惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
GbyAI
GbyAI
WordPress大学
WordPress大学
月光博客
月光博客
V
Visual Studio Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Google DeepMind News
Google DeepMind News
H
Help Net Security
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
博客园 - 司徒正美
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research
Blog — PlanetScale
Blog — PlanetScale
B
Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Microsoft Azure Blog
Microsoft Azure Blog
V
V2EX
L
LangChain Blog
腾讯CDC
T
The Blog of Author Tim Ferriss
量子位

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
What it takes to run a Polymarket Up/Down arbitrage bot i...
BlueWhale-Quant-Lab · 2026-06-03 · via DEV Community

A "risk-free" arbitrage on Polymarket's crypto Up/Down markets is easy to describe and hard to actually run. The edge — the cross-cycle sandwich — is real, but the money is won or lost in execution. Here's the engineering that turns the idea into a bot that survives production, and the specific things that break if you skip them.

The edge in two sentences

Polymarket runs Up/Down markets on the same asset across cycles (5m/15m/1h/4h/1d). Two cycles that settle at the same time share one final price but have different strikes (the per-cycle "price to beat"). Buy UP on the lower strike and DOWN on the higher strike: at least one leg always wins, and if the settlement price lands between the two strikes, both win. If the legs cost under $1.00 combined, that's a structural edge — on paper.

total_cost = up_price_low_strike + down_price_high_strike
edge = total_cost < 1.00          # at least one leg pays $1 -> can't lose if both fill

Enter fullscreen mode Exit fullscreen mode

The phrase that matters is "if both fill." Everything below is about that.

Problem 1 — direction is the whole game

Assign the sides from the strikes: UP on the lower PTB, DOWN on the higher. Get it backwards and the middle band — the region you most want — loses both legs (a "death sandwich"). So the bot's correctness hinges on a trustworthy price-to-beat per cycle, and the per-cycle rules are not uniform:

  • 5m/15m/4h: the Chainlink price pushed at the cycle open.
  • 1h: the Binance 1-hour candle Open.
  • 1d: the Binance 1-minute candle Close at the noon-ET boundary (DST-aware).

A PTB that locks a second or two late can already have drifted enough to flip which strike is "lower." So you gate on lock delay and refuse to fire on a stale strike.

Problem 2 — fire both legs, fast, together

Two legs posted seconds apart is two chances for the market to move between them, leaving you one-sided. The fix is boring but essential: one keep-alive connection, TCP_NODELAY, and asyncio.gather so both orders hit the book within milliseconds.

results = await asyncio.gather(place(leg_up), place(leg_down))

Enter fullscreen mode Exit fullscreen mode

Problem 3 — when only one leg fills

It will happen. Now you hold a naked leg and must top up the other side — and this is where bots quietly hemorrhage:

  • Overbuy loop. Size the top-up from the positions API and it lags (reads 0), so you resubmit, it fills, reads 0 again... A real run targeted 4.29 shares and bought 37.5. Size from an internal fill tally, never a lagging read.
  • Fee drift. Fees mean the two legs never match to the exact share — use a tolerance band instead of chasing crumbs.
  • The $1 floor. Orders under ~$1 notional are rejected; a 1-share crumb loops forever on invalid amount. Below the floor, let it settle.

Problem 4 — timeouts must not double-fill

On an HTTP timeout, the naive retry resubmits the order. If the first one actually landed, you've now got double exposure. Confirm against /data/trades before any resubmit; treat a timeout as "unknown," not "failed."

Problem 5 — the 2026-04 SDK migration

Late April 2026, Polymarket shipped a V2 SDK that broke older bots two ways. If yours started failing then, this is why:

# order_version_mismatch -> the wire body must be built by order_to_json_v2
from py_clob_client_v2.order_utils.model.order_data_v2 import order_to_json_v2
body = order_to_json_v2(signed, api_key, OrderType.GTC.value, False, False)

# 'not enough balance / allowance' (with funds!) -> sync the cache once at startup
client.update_balance_allowance(params=BalanceAllowanceParams(asset_type=AssetType.COLLATERAL))

Enter fullscreen mode Exit fullscreen mode

The old hand-built {order, owner, orderType} body is dead, and the CLOB caches balance=0 after a deposit until you force a re-read.

The honest part

With cost < 1 and both legs filled, a pair can't lose. The risk is execution — one-sided fills, slippage, the gap between your two orders, rate limits while you scan and fire. A production engine is mostly machinery for shrinking that risk: direction lock, concurrent posting, a hedge/overbuy guard, timeout idempotency, and staying under the API limits. It is not a money printer; prediction-market trading can lose money, and you should paper-test before risking real funds.

The complete engine

Everything above — three execution routes (immediate / pre-place / downstream-lock), the dual engine (arbitrage + strangle), the hedge-leg hound for one-sided fills, live Oracle + market WebSockets, timeout idempotency, and both 2026-04 SDK fixes (order_to_json_v2 + startup update_balance_allowance) wired in — is the ready-to-run V25 build. Bilingual, configurable, fill your keys and run:

https://bluewhalequantlab.gumroad.com/l/polymarket-updown-sandwich-bot-v25

Respect that the strategy is the easy 20% and the execution is the other 80%.