← Back to MagicMoneyMachine

How my trading bot lost $22k on a single coin — and what I built to prevent it from happening again

By Renat · May 20, 2026 · 7 min read

In April and May 2026, my autonomous Coinbase trading bot lost $22,366 on a single coin (PRL) across our fleet of paper users. The bot kept buying the same coin, hit small fib-ladder wins, and looked like a winner in every metric until the underlying position retraced. The realized loss wiped out 30 days of net profit.

This page is the autopsy. I'm publishing it because:

  1. Most bots hide their losses. I'd rather you trust me with the bad news.
  2. The lessons here apply to anyone running automated trading.
  3. The fixes I shipped this month make MMM the most honest crypto bot on Coinbase. I want you to know exactly why.
📊 Public live ledger: bot.magicmoneymachine.app/live — every trade, every user, anonymized, real time.

What happened

PRL (Parallel) is a small-cap Coinbase Advanced asset. Auto-discovery added it to the trading universe in early April. Two of our engines flagged it as a setup:

Both engines kept firing as PRL chopped. Each entry led to a Fibonacci ladder sell — partials at +5%, +10%, +20%. Those partials sold quickly. Every sold partial looked like a win.

Between April 10 and May 16, the bot took 58 PRL trades:

Per-coin stats showed:

Net? -$22,366.

When PRL finally trended down past every ladder rung and the bot was forced to close the remainder, the realized loss erased 30 days of fleet PnL. One coin. One bug class. One month of forensics to fully understand it.

Update — the exact closeout moment (uncovered May 20 forensic)

The "forced close" wasn't a slow grind. It was a single 2-second event. On May 16 at 01:16:50 UTC, the bot's stale_winner exit logic decided PRL had "given back 34.8% from peak" and closed it across 8 paper users simultaneously (within 2 seconds of each other). Each user took a -15.54% loss on cost basis. Total fleet damage in that single 2-second window:

This is what the entire 30-day "PRL bleed" looks like when materialized into a single timestamp. We discovered it 4 days later when the public live ledger surfaced 8 identical red rows. The defense-in-depth guard against this pattern (refuse stale_winner if pnl_pct is negative) shipped ~3 hours after the closeout fired, in v3.52.1. The full disable of stale_winner ships in the May 24 Day-7 activation as belt-and-suspenders.

How the metrics lied

The 86% WR is structurally a lie. Here's the math.

A fib-ladder exit looks like this:

Entry at $100, $200 position size, 5 sell rungs:
  Rung 1: sell 20% at $105  (+5%)   -> +$2.00 win logged
  Rung 2: sell 25% at $110  (+10%)  -> +$5.00 win logged
  Rung 3: sell 25% at $120  (+20%)  -> +$10.00 win logged
  Rung 4: sell 20% at $135  (+35%)  -> not hit
  Rung 5: sell 10% at $150  (+50%)  -> not hit
  Forced close at $80 (-20%)        -> -$26.00 loss logged

That's a single trade. Net: -$9. But the database sees 4 sells: 3 wins, 1 loss. Win rate calc: 75%. Looks great. Was -$9.

PRL had this pattern 50+ times. The 50 small wins (each $2-$10) didn't even add up to the 8 big losses (each $1,500-$4,000). When you only watch win rate, you're watching the wrong number.

Root causes (4 layers, ranked by $-impact)

Layer 1: No per-coin total $-exposure cap

The bot could keep DCA'ing into PRL until that single coin held $2,300+ of cost basis. There was no rule that said "once PRL holds $200 of capital across all users, don't buy more."

Fix shipped in v3.53.13: cloud/per_coin_cap.py enforces a configurable cap (default $200/coin). Pre-trade check sums existing cost basis + new entry; refuses if the projected total exceeds the cap.

Layer 2: Multiplicative sizing dial chain

