The function was called enter_pack. That should have been the warning. A research agent had written a BTC cash-and-carry: when the perpetual traded more than eight basis points over spot, buy spot, short the perp, sit still. Funding and basis would do the rest. The backtest filled both legs in the same millisecond, at mid, plus a tick of politeness. The equity curve was a staircase. Nobody would call it exciting. That was the selling point.
We promoted it to paper on a Monday.
Monday: the pack that always filled
The first signal landed at 11:17 UTC. Basis on the screen was 9.4 bps, perp rich. In the backtest, enter_pack returned two fills and a residual of zero. In paper it returned a spot fill of 0.40 BTC at the ask, and a resting short on the perp that did not trade.
Spot had paid a 4 bp taker fee and about a 1 bp spread. The perp price we wanted was still on the book, then it wasn't. Twenty seconds later the quoted basis was 5 bps, because we had just lifted spot. Forty seconds later the perp filled, after the move. We were packed. We were packed at a basis that no longer paid for getting in and out.
The backtest would have booked "+9.4 bps carry, residual 0." The blotter had 4 bps of spot taker cost, a 40-second unhedged long, and an entry gap of about 5. I had a sample of one and, still, too much confidence in the staircase.
Tuesday: we opened the function
enter_pack took a list of legs and a target mid. It looped, filled each leg at mid * (1 ± slip), and wrote one portfolio row. There was no second timestamp. There was no branch in which leg two did not exist. The unit test asserted residual == 0.
That is a test that makes you feel like an adult. It will never fail.
We broke the pack into two orders with their own state: submitted, partial, filled, canceled. Incomplete became a first-class object. The historical replay still didn't have a real book, so we cheated. Delay the second fill by a draw from Monday's wait (mean 26 seconds, a tail I did not like), and drift its price by whatever spot did in that window. Crude, but the staircase grew notches before lunch: packs that entered at 3 bps, packs that never became packs.
Wednesday: three seconds, then dump it
If the second leg isn't on within three seconds, flatten the first. We should have started there. It sounds conservative until you price the abort. Flattening means you crossed spot to get in and you cross it to get out. Two taker fees, two spreads, no carry, no funding. In the rewritten replay those aborts were not rare. They clustered on the bars where the basis looked most "real," which is usually the bars where something is already flowing through spot.
By Wednesday night we had seventeen paper signals to argue with.
| Backtest, Monday morning | Paper, by Wednesday | |
|---|---|---|
| Entry | Both legs at mid, one timestamp | Spot at the ask; perp 5–40s later, or never |
| Residual | Always 0 | Unhedged on 10 of 17 signals |
| Fees on a working trade | Two takers | Two takers, or four if we abort |
| PnL driver | Basis + funding | Whatever spot did while we waited |
A colleague still has a notebook that treats the pack as a listed product, BTC_CARRY, with a flat 2 bp "execution tax." I liked that notebook. It produced the same staircase the agent did. A tax is a mean. Orphans are a distribution. Means do not get run over in a thin hour; 0.40 BTC of leftover spot can.
Thursday: leftover, then coffee
Three seconds aborted almost everything once we were also waiting on a queue. We loosened paper to fifteen. At 02:11 UTC Thursday, spot filled and the perp did not. I was still in the "it will rest, it will lift" phase of grief when I went to make coffee.
02:11:08 filled BTCUSDT 0.40 buy
02:11:08 submitted BTCUSDT-PERP 0.40 sell, post-only
02:11:41 still working
02:26:00 residual mark −18.1 bps
BTC sold off 18 bps in a quiet window. The residual was the whole trade. Funding, when it printed, credited a perp we did not have. Spot just sat there being long. The original backtest's overnight path never contained a one-legged position, so it had never asked the question we ask of every other book: what is the worst bar this leftover can print, and where is the stop for a position we did not mean to hold?
The seven full packs were not heroes either. By the time the second leg printed, our own spot lift had already leaned on the index, and the entry basis was 3 to 5 bps worse than the snapshot that had fired the signal. The eight-bps threshold was a number about a screen.
What we'd skip next time
We would not ship a multi-leg as a single fill function. Same rule for a perp-spot carry, a calendar, or the call vertical an agent submits as two limits and then celebrates when both "fill" at mid.
- Per-leg order state, including partials. Treat the pack as a parent of two tickets.
- A max-orphan timer that actually fires, and a flatten path that pays two spreads on the way out.
- Mark-to-book on the residual, with a stop sized for the leftover. The packed net is the wrong notional.
- No carry credited, no funding accrued, until both legs are on. Incomplete is incomplete.
- Refuse mid-on-mid as a default for anything that has two tickets. If you must guess, guess worse on the thin leg and later on the second fill.
And we would not let test_pack_is_atomic into the repo. Atomic is a property of a matching engine, not a helper function. BTC spot and BTC perpetual are two books that sometimes rhyme. Paper is where they stop rhyming, which is the only reason the staircase was ever interesting.



