Rejoignez notre page de fans
RegimeRouter — trend/range classifier with a per-regime win rate ledger - expert pour MetaTrader 5
- Vues:
- 109
- Publié:
-
Besoin d'un robot ou d'un indicateur basé sur ce code ? Commandez-le sur Freelance Aller sur Freelance
RegimeRouter — trend/range classifier with a per-regime win rate ledger

The problem
A trend-following rule loses money in a range. A mean-reversion rule gets destroyed in a trend. Most EAs pick one and hope the market cooperates. The usual fix is a single ADX filter. ADX measures one thing, directional strength, and says nothing about whether returns are actually persistent or mean-reverting.
How it classifies
On every closed bar it measures three independent properties of the recent price series.
- ADX — classic directional strength.
- Hurst exponent — rescaled range (R/S) analysis of log returns. Above 0.5 the series is persistent. Below 0.5 it is anti-persistent. At 0.5 it is a random walk.
- Lag-1 autocorrelation — whether a move tends to be followed by another move the same way, or by a snap back.
Each casts a vote. Plus one for trend, minus one for range, zero for undecided. The votes are summed. If the sum clears InpMinVotes in either direction the regime is TREND or RANGE. Otherwise it is NEUTRAL and the EA does not trade at all. If any one of the three cannot be computed it does not vote and the bar is NEUTRAL. Requiring agreement is the point. One indicator alone is a coin flip with extra steps.
How it routes
| Regime | Module |
|---|---|
| TREND | Break of the N-bar high or low, taken only in the direction the fast and slow EMA are already pointing. |
| RANGE | Fade a stretched z-score of price against its own moving average. Buy the low tail, sell the high tail. |
| NEUTRAL | Nothing. |
The ledger
Every position is opened with a magic number of InpMagicBase plus the regime id, so the regime that produced a trade is stamped on the trade itself. On startup the EA walks the deal history, groups deals by position id, and rebuilds the record. It survives a restart and it survives being moved to another terminal.
For each module it reports the raw win rate, the Wilson 95% lower bound, the breakeven win rate implied by that module's own average win and average loss, the profit factor, and a verdict.
TREND 96 tr 38 W raw 39.6% wilson95 30.4% breakeven 34.2% PF 1.26 net +734.84 [UNPROVEN]
The middle two numbers are the ones that matter. A 2R trend follower is profitable above roughly 34%. A 1R fade needs better than 50%. And a raw win rate from six trades is not evidence of anything. The verdict is simply whether the lower bound clears breakeven, which is the only version of "this module works" that survives a small sample.
The A/B switch
InpForceRegime disables the router and forces every trade through one module. Run the same symbol and the same period three times — AUTO, then ALWAYS_TREND, then ALWAYS_RANGE — and you get a direct measurement of whether the classifier is adding anything. The three readings are still logged in a forced run, so you can see how the forced module performed on the bars the router would have refused.
Do that before trusting it. The routing idea is a hypothesis, not a result.
Backtest
H1 · 2026.01.01 to 2026.09.20 · 10 000 USD · Random delay enabled · all inputs at default. Two symbols, both shown.
EURUSD H1
| Metric | Value |
|---|---|
| Total net profit | +900.42 |
| Gross profit / gross loss | 3 712.84 / 2 812.42 |
| Profit factor | 1.32 |
| Expected payoff | 9.00 |
| Recovery factor | 1.71 |
| Total trades | 100 |
| Maximal balance drawdown | 505.32 (4.56%) |
| Maximal equity drawdown | 527.80 (4.76%) |
| Module | Trades | Wins | Raw | Wilson 95% low | Net |
|---|---|---|---|---|---|
| TREND | 96 | 38 | 39.6% | 30.4% | +734.84 |
| RANGE | 4 | 4 | 100.0% | 51.0% | +165.58 |
96 + 4 = 100 trades and +734.84 + 165.58 = +900.42, so the ledger reconciles exactly against the tester report.
XAUUSD H1 — same EA, same settings, same period
| Metric | Value |
|---|---|
| Total net profit | −1 554.11 |
| Final balance | 8 445.89 |
| Total trades | 85 |
| Module | Trades | Wins | Raw | Wilson 95% low | Net |
|---|---|---|---|---|---|
| TREND | 78 | 26 | 33.3% | 23.9% | −1 576.33 |
| RANGE | 7 | 4 | 57.1% | 25.0% | +22.22 |
78 + 7 = 85 trades and −1 576.33 + 22.22 = −1 554.11. This one loses money. I am publishing it next to the winner on purpose, because a listing that shows only the symbol that worked tells you nothing about the EA.
What that result does and does not show
Read this part before you use it.
- The TREND module is not proven on either symbol. On EURUSD its average win was 93.35 and its average loss 48.49, so it needed about 34.2% of trades to win just to break even. It won 39.6%. But the Wilson 95% lower bound on that win rate is 30.4%, which is below breakeven. At this sample size the result is consistent with no edge at all. On XAUUSD the same module read 33.3% raw and 23.9% at the lower bound, and it lost money. That is the same verdict in both cases: not enough evidence yet.
- It would take roughly 320 trades at the EURUSD win rate for the lower bound to clear breakeven. One symbol on H1 produced 100 in about nine months, so that is a portfolio problem, not a longer-backtest problem.
- The RANGE module is essentially untested. Four trades on EURUSD, seven on XAUUSD. The 100% win rate on EURUSD means nothing, which is exactly why the Wilson column exists.
- There is no out-of-sample test. One period, one timeframe, two symbols.
- Modelling was "Every tick", not real ticks. Exits are left to the broker's SL and TP, so the intrabar path matters. Re-run it on real ticks before drawing conclusions.
I am publishing it because the measurement apparatus is the useful part, not because I have a validated edge to sell you. Run the A/B. If the router does not beat its own two modules on your symbol, that is worth knowing too.
Execution notes
- Signals are evaluated on bar close, so this is built for M15 and higher.
- Positions open with no stops, then the stops are attached from the real fill price. A stop computed from a pre-trade snapshot can already be invalid by the time the order fills.
- If attaching the stops fails the position is closed immediately rather than left unprotected.
- Stop distances are clamped to the symbol's own stops level and freeze level.
- Exits belong to the broker's SL and TP. There is no manual timed force-close.
- Optional ATR trailing stop for trend trades, applied at most once per bar and never on the entry bar.
- One position at a time. On a netting account a second order on the same symbol merges into the existing position instead of becoming its own trade, which would silently corrupt the ledger.
- Risk-based lot sizing, a daily loss limit, a daily trade cap, a spread filter, a minimum take-profit-to-spread ratio, and an optional session filter.
Main inputs
| Input | Default | What it does |
|---|---|---|
| InpForceRegime | Auto | Force one module, to A/B the classifier |
| InpMinVotes | 2 | Votes out of three needed to commit to a regime |
| InpADXTrendLevel / InpADXRangeLevel | 25 / 20 | ADX vote thresholds |
| InpHurstBars | 256 | Bars of returns behind the Hurst estimate |
| InpHurstAdaptive | off | Judge Hurst against its own distribution instead of fixed levels |
| InpAutoCorrThreshold | 0.05 | Autocorrelation must clear this to vote |
| InpBreakoutBars | 20 | Trend module: N-bar high/low to break |
| InpRangeZEntry | 2.0 | Range module: z-score at which to fade |
| InpRiskPercent | 0.5 | Risk per trade, % of balance |
| InpMagicBase | 772000 | Regime id is added to this |
Note on the Hurst threshold
There is an input called InpHurstAdaptive , off by default.
The textbook trend/range line for the Hurst exponent is 0.5. In practice that line is in the wrong place. The R/S estimator is biased upward on a finite sample, so a 256-bar estimate of an ordinary series lands well above 0.5. Measured on EURUSD H1 the readings averaged 0.568 and dropped below 0.45 only twice in 419 observations. Against a fixed 0.45 / 0.55 band that voter is not measuring anything. It is a near-permanent vote for TREND.
Turning InpHurstAdaptive on drops the absolute scale and asks a relative question instead: is the series more persistent than this symbol has recently been? The last N readings are kept and the vote is cast on percentiles of that history rather than on 0.5.
The cost of that is real. By construction the voter then votes RANGE on a fixed share of bars whatever the market is doing. So it is a switch, not a rewrite. It is off by default because the backtests above were run with it off, and I do not want the shipped default to be a setting I have no results for.
No strategy is guaranteed to be profitable. This gives you a structure to test with the measurement built in. It does not give you an edge.
— Ali Rajput
CSetupLedger: a per-setup win rate ledger for Expert Advisors
Scores every setup type in your EA on its own record instead of lumping them into one equity curve. Rebuilds itself from the account's deal history on init so a restart cannot wipe the record. Prints a Wilson score lower bound next to the raw win rate so a three trade hot streak stops looking like an edge.
Position sizing from risk, using the broker's own tick value and volume step
Position size from a risk amount, computed from the symbol's real tick value, tick size and volume step rather than an assumed pip value. It always rounds volume down, and when your risk is smaller than the minimum lot it says so and reports what that lot actually costs. No terminal state, so the sizing logic is testable offline - a 41-assertion test script is included.
One-Click Trade Manager — risk-based lot size with entry, stop and target in one click
Works out the lot from your risk percent and the stop distance, then opens the trade with the stop loss and take profit already attached. Never trades by itself.
MACD Signals
Indicator edition for new platform.
