Regime Detection
π¦ AthenaAI is an AI-powered ensemble machine-learning trading bot for PocketOption, built on BinaryOptionsToolsV2 β Get it on GitLab
π¬ Need help? Join the Chipa Discord Β· β‘ Go no-code with ChipaEditor
RegimeDetector (in src/core/regime.py) classifies the current market into one of four regimes on every trade-loop iteration. The regime label feeds three consumers:
- the expiry selector (trending β longer expiries, volatile β shorter),
- the adaptive strategy (per-regime win-rate tracking and blocking),
- the optional volatile-regime skip gate in the signal pipeline (
skip_volatile_regime, off by default).
The four regimes
Defined in src/utils/enums.py and returned by RegimeDetector.detect:
| Regime | Meaning |
|---|---|
VOLATILE | Return volatility is high β choppy, reversal-prone market |
TRENDING_UP | Clear upward price drift |
TRENDING_DOWN | Clear downward price drift |
RANGING | None of the above β sideways / quiet market (also the default when there is not enough data) |
The algorithm
detect(candles, window=30) is a single static method β there is no state to persist. The window comes from BotConfig.regime_window (default 30; see regime-window).
-
If fewer than
windowcandles exist, returnRANGINGimmediately. -
Take the closes of the last 30 candles and compute per-bar fractional returns:
rets = np.diff(closes) / (closes[:-1] + 1e-10) -
Fit a straight line through the closes (
np.polyfit(arange, closes, 1)); the slope is the raw trend in price units per candle. -
Compute vol =
np.std(rets)β the standard deviation of returns (a dimensionless fraction). -
Normalize the trend so the threshold is price-level independent:
rel_trend = trend / (closes[-1] + 1e-10) * windowDividing by the last close converts the slope to a fractional change per candle; multiplying by
windowscales it to the fractional change over the whole 30-candle window. Sorel_trend = 0.0003means the fitted line moved about 0.03% of the price level (~3.5 pips on EURUSD at 1.17) across the window. -
Classify, in this order (volatility wins over trend):
if vol > 0.0008: return Regime.VOLATILE if rel_trend > 0.0003: return Regime.TRENDING_UP if rel_trend < -0.0003: return Regime.TRENDING_DOWN return Regime.RANGING
| Check | Threshold | Regime |
|---|---|---|
| 1st | vol > 0.0008 (0.08% per-bar return std) | VOLATILE |
| 2nd | rel_trend > 0.0003 (+0.03% over the window) | TRENDING_UP |
| 3rd | rel_trend < -0.0003 | TRENDING_DOWN |
| else | β | RANGING |
Because the volatility check comes first, a strongly trending but very choppy market is labeled VOLATILE, not trending.
Calibration note: 1-minute EURUSD
The thresholds are a v6 recalibration specifically for 1-minute EURUSD candles. The code comment records that the old values (0.005 for volatility, 0.002 for trend) were far too aggressive at this timeframe β per-bar volatility on 1-minute EURUSD almost never reaches 0.5%, so effectively every candle window was classified RANGING and the regime-dependent logic (expiry scoring, adaptive blocking) never differentiated.
If you trade a different asset or timeframe, expect to re-tune these constants: higher-volatility assets (crypto, indices) or longer timeframes produce larger per-bar returns and will read VOLATILE almost constantly with the current 0.0008 cutoff. The thresholds are hard-coded in src/core/regime.py β there is no environment variable or config field for them.
Relationship to the volatility feature
The regime detectorβs vol is the same quantity as the feature engineβs volatility feature (index 6), but computed over a different window: the regime uses regime_window (30 candles) while the feature uses feature_window (20 candles). The expiry selector reads the 20-candle feature value with its own thresholds (0.003 / 0.001), independent of the regime label it also receives.
See also
- Signal gates β where the volatile-skip gate sits in the pipeline
- Adaptive strategy β how losing regimes get blocked
- Expiry selection β how regime shapes expiry choice
- skip-volatile-regime, regime-window
- API reference: src.core.regime
π‘ Want to discuss how AthenaAI makes decisions β or design your own logic like this without writing code? Join the Chipa Discord and give ChipaEditor a try.