I Built an Emergency Brake for My Trading Bot. It Never Fired. Here's Why.
I Built an Emergency Brake for My Trading Bot. It Never Fired. Here's Why.
March 5, 2026 — Day 66 of building Trader-7, an LLM-powered crypto trading system
Two weeks ago, I felt good about where Trader-7 stood.
I'd shipped four sprints in quick succession — a regime watchdog, a cooldown after market flips, an emergency brake after five consecutive losses, and a boundary penalty for uncertain conditions.
The system ran clean for 70+ cycles. No errors. The logs showed safety systems firing when they should.
Then we had a bad week.
- March 3: BTC dropped 2.8% overnight. Three long positions stopped out in 32 minutes. Combined loss: -$96.
- March 5: A one-cycle macro selloff took the remaining four positions. Combined loss: -$79.68.
I brought in three specialist agents — a quant analyst, a professional crypto trader, and a system architect — and asked them to tear the system apart.
What they found changed how I think about building automated systems.
The Emergency Brake That Never Braked
The emergency brake (Sprint 102) was deployed about a week ago. In that time, it never fired. Not once.
This wasn't a high threshold that just hadn't been met. This was an emergency brake with two independent bugs that prevented it from ever activating — regardless of how many consecutive losses occurred.
Bug 1: The invisible loss.
My system has a reevaluator that closes trades early when signals flip. Those closes take a different code path than stop-losses — and that path never tells the emergency brake about the loss. The counter never increments.
SOL trade 179 was closed by the reevaluator at -$17.19. From the emergency brake's perspective, that trade never happened.
Bug 2: The restart that rewrites history.
On every startup, the system reconstructs the current losing streak from the database. But it's counting all losses in the window, not the consecutive tail.
Trade history: W, L, L, W, L, L, L should restore a streak of 3. Instead, the code gives 5.
Every Railway deployment restarts the container. Every restart miscounts the current streak. Combined with Bug 1, the result was an emergency brake that had been disabled by its own startup logic.
Two bugs. Either one alone would have silenced the brake. Together, they were invisible.
The State That Evaporated
Sprint 101 added a regime transition cooldown — after a market flip, pause new entries for three cycles.
It worked in testing. It fired correctly in the logs. During March 5's chaos — three regime flips in four hours — it activated exactly as designed.
But: the cooldown state is stored in Python instance variables. Railway restarts the container on every deployment. Every git push wipes the instance variables.
If I deploy during a regime flip, the cooldown that should protect the next three cycles is silently reset to zero. The system immediately opens new positions as if no flip had happened.
The fix is straightforward: write cooldown state to the database. But the bug is a reminder that in-memory state and cloud deployments are fundamentally incompatible with safety mechanisms.
The Filter That Locked Itself Out
Sprint 103 added a confidence penalty for trades near the regime boundary. If BTC is within 3% of SMA50, reduce confidence by up to 15 points.
The problem: defensive mode requires 82% minimum confidence. At 1.5% SMA50 distance, the penalty reduces 85% confidence to 77.5% — below the 82% floor.
DeepSeek's confidence ceiling is 85-88%.
The system had mathematically locked itself out of an entire price zone.
The fix: reduce penalty zone from 3% to 2%. Two numbers. Two lines of code.
The Meta-Lesson: Safety Systems Need Safety Tests
You can't verify a safety system is working by watching for it not to fail.
The emergency brake looked healthy. The logs were clean. No errors.
The only way to confirm it works is to deliberately test it — with synthetic data that should trigger it, or by running diagnostics against live data and confirming activations exist where you'd expect.
We didn't do that after deploying Sprint 102. We watched for the brake to fire, and when it didn't, we assumed conditions hadn't been met.
That was the wrong assumption.
The Journey as Feedback
We built Sprints 100–103, the system failed to improve, and now we're doing Sprints 104–108 to fix what we thought we'd already fixed.
That's frustrating.
But: we ran 88 paper trades worth of real-world data collection. We surfaced hidden bugs that would have been nearly impossible to find in unit testing. We're shipping fixes based on evidence, not speculation.
Each sprint that didn't work taught us something a successful sprint couldn't.
What's Next
Phase 6 deploys in sequence with 24-48h observation:
- Sprint 104 — Fix both loss streak bugs
- Sprint 105 — Persist cooldown state to DB
- Sprint 106 — Reduce penalty zone 3% → 2%
- Sprint 107 — ETH/SOL correlation cap
Current position: 88 trades, -$31.28 (-1.0%), 36.4% win rate. The gap to break-even is 3 percentage points. The infrastructure to close that gap now works.
Trader-7 is an experimental LLM-powered trading system in paper trading mode. This is not financial advice.