Each entry was sized by 11 multiplicative factors. When a coin gave 3 small wins in a row, the bot's confidence would compound through the chain, growing position size on subsequent entries. PRL got progressively larger entries until they were structurally too big to recover from.

Counterfactual: if every trade had been a constant $50 (no chain), the same 30-day window would have netted +$22,773 instead of -$22,176.

Fix shipped in v3.53.7: MMM_SIMPLE_SIZING=1 env flag bypasses the dial chain entirely. Default OFF; gets flipped on May 31 as a planned Day-14 activation.

Layer 3: Win rate as primary metric

The metric didn't lie — it just measured the wrong thing for the asymmetric ladder pattern.

Fix shipped in v3.53.9: cloud/engine_accuracy.py surfaces $-magnitude per (engine, coin) alongside WR%. The dashboard now shows both. If 50 small wins add up to less than 8 big losses, you see it instantly.

Layer 4: No visibility into "which coin is the bleed?"

For 30 days, no one forensically asked "of all the trades the bot made, which coin contributed the most $-loss?" The data was sitting in Supabase the whole time.

Fix shipped in v3.53.9: /admin/benchmark dashboard now has a "Coin Contribution" section ranking the top 10 losers + top 10 winners by 30d $-PnL.

What I learned

  1. Win rate lies when you have asymmetric ladders. Always track $-magnitude alongside. A "winning" engine that net-loses dollars is a losing engine.
  2. Per-coin exposure limits are non-negotiable. Capital preservation means no single coin should ever absorb more than X% of fleet capital without explicit opt-in.
  3. Multiplicative sizing chains compound enthusiasm. Constant sizing is forensically better in our 30d window by +$22,773.
  4. Auto-discovery without proven-winner gating is risk amplification. PRL came in through auto-discovery.
  5. The bottleneck wasn't engineering — it was visibility. Every fix started with someone (me) finally asking the right question of the database.

What I shipped to prevent the next one

All live on bot.magicmoneymachine.app as of v3.53.13:

ModuleWhat it does
cloud/per_coin_cap.pyRefuses entry if coin's total cost basis + new entry > cap
cloud/engine_accuracy.pyLive $-PnL per (engine, coin), 30d + 7d
cloud/live_ledger.pyPublic anonymized trade ledger at /live
oracle.pyCounterfactual replay — test any hypothesis in <5s
cloud/autonomy_tripwire.pySelf-pauses on daily 5%, weekly 15%, monthly 30% DD
cloud/autonomy_throttle.pyReduces sizing 25-75% on alpha underperformance
cloud/benchmark_tracker.pyDaily snapshot of fleet equity vs BTC HODL
MMM_SIMPLE_SIZINGConstant per-trade sizing (flips May 31)
MMM_ENGINES_SHADOW_ONLYShadow the bleed engine (flips June 7)

The honest performance frame

Pre-fix (Apr 16 – May 15, 2026): fleet lost ~14.7% on $130k starting equity (-$19k). BTC HODL same window returned +11.4%. Bot under-performed BTC by ~26pp.

Post-fix (May 17 – ongoing): daily alpha snapshots show +2.03pp, +0.02pp, +1.67pp, +1.12pp on the first four days. Encouraging but small sample.

90-day verdict comes Aug 15, 2026. Per our own doctrine: alpha > 0 over 90 days = the bot is working; alpha < -5pp = rebuild, don't tweak. No mid-window panic activations.

Why this is the pitch, not a confession

You can look at our trade history. You can run the same Oracle hypotheses we run. You can watch the live ledger update every 30 seconds. You can read this post-mortem and decide whether the team behind your robo-trader is the kind of team that publishes its losses.

I'd rather lose 100 prospects who want a bot that's never lost than win 10 customers who'll find out about the loss when it happens to them.

The transparency is the product.


Try it on paper (free)

You don't have to take my word for it. The bot has a free paper mode that runs the same signals on simulated capital. You see exactly what it would have done with your money before depositing a dollar.

Start free on Telegram → View live ledger How it works