Event Contract Arbitrage: YES + NO vs $1
One YES plus one NO always pays $1 at settlement. Here is how event contract arbitrage works when the two books disagree, and what fees and collateral cost.
Event contract arbitrage starts from one identity: a single YES and a single NO on the same question pay exactly $1 between them at settlement, since one side resolves at $1 and the other at $0. When the two asks add to less than $1 the pair locks in the difference, and when the two bids add to more than $1 the difference lands up front instead. In the order book the two prices sit a cent or two away from $1 most of the time, and nearly all of that gap belongs to fees and to the cash held until the question resolves. For the pricing convention underneath, start with event contract prices as probabilities.
What does YES plus NO equal on an event contract?
A binary event contract pays a fixed $1 if a stated outcome happens and nothing if it does not. Prices quote in cents, roughly 1 to 99, and the smallest step, the tick, is normally one cent. Buy YES at 60 cents and NO at 40 cents on the same question and you have paid $1 for $1 of guaranteed payout.
Two conditions make the identity exact. The contracts have to resolve off one question, with identical wording and an identical settlement source, and they have to be matched in size, one YES against one NO. How event contracts settle covers the resolution source, which is where an identity like this holds or quietly breaks.
When can you buy YES and NO for less than $1?
The YES ask and the NO ask are the two prices available to you this second, so add them. A sum under $1 means those two offers together hand over a fixed $1 payout for less than a dollar, and the gross edge per pair is $1 minus the two asks.
When can you sell the pair for more than $1?
Reverse it. The YES bid and the NO bid are the prices you can sell into immediately. When those two add to more than $1, selling one of each collects more than a dollar today against a $1 obligation at resolution.
Selling a contract you do not hold is a short position, and the venue holds collateral against it until the question resolves. A short YES and a short NO on the same question can only ever pay out $1 in total, and a venue that nets the pair holds little beyond the credit already received. A venue that margins each leg on its own ties up most of a dollar per pair against an obligation the credit has already funded.
Why the sum drifts away from $1
- Two books, not one. Nothing in the matching engine forces the best YES offer and the best NO offer to add to exactly $1.
- A resting bid on one side is an offer on the other. Buying YES at 60 and selling NO at 40 are the same economic position, so a resting YES bid at 60 is in substance a NO offer at 40.
- Fees, charged per contract and per leg. The taker fee for removing a resting order lands twice on a trade whose whole edge is a cent or two.
- The tick is enormous next to the notional. One cent on a $1 contract is a full percent of the payout.
The panel below takes the quoted spread, the distance between the best bid and the best offer, on four household names in a fifteen minute mid-morning sample of recent sessions. What a bid-ask spread is has the mechanics.
The exact SQL behind every number
SELECT
ticker,
round(avg(toFloat64(ask_price) - toFloat64(bid_price)) * 100, 2) AS spread_cents,
round(avg((toFloat64(ask_price) - toFloat64(bid_price))
/ ((toFloat64(ask_price) + toFloat64(bid_price)) / 2)) * 10000, 2) AS spread_bps,
countDistinct(toDate(toTimeZone(sip_timestamp, 'America/New_York'))) AS sessions_sampled
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('SPY', 'AAPL', 'MSFT', 'KO')
AND sip_timestamp >= today() - 9
AND sip_timestamp < today() - 2
AND toHour(toTimeZone(sip_timestamp, 'America/New_York')) = 10
AND toMinute(toTimeZone(sip_timestamp, 'America/New_York')) < 15
AND bid_price > 0
AND ask_price > bid_price
GROUP BY ticker
ORDER BY spread_bps DESCOver 5 sessions of that sample, the widest of the four, MSFT, averaged 2.68 basis points of its own price, or 13.18 cents. The tightest, SPY, averaged 0.32 basis points. A basis point is one hundredth of a percent. A one cent wide market on a $1 event contract measures 100 basis points on that scale, so the penny that rounds to nothing on a household share price is the entire edge on an event pair.
Event contract arbitrage, priced out line by line
Here is the whole calculation in a short Python script, standard library only. Save it as yes_no_arb.py and run python3 yes_no_arb.py.
#!/usr/bin/env python3
'''YES and NO pair arithmetic. Every quote and fee below is invented.'''
LOT = 100 # contracts per leg
TAKER_FEE = 0.0035 # per contract, charged on each leg
DAYS = 46 # calendar days until the question resolves
NETS_THE_PAIR = False # does the venue treat the two shorts as one $1 liability?
YES_BID, YES_ASK = 0.58, 0.60
NO_BID, NO_ASK = 0.37, 0.39
def report(label, gross, collateral):
fees = 2 * TAKER_FEE
net = gross - fees
print()
print(label)
print(f' gross edge {gross:+.4f} per pair')
print(f' fee drag {-fees:+.4f} per pair')
print(f' net edge {net:+.4f} per pair')
print(f' net on the lot {net * LOT:+.2f} dollars')
print(f' collateral {collateral * LOT:.2f} dollars for {DAYS} days')
if net <= 0:
print(' no trade: the fees are wider than the gap')
elif collateral <= 0:
print(' return: undefined, the credit covers the obligation')
else:
period = net / collateral
annual = (1 + period) ** (365 / DAYS) - 1
print(f' period return {period * 100:.2f}% over {DAYS} days')
print(f' annualised {annual * 100:.2f}%')
buy_cost = YES_ASK + NO_ASK
report('buy one YES and one NO, collect 1.00 at resolution',
1.00 - buy_cost, buy_cost)
credit = YES_BID + NO_BID
if NETS_THE_PAIR:
held = max(0.0, 1.00 - credit)
else:
held = (1.00 - YES_BID) + (1.00 - NO_BID)
report('sell one YES and one NO, pay 1.00 at resolution',
credit - 1.00, held)
With those invented quotes the buy side prints a gross edge of one cent per pair, a fee drag of seven tenths of a cent across the two legs, and three tenths of a cent left over. On a lot of 100 pairs that is 30 cents of net edge against $99 of cash locked up for 46 days, which annualises to about 2.4 percent. The sell side prints no trade, since the two bids add to 95 cents against a $1 obligation.
The annualised line reframes the position as a loan: the same net edge is worth roughly four times as much on a question resolving in 12 days as on one resolving in 48.
Why a $1 payout is worth less than $1 today
Listed options carry an identity of exactly the same kind, put-call parity: at one strike and one expiry, the call price minus the put price equals the stock price minus the present value of the strike. Put-call parity explained is the full treatment. The panel below prices both sides of it across the strikes around the money on SPY, the S&P 500 ETF.
The exact SQL behind every number
WITH
latest_day AS
(
SELECT max(date) AS d
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date >= today() - 30
),
cycle AS
(
SELECT min(expiration_date) AS exp
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date = (SELECT d FROM latest_day)
AND days_to_expiry >= 25
)
SELECT
concat('$', toString(toUInt32(strike_price))) AS strike,
round(maxIf(toFloat64(option_close), startsWith(lowerUTF8(option_type), 'c'))
- maxIf(toFloat64(option_close), startsWith(lowerUTF8(option_type), 'p')), 2) AS call_minus_put,
round(any(toFloat64(underlying_close)) - any(toFloat64(strike_price)), 2) AS stock_minus_strike,
round(any(toFloat64(underlying_close)) - any(toFloat64(strike_price))
- (maxIf(toFloat64(option_close), startsWith(lowerUTF8(option_type), 'c'))
- maxIf(toFloat64(option_close), startsWith(lowerUTF8(option_type), 'p'))), 2) AS wedge_dollars,
any(days_to_expiry) AS days_to_expiry
FROM global_markets.options_greeks
WHERE underlying_symbol = 'SPY'
AND date = (SELECT d FROM latest_day)
AND expiration_date = (SELECT exp FROM cycle)
AND volume > 0
AND iv_converged = 1
AND modulo(toUInt32(strike_price), 5) = 0
AND abs(toFloat64(strike_price) / toFloat64(underlying_close) - 1) < 0.04
GROUP BY strike_price
HAVING countIf(startsWith(lowerUTF8(option_type), 'c')) > 0
AND countIf(startsWith(lowerUTF8(option_type), 'p')) > 0
ORDER BY strike_priceCall minus put ran from 28.66 at the lowest strike shown to -25.75 at the highest, tracing stock minus strike step for step. Stock minus strike less call minus put came in at -0.29 dollars at $745 and -0.88 dollars at $800. Both readings are negative: call minus put sits above stock minus strike at each end of the curve, and the offset is the discount on strike money owed 28 days out, net of any dividend the shares pay before then.
A YES and NO pair carries the same offset. The $1 shows up at resolution, not today, so asks adding to 99 cents six weeks out may not be mispriced at all. Options desks trade this financing wedge on purpose, and box spreads and the implied loan rate works through their version.
Is event contract arbitrage free money?
Price the gap as a rate and the answer usually appears on its own. One cent of gross gap on a 99 cent pair resolving in 46 days works out near 8 percent annualised before costs, which looks obvious. The invented fee schedule above takes the same trade to roughly 2.4 percent. The yardstick is what cash earns over the same holding period with no work at all, the short end of the Treasury curve.
The exact SQL behind every number
SELECT
toString(toStartOfMonth(date)) AS month,
round(avg(yield_1_month), 2) AS yield_1_month_pct,
round(avg(yield_3_month), 2) AS yield_3_month_pct,
round(avg(yield_1_year), 2) AS yield_1_year_pct
FROM global_markets.treasury_yields
WHERE date >= toStartOfMonth(today() - 730)
AND yield_3_month > 0
GROUP BY month
ORDER BY monthAs of the month beginning 2026-08-01, the 3 month bill yield averaged 3.9 percent and the 1 month averaged 3.78 percent, across 25 months of readings. A pair sum gap is a financing rate standing next to the risk free rate, rather than a coupon lying on the floor.
FAQ
Does YES plus NO always add up to $1?
At settlement, yes: one side pays $1 and the other pays nothing, every time. In the order book, no. The YES ask plus the NO ask normally sits above $1 and the two bids sit below it.
Is event contract arbitrage risk free?
The $1 payout is fixed, and the costs around it are not. Fees land on both legs, and the cash or collateral is held until the question resolves.
How do days to resolution change the return?
They divide it. A net edge of three tenths of a cent on 99 cents of committed cash is about 0.3 percent, which annualises near 9.6 percent over 12 days and near 2.3 percent over 48.
What is collateral on a short YES and NO pair?
Cash the venue holds against your $1 obligation until the question resolves. A venue that nets the two shorts into one $1 liability holds close to nothing beyond the credit received, while a venue that margins each leg separately can hold most of a dollar per pair.
Data notes and limits
- The spread panel samples a fifteen minute mid-morning window on recent sessions and averages the quoted spread across every update inside it.
- The parity panel uses daily closing marks for the options and the underlying, not struck at the same instant, so part of the offset between the two sides is timing noise.
- Bill yields are monthly averages of daily readings, and the final month is partial. Every quote and every fee in the Python script is invented, and no venue's schedule is reproduced.
To price the same spread or parity numbers for another name or expiry, ask in plain English on the Strasmore terminal.