NineFifteenAM

Mistakes that cost me

The ₹40,000 bug I shipped on a Friday

2 min readBy Shubham

A missing check turned one rejected order into eleven retries in nine seconds. The code path, the logs, and the guard that now makes it impossible.

At 13:42 on a Friday my bot sent an entry order that the broker rejected for insufficient margin. The rejection was handled — that part worked. What did not work was what happened next.

What happened, in order

The retry logic treated a rejection the same way it treated a network timeout, so it tried again. And again. Eleven times in nine seconds, until the position sizing check finally caught up and halted the strategy. Nine attempts were rejected too. Two went through, at prices four rupees apart, leaving me with double the intended position in a stock I had already decided to size small.

Why the retry loop existed at all

The retry was added for a real reason. Broker APIs drop connections, and a timeout does not tell you whether the order reached the exchange. The mistake was lumping every failure into one category.

The fix

Classify the error before any retry, and let only the transient class through. Everything else raises, gets logged with the broker's own message, and halts the strategy for the day if it repeats. I also added a hard ceiling that no code path can bypass: a maximum of three attempts per signal, counted in the trade registry rather than inside the function doing the retrying. The bug happened partly because the counter lived in the wrong place.

How I found it

Forty minutes, because I had the session replay. Every decision the bot makes is recorded with the state it saw at the time, so I could rerun the afternoon and watch the loop happen. Without that I would have been reading log files and guessing.

If you build one piece of infrastructure before going live, make it this one. Not the backtester, not the dashboard — the ability to replay exactly what your bot saw and decided.

Questions people ask me

Should I add retries to my trading bot at all?

Yes, but only for failures where retrying can succeed — timeouts and connection errors. Classify first, retry second, and always cap attempts somewhere the retry code itself cannot reach.

How do you know whether an order reached the exchange?

You don't, from the failed request alone. Fetch the order book and reconcile against your own record of what you sent. Treat reconciliation as the default response to an ambiguous failure.

riskpostmortempythonexecution
S

Shubham

I trade Indian markets and write the software that does it for me. I publish the engineering and the mistakes twice a week — no tips, no calls, no returns.

The Saturday letter

One email a week: what I built, what broke, and the lesson I'd pay money to have learned earlier.

Free. Unsubscribe anytime. No tips, no spam.

Related

15 Sept 2026
Nine checks before your bot touches real moneyThe pre-live checklist I wish someone had handed me: paper-live parity, kill switches, config hashes, and the failure I only caught on the eighth check.
Best practices
11 Sept 2026
Month 6: the strategy worked, the plumbing didn'tBacktests looked fine, live results didn't match, and the gap had nothing to do with the strategy. What I found when I replayed real order books.
The journey
26 Sept 2026
Algo trading in India: the rules, the cost, and what to do firstWhat the law requires of a retail algo trader in India, what a system costs to run after the April 2026 STT change, and the order to build it in.
Guides