One bug caused 86% of our trading losses
Our first auto-trader lost ₩5.1 million on paper in 190 exits. When we split the losses by the reason for each exit, one code path accounted for 86.5% of them. Then the same bug fooled us a second time.
How this was made: the code, the research runs and the first drafts of this text were produced by an AI assistant (Claude) working under the operator's direction; the operator made every decision and checked the numbers. All trading was on paper: real prices, no real money. Nothing here is investment advice.
Losses by exit reason
| Exit reason | Exits | Result, KRW | Average | Win rate | Median hold |
|---|---|---|---|---|---|
| Unconfirmed alarm exit | 157 | −4,416,442 | −0.37% | 10.2% | 12 s |
| Holding time ran out | 18 | −244,623 | −0.26% | 38.9% | 2 h |
| Confirmed alarm exit | 6 | −684,389 | −2.10% | 0% | 14 min |
| Trailing stop | 5 | +613,519 | +2.33% | 100% | 18 min |
| Stop-loss | 2 | −386,990 | −3.69% | 0% | 23 min |
| Other | 2 | +13,194 | — | — | — |
157 of the 190 exits came from one rule: an alarm that sold immediately, with no confirmation, no minimum holding time and no check that the price had actually moved. Those exits had a median holding time of 12 seconds. Their median round-trip cost, measured in the same ledger, was 0.43%, so they lost money even when the price did not move: 97 of them, 62%, ended with the price within 0.35% of the entry and still lost.
Exits within 30 seconds of entry, 114 trades, made 63% of all the losses on their own.
What the code did
In the same file, two other alarms already required a confirmation step before selling. This one had been left out. A sister module had been fixed for the same problem weeks earlier; this one had not. We changed it so that an unconfirmed alarm can only sell after a minimum holding time of 20 seconds, a real loss larger than the round-trip cost and six seconds of confirmation, while the hard safety exits, the stop-loss and the crash exit, still fired immediately.
Replayed against the ledger, the new rule would have blocked 143 of the 157 alarm exits. We did not claim that as a gain. Blocking an exit only means not paying the round trip at that moment; what the price did afterwards, had we held, cannot be proved from this ledger.
The second mistake
The audit also showed that trades from the 3-minute signal window had lost ₩4.42 million while the 1-hour window had made money, and we recommended trading the 3-minute window less. A day later we withdrew it. 157 of the 158 trades from the 3-minute window were exactly those alarm exits. Without them, the 3-minute window had one trade. We had compared two code paths and called it a difference between timeframes.
The same second audit found a related flaw: six confirmed alarm exits had all sold inside their own stop-loss, at an average of −2.0%, and five of the six coins were higher fifteen minutes later. Alarms were now overruling the risk plan. We stopped them from selling before the stop line.
What we took from it
- Split losses by exit reason and by code path before blaming the strategy. One bug can look exactly like a bad strategy.
- A pattern found in the data can be the bug in disguise. Check whether the groups you compare went through the same code.
- Do not change a policy on 8 to 12 trades.
- Keep the evidence: only 32 of the 190 exits still had their post-exit price records, because a 50-entry log had overwritten the rest. We raised it to 200.
Fixing the bug removed a bug, not the underlying problem: the strategy's edge per trade was still smaller than its costs. The whole six weeks.