Open two WebSocket connections. One to the Chainlink oracle that settles Polymarket 15 minute crypto markets. One to the Polymarket order book.
Watch them side by side.
The oracle updates in under a second. The order book takes 55 seconds to reflect the same move. For almost a full minute tokens are sitting there priced on stale data.
The settlement source is public. Anyone can connect. And it consistently runs almost a minute ahead of the market it settles.
That felt like a bug at first. It is not. It is just how markets work. But usually you cannot measure it this cleanly.
So I wrote about 1,400 lines of Python to trade on it.
The core logic is pretty simple. On every oracle price tick, check three things:
price moved > 0.07% from market open
time remaining > 5 minutes
token price < $0.62
All three true? Buy the cheap side. Wait for settlement. Collect $1 or lose your stake.
The interesting part was not the strategy. It was making this actually run reliably.
You need a single process that holds open a WebSocket receiving sub second updates, tracks 16 overlapping markets, evaluates signals on every tick, places orders without blocking the price feed, sends Telegram notifications, persists state for crash recovery, and monitors its own health. All at the same time.
asyncio was the obvious choice. Almost zero CPU work, everything is IO bound. Seven concurrent tasks in one event loop:
tasks = [
oracle.run(shutdown),
market_lifecycle_loop(...),
signal_evaluation_loop(...),
telegram.run(shutdown),
state_persist_loop(...),
redeem_loop(...),
sanity_check_loop(...),
]
await asyncio.gather(*tasks)
No threads. No locks. No multiprocessing.
The nastiest bug I hit was zombie WebSocket connections. Connection stays alive, ping pong works, no exceptions thrown. But price data silently stops flowing. Your bot just sits there doing absolutely nothing and looks healthy the whole time.
A recv timeout does not help because heartbeat frames still arrive. I ended up tracking the last real price timestamp on monotonic clock and checking it on every timeout. If real data has not arrived in too long, kill the connection and force reconnect.
I lost multiple evenings to this before I figured it out.
Another thing that burned me. Start the bot. Logs look perfect. Run it for 20 minutes. Then discover the Telegram chat id was wrong and every notification silently failed. You had no idea anything was off.
Now the bot verifies every external credential before entering the main loop. Hits Telegram getMe, sends a test message, checks Polymarket API keys. If something is wrong you see it in the first 2 seconds:
ERROR: Telegram chat_id=123456 is invalid.
Tip: send any message to @your_bot first, then use getUpdates to find your chat_id.
The backtest ran across 8,876 resolved markets and 146,000 price points. 5,017 trades flagged. 61.4% win rate across BTC, ETH, XRP and SOL.
I tried 7 different ways to break it. Date split, parameter grid search, doubled fees, daily breakdown. None of them killed it.
But let me be real. The book is thin, fills will be harder than the backtest assumes, and the lag will shrink over time. This is not a retirement plan.
The whole thing is open source. Demo mode connects to live data and paper trades without any API keys.
https://github.com/JonathanPetersonn/oracle-lag-sniper
If you have built similar real time asyncio systems I genuinely want to know how you structured them. This "many concurrent long lived tasks sharing state" pattern feels common but I could not find good open source references when I was building this.
Top comments (0)