Market Making on Prediction Markets: Quoting Both Sides of a Binary Contract
Market making seeks to provide executable prices on both sides of a market. Earning a quoted spread requires the relevant transactions to occur; simply posting two prices does not make a position neutral or profitable. One side can fill while the other does not, leaving directional exposure.
Start with the exact instrument, order rules, available inventory and costs. The binary examples below assume an ordinary $1-or-$0 payout. They are not a description of every event product or a recommendation to quote a current market.
The spread is a proposal, not an earned return
Polymarket international's market-making documentation distinguishes quote construction, order maintenance and inventory management. Its venue instructions are separate from Banger's public paper workflow. In a hypothetical round trip, acquiring a contract at 0.48 and disposing of it at 0.52 produces 0.04 gross before costs only if both transactions actually complete for the relevant quantity.
A trader responding to new information may execute your stale quote before you cancel it. That is an adverse-selection risk, not evidence that every fill came from an insider. Save observations around each simulated fill and examine what happens afterward rather than assigning a motive to public flow.
Inventory changes the quoting question
If your YES exposure is above the intended target, lowering a hypothetical YES bid discourages further acquisition and lowering its ask may make a reducing sale more competitive. These are incentives, not a flattening guarantee. Availability, price limits, cash and held outcome positions still constrain the transactions.
Keep contract quantity separate from dollar notional. Buying NO and selling held YES can have related ordinary-binary exposure, but they are different account operations. Do not implement a negative position as a naked short without checking the venue and account rules.
Test the quote arithmetic in isolation
The following standalone calculator proposes two prices on a deliberately simplified fixed grid. Every input is hypothetical. Its skew is a chosen research heuristic, not the complete Avellaneda-Stoikov model or an empirically validated rule. It neither uses an account nor sends orders.
from decimal import Decimal, ROUND_FLOOR, ROUND_CEILING
def candidate_quotes(fair, inventory, half_spread, skew_per_contract,
tick, lower, upper, inventory_cap):
# Toy fixed price grid. No SDK order or cancellation calls.
p, q, h, k, step, lo, hi, cap = map(
lambda x: Decimal(str(x)),
[fair, inventory, half_spread, skew_per_contract,
tick, lower, upper, inventory_cap],
)
if not all(x.is_finite() for x in [p, q, h, k, step, lo, hi, cap]):
raise ValueError("inputs must be finite")
if not (0 <= lo < hi <= 1 and 0 <= p <= 1 and h > 0
and k >= 0 and step > 0 and cap > 0):
raise ValueError("invalid hypothetical quote parameters")
if abs(q) >= cap:
return None # Suppress candidates; this does not liquidate inventory.
center = p - q * k
bid = ((center - h) / step).to_integral_value(rounding=ROUND_FLOOR) * step
ask = ((center + h) / step).to_integral_value(rounding=ROUND_CEILING) * step
if not lo <= bid < ask <= hi:
return None
return bid, ask
print(candidate_quotes("0.50", "10", "0.02", "0.001",
"0.01", "0.01", "0.99", "100"))
# Hypothetical candidates: (0.47, 0.51). No orders are submitted.The example rejects invalid inputs and suppresses candidates outside its price band or at its illustrative inventory cap. Suppression does not cancel existing orders, sell positions or stop a worker. Actual market price grids, minimum sizes, eligibility and order semantics must be checked separately before an integration can use a candidate.
Order state must be authoritative
An order request, acceptance, partial fill, cancellation request and cancellation confirmation are different events. Reconcile them before deciding your exposure. Replacing a quote without knowing the old order's state can leave more working quantity than intended.
Test interruptions and reconnects with explicit fixtures: a duplicate fill, one-sided fill, uncertain cancellation, absent quote, changed grid and a closed market. Preserve the original inputs and expected state transitions. A successful arithmetic function covers none of those lifecycle cases by itself.
What Banger paper evidence can establish
Banger's public beta is paper-only. The public 0.1.7 SDK uses on_market_tick(market, tick, ctx), actual Context methods and a declared RiskEnvelope; it does not provide the invented on_tick/ctx.market/ctx.limit_order interface previously shown here.
Its packaged forward-paper context explicitly assumes a fill at a non-crossing limit in one path. That can make a passive-quote experiment optimistic. Inspect the model and logs, and do not call a simulated round trip proof that both real quotes would have filled. Hosted historical backtests are a separate research path.
Keep the acceptance question narrow and visible
Record the model version, exact contract, quote grid, hypothetical size, inventory target, fee assumptions and shutdown procedure. A no-order arithmetic or feed check establishes limited implementation evidence. Simulated orders add model-dependent evidence. Neither proves earned spread, real execution, legal eligibility or a profitable market-making strategy.