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.

01
Open on the B-book

Buy YES against the platform at mid p. No real CLOB fill. The desk is the counterparty.

02
Push the external book

Buy the same side on the public market with personal capital. Mid walks by impact Δ.

03
B-book marks

Internal mark jumps to p+Δ. B-book profit is about (S / p) × Δ while personal paid VWAP.

04
Unwind personal

Sell after partial reversion. Fees and reversion usually dominate unless S is too large for L.

Dual-book attack when a B-book marks to an external market. The defense is not hoping reversion is high. It is capping S against price × liquidity.

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.

StatisticValue
Seeds × attacks32 × 200
Price range0.1¢ – 99¢
Liquidity range$1k – $1M
Mean attacker PnL (capped)-$1,077
Median attacker PnL-$752
P10 / P90-$3,352 / +$497
Attacker win rate13.5%
Uncapped mean (baseline)+$2,654
Threshold grid171 / 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.

$0$250$500$750$1000$12500¢20¢40¢60¢80¢100¢high-acc cliffs
$10k liq$50k liq$100k liq$500k liq
Max allowed B-book size on a $5k account across 0.1¢–99¢. Below about 80¢ the curve is liquidity × price. Above 80¢ the high-accuracy caps flatten it.

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
-9.4-23.7-30-35.9-38.5-39.9-40.8-41.1-52.6
-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
Best attacker net under the B-book size cap across 0.1¢–99¢ and $1k–$1M liquidity. Every cell is negative. The full 171-cell grid has zero leaks.

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:

PriceMax 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.

0.901.000.801.00−0.85Vance YESpersonParty R YESpartypres_2028_Rfactorpres_2028_DfactorParty D YESpartyNewsom YESperson
Aligned R bookraw $1,000 to eff $1,074
Offset R vs Draw $1,000 to eff $50
House seats (rho about 0.4)raw $1,200 to eff $930
Newsom is not wired into the Republican factor. He loads on Dem with Party D. Vance and Party R stack on the R factor. That is why continuous loadings beat a single correlated flag.

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.

KnobDefault
Max position25% of account
Per market10%
Per multi-outcome group15%
Effective correlated exposure20%
Min liquidity$10,000
Min 24h volume$5,000
Manip coefficient0.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.