Executive summary
I ran an inverted-alpha paper-trading experiment to test whether inverting my live signals would produce net-positive P&L over 100 round-trips. The inverted-alpha book (Book 2) hit a 63% win rate — good enough to celebrate — but the per-trade average loss was six times larger than the per-trade win size. The shape of the P&L didn't match any thesis I had. After a few days of staring at the numbers, I traced the problem to a single missing keyword argument in the close-order routing path. One line of fix, and the per-round-trip cost on the inverted book dropped from about $0.29 to under $0.02 — roughly a 21x reduction in per-trade bleed. This post is the story of finding the bug, why it hid for three days, and the structural test I should have written up front.
The signal that didn't match any thesis
A quick refresher on the inverted-alpha setup (I covered the original thesis in more detail in "The Inverted Control"). I run a multi-book paper-trading experiment on the same live signal source. Book 1 executes the signal as-is. Book 2 executes the inverted side of every signal — if Book 1 goes long, Book 2 goes short on the same symbol and size. The idea is simple: if my signal has negative edge on average, its inverse should have positive edge, less fees. Historical shadow analysis said the inversion would have produced roughly +$40 on 496 round-trips where Book 1 actually lost about $70. The live test was going to confirm or deny that in new market conditions.
Two days in, Book 2 looked weird. The win rate was sitting around 63% — higher than Book 1's 34%, which is what you'd expect if the inversion thesis held. But the net P&L on Book 2 was already deeply negative, with an average per-round-trip loss three times worse than Book 1. The shape didn't make sense: a book that wins 63% of the time shouldn't bleed faster than one that wins 34% of the time unless the losing trades are massively larger than the winning trades. And they were. The average win was small and the average loss was huge. The R-multiple on Book 2 was roughly inverted from what the mirror design implied.
What I initially suspected
My first hypothesis was that the inversion thesis was just wrong in the current regime. Maybe the market had shifted from trending to mean-reverting, and the signal that had been losing in trend mode was now correct in the new regime — which would make its inverse wrong. That's an honest failure mode, and if that's what was happening, I needed to kill the test early.
My second hypothesis was sample-size variance. Eighty round-trips is not a lot. A handful of asymmetric outliers can make the per-trade average look catastrophic before the law of large numbers smooths things out. I considered waiting for 200 round-trips before acting.
Neither hypothesis explained the specific R-multiple asymmetry. If the signal had flipped edge direction, the win rate should have dropped toward 50% or below, not landed at 63%. If it was pure variance, the wins and losses should have been roughly symmetric around the expected mean. What I was seeing — high win rate, small wins, large losses — is the mechanical signature of something clipping the wins and letting the losses run.
The trace that revealed it
I went into the logs. For each closed position on Book 2, I pulled the close-order record and checked which book the close actually hit. Every single one had routed to Book 1's ledger. Book 2's open positions existed. Book 2's trades showed up in the comparison snapshot. But Book 2's closes were landing on Book 1, which meant Book 2 positions were only closing when Book 1's mirror trade hit its own TP or SL — at Book 1's magnitudes, not Book 2's.
That's the asymmetry I was seeing. Book 2's take-profit threshold (set symmetrically with Book 1 for the experiment) never fired on its own positions. Book 2 closed when Book 1's signal exited — and since Book 2 is the inverse, Book 1's winning exits were Book 2's losing exits, at Book 1's take-profit magnitude. Meanwhile, Book 1's losing exits (at its smaller stop-loss magnitude) were Book 2's winning exits. Wins capped at small, losses running to large. The R-multiple wasn't mysteriously inverted; it was mechanically forced that way by a routing bug.
The root cause — one missing kwarg
Found it in the futures TP/SL monitor. The loop fetches all open positions across every book without a per-book filter (intentional — one loop watches the whole portfolio). For each position that trips its TP or SL threshold, it constructs a close-order and hands it to the execution engine:
# Before (the bug)
close_order = SimulatedOrder(
lane="futures", symbol=pos.symbol, action=close_action,
quantity=pos.quantity, price_vnd=live_price, leverage=pos.leverage,
note=f"Auto-close: {close_reason}",
)
close_result = await engine.execute_futures(close_order)
The monitor passes no book_id. Downstream, execute_futures defaults book_id=1 when the argument isn't provided. The close-execution query then filters the position table by that default book_id, looking for a Book 1 position matching this symbol to close. For a Book 2 position that needs to close, the query finds nothing that matches — Book 1 has no such position. The execution path returns cleanly with zero matches. No exception. No warning. Just a silent no-op.
The monitor logs a cheerful "Auto-close" message. The database state is unchanged. The position keeps running until the Book 1 mirror signal decides to exit, at which point the close finally lands on the correct book via a completely different code path (the mirror-fire routing in the execution engine). That's why Book 2 positions did eventually close — through Book 1's exit, not their own.
The 1-line fix
# After
close_result = await engine.execute_futures(close_order, book_id=pos.book_id)
That's the whole patch. Route the close to the same book the position lives on. I added a comment block above the call referencing the session log where the bug was diagnosed, so the next person reading this code has some archaeology to work with if they're wondering why the kwarg is suddenly important.
Before and after
The fix went live with the backend restart. Book 2 had 88 round-trips on its books at that moment. I locked that as the pre-fix baseline and started counting post-fix round-trips separately.
| Window | Round-trips | Avg cost per round-trip |
|---|---|---|
| Pre-fix (contaminated by bug) | 88 | about $0.29 |
| Post-fix (clean) | 87 | about $0.01 |
The 21x reduction in per-trade cost isn't the inverted-alpha signal suddenly working. It's the mirror book's own take-profit and stop-loss thresholds finally firing, instead of being clipped by Book 1's exit timing. Wins land at the size they were designed to land at. Losses stop at the size they were designed to stop at. The R-multiple on Book 2 is now something close to symmetric, which is what the inverted-alpha experiment was supposed to measure in the first place.
The part I'm not claiming
Eighty-seven post-fix round-trips is still not a lot. The number could drift back toward zero or turn positive or stay mildly negative as the sample grows. What I'm claiming is narrow: the bug was contaminating the signal to the point where no verdict was meaningful, and fixing it moved the book roughly to break-even on post-fix trades — which at least lets the actual inverted-alpha thesis get tested on its own merits. Whether the thesis itself holds up over 100+ clean round-trips is still open.
I'm also not claiming that a bug this shape should be impossible for anyone smart to write. I wrote it. I shipped it. It ran for three days producing data that looked like a meaningful signal and wasn't. The uncomfortable part is how convincing the bad data was — a 63% win rate with a tidy asymmetric R-multiple is exactly the kind of shape that generates theories.
Takeaway: test cross-book routing, not just book behavior
Every unit test I had written pointed at Book 1 behavior in isolation. Does the close logic work? Does the TP trigger at the right threshold? Does the position close update the balance correctly? All of those passed. What I hadn't written was a test that opens a position on the inverted-alpha book (Book 2), triggers its TP, and asserts that the resulting close lands on Book 2's ledger and not Book 1's. A single-line assertion in the right place would have caught this bug before it shipped.
If you're running a multi-book or multi-account framework where the routing surface is implicit — where a missing keyword argument silently falls back to a default account — write the cross-routing assertion. It's the test that only exists once you have more than one book, and it's the test that stops being optional the moment silent no-ops can masquerade as winning trades.
Related reading
- "The Inverted Control" — the original inverted-alpha thesis and why I set up the multi-book experiment in the first place
- "Why Apple Silicon Quietly Won the Local-AI Race" — the stack this whole system runs on, one M1 Max
- "What 19 GB of Memory Compression Taught Me About MLX" — a companion story of another silent failure mode that hid in plain sight
Disclaimer: This post is engineering observation from a solo paper-trading experiment, not financial advice. The numbers reflect one specific configuration on a paper book denominated in a non-USD unit and converted for readability; results in any real live book will differ. Verify your own framework before trusting signal data from a multi-book setup.
Top comments (0)