prediction-markets · polymarket · arbitrage · convex-optimization · market-making
At 08:55 UTC on 22 September 2026, fifteen Polymarket order books about the Federal Reserve's next two meetings contained a portfolio that cost 9,477.48 USD and paid at least 9,572.65 USD, whatever the Fed decides. That is 95.17 USD locked in before the Fed says a word.
No single market offered a sure profit on its own. In every one of them, Yes and No together cost slightly more than a dollar, exactly as they should. The profit sat between the markets, in logical constraints the exchange does not enforce. Checking those constraints two contracts at a time, the way you would by eye, found 3.73 USD. Finding the other 91 took a linear program.
My reel sketched the idea in two minutes: payoff vectors, a convex hull, a separating hyperplane. This is the full version, with the proofs, working code, real order books, the market maker's side of the same geometry, and the papers behind all of it. It is long because each piece is used by the next one.
A Polymarket contract pays 1 if its event happens and 0 otherwise. The mechanism under it is a split: one unit of collateral (pUSD, a USDC-backed token since the April 2026 upgrade) mints one Yes and one No, and a Yes plus a No merge back into one unit. The matching engine uses this directly. A buy order for Yes at 0.60 and a buy order for No at 0.40 are matched by minting a fresh pair.
The consequence is that the Yes book and the No book are one book seen from two sides. The best No ask is one minus the best Yes bid, so buying both at the asks costs exactly . A replay of 308,416,666 WebSocket messages found the two books identical apart from 20 API glitches (Gebele, Mutzel & Matthes, 2026). I checked a live market this morning: Bitcoin above 86,000 on 23 September had Yes at 0.531 and No at 0.471, total 1.002.
Multi-outcome events ("negRisk" markets) get one more piece of glue. A converter turns No tokens into units of collateral plus one Yes on every other outcome. The contract enforces that at most one outcome resolves Yes, and it only runs in the No-to-Yes direction.
Nothing links separate events. "Who wins Pennsylvania" and "Pennsylvania margin of victory" are independent markets. So are the rungs of a "Bitcoin above K" ladder, and the meeting-by-meeting Fed markets versus the market on the Fed's whole path. Polymarket's newer Combos let you buy conjunctions through a request-for-quote, which adds a product and constrains nothing. Polymarket US nets ordered strike ladders against each other for margin, and its own documentation is clear that this lowers the collateral you post while leaving the risk where it was.
Inside a market the walls are built into the plumbing. Across markets they exist only if someone trades against the gaps. The problem is older than Polymarket: in 2011-12 Intrade let "Romney to sweep the first five primaries" trade above "Romney to win Iowa", which is impossible (Dudík, Lahaie & Pennock, 2012).
Take contracts, contract paying 1 if event happens. Let be the set of logically possible worlds and write each world as its payoff vector , the list of which contracts pay. A portfolio is a vector : buys Yes, buys No, which is the same trade as selling Yes plus a unit of cash that cancels out. Its profit in world is
where is the vector of Yes prices. The object that decides everything is the convex hull of the possible payoff vectors,
Theorem (de Finetti). No portfolio earns a sure profit if and only if .
One direction takes a line. If with a probability distribution, then for every portfolio
so the profit cannot be positive in every world. Coherent prices are exactly the prices that are the expected payoffs under some probability distribution over the worlds. The weights are the market's implied probabilities of complete scenarios, and is their average. Predd et al. (2009) state the convex-hull form cleanly as their Proposition 1. de Finetti described coherent points as those with no hyperplane separating them from the possible points.
For the reel's two contracts, win Pennsylvania () and win it by 5+ (), the possible vectors are , and . The fourth corner is impossible, so is the triangle . The unit square is everything two independent books can quote. The triangle is the part logic allows.

