Every bot I have taken from paper to live has had a worse first live week than its last paper week, and for an embarrassingly long time I blamed luck, or nerves, or the market somehow noticing me. The actual cause was more boring. Most paper-trading modes fill your order instantly, in full, at the mid price, and each of those three properties is a small subsidy that live trading takes back with interest.
Consider what a mid-price fill means. In a real market you buy at the ask and sell at the bid, so a round trip costs the full spread. A simulator that fills at mid hands you half the spread on every fill, for free, forever. On a major pair at a liquid venue the spread might be a basis point or two, which sounds ignorable, but if your bot trades forty times a day the subsidy alone can exceed the edge you think you found. On a thin altcoin pair, where spreads can run to tens of basis points, the paper curve becomes fiction. I have decomposed strategies that looked great on paper and found that essentially the entire return was spread the bot would never have collected.
The four things an instant fill hides
Latency first. Your signal fires at some timestamp, then reality happens: your code builds the order, the request travels to the exchange, the matching engine processes it, and a response comes back. Depending on where your machine sits relative to the venue, that loop takes somewhere between tens of milliseconds and a full second. In a quiet market it barely matters. But bots mostly want to trade in fast markets, and in fast markets the price at arrival is meaningfully different from the price at signal. Worse, the difference is not symmetric. When price is moving toward your order you get filled easily and are immediately offside. When it moves away, you miss the fill you actually wanted. That asymmetry is adverse selection, and it only ever costs you money.
Spread crossing second. If your bot sends market orders or crosses the spread with aggressive limits, it pays the touch rather than the mid, which means half a spread of cost on every single fill. This one is at least easy to model, but a surprising number of home-built simulators skip it entirely because the exchange's own paper mode skipped it.
Partial fills third. A simulator will happily fill your whole order at one price. A real book does not care what size you wanted. If your order is bigger than the liquidity resting at the touch, you either walk the book at progressively worse prices or you get a partial and end up holding a position smaller than your risk model assumed. Partials are also operationally useful to simulate because they surface bugs early. Your position tracking, stop logic, and PnL accounting all have to survive a half-filled order sooner or later.
Queue position fourth, and this is the one that ruins limit-order strategies. The naive simulation fills your resting limit whenever price touches your level. In reality, when price touches your level you are standing in line behind every order that was already resting there. If price kisses the level and bounces, the front of the queue got filled and you did not. The cruel part is that touch-and-bounce fills are disproportionately the profitable ones, while trades where price slices straight through your level, the ones both reality and the naive simulator fill, are disproportionately the ones where the market kept moving against you. Out of the same signal stream, fill-on-touch selects the winners and the live book selects the losers, so the paper curve diverges from reality in the flattering direction every time.
Building a fill model that behaves like the real thing
You do not need a full market microstructure simulation to fix most of this. A weekend of work covers the bulk. Add latency to every order, drawn from a distribution rather than a constant, somewhere in the range of fifty milliseconds to half a second depending on your infrastructure, and price the fill from market data after that delay instead of at the signal moment. Fill market orders at the touch plus a slippage penalty that grows with order size relative to visible depth, since even a crude linear penalty beats assuming infinite liquidity. Fill limit orders only when price trades through your level rather than merely touching it, and if you want to be more careful, snapshot the depth resting at your level when your order arrives, treat that as the queue ahead of you, and only fill once traded volume at that price exceeds it. Let orders fill partially, sized by the volume that actually printed. And charge real fees at your actual tier, maker and taker separately, because flipping a strategy's fee assumption from taker to maker can double its apparent quality without changing a single signal.
The principle underneath all of that is to bias every ambiguous modeling choice against yourself. You want a simulator that makes you slightly poorer than reality would. The failure mode of a pessimistic simulator is leaving a decent strategy on the shelf for an extra couple of weeks. The failure mode of an optimistic one is funding a bad strategy with real money, which historically is how I have made my most expensive mistakes.
The first thirty days: measure the divergence
Whatever you build in simulation, the real test starts when you flip to live. Keep the paper engine running in parallel on the same signals, same strategy, same parameters, shadow orders next to real ones, and compare trade by trade for roughly the first thirty days. Keep live size small enough that a total loss is annoying rather than damaging. These are the divergence metrics worth logging:
- Fill rate: the share of intended orders that filled completely, live versus paper. A big gap here usually means your queue model is still too generous.
- Slippage per trade: the signed difference between signal price and volume-weighted fill price, in basis points, compared against what the simulator charged you.
- Maker share: the fraction of fills that actually earned maker fees or rebates versus what paper assumed.
- Latency: median and worst-case time from signal to exchange acknowledgment, because tail latency is where fast-market losses hide.
- Partial fill frequency, and the average filled fraction when partials happen.
- Rejects, cancels, and rate-limit errors, which paper environments almost never produce and live environments produce constantly.
- Per-trade PnL delta: paper PnL minus live PnL on the same signal, tracked as a running average.
That last number is the one that decides things. If the running per-trade delta is a basis point or two and stable, your simulator is honest and you can start scaling with some confidence. If it is larger and not shrinking, the right move is to go back, recalibrate the fill model using the live data you just collected, and re-run the paper period, rather than keep paying the gap and hoping it closes on its own. This is also why we default the execution simulation in Blockcircle's backtester to pessimistic fills. An optimistic simulator produces optimistic users, and optimistic users churn the moment live results arrive.
None of this makes paper trading pointless. It is still the cheapest place to find logic bugs, broken position accounting, and strategies that lose even with free fills. It just cannot be the final gate before real money unless the fills inside it cost roughly what fills cost outside it. Model the spread, the delay, the queue, and the partials, run the shadow comparison for a month, and you will know with numbers rather than vibes whether the edge survives contact with a real order book.