๐ฆ Openclaw AI Polymarket Trading Bot โ TypeScript bot built with the Openclaw AI agent. Predicts crypto price direction on Polymarketโs 5-minute BTC Up/Down markets and places real orders.
A TypeScript bot that predicts whether Polymarketโs 5-minute Bitcoin Up/Down markets will move up (YES) or down (NO) over the next 5 minutes and places real CLOB orders. You need a valid PRIVATE_KEY in .env; CLOB API key / secret / passphrase are optional (auto-derived if omitted).
-
๐ Picks a market
It finds the current active โBTC up or down in 5 minutesโ market on Polymarket (Gamma API + time bucket, with fallbacks via Data API and active-market scan). -
๐ Collects data every 15 seconds
- Latest YES price from the order book
- Recent trader/whale participation on that market
- External wallet winrates for participating wallets
-
๐ฎ Makes a prediction
It combines:- EMA trend (fast vs slow EMA)
- RSI trend pressure
- Winrate-filtered whale pressure (wallets with winrate >= configured threshold)
- Optional LLM bias (if you set an OpenAI API key)
Into a single number: probability that YES goes up in 5 minutes (
pUp5m). -
โ๏ธ Decides an action
- If confidence >=
CONFIDENCE_THRESHOLDand time is safe โ OPEN predicted side โ - Otherwise โ HOLD โธ๏ธ
- If confidence >=
-
๐ฐ Executes
The bot places real market BUY orders when the signal is OPEN YES/NO. It keeps one trade per market and force-exits near settlement (FORCE_EXIT_SECONDS, default 3s) to avoid final-second flips.
Each run of the loop (every LOOP_SECONDS seconds, default 15):
1. Fetch market ticks (last 20 price snapshots) from Polymarket
2. If fewer than 3 ticks, wait (warm up)
3. Fetch whale flow for this market (recent large trades)
4. Compute wallet winrates locally from recent BTC 5m market trade history
5. Build features: EMA fast/slow, RSI, trend score, winrate-filtered whale pressure
5. (Optional) Call LLM scorer with features โ get a bias in [-1, 1]
6. Run predictor: combine trend + whale pressure + LLM โ pUp5m, confidence, side
7. Strategy: confidence gate + time gate โ HOLD / OPEN YES / OPEN NO
8. Check open-positions.json; if already in this market โ SKIP
9. If OPEN YES/NO โ place FOK buy, record position, log result
10. If remaining time <= FORCE_EXIT_SECONDS โ force sell and remove position
11. Log action and p5m/confidence to console
So: data โ features โ prediction โ decision โ real order and position lifecycle.
cd polymarket-shorthorizon-bot
npm install
cp .env.example .envEdit .env: set at least PRIVATE_KEY (see Environment variables).
npm run devOr after a build: npm run build && npm start (runs dist/main.js).
The bot places real orders when confidence and timing gates pass. It logs LIVE BUY orderID=..., records positions in open-positions.json, and force-closes near expiry (default 3s before settlement).
In another terminal:
npm run uiOpen http://localhost:8787 in your browser.
- Get Prediction ๐ โ fetches the same snapshot the bot uses (market, current YES price, prediction, whale stats).
- Auto Compare โฑ๏ธ โ you set โEntry YES priceโ and โAuto settle delay (sec)โ (e.g. 300 for 5 min). The UI waits that long, then fetches the new YES price and records whether the botโs predicted side (YES/NO) would have been correct.
- History ๐ โ table of past comparisons and accuracy (e.g. โTotal: 10 | Correct: 6 | Accuracy: 60%โ).
The Compare UI helps you review prediction vs outcome and track accuracy.
Copy .env.example to .env and adjust as needed.
| Variable | Description | Default |
|---|---|---|
| Data sources | ||
POLYMARKET_REST_BASE |
Gamma API base URL | https://gamma-api.polymarket.com |
BINANCE_REST_BASE |
Binance Futures REST URL | https://fapi.binance.com |
| CLOB | ||
PRIVATE_KEY |
Wallet private key (hex, 64 chars) | (required) |
CLOB_API_KEY |
L2 API key | (optional โ derived from PRIVATE_KEY if omitted) |
CLOB_SECRET |
L2 secret | (optional โ set all three or omit all three) |
CLOB_PASS_PHRASE |
L2 passphrase | (optional) |
CLOB_API_URL |
CLOB API base | https://clob.polymarket.com |
CLOB_CHAIN_ID |
Chain ID (Polygon mainnet) | 137 |
CLOSE_AFTER_SECONDS |
Optional timed close from open time (0 = disabled) | 0 |
| Optional LLM | ||
OPENAI_API_KEY |
If set, features are sent to the LLM for an extra bias signal | (empty = no LLM) |
OPENAI_BASE_URL |
OpenAI-compatible API base | https://api.openai.com/v1 |
OPENAI_MODEL |
Model name | gpt-4o-mini |
| Runtime | ||
LOOP_SECONDS |
Seconds between each loop run | 15 |
MAX_POSITION_USD |
Size in USD per position | 100 |
EDGE_THRESHOLD |
Legacy paper strategy threshold (kept for compatibility) | 0.03 |
CONFIDENCE_THRESHOLD |
Open only if model confidence >= this | 0.80 |
FORCE_EXIT_SECONDS |
Force-close position this many seconds before expiry | 3 |
EMA_FAST |
Fast EMA period | 5 |
EMA_SLOW |
Slow EMA period | 13 |
RSI_PERIOD |
RSI period | 14 |
WHALE_MIN_WINRATE |
Wallet winrate filter threshold for whale set | 0.70 |
WHALE_MIN_NOTIONAL |
Min wallet notional to consider a whale participant | 200 |
WALLET_WINRATE_API_URL |
Optional external API endpoint override (local compute works without it) | (empty) |
WALLET_WINRATE_API_KEY |
Optional bearer token for external winrate API | (empty) |
WALLET_WINRATE_TIMEOUT_MS |
Wallet API timeout | 3000 |
WALLET_WINRATE_CACHE_TTL_SEC |
Winrate cache TTL | 600 |
Startup: validateBotEnv checks PRIVATE_KEY, strategy ranges, and URLs. If CLOB_API_KEY / CLOB_SECRET / CLOB_PASS_PHRASE are all omitted, the bot calls Polymarketโs createOrDeriveApiKey() on first order. Open positions: open-positions.json (gitignored).
-
Get Prediction ๐
Calls the same backend as the bot (/api/prediction): current market, YES price, 5m prediction (pUp5m, side), confidence, whale stats. Good for a quick sanity check. -
Auto Compare (5m) โฑ๏ธ
- Click โGet Predictionโ once so the snapshot is loaded.
- โEntry YES priceโ is pre-filled with current YES; you can change it.
- Set โAuto settle delayโ to 300 (5 minutes) or another value.
- Click โStart Auto Compare.โ
- The UI waits that many seconds, then fetches the current YES price again and records: predicted side vs actual (YES if exit price โฅ entry, else NO). It appends one row to History and updates accuracy.
-
Whale Panel ๐
Shows the same whale breakdown as in the snapshot (top wallets, net YES, gross, bias). -
History ๐
Stored inlocalStorage. Columns: Time, Market, Pred Side, Entry YES, Exit YES, Actual (YES/NO), Correct (โ /โ). Below: total count, correct count, accuracy %.
The bot places real orders when the signal is OPEN YES or OPEN NO:
-
๐ Wallet
SetPRIVATE_KEY(the wallet that trades on Polymarket CLOB). See Polymarket CLOB Quickstart. -
๐ง Strategy data mode
By default wallet winrate is computed locally from recent BTC 5m market trades.WALLET_WINRATE_API_URLis optional if you want to override with external data. -
๐ Run the bot
npm run dev. When the signal is OPEN YES or OPEN NO (and no position in that market yet), the bot will:- Compute EMA/RSI trend plus winrate-filtered whale pressure
- Open only when confidence >=
CONFIDENCE_THRESHOLD - Record one position per market and force-exit at
FORCE_EXIT_SECONDSbefore settlement.
Code: Live logic is in src/main.ts. Position store: src/engine/positionStore.ts. Order placement: src/connectors/orderExecution.ts (placeOrder, buy, sell).
| Path | Role |
|---|---|
src/main.ts |
Entry point: loop every N seconds, fetch data โ features โ predict โ place orders |
src/config.ts |
Reads .env, exposes cfg |
src/envCheck.ts |
Startup validation for bot (validateBotEnv) and UI (validateUiEnv) |
src/types/index.ts |
Shared types: MarketTick, WhaleFlow, FeatureVector, Prediction, LivePosition, etc. |
src/connectors/polymarket.ts |
Gamma API (market resolution, YES price) + Data API (whale flow). getConditionId() for CLOB orders |
src/connectors/orderExecution.ts |
CLOB client wrapper: placeOrder, buy, sell, getTokenIdsForCondition |
src/connectors/walletPerformance.ts |
External wallet winrate lookup (batch + cache + normalize) |
src/engine/features.ts |
Builds EMA/RSI + winrate-filtered whale pressure features |
src/engine/predictor.ts |
Combines trend + whale pressure + LLM bias โ pUp5m, confidence, side |
src/engine/paperTrader.ts |
Legacy strategy helper (not primary live gate) |
src/engine/positionStore.ts |
Persisted live positions (open-positions.json): add, remove, check due-to-close for timed sell |
src/models/llmScorer.ts |
Optional: calls OpenAI (or compatible) API with features, returns bias in [-1, 1] |
src/uiServer.ts |
Serves the Compare UI and /api/prediction |
ui/ |
Static Compare UI (HTML, JS, CSS) |
-
๐ Credentials
A validPRIVATE_KEYis required. CLOB API key / secret / passphrase are optional in.env; if missing, they are obtained automatically viacreateOrDeriveApiKey()when the first order runs. -
๐ Market selection
The bot always picks the current 5-minute BTC up/down market (by time bucket or recent trades). -
๐ Whale flow + winrate
Whale side-pressure is built from current-market participants and filtered by wallet winrate (computed locally by default). -
โ ๏ธ No guarantees
This is a heuristic/experimental strategy. Past results do not guarantee future results. Trade at your own risk and only with money you can afford to lose. -
๐ Selling / closing
Primary close rule is force-exit before settlement viaFORCE_EXIT_SECONDS(default 3). OptionalCLOSE_AFTER_SECONDSremains available as secondary timer.
| Command | Description |
|---|---|
npm run dev |
๐ Run the bot with tsx (requires PRIVATE_KEY in .env) |
npm run ui |
๐ Start the Compare UI server on port 8787 |
npm run build |
๐ฆ Compile TypeScript to dist/ |
npm start |
node dist/main.js |
Built with Openclaw ๐ฆ AI agent.
