15-Minute Divergence — The 1-Year Refresh on 5,073 Trades
Two months after the first intraday backtest, the same strategy re-run on a 4.5× larger sample: 5,073 trades across 144 symbols. The noise-stop fix worked, the profit factor held at 1.50× — and the data says this is not a day-trading strategy at all.
Why Re-Run It
The first 15-minute divergence backtest covered 1,116 trades and ended with a specific diagnosis: 41.3% of trades were stopped out on the very first bar after entry. The structural stop — placed at the divergence pivot candle’s low minus a cent — was routinely tighter than the natural range of a 15-minute bar. The trade thesis was fine. The stop was inside the noise.
The proposed fix was an ATR stop floor: never place a stop closer than a fixed fraction of ATR14, regardless of where the pivot sits.
That fix has been in the config since late May. This post re-runs the strategy over a fresh full year of 15-minute IBKR bars and asks three questions:
- Did the stop floor actually reduce first-bar stop-outs?
- Does the edge survive on a sample 4.5× larger?
- What does the bigger sample say that the smaller one could not?
The short version: yes, yes, and something uncomfortable about what this strategy actually is.
The Sample
That BUY/SELL split is the first thing worth staring at. 98.9% of trades were long. The SPY regime filter suppresses short entries while SPY trades above its 200-day EMA, and over this particular twelve months SPY was above it almost continuously. So this is not a test of a long/short divergence system. It is a test of a long-only divergence system during a bull market, and every number below carries that asterisk.
Headline Results
A profit factor of 1.50× on 5,073 trades is a more trustworthy number than 1.42× on 1,116. Sample size matters more than the headline value: at n=5,073 a profit factor of 1.50 is unlikely to be an artefact of a handful of lucky trades. It is, however, still thin. Every dollar of profit is accompanied by two dollars of loss.
A note on the Sharpe ratio I published last time
The previous post led with a Sharpe of 2.99 and compared it to institutional benchmarks. That framing was wrong, and this larger dataset makes the reason obvious.
The backtest engine opens a position for every valid signal. Over this run it held up to 30 positions simultaneously, with a median of 4 open at any time. The live configuration caps concurrent positions at 3. A Sharpe ratio computed on daily P&L from an unconstrained-concurrency simulation measures the smoothness of a portfolio nobody could actually hold — it flatters itself by diversifying across more simultaneous bets than the risk rules permit. Run the same daily-return calculation on this dataset and it produces a Sharpe above 5, which should be read as a red flag about the methodology rather than a discovery about the strategy.
Trade-level statistics — profit factor, expectancy in R, drawdown in R — do not have this problem. Those are what this post leads with.
Did the Stop Floor Work?
The fix helped and it did not finish the job. A 0.5× ATR14 floor is half of what the original analysis recommended (1.0× ATR14). Nearly three trades in ten still die inside the first fifteen minutes, which suggests the floor is still calibrated below the noise band it is supposed to clear.
Widening the floor is not free, though. A wider stop means fewer shares for the same dollar risk, which shrinks every winner proportionally. The open question — and the next thing worth testing — is whether the trades rescued by a 1.0× floor pay for the size that all the other trades give up.
Where the Money Comes From
The shape is the same as the smaller sample, with one improvement worth naming: the stop-loss bucket fell from 72.1% of trades to 60.4%, and trailing-stop exits rose from 10.3% to 15.6%. More trades are surviving long enough to trail. That is exactly what a wider stop floor is supposed to do.
The distribution remains brutally fat-tailed. The best 5% of trades generate 49.5% of all gross profit. Miss those 254 trades — through a platform outage, a position cap, a day off, a hesitation — and the strategy is a losing system. 11.4% of trades close above +2R; the median trade closes at exactly 0.00R.
The Uncomfortable Finding
The strategy is configured as a day-trading system. flat_by_eod: true, no entries after 15:30 ET, everything closed by 15:45 ET. That is the stated design.
Split the results by whether the trade actually closed on the day it opened:
This reproduces, on a 4.5× larger sample, the single most important finding from the first run. It is no longer plausibly noise.
The honest reading is that the divergence signal on 15-minute bars is not an intraday mean-reversion signal. It is a swing-entry timing tool that happens to be computed on intraday data. The 15-minute chart is good at identifying where momentum has failed. It is not good at telling you that the resulting move will complete within the same session — and the six-and-a-half hour window is simply too short for a 4×ATR target to fill.
That creates a direct conflict with the strategy’s own risk design. Holding overnight means gap risk, which is precisely what the flat_by_eod rule exists to eliminate, and what the earnings-blackout filter exists to control. The version of this strategy that makes money in backtest is the version that carries exactly the risk the configuration was written to avoid.
There is no clean resolution here. Either the strategy accepts overnight gap exposure and is honestly relabelled as a swing system with intraday entries, or it stays flat-by-EOD and the backtest says it loses money. Choosing the first option means re-testing everything with an overnight gap model and a much smaller position size. Choosing the second means the signal needs a different exit framework entirely.
What Position Limits Do to the Numbers
The $187,830 headline assumes every signal gets taken. It does not survive contact with a real risk cap.
Re-running the same trade list under a first-come, maximum 5 concurrent positions rule — closer to the playbook’s 3–5 limit — gives:
This is the gap between a backtest and a tradeable system, and it is worth stating plainly: a position cap is not a minor haircut on backtest results. In a fat-tailed strategy where 5% of trades carry half the profit, any rule that arbitrarily drops a third of signals is a coin flip on whether the surviving set still contains the tail.
What Changes Next
1. Raise the ATR stop floor to 1.0× and re-measure. 29.2% first-bar stops is still too high. Test whether the rescued trades outweigh the size given up across the whole book.
2. Stop reporting Sharpe on unconstrained-concurrency runs. Position-capped equity curves, or nothing. The metric was doing more harm than good.
3. Decide what this strategy is. The same-day / overnight split has now appeared twice on independent samples. Continuing to describe a system as intraday when 100% of its profit comes from overnight holds is not a modelling choice, it is a labelling error.
4. Re-test on a bear or sideways regime. 5,015 of 5,073 trades were long, during twelve months of SPY above its 200-day EMA. This backtest contains essentially no information about how the strategy behaves when that changes — and a long-only signal validated only in a bull market is the most common way a backtest lies.
5. Model the position cap inside the backtest engine, not afterwards. Post-hoc filtering of a completed trade list is an approximation. The engine should refuse signals when the book is full, so sizing and equity compound correctly.
The edge appears to be real — a 1.50× profit factor across 5,073 trades and 144 symbols is not nothing. But it is a swing edge wearing an intraday costume, it depends on tails that a position cap may well remove, and it has never been tested outside a bull market. That is three unanswered questions, and none of them get resolved by running the same backtest again.