The open-source TypeScript framework for building automated Polymarket trading bots.
From idea to live prediction market strategy in 100 lines of code.
Quick Start · Features · Documentation · Examples · Analytics · Contributing
Polybot is a production-grade TypeScript SDK for building automated trading bots on Polymarket, the leading prediction market platform on Polygon. It provides everything you need to go from a trading idea to a live, risk-managed strategy — without reinventing position tracking, risk management, or order lifecycle handling every time.
Built for quantitative traders, developers building robust strategies, researchers backtesting signals, and teams that need production-grade risk management. Includes 25+ technical indicators, real-time WebSocket feeds, arbitrage detection, and a full analytics suite — all with 18-digit fixed-point Decimal precision.
pnpm add @polybot/sdk
# or: npm install @polybot/sdk
# or: yarn add @polybot/sdkImplement the SignalDetector interface — the only interface you need:
import type { SignalDetector, DetectorContextLike, SdkOrderIntent } from '@polybot/sdk';
import { buyYes, Decimal, MarketSide, marketTokenId } from '@polybot/sdk';
// Your entire strategy is this one interface
const oracleArb: SignalDetector<unknown, { price: Decimal; edge: number }> = {
name: 'OracleArbitrage',
detectEntry(ctx) {
const oracle = ctx.oraclePrice();
const ask = ctx.bestAsk(MarketSide.Yes);
if (!oracle || !ask) return null;
const edge = oracle.sub(ask).div(ask).toNumber();
return edge > 0.02 ? { price: ask, edge } : null; // 2% edge threshold
},
toOrder(signal, ctx) {
const size = Decimal.from(String(Math.floor(signal.edge * 1000)));
return buyYes(ctx.conditionId, marketTokenId('yes-token'), signal.price, size);
},
};
// The SDK handles everything else:
// Risk guards → Exit policies → Position tracking → Order lifecycle → P&LYou write the signal. Polybot handles the rest.
|
|
|
|
|
|
|
|
import { GuardPipeline, MaxSpreadGuard, MaxPositionsGuard,
CooldownGuard, KillSwitchGuard, CircuitBreakerGuard, Decimal } from '@polybot/sdk';
// Compose risk guards — AND semantics, short-circuits on first block
const guards = GuardPipeline.create()
.with(MaxSpreadGuard.normal()) // Block if bid-ask spread > 5%
.with(MaxPositionsGuard.create(5)) // Max 5 concurrent positions
.with(CooldownGuard.fromSecs(30)) // 30s cooldown between trades
.with(KillSwitchGuard.create(3, 5)) // Soft 3%, hard 5% daily loss
.with(CircuitBreakerGuard.create(
Decimal.from('500'), 0.2 // $500 daily limit, 20% consecutive loss
));
// Or use a built-in preset
const conservative = GuardPipeline.conservative();import { ExitPipeline, TakeProfitExit, StopLossExit,
TrailingStopExit, NearExpiryExit, EmergencyExit, Decimal } from '@polybot/sdk';
// Compose exit policies — OR semantics, first exit wins
const exits = ExitPipeline.create()
.with(new TakeProfitExit(Decimal.from('0.15'))) // Take profit at 15% ROI
.with(new StopLossExit(Decimal.from('-0.08'))) // Stop loss at -8%
.with(new TrailingStopExit(Decimal.from('0.05'))) // 5% trailing stop from HWM
.with(new NearExpiryExit(60_000)) // Exit 60s before market expiry
.with(new EmergencyExit({ maxHoldTimeMs: 3_600_000 })); // 1h max hold timeimport { PositionManager, Decimal,
conditionId, marketTokenId, MarketSide, unwrap } from '@polybot/sdk';
let manager = PositionManager.create();
// Open a position (returns Result, never throws)
const result = manager.open(
conditionId('0x123...'), marketTokenId('tok-yes'),
MarketSide.Yes, Decimal.from('0.45'), Decimal.from('100'), Date.now(),
);
manager = unwrap(result);
console.log(manager.openCount()); // 1
console.log(manager.totalNotional()); // 45.00
// Close with automatic P&L tracking
const closed = manager.close(conditionId('0x123...'), Decimal.from('0.55'), Date.now());
if (closed) {
console.log(closed.pnl.toString()); // "10" (profit)
}The SDK includes a full analytics module with 25+ indicators, all operating on Decimal precision:
import { calcSMA, calcEMA, calcRSI, calcMACD, calcBollingerBands,
calcADX, calcAroon, calcDEMA, calcTRIX, calcPSAR } from '@polybot/sdk';
const closes = candles.map(c => c.close);
const sma = calcSMA(closes, 20); // Simple Moving Average
const ema = calcEMA(closes, 12); // Exponential Moving Average
const rsi = calcRSI(closes, 14); // Relative Strength Index
const macd = calcMACD(closes); // MACD (12, 26, 9)
const bands = calcBollingerBands(closes); // Bollinger Bands (20, 2)import { calcATR, calcDonchian, calcKeltner, calcChandelier } from '@polybot/sdk';
const atr = calcATR(candles, 14); // Average True Range
const donchian = calcDonchian(candles, 20); // Donchian Channel
const keltner = calcKeltner(candles); // Keltner Channel
const chandelier = calcChandelier(candles); // Chandelier Exitimport { calcStochastic, calcCCI, calcOBV, calcVWMA,
calcMFI, calcCMF } from '@polybot/sdk';
const stoch = calcStochastic(candles); // Stochastic Oscillator
const cci = calcCCI(candles, 20); // Commodity Channel Index
const obv = calcOBV(candles); // On-Balance Volume
const mfi = calcMFI(candles, 14); // Money Flow Indeximport { calcImbalanceRatio, calcVWAP, calcSpreadBps,
estimateSlippage, calcBookDepth } from '@polybot/sdk';
const imbalance = calcImbalanceRatio(bids, asks, 5); // Top-5 level imbalance
const vwap = calcVWAP(bids, asks); // Volume-weighted avg price
const spreadBps = calcSpreadBps(bids, asks); // Spread in basis points
const slippage = estimateSlippage(asks, size); // Expected slippage for size| Category | Indicators |
|---|---|
| Price | SMA, EMA, RSI, Bollinger Bands |
| Volatility | ATR, Donchian Channel, Keltner Channel, Chandelier Exit |
| Trend | MACD, ADX, Aroon, DEMA, TRIX, Parabolic SAR |
| Momentum | Stochastic, Williams %R, CCI, ROC, Awesome Oscillator, StochRSI |
| Volume | OBV, VWMA, MFI, ADL, CMF, Force Index, NVI, VPT, PVO |
| Orderbook | Imbalance Ratio, VWAP, Spread (bps), Slippage Estimation, Book Depth |
pnpm install # Install dependencies
pnpm vitest run # Run all 2,000+ tests
pnpm test:watch # Watch mode for TDD
pnpm typecheck # TypeScript strict type checking
pnpm lint # Biome linting
pnpm build # Build ESM + CJS output
pnpm ci # Run all CI checks- Phase 0 — Shared kernel, lifecycle state machine, domain events
- Phase 1 — Risk guards, exit pipelines, position tracking, order FSM
- Phase 2 — Execution layer, Polymarket CLOB integration, authentication
- Phase 3 — WebSocket real-time market data, orderbook streaming
- Phase 4 — Strategy runtime, builder pattern, presets
- Phase 5 — Persistence, CTF operations (split/merge/redeem), journal
- Phase 6.1 — Library wrappers (validation, typed events, guard combinators)
- Phase 6.2 — JSDoc completion, documentation polish, CHANGELOG
- Hardening — Multiple adversarial review passes, 400+ tests added, bug fixes
- Phase 9 — Pricing models, backtesting, position sizing, microstructure, observability
- Gap-closing — Mempool monitoring, terminal dashboard, thread config hints, performance benchmarks
- Phase 7 — npm publish, documentation site, CLI tooling
| Feature | Polybot SDK | Raw CLOB Client | Script-based Bots |
|---|---|---|---|
| Strategy framework | Yes | No | No |
| Risk management (15 guards) | Yes | No | Manual |
| Exit pipeline (7 policies) | Yes | No | Manual |
| Position tracking with P&L | Yes | No | Basic |
| Order state machine (7 states) | Yes | No | No |
| Technical indicators (25+) | Yes | No | No |
| Orderbook analytics | Yes | No | Manual |
| Arbitrage detection | Yes | No | Manual |
| Rate limiting with presets | Yes | Manual | Manual |
| Market discovery & scanning | Yes | Manual | Manual |
| Library abstraction layer | Yes | No | No |
| Test suite | 2,000+ tests | N/A | N/A |
Contributions are welcome! Please follow these guidelines:
- Fork the repo and create a feature branch from
main - Write tests first (TDD) — all PRs must include tests
- Follow conventions — Biome lint, strict TypeScript, immutable patterns
- Keep files < 800 LOC — propose a split plan if needed
- Run all checks before submitting:
pnpm ci
See ARCHITECTURE.md for design decisions and module boundaries. See CONTRIBUTING.md for tutorials on adding guards, exits, and strategies.
MIT — built by @HugoLopes45