Scalping — IVA Break-In Fade Updated Analysis

A reproduction of this strategy's own backtest code (strategy_engine.py), run against Bybit's top-100 perps by 24h turnover and the original 166-symbol screened list, after finding the entry-price calculation uses information from before it exists.

1 · The bug

e4_iva_breakin() waits for price to close back inside the opening 30-minute value area (IVA) at bar re, then enters at:

entry_px = bars[re][1] # open of the SAME bar whose close just confirmed re-entry

Bar re's close is the very thing that confirms the signal — its open happened before that close existed. The correct convention, already used elsewhere in the same file for E8's entries, is to enter on the bar after the signal:

entry_px = bars[re + 1][1] # open of the bar AFTER confirmation

The effect compounds because the profit target isn't set relative to entry — it's a fixed price level (the point of control or value-area edge from the first 30 minutes). With the old buggy entry, that fixed target was reliably still ahead of price, because you were "entering" before the move that reached it had fully played out. With a realistic, delayed entry, price has frequently already travelled most or all of the way to that fixed target before a real entry is even possible — so a large share of trades start already at or past their own target. They still get labeled "TP" (the code only checks whether price touches the target level, not which side of entry it's on), but the R-multiple correctly comes out negative: in one example trade, a short entered at 25.448 was assigned a take-profit level of 25.466 — above entry, for a short. That's not a coding artifact in the fix; it's what a fixed, not entry-relative, target does once the entry price is honest.

2 · Corrected results, both universes

Universe / versionTradesGross win rateGross PFNet win rateNet PF
Top 100, as-coded (reproduces the Overview page)107,66597.1%15.5551.8%2.63
Top 100, fixed91,03212.6%0.0633.2%0.015
Screened 166, as-coded269,69296.7%14.6158.4%3.80
Screened 166, fixed228,16811.5%0.0583.9%0.019
Top 100 · as-coded net PF
2.63
Top 100 · fixed net PF
0.015
Screened · as-coded net PF
3.80
Screened · fixed net PF
0.019

Bars capped for readability — as-coded PF values (2.6–3.8) are ~150–250× the fixed values (0.015–0.019).

3 · Does it generalize, or is it specific to the screened list?

Same pattern on both universes: as-coded shows a strong apparent edge (net PF 2.63 top-100, 3.80 screened), and fixing the entry inverts both to severe losers (net PF 0.015 and 0.019) within a hair of each other. This isn't a screened-universe artifact in either direction — the bug inflates results roughly equally everywhere, and the corrected reality is roughly equally bad everywhere.

4 · How this compares to the E8 finding

This is the same shared codebase behind the E8 VWAP-deviation fade reproduction, and it has its own version of the same category of mistake — but the outcome is more severe here. E8's lookahead (a VWAP computed from a full day's future volume) degraded a real-looking edge down to a coin flip that then lost to costs. E4's lookahead (entering before the confirming close exists) was propping up the entire apparent edge on its own — fixing it doesn't just remove profitability, it reveals a structurally negative trade: a fixed, non-adaptive profit target that price has frequently already passed by the time a real entry is possible.

5 · What this means going forward

The core idea — a failed early-session breakout reverting toward the point of control — isn't disprovable from this alone, but this specific implementation isn't a viable starting point: the fixed IVA-based target needs to be entry-relative (e.g. a target expressed in R off the actual entry, not a static price level from the opening range), and the "TP" label needs to check which side of entry the target sits on before it's trusted as a win. Worth checking whether E3 and E5, which share the same finalize_trade() and similar re-entry-confirmation patterns in this file, have the same same-bar-open issue before trusting their published numbers either.

6 · Checked at 1-minute execution precision too

If E4's collapse after the entry fix was partly an artifact of how much price can move within a single 5-minute bar before a realistic entry lands, tightening execution to 1-minute precision should show it. It does, partially: the as-coded (bug-intact) reproduction's edge shrinks a lot — gross PF 15.55→3.99, net PF 2.63→1.09 — since the "free" price movement the lookahead captures is now bounded to about a minute instead of five. The fixed version improves too: gross PF 0.063→0.518, net PF 0.015→0.148. But the verdict doesn't change — even at 1-minute precision, the fixed entry is still clearly net-unprofitable. Part of the 5-minute analysis's severity was a granularity artifact; the underlying finding (this specific implementation's edge is the lookahead bug, not a real signal) was not. Full detail on the ATR-VWAP variant study page, §6.

All figures above come from a from-scratch reproduction: Bybit V5 public kline API, 5‑minute bars, Jan 1 – Aug 25 2026, top 100 perps by 24h USDT turnover plus the original 166-symbol screened list (135/166 passing the engine's own 0.5%-median-ATR liquidity gate). Cost basis: 0.055% taker + 0.02% slippage per side, round-trip, applied on top of the engine's raw R-multiples (which include no cost deduction of their own, same gap found in the E8 reproduction). "Gross" = raw price R-multiple, no costs. "Net" = after the cost basis above. The shared finalize_trade() crash bug documented on the E8 page (a lookahead-loop edge case that silently dropped whole symbols' trades) was patched for both the as-coded and fixed runs here, so this comparison isn't additionally distorted by that issue.