Market Regimes
How Forven classifies markets into four regimes — TREND_UP, TREND_DOWN, RANGE_BOUND, HIGH_VOL — and gates each strategy to the conditions it was built for.
A market regime is Forven's label for the condition a market is in right now: trending up, trending down, ranging, or violently volatile. Forven detects the regime from price structure, then uses it as a gate — a strategy only takes trades in the regimes it declares it can handle. This keeps a mean-reversion strategy from fighting a strong trend, and a breakout strategy from churning in a flat range.
This page is for users who want to understand how regimes are detected and how they shape backtests and promotion. Developers writing strategies should also read writing custom strategies to learn how to declare compatible_regimes.
The four regimes
Forven classifies every market into one of four regimes:
| Regime | Meaning | Rough trigger |
|---|---|---|
TREND_UP | Sustained upward trend | ADX above 25 with bullish EMA alignment |
TREND_DOWN | Sustained downward trend | ADX above 25 with bearish EMA alignment |
RANGE_BOUND | No clear direction; mean-reverting | ADX below 25, mixed EMA alignment |
HIGH_VOL | Elevated volatility regardless of direction | ATR ratio above 2.0 |
The triggers above are the classifier's broad logic, not exhaustive rules. Treat the thresholds as the engine's current defaults, not promises — they are tunable and may change.
How detection works
The regime detector reads four classic indicators off recent price history and combines them into a single label plus a confidence score:
- ADX — trend strength. High ADX means a directional market; low ADX means a range.
- EMA alignment — the relative order of fast and slow exponential moving averages, which gives the trend's direction.
- ATR ratio — current volatility against its baseline. A high ratio flags a
HIGH_VOLregime. - RSI — momentum, used to corroborate direction and exhaustion.
On a cache miss the detector fetches roughly 300 bars, computes the indicators, and classifies the regime. The result is cached for 5 minutes so repeated lookups on a hot path stay cheap. Each detection returns the regime, a confidence value, and the underlying adx, ema_alignment, atr_ratio, and rsi readings for telemetry.
A low-confidence reading — for example ADX near 18 with mixed EMAs — is reported as RANGE_BOUND with a confidence around 0.3. That is by design: when the market gives no clear signal, the safe default is "no trend".
Caveat: detection is synchronous and a cache miss fetches data, so a cold lookup can briefly stall its caller. Internally, latency-sensitive paths read a cached-only peek that returns nothing on a miss instead of fetching.
Regime gating
Detection on its own is just a label. Gating is where it does work.
Every strategy declares a compatible_regimes list — for example [TREND_UP, RANGE_BOUND]. Two things consume that list:
In backtests
When a strategy runs through the backtest engine with regime gating enabled, Forven pre-computes the regime for every bar and then:
- blocks entries on bars whose regime is not in the strategy's
compatible_regimes, and - forces an exit if the regime changes to an incompatible one mid-trade.
This means a backtest measures the strategy only where it claims an edge, not across conditions it was never meant to trade. The per-bar regimes also drive the colour shading you see behind the candles on a backtest chart.
Beta rough edge: regime pre-computation needs a warmup. Short windows under roughly 210 bars cannot establish a stable regime and default the whole window to
RANGE_BOUND. Backtest long enough to give the classifier real history.
At promotion
Promotion gates — and the live signal scanner — call regime detection before advancing or acting on a strategy. The gate fetches the strategy's compatible_regimes and compares them to the detected regime. The behaviour depends on your gating mode:
- Strict mode blocks a strategy that is incompatible with the current regime, and also rejects detections below your minimum confidence.
- Permissive mode warns instead of blocking.
Some examples of the policy in practice, from the engine's defaults:
- A mean-reversion strategy is blocked when ADX is above 25 (the market is trending, so reversion is the wrong tool).
- A trend-following strategy requires ADX of at least 20 before it is allowed to act.
The promotion gates themselves — fitness scoring, the metrics that feed them, and the full walk-forward gauntlet — are documented separately. Regime compatibility is one input among several.
Per-regime metrics
Because regimes are computed per bar, the backtester can slice your results by regime. Alongside the usual metrics, a backtest produces a by_regime breakdown — performance split across trend_up, trend_down, range_bound, and high_vol. Reading this breakdown tells you whether a strategy's edge is real and broad, or whether it is leaning on a single lucky regime. Prefer out-of-sample numbers over in-sample ones; in-sample metrics are optimistic by construction.
Forven is a research tool. Backtest and regime metrics describe the past on historical data; they are not predictive of future results, and nothing here is financial advice.
Configuration
Regime gating is governed by a small set of settings (found under Settings; precedence is environment variable, then key-value store, then config.json, then defaults):
| Key | Meaning | Default |
|---|---|---|
regime_min_confidence | Minimum confidence [0.0–1.0] for a detection to pass the gate. Raise it for stricter gating. | 0.3 |
strict_regime_gating | When true, block incompatible strategies and low-confidence detections. Permissive when false. | — |
allow_unknown_regime_strategies | When true, allow strategies that declare no regime compatibility. Blocked in strict mode when false. | — |
Raising regime_min_confidence above the floor has a sharp consequence worth knowing: a valid but low-confidence label (such as a quiet RANGE_BOUND reported at 0.3) will be rejected in strict mode. Tune it to your risk appetite rather than maxing it out.
Where you see it
The detected regime surfaces in the UI on the /strategies view and in the backtester's status pane. On a backtest chart, regimes appear as colour-coded shadings behind the price — one colour per TREND_UP, TREND_DOWN, RANGE_BOUND, and HIGH_VOL — so you can see, at a glance, which conditions a strategy was trading in when it won or lost.
Steps: gate a strategy to its regimes
- In your strategy, declare the regimes it is built for via
compatible_regimes— see writing custom strategies. Built-in strategies already declare theirs. - Decide your enforcement: set
strict_regime_gatingto block incompatible strategies, or leave it permissive to warn only. - Set
regime_min_confidence(default0.3). Raise it if you want the gate to reject ambiguous, low-confidence regimes. - Run a backtest with regime gating enabled. The engine pre-computes the per-bar regime, blocks out-of-regime entries, and forces exits on mid-trade regime flips.
- Read the
by_regimebreakdown in the result to confirm the edge holds where you expected it — and only there.
What you'll see: the backtest result includes a by_regime metrics slice and, on the chart, colour-coded regime shadings behind the candles. A gated strategy will show no entries during regimes it is incompatible with.
Related
- The gauntlet — the full robustness battery a strategy must survive.
- Metrics — every number a backtest computes, including the
by_regimeslice. - Writing custom strategies — how to declare
compatible_regimeson your own strategy.
Hypothesis-driven research
How Forven organizes research around market hypotheses that spawn strategies, judges them by hit-rate and diversity, and graduates only the proven.
Metrics
Every metric Forven computes on a backtest, what it means, the reliability flags that suppress false confidence, and why you trust out-of-sample.