Realized Profit-and-Loss Math V2 for Glosten-Milgrom and Hawkes
Audit / Issue Found
A real-world side panel showed Glosten-Milgrom reporting a realized loss of fourteen thousand two hundred fifty-three quote-currency units. The previous fix made that number flow into the daily-loss circuit breaker, but the user pointed out the deeper problem: the number itself is wrong. The accounting math has a bug that produces phantom profit-and-loss on every buy fill.
Before the patch
Both Glosten-Milgrom and Hawkes used a cost-basis-equity detector to compute realized profit-and-loss. The math is cost-basis-equity equals cash plus units times break-even. The detector takes a snapshot every cycle and books the delta as realized profit-and-loss on every fill, buy or sell.
The formula assumes Gunbot updates the break-even field atomically with the holdings field in the same cycle. In practice the two fields can update one cycle apart. When that lag happens, every buy fill produces a phantom delta equal to roughly the position value times the gap between the current break-even and the buy price. At two hundred fills per hour those phantoms compound very fast into a large fictitious total. The direction of the phantom depends on which field updated first, which varies by exchange.
On the user's pair the cumulative phantom contribution is probably the dominant component of the reported fourteen thousand loss. The strategy is almost certainly losing some real money to adverse selection in the current market regime, but the order of magnitude shown was inflated by the accounting bug.
After the patch
The detector now uses a sell-only formula that is independent of break-even update timing.
For a long-only spot maker, only sells can realize profit-and-loss. The correct math is: when units decrease by some quantity Q in a cycle, the cash delta represents the proceeds of the sell. Realized profit on that sell equals the cash gained minus Q times the current break-even. The break-even used here is the live current value, which is valid because sells do not change break-even. The formula is independent of how Gunbot times its break-even updates.
Buys no longer book any realized profit-and-loss. The cost basis update is implicit in Gunbot's break-even.
A one-shot reset runs on the first cycle after the fix lands. Any realized total accumulated under the old buggy detector is reset to zero so the new detector accumulates clean numbers from there. A warning is logged showing the prior contaminated total so the operator can see what got reset and roughly how big the contamination was. The reset only fires once, gated by a marker in the state store.
The cleanup applies to both Glosten-Milgrom and Hawkes since they share the same accounting pattern. Other strategies in the library (microprice, queue-reactive, OFI flash, Roll model, Harris scalper, Kalman grid) use a different per-fill formula that derives realized profit from qty times (sell_price - BE) directly rather than from a cost-basis-equity delta, so they were not affected by this specific bug.
Bottom line
The realized profit-and-loss number you see on Glosten-Milgrom and Hawkes resets to zero on the next restart and then accumulates honestly from confirmed sell fills. If the strategy was genuinely making spread, the new total will track up. If it was genuinely getting picked off by adverse selection, the new total will track down, but at the real rate, not the inflated rate. The daily-loss circuit breaker now fires off this corrected number, so it will act on real losses, not phantom ones.
Known small accuracy caveat: when a buy and a sell both happen in the same cycle, the detector sees only the net change in holdings and recovers the average sell price from the net cash change. If the buy and sell partially offset, this introduces a small bias on the recovered price, bounded by the spread of the offset trades. For typical maker quotes this is on the order of one one-hundredth of a percent of the trade size and is much smaller than the bug it replaces.