@catalyst-team/poly-sdk

Unified TypeScript SDK for Polymarket - Trading, market data, smart money analysis, and on-chain operations.
Builder: @hhhx402 | Project: Catalyst.fun
☕ Buy Me a Coffee (Polygon): 0x58d2ff253998bc2f3b8f5bdbe9c52cad7b022739
中文文档
Table of Contents
Overview
@catalyst-team/poly-sdk is a comprehensive TypeScript SDK that provides:
- Trading - Place limit/market orders (GTC, GTD, FOK, FAK)
- Market Data - Real-time prices, orderbooks, K-lines, historical trades
- Smart Money Analysis - Track top traders, calculate smart scores, follow wallet strategies
- On-chain Operations - CTF (split/merge/redeem), approvals, DEX swaps
- Arbitrage Detection - Real-time arbitrage scanning and execution
- WebSocket Streaming - Live price feeds and orderbook updates
Key Features
| Unified API | Single SDK for all Polymarket APIs |
| Type Safety | Full TypeScript support with comprehensive types |
| Rate Limiting | Built-in rate limiting per API endpoint |
| Caching | TTL-based caching with pluggable adapters |
| Error Handling | Structured errors with auto-retry |
Installation
pnpm add @catalyst-team/poly-sdk
npm install @catalyst-team/poly-sdk
yarn add @catalyst-team/poly-sdk
Architecture
The SDK is organized into three layers:
poly-sdk Architecture
================================================================================
┌──────────────────────────────────────────────────────────────────────────────┐
│ PolymarketSDK │
│ (Entry Point) │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ Layer 3: High-Level Services (Recommended) │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ TradingService │ │ MarketService │ │ OnchainService │ │
│ │ ────────────── │ │ ────────────── │ │ ────────────── │ │
│ │ • Limit orders │ │ • K-lines │ │ • Split/Merge │ │
│ │ • Market orders│ │ • Orderbook │ │ • Redeem │ │
│ │ • Order mgmt │ │ • Price history│ │ • Approvals │ │
│ │ • Rewards │ │ • Arbitrage │ │ • Swaps │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │RealtimeServiceV2│ │ WalletService │ │SmartMoneyService│ │
│ │ ────────────── │ │ ────────────── │ │ ────────────── │ │
│ │ • WebSocket │ │ • Profiles │ │ • Top traders │ │
│ │ • Price feeds │ │ • Smart scores │ │ • Copy trading │ │
│ │ • Book updates │ │ • Sell detect │ │ • Signal detect │ │
│ │ • User events │ │ • PnL calc │ │ • Leaderboard │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ ArbitrageService │ │
│ │ ───────────────────────────────────────────────────────────────────── │ │
│ │ • Market scanning • Auto execution • Rebalancer • Smart clearing │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ DipArbService │ │
│ │ ───────────────────────────────────────────────────────────────────── │ │
│ │ • 15m crypto UP/DOWN • Dip detection • Auto-rotate • Background redeem│
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ Layer 2: Low-Level Clients (Advanced Users / Raw API Access) │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │GammaApiClnt│ │DataApiClnt │ │SubgraphClnt│ │ CTFClient │ │BridgeClient│ │
│ │ ────────── │ │ ────────── │ │ ────────── │ │ ────────── │ │ ────────── │ │
│ │ • Markets │ │ • Positions│ │ • On-chain │ │ • Split │ │ • Cross- │ │
│ │ • Events │ │ • Trades │ │ • PnL │ │ • Merge │ │ chain │ │
│ │ • Search │ │ • Activity │ │ • OI │ │ • Redeem │ │ • Deposits │ │
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │
│ │
│ Uses Official Polymarket Clients: │
│ • @polymarket/clob-client - Trading, orderbook, market data │
│ • @polymarket/real-time-data-client - WebSocket real-time updates │
│ │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ Layer 1: Core Infrastructure │
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │RateLimiter │ │ Cache │ │ Errors │ │ Types │ │Price Utils │ │
│ │ ────────── │ │ ────────── │ │ ────────── │ │ ────────── │ │ ────────── │ │
│ │ • Per-API │ │ • TTL-based│ │ • Retry │ │ • Unified │ │ • Arb calc │ │
│ │ • Bottleneck│ │ • Pluggable│ │ • Codes │ │ • K-lines │ │ • Rounding │ │
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
Service Responsibilities
| PolymarketSDK | Entry point, integrates all services |
| TradingService | Order management (place/cancel/query) |
| MarketService | Market data (orderbook/K-lines/search) |
| OnchainService | On-chain ops (split/merge/redeem/approve/swap) |
| RealtimeServiceV2 | WebSocket real-time data |
| WalletService | Wallet/trader analysis |
| SmartMoneyService | Smart money tracking |
| ArbitrageService | Arbitrage detection & execution |
| DipArbService | Dip arbitrage for 15m crypto markets |
Quick Start
Basic Usage (Read-Only)
import { PolymarketSDK } from '@catalyst-team/poly-sdk';
const sdk = new PolymarketSDK();
const market = await sdk.getMarket('will-trump-win-2024');
console.log(`${market.question}`);
console.log(`YES: ${market.tokens.find(t => t.outcome === 'Yes')?.price}`);
console.log(`NO: ${market.tokens.find(t => t.outcome === 'No')?.price}`);
const orderbook = await sdk.getOrderbook(market.conditionId);
console.log(`Long Arb Profit: ${orderbook.summary.longArbProfit}`);
console.log(`Short Arb Profit: ${orderbook.summary.shortArbProfit}`);
const arb = await sdk.detectArbitrage(market.conditionId);
if (arb) {
console.log(`${arb.type.toUpperCase()} ARB: ${(arb.profit * 100).toFixed(2)}% profit`);
console.log(arb.action);
}
With Authentication (Trading)
import { PolymarketSDK } from '@catalyst-team/poly-sdk';
const sdk = await PolymarketSDK.create({
privateKey: process.env.POLYMARKET_PRIVATE_KEY!,
});
const order = await sdk.tradingService.createLimitOrder({
tokenId: yesTokenId,
side: 'BUY',
price: 0.45,
size: 10,
orderType: 'GTC',
});
console.log(`Order placed: ${order.id}`);
const openOrders = await sdk.tradingService.getOpenOrders();
console.log(`Open orders: ${openOrders.length}`);
sdk.stop();
Services Guide
PolymarketSDK (Entry Point)
The main SDK class that integrates all services.
import { PolymarketSDK } from '@catalyst-team/poly-sdk';
const sdk = await PolymarketSDK.create({
privateKey: '0x...',
chainId: 137,
});
sdk.tradingService
sdk.markets
sdk.wallets
sdk.realtime
sdk.smartMoney
sdk.dipArb
sdk.dataApi
sdk.gammaApi
sdk.subgraph
await sdk.getMarket(identifier);
await sdk.getOrderbook(conditionId);
await sdk.detectArbitrage(conditionId);
sdk.stop();
TradingService
Order management using @polymarket/clob-client.
Important: Polymarket Order Minimums
- Minimum order size: 5 shares (
MIN_ORDER_SIZE_SHARES)
- Minimum order value: $1 USDC (
MIN_ORDER_VALUE_USDC)
- Orders below these limits are validated and rejected before sending to API
import { TradingService, MIN_ORDER_SIZE_SHARES, MIN_ORDER_VALUE_USDC } from '@catalyst-team/poly-sdk';
const trading = new TradingService(rateLimiter, cache, {
privateKey: process.env.POLYMARKET_PRIVATE_KEY!,
});
await trading.initialize();
const gtcOrder = await trading.createLimitOrder({
tokenId: yesTokenId,
side: 'BUY',
price: 0.45,
size: 10,
orderType: 'GTC',
});
const gtdOrder = await trading.createLimitOrder({
tokenId: yesTokenId,
side: 'BUY',
price: 0.45,
size: 10,
orderType: 'GTD',
expiration: Math.floor(Date.now() / 1000) + 3600,
});
const fokOrder = await trading.createMarketOrder({
tokenId: yesTokenId,
side: 'BUY',
amount: 10,
orderType: 'FOK',
});
const fakOrder = await trading.createMarketOrder({
tokenId: yesTokenId,
side: 'SELL',
amount: 10,
orderType: 'FAK',
});
const openOrders = await trading.getOpenOrders();
await trading.cancelOrder(orderId);
await trading.cancelAllOrders();
const isScoring = await trading.isOrderScoring(orderId);
const rewards = await trading.getCurrentRewards();
const earnings = await trading.getEarnings('2024-12-07');
MarketService
Market data, K-lines, orderbook analysis.
import { MarketService } from '@catalyst-team/poly-sdk';
const market = await sdk.markets.getMarket('btc-100k-2024');
const prices = await sdk.markets.getKLines(conditionId, '1d');
const dual = await sdk.markets.getDualKLines(conditionId, '1d');
console.log(dual.primary);
console.log(dual.secondary);
console.log(dual.spreadAnalysis);
const klines = await sdk.markets.getKLinesOHLCV(conditionId, '1h', { limit: 100 });
const dualOHLCV = await sdk.markets.getDualKLinesOHLCV(conditionId, '1h');
console.log(dualOHLCV.yes);
console.log(dualOHLCV.no);
console.log(dualOHLCV.spreadAnalysis);
console.log(dualOHLCV.realtimeSpread);
const orderbook = await sdk.markets.getProcessedOrderbook(conditionId);
const spread = await sdk.markets.getRealtimeSpread(conditionId);
if (spread.longArbProfit > 0.005) {
console.log(`Long arb: buy YES@${spread.yesAsk} + NO@${spread.noAsk}`);
}
const signals = await sdk.markets.detectMarketSignals(conditionId);
Understanding Polymarket Orderbook
Important: Polymarket orderbooks have a mirror property:
Buy YES @ P = Sell NO @ (1-P)
This means the same order appears in both orderbooks. Simple addition causes double-counting:
const askSum = YES.ask + NO.ask;
import { getEffectivePrices, checkArbitrage } from '@catalyst-team/poly-sdk';
const effective = getEffectivePrices(yesAsk, yesBid, noAsk, noBid);
const arb = checkArbitrage(yesAsk, noAsk, yesBid, noBid);
if (arb) {
console.log(`${arb.type} arb: ${(arb.profit * 100).toFixed(2)}% profit`);
}
OnchainService
Unified interface for all on-chain operations: CTF + Approvals + Swaps.
import { OnchainService } from '@catalyst-team/poly-sdk';
const onchain = new OnchainService({
privateKey: process.env.POLYMARKET_PRIVATE_KEY!,
rpcUrl: 'https://polygon-rpc.com',
});
const status = await onchain.checkReadyForCTF('100');
if (!status.ready) {
console.log('Issues:', status.issues);
await onchain.approveAll();
}
const splitResult = await onchain.split(conditionId, '100');
const mergeResult = await onchain.mergeByTokenIds(conditionId, tokenIds, '100');
const redeemResult = await onchain.redeemByTokenIds(conditionId, tokenIds);
await onchain.swap('MATIC', 'USDC_E', '50');
const balances = await onchain.getBalances();
console.log(`USDC.e: ${balances.usdcE}`);
Note: Polymarket CTF requires USDC.e (0x2791...), not native USDC.
RealtimeServiceV2
WebSocket real-time data using @polymarket/real-time-data-client.
import { RealtimeServiceV2 } from '@catalyst-team/poly-sdk';
const realtime = new RealtimeServiceV2({
autoReconnect: true,
pingInterval: 5000,
});
realtime.connect();
realtime.subscribeMarket([yesTokenId, noTokenId]);
realtime.on('priceUpdate', (update) => {
console.log(`${update.assetId}: ${update.price}`);
console.log(`Midpoint: ${update.midpoint}, Spread: ${update.spread}`);
});
realtime.on('bookUpdate', (update) => {
console.log(`Best bid: ${update.bids[0]?.price}`);
console.log(`Best ask: ${update.asks[0]?.price}`);
});
realtime.on('lastTrade', (trade) => {
console.log(`Trade: ${trade.side} ${trade.size} @ ${trade.price}`);
});
const price = realtime.getPrice(yesTokenId);
const book = realtime.getBook(yesTokenId);
realtime.disconnect();
WalletService
Wallet analysis and smart money scoring.
const traders = await sdk.wallets.getTopTraders(10);
const profile = await sdk.wallets.getWalletProfile('0x...');
console.log(`Smart Score: ${profile.smartScore}/100`);
console.log(`Win Rate: ${profile.winRate}%`);
console.log(`Total PnL: $${profile.totalPnL}`);
const sellResult = await sdk.wallets.detectSellActivity(
'0x...',
conditionId,
Date.now() - 24 * 60 * 60 * 1000
);
if (sellResult.isSelling) {
console.log(`Sold ${sellResult.percentageSold}%`);
}
const groupSell = await sdk.wallets.trackGroupSellRatio(
['0x...', '0x...'],
conditionId,
peakValue,
sinceTimestamp
);
SmartMoneyService
Smart money detection and real-time auto copy trading.
import { PolymarketSDK } from '@catalyst-team/poly-sdk';
const sdk = await PolymarketSDK.create({ privateKey: '0x...' });
const wallets = await sdk.smartMoney.getSmartMoneyList(50);
const isSmartMoney = await sdk.smartMoney.isSmartMoney('0x...');
const sub = sdk.smartMoney.subscribeSmartMoneyTrades(
(trade) => {
console.log(`${trade.traderName} ${trade.side} ${trade.outcome} @ $${trade.price}`);
},
{ filterAddresses: ['0x...'], minSize: 10 }
);
const subscription = await sdk.smartMoney.startAutoCopyTrading({
topN: 50,
sizeScale: 0.1,
maxSizePerTrade: 10,
maxSlippage: 0.03,
orderType: 'FOK',
minTradeSize: 5,
sideFilter: 'BUY',
dryRun: true,
onTrade: (trade, result) => {
console.log(`Copied ${trade.traderName}: ${result.success ? '✅' : '❌'}`);
},
onError: (error) => console.error(error),
});
console.log(`Tracking ${subscription.targetAddresses.length} wallets`);
const stats = subscription.getStats();
console.log(`Detected: ${stats.tradesDetected}, Executed: ${stats.tradesExecuted}`);
subscription.stop();
sdk.stop();
Note: Polymarket minimum order size is $1. Orders below $1 will be automatically skipped.
📁 Full examples: See scripts/smart-money/ for complete working scripts:
04-auto-copy-trading.ts - Full-featured auto copy trading
05-auto-copy-simple.ts - Simplified SDK usage
06-real-copy-test.ts - Real trading test
ArbitrageService
Real-time arbitrage detection, execution, and position management.
import { ArbitrageService } from '@catalyst-team/poly-sdk';
const arbService = new ArbitrageService({
privateKey: process.env.POLY_PRIVKEY,
profitThreshold: 0.005,
minTradeSize: 5,
maxTradeSize: 100,
autoExecute: true,
enableRebalancer: true,
minUsdcRatio: 0.2,
maxUsdcRatio: 0.8,
targetUsdcRatio: 0.5,
sizeSafetyFactor: 0.8,
autoFixImbalance: true,
});
arbService.on('opportunity', (opp) => {
console.log(`${opp.type.toUpperCase()} ARB: ${opp.profitPercent.toFixed(2)}%`);
});
arbService.on('execution', (result) => {
if (result.success) {
console.log(`Executed: $${result.profit.toFixed(2)} profit`);
}
});
const results = await arbService.scanMarkets({ minVolume24h: 5000 }, 0.005);
const best = await arbService.findAndStart(0.005);
console.log(`Started: ${best.market.name} (+${best.profitPercent.toFixed(2)}%)`);
await new Promise(r => setTimeout(r, 60 * 60 * 1000));
await arbService.stop();
const clearResult = await arbService.clearPositions(best.market, true);
console.log(`Recovered: $${clearResult.totalUsdcRecovered.toFixed(2)}`);
DipArbService
Dip Arbitrage for Polymarket 15-minute crypto UP/DOWN markets (BTC, ETH, SOL, XRP).
Strategy: Detect sudden price dips → Buy dipped side (Leg1) → Wait for opposite to drop → Buy opposite (Leg2) → Lock profit (UP + DOWN = $1)
Quick Start
PRIVATE_KEY=0x... npx tsx scripts/dip-arb/auto-trade.ts
Features
| Dip Detection | Detects 15%+ price drops within 10s sliding window |
| Two-Leg Execution | Leg1 (buy dip) + Leg2 (buy opposite when cost < target) |
| Auto-Rotate | Automatically switches to next market when current ends |
| Background Redeem | Waits for Oracle resolution (~5min) then redeems winning positions |
| WebSocket Reconnect | Auto re-subscribes on disconnect |
Programmatic Usage
import { PolymarketSDK } from '@catalyst-team/poly-sdk';
const sdk = new PolymarketSDK({ privateKey: '0x...' });
sdk.dipArb.updateConfig({
shares: 10,
sumTarget: 0.9,
dipThreshold: 0.15,
windowMinutes: 14,
autoExecute: true,
});
sdk.dipArb.on('signal', (signal) => {
console.log(`${signal.type}: ${signal.side} @ ${signal.price}`);
});
sdk.dipArb.on('execution', (result) => {
console.log(`${result.leg} ${result.success ? '✅' : '❌'}`);
});
sdk.dipArb.on('roundComplete', (result) => {
console.log(`Profit: $${result.profit?.toFixed(2)}`);
});
const market = await sdk.dipArb.findAndStart({
coin: 'ETH',
preferDuration: '15m',
});
sdk.dipArb.enableAutoRotate({
enabled: true,
underlyings: ['ETH'],
duration: '15m',
settleStrategy: 'redeem',
redeemWaitMinutes: 5,
});
const stats = sdk.dipArb.getStats();
console.log(`Signals: ${stats.signalsDetected}, L1: ${stats.leg1Filled}, L2: ${stats.leg2Filled}`);
await sdk.dipArb.stop();
sdk.stop();
Events
started | DipArbMarketConfig | Started monitoring market |
stopped | - | Stopped monitoring |
newRound | { roundId, upOpen, downOpen } | New trading round |
signal | DipArbSignalEvent | Leg1/Leg2 signal detected |
execution | DipArbExecutionResult | Trade execution result |
roundComplete | { profit, profitRate } | Round finished |
rotate | { reason, newMarket } | Switched to new market |
settled | { success, amountReceived } | Position redeemed |
Scripts
PRIVATE_KEY=0x... npx tsx scripts/dip-arb/auto-trade.ts
PRIVATE_KEY=0x... npx tsx scripts/dip-arb/redeem-positions.ts
Low-Level Clients
For advanced users who need direct API access:
import {
DataApiClient,
GammaApiClient,
SubgraphClient,
CTFClient,
BridgeClient,
SwapService,
} from '@catalyst-team/poly-sdk';
const positions = await sdk.dataApi.getPositions('0x...');
const trades = await sdk.dataApi.getTrades('0x...');
const leaderboard = await sdk.dataApi.getLeaderboard();
const markets = await sdk.gammaApi.searchMarkets({ query: 'bitcoin' });
const trending = await sdk.gammaApi.getTrendingMarkets(10);
const events = await sdk.gammaApi.getEvents({ limit: 20 });
const userPositions = await sdk.subgraph.getUserPositions(address);
const isResolved = await sdk.subgraph.isConditionResolved(conditionId);
const globalOI = await sdk.subgraph.getGlobalOpenInterest();
Breaking Changes (v0.3.0)
UnifiedMarket.tokens is now an Array
Before (v0.2.x):
const yesPrice = market.tokens.yes.price;
const noPrice = market.tokens.no.price;
After (v0.3.0):
const yesToken = market.tokens.find(t => t.outcome === 'Yes');
const noToken = market.tokens.find(t => t.outcome === 'No');
const yesPrice = yesToken?.price;
const noPrice = noToken?.price;
Migration Guide
function getTokenPrice(market: UnifiedMarket, outcome: 'Yes' | 'No'): number {
return market.tokens.find(t => t.outcome === outcome)?.price ?? 0;
}
const yesPrice = getTokenPrice(market, 'Yes');
const noPrice = getTokenPrice(market, 'No');
Why the change? The array format better supports multi-outcome markets and is more consistent with the Polymarket API response format.
Examples
Run examples with:
pnpm example:basic
pnpm example:smart-money
pnpm example:trading
pnpm example:realtime
pnpm example:arb-service
| 01-basic-usage.ts | Get markets, orderbooks, detect arbitrage |
| 02-smart-money.ts | Top traders, wallet profiles, smart scores |
| 03-market-analysis.ts | Market signals, volume analysis |
| 04-kline-aggregation.ts | Build OHLCV candles from trades |
| 05-follow-wallet-strategy.ts | Track smart money, detect exits |
| 06-services-demo.ts | All SDK services in action |
| 07-realtime-websocket.ts | Live price feeds, orderbook updates |
| 08-trading-orders.ts | GTC, GTD, FOK, FAK order types |
| 09-rewards-tracking.ts | Market maker incentives, earnings |
| 10-ctf-operations.ts | Split, merge, redeem tokens |
| 11-live-arbitrage-scan.ts | Scan markets for opportunities |
| 12-trending-arb-monitor.ts | Real-time trending monitor |
| 13-arbitrage-service.ts | Full arbitrage workflow |
| 14-dip-arb-service.ts | Dip arbitrage for 15m crypto |
DipArb Scripts (in scripts/dip-arb/):
API Reference
For detailed API documentation, see:
Type Exports
import type {
UnifiedMarket,
MarketToken,
ProcessedOrderbook,
ArbitrageOpportunity,
EffectivePrices,
Side,
OrderType,
Order,
OrderResult,
LimitOrderParams,
MarketOrderParams,
KLineInterval,
KLineCandle,
DualKLineData,
SpreadDataPoint,
PriceUpdate,
BookUpdate,
OrderbookSnapshot,
WalletProfile,
SellActivityResult,
SmartMoneyWallet,
SmartMoneyTrade,
AutoCopyTradingOptions,
AutoCopyTradingStats,
AutoCopyTradingSubscription,
SplitResult,
MergeResult,
RedeemResult,
ArbitrageMarketConfig,
ArbitrageServiceConfig,
ScanResult,
ClearPositionResult,
DipArbServiceConfig,
DipArbMarketConfig,
DipArbSignalEvent,
DipArbExecutionResult,
DipArbRoundState,
DipArbStats,
} from '@catalyst-team/poly-sdk';
Dependencies
@polymarket/clob-client - Official CLOB trading client
@polymarket/real-time-data-client - Official WebSocket client
ethers@5 - Blockchain interactions
bottleneck - Rate limiting
License
MIT