How a Test Suite Took Down a Live Trading Bot for 9 Hours
On April 8, 2026, V3.6 Fear & Greed stopped trading. Not because the market crashed. Not because the bot had a bug. Because a test suite wrote fake prices to the same file the live bot reads from — and the bot's own safety system did exactly what it was supposed to do.
Key Takeaways
- Grid trading places buy and sell orders at fixed intervals around a price
- All results shown are from real exchange execution, not backtests
- Production bot operations require robust error handling and monitoring
What Happened
At approximately 05:24 UTC on April 8, V3.6 FG — CoinClaw's Fear & Greed gated live trading bot — started skipping every cycle. The logs showed the same message repeating every 30 minutes:
WARN Price sanity check failed: cache price $80,000.00 vs expected ~$68,125. Gap: 17.4%. Skipping cycle.
V3.6 was reading a BTC price of $80,000 from its market data cache. The real BTC price on Binance was around $68,125. That's a 17.4% gap — well above the 5% sanity threshold that CoinClaw uses to protect against bad data.
The bot did the right thing: it refused to trade on data it couldn't trust. But it kept refusing, cycle after cycle, for the next 9 hours.
The Root Cause: A Shared File Path
CoinClaw's architecture uses a shared market data cache at ~/.coinclaw/market_data/latest.json. The design is intentional — the live bot (V3.5 Grid) fetches prices from Binance every 15 minutes and writes them to this file. Paper bots and V3.6 read from it instead of making their own API calls, which reduces rate-limit risk when multiple bots run on the same machine.
The problem was in the test suite. Specifically, tests/test_v35_grid_live.py calls run_cron_cycle() — the same function the live bot uses — without passing a market_data_cache_path parameter. When that parameter is missing, the function defaults to the real cache path.
So when anyone ran the CoinClaw test suite, the test's mock exchange prices ($70,000–$83,000) got written to the live cache file. The next time V3.6 woke up and read the cache, it saw a price that didn't match reality.
Here's the chain of events:
- An agent runs
pyteston the CoinClaw repo (routine CI/testing) test_v35_grid_live.pycallsrun_cron_cycle()with mock exchange datarun_cron_cycle()writes mock prices to~/.coinclaw/market_data/latest.json— the real cache- V3.6 FG reads the cache on its next cycle, sees $80,000 BTC
- Price sanity check compares $80,000 to the real Binance price (~$68,125), finds a 17% gap
- V3.6 skips the cycle. Repeats every 30 minutes until the cache is overwritten with real data.
Why V3.5 and V3.7 Were Fine
This only affected V3.6. Here's why the other live bots were unharmed:
- V3.5 Grid — intentionally paused (standing decision). Even if it were running, V3.5 is the bot that writes to the cache. Its next cycle would have overwritten the mock data with real Binance prices, fixing the problem for everyone.
- V3.7 Scalper — fetches prices directly from the Binance API on every cycle. It never reads the shared cache. V3.7 ran 175 clean cycles on April 8 with zero errors.
V3.6 was the only live bot that depended on the cache for its price data. That dependency was the vulnerability.
The Fix: Test Isolation
The immediate fix was straightforward: every test that calls run_cron_cycle() now passes market_data_cache_path=tmp_path / "latest.json". This sends mock data to a temporary directory that gets cleaned up after the test — nowhere near the live cache.
But the team went further. olivdelm directed that V3.6 should fetch prices directly from the Binance API, just like V3.5 and V3.7. The shared cache should only be used by paper bots, where stale or incorrect data causes a skipped cycle — not a 9-hour outage on a live trading bot.
This is the right architectural decision. A live bot that trades real money should never depend on a file that any process on the machine can overwrite. Direct API calls are more expensive in terms of rate limits, but they're also more reliable — and reliability matters more than efficiency when real capital is at stake.
The Safety System Worked
Here's the thing that's easy to miss in this story: no money was lost.
V3.6's price sanity check caught the bad data and refused to trade. That's exactly what it's designed to do. The bot didn't place orders at $80,000 when BTC was at $68,000. It didn't buy high or sell low based on corrupted data. It just... stopped. And waited.
In trading bot development, a bot that stops trading when it sees bad data is infinitely better than a bot that trades on bad data. The 9-hour outage cost V3.6 some potential trades (though with Fear & Greed at 17 — extreme fear — V3.6 wasn't likely to be aggressive anyway). The alternative — trading on a 17% price error — could have been catastrophic.
This is defense in depth working as intended. The price sanity check was added specifically for scenarios like this — scenarios the developers didn't anticipate when they wrote it, but that it caught anyway.
The Broader Lesson
This incident is a textbook example of a category of bugs that's surprisingly common in production systems: test-production boundary violations.
The test suite was correct — it tested the right function with the right mock data. The live bot was correct — it read from the right cache file and applied the right sanity checks. The bug was in the boundary between them: a shared file path that both the test and the production system assumed they owned.
In web development, this is why you have separate databases for test and production. In trading bot development, the same principle applies to every shared resource: cache files, state files, wallet files, API connections. If a test can write to it, and a live bot can read from it, you have a potential incident.
The CoinClaw team's response — isolating test paths and removing the cache dependency from live bots entirely — addresses both the symptom and the root cause. That's the kind of fix that prevents not just this bug, but the entire category of bugs it belongs to.
Current Bot Status
As of April 8, 2026:
- V3.7 Scalper (LIVE) — running clean, 175+ cycles, +$3.87 P&L, zero errors
- V3.6 FG (LIVE) — recovered after the NameError fix (PR #1126) was merged. Running clean since ~03:39 UTC. The cache corruption fix is a separate PR.
- V3.5 Grid (LIVE) — intentionally paused (standing decision)
- V3.8 ETH Grid (PAPER) — paper trading at +$18.31. Live deployment pending PR #1127 review.
The Fear & Greed Index sits at 17 (extreme fear). V3.6's fear-gated strategy means it's watching the market cautiously — which, given today's events, feels appropriate.