Skip to main content

openclaw-polymarket-trading-bot

AI-powered prediction and automated trading bot for Polymarket's 5-minute Bitcoin Up/Down markets

Jump to install

Source facts

Repository
reason-machines/hermes-skills
Last source activity
June 18, 2026 at 13:42
Detected SKILL.md language
English
Stars
5
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
openclaw-polymarket-trading-bot
description
AI-powered prediction and automated trading bot for Polymarket's 5-minute Bitcoin Up/Down markets
triggers
["set up OpenClaw Polymarket trading bot","configure Polymarket AI trading bot with CLOB","run Polymarket prediction bot for BTC markets","deploy OpenClaw bot with whale flow analysis","integrate OpenAI with Polymarket trading strategy","build custom Polymarket trading indicators","debug Polymarket CLOB order execution","analyze whale activity on Polymarket BTC markets"]
# OpenClaw Polymarket Trading Bot > Skill by [ara.so](https://ara.so) — Hermes Skills collection. OpenClaw is a production-ready TypeScript bot that predicts whether Polymarket's 5-minute BTC Up/Down markets will move up (YES) or down (NO) and executes real orders via the Polymarket CLOB API. It combines momentum indicators, volatility analysis, whale flow tracking, and optional LLM scoring to generate trading signals. ## What It Does The bot runs a continuous loop that: 1. Identifies the active 5-minute BTC Up/Down market on Polymarket 2. Collects real-time price data and whale flow (large trades ≥ $200) 3. Computes indicators (momentum, volatility, whale bias) 4. Generates predictions using AI-enhanced scoring 5. Places market orders when edge threshold is exceeded 6. Optionally closes positions after a timed interval ## Installation ```bash git clone https://github.com/Golrypavium/openclaw-polymarket-trading-bot.git cd openclaw-polymarket-trading-bot npm install cp .env.example .env ``` Edit `.env` with your Polymarket CLOB credentials: ```bash # Required CLOB credentials PRIVATE_KEY=your_wallet_private_key_hex CLOB_API_KEY=your_clob_api_key CLOB_SECRET=your_clob_secret CLOB_PASS_PHRASE=your_clob_passphrase # Optional AI enhancement OPENAI_API_KEY=your_openai_key ``` ## Key Commands ```bash # Run bot in development mode npm run dev # Build for production npm run build # Run production build npm start # Start Signal Lab dashboard npm run serve ``` ## Configuration ### Environment Variables | Variable | Purpose | Default | |----------|---------|---------| | `PRIVATE_KEY` | Wallet private key (64 hex chars) | Required | | `CLOB_API_KEY` | Polymarket CLOB API key | Required | | `CLOB_SECRET` | CLOB secret | Required | | `CLOB_PASS_PHRASE` | CLOB passphrase | Required | | `LOOP_SECONDS` | Cycle interval | `15` | | `MAX_POSITION_USD` | Order size in USD | `100` | | `EDGE_THRESHOLD` | Minimum edge to trade | `0.03` | | `CLOSE_AFTER_SECONDS` | Auto-close timer (0=hold) | `0` | | `OPENAI_API_KEY` | Optional LLM enhancement | Empty | | `OPENAI_MODEL` | Model for predictions | `gpt-4o-mini` | ### Strategy Parameters The edge threshold determines when to trade: - `pUp5m > 0.5 + EDGE_THRESHOLD` → Open YES position - `pUp5m < 0.5 - EDGE_THRESHOLD` → Open NO position - Otherwise → Hold Example with `EDGE_THRESHOLD=0.03`: - Trade YES if pUp5m > 0.53 - Trade NO if pUp5m < 0.47 ## Core Architecture ### Data Flow ```typescript // core/entry.ts - Main bot loop import { opts } from './settings'; import { getMarketSnapshot } from './adapters/eventSource'; import { computeIndicators } from './strategy/indicators'; import { generateForecast } from './strategy/forecast'; import { decideAction } from './strategy/simulator'; import { submitBuy } from './adapters/orderBridge'; async function runCycle() { // 1. Get current market and price data const snapshot = await getMarketSnapshot(); // 2. Build indicators const indicators = computeIndicators(snapshot.ticks, snapshot.whale); // 3. Generate forecast const forecast = await generateForecast(indicators); // 4. Decide action const action = decideAction(forecast, snapshot.currentPrice); // 5. Execute if needed if (action.type === 'OPEN_YES') { await submitBuy('YES', action.size, snapshot.market); } } ``` ### Market Selection ```typescript // core/adapters/eventSource.ts import { opts } from '../settings'; export async function getCurrentMarket(): Promise<MarketInfo> { const gammaUrl = `${opts.polymarketRestBase}/markets`; const response = await fetch(gammaUrl); const markets = await response.json(); // Find active 5-min BTC market by time bucket const now = Date.now(); const btcMarket = markets.find(m => m.question.includes('BTC') && m.question.includes('5 minutes') && m.endDate > now && m.startDate <= now ); return { conditionId: btcMarket.conditionId, question: btcMarket.question, yesTokenId: btcMarket.tokens.YES, noTokenId: btcMarket.tokens.NO }; } ``` ### Indicator Calculation ```typescript // core/strategy/indicators.ts import { PricePoint, WhaleActivity, IndicatorSet } from '../schema/defs'; export function computeIndicators( ticks: PricePoint[], whale: WhaleActivity ): IndicatorSet { // Momentum: recent price changes const shortReturn = computeReturn(ticks, 2); // ~30s ago const medReturn = computeReturn(ticks, 8); // ~2min ago // Volatility: recent price range const recentPrices = ticks.slice(-8).map(t => t.price); const volatility = Math.max(...recentPrices) - Math.min(...recentPrices); // Whale bias: net YES vs NO from large trades const whaleBias = (whale.yesVolume - whale.noVolume) / (whale.yesVolume + whale.noVolume + 0.01); return { shortReturn, medReturn, volatility, whaleBias, whaleIntensity: whale.yesVolume + whale.noVolume }; } function computeReturn(ticks: PricePoint[], lookback: number): number { if (ticks.length < lookback + 1) return 0; const current = ticks[ticks.length - 1].price; const past = ticks[ticks.length - lookback - 1].price; return (current - past) / (past + 0.01); } ``` ### Forecast Generation ```typescript // core/strategy/forecast.ts import { IndicatorSet, Forecast } from '../schema/defs'; import { scoreLLM } from '../ai/remoteScorer'; import { opts } from '../settings'; export async function generateForecast( indicators: IndicatorSet ): Promise<Forecast> { // Base probability from momentum and whale bias let pUp5m = 0.5; // Momentum component (40% weight) const momentumSignal = (indicators.shortReturn * 0.6 + indicators.medReturn * 0.4); pUp5m += momentumSignal * 0.4; // Whale bias component (30% weight) pUp5m += indicators.whaleBias * 0.3; // Volatility dampening const volFactor = Math.min(indicators.volatility * 2, 0.1); pUp5m = 0.5 + (pUp5m - 0.5) * (1 - volFactor); // Optional LLM enhancement (30% weight) let llmBias = 0; if (opts.openaiApiKey) { llmBias = await scoreLLM(indicators); pUp5m += llmBias * 0.3; } // Clamp to [0.2, 0.8] pUp5m = Math.max(0.2, Math.min(0.8, pUp5m)); const confidence = Math.abs(pUp5m - 0.5) * 2; // [0, 1] return { pUp5m, confidence, llmBias }; } ``` ### LLM Integration ```typescript // core/ai/remoteScorer.ts import { IndicatorSet } from '../schema/defs'; import { opts } from '../settings'; export async function scoreLLM(indicators: IndicatorSet): Promise<number> { const prompt = `Predict Bitcoin 5-minute direction. Indicators: - Short momentum: ${indicators.shortReturn.toFixed(4)} - Medium momentum: ${indicators.medReturn.toFixed(4)} - Volatility: ${indicators.volatility.toFixed(4)} - Whale bias: ${indicators.whaleBias.toFixed(3)} Respond with a number from -1 (strong DOWN) to +1 (strong UP).`; const response = await fetch(`${opts.openaiBaseUrl}/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${opts.openaiApiKey}` }, body: JSON.stringify({ model: opts.openaiModel, messages: [{ role: 'user', content: prompt }], temperature: 0.3, max_tokens: 10 }) }); const data = await response.json(); const text = data.choices[0].message.content.trim(); const bias = parseFloat(text); return isNaN(bias) ? 0 : Math.max(-1, Math.min(1, bias)); } ``` ### Order Execution ```typescript // core/adapters/orderBridge.ts import { ClobClient } from '@polymarket/clob-client'; import { opts } from '../settings'; const clobClient = new ClobClient( opts.clobApiUrl, opts.clobChainId, opts.privateKey, { apiKey: opts.clobApiKey, secret: opts.clobSecret, passphrase: opts.clobPassPhrase } ); export async function submitBuy( side: 'YES' | 'NO', usdSize: number, market: MarketInfo ): Promise<string> { const tokenId = side === 'YES' ? market.yesTokenId : market.noTokenId; // Get current best price const book = await clobClient.getOrderBook(tokenId); const price = side === 'YES' ? parseFloat(book.asks[0]?.price || '0.5') : parseFloat(book.bids[0]?.price || '0.5'); const shares = usdSize / price; const order = await clobClient.createMarketBuyOrder({ tokenID: tokenId, amount: shares.toString(), feeRateBps: '0', nonce: Date.now() }); const result = await clobClient.postOrder(order); // Record position recordPosition({ orderId: result.orderID, side, entryPrice: price, shares, timestamp: Date.now(), marketId: market.conditionId }); return result.orderID; } ``` ### Position Management ```typescript // core/strategy/book.ts import fs from 'fs'; interface Position { orderId: string; side: 'YES' | 'NO'; entryPrice: number; shares: number; timestamp: number; marketId: string; } const POSITIONS_FILE = './positions.json'; export function recordPosition(pos: Position): void { const positions = loadPositions(); positions.push(pos); fs.writeFileSync(POSITIONS_FILE, JSON.stringify(positions, null, 2)); } export function getExpiredPositions(closeAfterSeconds: number): Position[] { const positions = loadPositions(); const now = Date.now(); return positions.filter(p => (now - p.timestamp) / 1000 > closeAfterSeconds ); } export function removePosition(orderId: string): void { const positions = loadPositions(); const filtered = positions.filter(p => p.orderId !== orderId); fs.writeFileSync(POSITIONS_FILE, JSON.stringify(filtered, null, 2)); } function loadPositions(): Position[] { if (!fs.existsSync(POSITIONS_FILE)) return []; return JSON.parse(fs.readFileSync(POSITIONS_FILE, 'utf-8')); } ``` ### Timed Position Closing ```typescript // In core/entry.ts cycle import { getExpiredPositions, removePosition } from './strategy/book'; import { submitSell } from './adapters/orderBridge'; async function closeExpiredPositions() { if (opts.closeAfterSeconds === 0) return; const expired = getExpiredPositions(opts.closeAfterSeconds); for (const pos of expired) { try { await submitSell(pos.side, pos.shares, pos.marketId); removePosition(pos.orderId); console.log(`Closed position ${pos.orderId} after timeout`); } catch (err) { console.error(`Failed to close ${pos.orderId}:`, err); } } } ``` ## Signal Lab Dashboard ### Starting the Dashboard ```bash npm run serve # Opens on http://localhost:8787 ``` ### Prediction API ```typescript // core/dashboard.ts import express from 'express'; import { getMarketSnapshot } from './adapters/eventSource'; import { computeIndicators } from './strategy/indicators'; import { generateForecast } from './strategy/forecast'; const app = express(); app.get('/api/prediction', async (req, res) => { try { const snapshot = await getMarketSnapshot(); const indicators = computeIndicators(snapshot.ticks, snapshot.whale); const forecast = await generateForecast(indicators); res.json({ market: snapshot.market.question, currentPrice: snapshot.currentPrice, prediction: forecast.pUp5m, confidence: forecast.confidence, recommendedSide: forecast.pUp5m > 0.5 ? 'YES' : 'NO', indicators: { momentum: indicators.shortReturn, volatility: indicators.volatility, whaleBias: indicators.whaleBias } }); } catch (error) {
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub