Files
2026-06-28 23:31:28 +08:00

270 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Polymarket Reverse Arbitrage Bot
TypeScript automation for my Polymarket reverse strategy on **15-minute BTC/ETH Up or Down** markets.
---
## My Polymarket account
<img width="815" height="291" alt="image" src="https://github.com/user-attachments/assets/0971eb6d-de7e-4f9a-82a1-14a2163db209" />
| | |
|---|---|
| **Profile** | [@odahoa](https://polymarket.com/@odahoa?tab=activity) |
| **Username** | `odahoa` |
| **Proxy wallet** | `0xe2511c9e41c5e762887e538b1d6e7221807aa237` |
| **Markets** | `btc-updown-15m`, `eth-updown-15m` |
All activity, positions, and PnL live on my profile:
**https://polymarket.com/@odahoa?tab=activity**
This bot trades **from that account** — it automates what I already do manually. It is not copy trading and does not watch any other wallet.
---
## Overview
Polymarket runs 15-minute windows like:
> **Bitcoin Up or Down — 1:45PM2:00PM ET**
Each window has two tokens:
| Token | Wins when |
|-------|-----------|
| **Up** | Price at end ≥ price at start |
| **Down** | Price at end < price at start |
Winning tokens pay **$1.00**. Losing tokens pay **$0.00**.
My strategy — the **reverse bot** — posts limit **BUY** orders on **both sides** every window:
1. **Cheap reversal side (710¢)** on the underdog outcome
2. **Expensive hedge side (9095¢)** on the favorite outcome
That is the same pattern visible on my [activity tab](https://polymarket.com/@odahoa?tab=activity): round limit prices (7¢, 8¢, 10¢ … 95¢), 2090 shares per fill, no sells — hold to resolution.
---
## Why "reverse"?
Early in a window, price often trends one way:
```
BTC pumps in first 10 minutes
→ Up token ~9097¢ (favorite)
→ Down token ~310¢ (underdog)
```
The crowd prices the underdog as nearly dead. The **reverse bet** is: *it flips before the window closes*.
| Leg | Outcome | Entry | If it wins |
|-----|---------|-------|------------|
| **Reverse** | Underdog | 710¢ | ~1014× |
| **Hedge** | Favorite | 9095¢ | ~511% |
Only one side pays $1 per window. I run both legs because:
- Cheap fills are rare but pay huge when they hit.
- Hedge fills are smaller profit but hit more often.
- Over hundreds of windows, a few reversals cover many losses.
---
## How I trade (manual → bot)
From my account history:
| Pattern | Detail |
|---------|--------|
| Markets | BTC & ETH 15m Up/Down only |
| Order type | Limit BUY only — never sell |
| Cheap leg | Fills at 710¢ (sometimes 525¢) on underdog |
| Hedge leg | Fills at 9095¢ on favorite |
| Both sides | Same window — e.g. Down @ 95¢ and Up @ 15¢ |
| Size | 2090 shares per order |
The bot replaces hand-placing every limit order each window.
---
## Bot logic
Every **5 seconds** (configurable):
```
1. Scan active btc-updown-15m / eth-updown-15m markets
2. Load Up & Down order books (CLOB API)
3. Underdog = outcome with lower best ask
4. Favorite = the other outcome
5. Post limit BUYs on underdog @ 7¢, 8¢, 9¢, 10¢
6. Post limit BUYs on favorite @ 90¢–95¢ (if hedge enabled)
7. Skip price levels already posted this session
```
### Cheap leg — underdog @ 710¢
```
Down best ask = 4¢ → bot bids 7¢, 8¢, 9¢, 10¢ on Down
```
If Down reverses and wins:
```
90 shares × 8¢ = $7.20 in
90 shares × $1 = $90.00 out → +$82.80 (~1,150%)
```
### Hedge leg — favorite @ 9095¢
```
Up best ask = 97¢ → bot bids 90¢–95¢ on Up
```
If Up holds and wins:
```
52 shares × 95¢ = $49.40 in
52 shares × $1 = $52.00 out → +$2.60 (~5%)
```
---
## Example window
**Market:** Bitcoin Up or Down — 1:452:00 PM ET
**BTC pumped early** → Up favored, Down cheap
| Token | Book | Bot posts |
|-------|------|-----------|
| Up (favorite) | ask 97¢ | BUY limits @ 9095¢ |
| Down (underdog) | ask 4¢ | BUY limits @ 710¢ |
| Result | Cheap leg | Hedge leg |
|--------|-----------|-----------|
| Up wins | Down → $0 | Up → small profit |
| Down reverses | Down → big profit | Up → $0 |
---
## Return table
| Buy price | Payout | Return if win |
|-----------|--------|---------------|
| 7¢ | $1.00 | +1,329% |
| 8¢ | $1.00 | +1,150% |
| 9¢ | $1.00 | +1,011% |
| 10¢ | $1.00 | +900% |
| 95¢ | $1.00 | +5% |
Most 710¢ bets go to zero. Edge comes from occasional reversals at high multiples.
---
## Quick start
```bash
git clone https://github.com/nidichaogequ/polymarket-reverse-arbitrage-bot
cd reverse-bot
npm install
cp .env.example .env
npm start # dry-run: logs orders, no submission
```
### Go live on @odahoa
```env
DRY_RUN=false
PRIVATE_KEY=0x... # account signing key
FUNDER_ADDRESS=0xe2511c9e41c5e762887e538b1d6e7221807aa237 # @odahoa proxy wallet
SIGNATURE_TYPE=2
```
| `SIGNATURE_TYPE` | Use for |
|------------------|---------|
| `0` | EOA / MetaMask |
| `2` | Gnosis Safe proxy *(typical Polymarket account)* |
| `3` | POLY_1271 deposit wallet |
---
## Config
### Strategy
| Variable | Default | Description |
|----------|---------|-------------|
| `CHEAP_BUY_MIN` | `0.07` | Low end of reversal bids |
| `CHEAP_BUY_MAX` | `0.10` | High end of reversal bids |
| `CHEAP_ORDER_USDC` | `10` | USDC per cheap limit order |
| `ENABLE_EXPENSIVE_HEDGE` | `true` | Post 9095¢ favorite bids |
| `EXPENSIVE_BUY_MIN` | `0.90` | Low end of hedge bids |
| `EXPENSIVE_BUY_MAX` | `0.95` | High end of hedge bids |
| `EXPENSIVE_ORDER_USDC` | `50` | USDC per hedge limit order |
| `MAX_SHARES_PER_ORDER` | `90` | Max shares per order |
### Markets & timing
| Variable | Default | Description |
|----------|---------|-------------|
| `MARKET_SLUG_PREFIXES` | `btc-updown-15m,eth-updown-15m` | Markets to scan |
| `POLL_INTERVAL_MS` | `5000` | Scan interval |
| `MINUTES_BEFORE_CLOSE_MIN` | `0` | Start trading N min into window |
| `MINUTES_BEFORE_CLOSE_MAX` | `15` | Stop trading N min before close |
Trade only late window (when cheap tokens show up):
```env
MINUTES_BEFORE_CLOSE_MIN=3
MINUTES_BEFORE_CLOSE_MAX=12
```
### Safety
| Variable | Default | Description |
|----------|---------|-------------|
| `DRY_RUN` | `true` | Log only — no real orders |
---
## Project layout
```
reverse-bot/
├── src/
│ ├── index.ts # main loop
│ ├── market-scanner.ts # active 15m markets + books
│ ├── strategy.ts # underdog/favorite + limit prices
│ ├── trader.ts # CLOB order submission
│ └── config.ts
├── .env.example
└── package.json
```
---
## Commands
```bash
npm start # run bot
npm run dev # run with hot reload
npm run build # compile TypeScript
```
---
## Risks
- **Most cheap bids lose.** 710¢ tokens frequently expire worthless.
- **Limits may not fill.** Bidding 7¢ when ask is 4¢ waits for sellers.
- **Both legs can't both win.** One side always goes to $0.
- **Real money.** Test with `DRY_RUN=true` first.
---
## Links
- My profile: https://polymarket.com/@odahoa
- My activity: https://polymarket.com/@odahoa?tab=activity
- Polymarket settings: https://polymarket.com/settings