Add a third contract and the triangle becomes a tetrahedron. With nested thresholds (win, win by 2.5+, win by 5+) the corners are 000, 100, 110 and 111, and is the ordered simplex . Two events plus their conjunction, the structure of a parlay, give corners 000, 100, 010 and 111. The facets of that tetrahedron are the Fréchet bounds
This is Pitowsky's correlation polytope (1991). Boole wrote the same inequalities down in 1854, and Pitowsky's summary is that "Boole's conditions are just the conditions of coherency". They show up in live quotes. On Kalshi's request-for-quote combos, 13 of 33 two-leg parlay quotes sat above the Fréchet upper bound (Rana et al., 2026). Those were one-sided quotes you could only buy, so they sat outside the hull without handing anyone a trade.

Now the useful direction. If , then is a point outside a closed convex set, and the separating hyperplane theorem (Boyd & Vandenberghe, Section 2.5) hands you and with
Take the portfolio . Its profit in every world is
The normal vector of the hyperplane is the portfolio, and the distance by which the price violates the inequality is the guaranteed profit. Abernethy, Chen & Wortman Vaughan (2013) prove their central market-maker theorem with exactly this move. A price outside the hull is cut off by a halfspace, and buying the bundle defined by its normal is an arbitrage.
For the reel, the violated facet is , so , and : long Yes on the win, long No on the margin. At the package costs and pays in the three worlds, a sure 0.05, or 5.26% on the money spent.
The boundary deserves a sentence. At no inequality is violated and the best guaranteed profit is zero. The same trade then costs exactly 1 and pays : you never lose and sometimes win. Formally, sure profit exists iff , and a "free lottery" exists iff is outside the relative interior of (Schervish, Seidenfeld & Kadane, 2008). Finance knows this as the finite-state Fundamental Theorem of Asset Pricing. No weak arbitrage is equivalent to strictly positive state prices (Stiemke's lemma). No strong arbitrage is equivalent to nonnegative ones (Farkas' lemma). de Finetti had the betting version decades before Ross proved the finance one, and Dybvig and Ross gave it its name. With fees, the boundary case loses money, so it matters more in theory than on a real book.
The theorem says a hyperplane exists. A trader wants the best one. Normalize the portfolio to one unit of gross exposure and maximize the worst-case profit:
LP duality turns the trader's problem into a statement about the market:
The best guaranteed profit per unit of exposure is the sup-norm distance from the price vector to the hull. Cap each position instead () and the same argument gives the distance. Andrews & Sarkar (2026) use exactly this pair to measure incoherence in language-model forecasts. The primal is the trader, and the dual is the coherent world closest to what the market is quoting.
On the reel's numbers the sup-norm version returns 0.025 with . The per-contract cap returns 0.05 with , the reel's trade. The nearest coherent price is . Here is the whole solver:
import numpy as np
from scipy.optimize import linprog
def arbitrage_lp(Phi, p):
"""Best guaranteed profit per unit of gross exposure (sum |h_i| <= 1).
Phi: outcomes x contracts matrix of 0/1 payoffs; p: Yes prices.
Returns (profit, h): h_i > 0 buys Yes on contract i, h_i < 0 buys No.
"""
m, n = Phi.shape
A = Phi - p # payoff minus price, per unit
c = np.r_[np.zeros(2 * n), -1.0] # maximize t, with h = u - v
A_ub = np.r_[np.c_[-A, A, np.ones(m)], # t <= A(u - v) in every outcome
[np.r_[np.ones(2 * n), 0.0]]] # sum(u + v) <= 1
b_ub = np.r_[np.zeros(m), 1.0]
bounds = [(0, None)] * (2 * n) + [(None, None)]
res = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, method="highs")
return res.x[-1], res.x[:n] - res.x[n:2 * n]
Phi = np.array([[0, 0], [1, 0], [1, 1]]) # (win, win by 5+)
profit, h = arbitrage_lp(Phi, np.array([0.62, 0.67]))
print(profit, h) # 0.025 [ 0.5 -0.5]The input is the list of possible worlds, one row each, and the prices. The LP does the rest. Everything else in this article is about what happens when those two inputs get realistic.
A real book has two prices per contract. Going long contract costs its ask . Going short means buying No at , which is selling at the bid. The quote is a box . There is a sure profit only if the whole box misses ; if any point of the box is coherent, every portfolio loses in some world at those quotes. This is the static version of Jouini & Kallal (1995), where no arbitrage is equivalent to a consistent price system between bid and ask. For the reel's pair the condition collapses to one line: the trade exists iff the margin's bid is above the win's ask. In the figure above, box A has its midpoint outside the triangle and still overlaps it, so there is no trade. Box B clears it by 0.03.
Fees shrink the box's margin further. Polymarket charges takers per share, with between 0.04 and 0.07 by category in 2026 (geopolitics is free), and makers pay nothing. At the politics rate the reel's package pays 0.0183 in fees, which cuts its 0.05 to 0.0317.
Midpoints outside the hull are everywhere. Sure profits at the quotes are rare. This morning's Ethereum "above K" ladder had three strikes priced out of order at the mid and zero once you used bids and asks. The eleven Bitcoin price buckets for the same day summed to 1.0165 at the mid. Buying all of them cost 1.047 at the asks and selling all of them raised 0.986 at the bids, so neither direction worked. Across 9,988 multi-outcome Polymarket events, Zang, Andrade & Nakajima (2026) find the cost of buying every Yes rises by 0.0595 per unit of log-outcome-count, 96% of it from the quoted markup, while the mids stay centered. The box grows with the number of outcomes, and its center stays put.
The reel's own structure existed in 2024. Polymarket listed "Who will win Pennsylvania?" and a twelve-bucket "Pennsylvania Margin of Victory". The winner price should equal the sum of the six Trump buckets, and "Trump by 2.5% or more" should never trade above the winner. I pulled the permanent 12-hour price series for all of them.

