**Research disclosure:** This article documents a real, working research build — not a
profit claim. The system described here reached a **profit factor of 0.53** in the best
backtest, which means it was still losing money at the time of writing. We publish it
honestly so other quant researchers can learn from the architecture *and* the failures.
What "MTF RVOL" Actually Means
MTF RVOL stands for **Multi-Timeframe Relative Volume**. The idea is simple: volume tells
you when participants are committed. Relative volume (RVOL) compares today's volume at a
bar to its 20-bar average. When RVOL spikes, something is happening. When it stays flat,
the bar is noise.
The "MTF" part adds context: a 15-minute signal only matters if the 1-hour and 4-hour
trends agree. A buy signal on a 15m bar while the 4h trend is down is a trap waiting to
happen.
The Data Engine (85+ Features)
The build pulls NIFTY 15-minute OHLCV bars (7,067 bars) from a DuckDB store, plus:
From these, the feature engine computes **117 columns** across 12 families:
1. **Price action (25 cols):** rvol, ATR(14), effort = `rvol × (close−open)/range`,
close location, wick bias, range high/low, accept/retest/failed-auction flags.
2. **Microstructure (12):** close quality, inside-bar breaks, velocity, trend, pressure.
3. **Order flow (10):** harmony, efficiency ratio, absorption (up/down), aggressive/passive flow.
4. **Operator analysis (4):** expand/absorb signals.
5. **S/R & breakout (6):** sr_score [0-100], break_prob [5-95], bull/bear power, trap_risk.
6. **Time (2):** hour_sin, hour_cos (cyclic encoding).
7. **Lag (6):** prev_return_1/3/5, prev_vol_1/3/5, prev_range_1/3/5.
8. **Multi-timeframe (4):** h1 close vs SMA, range ratio, vol ratio, h1 trend.
9. **Volatility regime (3):** vol_regime, contraction, expansion.
10. **Side score (12):** alignment, active side, CE/PE trade scores, gate states.
11. **Options (3):** pc_vol_ratio, pc_oi_ratio, total_premium.
12. **Operator anchor (12):** anchor scores, accept zones, liquidity levels, state codes.
Triple Barrier Labeling
Three label variants were tested, each long-only with `-1` = loss, `0` = no-trade, `+1` = win:
| Variant | SL | TP1 | TP2 | +1 / −1 / 0 |
||||||
| label_atr | 0.6 ATR | 1.8 ATR | 3.0 ATR | 18.6% / 65.8% / 15.7% |
| label_sr | range_low | range_high | — | 37.2% / 37.7% / 25.1% |
| label_blended | min(0.6ATR, range_low) | max(1.8ATR, range_high) | — | 23.3% / 41.3% / 35.4% |
The class imbalance is severe — most bars are "no-trade." This is realistic but makes
training hard.
Model Architecture
A single XGBoost (regression + classification) with Optuna tuning. Config:
`TRAIN_PCT=0.60, VAL_PCT=0.20` (60/20/20 split by time), CUSUM filter on training only,
`MAX_TRADES_PER_DAY=2`, regression top-20% quantile threshold.
**Regression results:** test correlation 0.031, but the **top-10% decile achieves +7.63%
average forward return at 60.5% win rate.** That is genuine directional skill — the model
knows which bars will move.
**Classification (label_sr):** Precision 0.427, Recall 0.827, F1 0.563 — the best of the
three.
The Brutal Part: Direction ≠ Profit
Here is the honest result. The regression model predicts direction at **60.5% accuracy in
the top decile**, yet the best backtest only reaches **profit factor 0.53** (win rate 15.4%,
avg R:R exactly 3.0).
Why? **Market microstructure, not prediction.** With a fixed 0.6/1.8 ATR stop/target, price
tags the stop before it reverses to the target. The average R:R is 3.0 (matching config), but
you need a ~25% win rate to break even at 3:1 — and the system only wins 15.4%.
This is the single most important lesson: *a model that is right about direction can still
lose money if the exit logic fights the path.*
Bugs We Actually Hit (So You Don't Have To)
1. **25-bar label shift:** `build_feature_matrix()` trimmed 25 rows but kept the old index,
shifting labels by 25 bars. Fixed PnL went from −42% to a more honest −6.26%.
2. **Ensemble meta-model mismatch:** dimension errors killed the ensemble (F1=0 on val).
Disabled.
3. **"Walk-forward" that wasn't:** the pipeline printed "walk-forward" but used a single
fixed split. A true walk-forward would retrain on rolling windows.
4. **max_hold mismatch:** labels used 6 bars, backtest used 8 — silent label/backtest
inconsistency.
5. **Hold exit forced loss:** `min(close, entry*0.998)` turned profitable holds into losses.
Where This Goes Next
To push PF above 1.0: widen SL to 1.0 ATR, use dynamic/trailing stops, re-enable the
ensemble, add online learning, and use the full options surface (skew, IV term structure).
The Takeaway
MTF RVOL Pro is a **real, reproducible research system** with honest results. It proves
directional edge exists (60.5% top-decile accuracy) but also proves that edge alone is not
enough. If you are building your own NIFTY ML system, start from the feature engine and the
label design — and respect the stop-loss math before trusting any directional model.
*This is research only. Not investment advice. Past results do not predict future performance.*