@catalyst-team/poly-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +0 -0
- package/README.md +803 -0
- package/dist/__tests__/clob-api.test.d.ts +5 -0
- package/dist/__tests__/clob-api.test.d.ts.map +1 -0
- package/dist/__tests__/clob-api.test.js +240 -0
- package/dist/__tests__/clob-api.test.js.map +1 -0
- package/dist/__tests__/integration/bridge-client.integration.test.d.ts +11 -0
- package/dist/__tests__/integration/bridge-client.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/bridge-client.integration.test.js +260 -0
- package/dist/__tests__/integration/bridge-client.integration.test.js.map +1 -0
- package/dist/__tests__/integration/clob-api.integration.test.d.ts +13 -0
- package/dist/__tests__/integration/clob-api.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/clob-api.integration.test.js +170 -0
- package/dist/__tests__/integration/clob-api.integration.test.js.map +1 -0
- package/dist/__tests__/integration/ctf-client.integration.test.d.ts +17 -0
- package/dist/__tests__/integration/ctf-client.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/ctf-client.integration.test.js +234 -0
- package/dist/__tests__/integration/ctf-client.integration.test.js.map +1 -0
- package/dist/__tests__/integration/data-api.integration.test.d.ts +9 -0
- package/dist/__tests__/integration/data-api.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/data-api.integration.test.js +161 -0
- package/dist/__tests__/integration/data-api.integration.test.js.map +1 -0
- package/dist/__tests__/integration/gamma-api.integration.test.d.ts +9 -0
- package/dist/__tests__/integration/gamma-api.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/gamma-api.integration.test.js +170 -0
- package/dist/__tests__/integration/gamma-api.integration.test.js.map +1 -0
- package/dist/__tests__/test-utils.d.ts +92 -0
- package/dist/__tests__/test-utils.d.ts.map +1 -0
- package/dist/__tests__/test-utils.js +143 -0
- package/dist/__tests__/test-utils.js.map +1 -0
- package/dist/clients/bridge-client.d.ts +388 -0
- package/dist/clients/bridge-client.d.ts.map +1 -0
- package/dist/clients/bridge-client.js +587 -0
- package/dist/clients/bridge-client.js.map +1 -0
- package/dist/clients/clob-api.d.ts +318 -0
- package/dist/clients/clob-api.d.ts.map +1 -0
- package/dist/clients/clob-api.js +388 -0
- package/dist/clients/clob-api.js.map +1 -0
- package/dist/clients/ctf-client.d.ts +473 -0
- package/dist/clients/ctf-client.d.ts.map +1 -0
- package/dist/clients/ctf-client.js +915 -0
- package/dist/clients/ctf-client.js.map +1 -0
- package/dist/clients/data-api.d.ts +134 -0
- package/dist/clients/data-api.d.ts.map +1 -0
- package/dist/clients/data-api.js +265 -0
- package/dist/clients/data-api.js.map +1 -0
- package/dist/clients/gamma-api.d.ts +401 -0
- package/dist/clients/gamma-api.d.ts.map +1 -0
- package/dist/clients/gamma-api.js +352 -0
- package/dist/clients/gamma-api.js.map +1 -0
- package/dist/clients/trading-client.d.ts +252 -0
- package/dist/clients/trading-client.d.ts.map +1 -0
- package/dist/clients/trading-client.js +543 -0
- package/dist/clients/trading-client.js.map +1 -0
- package/dist/clients/websocket-manager.d.ts +100 -0
- package/dist/clients/websocket-manager.d.ts.map +1 -0
- package/dist/clients/websocket-manager.js +193 -0
- package/dist/clients/websocket-manager.js.map +1 -0
- package/dist/core/cache-adapter-bridge.d.ts +36 -0
- package/dist/core/cache-adapter-bridge.d.ts.map +1 -0
- package/dist/core/cache-adapter-bridge.js +81 -0
- package/dist/core/cache-adapter-bridge.js.map +1 -0
- package/dist/core/cache.d.ts +40 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +71 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/errors.d.ts +38 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +84 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/rate-limiter.d.ts +31 -0
- package/dist/core/rate-limiter.d.ts.map +1 -0
- package/dist/core/rate-limiter.js +70 -0
- package/dist/core/rate-limiter.js.map +1 -0
- package/dist/core/types.d.ts +314 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +19 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/unified-cache.d.ts +63 -0
- package/dist/core/unified-cache.d.ts.map +1 -0
- package/dist/core/unified-cache.js +114 -0
- package/dist/core/unified-cache.js.map +1 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +258 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/errors.d.ts +33 -0
- package/dist/mcp/errors.d.ts.map +1 -0
- package/dist/mcp/errors.js +86 -0
- package/dist/mcp/errors.js.map +1 -0
- package/dist/mcp/index.d.ts +62 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +173 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +17 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +155 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/guide.d.ts +12 -0
- package/dist/mcp/tools/guide.d.ts.map +1 -0
- package/dist/mcp/tools/guide.js +801 -0
- package/dist/mcp/tools/guide.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +11 -0
- package/dist/mcp/tools/index.d.ts.map +1 -0
- package/dist/mcp/tools/index.js +27 -0
- package/dist/mcp/tools/index.js.map +1 -0
- package/dist/mcp/tools/market.d.ts +11 -0
- package/dist/mcp/tools/market.d.ts.map +1 -0
- package/dist/mcp/tools/market.js +314 -0
- package/dist/mcp/tools/market.js.map +1 -0
- package/dist/mcp/tools/order.d.ts +10 -0
- package/dist/mcp/tools/order.d.ts.map +1 -0
- package/dist/mcp/tools/order.js +258 -0
- package/dist/mcp/tools/order.js.map +1 -0
- package/dist/mcp/tools/trade.d.ts +38 -0
- package/dist/mcp/tools/trade.d.ts.map +1 -0
- package/dist/mcp/tools/trade.js +314 -0
- package/dist/mcp/tools/trade.js.map +1 -0
- package/dist/mcp/tools/trader.d.ts +11 -0
- package/dist/mcp/tools/trader.d.ts.map +1 -0
- package/dist/mcp/tools/trader.js +277 -0
- package/dist/mcp/tools/trader.js.map +1 -0
- package/dist/mcp/tools/wallet.d.ts +274 -0
- package/dist/mcp/tools/wallet.d.ts.map +1 -0
- package/dist/mcp/tools/wallet.js +579 -0
- package/dist/mcp/tools/wallet.js.map +1 -0
- package/dist/mcp/types.d.ts +413 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +5 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/services/authorization-service.d.ts +97 -0
- package/dist/services/authorization-service.d.ts.map +1 -0
- package/dist/services/authorization-service.js +279 -0
- package/dist/services/authorization-service.js.map +1 -0
- package/dist/services/market-service.d.ts +108 -0
- package/dist/services/market-service.d.ts.map +1 -0
- package/dist/services/market-service.js +458 -0
- package/dist/services/market-service.js.map +1 -0
- package/dist/services/realtime-service.d.ts +82 -0
- package/dist/services/realtime-service.d.ts.map +1 -0
- package/dist/services/realtime-service.js +150 -0
- package/dist/services/realtime-service.js.map +1 -0
- package/dist/services/swap-service.d.ts +217 -0
- package/dist/services/swap-service.d.ts.map +1 -0
- package/dist/services/swap-service.js +695 -0
- package/dist/services/swap-service.js.map +1 -0
- package/dist/services/wallet-service.d.ts +94 -0
- package/dist/services/wallet-service.d.ts.map +1 -0
- package/dist/services/wallet-service.js +173 -0
- package/dist/services/wallet-service.js.map +1 -0
- package/dist/utils/price-utils.d.ts +153 -0
- package/dist/utils/price-utils.d.ts.map +1 -0
- package/dist/utils/price-utils.js +236 -0
- package/dist/utils/price-utils.js.map +1 -0
- package/docs/00-design.md +760 -0
- package/docs/01-mcp.md +2041 -0
- package/docs/02-API.md +1148 -0
- package/docs/e2e/01-trader-tools.md +159 -0
- package/docs/e2e/02-market-tools.md +180 -0
- package/docs/e2e/03-order-tools.md +166 -0
- package/docs/e2e/04-wallet-tools.md +224 -0
- package/docs/e2e/05-trading-tools.md +327 -0
- package/docs/e2e/06-integration-scenarios.md +481 -0
- package/docs/e2e/coordinator.md +376 -0
- package/examples/01-basic-usage.ts +68 -0
- package/examples/02-smart-money.ts +95 -0
- package/examples/03-market-analysis.ts +108 -0
- package/examples/04-kline-aggregation.ts +158 -0
- package/examples/05-follow-wallet-strategy.ts +156 -0
- package/examples/06-services-demo.ts +124 -0
- package/examples/07-realtime-websocket.ts +117 -0
- package/examples/08-trading-orders.ts +278 -0
- package/examples/09-rewards-tracking.ts +187 -0
- package/examples/10-ctf-operations.ts +336 -0
- package/examples/11-live-arbitrage-scan.ts +221 -0
- package/examples/12-trending-arb-monitor.ts +406 -0
- package/examples/README.md +179 -0
- package/package.json +62 -0
- package/scripts/README.md +163 -0
- package/scripts/approvals/approve-erc1155.ts +129 -0
- package/scripts/approvals/approve-neg-risk-erc1155.ts +149 -0
- package/scripts/approvals/approve-neg-risk.ts +102 -0
- package/scripts/approvals/check-all-allowances.ts +150 -0
- package/scripts/approvals/check-allowance.ts +129 -0
- package/scripts/approvals/check-ctf-approval.ts +158 -0
- package/scripts/datas/001-report.md +486 -0
- package/scripts/datas/clone-modal-screenshot.png +0 -0
- package/scripts/deposit/deposit-native-usdc.ts +179 -0
- package/scripts/deposit/deposit-usdc.ts +155 -0
- package/scripts/deposit/swap-usdc-to-usdce.ts +375 -0
- package/scripts/research/research-markets.ts +166 -0
- package/scripts/trading/check-orders.ts +50 -0
- package/scripts/trading/sell-nvidia-positions.ts +206 -0
- package/scripts/trading/test-order.ts +172 -0
- package/scripts/truth.md +440 -0
- package/scripts/verify/test-approve-trading.ts +98 -0
- package/scripts/verify/test-provider-fix.ts +43 -0
- package/scripts/verify/test-search-mcp.ts +113 -0
- package/scripts/verify/verify-all-apis.ts +160 -0
- package/scripts/wallet/check-wallet-balances.ts +75 -0
- package/scripts/wallet/test-wallet-operations.ts +191 -0
- package/scripts/wallet/verify-wallet-tools.ts +124 -0
- package/src/__tests__/clob-api.test.ts +301 -0
- package/src/__tests__/integration/bridge-client.integration.test.ts +314 -0
- package/src/__tests__/integration/clob-api.integration.test.ts +218 -0
- package/src/__tests__/integration/ctf-client.integration.test.ts +331 -0
- package/src/__tests__/integration/data-api.integration.test.ts +194 -0
- package/src/__tests__/integration/gamma-api.integration.test.ts +206 -0
- package/src/__tests__/test-utils.ts +170 -0
- package/src/clients/bridge-client.ts +841 -0
- package/src/clients/clob-api.ts +629 -0
- package/src/clients/ctf-client.ts +1216 -0
- package/src/clients/data-api.ts +469 -0
- package/src/clients/gamma-api.ts +597 -0
- package/src/clients/trading-client.ts +749 -0
- package/src/clients/websocket-manager.ts +267 -0
- package/src/core/cache-adapter-bridge.ts +94 -0
- package/src/core/cache.ts +85 -0
- package/src/core/errors.ts +117 -0
- package/src/core/rate-limiter.ts +74 -0
- package/src/core/types.ts +360 -0
- package/src/core/unified-cache.ts +153 -0
- package/src/index.ts +455 -0
- package/src/mcp/README.md +380 -0
- package/src/mcp/errors.ts +124 -0
- package/src/mcp/index.ts +309 -0
- package/src/mcp/server.ts +183 -0
- package/src/mcp/tools/guide.ts +821 -0
- package/src/mcp/tools/index.ts +73 -0
- package/src/mcp/tools/market.ts +363 -0
- package/src/mcp/tools/order.ts +326 -0
- package/src/mcp/tools/trade.ts +417 -0
- package/src/mcp/tools/trader.ts +322 -0
- package/src/mcp/tools/wallet.ts +683 -0
- package/src/mcp/types.ts +472 -0
- package/src/services/authorization-service.ts +357 -0
- package/src/services/market-service.ts +544 -0
- package/src/services/realtime-service.ts +196 -0
- package/src/services/swap-service.ts +896 -0
- package/src/services/wallet-service.ts +259 -0
- package/src/utils/price-utils.ts +307 -0
- package/tsconfig.json +8 -0
- package/vitest.config.ts +19 -0
- package/vitest.integration.config.ts +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,803 @@
|
|
|
1
|
+
# @prediction-router/poly-sdk
|
|
2
|
+
|
|
3
|
+
Unified SDK for Polymarket APIs - Data API, Gamma API, CLOB API, and WebSocket real-time updates.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @prediction-router/poly-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { PolymarketSDK } from '@prediction-router/poly-sdk';
|
|
15
|
+
|
|
16
|
+
const sdk = new PolymarketSDK();
|
|
17
|
+
|
|
18
|
+
// Get market by slug or condition ID
|
|
19
|
+
const market = await sdk.getMarket('will-trump-win-2024');
|
|
20
|
+
console.log(market.tokens.yes.price); // 0.65
|
|
21
|
+
|
|
22
|
+
// Get processed orderbook with analytics
|
|
23
|
+
const orderbook = await sdk.getOrderbook(market.conditionId);
|
|
24
|
+
console.log(orderbook.summary.longArbProfit); // Arbitrage opportunity
|
|
25
|
+
|
|
26
|
+
// Detect arbitrage
|
|
27
|
+
const arb = await sdk.detectArbitrage(market.conditionId);
|
|
28
|
+
if (arb) {
|
|
29
|
+
console.log(`${arb.type} arb: ${arb.profit * 100}% profit`);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Architecture
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
37
|
+
│ PolymarketSDK │
|
|
38
|
+
├─────────────────────────────────────────────────────────────┤
|
|
39
|
+
│ Layer 3: Services │
|
|
40
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
|
|
41
|
+
│ │WalletService│ │MarketService│ │ RealtimeService │ │
|
|
42
|
+
│ │ - profiles │ │ - K-Lines │ │ - subscriptions │ │
|
|
43
|
+
│ │ - sell det. │ │ - signals │ │ - price cache │ │
|
|
44
|
+
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
|
|
45
|
+
├─────────────────────────────────────────────────────────────┤
|
|
46
|
+
│ Layer 2: API Clients │
|
|
47
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │
|
|
48
|
+
│ │ DataAPI │ │ GammaAPI │ │ CLOB API │ │ WebSocket │ │
|
|
49
|
+
│ │positions │ │ markets │ │ orderbook│ │ real-time │ │
|
|
50
|
+
│ │ trades │ │ events │ │ trading │ │ prices │ │
|
|
51
|
+
│ └──────────┘ └──────────┘ └──────────┘ └─────────────┘ │
|
|
52
|
+
├─────────────────────────────────────────────────────────────┤
|
|
53
|
+
│ Layer 1: Infrastructure │
|
|
54
|
+
│ ┌────────────┐ ┌─────────┐ ┌──────────┐ ┌────────────┐ │
|
|
55
|
+
│ │RateLimiter │ │ Cache │ │ Errors │ │ Types │ │
|
|
56
|
+
│ │per-API │ │TTL-based│ │ retry │ │ unified │ │
|
|
57
|
+
│ └────────────┘ └─────────┘ └──────────┘ └────────────┘ │
|
|
58
|
+
└─────────────────────────────────────────────────────────────┘
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## API Clients
|
|
62
|
+
|
|
63
|
+
### DataApiClient - Positions, Trades, Leaderboard
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// Get wallet positions
|
|
67
|
+
const positions = await sdk.dataApi.getPositions('0x...');
|
|
68
|
+
|
|
69
|
+
// Get recent trades
|
|
70
|
+
const trades = await sdk.dataApi.getTrades('0x...');
|
|
71
|
+
|
|
72
|
+
// Get leaderboard
|
|
73
|
+
const leaderboard = await sdk.dataApi.getLeaderboard();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### GammaApiClient - Markets, Events
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// Search markets
|
|
80
|
+
const markets = await sdk.gammaApi.searchMarkets({ query: 'bitcoin' });
|
|
81
|
+
|
|
82
|
+
// Get trending markets
|
|
83
|
+
const trending = await sdk.gammaApi.getTrendingMarkets(10);
|
|
84
|
+
|
|
85
|
+
// Get events
|
|
86
|
+
const events = await sdk.gammaApi.getEvents({ limit: 20 });
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### ClobApiClient - Orderbook, Trading
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// Get orderbook
|
|
93
|
+
const book = await sdk.clobApi.getOrderbook(conditionId);
|
|
94
|
+
|
|
95
|
+
// Get processed orderbook with analytics
|
|
96
|
+
const processed = await sdk.clobApi.getProcessedOrderbook(conditionId);
|
|
97
|
+
console.log(processed.summary.longArbProfit);
|
|
98
|
+
console.log(processed.summary.shortArbProfit);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Services
|
|
102
|
+
|
|
103
|
+
### WalletService - Smart Money Analysis
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// Get top traders
|
|
107
|
+
const traders = await sdk.wallets.getTopTraders(10);
|
|
108
|
+
|
|
109
|
+
// Get wallet profile with smart score
|
|
110
|
+
const profile = await sdk.wallets.getWalletProfile('0x...');
|
|
111
|
+
console.log(profile.smartScore); // 0-100
|
|
112
|
+
|
|
113
|
+
// Detect sell activity (for follow-wallet strategy)
|
|
114
|
+
const sellResult = await sdk.wallets.detectSellActivity(
|
|
115
|
+
'0x...',
|
|
116
|
+
conditionId,
|
|
117
|
+
Date.now() - 24 * 60 * 60 * 1000
|
|
118
|
+
);
|
|
119
|
+
if (sellResult.isSelling) {
|
|
120
|
+
console.log(`Sold ${sellResult.percentageSold}%`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Track group sell ratio
|
|
124
|
+
const groupSell = await sdk.wallets.trackGroupSellRatio(
|
|
125
|
+
['0x...', '0x...'],
|
|
126
|
+
conditionId,
|
|
127
|
+
peakValue,
|
|
128
|
+
sinceTimestamp
|
|
129
|
+
);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### MarketService - K-Lines and Signals
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// Get K-Line candles
|
|
136
|
+
const klines = await sdk.markets.getKLines(conditionId, '1h', { limit: 100 });
|
|
137
|
+
|
|
138
|
+
// Get dual K-Lines (YES + NO) with spread analysis
|
|
139
|
+
const dual = await sdk.markets.getDualKLines(conditionId, '1h');
|
|
140
|
+
console.log(dual.yes); // YES token candles
|
|
141
|
+
console.log(dual.no); // NO token candles
|
|
142
|
+
|
|
143
|
+
// Historical spread (from trade close prices) - for backtesting
|
|
144
|
+
console.log(dual.spreadAnalysis); // SpreadDataPoint[]
|
|
145
|
+
for (const point of dual.spreadAnalysis) {
|
|
146
|
+
console.log(`${point.timestamp}: priceSum=${point.priceSum}, spread=${point.priceSpread}`);
|
|
147
|
+
if (point.arbOpportunity) {
|
|
148
|
+
console.log(` Historical ${point.arbOpportunity} signal`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Real-time spread (from orderbook) - for live trading
|
|
153
|
+
if (dual.realtimeSpread) {
|
|
154
|
+
const rt = dual.realtimeSpread;
|
|
155
|
+
console.log(`Ask Sum: ${rt.askSum} (spread: ${rt.askSpread})`);
|
|
156
|
+
console.log(`Bid Sum: ${rt.bidSum} (spread: ${rt.bidSpread})`);
|
|
157
|
+
if (rt.arbOpportunity) {
|
|
158
|
+
console.log(`🎯 ${rt.arbOpportunity} ARB: ${rt.arbProfitPercent.toFixed(2)}% profit`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Quick real-time spread check (without K-lines)
|
|
163
|
+
const spread = await sdk.markets.getRealtimeSpread(conditionId);
|
|
164
|
+
if (spread.longArbProfit > 0.005) {
|
|
165
|
+
console.log(`Long arb: buy YES@${spread.yesAsk} + NO@${spread.noAsk}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Detect market signals
|
|
169
|
+
const signals = await sdk.markets.detectMarketSignals(conditionId);
|
|
170
|
+
for (const signal of signals) {
|
|
171
|
+
console.log(`${signal.type}: ${signal.severity}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Detect arbitrage
|
|
175
|
+
const arb = await sdk.markets.detectArbitrage(conditionId);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### Understanding Polymarket Orderbook & Arbitrage
|
|
179
|
+
|
|
180
|
+
⚠️ **重要:Polymarket 订单簿的镜像特性**
|
|
181
|
+
|
|
182
|
+
Polymarket 的订单簿有一个关键特性容易被忽略:
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
买 YES @ P = 卖 NO @ (1-P)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
这意味着**同一订单会在两个订单簿中出现**。例如,一个 "Sell NO @ 0.50" 订单
|
|
189
|
+
会同时作为 "Buy YES @ 0.50" 出现在 YES 订单簿中。
|
|
190
|
+
|
|
191
|
+
**常见误解:**
|
|
192
|
+
```typescript
|
|
193
|
+
// ❌ 错误: 简单相加会重复计算镜像订单
|
|
194
|
+
const askSum = YES.ask + NO.ask; // ≈ 1.998-1.999,而非 ≈ 1.0
|
|
195
|
+
const bidSum = YES.bid + NO.bid; // ≈ 0.001-0.002,而非 ≈ 1.0
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**正确做法:使用有效价格 (Effective Prices)**
|
|
199
|
+
```typescript
|
|
200
|
+
import { getEffectivePrices, checkArbitrage } from '@prediction-router/poly-sdk';
|
|
201
|
+
|
|
202
|
+
// 计算考虑镜像后的最优价格
|
|
203
|
+
const effective = getEffectivePrices(yesAsk, yesBid, noAsk, noBid);
|
|
204
|
+
|
|
205
|
+
// effective.effectiveBuyYes = min(YES.ask, 1 - NO.bid)
|
|
206
|
+
// effective.effectiveBuyNo = min(NO.ask, 1 - YES.bid)
|
|
207
|
+
// effective.effectiveSellYes = max(YES.bid, 1 - NO.ask)
|
|
208
|
+
// effective.effectiveSellNo = max(NO.bid, 1 - YES.ask)
|
|
209
|
+
|
|
210
|
+
// 使用有效价格检测套利
|
|
211
|
+
const arb = checkArbitrage(yesAsk, noAsk, yesBid, noBid);
|
|
212
|
+
if (arb) {
|
|
213
|
+
console.log(`${arb.type} arb: ${(arb.profit * 100).toFixed(2)}% profit`);
|
|
214
|
+
console.log(arb.description);
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
详细文档见: [docs/01-polymarket-orderbook-arbitrage.md](docs/01-polymarket-orderbook-arbitrage.md)
|
|
219
|
+
|
|
220
|
+
#### Spread Analysis - Two Approaches
|
|
221
|
+
|
|
222
|
+
我们提供两种 Spread 分析方式,核心区别如下:
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
226
|
+
│ spreadAnalysis (历史分析) │ realtimeSpread (实时分析) │
|
|
227
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
228
|
+
│ 数据源: 成交记录的收盘价 │ 数据源: 订单簿的最优 bid/ask │
|
|
229
|
+
│ YES_close + NO_close │ 使用有效价格 (考虑镜像订单) │
|
|
230
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
231
|
+
│ ✅ 可构建历史曲线 │ ❌ 无法构建历史曲线* │
|
|
232
|
+
│ ✅ Polymarket 保留成交历史 │ ❌ Polymarket 不保留盘口历史 │
|
|
233
|
+
│ ✅ 适合回测、模式识别 │ ✅ 适合实盘交易、套利执行 │
|
|
234
|
+
│ ⚠️ 套利信号仅供参考 │ ✅ 套利利润计算准确 │
|
|
235
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
236
|
+
|
|
237
|
+
* 如需构建实时 Spread 的历史曲线,必须自行存储盘口快照数据
|
|
238
|
+
参考: apps/api/src/services/spread-sampler.ts
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**核心区别:**
|
|
242
|
+
|
|
243
|
+
1. **成交价 vs 盘口价**
|
|
244
|
+
- 成交价 (close): 过去某时刻实际成交的价格
|
|
245
|
+
- 盘口价 (bid/ask): 当前市场上的最优挂单价格
|
|
246
|
+
- 例: YES 最后成交 0.52,但当前 bid=0.50, ask=0.54
|
|
247
|
+
|
|
248
|
+
2. **为什么套利计算需要有效价格?**
|
|
249
|
+
- 同一订单在 YES 和 NO 订单簿中都有镜像
|
|
250
|
+
- 简单的 `YES.ask + NO.ask` 会重复计算
|
|
251
|
+
- 必须用 `min(YES.ask, 1-NO.bid)` 等公式消除重复
|
|
252
|
+
|
|
253
|
+
3. **为什么历史分析只能用成交价?**
|
|
254
|
+
- Polymarket CLOB API 不保存历史盘口数据
|
|
255
|
+
- 只有成交记录 (trades) 有历史
|
|
256
|
+
- 除非你自己运行 spread-sampler 持续采样盘口
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
// SpreadDataPoint (历史分析 - 可构建曲线)
|
|
260
|
+
interface SpreadDataPoint {
|
|
261
|
+
timestamp: number;
|
|
262
|
+
yesPrice: number; // YES 收盘价 (来自成交记录)
|
|
263
|
+
noPrice: number; // NO 收盘价
|
|
264
|
+
priceSum: number; // YES + NO
|
|
265
|
+
priceSpread: number; // priceSum - 1 (偏离均衡程度)
|
|
266
|
+
arbOpportunity: 'LONG' | 'SHORT' | ''; // 参考信号
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ProcessedOrderbook.summary (实时分析 - 使用有效价格)
|
|
270
|
+
interface OrderbookSummary {
|
|
271
|
+
// 有效价格 (考虑镜像订单)
|
|
272
|
+
effectivePrices: {
|
|
273
|
+
effectiveBuyYes: number; // min(YES.ask, 1 - NO.bid)
|
|
274
|
+
effectiveBuyNo: number; // min(NO.ask, 1 - YES.bid)
|
|
275
|
+
effectiveSellYes: number; // max(YES.bid, 1 - NO.ask)
|
|
276
|
+
effectiveSellNo: number; // max(NO.bid, 1 - YES.ask)
|
|
277
|
+
};
|
|
278
|
+
// 套利成本/收入
|
|
279
|
+
effectiveLongCost: number; // effectiveBuyYes + effectiveBuyNo
|
|
280
|
+
effectiveShortRevenue: number; // effectiveSellYes + effectiveSellNo
|
|
281
|
+
// 套利利润
|
|
282
|
+
longArbProfit: number; // 1 - effectiveLongCost (> 0 可套利)
|
|
283
|
+
shortArbProfit: number; // effectiveShortRevenue - 1 (> 0 可套利)
|
|
284
|
+
yesSpread: number; // YES.ask - YES.bid (市场效率指标)
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### TradingClient - Order Execution
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { TradingClient, RateLimiter } from '@prediction-router/poly-sdk';
|
|
292
|
+
|
|
293
|
+
const rateLimiter = new RateLimiter();
|
|
294
|
+
const tradingClient = new TradingClient(rateLimiter, {
|
|
295
|
+
privateKey: process.env.POLYMARKET_PRIVATE_KEY!,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
await tradingClient.initialize();
|
|
299
|
+
console.log(`Wallet: ${tradingClient.getAddress()}`);
|
|
300
|
+
|
|
301
|
+
// GTC Limit Order (stays until filled or cancelled)
|
|
302
|
+
const order = await tradingClient.createOrder({
|
|
303
|
+
tokenId: yesTokenId,
|
|
304
|
+
side: 'BUY',
|
|
305
|
+
price: 0.45,
|
|
306
|
+
size: 10,
|
|
307
|
+
orderType: 'GTC',
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// GTD Limit Order (expires at timestamp)
|
|
311
|
+
const gtdOrder = await tradingClient.createOrder({
|
|
312
|
+
tokenId: yesTokenId,
|
|
313
|
+
side: 'BUY',
|
|
314
|
+
price: 0.45,
|
|
315
|
+
size: 10,
|
|
316
|
+
orderType: 'GTD',
|
|
317
|
+
expiration: Math.floor(Date.now() / 1000) + 3600, // 1 hour
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// FOK Market Order (fill entirely or cancel)
|
|
321
|
+
const marketOrder = await tradingClient.createMarketOrder({
|
|
322
|
+
tokenId: yesTokenId,
|
|
323
|
+
side: 'BUY',
|
|
324
|
+
amount: 10, // $10 USDC
|
|
325
|
+
orderType: 'FOK',
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// FAK Market Order (partial fill ok)
|
|
329
|
+
const fakOrder = await tradingClient.createMarketOrder({
|
|
330
|
+
tokenId: yesTokenId,
|
|
331
|
+
side: 'SELL',
|
|
332
|
+
amount: 10, // 10 shares
|
|
333
|
+
orderType: 'FAK',
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// Order management
|
|
337
|
+
const openOrders = await tradingClient.getOpenOrders();
|
|
338
|
+
await tradingClient.cancelOrder(orderId);
|
|
339
|
+
await tradingClient.cancelAllOrders();
|
|
340
|
+
|
|
341
|
+
// Get trade history
|
|
342
|
+
const trades = await tradingClient.getTrades();
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Rewards - Market Making Incentives
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
// Check if your orders are earning rewards
|
|
349
|
+
const isScoring = await tradingClient.isOrderScoring(orderId);
|
|
350
|
+
|
|
351
|
+
// Get markets with active reward programs
|
|
352
|
+
const rewards = await tradingClient.getCurrentRewards();
|
|
353
|
+
for (const reward of rewards) {
|
|
354
|
+
console.log(`${reward.question}`);
|
|
355
|
+
console.log(` Max Spread: ${reward.rewardsMaxSpread}`);
|
|
356
|
+
console.log(` Min Size: ${reward.rewardsMinSize}`);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Get your daily earnings
|
|
360
|
+
const earnings = await tradingClient.getTotalEarningsForDay('2024-12-07');
|
|
361
|
+
console.log(`Total earned: $${earnings.totalEarnings}`);
|
|
362
|
+
|
|
363
|
+
// Check balance and allowance
|
|
364
|
+
const balance = await tradingClient.getBalanceAllowance('COLLATERAL');
|
|
365
|
+
console.log(`USDC Balance: ${balance.balance}`);
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### RealtimeService - WebSocket Subscriptions
|
|
369
|
+
|
|
370
|
+
⚠️ **重要:Orderbook 自动排序**
|
|
371
|
+
|
|
372
|
+
Polymarket CLOB API 返回的 orderbook 顺序与标准预期相反:
|
|
373
|
+
- **bids**: 升序排列 (最低价在前 = 最差价)
|
|
374
|
+
- **asks**: 降序排列 (最高价在前 = 最差价)
|
|
375
|
+
|
|
376
|
+
我们的 SDK **自动规范化** orderbook 数据:
|
|
377
|
+
- **bids**: 降序排列 (最高价在前 = 最佳买价)
|
|
378
|
+
- **asks**: 升序排列 (最低价在前 = 最佳卖价)
|
|
379
|
+
|
|
380
|
+
这意味着你可以安全地使用 `bids[0]` 和 `asks[0]` 获取最优价格:
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
const book = await sdk.clobApi.getOrderbook(conditionId);
|
|
384
|
+
const bestBid = book.bids[0]?.price; // ✅ 最高买价 (最佳 bid)
|
|
385
|
+
const bestAsk = book.asks[0]?.price; // ✅ 最低卖价 (最佳 ask)
|
|
386
|
+
|
|
387
|
+
// WebSocket 更新同样自动排序
|
|
388
|
+
wsManager.on('bookUpdate', (update) => {
|
|
389
|
+
const bestBid = update.bids[0]?.price; // ✅ 已排序
|
|
390
|
+
const bestAsk = update.asks[0]?.price; // ✅ 已排序
|
|
391
|
+
});
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
import { WebSocketManager, RealtimeService } from '@prediction-router/poly-sdk';
|
|
396
|
+
|
|
397
|
+
const wsManager = new WebSocketManager();
|
|
398
|
+
const realtime = new RealtimeService(wsManager);
|
|
399
|
+
|
|
400
|
+
// Subscribe to market updates
|
|
401
|
+
const subscription = await realtime.subscribeMarket(yesTokenId, noTokenId, {
|
|
402
|
+
onPriceUpdate: (update) => {
|
|
403
|
+
console.log(`${update.assetId}: ${update.price}`);
|
|
404
|
+
},
|
|
405
|
+
onBookUpdate: (update) => {
|
|
406
|
+
console.log(`Best bid: ${update.bids[0]?.price}`);
|
|
407
|
+
},
|
|
408
|
+
onLastTrade: (trade) => {
|
|
409
|
+
console.log(`Trade: ${trade.side} ${trade.size} @ ${trade.price}`);
|
|
410
|
+
},
|
|
411
|
+
onPairUpdate: (update) => {
|
|
412
|
+
console.log(`YES + NO = ${update.spread}`);
|
|
413
|
+
if (update.spread < 0.99) console.log('ARB opportunity!');
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// Get cached prices
|
|
418
|
+
const price = realtime.getPrice(yesTokenId);
|
|
419
|
+
|
|
420
|
+
// Cleanup
|
|
421
|
+
await subscription.unsubscribe();
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### CTFClient - On-Chain Token Operations
|
|
425
|
+
|
|
426
|
+
The CTF (Conditional Token Framework) client enables on-chain operations for Polymarket's conditional tokens. This is essential for:
|
|
427
|
+
- **Arbitrage**: Merge tokens when buying YES + NO < $1
|
|
428
|
+
- **Market Making**: Split USDC to create inventory
|
|
429
|
+
- **Redemption**: Claim winnings after market resolution
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
import { CTFClient, CTF_CONTRACT, USDC_CONTRACT } from '@prediction-router/poly-sdk';
|
|
433
|
+
|
|
434
|
+
const ctf = new CTFClient({
|
|
435
|
+
privateKey: process.env.POLYMARKET_PRIVATE_KEY!,
|
|
436
|
+
rpcUrl: 'https://polygon-rpc.com', // optional
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
console.log(`Wallet: ${ctf.getAddress()}`);
|
|
440
|
+
console.log(`USDC Balance: ${await ctf.getUsdcBalance()}`);
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
#### Split: USDC → YES + NO Tokens
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
// Split 100 USDC into 100 YES + 100 NO tokens
|
|
447
|
+
const splitResult = await ctf.split(conditionId, '100');
|
|
448
|
+
console.log(`TX: ${splitResult.txHash}`);
|
|
449
|
+
console.log(`Created ${splitResult.yesTokens} YES + ${splitResult.noTokens} NO`);
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
#### Merge: YES + NO → USDC
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
// Merge 100 YES + 100 NO → 100 USDC (for arbitrage)
|
|
456
|
+
const mergeResult = await ctf.merge(conditionId, '100');
|
|
457
|
+
console.log(`TX: ${mergeResult.txHash}`);
|
|
458
|
+
console.log(`Received ${mergeResult.usdcReceived} USDC`);
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
#### Redeem: Winning Tokens → USDC
|
|
462
|
+
|
|
463
|
+
⚠️ **重要:两种 Redeem 方法**
|
|
464
|
+
|
|
465
|
+
Polymarket 使用自定义的 token ID,与标准 CTF position ID 计算方式不同:
|
|
466
|
+
|
|
467
|
+
| 方法 | 适用场景 | Token ID 来源 |
|
|
468
|
+
|------|----------|---------------|
|
|
469
|
+
| `redeemByTokenIds()` | **Polymarket CLOB 市场** ✅ | CLOB API 返回的 tokenId |
|
|
470
|
+
| `redeem()` | 标准 Gnosis CTF 市场 | `keccak256(collectionId, conditionId, indexSet)` |
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
// ✅ 推荐:Polymarket 市场使用 redeemByTokenIds
|
|
474
|
+
const tokenIds = {
|
|
475
|
+
yesTokenId: '25064375110792967023484002819116042931016336431092144471807003884255851454283',
|
|
476
|
+
noTokenId: '98190367690492181203391990709979106077460946443309150166954079213761598385827',
|
|
477
|
+
};
|
|
478
|
+
const result = await ctf.redeemByTokenIds(conditionId, tokenIds);
|
|
479
|
+
console.log(`Redeemed ${result.tokensRedeemed} ${result.outcome} tokens`);
|
|
480
|
+
console.log(`Received ${result.usdcReceived} USDC`);
|
|
481
|
+
|
|
482
|
+
// ❌ 不要用于 Polymarket:redeem() 使用计算的 position ID
|
|
483
|
+
// const result = await ctf.redeem(conditionId); // 可能找不到余额
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
**为什么 Polymarket token ID 不同?**
|
|
487
|
+
- Polymarket 在 CTF 之上包装了一层 ERC-1155 tokens
|
|
488
|
+
- CLOB API 返回的 `tokenId` (如 `"25064375..."`) 与标准 CTF 计算的 position ID 不同
|
|
489
|
+
- 必须使用 CLOB API 的 token ID 才能正确查询余额和 redeem
|
|
490
|
+
|
|
491
|
+
#### Position Queries
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
// Get token balances
|
|
495
|
+
const balances = await ctf.getPositionBalance(conditionId);
|
|
496
|
+
console.log(`YES: ${balances.yesBalance}, NO: ${balances.noBalance}`);
|
|
497
|
+
|
|
498
|
+
// Check if market is resolved
|
|
499
|
+
const resolution = await ctf.getMarketResolution(conditionId);
|
|
500
|
+
if (resolution.isResolved) {
|
|
501
|
+
console.log(`Winner: ${resolution.winningOutcome}`);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Gas estimation
|
|
505
|
+
const splitGas = await ctf.estimateSplitGas(conditionId, '100');
|
|
506
|
+
const mergeGas = await ctf.estimateMergeGas(conditionId, '100');
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
#### Arbitrage Flow
|
|
510
|
+
|
|
511
|
+
⚠️ **注意:必须使用有效价格计算套利,不能简单相加 ask/bid**
|
|
512
|
+
|
|
513
|
+
由于 Polymarket 的镜像订单特性(见上文),正确的套利计算方式如下:
|
|
514
|
+
|
|
515
|
+
```
|
|
516
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
517
|
+
│ LONG ARB (effectiveLongCost < $1): │
|
|
518
|
+
│ 有效买入成本: │
|
|
519
|
+
│ effectiveBuyYes = min(YES.ask, 1 - NO.bid) │
|
|
520
|
+
│ effectiveBuyNo = min(NO.ask, 1 - YES.bid) │
|
|
521
|
+
│ 操作: │
|
|
522
|
+
│ 1. 用有效价格买入 YES + NO │
|
|
523
|
+
│ 2. CTF Merge → $1 USDC │
|
|
524
|
+
│ 3. Profit = 1 - effectiveLongCost │
|
|
525
|
+
├─────────────────────────────────────────────────────────────┤
|
|
526
|
+
│ SHORT ARB (effectiveShortRevenue > $1): │
|
|
527
|
+
│ 有效卖出收入: │
|
|
528
|
+
│ effectiveSellYes = max(YES.bid, 1 - NO.ask) │
|
|
529
|
+
│ effectiveSellNo = max(NO.bid, 1 - YES.ask) │
|
|
530
|
+
│ 操作: │
|
|
531
|
+
│ 1. CTF Split $1 → 1 YES + 1 NO │
|
|
532
|
+
│ 2. 用有效价格卖出 YES + NO │
|
|
533
|
+
│ 3. Profit = effectiveShortRevenue - 1 │
|
|
534
|
+
└─────────────────────────────────────────────────────────────┘
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
import { checkArbitrage, getEffectivePrices } from '@prediction-router/poly-sdk';
|
|
539
|
+
|
|
540
|
+
// checkArbitrage 内部使用有效价格计算
|
|
541
|
+
const arb = checkArbitrage(yesAsk, noAsk, yesBid, noBid);
|
|
542
|
+
if (arb?.type === 'long') {
|
|
543
|
+
console.log(arb.description); // "Buy YES @ 0.48 + NO @ 0.50, Merge for $1"
|
|
544
|
+
// Buy both tokens at effective prices, then merge
|
|
545
|
+
await tradingClient.createMarketOrder({ tokenId: yesTokenId, side: 'BUY', amount: 100 });
|
|
546
|
+
await tradingClient.createMarketOrder({ tokenId: noTokenId, side: 'BUY', amount: 100 });
|
|
547
|
+
await ctf.merge(conditionId, '100');
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### ArbitrageService - Automated Arbitrage
|
|
552
|
+
|
|
553
|
+
The ArbitrageService combines TradingClient and CTFClient for automated arbitrage detection and execution.
|
|
554
|
+
|
|
555
|
+
**内部使用有效价格计算**,自动处理 Polymarket 的镜像订单特性。
|
|
556
|
+
|
|
557
|
+
详细的套利计算原理见: [docs/01-polymarket-orderbook-arbitrage.md](docs/01-polymarket-orderbook-arbitrage.md)
|
|
558
|
+
|
|
559
|
+
```typescript
|
|
560
|
+
import { ArbitrageService, TradingClient, CTFClient, RateLimiter } from '@prediction-router/poly-sdk';
|
|
561
|
+
|
|
562
|
+
const rateLimiter = new RateLimiter();
|
|
563
|
+
const tradingClient = new TradingClient(rateLimiter, { privateKey: '...' });
|
|
564
|
+
const ctfClient = new CTFClient({ privateKey: '...' });
|
|
565
|
+
const sdk = new PolymarketSDK();
|
|
566
|
+
|
|
567
|
+
const arbService = new ArbitrageService(tradingClient, ctfClient, sdk.clobApi, {
|
|
568
|
+
minProfitThreshold: 0.005, // 0.5% minimum (based on effective prices)
|
|
569
|
+
maxGasCost: 0.10, // $0.10 max gas
|
|
570
|
+
dryRun: true, // Simulation mode
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// Detect opportunity (uses effective prices internally)
|
|
574
|
+
const opportunity = await arbService.detectOpportunity(conditionId);
|
|
575
|
+
if (opportunity) {
|
|
576
|
+
console.log(`${opportunity.type} arb: ${opportunity.profitPercent.toFixed(2)}%`);
|
|
577
|
+
console.log(`Effective cost: ${opportunity.effectiveCost}`);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Scan multiple markets
|
|
581
|
+
const opportunities = await arbService.scanMarkets(conditionIds);
|
|
582
|
+
|
|
583
|
+
// Execute (or simulate)
|
|
584
|
+
const result = await arbService.execute({
|
|
585
|
+
conditionId,
|
|
586
|
+
amount: 100, // $100 USDC
|
|
587
|
+
});
|
|
588
|
+
console.log(`Profit: $${result.netProfit.toFixed(4)}`);
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
## Price Utilities
|
|
592
|
+
|
|
593
|
+
```typescript
|
|
594
|
+
import {
|
|
595
|
+
roundPrice,
|
|
596
|
+
validatePrice,
|
|
597
|
+
calculateBuyAmount,
|
|
598
|
+
getEffectivePrices, // For Polymarket mirror orderbook
|
|
599
|
+
checkArbitrage,
|
|
600
|
+
formatUSDC,
|
|
601
|
+
calculatePnL,
|
|
602
|
+
type TickSize,
|
|
603
|
+
} from '@prediction-router/poly-sdk';
|
|
604
|
+
|
|
605
|
+
// Round price to tick size
|
|
606
|
+
const tickSize: TickSize = '0.01';
|
|
607
|
+
roundPrice(0.523, tickSize, 'floor'); // 0.52
|
|
608
|
+
roundPrice(0.523, tickSize, 'ceil'); // 0.53
|
|
609
|
+
|
|
610
|
+
// Validate price
|
|
611
|
+
const validation = validatePrice(0.525, tickSize);
|
|
612
|
+
if (!validation.valid) {
|
|
613
|
+
console.log(validation.error);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Calculate order cost
|
|
617
|
+
const cost = calculateBuyAmount(0.52, 100); // $52
|
|
618
|
+
console.log(formatUSDC(cost)); // "$52.00"
|
|
619
|
+
|
|
620
|
+
// Get effective prices (considering Polymarket mirror orders)
|
|
621
|
+
const effective = getEffectivePrices(yesAsk, yesBid, noAsk, noBid);
|
|
622
|
+
console.log(`Effective buy YES: ${effective.effectiveBuyYes}`); // min(YES.ask, 1 - NO.bid)
|
|
623
|
+
console.log(`Effective buy NO: ${effective.effectiveBuyNo}`); // min(NO.ask, 1 - YES.bid)
|
|
624
|
+
|
|
625
|
+
// Check for arbitrage (uses effective prices internally)
|
|
626
|
+
const arb = checkArbitrage(
|
|
627
|
+
yesAsk, noAsk, // Ask prices
|
|
628
|
+
yesBid, noBid // Bid prices
|
|
629
|
+
);
|
|
630
|
+
if (arb) {
|
|
631
|
+
console.log(`${arb.type} arb: ${(arb.profit * 100).toFixed(2)}% profit`);
|
|
632
|
+
console.log(arb.description); // "Buy YES @ 0.48 + NO @ 0.50, Merge for $1"
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Calculate PnL
|
|
636
|
+
const pnl = calculatePnL(0.40, 0.55, 100, 'long');
|
|
637
|
+
console.log(`PnL: ${formatUSDC(pnl.pnl)} (${pnl.pnlPercent.toFixed(1)}%)`);
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
## K-Line Intervals
|
|
641
|
+
|
|
642
|
+
Supported intervals: `30s`, `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `12h`, `1d`
|
|
643
|
+
|
|
644
|
+
```typescript
|
|
645
|
+
import type { KLineInterval } from '@prediction-router/poly-sdk';
|
|
646
|
+
|
|
647
|
+
const interval: KLineInterval = '1h';
|
|
648
|
+
const candles = await sdk.markets.getKLines(conditionId, interval);
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
## Types
|
|
652
|
+
|
|
653
|
+
```typescript
|
|
654
|
+
import type {
|
|
655
|
+
// Core
|
|
656
|
+
UnifiedMarket,
|
|
657
|
+
PriceUpdate,
|
|
658
|
+
BookUpdate,
|
|
659
|
+
ProcessedOrderbook,
|
|
660
|
+
ArbitrageOpportunity,
|
|
661
|
+
EffectivePrices, // Effective prices for Polymarket mirror orderbook
|
|
662
|
+
|
|
663
|
+
// K-Lines & Spread
|
|
664
|
+
KLineInterval,
|
|
665
|
+
KLineCandle,
|
|
666
|
+
DualKLineData,
|
|
667
|
+
SpreadDataPoint, // Historical spread (trade prices)
|
|
668
|
+
|
|
669
|
+
// Wallet
|
|
670
|
+
WalletProfile,
|
|
671
|
+
SellActivityResult,
|
|
672
|
+
|
|
673
|
+
// Trading
|
|
674
|
+
Side,
|
|
675
|
+
OrderType,
|
|
676
|
+
OrderParams,
|
|
677
|
+
MarketOrderParams,
|
|
678
|
+
Order,
|
|
679
|
+
OrderResult,
|
|
680
|
+
TradeInfo,
|
|
681
|
+
|
|
682
|
+
// Rewards
|
|
683
|
+
UserEarning,
|
|
684
|
+
MarketReward,
|
|
685
|
+
|
|
686
|
+
// CTF
|
|
687
|
+
CTFConfig,
|
|
688
|
+
SplitResult,
|
|
689
|
+
MergeResult,
|
|
690
|
+
RedeemResult,
|
|
691
|
+
PositionBalance,
|
|
692
|
+
MarketResolution,
|
|
693
|
+
|
|
694
|
+
// Arbitrage
|
|
695
|
+
ArbitrageConfig,
|
|
696
|
+
ArbitrageOpportunity,
|
|
697
|
+
ArbitrageExecutionParams,
|
|
698
|
+
ArbitrageResult,
|
|
699
|
+
ArbitrageTransaction,
|
|
700
|
+
|
|
701
|
+
// Price Utils
|
|
702
|
+
TickSize,
|
|
703
|
+
|
|
704
|
+
// API types
|
|
705
|
+
Position,
|
|
706
|
+
Trade,
|
|
707
|
+
LeaderboardEntry,
|
|
708
|
+
GammaMarket,
|
|
709
|
+
ClobMarket,
|
|
710
|
+
Orderbook,
|
|
711
|
+
} from '@prediction-router/poly-sdk';
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
## Error Handling
|
|
715
|
+
|
|
716
|
+
```typescript
|
|
717
|
+
import { PolymarketError, ErrorCode, withRetry } from '@prediction-router/poly-sdk';
|
|
718
|
+
|
|
719
|
+
try {
|
|
720
|
+
const market = await sdk.getMarket('invalid-slug');
|
|
721
|
+
} catch (error) {
|
|
722
|
+
if (error instanceof PolymarketError) {
|
|
723
|
+
if (error.code === ErrorCode.MARKET_NOT_FOUND) {
|
|
724
|
+
console.log('Market not found');
|
|
725
|
+
} else if (error.code === ErrorCode.RATE_LIMITED) {
|
|
726
|
+
console.log('Rate limited, retry later');
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Auto-retry with exponential backoff
|
|
732
|
+
const result = await withRetry(() => sdk.getMarket(slug), {
|
|
733
|
+
maxRetries: 3,
|
|
734
|
+
baseDelay: 1000,
|
|
735
|
+
});
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
## Rate Limiting
|
|
739
|
+
|
|
740
|
+
Built-in rate limiting per API type:
|
|
741
|
+
- Data API: 10 req/sec
|
|
742
|
+
- Gamma API: 10 req/sec
|
|
743
|
+
- CLOB API: 5 req/sec
|
|
744
|
+
|
|
745
|
+
```typescript
|
|
746
|
+
import { RateLimiter, ApiType } from '@prediction-router/poly-sdk';
|
|
747
|
+
|
|
748
|
+
// Custom rate limiter
|
|
749
|
+
const limiter = new RateLimiter({
|
|
750
|
+
[ApiType.DATA]: { maxConcurrent: 5, minTime: 200 },
|
|
751
|
+
[ApiType.GAMMA]: { maxConcurrent: 5, minTime: 200 },
|
|
752
|
+
[ApiType.CLOB]: { maxConcurrent: 2, minTime: 500 },
|
|
753
|
+
});
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
## Caching
|
|
757
|
+
|
|
758
|
+
Built-in TTL-based caching:
|
|
759
|
+
|
|
760
|
+
```typescript
|
|
761
|
+
// Clear all cache
|
|
762
|
+
sdk.clearCache();
|
|
763
|
+
|
|
764
|
+
// Invalidate specific market
|
|
765
|
+
sdk.invalidateMarketCache(conditionId);
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
## Examples
|
|
769
|
+
|
|
770
|
+
| Example | Description | Source |
|
|
771
|
+
|---------|-------------|--------|
|
|
772
|
+
| [Basic Usage](examples/01-basic-usage.ts) | Get markets, orderbooks, detect arbitrage | `pnpm example:basic` |
|
|
773
|
+
| [Smart Money](examples/02-smart-money.ts) | Top traders, wallet profiles, smart scores | `pnpm example:smart-money` |
|
|
774
|
+
| [Market Analysis](examples/03-market-analysis.ts) | Market signals, volume analysis | `pnpm example:market-analysis` |
|
|
775
|
+
| [K-Line Aggregation](examples/04-kline-aggregation.ts) | Build OHLCV candles from trades | `pnpm example:kline` |
|
|
776
|
+
| [Follow Wallet](examples/05-follow-wallet-strategy.ts) | Track smart money positions, detect exits | `pnpm example:follow-wallet` |
|
|
777
|
+
| [Services Demo](examples/06-services-demo.ts) | All SDK services in action | `pnpm example:services` |
|
|
778
|
+
| [Realtime WebSocket](examples/07-realtime-websocket.ts) | Live price feeds, orderbook updates | `pnpm example:realtime` |
|
|
779
|
+
| [Trading Orders](examples/08-trading-orders.ts) | GTC, GTD, FOK, FAK order types | `pnpm example:trading` |
|
|
780
|
+
| [Rewards Tracking](examples/09-rewards-tracking.ts) | Market maker incentives, earnings | `pnpm example:rewards` |
|
|
781
|
+
| [CTF Operations](examples/10-ctf-operations.ts) | Split, merge, redeem tokens | `pnpm example:ctf` |
|
|
782
|
+
| [Arbitrage Service](examples/11-arbitrage-service.ts) | Detect and execute arbitrage | `pnpm example:arbitrage` |
|
|
783
|
+
| [Live Arbitrage Scan](examples/12-live-arbitrage-scan.ts) | Scan real markets for opportunities | `pnpm example:live-arb` |
|
|
784
|
+
| [Trending Arb Monitor](examples/13-trending-arb-monitor.ts) | Real-time trending markets monitor | `pnpm example:trending-arb` |
|
|
785
|
+
|
|
786
|
+
Run any example:
|
|
787
|
+
|
|
788
|
+
```bash
|
|
789
|
+
pnpm example:basic
|
|
790
|
+
pnpm example:smart-money
|
|
791
|
+
pnpm example:trading
|
|
792
|
+
# etc.
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
## Dependencies
|
|
796
|
+
|
|
797
|
+
- `@nevuamarkets/poly-websockets` - WebSocket client
|
|
798
|
+
- `bottleneck` - Rate limiting
|
|
799
|
+
- `ethers` - Blockchain interactions (for CTFClient)
|
|
800
|
+
|
|
801
|
+
## License
|
|
802
|
+
|
|
803
|
+
Private
|