Over 93 twelve-hour points from 20 September to the eve of the election, the inequality never came close: the 2.5%+ bucket stayed at least 27 cents below the winner. The identity was noisier. The winner traded a median 2.3 cents above the sum of the Trump buckets, with a range of -2.8 to +15.4 cents. All twelve buckets summed to between 1.02 and 1.12, median 1.06, and reached 1.247 on the morning of the election. Those are price-series values, most likely midpoints, not executable quotes, so none of it is a trade. It shows the hull being violated at the mid for weeks on end.
The top of the book is a few hundred shares. Beyond it, each order book is a staircase of levels, and the cost of buying shares is convex and piecewise linear in . Fees are charged per share at each fill price, so they keep each level linear. The depth-aware best arbitrage is therefore still a linear program, with one variable per book level and one constraint per possible world:
where buys Yes on contract at ask level and buys No at one minus bid level . and are the totals, and is the fee. The same structure appears in Fortnow, Kilian, Pennock & Wellman (2005) for matching orders on logical securities.
def book_lp(books, Phi, rate=0.05):
"""Max guaranteed profit over every level of every order book.
books[j] = {"asks": [(price, size), ...], "bids": [(price, size), ...]}
for the Yes token of contract j; Phi[w, j] = 1 if contract j pays in outcome w.
Yes is bought at an ask, No at 1 - bid (the two books mirror each other).
"""
fee = lambda x: rate * x * (1 - x) # taker fee per share
cost, pay, cap = [], [], []
for j, book in enumerate(books):
for a, size in book["asks"]:
cost.append(a + fee(a)); pay.append(Phi[:, j]); cap.append(size)
for b, size in book["bids"]:
cost.append(1 - b + fee(b)); pay.append(1 - Phi[:, j]); cap.append(size)
cost, pay = np.array(cost), np.array(pay).T # pay: outcomes x fills
m = len(Phi)
res = linprog(np.r_[cost, -1.0], # minimize cost - t
A_ub=np.c_[-pay, np.ones(m)], b_ub=np.zeros(m),
bounds=[(0, s) for s in cap] + [(None, None)], method="highs")
return -res.fun, res.x[:-1]This is the function that found the 95 USD. The setup is three negRisk events on Polymarket:
The worlds are the 25 (October, December) pairs, with 15 contracts and a 0.05 taker fee rate.
The natural checks are pairwise. The December "no change" bracket can be no cheaper than the two paths that end in a December pause: . At 08:55:11 UTC the mids broke all four such bounds by 3.05 to 6.5 cents. At the quotes after fees, the four packages would have earned -3.41, +0.13, -3.78 and +1.73 cents. The best of them, walked through the depth, locked in 3.73 USD on about 896 USD of capital.
The joint LP found 95.17 USD on 9,477.48 USD. Its unit package has seven legs:
It pays at least 3 in each of the 25 worlds. It cost 2.8675 at the mids and 2.894 at the quotes, plus 0.0375 in fees, leaving 6.85 cents per package. It fuses the October-hike and December-pause violations into one position. The Hike-Hike-Pause leg they share, bought in one pairwise package and sold in the other, drops out, and its 0.21/0.23 book was among the widest on the board. Legs cancelling is the reason the joint LP finds far more than any pair on its own.

