1 · The bug
E3 enters on the bar after a confirmed breakout — the entry side of the trade is honest. The take-profit target, however, comes from the day's volume-profile node structure:
day["profile"]["nodes"] is built once per day in build_store.py's profile_with_nodes(db), where db is every bar in that calendar day — including bars that happen hours after a morning entry. A node that only forms from afternoon or evening volume can still end up as a signal's take-profit target if the signal fired that morning. The 30-minute IVA (vah/val) used for the stop is correctly built from only the first 30 minutes and is unaffected — this bug is specific to the profit target.
2 · A concrete example
AGLDUSDT, long entered 2026-01-05 14:45 UTC. Entry 0.2902, stop 0.289586.
| Version | TP level | Outcome | R |
|---|---|---|---|
| As-coded (full-day profile) | 0.292655 | TP hit | +4.00R |
| Causal-fixed (profile up to signal time only) | 0.293405 (farther out — no later-forming node existed yet) | Price reversed, stop hit instead | −1.00R |
Same signal, same entry, opposite outcome — purely a function of which day's worth of volume the profit target was allowed to see.
3 · Corrected results, both universes
| Universe / version | Trades | Symbols | Gross PF | Net PF |
|---|---|---|---|---|
| Top 100, as-coded (reproduces the Overview page) | 20,563 | 10/100 | 1.131 | 0.763 |
| Top 100, causal-fixed profile | 51,309 | 24/100 | 1.048 | 0.760 |
| Screened 166, as-coded | 87,546 | 42/166 | 1.180 | 0.890 |
| Screened 166, causal-fixed profile | 144,995 | 66/166 | 1.052 | 0.829 |
The as-coded screened-universe gross PF (1.180) matches the originally published 1.17 within rounding, confirming this reproduction. Symbol counts jump sharply between as-coded and fixed — not because more symbols became tradable, but because of a separate, shared bug (§3.1).
3.1 · The shared finalize_trade() crash bug hits E3 harder than E4/E8
The crash-and-silently-drop-a-whole-symbol's-trades bug already documented on the E4 and E8 updated-analysis pages affects E3 far more severely, simply because E3 fires roughly 2,000+ trades per symbol over the test window — a much higher signal rate than E4 or E8 — so it hits the unhandled end-of-data path constantly. As-coded, only 10/100 (top-100) and 42/166 (screened) symbols survive to produce a result; patching just the crash (independent of the profile-target fix) recovers 24/100 and 66/166. The trade-count and symbol-count jump in the table above between “as-coded” and “fixed” rows reflects both the crash patch and the profile fix applied together.
4 · A second, separate bug: day-level ATR sizing
Independently of the profile-target bug, E3's stop distance is sized off day["atr15"] — a single scalar per calendar day, computed in build_store.py as the last 15-minute bar's ATR reading for that day, not a value available at signal time. A morning signal is sized using an ATR that reflects that evening's volatility too. Spot-checked on ETHUSDT, 2026-01-01, 09:00 UTC: stored day-level ATR = 6.283 vs. a causal as-of-09:00 value of 3.793 — a 65% overstatement. Across 24,141 morning observations checked project-wide, the day-level/causal ratio ranges 0.48×–1.99× (5th–95th percentile) — a broad, material distortion, not an edge case. Re-testing E3 with a proper causal ATR instead of the day-level value, on top of the profile-target fix already applied:
| Universe | Net PF, day-level ATR | Net PF, causal ATR |
|---|---|---|
| Top 100 | 0.760 | 0.741 |
| Screened 166 | 0.829 | 0.808 |
The ATR fix moves net PF by only a few hundredths in either direction — a real bug, worth fixing, but not one that changes E3's verdict. This same day-level-ATR bug also affects E4 and E5's reproductions on this site (see their own updated-analysis pages); it does not affect the separate ATR-VWAP variant study, which computes its own proper causal rolling ATR independently and never reads this field.
5 · What this means
E3's core idea — a confirmed breakout beyond the opening value area continuing in that direction — is honestly weaker than published even before costs: fixing the lookahead in its own profit target roughly halves the gross edge (1.13–1.18 → 1.05), which is close enough to breakeven that costs alone were always going to decide the outcome. The net verdict is unchanged either way — E3 remains a net loser, now on a more honestly-computed number rather than a partially-inflated one.
finalize_trade() crash bug (documented on the E4/E8 pages) was patched for every run in this table. See the OI+CVD+Volume confluence page, §11–14, for the broader hardening pass this bug was found during.