← The short versionThe market maker, in full
A binary logarithmic market scoring rule, with this event's actual numbers
0. What problem this solves
There are a few standard ways to run a betting game, and each one has a catch:
- Bookmaker. The house sets odds and eats the risk. If the lines are bad, points inflate without bound.
- Pari-mutuel pool. No counterparty risk, but nobody knows their payout until the pool closes.
- Order book. Needs someone on the other side at the same moment, which a room of wedding guests won't reliably provide.
We use Hanson's logarithmic market scoring rule (LMSR), an automated market maker. It always quotes, fills instantly, locks the fill, and its worst-case loss is a constant you choose up front.
That constant is the seed S, and it means every market created injects up to 10,000 new points into the ecosystem. The seed is the only way points enter the game after starting balances, so total inflation is capped at seed times number of markets.
1. State and cost function
Each market has two outcomes. A contract on a side pays 1 point if that side wins. Let qY,qN∈Z≥0 be the contracts sold on each side and b>0 the liquidity parameter. The maker's cost function is
C(qY,qN)=bln(eqY/b+eqN/b) Moving the state from q to q′ costs C(q′)−C(q). C is convex and increasing in each coordinate, so buying is never free and later buyers of a side always pay more per contract than earlier ones.
For an opening probability p0 the initial state is q0=(blnp0,bln(1−p0)), which gives C(q0)=0 and an opening price of exactly p0. We store the integer contracts sold and fold q0 into the price as an offset.
2. Price is probability
The instantaneous price of a YES contract is the partial derivative of the cost function:
pY=∂qY∂C=eqY/b+eqN/beqY/b=σ(bqY−qN+logitp0),σ(z)=1+e−z1 pN=1−pY=σ(−z) Prices sum to one and behave as probabilities. We evaluate pN as σ(−z) directly rather than 1−pY: near z≈30, 1−σ(z)≈10−13 and computing it by subtraction discards nearly all significant digits, which undercharges buyers of the cheap side and breaks the bound in §5.
3. Filling a bet
Guests think in points, not contracts, so we solve for the x contracts whose cost equals the stake s. Buying YES, with Σ=eqY/b+eqN/b so that pY=eqY/b/Σ:
bln(e(qY+x)/b+eqN/b)−blnΣe(qY+x)/bex/bx=s=es/bΣ−eqN/b=pYes/b−pN=bln(pYes/b−(1−pY))=blog1p(pYexpm1(s/b)) The last form is what runs. expm1 and log1p keep precision for small s/b, and for s/b>30 we use the asymptote x≈s−blnpY to avoid overflow. Sanity check: as s→0, x≈s/pY, the spot price. The average price paid, s/x, lies strictly between the pre- and post-trade probabilities.
4. Choosing b from the seed
The host sets the seed S, the most the maker may lose on one market, and b follows from the bound in §5:
b=ln(1/min(p0,1−p0))S⟹b=ln2S for p0=21 This event: S=10,000⇒b=0.693147…10,000=14,426.95 For a skewed open such as 80/20 the same seed yields a smaller b, so the worst case (everyone piles onto the 20% side and it wins) still costs exactly S.
5. Why the loss is bounded
Suppose YES wins. The maker pays qY and collected R=C(q)−C(q0) in exact arithmetic. Its loss is
LY=qY−(C(q)−C(q0))=qY−bln(eqY/b+eqN/b)+C(q0)≤qY−blneqY/b+C(q0)(drop eqN/b>0)=C(q0)=bln2=Sfor q0=(0,0) With a skewed q0 the payout term becomes qY−qY,0 and the bound is −qY,0=bln(1/p0). You only reach the bound when essentially all money lands on the winner. In a mixed market the maker loses less, and when the crowd is wrong it profits, since it never pays out losing stakes. Inflation across the event is at most S×markets and usually a fraction of that. There is no rake and no guest edge: at the true probability a bet has zero expected value minus the price impact you cause yourself.
6. Integers, rounding, and the ledger
- The guest picks an integer stake s and the ledger charges it exactly.
- We floor contracts: x⋆=⌊x⌋. Since C is increasing, C(q+x⋆)−C(q)≤s, so the guest slightly overpays, the remainder stays with the maker, and realised loss never exceeds the bound. We reject a bet that floors to zero contracts.
- qY,qN are integer sums of contracts sold and you can rebuild them from the bets table. Probabilities are display-only floats derived from them.
- Every balance change is appended to the ledger.
- Settlement pays exactly the contracts quoted at purchase. Undo reverses those rows and cancel refunds stakes.
7. Worked example with this event's settings
Seed 10,000, b=14,426.95, per-bet cap 5,000, market opens at 50/50.
Bet 1: 5,000 on YES at pY=0.50.
x=blog1p(0.5expm1(5,000/b))=8,706 contracts,pY←σ(b8,706)=65 Average price 57%. Payout if YES 8,706, profit +3,706.
Bet 2, same side: another 5,000 on YES at pY=65 buys only 7,143 contracts and moves the price to 75%. The price moved against you.
Bet 2, other side instead: 5,000 on NO at pN=35 buys 11,187 contracts (2.24× if NO), and pulls YES back to 46%.
In every branch, Bet 1 still holds 8,706 contracts. Nothing after a fill changes it.
8. Operational details
- Slippage guard. The client quotes locally from the state it rendered with and sends the quoted contracts with the bet. The server re-quotes inside a transaction, and if the fill would be over 2% worse than shown, it refuses and the guest sees the new quote.
- Repeated bets are fine and the cap is per bet. A position's average price is ∑si/∑xi.
- Clamp. We limit opening probabilities to [0.02,0.98] so b stays finite.
- Cashing out. Selling x contracts is the same trade in reverse, so the proceeds are C(q)−C(q−xeside)=−blog1p(p⋅expm1(−x/b)), floored. Because the cost function is path independent this doesn't change the loss bound at all. We only allow selling a whole position on a side, and only while the market is open.
- Leaderboard. Guests are ranked by balance plus open positions marked at current prices, ∑xipi. Summed over everyone that equals the maker's expected loss at today's prices, which is the seed showing up in the pie. It is deliberately not the liquidation value, since selling a whole position moves the price against you and would make every holder look underwater.
- Not implemented yet: more than two outcomes. The cost function generalises to bln∑ieqi/b with bound blnn.