Three minutes later, at 08:58:07, every pairwise package was negative. The joint LP still found 23.88 USD on 4,228.11 USD, a quarter of the earlier edge.
The LP proves a payoff of at least 9,572.65 USD in every world. It says nothing about when that payoff arrives, whether the contracts resolve the way the model assumes, or whether all fifteen legs actually fill. Each of those three gaps can erase the edge.
The clock. The Fed packages pay on 9 December, 78 days out. 95.17 USD on 9,477.48 USD is 1.00% for the period, 4.70% annualized. The 08:58 book gives 0.57%, or 2.64% annualized. Kalshi pays 3.25% a year on cash and open positions, and Polymarket pays a 3.25% holding reward on 18 listed long-dated markets (not these). So this "arbitrage" is a short-dated bond with extra risk attached. Formally, with an opportunity rate , a package costing that pays at least at beats cash only if . Page & Clemen (2013) derive the resulting no-trade band: at a 5% rate nothing above 0.95 or below 0.05 should trade with a year or more to go. Gebele & Matthes (2026) measure the same wedge on near-certain Polymarket contracts at 3.06% to 6.89% annualized.
The referee. The whole construction assumes you know , which contracts pay in which world. Resolution rules decide that, and two contracts about "the same" event can disagree:
Polymarket's oracle adds its own variance. UMA proposals face a two-hour challenge window, and a second dispute goes to a token-holder vote. The Ukraine minerals market (7.08M USD of volume) resolved Yes before any deal existed. The Zelenskyy suit market went through five propose-and-dispute rounds on 242M USD of volume.
Geometrically, resolution risk means extra worlds. Add "the rules disagree" to and you add vertices. grows, and a price vector that was outside the old hull can sit inside the new one. The arbitrage only existed in the smaller outcome space.
The plumbing. The seven legs of a package do not fill atomically. Polymarket matches off-chain and settles on-chain, and Shen et al. (2026) document 980,133 filled orders that were reverted before settlement, over 24.3% of fills at peak hours, with at least 1.49M USD extracted. One pattern is aimed squarely at arbitrage bots. The attacker posts a fake cross-outcome arbitrage, lets a bot fill part of the basket, then cancels the remaining legs.
The Fed example had 25 worlds. Logic rarely stays that small. With unrelated binary events there are worlds, one LP constraint each. David Pennock's 2012 combinatorial election market counted 2 to the power 57, about 144 quadrillion, possible electoral maps. Deciding whether a price vector lies in a correlation polytope is NP-complete in general (Pitowsky, 1991). Even pricing a combinatorial LMSR is #P-hard for simple bet languages (Chen et al., 2008).
In practice you never list the worlds. You keep a small working set, solve the LP on it, then ask an integer program for the world that hurts the current hedge the most, add it, and repeat. This is column generation, and its pricing step is a 0-1 program over the logical constraints. The LP view of coherence is old: Boole posed the problem, Hailperin wrote it as a linear program in 1965, and Nilsson (1986) rediscovered it as probabilistic logic. Hansen et al. (1995) solved probabilistic-logic instances with 140 variables and 300 sentences this way, generating about 2,100 of the possible columns. Modern MILP solvers make this routine at the sizes prediction markets produce.
The binding constraint is writing down at all: deciding which contracts are logically linked, and how.
A relation that holds 62.8% of the time is a statistical bet. Encoding it as a hard constraint in turns a correlation into a fake arbitrage.
The measured history reflects all of this. Saguillo et al. estimate 39.6M USD of realized arbitrage profit on Polymarket between April 2024 and April 2025, from trade prices and before fees, which Polymarket did not charge at the time:
Gebele, Mutzel & Matthes recount the same window counting only profits tied to an actual conversion or a completed basket, and get 291,424 USD. Over 2024 to 2026 they count 1.12M. Their book replay found the Yes and No books to be exact mirrors, so they treat single-market Yes-plus-No gaps in trade data as feed artifacts and leave them out. The median profit per conversion fell from about 1 USDC before July 2024 to 0.08 in early 2026, which is what competition looks like. In sports the reel's nesting is moneyline versus spread. Cheng, Yang & Zou (2026) found 290 executable episodes in 173 NBA games, with a median return of 101 bps, and 76.9% of them capped at an average of 14.8 shares.

