Do volume profile levels (POC, value area, HVN/LVN) work as support and resistance on NSE?
Short answer: On 9 months of 1-minute data for the 50 most liquid NSE stocks, profile levels held no more often than random prices.
Published 2026-10-30 · original backtest on Indian market data by TRINETRA
Date: 2026-10-30 · Script: engine/scripts/bench_orderflow_levels.py Data: Upstox 1-minute bars, the 50 most liquid NSE stocks by 20-session median turnover, 2 Feb → 29 Oct 2026 (~185 sessions each). Results in BENCH_orderflow_levels.json.
Verdict
No volume-profile level predicts support or resistance better than a random price. The apparent power of a "rejection on volume" at a level is mostly arithmetic. What remains is general intraday mean reversion that random prices share. Print-level delta and depth walls can't be tested from bars and have no history. TRINETRA now records them every session.
Design
- Levels for day D come only from data before D. The 5-session composite profile gives POC, value-area high/low, high-volume nodes and low-volume nodes. The prior session gives POC, VAH, VAL, high, low and VWAP.
- Placebo: 8 random prices per stock-day, drawn uniformly within the same prior 5-session range.
- For each level's first touch on day D: hold if price moves R away on the approach side before a bar closes R beyond; break otherwise. R = 0.3% and 0.5%. Unresolved touches are excluded.
- 95% intervals bootstrap trading dates, because touches on one day share the market.
1. Levels vs random prices (R = 0.3%)
| level | touches | hold | vs random | 95% CI |
|---|---|---|---|---|
| yesterday VWAP | 3,427 | 56.8% | +1.4 | −0.4 to +3.1 |
| yesterday value high | 3,123 | 56.2% | +0.8 | −1.1 to +2.8 |
| high-volume node | 18,078 | 56.1% | +0.7 | −0.3 to +1.8 |
| 5-day value high | 2,101 | 56.0% | +0.6 | −1.8 to +2.6 |
| low-volume node | 15,987 | 55.9% | +0.5 | −0.5 to +1.6 |
| random price | 15,956 | 55.4% | — | — |
| 5-day POC | 2,349 | 55.1% | −0.3 | −2.5 to +2.0 |
| yesterday POC | 3,157 | 55.1% | −0.3 | −1.9 to +1.5 |
| yesterday high / low | 2,650 / 2,783 | 54.2 / 53.8% | −1.2 / −1.6 | both span 0 |
| 5-day value low | 2,156 | 53.7% | −1.7 | −3.9 to +0.5 |
Every interval spans zero, and the 0.5% threshold gives the same picture. POCs sit slightly below random, consistent with a POC being where price spends time rather than a barrier.
2. The reaction at the touch
At R = 0.3%, a "rejection on volume" (touch bar closes back on the approach side, at ≥2× the volume of the 30 bars before it) holds 71% at profile levels against 48% for a plain touch. It looks like the order-flow edge. Then remove the arithmetic: the outcome window starts at the touch bar's close, and a rejection candle closes nearer the hold target. A random walk from distance x reaches +R before −R with probability (R + x) / 2R.
| touch type (R = 0.3%) | hold | random-walk expected | excess |
|---|---|---|---|
| profile level, rejection + volume | 71.0% | 66.5% | +4.5 (CI 3.1 to 5.9) |
| random price, rejection + volume | 68.5% | 65.0% | +3.5 (CI 1.3 to 5.5) |
| profile level, plain touch | 48.2% | 42.4% | +5.9 (CI 3.5 to 8.1) |
| random price, plain touch | 49.1% | 42.5% | +6.6 (CI 3.6 to 9.9) |
| profile level, volume without rejection | 43.7% | 33.6% | +10.0 (CI 8.2 to 11.8) |
| random price, volume without rejection | 40.6% | 33.7% | +7.0 (CI 4.9 to 9.3) |
- About 20 of the 23-point gap is arithmetic. A rejection on volume is not better than a plain touch once its starting position is accounted for.
- Every row beats random walk by 3–10 points, including random prices. That's general intraday mean reversion in NSE large caps, not a property of levels.
- Profile levels and random prices overlap in every row. The one gap that looks large (volume without rejection: +10.0 vs +7.0) also has overlapping intervals.
Product decisions (built 2026-10-30)
- Order Flow page (
/order-flow/SYMBOL): live print-level delta, buyer-initiated share, book imbalance, 5-level book, resting walls, footprint, today's profile against the 5-day composite, VWAP ±1σ and estimated CVD. Labelled descriptive, not predictive. Every level carries its row from the table above. - Recording: every watched symbol is written to
data/orderflow/<date>/<SYM>.jsonlevery 5 s.scripts/record_orderflow.py --top 50records a fixed universe for a whole session. When about 40 sessions exist, test: do walls hold more than random prices, and does print delta at a touch add anything beyond the random-walk expectation?
Limits
- 1-minute bars spread each bar's volume evenly across its range; the profile is exact only at that resolution.
- Large caps only. Thin stocks may behave differently, untested.
- 9 months, one regime. ~185 sessions × 50 stocks is large for touches but small for regimes.
- Live delta is classified per feed update (Lee-Ready against the prior quote), not per exchange trade.