Crypto Bot - Two Bugs That Cost Me $100 (And How I Fixed Them in One Day)
Two Bugs That Cost Me $100 (And How I Fixed Them in One Day)
December 9, 2025
My trading bot ran for 14 hours yesterday. It lost $100 and taught me two lessons worth far more.
The Setup
I'm building an AI-powered trading system. It uses DeepSeek for market analysis, validates proposals through a rules engine, and executes trades on perpetual futures. Paper trading for now, but the lessons are real.
After 14 hours of trading, I had 5 trades, a 32% win rate, and a $100 hole in my paper account. Not great. But the interesting part wasn't the losses - it was why they happened.
Bug #1: The Ghost Positions
What I saw: Valid trades getting auto-closed as "orphans" every time the container restarted.
What I thought: Maybe the reconciliation logic is too aggressive?
What was actually happening: The perpetual adapter's position dictionary was empty on startup. Not because positions didn't exist - because I never loaded them.
Here's the embarrassing part. My spot trading adapter had this:
def __init__(self, ...):
if paper_trading:
self._paper_positions = {}
if self.db:
self._load_paper_positions_from_db() # <-- This existed
My perpetual adapter had this:
def __init__(self, ...):
if paper_trading:
self._paper_positions = {}
# <-- This method didn't exist
Same codebase. Same feature. One worked, one didn't. I'd added the perpetual adapter later and simply forgot to add the persistence method.
The fix: 15 lines of code to load positions from the database on startup.
The lesson: When you add a new path through your system (spot vs perpetual), verify both paths have the same capabilities. Silent gaps are the worst bugs because they don't throw errors - they just quietly lose data.
Bug #2: The Late Entry Problem
What I saw: The AI entering LONG positions that immediately went against me.
What I thought: Maybe the AI's analysis is wrong?
What was actually happening: The AI's analysis was fine. The timing was terrible.
I pulled up the charts. SOL had rallied 10% and peaked at 12:00 UTC. My bot entered LONG at 20:39 UTC - eight hours after the peak. ETH was the same story. The rallies were over. I was buying the top.
My validator had all these checks:
- RSI < 70? Check (RSI was 65)
- ADX > 15? Check (ADX was 28)
- Entry within 3% of proposed price? Check
Everything passed. But price was 6% above the 20-day moving average. The rally was exhausted. The validator didn't know to check for that.
The AI prompt even said: "Avoid Chasing: Don't enter if price >5% above fair value."
But that was just text. Advice. A suggestion. The validator didn't enforce it.
The fix: One new check in the validator:
# Check 10: Price Extension Filter
if proposal.direction == 'LONG' and price_extension > 4%:
return Rejected("Price extended - chasing rally")
The lesson: Soft guidance isn't enforcement. If a rule matters, it needs to be in the validator with a hard rejection. The AI will eventually ignore suggestions. Code doesn't ignore code.
The Meta-Lesson
Both bugs had the same root cause: I assumed things worked because I didn't see them fail.
The perpetual adapter "worked" because trades opened fine. I didn't test restarts.
The entry timing "worked" because trades got approved. I didn't check if approvals were good.
The fix for both was the same: make the invisible visible.
For persistence: load positions on startup and log what you loaded.
For entry timing: add a hard check that rejects bad entries with a clear message.
Now when a LONG gets rejected for being 5% above SMA, I see it in the logs:
Rules rejection: Price 5.2% above SMA20 (>4% - chasing rally)
That's not a bug. That's the system doing its job.
What I'm Doing Next
Rather than guess at the "perfect" take-profit level, I added analytics to track:
- TP1 hit rate by coin (is SOL underperforming?)
- TP1 hit rate by market regime (do weak trends need tighter targets?)
- "Near miss" analysis (how often does price get close to TP but reverse?)
In two weeks, I'll have data. Data beats intuition.
The Numbers
- Time lost to debugging: 3 hours
- Code written to fix both bugs: ~50 lines
- Paper money lost: $100
- Confidence in the system: Higher than before the bugs
Finding bugs is progress. Fixing them is learning. The bot is better today than it was yesterday.
That's the game.
Building Trader-7 in public. Follow along at jamiewatters.work