Now switch sides. An order book is a set of independent books, and nothing inside it keeps the joint price vector in . An automated market maker can do that.
Hanson's logarithmic market scoring rule (LMSR) prices exclusive outcomes with a cost function
where is the vector of shares sold and a trade costs . The market maker's worst-case loss is . Over a combinatorial outcome space, the same construction becomes
Prices are expectations under a Gibbs distribution over worlds, so they sit inside by construction. This is an exponential family in disguise. The cost function is the log-partition function, prices are its mean parameters, and the space of reachable prices is the marginal polytope of Wainwright & Jordan (2008). Abernethy, Kutty, Lahaie & Sami (2014) spell out the dictionary: market prices correspond to mean parameters, and the cost function to the log-partition function.
Abernethy, Chen & Wortman Vaughan (2013) prove this is the only way to do it. Ask for path independence, well-defined instantaneous prices, information incorporation, no arbitrage and expressiveness. Then the closure of reachable prices must equal (their Theorem 3.2), and every such market maker has the form
for a strictly convex (Theorem 4.2). Its worst-case loss is exactly (Theorem 4.4). For the LMSR, is times the negative entropy and the loss is . Their framework explicitly excludes continuous double auctions. A set of independent books behaves like independent cost functions, whose price space is the whole cube , larger than . That is the mechanism-level reason Polymarket's markets can be arbitraged against each other.
Why not run the combinatorial version? Because pricing it is #P-hard. The closest real attempt is PredictWiseQ, a play-money market Dudík, Lahaie, Pennock and Rothschild ran from 16 September to 6 November 2012 over state-level election outcomes (EC 2013). It had 437 traders, 3,137 trades, 17,222 securities and 20,983 consistency constraints, generated as trades arrived. Pennock's launch post explained that the market maker would never let Obama winning Ohio and Florida price above Obama winning Ohio. That is the reel's inequality, enforced by the house.
If a cost-function market maker's prices drift outside , how much can a trader extract? Kroer, Dudík, Lahaie & Balakrishnan (2016) answer exactly. Define the mixed Bregman divergence and its projection onto the hull, . Then (their Proposition 2.4)
and any trade that moves the prices to achieves it. For independent binary LMSR books, is times a sum of binary KL divergences. On the reel's quote with , the projection onto lands at the logit mean, , and the guaranteed profit is 0.2734 USD. A direct convex program over trades agrees to four decimals. Arbitrage against a market maker is a distance to the hull, measured in the market maker's own geometry.
The projection is a convex program over , and has too many corners to list. Frank-Wolfe needs only a linear-minimization oracle over the corners, , which is one integer program over the logical constraints. Each step moves toward the best corner, and the Frank-Wolfe gap certifies how far from optimal you are. Kroer et al. show that moving the market to earns at least , which gives a stopping rule measured in money. Two refinements matter in practice. The fully corrective variant re-optimizes over every corner found so far. And because the LMSR's gradient blows up at the boundary of , they shrink the polytope slightly toward an interior point and relax the shrinkage adaptively, following Krishnan, Lacoste-Julien & Sontag (2015).
The code is short. The logic lives in the constraint matrix: here a synthetic swing-state market with 7 state winners, 7 "wins by 5+" contracts and a national winner through electoral votes.
from scipy.optimize import Bounds, LinearConstraint, milp, minimize_scalar
from scipy.special import logit
EV = np.array([11, 16, 15, 6, 16, 19, 10]) # AZ GA MI NV NC PA WI
# z = (w_1..w_7, m_1..m_7, N): wins state, wins it by 5+, wins the presidency
A = np.zeros((9, 15)); lo = np.full(9, -np.inf); hi = np.zeros(9)
for i in range(7):
A[i, 7 + i], A[i, i] = 1, -1 # m_i <= w_i: a 5+ win is a win
A[7, :7], A[7, 14], lo[7], hi[7] = EV, -51, 0, np.inf # N = 1 needs 51 swing EV
A[8, :7], A[8, 14], hi[8] = EV, -93, 50 # N = 0 allows at most 50
LOGIC = LinearConstraint(A, lo, hi)
def oracle(c):
"""Cheapest outcome vector in direction c: one integer program."""
res = milp(c, constraints=LOGIC, integrality=np.ones(15), bounds=Bounds(0, 1))
return np.round(res.x)
def frank_wolfe(p, mu, b=100.0, iters=300, tol=1e-6):
"""KL projection of independent LMSR prices p onto the hull M."""
D = lambda m: b * np.sum(m * np.log(m / p) + (1 - m) * np.log((1 - m) / (1 - p)))
for it in range(iters + 1):
grad = b * (logit(mu) - logit(p))
z = oracle(grad) # best corner for this gradient
gap = grad @ (mu - z) # D(mu) - D(mu*) <= gap
if gap < tol or it == iters:
return mu, D(mu) - gap # guaranteed profit >= D - gap
d = z - mu
step = minimize_scalar(lambda s: D(mu + s * d), bounds=(0, 1 - 1e-12),
method="bounded").x
mu = mu + step * dThis market has worlds, few enough to check by brute force. I priced it with a correlated model, let the books drift, and broke two implications. The brute-force projection is worth USD. Fully corrective Frank-Wolfe certified it to a gap below after 13 oracle calls, plus 30 to find a starting point. The plain version above was still at a gap of 0.47 after 300.

