Placing Orders
All order-placement commands (buy, sell, buylimit, buystop, selllimit, sellstop, buyat, sellat) and every parameter that applies to them.
Overview#
Order-placement commands tell the EA to open a new trade position, either immediately at the current market price or at a specified price level in the future. You send these commands via TradingView webhook alerts. Every open command requires a position sizing parameter; all other parameters are optional unless a specific combination demands them (for example, risk-based sizing requires a stop loss distance).
How It Works#
When TradingView fires an alert and posts the signal to the webhook URL:
- The platform receives the payload and detects the format (CSV or JSON).
- The three core fields (license key, command, and symbol) are extracted and validated first.
- All parameters are validated in sequence: sizing, stop loss, take profit, pending entry price, spread limits, scheduling, and authentication.
- If any validation fails, the signal is rejected immediately. The platform returns the rejection reason to TradingView and records a row in Signal Logs under the Rejected Signals tab (provided the license key was valid and extractable from the payload).
- If validation passes, the signal is queued and delivered to the connected EA over the live connection.
- The EA places the order with the broker.
- The EA sends an acknowledgement back to the platform. The Signal Logs entry on the dashboard is updated with the outcome: filled, spread too wide, position limit reached, outside active hours, and so on.
A signal that passes platform validation but is rejected by the EA (e.g., because the broker spread exceeded the limit) does not appear in the Rejected Signals tab. It appears as an accepted signal in Signal Logs with an outcome pill describing what the EA reported.
Market Orders#
buy: Open a Long Position at Market#
Instructs the EA to open a buy (long) position immediately at the best available ask price.
Minimum valid signal:
LICENSE,buy,EURUSD,size_lots=0.1
With stop loss and take profit:
LICENSE,buy,EURUSD,size_lots=0.1,sl_pips=50,tp_pips=100
Risk-based sizing:
LICENSE,buy,EURUSD,size_pct=1.5,sl_pips=50,tp_pips=100
JSON format:
{"license":"LICENSE","action":"buy","symbol":"EURUSD","size_lots":0.1,"sl_pips":50,"tp_pips":100}
Full-featured example (trailing stop, spread protection, magic, timed close):
LICENSE,buy,EURUSD,size_pct=1,sl_pips=50,tp_pips=100,distance_pips=30,trail_step=5,marketprice=1.0850,maxspread_pips=3,magic=100,closetime=14400
sell: Open a Short Position at Market#
Instructs the EA to open a sell (short) position immediately at the best available bid price.
Minimum valid signal:
LICENSE,sell,GBPUSD,size_lots=0.5
With stop loss and take profit:
LICENSE,sell,GBPUSD,size_lots=0.5,sl_pips=30,tp_pips=60
JSON format:
{"license":"LICENSE","action":"sell","symbol":"GBPUSD","size_lots":0.5,"sl_pips":30,"tp_pips":60}
Close Execution Policy for Market Orders#
When the EA sends a market order to the broker, it uses a large acceptable deviation. This means the order will fill even during fast markets, news events, or thin-liquidity windows. If the observed fill price deviates materially from the reference price, Signal Logs shows an amber "Extreme volatility" indicator on that row. This is a disclosure, not an error. The trade executed.
Pending Orders#
Pending orders sit on the broker as unfilled orders until the market reaches the specified entry price, at which point the broker converts them to live positions. The EA also manages its own expiry timer on pending orders, independent of any broker-native expiry support.
Stops, targets, and management attach when the order fills. A pending order can carry the same management parameters as a market order — sl_* / tp_*, a multi-target TP/SL ladder (tp_targets / sl_targets), a trailing stop (distance_*), an automatic breakeven (be_trigger_*), and a timed close (closetime). These are not active while the order sits unfilled; the EA attaches them — including the broker-side stop/take-profit backstop and the software ladder — at the moment the order fills, anchored to the actual fill price and volume. Cancel the order before it fills and nothing is attached. Seeing no managed stop on an unfilled pending order is expected; management appears on fill.
buylimit: Buy Limit Order#
Places an order to buy when the price drops to the specified entry level. Used when you expect the market to pull back before continuing higher.
The entry price must be below the current ask at the time the EA places the order. If the market has already moved above the specified price, placing a buy limit at that level is invalid. Use buy (immediate market order) instead.
Example:
LICENSE,buylimit,EURUSD,price=1.0800,size_lots=0.2,sl_pips=30,tp_pips=60
JSON:
{"license":"LICENSE","action":"buylimit","symbol":"EURUSD","price":1.0800,"size_lots":0.2,"sl_pips":30,"tp_pips":60}
buystop: Buy Stop Order#
Places an order to buy when the price rises to the specified entry level. Used for breakout entries: the order activates only if the market pushes through a resistance level.
The entry price must be above the current ask at the time the EA places the order.
Example:
LICENSE,buystop,EURUSD,price=1.1000,size_lots=0.1,sl_pips=30,tp_pips=60
selllimit: Sell Limit Order#
Places an order to sell when the price rises to the specified entry level. Used when you expect the market to rally to a resistance zone before reversing.
The entry price must be above the current bid.
Example:
LICENSE,selllimit,GBPUSD,price=1.2800,size_lots=0.1,sl_pips=30,tp_pips=60
sellstop: Sell Stop Order#
Places an order to sell when the price drops to the specified entry level. Used for breakout entries to the downside.
The entry price must be below the current bid.
Example:
LICENSE,sellstop,GBPUSD,price=1.2600,size_lots=0.1,sl_pips=30,tp_pips=60
buyat: Buy at Price (auto limit/stop)#
Automatically resolves to a buy limit or buy stop depending on where the live market is when the signal reaches the EA:
- If
priceis below the current ask at execution time → the order is placed as a buy limit - If
priceis above the current ask at execution time → the order is placed as a buy stop
Use this command when the strategy fires an alert without knowing which side of the market the price will be on at execution time. Common in strategies that use historical bar data rather than real-time prices.
Example:
LICENSE,buyat,NQ,price=21000,size_lots=1,sl_pips=40,tp_pips=80
The resolution from buyat to limit or stop happens at the EA, using the live bid/ask at the moment the signal arrives. If there is network delay or the signal is queued with delay=, the market may have moved since the alert fired; the type the EA places may not be what you expected. For deterministic order types, use buylimit or buystop directly.
sellat: Sell at Price (auto limit/stop)#
Automatically resolves to a sell limit or sell stop:
- If
priceis above the current bid at execution time → placed as a sell limit - If
priceis below the current bid at execution time → placed as a sell stop
Example:
LICENSE,sellat,NQ,price=20800,size_lots=1,sl_pips=40,tp_pips=80
Pending Order Expiry#
By default, if neither expiry nor expiry_time is included, a pending order is good-till-cancelled (GTC): it stays on the broker until it fills or until you cancel it with a cancel command. The EA does not auto-cancel a no-expiry pending order. (It still counts toward the Live Pending-Order Ceiling below until it fills or is cancelled.)
expiry: seconds until cancellation:
LICENSE,buylimit,EURUSD,price=1.0800,size_lots=0.1,expiry=3600
The EA starts a countdown from the moment it places the order. When the countdown reaches zero, the EA cancels the order and logs the cancellation.
expiry_time: specific datetime for cancellation:
LICENSE,buylimit,EURUSD,price=1.0800,size_lots=0.1,expiry_time=2026-05-01T14:30:00Z
expiry_time is interpreted as UTC, and the EA converts that instant to broker server time for placement (so it expires at the correct real-world moment on any broker). Supported formats:
- No timezone suffix (e.g.,
2026-05-01T14:30:00): treated as UTC - UTC suffix
Z(e.g.,2026-05-01T14:30:00Z): UTC (same as bare) - Explicit offset (e.g.,
2026-05-01T14:30:00-05:00): the offset is honored, converted to UTC (here, 19:30 UTC)
How to write the time you want (all expire at the 14:30 figure):
| You want it to expire at… | Write it as | Example |
|---|---|---|
| A specific UTC time | bare, or append Z | expiry_time=2026-05-01T14:30:00Z |
| Your broker's server time (the MT5 chart clock) | append your broker's UTC offset | GMT+3 broker → expiry_time=2026-05-01T14:30:00+03:00 |
| A specific local / exchange timezone | append that zone's offset | EST (−05:00) → expiry_time=2026-05-01T14:30:00-05:00 |
| A relative duration (no timezone math) | use expiry in seconds | expiry=3600 (1 hour after placement) |
When both are provided, expiry_time takes priority over expiry. If the EA is offline when the expiry time passes, it cancels the order on reconnect by comparing the stored expiry against the current time.
Expiry horizons are plan-capped. Trial accounts are limited to 15-minute expiry horizons. Paid plans (Standard, Pro, Premium) support up to 24 hours. Trial signals that exceed the 15-minute cap are rejected at the platform level with HTTP 402 before reaching the EA. Signals on any plan whose expiry exceeds 86,400 seconds, or whose expiry_time resolves to more than 24 hours in the future, are rejected with HTTP 400 (no plan goes beyond 24 hours). All three rejections are recorded in Signal Logs → Rejected Signals tab so you can spot the misconfigured alert.
Live Pending-Order Ceiling#
Each license has a per-tier ceiling on how many unfilled pending orders may be open simultaneously (Trial 5, Standard 50, Pro 500, Premium 5,000). This is the anti-spam ceiling: it caps how many pending-order signals can be in flight at once, per license. There is no global cap across licenses. Once a license's ceiling is reached, any new pending order signal returns HTTP 429 with the current live count in the X-Pending-Order-Count response header.
A slot frees the moment its order fills or you cancel it (cancellong / cancelshort / cancelall). Orders with a declared expiry / expiry_time also free their slot when that time passes.
Set an expiry on your pending-order signals so your ceiling stays clear even if a fill notification is ever missed. A pending order with no expiry still works normally at your broker and fills whenever price reaches the trigger; the ceiling is platform-side accounting only and never cancels or alters your broker order.
Position Sizing#
Position sizing is required on all eight order-placement commands. Exactly one of the two sizing parameters must be present.
size_lots: Fixed Volume#
Specifies the exact lot size to trade. Use any positive value your broker permits (subject to minimum lot size and lot step).
LICENSE,buy,EURUSD,size_lots=0.1,sl_pips=50
A size_lots above 100,000 (far beyond any broker's max volume) is rejected with HTTP 400. This catches a fat-finger (size_lots=100 meant 1.00) or a leaked key before it opens at the broker's maximum volume. Previously only >0 was checked and the EA silently clamped an oversized value to the broker's max.
size_pct: Risk-Based Sizing#
Specifies what percentage of account balance to risk on this trade. The EA calculates the lot size using:
Lots = (Balance × risk%) ÷ (SL distance in pips × pip value)
Because this formula requires a stop loss distance, size_pct always requires a stop loss parameter (sl_pips, sl_price, or sl_pct). Omitting the stop loss when using size_pct is rejected at the platform level.
Any of the three stop forms works — on both market and pending orders. The EA converts a sl_price (absolute level) or sl_pct (percentage) into the pip distance the risk formula needs, measuring from the entry-side quote (the ask for a buy, the bid for a sell) on a market order, or from the order's own price on a pending order. So size_pct=1.5,sl_pct=0.5 and size_pct=1.5,sl_price=1.0750 size correctly, not just sl_pips.
Valid range for size_pct: greater than 0 and up to 100.
LICENSE,buy,EURUSD,size_pct=1.5,sl_pips=50,tp_pips=100
On high-value instruments (XAUUSD, indices, crypto), a tight stop loss combined with a high size_pct can produce very large lot sizes. Test with size_lots=0.01 first to confirm the trade opens, then switch to size_pct once the signal is confirmed working.
Missing Position Sizing#
If an opening command (buy, sell, or any pending order) omits both size_lots and size_pct, the platform rejects it with HTTP 400 ("Position sizing is required...") and records a row in Signal Logs → Rejected Signals. The signal never reaches the EA, so the EA's Default Lot Size input setting does not apply to webhook-opened trades. Always include an explicit size_lots or size_pct on every opening alert.
Mutual Exclusion#
Including both size_lots and size_pct in the same signal is rejected at the platform level.
Stop Loss#
Stop loss parameters are optional for all order-placement commands, except when size_pct is used, in which case a stop loss is required. Use at most one stop loss format per signal.
| Parameter | What it specifies |
|---|---|
sl_pips | Distance from entry in pips |
sl_price | Absolute price level |
sl_pct | Percentage distance from entry price |
Sending more than one stop loss format in the same signal is rejected at the platform (only one is allowed).
For modify commands, when separate signals have specified different formats over time, the EA resolves them in this order: price before percentage before pips.
Percentage formula:
- Buy positions: SL = entry × (1 − pct ÷ 100)
- Sell positions: SL = entry × (1 + pct ÷ 100)
sl_pips (and tp_pips) have an upper bound. A pip distance above roughly 1,000,000 is rejected with HTTP 400 (sl_pips is implausibly large …), the same way size_lots has a ceiling. This catches an absurd typo — for example sl_pips=100000 when you meant 100 — which on a SELL would otherwise place a stop so far away it never triggers, leaving an effectively unprotected position you believe is guarded. A legitimately wide stop (well under 1,000,000 pips) is unaffected.
sl_price=0 is not valid and is rejected at the platform. Use a positive price level or omit the parameter to open without a stop loss.
sl_price has an upper ceiling too. An absolute SL price above roughly 1,000,000,000 (1e9) is rejected with HTTP 400, matching the per-target slN_price siblings that were already capped (previously only negative or zero was rejected). A real instrument price is far below this ceiling, so legitimate values are unaffected.
For pending orders with absolute price SL: the SL must be on the correct side of the entry price:
- Buy limit / buy stop: SL must be below the entry price
- Sell limit / sell stop: SL must be above the entry price
Violations are rejected at the platform.
Take Profit#
Take profit parameters are optional. Use at most one per signal.
| Parameter | What it specifies |
|---|---|
tp_pips | Distance from entry in pips |
tp_price | Absolute price level |
tp_pct | Percentage distance from entry price |
Percentage formula:
- Buy positions: TP = entry × (1 + pct ÷ 100)
- Sell positions: TP = entry × (1 − pct ÷ 100)
tp_price=0 is not valid and is rejected.
tp_price has an upper ceiling too. An absolute TP price above roughly 1,000,000,000 (1e9) is rejected with HTTP 400, matching the per-target tpN_price siblings that were already capped (previously only negative or zero was rejected). A real instrument price is far below this ceiling, so legitimate values are unaffected.
For pending orders with absolute price TP: the TP must be on the correct side:
- Buy limit / buy stop: TP must be above the entry price
- Sell limit / sell stop: TP must be below the entry price
Multi-Target TP/SL#
Splits the position across up to 10 price targets per side. The EA closes a defined portion of the position at each target. Percentages must sum to exactly 100%.
For full syntax documentation, examples, and the rounding behaviour on whole-unit instruments, see the multi-target TP/SL article. Key constraints:
- Targets are numbered from 1 upward with no gaps (
tp1,tp2,tp3, nottp1,tp3) - Use either
_close(percentage of original volume) or_lots(fixed volume) across all targets on a side; mixing the two modes is not permitted - Maximum 10 levels per side (TP and SL are independent; you can have 3 TP levels and 2 SL levels simultaneously)
- The EA rounds lot sizes down to the broker's lot step; the last target receives the remainder
- In fixed-lot (
_lots) mode, the per-level lots are capped to the cumulative remaining position size — once the running total reaches the position, later levels close 0 and the last affordable level is trimmed to what's left, so the legs can never sum past the position
Input methods#
Individual parameters (CSV or JSON):
LICENSE,buy,EURUSD,size_lots=0.3,tp1_pips=30,tp1_close=50,tp2_pips=60,tp2_close=30,tp3_pips=100,tp3_close=20
Compact string (CSV or JSON string value):
LICENSE,buy,EURUSD,size_lots=0.3,tp_pips=30:50;60:30;100
The last segment may omit the percentage; the platform assigns the remainder to reach 100%.
JSON array:
{"license":"LIC","action":"buy","symbol":"EURUSD","size_lots":0.3,"tp_targets":[{"pips":30,"close_pct":50},{"pips":60,"close_pct":30},{"pips":100,"close_pct":20}]}
JSON targets support pips, price, close_pct, and close_lots per entry.
Combining a single SL with tp_targets#
Sending a plain sl_pips alongside tp_targets is valid. The broker stop loss handles the SL as a single level; the multi-target manager handles only the TP partial closes. To get a managed multi-level SL, send sl_targets explicitly.
NETTING account behaviour#
On NETTING accounts, a second buy for the same symbol adds volume to the existing position rather than opening a new ticket. When the second signal carries multi-TP/SL targets, the EA replaces the existing target schedule entirely. The new targets apply to the full net position. To keep the original schedule, do not include target parameters on the second signal — in that case the existing ladder is re-anchored to the new volume-weighted average entry (its pips/percent levels are re-measured from the new average, the same way auto-breakeven and trailing stops re-anchor on a scale-in) and its leg volumes are re-split across the larger net position. Absolute price-based levels stay put. The broker-side safety-net stop is re-asserted at the new levels too.
Even without new target parameters, the EA keeps the ladder fitted to the live position: if the net position grows (a plain add) or shrinks (an external partial close), the un-fired levels are re-split across the new remaining volume by their relative percentages — already-fired levels stay frozen, and fixed-_lots levels keep their lots with only the cap re-checked. This also runs on EA restart, so a change made while the EA was offline is reconciled on reload.
Pending Entry Price#
The price parameter specifies the entry price level for all six pending order commands. It is required. Pending order signals without it are rejected.
LICENSE,buylimit,EURUSD,price=1.0800,size_lots=0.2,sl_pips=30,tp_pips=60
price has no meaning on buy and sell (market orders execute at the best available price regardless).
Spread and Slippage Protection#
Three parameters control whether the EA executes when market conditions are poor at the moment of order placement.
marketprice: Stale-Signal Protection (Mode A)#
Include the market price your TradingView strategy was looking at when it fired the alert (typically the close value from the bar). When the EA receives the signal, it compares the best current execution price against your reference price. If the deviation exceeds your limit, the EA skips the order.
This catches stale alerts (signals delayed in transit) and sudden moves between alert generation and EA receipt.
LICENSE,buy,EURUSD,size_lots=0.1,sl_pips=50,marketprice=1.0850,maxspread_pips=3
maxspread_pips: Maximum Spread in Pips#
Sets the maximum acceptable spread (or deviation from marketprice when Mode A is active). The EA checks the live bid/ask spread at the moment of execution.
Range: 0 to 100,000. Setting to 0 disables the check.
maxspread_pct: Maximum Spread as Percentage#
Sets the maximum acceptable spread as an absolute percentage of price. maxspread_pct=0.5 means 0.5%, not 50%.
Range: 0 to 100. Values outside this range are rejected at the platform level. Setting to 0 disables the check.
Mode A vs Mode B#
| Condition | Stale signal caught | Wide spread caught |
|---|---|---|
marketprice included | Yes | Yes |
marketprice omitted | No | Yes (spread vs. bid/ask only) |
When marketprice is included (Mode A), the EA measures deviation between the current execution price and your reference price. When omitted (Mode B), the EA only checks whether the live bid/ask spread exceeds the limit and cannot detect an alert that arrived late during a tight market.
When both are set#
Both conditions must pass for the trade to execute. Setting both gives tighter control: the pips limit operates in absolute terms, while the percentage limit is instrument-agnostic.
Where spread rejections appear#
A spread-rejected trade does not appear in the Rejected Signals tab. It appears as an accepted signal entry in Signal Logs with an amber "Trade rejected: spread too wide" indicator. The pill shows the measured value, the configured limit, and which source provided the threshold (the signal itself or the dashboard default).
A malformed spread parameter (e.g., maxspread_pct=150 or maxspread_pips=-1) is a platform-level validation error and does appear in Rejected Signals.
Dashboard defaults#
Both maxspread_pips and maxspread_pct can be configured as per-user or per-license defaults in EA Settings on the dashboard. Signal-level values take priority. When a signal omits the field, the EA uses the dashboard default. The rejection pill notes which source was active.
Recommended starting ranges#
| Instrument type | maxspread_pips | maxspread_pct |
|---|---|---|
| Forex majors (EURUSD, GBPUSD, USDJPY) | 2-5 | 0.02-0.05 |
| Forex minors | 5-10 | 0.05-0.15 |
| Forex exotics (USDTRY, USDZAR) | 15-30 | 0.10-0.30 |
| Metals (XAUUSD, XAGUSD) | 10-30 | 0.03-0.10 |
| Indices and futures (NAS100, SPX500) | 10-30 ticks | 0.02-0.05 |
| Crypto (BTCUSD) | 30-100 | 0.05-0.20 |
These are starting points. Tune for your broker's typical spreads and your strategy's tolerance for slippage.
Trailing Stops and Auto-Breakeven at Entry#
Both trailing stops and auto-breakeven triggers can be attached to any buy, sell, or pending order signal. The EA registers the monitor when the position opens (or when the pending order fills).
For full parameter documentation, mutual exclusion rules, and lifecycle behaviour, see the trailing stop and breakeven article. The parameters that apply at entry time are summarised here.
Trailing stop parameters at entry#
Use exactly one distance mode:
| Parameter | What it controls |
|---|---|
distance_pips | Trail distance in pips |
distance_pct | Trail distance as a percentage of entry price (greater than 0, up to 99) |
distance_atr | Trail distance as an ATR multiplier (0.1-20.0) |
Optional with any distance mode:
| Parameter | What it controls |
|---|---|
trail_trigger | Pips of profit before trailing activates |
trail_trigger_pct | Percentage profit before trailing activates |
trail_trigger_price | Exact price level that activates trailing |
trail_step | Minimum pips the SL must move per update (use with distance_pips) |
trail_pct_step | Minimum percentage move per update (use with distance_pct) |
trail_atr_period | ATR period in bars (2-500, default 14; use with distance_atr) |
trail_atr_timeframe | ATR timeframe (M1, M5, M15, M30, H1, H4, D1, W1, MN1; use with distance_atr) |
Trigger modes are mutually exclusive: use at most one of trail_trigger, trail_trigger_pct, trail_trigger_price.
Auto-breakeven parameters at entry#
Use exactly one trigger mode and at most one offset mode:
| Parameter | What it controls |
|---|---|
be_trigger_pips | Pips of profit that fires the breakeven move |
be_trigger_pct | Percentage profit that fires the breakeven move |
be_trigger_price | Exact price level that fires the breakeven move |
be_offset_pips | How far above or below entry to place the SL (positive = lock in profit) |
be_offset_pct | Offset as a percentage of entry price |
be_offset_price | Absolute SL price to move to |
Mutual exclusion between trailing stop and breakeven#
Both can be registered on the same position. They coexist until one fires first. When the trailing stop trigger fires, the breakeven monitor is removed. When the breakeven trigger fires, the trailing stop monitor is removed. If both triggers resolve to the same price (within 1 pip), neither is registered and the trade still executes; the acknowledgement includes a warning field. When this happens, adjust the trigger values so the two do not conflict.
Manual SL edits after setting auto-breakeven do not cancel the monitor. When the trigger price is reached, the EA will move the SL to breakeven regardless of any subsequent manual changes to the stop. To cancel the auto-breakeven monitor, send a nobreakeven command.
Trade Identity and Scheduling Parameters#
magic: Magic Number#
Associates the trade with a specific integer identifier. Behaviour depends on the Magic Number Mode configured in the EA's input settings:
Single mode (default): The signal's magic parameter is ignored. All trades opened by the EA use the EA's configured Default Magic Number. Close and modify commands will only affect positions that carry that default magic.
Multi-Strategy mode: The signal's magic parameter is used. Open commands (buy, sell, pending order commands) require magic to be present. Signals without it are rejected. Symbol-scoped close, cancel, and modify commands also require magic: sent without it they are rejected with HTTP 400 (the request is ambiguous about which strategy to act on). Add magic=N to target one strategy, magic=ALL to sweep every strategy's positions on that symbol, or use a symbol-less closeall / cancelall as the cross-strategy emergency brake.
delay: Queued Execution#
Delays the signal by a specified number of seconds. The signal is held on the server and delivered to the EA when the time arrives. Survives server restarts.
LICENSE,buy,EURUSD,size_lots=0.1,sl_pips=50,delay=30
Maximum delay: 86,400 seconds (24 hours). Signals with delay greater than 86,400 are rejected with HTTP 400 (no longer silently capped) and the rejection is recorded in Signal Logs → Rejected Signals tab. Signals older than 28 hours that did fit under the cap are automatically expired as a safety measure.
Plan requirement: The delay parameter is not available on Trial accounts. Sending delay on a Trial account returns HTTP 402 and writes a Rejected Signals row. Paid plans also have a per-license ceiling on how many delayed signals may be queued at once. When that ceiling is reached, the platform returns HTTP 429.
delay works on every command, not just entries. Close commands (closeall, closelong, closeshort, cancellong, etc.), trade management (modify, trail, breakeven), symbol filter toggles (eaon, eaoff, eaoffexcept, eaonexcept), and the queue-control command (clearqueue) all accept delay=. For server-side actions, the mutation is deferred to the scheduled time. For example, eaoff,EURUSD,delay=60 does not disable EURUSD until 60 seconds later, and clearqueue,delay=10 queues itself and cancels everything else queued for the same license when it fires.
To cancel a queued delayed signal before it fires, send an immediate clearqueue command.
closetime: Timed Position Close#
Automatically closes the position a specified number of seconds after it fills. The countdown starts from the broker's confirmed open time.
Range: 1 to 2,592,000 seconds (1 second to 30 days).
LICENSE,buy,EURUSD,size_lots=0.1,sl_pips=50,closetime=3600
The timed close persists across EA restarts. If the position hits its TP or SL, or is closed manually, the timed close is automatically cancelled. Compatible with multi-TP/SL, trailing stops, and breakeven; any of these can close the position before the timer fires.
Common use cases: news scalping (enter before release, exit X seconds after), session-based trading, demo testing with limited exposure duration.
active_start and active_end: Per-Signal Active Hours#
Restricts when the EA will act on this specific signal. If the signal arrives outside the specified window, the EA ignores the open command.
Format: HH:MM in 24-hour notation. Leading zeros are required.
LICENSE,buy,EURUSD,size_lots=0.1,sl_pips=50,active_start=08:00,active_end=17:00
Supports overnight sessions (e.g., active_start=22:00,active_end=06:00 spans midnight).
These parameters override this license's configured active hours setting for this signal only. The override is per-license, never account-wide: other licenses on the same account use their own configured window and are not affected. The timezone used is the one configured in EA settings.
Validation rules:
- Both must be supplied together. A signal that includes only one of the two is rejected with HTTP 400 and recorded in Signal Logs → Rejected Signals tab. The platform does not silently fill the missing bound from the configured value. Omit both for an always-on window.
- A malformed value is rejected with HTTP 400 (e.g.
9:00without a leading zero, or25:00) and recorded in Signal Logs → Rejected Signals tab (no longer silently dropped). UseHH:MM24-hour format with leading zeros. active_startandactive_endmust differ. An equal pair (e.g.09:00/09:00), including00:00/00:00, is a zero-length window that would block every entry, so it is rejected with HTTP 400.
Active hours do not affect close, cancel, or modify commands. Open commands (buy, sell, pending orders) are the only ones that check active hours.
Signal Authentication (auth)#
Signal Authentication is a per-license switch. Turn it on and set a password, and every webhook alert for that license must include auth=<your password> (CSV) or "auth":"<your password>" (JSON), or the signal is blocked. Turn it off and no alert needs it.
When it is enabled, the requirement applies to every command with no exceptions. A signal that omits auth is blocked with the reason "missing_auth"; a signal that carries the wrong password is blocked with the reason "invalid_auth". When it is disabled, no signal needs auth; if you include it anyway, it is parsed and then ignored.
LICENSE,buy,EURUSD,size_lots=0.1,sl_pips=50,auth=YourPassword
The parameter may appear anywhere in the parameter list. It is looked up by name, not by position.
The password is scrubbed from the signal before it is stored, whether authentication is on or off, so the stored record never contains the plaintext password. The password is never sent to the EA.
For setup instructions and the full authentication lifecycle, see the signal authentication article.
Error Messages and Meanings#
Group A: Platform Validation Rejections (HTTP 400)#
Surface: Signal Logs → Rejected Signals tab AND the TradingView alert execution history response body.
A Rejected Signals row is only created when the platform can extract a valid license key from the payload. If the license key is missing or malformed, no row appears in Signal Logs. The rejection is still returned to TradingView. Very long rejection messages may be shortened.
| Message | Cause | What to do |
|---|---|---|
| "Position sizing is required. Specify size_lots (fixed volume, e.g. size_lots=0.1) or size_pct (risk-based, e.g. size_pct=1.5). Signals without explicit sizing are rejected for safety." | Trade-opening command has neither size_lots nor size_pct | Add size_lots=0.1 (or a suitable value) or size_pct=1.5 to the alert |
| "Conflicting position sizing parameters: size_lots, size_pct. Use either size_lots (fixed volume) or size_pct (risk-based), not both." | Both size_lots and size_pct are present | Remove one; use only size_lots or only size_pct |
Invalid size_pct={value}. Must be > 0 and <= 100 (percentage of account balance to risk on this trade). | size_pct is 0, negative, or above 100 | Use a value strictly greater than 0 and no more than 100 |
| "size_pct requires a stop loss to calculate position size. The EA uses risk-based sizing: lots = (balance × size_pct%) ÷ (sl_pips × pip_value). Add a stop loss parameter (sl_pips, sl_price, or sl_pct)." | size_pct is present but no stop loss parameter is included | Add sl_pips, sl_price, or sl_pct to the signal |
| "Conflicting stop loss parameters: {list}. Use only one of: sl_pips, sl_price, or sl_pct." | More than one SL format is present in the same signal | Remove all but one SL parameter |
| "Conflicting take profit parameters: {list}. Use only one of: tp_pips, tp_price, or tp_pct." | More than one TP format is present in the same signal | Remove all but one TP parameter |
| "sl_price=0 is not valid. Use a positive price value to set the stop loss." | sl_price is set to 0 | Use a positive price level or omit sl_price to open without a stop loss |
| "tp_price=0 is not valid. Use a positive price value to set the take profit." | tp_price is set to 0 | Use a positive price level or omit tp_price to open without a take profit |
| "{COMMAND} requires a price parameter specifying the entry level. Example: price=1.0800" | A pending order command (buylimit, buystop, selllimit, sellstop, buyat, sellat) was sent without a price parameter | Add price= followed by the desired entry price |
| "Take profit (tp_price={value}) must be above entry price ({entry}) for BUYLIMIT orders" | TP price is below the entry price on a buy order | Move the TP above the entry price level |
| "Stop loss (sl_price={value}) must be below entry price ({entry}) for BUYLIMIT orders" | SL price is above the entry price on a buy order | Move the SL below the entry price level |
| "Take profit (tp_price={value}) must be below entry price ({entry}) for SELLLIMIT orders" | TP price is above the entry price on a sell order | Move the TP below the entry price level |
| "Stop loss (sl_price={value}) must be above entry price ({entry}) for SELLLIMIT orders" | SL price is below the entry price on a sell order | Move the SL above the entry price level |
| "Gap detected in TP target numbering. Missing: {missing}. Found: {found}. Targets must be numbered sequentially starting from TP1 with no gaps." | Multi-target TP levels skip a number (e.g., tp1 and tp3 without tp2) | Add the missing level or renumber from 1 with no gaps |
| "Multi-TP close percentages must sum to 100% (got {total}%)" | The close percentages across TP targets do not total 100 | Adjust the percentage values until they sum exactly to 100 |
| "Cannot mix _close (percentage) and _lots (volume) across TP targets. Use one mode." | Some TP targets use _close and others use _lots | Pick one mode (percentage or fixed volume) and apply it consistently across all targets |
| "TP{N} has a level but no close percentage or lots specified" | A TP level has a price or pips value but no _close or _lots amount | Add tp\{N\}_close= or tp\{N\}_lots= for that level |
| "Conflicting trailing stop parameters: {list}. Use only one of: distance_pips, distance_pct, or distance_atr." | Multiple trail distance modes in the same signal | Keep only one distance type |
| "Conflicting breakeven trigger parameters: {list}. Use only one of: be_trigger_pips, be_trigger_pct, or be_trigger_price." | Multiple breakeven trigger modes in the same signal | Keep only one trigger type |
| "Conflicting breakeven offset parameters: {list}. Use only one of: be_offset_pips, be_offset_pct, or be_offset_price." | Multiple breakeven offset modes in the same signal | Keep only one offset type |
| "maxspread_pct={value} out of allowed range [0, 100]" | maxspread_pct is negative or above 100 | Use a value between 0 and 100 (e.g., 0.05 for 0.05%); or use 0 to disable the check |
| "maxspread_pips={value} out of allowed range [0, 100000]" | maxspread_pips is negative or above 100,000 | Use a value between 0 and 100,000 |
| "Invalid numeric value for '{field}' (NaN/Infinity not allowed)" | A numeric field evaluates to not-a-number or infinity | Replace the value with a valid finite number |
| "'{field}' cannot be negative (got {value})" | A field that must be non-negative (e.g., sl_pips, tp_pips, distance_pips) was given a negative value | Use a positive value or omit the field |
| "Invalid value '{value}' - must be a finite number" | A numeric field is not a finite number | Replace with a valid real number |
| "Invalid value '{value}' - expected a number (non-ASCII characters not allowed)" | A numeric field contains Unicode digits or other non-ASCII characters | Use standard ASCII numerals only |
| "Invalid close_pct={value}. Must be between 0 (exclusive) and 100 (inclusive)." | close_pct is 0, negative, or above 100 | Use a value strictly greater than 0 and up to 100 |
| "Invalid close_lots={value}. Must be greater than 0." | close_lots is 0 or negative | Use a positive lot value |
| "Invalid value '{value}' for closetime - must be between 1 and 2592000 seconds (1 second to 30 days)" | closetime is out of range | Use a value between 1 and 2,592,000 |
Group B: Plan and Quota Rejections#
Surface: TradingView alert response only (HTTP 402 or HTTP 429). These do not appear in Signal Logs → Rejected Signals.
| Message | Cause | What to do |
|---|---|---|
"Delayed signals require a paid plan. Upgrade to use delay=." | delay parameter used on a Trial account | Upgrade to a paid plan or remove delay from the alert |
| "Pending-order expiry exceeds this plan's {N}-minute cap. Upgrade for longer expiries." | expiry or expiry_time exceeds the plan's allowed horizon | Reduce the expiry duration to fit within the plan cap or upgrade the plan |
| "Live pending-order limit reached ({current}/{max}). Cancel unfilled orders or wait for them to expire before placing more." | The per-license pending-order ceiling has been reached | Send cancellong, cancelshort, or cancelall to free capacity, or wait for existing orders to fill or expire |
Where to look#
| Situation | Where to look |
|---|---|
| Signal rejected and you want to see the reason | Signal Logs → Rejected Signals tab in the dashboard |
| Signal rejected but nothing in Rejected Signals | The license key in the payload is missing or malformed. Fix the key format first; once it is valid, all rejections will appear in Signal Logs. |
| Trade did not open despite signal being accepted | The EA may have declined at execution time (spread, position size limits, strategy allowance for the symbol, active hours, EA disconnected). Check Signal Logs for the outcome pill on the accepted signal row. Also check the MT5 Experts tab for local EA messages. A "Position limit reached" pill means either your Max Long/Short Lots caps or your plan's strategies-per-symbol allowance, because the two share one message. |
| HTTP 429 (pending-order ceiling hit) | Cancel unfilled pending orders with a cancel command, then retry |
| HTTP 402 (plan gate) | Dashboard → Subscription page to upgrade, or remove the gated parameter from the alert |
| Spread-rejected trade not visible in Rejected Signals | Signal Logs → the accepted signal row should show an amber spread-rejection pill. The rejection was EA-side, not platform-side. |
Plan and Tier Differences#
| Feature or Limit | Trial | Standard | Pro | Premium |
|---|---|---|---|---|
buy and sell (market orders) | Available | Available | Available | Available |
| All pending order commands | Available | Available | Available | Available |
| Live pending-order ceiling | 5 per license | 50 per license | 500 per license | 5,000 per license |
Pending order expiry horizon (expiry, expiry_time) | 15 minutes max | 24 hours max | 24 hours max | 24 hours max |
delay parameter | Not available | Available | Available | Available |
| Concurrent queued delayed signals | 0 | 50 per license | 150 per license | 500 per license |
| All other order parameters | Available | Available | Available | Available |
When the pending-order ceiling is hit: the platform returns HTTP 429 with the current live count in a response header. Slots drain automatically as orders fill, as orders are cancelled (cancellong / cancelshort / cancelall), or as their declared expiry elapses. If you're at the cap and none of those conditions clears the queue, you likely have many genuinely unfilled orders open on the broker.
When the delayed-signal queue ceiling is hit: HTTP 429 is returned with the current queue depth in a response header. Send a clearqueue signal to cancel pending delayed signals and free capacity.
When the expiry cap is exceeded: HTTP 402 is returned. The fix is to reduce the expiry to fit within the plan's allowed horizon, or to upgrade the plan.
When a Trial account uses delay: HTTP 402 is returned. Remove delay from the alert or upgrade to a paid plan.
Known Edge Cases and Gotchas#
-
buyatandsellatresolve at EA receipt, not at alert time. If there is delay in transit (network, thedelayparameter, or queue congestion), the market may have moved. The EA places the order based on the live bid/ask when it receives the signal. The resulting order type (limit vs stop) may differ from what you expected at alert time. -
Pending order expiry is EA-managed, not broker-managed. Many brokers do not natively support pending order expiry. The EA tracks expiry itself and cancels the order when the time comes. If the EA is offline when the expiry passes, it cancels the order on reconnect. During that gap, an expired order remains live on the broker.
-
expiry_timewithout a timezone suffix is interpreted as UTC. The EA converts that UTC instant to broker server time for placement, so it expires at the correct real-world moment on any broker. If you write a broker-local time expecting it to be used as-is (e.g.expiry_time=2026-05-01T14:00:00meaning 14:00 broker time), you'll instead get 14:00 UTC — append your broker's offset (e.g.…+03:00) to express broker-local time. -
sl_priceandtp_pricemust be on the correct side ofpricefor pending orders. A buy limit with a TP below the entry price, or an SL above the entry price, is rejected at the platform. This is validated even though the broker would ultimately also reject such an order. The platform catches it before it reaches the EA. -
size_pcton high-value instruments can produce unexpectedly large positions. XAUUSD, indices, and crypto have very different pip values from standard forex pairs. A 1-pip SL on XAUUSD is 10 cents per lot, which meanssize_pct=1on a $10,000 account with a 5-pip SL computes to around 20 lots. Always test withsize_lots=0.01first. -
Compact TP/SL syntax: if explicit percentages already sum to 100 and a remainder segment is present, the remainder segment resolves to 0% and the signal is now rejected (HTTP 400) with a clear error — it is no longer silently discarded into a position with no targets. Verify the arithmetic. The trailing segment may omit the percentage only when earlier segments leave a non-zero remainder; a complete single level such as
tp_pips=30:100is accepted, and a malformed compact string (bad number, percentage over 100, pips ≤ 0) is also rejected. -
Sequential numbering with no gaps is strictly enforced for multi-target TP/SL. Sending
tp1_pipsandtp3_pipswithout atp2_pipsis rejected. Always number from 1 upward with no skipped levels. -
In Multi-Strategy magic mode, open commands without
magicare rejected by the platform before the signal reaches the EA. If you're migrating from Single mode to Multi-Strategy mode, addmagic=to all your open-command alerts. -
On NETTING accounts, a second
buyfor the same symbol does not open a second ticket. The broker adds to the existing net position. Any multi-TP/SL targets in the second signal replace the existing schedule entirely. The new percentages are calculated against the full net volume post-add. -
ATR trailing stops are limited to 50 concurrent handles per EA instance. Opening more than 50 positions with
distance_atractive causes subsequent positions to open without a trailing stop. A warning is logged to the MT5 Experts tab but no platform-level rejection occurs. -
trail_atr_timeframeis case-insensitive.h1is normalised toH1. An unrecognised value (e.g.H3) is rejected with HTTP 400 and recorded in Rejected Signals, not silently defaulted. Valid values: M1, M5, M15, M30, H1, H4, D1, W1, MN1. -
Spread-protection rejections do not appear in the Rejected Signals tab. They appear as outcome pills on accepted signal rows. If a signal is accepted but no trade opens, expand the Signal Logs row and read the outcome pill, not the Rejected Signals tab.
-
maxspread_pctis an absolute percentage, not basis points.maxspread_pct=0.5means 0.5% of price. Confusing this with a tighter value (e.g., entering 50 thinking it means 0.5%) will reject nearly every trade. -
Setting
delayon a pending order signal delays when the pending order is placed, not when it fills. Adelay=60on abuylimitmeans the pending order is submitted to the broker 60 seconds after the alert fires. The pending order then waits for the market to reach the entry price in the usual way.
Frequently Asked Questions#
Q: Should I use size_lots or size_pct?
A: Use size_lots when you want a fixed position size regardless of account balance. Use size_pct when you want to risk a consistent percentage of your account on each trade; the EA calculates the lot size automatically from the stop loss distance. size_pct requires a stop loss; size_lots does not.
Q: What happens if I include neither size_lots nor size_pct?
A: On an opening command the platform rejects the signal with HTTP 400 ("Position sizing is required...") and records it in Signal Logs → Rejected Signals. The signal never reaches the EA, so its Default Lot Size input does not come into play. Add an explicit size_lots (fixed volume) or size_pct (risk-based) to every opening alert.
Q: My size_pct signal was rejected even though I have a stop loss. Why?
A: The most common cause is that size_pct is outside the valid range. Values must be strictly greater than 0 and no more than 100. A size_pct=0 or size_pct=150 are both invalid. Check the exact value in your TradingView alert.
Q: What is the difference between buylimit and buyat?
A: buylimit always places a buy limit order regardless of where the market is. buyat checks the live price when the signal reaches the EA and places either a buy limit (if entry is below current ask) or a buy stop (if entry is above current ask). Use buylimit when you know the market is above your entry and you want a pullback entry. Use buyat when you don't know which side the market will be on when the alert fires.
Q: How do I set a pending order that expires in 1 hour?
A: Add expiry=3600 to the signal (3600 seconds = 1 hour). The EA starts the countdown when it places the order. For a specific time instead of a duration, use expiry_time in UTC — expiry_time=2026-05-01T15:00:00Z (a bare 2026-05-01T15:00:00 is also UTC). To express a broker-local or other local time, append the matching offset, e.g. expiry_time=2026-05-01T17:00:00+02:00.
Q: What happens to a pending order if the EA disconnects? A: The order remains on the broker as a live pending order. If the market hits the entry price while the EA is offline, it fills normally. When the EA reconnects, it detects the filled position and registers it. If the EA was offline through the expiry time, it will cancel the order on reconnect.
Q: My trade opened immediately and then closed. What happened?
A: Check whether closetime was included in the signal with a very small value (e.g., closetime=1 means close 1 second after fill). Also check if the position was stopped out immediately because the SL was too close to the entry price for the broker's minimum stop distance.
Q: How do marketprice and maxspread_pips interact?
A: When both are present, marketprice is the reference your strategy was looking at. The EA computes the deviation between the current execution price and your reference, then checks whether that deviation exceeds maxspread_pips. This is Mode A: it catches both stale alerts and wide spreads. Without marketprice, the EA only measures the live broker spread (ask minus bid), which cannot detect a stale signal that arrived during a tight market (Mode B).
Q: Does delay work on pending orders?
A: Yes. Adding delay=60 to a buylimit signal means the pending order is submitted to the broker 60 seconds after the alert fires. The pending order then waits for the market to reach the entry price in the usual way. Delay and expiry are independent; a pending order can have both.
Q: I hit the pending-order limit. What do I do?
A: Send a cancel command to free capacity. cancellong SYMBOL cancels pending buy orders on that symbol; cancelshort SYMBOL cancels pending sell orders; cancelall SYMBOL cancels all pending orders on a symbol. After freeing space, re-send the pending order signal.
Q: Can I include a trailing stop and auto-breakeven on the same signal? A: Yes. Both are registered on the position when it opens. They coexist until one trigger fires. If the trailing stop trigger fires first, the breakeven monitor is removed automatically. If the breakeven trigger fires first, the trailing stop monitor is removed. Adjust the trigger levels so they do not both resolve to the same price. If they conflict within 1 pip of each other, neither is registered and the trade still opens without either active.
Q: My multi-TP percentages add up to 100 but the signal was still rejected. Why?
A: The most common cause is a numbering gap. For example, defining tp1_pips and tp3_pips without a tp2_pips. All levels must be numbered sequentially from 1 with no gaps. Another common cause is mixing _close and _lots; all levels on a side must use the same mode.