| name | polymarket-openclaw-ai-arbitrage-bot |
| description | AI-enhanced Polymarket CLOB trading bot for BTC 5m/15m arbitrage with OpenClaw decision engine |
| triggers | ["set up polymarket trading bot","configure openclaw arbitrage strategy","trade on polymarket btc 5 minute markets","implement polymarket clob automation","debug polymarket api credentials","run polymarket ai trading bot","configure polymarket arbitrage bot","troubleshoot polymarket wallet signing"] |
Polymarket OpenClaw AI Arbitrage Bot
Skill by ara.so — Hermes Skills collection.
This skill enables AI coding agents to work with the OpenClaw Polymarket AI Trading Bot, a TypeScript-based automated trading system for Polymarket CLOB markets focusing on BTC 5-minute and 15-minute Up/Down prediction markets.
What This Bot Does
The bot automates short-horizon prediction market trading on Polymarket using:
- Market selection: Targets BTC/ETH/SOL 5m/15m/60m markets
- Pricing: Polls Gamma/CLOB for UP/DOWN outcome token prices
- Strategies: Executes
trade_1 or trade_2 rule-based strategies
- OpenClaw decision layer: Optional AI-enhanced decision engine
- Execution: Submits market orders via Polymarket v2 CLOB API
- Risk management: Cooldowns, retries, position limits, safety locks
Architecture: L1 wallet signing → API credential derivation → L2 authenticated CLOB client → market polling → strategy decision → order execution.
Installation
git clone https://github.com/lorine93s/openclaw-polymarket-ai-arbitrage-trading-bot
cd openclaw-polymarket-ai-arbitrage-trading-bot
npm install
cp .env.example .env
Environment Configuration
Edit .env with your credentials:
POLYMARKET_PRIVATE_KEY=your_private_key_here
POLYMARKET_FUNDER_ADDRESS=0xYourFunderAddress
POLYMARKET_SIGNATURE_TYPE=POLY_PROXY
Validation: The bot validates all required environment variables on startup using Zod schemas. Missing or invalid keys will trigger clear error messages.
Strategy Configuration (trade.toml)
Basic Market Setup
strategy = "trade_1"
trade_usd = 10.0
max_retries = 3
entry_buy_cooldown_sec = 30
[market]
market_coin = "btc"
market_period = "5"
Trade Strategy 1 (Time-Based Exits)
[trade_1]
entry_range_min = 0.45
entry_range_max = 0.55
buy_up_ratio_threshold = 1.05
buy_down_ratio_threshold = 1.05
exit_after_secs = 120
exit_up_ratio_threshold = 0.95
exit_down_ratio_threshold = 0.95
emergency_swap_enabled = true
emergency_swap_ratio_threshold = 1.15
Trade Strategy 2 (Price-Based Exits)
[trade_2]
entry_range_min = 0.40
entry_range_max = 0.60
buy_up_ratio_threshold = 1.08
buy_down_ratio_threshold = 1.08
exit_up_profit_target = 0.65
exit_down_profit_target = 0.35
emergency_swap_enabled = false
OpenClaw AI Decision Layer
[openclaw]
enabled = true
mode = "deterministic"
min_edge_bps = 50
max_spread_bps = 200
lookback_points = 12
Running the Bot
npm run dev
npm run build
npm start
npm run typecheck
npm run lint
Core API and Code Patterns
Market Slug Generation
import { formatSlug } from './config/slug';
const slug = formatSlug('btc', '5');
const ethSlug = formatSlug('eth', '15');
CLOB Client Initialization
import { initClobClient } from './services/clob';
const clobClient = await initClobClient();
await clobClient.createOrDeriveAPIKey();
const l2Client = await initClobClient({ signatureType: 'POLY_PROXY', feeRecipient: 'YOUR_ADDRESS' });
Market Data Fetching
import { getMarketBySlug } from './services/gamma';
const marketData = await getMarketBySlug(slug);
if (!marketData) {
throw new Error(`Market not found: ${slug}`);
}
console.log('Market ID:', marketData.id);
console.log('End time:', marketData.end_date_iso);
console.log('Tokens:', marketData.tokens);
Price Polling
import { updatePrices } from './trade/prices';
import { Trade } from './trade/trade';
const trade = new Trade(
l2Client,
config,
marketData.tokens[0].token_id,
marketData.tokens[1].token_id,
marketData.end_date_iso
);
await updatePrices(trade, clobClient);
console.log('UP price:', trade.upPrice);
console.log('DOWN price:', trade.downPrice);
console.log('Spread:', trade.upPrice + trade.downPrice);
Order Execution
import { createAndPostMarketOrder } from './trade/trade';
await createAndPostMarketOrder(
trade,
'BUY',
trade.upTokenId,
trade.upPrice,
10.0
);
if (trade.hasBought) {
await createAndPostMarketOrder(
trade,
'SELL',
trade.boughtTokenId,
trade.boughtSide === 'Up' ? trade.upPrice : trade.downPrice,
trade.boughtTokens
);
}
Strategy Decision Logic
import { make_trading_decision } from './trade/decision';
await make_trading_decision(trade);
OpenClaw Decision Integration
import { openclawDecision } from './trade/openclaw';
const decision = await openclawDecision(trade, config);
console.log('Action:', decision.action);
console.log('Reason:', decision.reason);
console.log('Confidence:', decision.confidence);
Error Handling and Retries
import { retryWithPolicy } from './utils/retry';
import { formatTradingError } from './utils/tradingErrorMessage';
try {
await retryWithPolicy(
async () => {
return await clobClient.createOrder(orderArgs);
},
3,
'createOrder'
);
} catch (err) {
const friendlyMessage = formatTradingError(err);
console.error('Order failed:', friendlyMessage);
if (shouldCooldown(err)) {
await new Promise(r => setTimeout(r, config.entry_buy_cooldown_sec * 1000));
}
}
Common Patterns
Running Multiple Market Windows
To trade both 5-minute and 15-minute markets simultaneously, run two separate processes:
Terminal 1 - 5 minute config (trade-5m.toml):
[market]
market_coin = "btc"
market_period = "5"
npm run dev -- --config=trade-5m.toml
Terminal 2 - 15 minute config (trade-15m.toml):
[market]
market_coin = "btc"
market_period = "15"
npm run dev -- --config=trade-15m.toml
Balance Monitoring
const balance = await l2Client.getBalance();
console.log('Available USDC:', balance);
if (balance < config.trade_usd) {
throw new Error(`Insufficient balance: ${balance} < ${config.trade_usd}`);
}
Position Tracking
class Trade {
hasBought: boolean = false;
boughtSide: 'Up' | 'Down' | null = null;
boughtPrice: number = 0;
boughtTokens: number = 0;
boughtTokenId: string = '';
boughtTime: number = 0;
resetPosition() {
this.hasBought = false;
this.boughtSide = null;
this.boughtPrice = 0;
this.boughtTokens = 0;
this.boughtTokenId = '';
this.boughtTime = 0;
}
}
Safe Shutdown
process.on('SIGINT', async () => {
console.log('\n⚠️ Shutdown signal received');
if (trade.hasBought) {
console.log('🔒 Warning: Position still open!');
console.log(` Side: ${trade.boughtSide}`);
console.log(` Tokens: ${trade.boughtTokens}`);
console.log(' Consider manual exit before shutdown');
}
process.exit(0);
});
Troubleshooting
"Private key must be a valid byteslike value"
Cause: Invalid or missing POLYMARKET_PRIVATE_KEY in .env.
Solution:
POLYMARKET_PRIVATE_KEY=abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890
API Credential Errors
Symptom: 401/403 errors from CLOB API.
Solution:
const clobClient = await initClobClient();
await clobClient.createOrDeriveAPIKey();
console.log('Funder:', process.env.POLYMARKET_FUNDER_ADDRESS);
Order Placement Failures
Common causes:
- Insufficient balance
- Market expired/not active
- Price moved (stale quote)
- Network latency
Debug approach:
console.log('Attempting order:', {
side: 'BUY',
tokenId: trade.upTokenId,
price: trade.upPrice,
amount: config.trade_usd,
balance: await l2Client.getBalance()
});
const market = await getMarketBySlug(slug);
console.log('Market active:', new Date(market.end_date_iso) > new Date());
OpenClaw Decision Issues
Symptom: HOLD action when expecting trades.
Solution:
[openclaw]
min_edge_bps = 25
max_spread_bps = 300
lookback_points = 6
Cooldown Loops
Symptom: Bot stuck in cooldown after failed buys.
Solution:
entry_buy_cooldown_sec = 10
Market Not Found
Symptom: Market not found: will-btc-close-higher-in-the-next-5-minutes
Solution:
[market]
market_period = "15" # Switch from "5" if 5m market unavailable
Memory Leaks / High CPU
Symptom: Bot slows down over time.
Solution:
const MAX_LOOKBACK = 100;
if (priceHistory.length > MAX_LOOKBACK) {
priceHistory = priceHistory.slice(-MAX_LOOKBACK);
}
await new Promise(r => setTimeout(r, 2000));
Key Files Reference
| File | Purpose |
|---|
src/index.ts | Entry point, market loop, CLOB auth |
src/config/toml.ts | Config schema and validation |
src/config/env.ts | Environment variable loading |
src/config/slug.ts | Market slug generation |
src/services/clob.ts | CLOB client initialization |
src/services/gamma.ts | Gamma API market data |
src/trade/trade.ts | Trade class, order execution |
src/trade/decision.ts | Strategy decision logic |
src/trade/prices.ts | Price polling and updates |
src/trade/openclaw.ts | OpenClaw AI decision engine |
src/utils/retry.ts | Retry policy for transient errors |
src/utils/tradingErrorMessage.ts | Human-readable error formatting |
Safety Reminders
- Start with small
trade_usd (5-10 USD) for testing
- Paper trade first by setting very restrictive entry thresholds
- Monitor positions — 5m/15m markets move fast
- Execution risk exists — partial fills, slippage, API latency
- Not financial advice — this is experimental automation software
- Comply with local regulations — prediction markets may be restricted in your jurisdiction