Two caveats before anyone builds a bot on this. First, Kroer et al. tested their market maker on play money: Yahoo's Predictalot over the 2010 NCAA tournament, outcomes and 93,036 bets. With a 30-minute budget, the first full projection only finished after 45 of the 63 games had settled, and the paper measures forecast accuracy, not trading profit. It is a market-maker design, and posts that call it "the Polymarket arbitrage algorithm" are repurposing it. Second, Proposition 2.4 is about a cost-function market maker. Against an order book the exact tool is the depth LP from the previous section.
The last piece is quoting a single binary well. Glosten and Milgrom's 1985 model is, in its own worked example, a two-valued asset, which makes it a prediction market. Let with prior . A fraction of traders know and trade on it, and the rest buy or sell with probability one half. A competitive, risk-neutral market maker quotes the conditional expectations and :
At the spread is exactly . In price units the quotes are lopsided. In log-odds they are perfectly symmetric, because a buy multiplies the odds by :
Now look at the fee schedule. A taker fee of per share is, to first order, a constant in log-odds, since . At it ranges from 0.0488 to 0.0513 across the whole price range. Polymarket's and Kalshi's fee curves both charge a flat log-odds toll. In Glosten-Milgrom terms, rates of 0.04, 0.05 and 0.07 match the spread of a market with 2%, 2.5% and 3.5% informed traders ().

