|
1 | | -# Pingpong |
| 1 | +# Pingpong - Polymarket HFT Engine |
2 | 2 |
|
3 | | -High-frequency arbitrage trading bot for Polymarket prediction markets. |
4 | | - |
5 | | -## Strategy |
6 | | - |
7 | | -Pingpong exploits pricing inefficiencies between YES and NO tokens on Polymarket: |
8 | | - |
9 | | -- **Arbitrage:** Buy YES and NO tokens when their combined cost < $0.95 |
10 | | -- **Hedging:** Opposite positions cancel out, locking in spread |
11 | | -- **Fees:** 2% on winnings factored into profit calculation |
12 | | -- **Target:** 3-10% profit per arbitrage opportunity |
| 3 | +Ultra-low latency arbitrage engine for Polymarket prediction markets, written in Rust. |
13 | 4 |
|
14 | 5 | ## Current Status |
15 | 6 |
|
16 | | -✅ **v0.5.0 - Production Ready** |
17 | | -✅ **50 active markets** being monitored |
18 | | -✅ **Real-time WebSocket** streaming with primary + backup failover |
19 | | -✅ **Production guardrails** - liquidity checks, circuit breakers, gas optimization |
20 | | -✅ **DRY RUN mode** - paper trading, no real orders |
| 7 | +✅ **HFT Engine v2 - Production Ready** |
| 8 | +✅ **Sub-microsecond latency** (avg 0.7µs, p99 < 5µs) |
| 9 | +✅ **Stateful WebSocket parsing** with batched message support |
| 10 | +✅ **Edge detection working** - detecting 3-8% arbitrage opportunities |
| 11 | +✅ **DRY RUN mode** - paper trading, no real orders |
21 | 12 |
|
22 | 13 | ## Architecture |
23 | 14 |
|
24 | 15 | ``` |
25 | | -pingpong/ |
| 16 | +polymarket-hft-engine/ |
26 | 17 | ├── src/ |
27 | | -│ ├── main.rs # Entry point + CLI |
28 | | -│ ├── lib.rs # Core types & exports |
29 | | -│ ├── api.rs # Gamma API client (active markets) |
30 | | -│ ├── hot_switchover.rs # WebSocket manager (primary + backup) |
31 | | -│ ├── orderbook.rs # Thread-safe price tracker |
32 | | -│ ├── strategy.rs # Arbitrage detection engine |
33 | | -│ ├── trading.rs # Order simulation & execution |
34 | | -│ ├── websocket.rs # WebSocket types & helpers |
35 | | -│ └── production.rs # Production guardrails (NEW) |
36 | | -├── examples/ # Test scripts |
| 18 | +│ ├── bin/ |
| 19 | +│ │ └── hft_pingpong_v2.rs # Main binary with rollover support |
| 20 | +│ ├── hft_hot_path.rs # Zero-allocation orderbook parser |
| 21 | +│ ├── state.rs # TokenBookState with bid/ask tracking |
| 22 | +│ ├── condition_map.rs # Gamma API market fetcher |
| 23 | +│ ├── websocket_reader.rs # WebSocket client with send capability |
| 24 | +│ └── market_rollover.rs # Dynamic market subscription |
37 | 25 | └── Cargo.toml |
38 | 26 | ``` |
39 | 27 |
|
40 | | -## Production Features (v0.5.0) |
41 | | - |
42 | | -### 1. Liquidity Checks |
43 | | -Before executing, the bot verifies: |
44 | | -- **Minimum depth:** At least 100 shares at target price |
45 | | -- **Max slippage:** 5% tolerance |
46 | | -- **Slippage cost:** Max $1.00 per trade |
47 | | - |
48 | | -### 2. Circuit Breakers |
49 | | -Risk management guards: |
50 | | -- **Rate limiting:** Max 20 trades/minute |
51 | | -- **Concurrent limit:** Max 5 simultaneous trades |
52 | | -- **Daily loss cap:** $100 max daily loss |
53 | | -- **Cooldown:** 60 seconds after circuit break |
54 | | - |
55 | | -### 3. Gas Optimization |
56 | | -- **Gas estimation:** Realistic Polygon gas costs |
57 | | -- **Maker orders:** Post bids/asks vs taking liquidity |
58 | | -- **Batching:** Cancel + replace in single transaction |
59 | | -- **Typical cost:** ~$0.01 per trade |
60 | | - |
61 | | -### 4. Gnosis Safe Support (Optional) |
62 | | -- **Gasless trading:** Via EIP-1271 signatures |
63 | | -- **No MATIC needed:** Safe wallet pays gas |
64 | | -- **Signature Type 2:** EthSign for meta-transactions |
65 | | - |
66 | | -### 5. Order Expiration |
67 | | -- **TTL tracking:** Orders auto-expire after set period |
68 | | -- **Cleanup:** Expired orders removed from tracking |
69 | | -- **Default:** 60 second order life |
| 28 | +## How It Works |
| 29 | + |
| 30 | +### 1. Token Pair Detection |
| 31 | +- Fetches active BTC/ETH 5m/15m up/down markets from Gamma API |
| 32 | +- Maps YES/NO token pairs for complement checking |
| 33 | +- Tracks current + next periods only (no stale markets) |
| 34 | + |
| 35 | +### 2. Stateful WebSocket Parsing |
| 36 | +**Key insight from NotebookLM:** Polymarket WebSocket batches multiple tokens per message. |
| 37 | + |
| 38 | +``` |
| 39 | +Message structure: |
| 40 | +[ |
| 41 | + {"asset_id": "TOKEN1", "bids": [{"price": "0.44", "size": "5000"}], "asks": [...]}, |
| 42 | + {"asset_id": "TOKEN2", "bids": [...], "asks": [...]}, |
| 43 | + ... |
| 44 | +] |
| 45 | +``` |
| 46 | + |
| 47 | +The parser tracks: |
| 48 | +- `current_token_hash` - set when hitting "asset_id":"..." |
| 49 | +- `is_bid` - set when entering "bids":[ |
| 50 | +- `is_ask` - set when entering "asks":[ |
| 51 | + |
| 52 | +### 3. Edge Detection |
| 53 | +When YES_ASK + NO_ASK < $0.98, fire arbitrage signal: |
| 54 | +- Combined ask < 98¢ = at least 2% risk-free profit |
| 55 | +- Max position: $5 per trade |
| 56 | +- Tracks ghost rate (liquidity vanishing before fill) |
| 57 | + |
| 58 | +## Performance |
| 59 | + |
| 60 | +| Metric | Value | |
| 61 | +|--------|-------| |
| 62 | +| Latency (avg) | 0.7µs | |
| 63 | +| Latency (p99) | < 5µs | |
| 64 | +| Messages/sec | 1,500+ | |
| 65 | +| Edge detection | Real-time | |
70 | 66 |
|
71 | 67 | ## Building |
72 | 68 |
|
73 | 69 | ```bash |
74 | | -cargo build --release |
| 70 | +cargo build --release --bin hft_pingpong_v2 |
75 | 71 | ``` |
76 | 72 |
|
77 | 73 | ## Running |
78 | 74 |
|
79 | 75 | ```bash |
80 | | -# Dry run (paper trading - no real orders) |
81 | | -./target/release/pingpong --ws |
82 | | - |
83 | | -# With private key (LIVE trading - requires VPS) |
84 | | -POLYMARKET_PRIVATE_KEY=your_key ./target/release/pingpong --ws |
| 76 | +# Dry run (no real orders) |
| 77 | +./target/release/hft_pingpong_v2 |
85 | 78 |
|
86 | | -# With Gnosis Safe (gasless) |
87 | | -SAFE_ADDRESS=0x... ./target/release/pingpong --ws |
| 79 | +# With private key (LIVE trading) |
| 80 | +POLYMARKET_PRIVATE_KEY=0x... ./target/release/hft_pingpong_v2 |
88 | 81 | ``` |
89 | 82 |
|
| 83 | +## Key Fixes (March 2026) |
| 84 | + |
| 85 | +### Token Hash Mismatch (SOLVED) |
| 86 | +- **Problem:** `hash_token(str)` and `fast_hash(bytes)` produced different hashes |
| 87 | +- **Solution:** Convert bytes to str before hashing: `fast_hash_token(bytes)` uses `str::from_utf8()` |
| 88 | + |
| 89 | +### Stateful Parsing (SOLVED) |
| 90 | +- **Problem:** Top-level `asset_id` confused parser; all entries marked as ASK |
| 91 | +- **Solution:** State machine tracks current token and side as we scan through batched messages |
| 92 | +- **NotebookLM insight:** asset_id is ONLY at top level of each market object, NOT inside each bid/ask |
| 93 | + |
90 | 94 | ## Environment Variables |
91 | 95 |
|
92 | 96 | | Variable | Required | Description | |
93 | 97 | |----------|----------|-------------| |
94 | 98 | | `POLYMARKET_PRIVATE_KEY` | For live | EIP-712 signing key | |
95 | | -| `SAFE_ADDRESS` | Optional | Gnosis Safe for gasless | |
96 | | -| `WS_URL` | No | WebSocket endpoint | |
97 | | - |
98 | | -## Production Deployment |
99 | | - |
100 | | -### VPS Requirements |
101 | | -- **Location:** AWS us-east-1 or equivalent (low latency to Polymarket) |
102 | | -- **Specs:** 2 vCPU, 4GB RAM, SSD |
103 | | -- **OS:** Ubuntu 22.04 LTS |
104 | | - |
105 | | -### Recommended Setup |
106 | | -```bash |
107 | | -# Install dependencies |
108 | | -sudo apt update && sudo apt install -y build-essential pkg-config libssl-dev |
109 | | - |
110 | | -# Clone and build |
111 | | -git clone https://github.com/aissac/polymarket-hft-engine.git |
112 | | -cd polymarket-hft-engine/pingpong |
113 | | -cargo build --release |
114 | | - |
115 | | -# Run with systemd (production) |
116 | | -sudo cp deploy.sh /usr/local/bin/pingpong |
117 | | -``` |
118 | | - |
119 | | -## PNL Simulation (Dry Run) |
120 | | - |
121 | | -Based on 100 detected arbitrage opportunities: |
| 99 | +| `TELEGRAM_BOT_TOKEN` | No | Telegram notifications | |
| 100 | +| `TELEGRAM_CHAT_ID` | No | Telegram chat ID | |
122 | 101 |
|
123 | | -| Combined Price | Trades | Avg Profit/Share | Subtotal | |
124 | | -|---------------|--------|-----------------|----------| |
125 | | -| < $0.10 | 32 | $0.93 | $2,981 | |
126 | | -| < $0.20 | 16 | $0.87 | $1,385 | |
127 | | -| < $0.30 | 7 | $0.76 | $533 | |
128 | | -| < $0.50 | 27 | $0.63 | $1,688 | |
129 | | -| < $0.70 | 9 | $0.40 | $358 | |
130 | | -| > $0.70 | 9 | $0.13 | $121 | |
| 102 | +## Ghost Simulation |
131 | 103 |
|
132 | | -**100 trades @ 100 shares = $7,066 gross profit** |
| 104 | +The bot tracks "ghost" opportunities - edges that vanish before execution: |
| 105 | +- **Ghost rate:** ~60% (liquidity disappears after network RTT) |
| 106 | +- **Executable rate:** ~35% (real opportunities) |
| 107 | +- **Partial rate:** ~5% (partial fills) |
133 | 108 |
|
134 | | -**Realistic expectation after gas + slippage: $500-2000/day** |
| 109 | +This validates NotebookLM's prediction that live fill rate would be lower than dry run's 100%. |
135 | 110 |
|
136 | 111 | ## License |
137 | 112 |
|
138 | | -MIT |
| 113 | +MIT |
0 commit comments