Event contracts look simple from the outside. A price between a fraction of a cent and a dollar. A YES or a NO. A number you can size and forget until resolution.
The book is not simple. If you B-book a portfolio of those contracts (you are the counterparty, the trader never hits the real CLOB, prices still mark to a public market), a flat "25% max position" rule will not save you. Thin names can be pushed. Near-certain prices can be farmed. Three House seats in the same state are not independent, and they are not the same market.
That is the world of funded trading platforms and other B-book event books. The risk is not "do we understand YES and NO." The risk is that the desk is short a correlated stack of outcomes while someone can still move a thin external mid.
I needed a risk layer that treated those as first-class problems. Not a notebook dump. Not a boolean "is this correlated?" flag. Something you can put in front of an order gate and defend with numbers a quant would actually check.
So I built one. Continuous correlation (rho or factor loadings). Liquidity-scaled position caps derived from a dual-book attack model. High-accuracy size cliffs. Multi-outcome group exposure. One trade gate that returns allow, reason, and details. Pure Python. No framework.
Then I stress-tested it the way you should stress-test risk code: a full tradable price band from 0.1¢ toward the top of the book, liquidity from $1k to $1M, multi-seed attack simulations, and a threshold grid that is not allowed to leak.
This is that story.
Three failure modes
Most retail risk UIs stop at max notional. That is necessary and not sufficient.
Manipulation. A B-book platform that marks to an external book creates a dual-book surface. Open large size on the B-book at mid. Push the real mid with personal capital. The B-book marks to the new mid and captures the full impact. Personal pays VWAP and reversion. If B-book size is not capped against liquidity, the attack is positive EV.
High-accuracy farming. At 50¢ an efficient market is roughly fair before fees. At 90¢ the same statement is only true if true probability equals price. If the market is soft, the book is short a yield farm. Even when fair, path risk into a tight drawdown is brutal. A few 80¢ losers erase a month of small wins. In practice we tighten size hard by 80¢ and especially at 90¢, even when the venue can quote finer tops like 99.9¢.
Correlation. Binary "correlated / not" fails on real politics and sports. Neighboring districts share a swing factor without being identical. A nominee YES and a party YES are linked hard but not one-to-one. You need a score, or better, factor loadings.
Everything below is designed around those three.
The dual-book attack
Assume a B-book that marks to an external order book. The platform is the counterparty. It does not need to place the trader's order on the real CLOB. That is the whole point of B-booking: internalize the trade, still use public prices.
Buy YES against the platform at mid p. No real CLOB fill. The desk is the counterparty.
Buy the same side on the public market with personal capital. Mid walks by impact Δ.
Internal mark jumps to p+Δ. B-book profit is about (S / p) × Δ while personal paid VWAP.
Sell after partial reversion. Fees and reversion usually dominate unless S is too large for L.
The naive simulator models the personal leg as entering at the old mid and exiting above it. Then the attacker always "wins." That is wrong. Personal entry walks the book. Exit meets reversion. Fees are real.
With linear impact Δ ≈ Q / L, half-spread, round-trip costs around 3–4%, and reversion near 50%, attacker net is approximately:
net ≈ (S / p) × Δ − personal impact costs − fees
When reversion is about half, personal mid PnL collapses toward zero and costs dominate. For the B-book leg, substitute the liquidity cap S = c · p · L into the mark-to-market profit term:
S_max = min(account_cap, c × p × L)
c ≈ 0.03 × 0.85 = 0.0255
That coefficient is the production default. It scales with price and liquidity. A 10¢ name on $25k depth is not allowed the same notional as a 60¢ name on $500k depth. Above 80¢, high-accuracy cliffs cut size further.
Impact itself is room-limited. You cannot push a 99¢ contract through a 50-point linear move. The model clamps Δ to the remaining distance to the top of the book. Without that clamp, extreme prices produce fake LEAKs. With it, the physics stay inside the probability simplex.
Public venues can quote very fine ticks (down to 0.01¢ on some books, and tops near 99.9¢). Our risk defaults still treat 80¢ / 85¢ / 90¢ as the practical high-accuracy cliffs for size, because that is where yield-farm path risk and soft pricing start to matter for a B-book.
Evidence across the full price band
I do not want a grid that only covers "comfortable" mids. Event contracts trade from a tenth of a cent up through the nineties. The suite covers 0.001–0.99 and liquidities from $1k to $1M.
Threshold grid at reversion 0.5: 171 cells, 171 OK, 0 LEAK.
Attack simulations under the cap: 32 seeds × 200 attempts, prices log-uniform on 0.1¢–99¢, liquidity log-uniform on $1k–$1M, random reversion 0.3–0.7.
| Statistic | Value |
|---|---|
| Seeds × attacks | 32 × 200 |
| Price range | 0.1¢ – 99¢ |
| Liquidity range | $1k – $1M |
| Mean attacker PnL (capped) | -$1,077 |
| Median attacker PnL | -$752 |
| P10 / P90 | -$3,352 / +$497 |
| Attacker win rate | 13.5% |
| Uncapped mean (baseline) | +$2,654 |
| Threshold grid | 171 / 171 OK · 0 LEAK |
Uncapped baseline (same family of attacks, no size formula): mean attacker PnL is positive (about +$2.7k per seed mean). With the cap: mean is -$1,077, median -$752, seed-median-of-means firmly negative. Lucky wins still happen (about 14% of attacks). EV is what matters.
The cap curve is the other half of the story. Below the high-accuracy region, max B-book size rises with price × liquidity. At 80¢ / 85¢ / 90¢ the cliffs flatten the curve on a $5k account.
And the attack surface as a heatmap: best attacker net under the cap. Every cell is negative.
| Price | $1k | $5k | $10k | $25k | $50k | $100k | $250k | $500k | $1M |
|---|---|---|---|---|---|---|---|---|---|
| 0.1¢ | -3.4 | -10.1 | -16.8 | -30 | -41.5 | -51.5 | -42.6 | -39 | -36.9 |
| 1¢ | -9.4 | -23.7 | -30 | -35.9 | -38.5 | -39.9 | -40.8 | -41.1 | -52.6 |
| 5¢ | -23.7 | -35.9 | -38.5 | -33.7 | -34.2 | -34.5 | -31.1 | -62.2 | -68.5 |
| 10¢ | -30 | -38.5 | -39.9 | -19.3 | -19.5 | -24.9 | -34.8 | -68.5 | -47.6 |
| 20¢ | -34.8 | -22.7 | -23.2 | -10.9 | -13.9 | -27.8 | -39.7 | -47.6 | -36.5 |
| 40¢ | -21.4 | -12.9 | -13.1 | -8 | -16.1 | -32.1 | -32.6 | -36.5 | -30.8 |
| 60¢ | -15.7 | -9.3 | -9.4 | -9 | -18 | -32.4 | -30.1 | -32.7 | -28.9 |
| 80¢ | -12.6 | -7.4 | -7.6 | -6.5 | -7.3 | -7.7 | -6.4 | -6.5 | -5.7 |
| 90¢ | -11.4 | -7.1 | -8.3 | -5.7 | -6 | -6.1 | -5.1 | -5.1 | -4.5 |
| 95¢ | -10.2 | -7 | -8 | -5.7 | -5.9 | -6 | -5 | -5 | -4.5 |
| 99¢ | -9.2 | -6 | -6 | -5.3 | -5.6 | -5.8 | -5 | -5 | -4.5 |
That is the bar I care about: not "we thought about manipulation," but here is the grid, here are the seeds, here is the uncapped control.
High-accuracy cliffs
Even without a dual-book attack, near-certain contracts are awkward inventory for a B-book. Path risk and soft pricing both matter. Defaults:
| Price | Max size |
|---|---|
| Under 80¢ | Normal book limits |
| 80¢+ | 5% of account |
| 85¢+ | 3% of account |
| 90¢+ | 2% of account |
Policy choice on top of sizing: treat 80¢+ as hedge-required if you can transfer risk (A-book that slice). The size cliffs are the floor either way.
Correlation is continuous
Take two patterns that show up constantly on public books.
House seats, same state, same cycle. Dem YES on neighboring districts loads on a midterm swing. Not independent. Not identical. Something like ρ ≈ 0.35–0.50 is honest. Binary "yes" over-blocks multi-district books. Binary "no" lets a trader stack the same factor three times.
Person winner vs party winner. Nominee YES and same-party YES: high but not 1.0. Opposing party: offsetting. Newsom does not load on the Republican factor the way Vance does. He loads on the Democratic side.
Factor form (independent factors for the default engine):
E_f = Σ size_i × side_i × loading_i,f
effective = √(Σ E_f²)
Pairwise form when you only have a rho table:
Var = wᵀ Σ w
effective = √(max(Var, 0))
Cap effective exposure (default 20% of account). Same-direction stacks burn budget. Offsets shrink it.
Discovery of rho is separate from enforcement. Hand labels, rules, later a model. The engine only needs loadings or a matrix. Do not block shipping risk on perfect ontology.
The gate
One function sits in front of every order. It runs a fixed sequence of checks and returns a reason you can log or show in a UI.
First it rejects if the account already has too many open positions, or if the market fails min liquidity / min 24h volume. Then it computes the liquidity-scaled max size (price × depth × 0.0255, floored by account and high-accuracy cliffs) and rejects if the order is larger. Then per-trade size, per-market concentration, and multi-outcome group exposure. Finally it recomputes effective correlated exposure with the candidate added and rejects if that would breach the portfolio cap.
That is the whole production surface for the open-source core: pure functions, no I/O, no product branding. You wire check_trade into whatever stack takes orders for a B-book event platform.
Defaults
Opinionated starting points. Override them. Calibrate on your own attack sims and loss data.
| Knob | Default |
|---|---|
| Max position | 25% of account |
| Per market | 10% |
| Per multi-outcome group | 15% |
| Effective correlated exposure | 20% |
| Min liquidity | $10,000 |
| Min 24h volume | $5,000 |
| Manip coefficient | 0.0255 × price × liquidity |
| High-accuracy 80¢ / 85¢ / 90¢ | 5% / 3% / 2% of account |
The primitives are the caps, the factor math, and the evidence that the caps hold on a full price grid. A firm-wide VaR dashboard, continuous futures margin, and automated correlation discovery are products you build around those primitives, not substitutes for them.
What I would check if I were reviewing this
If someone handed me a risk engine for event contracts, I would ask:
- Do you model dual-book manipulation with VWAP and reversion, or only B-book mark-to-market?
- Does your price grid include the thin tails (0.1¢ and the high nineties), or only comfortable mids?
- Is impact room-limited near the top of the book?
- Is correlation continuous?
- Can I see multi-seed EV under the cap and an uncapped control?
- Are the constants justified, not vibes?
This package is my answer to those questions. The simulations and threshold grid are in-repo. The charts above are the same numbers.
If you B-book public event markets, start with liquidity × price caps and continuous correlation. Binary flags will either over-trade or over-block. Thin books without a manip formula will get farmed. Extreme prices without room-limited impact will lie to you.
That is the work.