Inventory is the other half, and it behaves differently near resolution. If the contract's "score" follows a Brownian motion, the price is and
which depends only on the price and the time left (Archak & Ipeirotis, 2009). At a one-hour move has a standard deviation of 1.49 cents a month out, 3.08 cents a week out and 8.14 cents on the last day. On Kalshi data a shape forecasts hourly volatility better. Xi, Moallemi, Pai & Wang (2026) report a 10% better interval score, and another 13% from adding a Glosten-Milgrom term in the spread and volume.
A position of contracts held to resolution carries variance . With exponential utility, the indifference price of the inventory is approximately . That is Avellaneda-Stoikov's reservation price with replaced by , the variance a binary still has to release before it settles. (That substitution is my own derivation. The generic model is in the Market Making Machine article.) Feil & Nendel (2026) solve the full stochastic-control problem with a settlement penalty . In their simulation the optimal quotes cut the standard deviation of P&L from 28.11 to 10.34, while mean P&L went from 12.47 to 12.39.
Automated market makers face the same volatility through loss-versus-rebalancing (LVR), what a pool loses to arbitrageurs trading against its stale price. Paradigm's pm-AMM chooses the invariant so that LVR per unit of pool value does not depend on the price. The pool value is and . The dynamic version shrinks liquidity like to hold expected LVR constant over time, at the price of losing half the initial wealth in expectation. A constant-product pool is cheaper at 0.5 (0.318 against 0.5, in units of ) and far worse in the tails (0.907 at ). Moallemi, Robinson & Zhu (2026) generalize the construction: constant product is exactly the uniform AMM for a price that diffuses linearly in log-odds. I could not find pm-AMM running on a production venue, only a hackathon build and a testnet beta.

The live venues pay makers to carry this risk. Polymarket's liquidity rewards score each resting order by
where is the maximum qualifying spread, the order's distance from the size-adjusted midpoint and a market multiplier. One-sided quotes stop scoring below 0.10 and above 0.90. Makers pay no fees and receive 15-25% of taker fees back.
The evidence says makers are on the right side:
On a binary, market making is inventory carried to resolution, which is why every tool in this section scales with .
1. Write the outcome table before you look at prices. The whole edge is . If you cannot list which contracts pay in which world, resolution rules included, you have a correlation bet with an arbitrage label on it.
2. Test at the quotes, never the mids. The ETH ladder had three violations at the mid and none at the quotes. The Pennsylvania buckets summed to 1.02 to 1.12 for weeks. Midpoints outside the hull are the normal state of a prediction market.
3. Solve jointly. On the same fifteen books, the best pairwise package locked in 3.73 USD and the LP locked in 95.17. Legs cancel, and cancelled legs skip their spreads and fees.
4. Put the clock in the inequality. 1% over 78 days is 4.7% a year, about what cash earns on the venue. Discount every package's payoff by before you compare it with the cost.
5. Budget for the referee and the plumbing. Resolution sources, oracle disputes and reverted fills are extra worlds in . Price them before you call anything riskless.
6. If you make markets, think in log-odds. The adverse-selection spread, the fee schedule and the inventory risk all scale with . In log-odds units they are flat, so one quoting rule covers the whole price range.
The machinery in this article is convexity, constrained optimization and Bayes' rule. QuantFrame's Optimization module builds the first two up to KKT conditions, and Probability & Random Variables covers the event algebra and belief updating the rest runs on. This breakdown stays free; your roadmap is at quantframe.io.
Coherence, duality and arbitrage
Combinatorial markets and cost-function market makers
Market making for binary contracts
Prediction-market arbitrage in the data
Venue documentation (accessed 22 September 2026)
Found this useful?
Likes decide what gets written next.Sign in to like
QuantFrame teaches you the math, code, and projects to break into quant. Plus a personalized roadmap built for your background and goals.