On the morning of August 1, 2012, a trading firm sent more than four million orders into the US stock market in 45 minutes. It was trying to fill 212.
Knight Capital was one of the largest market makers in American equities. By lunchtime it had bought and sold 397 million shares nobody wanted, sat on billions in unintended positions, and was down roughly $460 million. The firm was sold off inside a year.
Here's the part that should bother you. The code wasn't broken in the way you're probably imagining. It did exactly what it was written to do.
A deployment went out to eight servers and seven of them got the new version. The eighth still carried a dormant function from 2003, and the new release reused a flag bit that happened to switch that old function back on.
One server. One repurposed bit. No error at all in the trading logic itself.
I think about that story every time someone shows me a bot and wants to talk about the entry signal.
Automation doesn't care what it's scaling. Give a system a real edge and it will apply that edge tirelessly, without hesitating, at 3am, in a market you aren't watching. Give it a mistake and it applies the mistake the same way. Same speed, same consistency, no fatigue, no second thoughts.
A human making Knight's error would have caught it in about ninety seconds. Something feels wrong. Why do I own this much?
A machine feels nothing. It keeps going until something outside it says stop.
Most retail traders building automated systems spend the overwhelming majority of their time on the part that generates signals and almost none on the part that defines what the system isn't allowed to do.
I did this myself. My first bot had a lovely entry condition and no maximum position size. It never blew up, which taught me nothing useful — I mistook luck for engineering.
There's an asymmetry here that builders keep missing. A flaw in your signal logic costs you a run of mediocre trades, and you'll spot it in the equity curve within a few weeks. A flaw in your sizing or your order loop costs you the account, and you'll spot it in about four minutes.
The version I see most often in crypto isn't dramatic at all. A script asks the exchange for its current position, the API hands back an error object instead of a number, the code reads that as zero, and the bot concludes it's flat and opens a second full position on top of the first. You're now running double the leverage you tested at, and every single line of the strategy is behaving correctly.
Compare that to how institutions are required to operate. Under SEC Rule 15c3-5, written partly in response to this exact class of failure, any broker with market access has to maintain pre-trade controls that reject orders exceeding preset price or size parameters and cap aggregate capital exposure. Not "should consider." Has to.
You get none of that by default. Your exchange API will cheerfully accept an order ten times the size you meant because you typed an extra zero into a config file, or because a sizing function divided by a stale balance it fetched before the last fill.
So here's what I'd do differently if I were starting over. Before writing the entry logic, write the ceiling.
Pick a maximum position size as an absolute number, not a formula — a hard cap the system can never exceed no matter what any calculation hands it. Pick the daily loss at which the bot stops trading and needs you to restart it by hand. Pick a maximum number of orders per hour, because a runaway loop shows up as order volume long before it shows up in your P&L.
Then break it on purpose. Feed the system a deliberately corrupted config and watch what happens. If it doesn't refuse the order, you don't have limits. You have intentions.
A kill switch that adjusts position size instead of halting isn't a kill switch. It's hope with a config file.
None of this generates returns. Constraints never do. They just decide whether you're still trading the day your edge finally shows up, which is the unglamorous half of systematic trading and the half that determines whether four years of compounding survives one bad Tuesday morning. We publish our hard limits and drawdown rules next to the backtest data at v33systematic.com, because the risk controls are the part actually worth copying.