Slippage Protection
The pre-fill spread gate (marketprice, maxspread_pips, maxspread_pct) and post-fill extreme slippage disclosure for close commands.
Overview#
PineHook provides two layers of slippage-related control. Spread gate protection checks market conditions before an order is submitted; if the broker's spread or the price drift from a TradingView reference is too wide, the trade is blocked outright. Extreme slippage disclosure applies to close commands only: closes always execute regardless of conditions, but when the fill price deviates significantly from the price at the time the command was sent, the platform flags it with a visible badge.
The legacy per-trade slippage parameter (which configured MT5's SetDeviationInPoints) has been removed. The MQL5 CTrade library applies its own built-in default deviation on opens, and close commands always force a generous deviation to guarantee execution. There is no longer a user-facing slippage tolerance setting; the spread gate covers the equivalent protection at the layer above order submission.
How It Works#
1. Spread Gate (Pre-Fill Protection)#
The spread gate is configured through webhook signal parameters and evaluated by the EA at the moment it is about to send an order. If the gate fails, the order is never submitted; the EA sends a rejection acknowledgment to the platform, which records it on the Signal Logs page.
Three parameters control the gate:
| Parameter | Type | Allowed range | Meaning |
|---|---|---|---|
marketprice | float | 0 to 1,000,000,000 | The price your TradingView strategy saw when the alert fired. Setting this enables Mode A. A value of 0 (or omitting the parameter) switches to Mode B. |
maxspread_pips | float | 0 to 100,000 | Maximum acceptable deviation or broker spread in adjusted pips. Setting to 0 disables this check. |
maxspread_pct | float | 0 to 100 | Maximum acceptable spread as an absolute percentage of price (not a fraction: 0.05 means 0.05%). Setting to 0 disables this check. |
When both maxspread_pips and maxspread_pct are set to non-zero values, both conditions must pass for the trade to execute. One failing condition blocks the trade, even if the other would have passed.
Mode A: Stale-Signal Protection#
When marketprice is included in the signal, the EA compares the live price the order would fill at (Ask for a buy, Bid for a sell) against the marketprice reference your strategy sent. If the gap between them exceeds maxspread_pips or maxspread_pct, the trade is rejected.
This catches two things: signals that have gone stale (the alert was queued in TradingView's system and the market has moved since it fired), and illiquid books where the fill price sits well outside the reference.
Mode A math (performed entirely by the EA using live MT5 symbol data; nothing is hardcoded):
- Pips deviation: the absolute difference between the live fill price and
marketprice, divided by the symbol's adjusted pip size - Percent deviation: the same absolute difference, divided by the live fill price, multiplied by 100
Mode B: Wide-Book Protection#
When marketprice is omitted or set to 0, the EA evaluates the broker's raw spread (the gap between Ask and Bid) rather than any deviation from a reference price. This catches news candles and after-hours illiquidity but cannot detect a stale signal that arrived during a tight market.
Mode B math:
- Pips spread: (Ask minus Bid) divided by the symbol's adjusted pip size
- Percent spread: (Ask minus Bid) divided by the midpoint of Ask and Bid, multiplied by 100 (the midpoint denominator is standard for spread-as-percentage and is symmetric regardless of direction)
Mode comparison:
| Scenario | Mode A (marketprice set) | Mode B (no marketprice) |
|---|---|---|
| Fast market, tight spread | Executes | Executes |
| Stale signal, spread still tight | Rejected | Executes (not caught) |
| News candle, wide spread | Rejected | Rejected |
| After-hours illiquidity | Rejected | Rejected if spread exceeds limit |
Combining Both Parameters#
Example: signal includes maxspread_pips=3 and maxspread_pct=0.05
- Live market: Ask=1.0852, Bid=1.0851 (1 pip spread, 0.009% of price): both pass, trade executes
- Live market: Ask=1.0855, Bid=1.0850 (5 pip spread): pips check fails (5 > 3), trade is blocked; the pct check is not evaluated once one condition fails
2. Extreme Slippage Disclosure (Close Commands Only)#
Close commands bypass the spread gate entirely and always execute. After the fill completes, the EA measures how far the actual fill price deviated from the price at the time the close command was sent. When that deviation is significant, the EA reports it back to the platform as part of the close acknowledgment.
The platform stores the observed deviation in pips and in MT5 points, then renders an amber badge on the Signal Logs row. The badge reads:
Extreme volatility: X.X pips slippage
Hovering over the badge shows a tooltip:
"This close executed with X.X pips (Y points) of slippage due to extreme market volatility. We prioritized executing your close over waiting for a better price, because close commands always execute regardless of spread."
The reference price (broker's Ask/Bid snapshot at send time) is also shown in the tooltip when available. This is disclosure only; the trade has already completed. No action is required.
Configuration Sources#
| Setting | What it controls | Where to configure | Priority |
|---|---|---|---|
maxspread_pips in the signal | Spread gate pips limit for that specific trade | TradingView alert body | 1st (overrides dashboard) |
maxspread_pct in the signal | Spread gate percent limit for that specific trade | TradingView alert body | 1st (overrides dashboard) |
| EA Settings dashboard (global or per-license) max_spread_pips / max_spread_pct | Spread gate defaults when signal omits those fields | EA Settings page | 2nd (applies when signal omits them) |
marketprice in the signal | Reference price for Mode A; controls which mode runs | TradingView alert body | Signal-only; no dashboard equivalent |
Data Flow Summary#
- TradingView fires an alert and posts the payload to your webhook URL.
- The platform validates the slippage-related parameters in the payload. If any are out of range or malformed, the signal is rejected immediately and the reason is recorded in Signal Logs under Rejected Signals.
- For a valid signal, the platform records the parsed parameters and delivers the signal to the EA over the WebSocket connection.
- The EA evaluates the spread gate using live MT5 price data. If the gate fails, the order is not submitted and the EA sends a rejection acknowledgment back to the platform. The platform records the rejection on the Signal Logs row as a "Trade rejected" amber pill.
- If the gate passes, the order is submitted to the broker with the configured execution tolerance. MT5 handles the actual fill.
- For close commands, the EA completes the fill (regardless of spread or tolerance), then measures the fill deviation. If the deviation is significant, the acknowledgment includes the slippage measurement, and the platform renders the "Extreme volatility" badge on the Signal Logs row.
User-Facing States#
| State | What it means | Impact |
|---|---|---|
| Signal accepted, trade executed normally | All spread gate conditions passed, fill was within tolerance | No badge on the Signal Logs row |
| Signal accepted, trade rejected by spread gate | Signal parsing succeeded but the EA's spread check failed at order time | Amber "Trade rejected" pill on the Signal Logs row (signal row is not in Rejected Signals tab) |
| Signal rejected at ingest (malformed parameter) | A slippage-related parameter was out of range or non-numeric | Row appears in Signal Logs → Rejected Signals tab with the offending field highlighted in red |
| Close completed with extreme slippage | A close command executed with significant fill deviation | Amber "Extreme volatility" badge on the Signal Logs row; trade has already completed |
Error Messages and Meanings#
Group A: Validation Errors (signal rejected at ingest)#
These messages appear in Signal Logs → Rejected Signals tab and are also returned to TradingView as the HTTP 400 response body. Two preconditions apply: the platform must have been able to extract a valid license key from the payload to create the row, and very long messages are shortened.
| Message (as shown in Rejected Signals) | Cause | What to do |
|---|---|---|
maxspread_pips={value} out of allowed range [0.0, 100000.0] | The value submitted for maxspread_pips is negative or exceeds 100,000 | Correct the value in the TradingView alert body. Valid range is 0 to 100,000. |
maxspread_pct={value} out of allowed range [0.0, 100.0] | The value submitted for maxspread_pct is negative or exceeds 100 | Correct the value. Valid range is 0 to 100. Remember this is an absolute percentage (0.05 = 0.05%, not 5%). |
marketprice={value} out of allowed range [0.0, 1000000000.0] | A negative value, or a value above 1,000,000,000, was submitted for marketprice | Use 0 to disable stale-signal checking or supply a valid positive reference price (up to 1,000,000,000). |
Invalid value '{value}' for {param} - must be a finite number | A slippage parameter was set to infinity, NaN, or a non-representable float | Replace with a valid finite number. |
Invalid value '{value}' for {param} - non-ASCII characters not allowed | The parameter value contained non-ASCII characters (e.g. fullwidth digits, Unicode minus sign) | Use plain ASCII numerals and a standard minus sign. |
Group B: Trade Execution Rejections (trade blocked by the spread gate)#
These appear on the Signal Logs page as an amber "Trade rejected" pill on the signal row (not in the Rejected Signals tab; the signal itself was valid). Expanding the pill shows the observed value, the configured limit, the source of that limit (signal-level or dashboard default), and the live MT5 symbol metadata.
| Pill text | Cause | What to do |
|---|---|---|
| "Trade rejected: Broker spread exceeded your pips limit" | The broker's raw Ask-Bid spread (Mode B, no marketprice set) exceeded maxspread_pips | Check the observed value shown in the expanded pill. If the observed spread is consistently above the limit during normal trading, raise maxspread_pips. If this only happens during news or off-hours, the limit is working as intended. |
| "Trade rejected: Broker spread exceeded your percent limit" | Same as above but for the maxspread_pct check | Same resolution. The observed percentage is shown in the expanded pill. |
| "Trade rejected: Price moved too far from the alert reference (pips)" | Mode A only. The live price diverged from marketprice by more pips than maxspread_pips. The signal was stale or the market moved sharply. | Check the "Marketprice (TV)" and "Reference price" rows in the expanded pill to see the exact gap. If the signal was actually stale, this rejection prevented a bad fill. If the gap looks wrong, the marketprice value in the TradingView alert may not be capturing the current price correctly. |
| "Trade rejected: Price moved too far from the alert reference (percent)" | Same as above but for the maxspread_pct check | Same resolution. |
Group C: Post-Fill Disclosure (close commands only)#
This appears on the Signal Logs page as an amber "Extreme volatility" badge on the close signal's row. It is informational only; the trade has already completed.
| Badge text | Meaning | What to do |
|---|---|---|
| "Extreme volatility: X.X pips slippage" | The close fill price deviated significantly from the price snapshot at the time the close command was sent. This is typical during fast markets or news events. | No action needed. Hovering the badge shows the full detail including pips, points, and the reference price. If you're concerned about fill quality, review your broker's execution logs. |
Where to look#
| Problem | Where to look |
|---|---|
| "My signal didn't fire" or "TradingView shows an error" | Signal Logs → Rejected Signals tab. Look for the row with the offending field highlighted in red. |
| "My signal shows as accepted but the trade didn't execute" | Signal Logs → the signal row itself. Look for the amber "Trade rejected" pill. Expand it to see observed vs limit values. |
| "I see a yellow/amber badge on a close" | Signal Logs → the close signal row. Hover the "Extreme volatility" badge for the fill deviation detail. |
| "My TradingView alert says the webhook returned an error" | Signal Logs → Rejected Signals tab for validation errors, OR the signal row's Trade rejected pill for gate rejections that return a non-200 ACK. |
Plan and Tier Differences#
Slippage protection is available on all plans with no behavioral differences between Standard, Pro, and Premium.
| Feature | Standard | Pro | Premium |
|---|---|---|---|
Spread gate (maxspread_pips and maxspread_pct) | Available | Available | Available |
Mode A stale-signal protection via marketprice | Available | Available | Available |
| Extreme slippage disclosure on close commands | Available | Available | Available |
| Dashboard default spread settings (global and per-license) | Available | Available | Available |
Known Edge Cases and Gotchas#
-
maxspread_pips=0andmaxspread_pct=0disable the check; they do not reject all trades. Setting a signal limit to 0 (or omitting it) makes that check fall back to your dashboard default. If the dashboard default is also 0, the check is disabled; if a non-zero dashboard default is set, that value still applies and the trade can be rejected as a dashboard default. To force a check off regardless of dashboard settings you must also set the dashboard value to 0. Use a very small positive value (e.g.0.001) to effectively block all trades for testing. -
marketprice=0disables Mode A and switches to Mode B. Some TradingView alert templates hard-codemarketprice=0as an explicit "no reference" signal. This is valid and generates no warning. -
Close commands never run the spread gate.
closeall,closelong,closeshort, and other close variants always execute.maxspread_pipsandmaxspread_pctin a close signal are parsed and stored but have no effect on execution. The "Extreme volatility" badge is post-fill disclosure, not a gate. -
Pending orders (buylimit, buystop, selllimit, sellstop) do run the spread gate. Slippage protection is not limited to market orders. The EA evaluates spread conditions before submitting any order type, including pending orders.
-
When both pips and pct limits are set, the pips check is evaluated first. If the pips check fails, the pct check is not evaluated. The rejection pill shows whichever condition failed first.
-
Dashboard defaults apply when the signal omits the field or sends 0. If a signal includes
maxspread_pips=5, that value is used regardless of what is configured on the dashboard. The expanded reject pill shows the source label ("signal-level" vs "dashboard default") so you can see exactly which value triggered the rejection. -
Recommended starting values for spread limits, by instrument type:
Instrument type maxspread_pipsmaxspread_pctForex 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 based on your broker's typical spreads and your strategy's sensitivity to price variation.
Frequently Asked Questions#
Q: Why was the slippage parameter removed?
A: It overlapped with the spread gate. Both features rejected fills that drifted too far from the expected price, just at different layers (the spread gate runs before order submission; slippage tolerance ran during fill). Keeping both meant two competing settings for one effect, which confused users. The spread gate (maxspread_pips, maxspread_pct, marketprice) now handles all user-configurable execution protection. MT5's CTrade library applies its own internal default deviation on open orders, which is sufficient for normal market conditions.
Q: My trade executed but the fill price was worse than I expected. Is there anything I can do?
A: Configure marketprice plus maxspread_pips (or maxspread_pct) in your TradingView alert. The spread gate will reject signals where the live price has drifted too far from the strategy's reference price, preventing bad fills before they happen. See the Mode A section above.
Q: Should I use maxspread_pips or maxspread_pct?
A: For forex, pips is the more intuitive unit and easier to tune from experience. For instruments priced very differently (indices, crypto, exotic pairs), pct is more stable since a "1 pip" equivalent means very different things across instruments. Using both gives complementary protection: one in absolute pips and one relative to price. When both are set, both must pass.
Q: My trade fires correctly on TradingView but Signal Logs shows "Trade rejected: spread too wide." Why does TradingView show success? A: TradingView's alert shows a green result when your webhook URL returned an HTTP 200 response, meaning the signal was valid and accepted by the platform. The spread gate runs later, on the EA side, using live MT5 price data. The rejection happens inside the EA and is reported back to the platform after TradingView has already shown success. Check the amber "Trade rejected" pill on the signal row in Signal Logs for the specific reason and the observed vs configured limit.
Q: Does the spread gate run on pending orders? A: Yes. The EA evaluates spread conditions before submitting any order type, including limit orders (buylimit, selllimit) and stop orders (buystop, sellstop). The check uses the live market price and spread at the moment the signal is processed, not the pending order's target price.
Q: Why does my close command show an "Extreme volatility" badge? A: Close commands always execute regardless of spread or slippage conditions, by design: failing to close an open position would expose the account to risk. The badge discloses that the fill price differed significantly from the price when the close command was sent. This happens during fast markets and news events. No action is needed; hovering the badge shows the full detail.
Q: I set marketprice in my signal but trades are still rejecting with "Price moved too far." How does the EA get the reference price?
A: The EA uses live MT5 bid/ask data at the moment it processes the signal, not a cached price from when the signal was queued. If there is a delay between when TradingView fires the alert and when the EA processes it (due to network lag, a WebSocket reconnect, or a large signal queue), the live price may have moved significantly from the marketprice value. The exact values are visible in the expanded reject pill (Marketprice TV vs Reference price). If rejections happen during brief disconnects, review the EA's connection stability in the MetaTrader Experts tab.