← Writing

I lost $800 to trading bots, so I built one where the risk limits require a code edit

I bought commercial scalper bots, disabled their loss limits, and paid for it. The bot I'm building instead has a Risk Cage: six catastrophic-stop circuits that cannot be toggled off from any settings screen.

On this page

The most honest thing I can tell you about automated trading is how I got here: I bought commercial scalper bots, they came with loss limits, I turned the loss limits off, and I lost $800.

Not the bots’ fault. The bots did what grid scalpers do — made small, steady wins until the market trended hard against the grid, at which point the loss limit was the only thing standing between “bad week” and “blown account.” I had removed it, because it was a setting, and settings exist to be tuned by confident people. The market ran, the grid martingaled into it, and the account paid for my confidence.

The $800 wasn’t the expensive part. The expensive part would have been learning nothing. What I actually learned is the design principle behind the bot I’m building now: the failure mode of a trading bot is not its strategy — it’s the ease with which its operator can override its discipline.

The GUI toggle is the bug

Every commercial bot I’ve used treats risk limits as preferences: a max-loss field in a settings panel, right next to the color scheme. Mechanically, that’s an invitation. The moment a limit stops a promising-looking run, you — drawdown-tilted, sure the market will turn — can undo months of the developer’s caution with one click. I know, because I clicked.

So my bot inverts it: changing a risk limit requires editing the source code. No settings screen, no config flag, no override parameter. If future-me wants to raise a limit, he has to open the file, change the constant, and sit with what he’s doing — with version control watching. It’s friction as a feature: not because a code edit is hard, but because it cannot be done in the emotional state that produces the click. The click takes a second. The edit takes long enough to hear yourself.

The Risk Cage

The architecture has nine layers, and the strategy is only one of them. The layer that matters most sits near the top, wrapped around everything the strategy wants to do: the Risk Cage — six independent catastrophic-stop circuits, each capable of halting trading on its own:

  1. Per-trade — the worst case of any single position is bounded.
  2. Per-cycle — the worst case of one full grid cycle is bounded.
  3. Daily — a hard stop on the day’s total loss.
  4. Weekly — a hard stop above that, catching slow bleeds the daily stop misses.
  5. Drawdown — a limit on total decline from equity peak, regardless of calendar.
  6. Exposure — a cap on total open position size, so the grid can’t quietly stack lots into one direction.

Six circuits is deliberate redundancy. Each guards a different way accounts die: the single bad trade, the bad cycle, the bad day, the death-by-a-thousand-cuts week, the long slide, the over-leveraged snapshot. Any one tripping halts the bot — and none of them can be disabled at runtime, by design, by the person who has already proven he would.

Around the cage, the rest of the nine layers: a regime filter deciding whether the market is even tradeable before the strategy runs, ATR-aware position sizing beneath it, then the grid mechanics, entries, exits, and execution — with stress backtesting and a deployment ramp as the final layers rather than afterthoughts.

The bug that proved the point

While building the sizing layer, I caught a bug that is exactly why paranoia has to be structural: the worst-case-loss calculation under-priced a flat five-level grid by 2× on the first attempt.

Think about what that means operationally. Every limit in the cage reasons in terms of worst-case loss. If the worst-case math is half of reality, every circuit is silently twice as loose as configured — the cage looks intact and holds nothing. A bot can be conservatively configured and recklessly implemented, and no settings screen will ever show you the difference. Sizing math needs tests and adversarial review like it’s cryptography, because in account-survival terms, it is.

Backtest against the days that kill accounts

Ordinary backtests average across ordinary markets, which is precisely how grid strategies fool their owners — they look smooth right up until the one day that matters. So the stress layer replays the days that actually kill accounts: the Swiss franc unpeg in January 2015, Brexit night 2016, the March 2020 liquidity collapse, the yen moves of 2022. The pass criterion isn’t profit on those days. It’s that the cage halts, the exposure stays bounded, and the account survives to trade the boring months where grids earn their keep.

And because backtests only earn limited trust, the deployment plan is an eight-month ramp — paper trading first, then live with small size, with promotion gates rather than dates. Eight months feels long only until you compare it with how long it takes to rebuild an account.

The pivot, and the frozen reference

One structural twist: the bot began in Python, but the official MetaTrader Python API is Windows-only — a constraint I’ve dealt with before via a VM — while MT5 runs natively on my Mac. For an always-on bot, the VM was the wrong foundation, so I’m porting to native MQL5, the terminal’s own language.

The Python codebase wasn’t discarded. It’s frozen as python-reference-v1 — the executable specification. The MQL5 port must reproduce its decisions and its cage behavior, with the Python version serving as the acceptance test. A rewrite with a frozen reference is a port; a rewrite without one is a second chance to make new mistakes.

What the $800 actually bought

A design rule I’d now apply well beyond trading: any system operated under emotional pressure must make its safety rails harder to remove than to obey. Deploy gates, deletion confirmations, trading limits — if the override is one click, the override is the failure mode, and it will be exercised at exactly the worst moment by exactly the person who configured it.

The bot isn’t finished. The discipline is. That ordering is the whole point.

← All writing Book a call →
Book a call → WhatsApp