Slippage and Liquidity in Prediction Markets: Estimating Snapshot Costs
Displayed depth can help estimate the cost of a hypothetical purchase. It cannot tell you that the orders will still exist when your request arrives or that your activity will leave prices unchanged. A useful liquidity study separates the quoted snapshot, its arithmetic and the actual execution it has not observed.
Define the benchmark and units
For a fully paid binary contract with a maximum one-dollar payout, express a quoted contract price in dollars and size in contracts. If a venue supplies cents, fixed-point strings or another payout scale, normalize using that endpoint's documented schema. Do not apply a one-dollar conversion to a different product by habit.
Slippage needs a named benchmark: perhaps the best ask observed at decision time or a pre-arrival quote. The ask minus midpoint is not the same measure as an average purchase price minus the initial best ask. State whether fees are included. A displayed last trade may be stale and does not promise available size.
Walk a static ask snapshot
The following standalone helper assumes ascending asks for one identified outcome. It rejects invalid prices, sizes and ordering, preserves partial availability and reports the unfilled remainder. Decimal arithmetic avoids binary floating-point surprises. It does not connect to a venue, submit orders or model competing requests.
from decimal import Decimal
def ask_snapshot_cost(levels, contracts):
def number(value):
value = Decimal(str(value))
if not value.is_finite():
raise ValueError("finite values required")
return value
target = number(contracts)
if target <= 0:
raise ValueError("positive contract quantity required")
book = []
for price, quantity in levels:
p, q = number(price), number(quantity)
if not (0 <= p <= 1) or q <= 0:
raise ValueError("invalid one-dollar ask level")
if book and p < book[-1][0]:
raise ValueError("asks must be ascending")
book.append((p, q))
remaining, cost = target, Decimal(0)
for price, quantity in book:
take = min(remaining, quantity)
cost += take * price
remaining -= take
if remaining == 0:
break
filled = target - remaining
average = cost / filled if filled else None
return {"filled": filled, "unfilled": remaining, "cost_usd": cost,
"average_price": average,
"above_best_ask": average - book[0][0] if filled else None}
example = ask_snapshot_cost([(".55", 50), (".57", 200), (".60", 500)], 600)
assert example["cost_usd"] == Decimal("351.50")
assert example["unfilled"] == 0The hypothetical average is about 0.58583 dollars, before fees. A request larger than available depth leaves an explicit unfilled quantity in the result. Empty depth produces no average. These are arithmetic outcomes under a frozen-book assumption, not predictions about a real order type or matching engine.
Examine how the snapshot was obtained
Record receipt time, outcome ID, quote side, source sequence where available and whether the feed covers the complete book. A stream interruption, missing outcome mapping or stale cached snapshot can make accurate arithmetic describe the wrong state. Candle volume and last-trade price are different data from contemporaneous resting depth.
Study comparable observations across the periods relevant to the experiment. Do not assume a sport, category, venue, hour or headline reliably has deeper liquidity than another. Higher aggregate volume may coexist with poor size at the specific prices and times you need.
Include uncertainty and costs
Partial fills, cancellations, price changes and adverse selection can matter. Breaking a hypothetical request into pieces does not guarantee that depth replenishes or that total impact falls. A resting order may never execute. Current fee rules can depend on venue, series, role, price and rounding; a fixed percentage applied to every displayed level is not a verified invoice.
For a paper study, declare conservative alternatives to the frozen-book estimate and keep incomplete outcomes. Banger's packaged forward-paper engine does not reconstruct real queue position or prove full-depth execution. Its non-crossing limit path can assume a fill, which must not be presented as a liquidity observation.
Report what is known
A defensible result identifies the snapshot and benchmark, the requested contracts, displayed available quantity, estimated cost, fees assumed and unfilled remainder. It also states the data and execution behavior that were not measured. That makes the estimate reproducible without promising an exit, a profitable size or an ability to trade without moving prices.