Open methodology
How we classify EMA regime, count whipsaws, and call alignment.
No black box. Every formula and parameter is published below. We compute everything from EOD and intraday OHLCV; no proprietary feed, no hand-tuning per market session. The 5-year regime backtest is recomputed nightly from the same code path that drives the live site.
1 — Exponential Moving Average (EMA)
For a closing-price series P and length L:
EMAt = α · Pt + (1 − α) · EMAt−1
EMA0 = P0
We use pandas' .ewm(span=L, adjust=False), which produces the recursive form above. No lookahead.
2 — Regime classifier
Three conditions must agree for a directional regime call:
- EMA alignment: fast EMA > slow EMA (Bull) or fast EMA < slow EMA (Bear)
- Slow-EMA slope: |Δ over last 5 bars / |EMAt−5|| ≥ 5 bps
- Price position: close on the trend side of the fast EMA
If all three agree → Trending Bull/Bear. Otherwise → Ranging.
SLOPE_DN = −0.0005
if fast > slow and slope > SLOPE_UP and close > fast: → "Trending Bull"
elif fast < slow and slope < SLOPE_DN and close < fast: → "Trending Bear"
else: → "Ranging"
1-hour timeframe uses 20/50 EMA. Daily uses 50/200. These are the conventional pairs for those horizons on Indian indices.
3 — Whipsaw counter
A whipsaw is a fast/slow EMA crossover that reverses within min_bars bars
(default 3). For each pair of consecutive crossovers in the 30-day window, if the second flip lands within 3 bars
of the first, we count it as one whipsaw.
Window: last 30 calendar days, queried from our ohlcv Postgres table — not from a rolling Yahoo fetch.
EMA pair: 9/21. Bar size: 5-minute and 15-minute.
4 — Multi-timeframe alignment
Per timeframe, we compute fast and slow EMAs and call:
- Bull if fast > slow × 1.0002 (2-bps cushion)
- Bear if fast < slow × 0.9998
- Flat otherwise
The cushion stops EMAs that are within 2 bps of each other from flickering Bull/Bear/Bull every bar.
5 — Backtest of the regime classifier
For every historical day in our database, we classify the regime using the rules above, then measure the close-to-close return of the next day. The table below summarises forward returns by regime — a regime call has predictive value if the mean and win-rate differ across regimes.
NIFTY — daily, fast=50, slow=200
Sample: 2022-02-24 → 2026-04-29 · 1029 days
| Regime | N days | Mean fwd 1d return | Win rate | Std dev | t-stat |
|---|---|---|---|---|---|
| Trending Bull | 589 | +0.034% | 54.5% | 0.739% | 1.12 |
| Trending Bear | 97 | +0.141% | 49.5% | 1.205% | 1.15 |
| Ranging | 343 | +0.026% | 52.5% | 0.918% | 0.52 |
BANKNIFTY — daily, fast=50, slow=200
Sample: 2022-02-24 → 2026-04-29 · 1028 days
| Regime | N days | Mean fwd 1d return | Win rate | Std dev | t-stat |
|---|---|---|---|---|---|
| Trending Bull | 583 | +0.005% | 51.6% | 0.886% | 0.13 |
| Trending Bear | 69 | +0.178% | 56.5% | 1.380% | 1.07 |
| Ranging | 376 | +0.093% | 56.9% | 1.184% | 1.52 |
Caveats: forward-return statistics over a 5-year window include 2022's strong uptrend, 2023 chop, 2024 volatility, and 2025–26 mixed regime. Survivorship bias is not a concern (we use the index, not constituents). The numbers above are unconditional — no transaction costs, no slippage, no position sizing. They measure the information value of the regime call, not the P&L of any specific trading rule.
6 — Data and cadence
- Source: Yahoo Finance chart API (^NSEI, ^NSEBANK), accessed via
curl_cffiwith chrome TLS fingerprint to avoid WAF blocks on cloud IPs. - Cadence: refresh every 5 minutes. Each refresh persists fresh bars to
ohlcvand writes a snapshot row. - History: 5 years of daily bars, 2 years of hourly, 60 days of 15-minute and 5-minute. Backfilled on first start, then top-up only.
- Timezone:
Asia/Kolkatafor display, UTC for storage.