If your Polymarket Up/Down bot started throwing order_version_mismatch or not enough balance / allowance (with funds in your wallet) in late April 2026, you hit the V2 SDK upgrade. Here are both fixes, plus a minimal PTB → signal → order quickstart.
Fix 1 — order_version_mismatch: serialize with order_to_json_v2
The order wire body changed. The old hand-built JSON ({"order": ..., "owner": ..., "orderType": ...}) is rejected. Serialize the signed order with order_to_json_v2 from py_clob_client_v2 — the V2 wire adds timestamp/metadata/builder, postOnly/deferExec, and an integer salt.
from py_clob_client_v2.order_utils.model.order_data_v2 import order_to_json_v2
signed = client.create_order(OrderArgs(price=p, size=s, side="BUY", token_id=tid))
body = order_to_json_v2(signed, client.creds.api_key, OrderType.GTC.value, False, False)
# POST `body` to /order with create_level_2_headers(...)
Fix 2 — not enough balance / allowance: sync once at startup
After a deposit, the on-chain balance updates but the CLOB cache doesn't refresh — get_balance_allowance returns balance=0 and orders are rejected. Force a re-read once at startup:
from py_clob_client_v2 import BalanceAllowanceParams, AssetType
client.update_balance_allowance(params=BalanceAllowanceParams(asset_type=AssetType.COLLATERAL))
The strategy it powers — cross-cycle sandwich
Two Up/Down markets on the same asset settling at the same time but on different cycles (5m/15m/1h/4h/1d) have different strikes (PTB). Buy UP on the lower strike and DOWN on the higher strike: at least one leg always wins, and if settlement lands between the strikes, both win (~2×). Under $1.00 combined, it's a structural edge — the real risk is execution.
from polymarket_updown_quickstart import Leg, sandwich_signal
sandwich_signal(Leg("15m", ptb=70000, up_price=0.55, down_price=0.47),
Leg("1h", ptb=70120, up_price=0.50, down_price=0.44))
# -> buy UP on 15m + DOWN on 1h, total_cost 0.99, edge=True, sweet_band (70000,70120)
Repo (free, MIT, 8 tests, runnable demo):
https://github.com/BlueWhale-Quant-Lab/polymarket-updown-arbitrage-quickstart
From quickstart to a running bot
The quickstart is the minimal shape. A real deployment also needs live price/orderbook feeds, multiple execution routes, a hedge guard for one-sided fills, timeout idempotency, and rate-limit handling. If you want the complete, ready-to-run engine with both SDK fixes wired in, there's a full V25 build — but the quickstart above stands on its own for learning the flow.
Takeaway
Post-April-2026 Polymarket: build order bodies with order_to_json_v2, and call update_balance_allowance once at startup. Those two lines unbreak most Up/Down bots.
Top comments (0)