Strategies
EURUSD 1H London-Session 2-Sigma Band Fade: short above / long below a 20-bar mean +/- 2 std, exit at the mean, after 12 bars or at a 1.5x ATR(20) intrabar stop (FX venue, long+short, 1.5x cap)
Outcome: Live
EurusdLondonBandFade
Outcome Summary
EurusdLondonBandFade was a faithful port of a user's EURUSD 1-hour London-session 2-sigma band-fade rule. In its single iteration the full backtest lost 6.78% (Sharpe -0.66, 500 trades, average -0.0088% of notional), and it lost most heavily in stressed volatility regimes. The backtest review found no reversion edge even before costs and voted abandon, so optimization and the later reviews never ran. The pipeline still records the final stage as live_stage, which conflicts with that abandon verdict and should be checked.
Hypothesis
Implementation
EURUSD.FX 1-hour fade of 20-bar 2-sigma bands during London hours. On a closed bar inside 07:00-16:00 Europe/London (the bar opens at 07:00 or later and closes at 16:00 or earlier; DST-aware via zoneinfo), a close above mean+2*pop-std opens a short and a close below mean-2*pop-std opens a long. Exits come from whichever happens first: a closed bar back at or through the current 20-bar mean, 12 bars after the entry fill (market orders, filled at the next bar's open on the FX session venue), or a reduce-only intrabar stop placed on the entry fill at fill -/+ 1.5*Wilder ATR(20) (submit_stop_order, crossed_policy=market). Sizing: notional = min(0.5% * equity / (1.5*ATR/close), 1.5 * equity), in whole EUR units, with a 1,000-unit minimum.
Faithful implementation of the settled rule. calculate_signal returns the continuous z-score (close-mean)/sd, and should_enter thresholds it at +/-band_k, which is the same as comparing the close with the bands. Session gating applies to entries only. A protective stop is placed from on_order_filled using the ATR of the signal bar; the base cancels it on a mean or time exit, and on_position_closed records the exit time so no entry happens on the bar an exit occurred. Risk route (a): with the 1.5x leverage cap binding (0.5%/stop% is usually above 1.5x), the loss at the stop is about 1.5 x 0.2-0.3% = 0.3-0.45% of equity, under 2%. All state is held in scalar attributes. The ATR is incremental, and the mean and std use only the last lookback bars (bounded). Execution substitutions follow the registry: next_open_fill for market orders and a platform-matched intrabar stop instead of an exchange-resting order. Risk noted: the expected average trade is close to the 0.10% FX analyst floor.
Verification Results
No code change needed. Note that the first-bar stop coverage depends on the platform's session-stop switch.
The protective stop is placed in on_order_filled while the entry fills at the next bar's open. Per src/backtesting/next_open.py, without SF_SESSION_STOP_FILLS an order sent at the open is released only after bar N+1's range has been matched, so in the entry bar itself the stop is tested only against that bar's close. This is platform behaviour, not a strategy defect. The stop protects from the second bar onward either way.
Optional: none required.
Wilder ATR updates only start once the base begins calling calculate_signal (after min_bars_required = 21 bars). The first true range has no previous close, so it falls back to high-low. The ATR seeds about 20 bars later than strictly necessary. This is harmless: the evaluation warmup is 60 bars and entries are gated on atr_value > 0.
Expected gross capture (~0.12-0.2% per trade by the hypothesis's own arithmetic) is close to the 0.10% FX analyst floor. The mean target is the moving 20-bar mean, which drifts toward price, so per-trade capture shrinks. About 1,000 sandbox trades in 735 days means roughly 1.4 trades per day. The analyst should check whether avg_trade_return_pct clears the floor after carry on trades held across the 17:00 New York roll.
Backtest Review
- Sharpe
- -0.66
- Total return
- -6.78%
- Max drawdown
- 11.44%
- Trades
- 500
- Win rate
- 40.2%
- Profit factor
- 0.90
The code does what the user's rule says: London-session gate (DST-aware), 20-bar population-std bands, entries against the move, exit at the mean, a 12-bar clock, a reduce-only 1.5x ATR stop, and risk-sized notional capped at 1.5x. Trades are balanced (201 long, 194 short) and entered on band breaches, as the hypothesis predicts.
The sample is reliable: 395 closed trades over the development period (to 2026-06-05), clean input audit, metrics_reliable true.
Risk control works: largest loss is $572 (about 0.57% of equity) and max drawdown is 10.2%, inside the pre-registered 15% limit.
Net expectancy is negative. Average trade return is -0.008% of notional against the 0.10% FX floor, profit factor 0.91, Sharpe -0.65, total return -5.7%, and 2025 and 2026 are both losing years.
The edge is not positive even before costs. Price PnL summed over the ledger is about -$2.9k, a mean gross of about -0.004% per trade. Commission ($4.0k) and overnight carry ($2.4k) add losses on top. Fees are not what kills this strategy: the fade itself has no reversion edge.
The QA concern is confirmed. The hypothesis expected about 0.12-0.2% gross capture per trade; the measured capture is around zero. Short fades do worst, with a 35% win rate, which fits band walks continuing rather than reverting.
Outcome Summary
Hourly EURUSD 2-sigma band breaches in the London session did not revert enough to give any gross edge, and short fades were worst (36% win rate), so a fade needs a regime or trend filter before costs are even relevant.
At backtest review the analyst voted abandon before optimization: the fade lost money even before costs (gross price PnL about -$2.9k, or roughly -0.004% per trade), so fees were not the cause. The record nonetheless shows a final stage of live_stage, with no optimization, analyst, risk-officer or abandon-reason record; the input does not explain this mismatch.
A user-submitted EURUSD 1-hour mean-reversion fade on the FX venue: during the London session it shorted closes above a 20-bar mean + 2 std and bought closes below mean - 2 std, exiting at the mean, after 12 bars, or at a 1.5x ATR(20) stop, with risk-sized notional capped at 1.5x leverage.
Over the full backtest (2024-10-30 to 2026-10-30) it lost 6.78% with a Sharpe of -0.66 across 500 closed trades: 40.2% win rate, profit factor 0.90, average trade -0.0088% of notional (against a 0.10% FX floor), and 11.4% max drawdown. Commission was $5,033 and overnight carry about $2,960; the signal diagnostic found no information (IC 0.004, t=0.1).
Backtest and paper results are hypothetical. Trading involves risk of loss.