RegimeRouter — trend/range classifier with a per-regime win rate ledger

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.
On every closed bar it measures three independent properties of the recent price series.
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.
| 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. |
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.
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.
H1 · 2026.01.01 to 2026.09.20 · 10 000 USD · Random delay enabled · all inputs at default. Two symbols, both shown.
| 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.
| 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.
Read this part before you use it.
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.
| 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 |
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.
PropFirm Equity Protector – Institutional Risk Manager (Open Source)
Professional Utility EA for prop firm risk management. It features daily equity monitoring, phased mitigation of losing positions, and absolute hard stops via a self-healing graphical dashboard.