Skip to content
Parth Parekh
NOTELONG READ6 MIN READ
← ALL NOTES

A timeout is not a fill

Every OMS has to decide what to write when the socket goes quiet. Most get this wrong once, lose money, and then build the thing I'm describing.

A TIMEOUT IS NOT A FILLPARTH PAREKH

You send an order. The request leaves. Nothing comes back until the client library times out.

So what do you put in your book?

Not 'rejected' and not 'filled'. You don't know yet. The order might never have reached the broker. It might be live at the exchange right now. A timeout only means you didn't get an answer.

A timeout means you didn't get an answer. That's it.

What goes wrong by default

The easy code path marks the order failed and moves on. Then the fill shows up. Your system thinks you're flat; the exchange thinks you're long. If the strategy re-enters, you're double.

The other bad path is marking it filled when you aren't. Every hedge and square-off after that is wrong.

Both come from treating 'unknown' as if it were 'no'.

Three states, not two

  • 01Live at the venue — you have an ack or a fill you can point to.
  • 02Not live — the venue said no, with a reason.
  • 03Unknown — you sent something and nobody told you the outcome yet.

Unknown has to exist in your schema and on the blotter. When you're there, you go ask the broker — not guess, not wait for luck.

That recheck should not run on the send path. If the broker is slow enough to time out, it's probably slow enough to time out again on the status query. Mark unknown, return fast, let a background loop chase the answer.

Finding an order you can't name

Brokers usually give you an ID in the response you never got. So you attach your own client tag before send and search the book with that.

Without that, you match on symbol, side, qty, price, and a time window — which gets messy if the strategy fires similar orders back to back.

Status also comes back in layers: live socket, cache, order book poll, direct query. Use the fastest source that can answer, and log which one answered. When someone argues about a number three days later, that log matters.

Partials and child orders

Answers are rarely clean. Partial fills are normal. On Indian venues one parent order can split into several children against freeze qty. You aggregate children before you call the parent done.

Rechecks can double-book if a late status arrives while you're writing. Writes need to be idempotent on the venue's IDs.

When the broker host is sick

One timeout is noise. A streak is a signal. Per-host circuit breakers stop sending to a lane that's failing so the other four brokers keep working.

When a lane opens, something human-readable should say so — strategies on that broker are effectively paused.

Reconciliation is the backstop

All of this is best-effort. Periodically you still compare your book to the broker's. Their book wins.

That's how you catch whatever slipped through — and how you know the rest of the machinery is doing its job.

The broker book is truth. Yours is a cache.

MORE NOTESPARTH PAREKH