@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.
Files changed (244) hide show
  1. package/.env +0 -0
  2. package/README.md +803 -0
  3. package/dist/__tests__/clob-api.test.d.ts +5 -0
  4. package/dist/__tests__/clob-api.test.d.ts.map +1 -0
  5. package/dist/__tests__/clob-api.test.js +240 -0
  6. package/dist/__tests__/clob-api.test.js.map +1 -0
  7. package/dist/__tests__/integration/bridge-client.integration.test.d.ts +11 -0
  8. package/dist/__tests__/integration/bridge-client.integration.test.d.ts.map +1 -0
  9. package/dist/__tests__/integration/bridge-client.integration.test.js +260 -0
  10. package/dist/__tests__/integration/bridge-client.integration.test.js.map +1 -0
  11. package/dist/__tests__/integration/clob-api.integration.test.d.ts +13 -0
  12. package/dist/__tests__/integration/clob-api.integration.test.d.ts.map +1 -0
  13. package/dist/__tests__/integration/clob-api.integration.test.js +170 -0
  14. package/dist/__tests__/integration/clob-api.integration.test.js.map +1 -0
  15. package/dist/__tests__/integration/ctf-client.integration.test.d.ts +17 -0
  16. package/dist/__tests__/integration/ctf-client.integration.test.d.ts.map +1 -0
  17. package/dist/__tests__/integration/ctf-client.integration.test.js +234 -0
  18. package/dist/__tests__/integration/ctf-client.integration.test.js.map +1 -0
  19. package/dist/__tests__/integration/data-api.integration.test.d.ts +9 -0
  20. package/dist/__tests__/integration/data-api.integration.test.d.ts.map +1 -0
  21. package/dist/__tests__/integration/data-api.integration.test.js +161 -0
  22. package/dist/__tests__/integration/data-api.integration.test.js.map +1 -0
  23. package/dist/__tests__/integration/gamma-api.integration.test.d.ts +9 -0
  24. package/dist/__tests__/integration/gamma-api.integration.test.d.ts.map +1 -0
  25. package/dist/__tests__/integration/gamma-api.integration.test.js +170 -0
  26. package/dist/__tests__/integration/gamma-api.integration.test.js.map +1 -0
  27. package/dist/__tests__/test-utils.d.ts +92 -0
  28. package/dist/__tests__/test-utils.d.ts.map +1 -0
  29. package/dist/__tests__/test-utils.js +143 -0
  30. package/dist/__tests__/test-utils.js.map +1 -0
  31. package/dist/clients/bridge-client.d.ts +388 -0
  32. package/dist/clients/bridge-client.d.ts.map +1 -0
  33. package/dist/clients/bridge-client.js +587 -0
  34. package/dist/clients/bridge-client.js.map +1 -0
  35. package/dist/clients/clob-api.d.ts +318 -0
  36. package/dist/clients/clob-api.d.ts.map +1 -0
  37. package/dist/clients/clob-api.js +388 -0
  38. package/dist/clients/clob-api.js.map +1 -0
  39. package/dist/clients/ctf-client.d.ts +473 -0
  40. package/dist/clients/ctf-client.d.ts.map +1 -0
  41. package/dist/clients/ctf-client.js +915 -0
  42. package/dist/clients/ctf-client.js.map +1 -0
  43. package/dist/clients/data-api.d.ts +134 -0
  44. package/dist/clients/data-api.d.ts.map +1 -0
  45. package/dist/clients/data-api.js +265 -0
  46. package/dist/clients/data-api.js.map +1 -0
  47. package/dist/clients/gamma-api.d.ts +401 -0
  48. package/dist/clients/gamma-api.d.ts.map +1 -0
  49. package/dist/clients/gamma-api.js +352 -0
  50. package/dist/clients/gamma-api.js.map +1 -0
  51. package/dist/clients/trading-client.d.ts +252 -0
  52. package/dist/clients/trading-client.d.ts.map +1 -0
  53. package/dist/clients/trading-client.js +543 -0
  54. package/dist/clients/trading-client.js.map +1 -0
  55. package/dist/clients/websocket-manager.d.ts +100 -0
  56. package/dist/clients/websocket-manager.d.ts.map +1 -0
  57. package/dist/clients/websocket-manager.js +193 -0
  58. package/dist/clients/websocket-manager.js.map +1 -0
  59. package/dist/core/cache-adapter-bridge.d.ts +36 -0
  60. package/dist/core/cache-adapter-bridge.d.ts.map +1 -0
  61. package/dist/core/cache-adapter-bridge.js +81 -0
  62. package/dist/core/cache-adapter-bridge.js.map +1 -0
  63. package/dist/core/cache.d.ts +40 -0
  64. package/dist/core/cache.d.ts.map +1 -0
  65. package/dist/core/cache.js +71 -0
  66. package/dist/core/cache.js.map +1 -0
  67. package/dist/core/errors.d.ts +38 -0
  68. package/dist/core/errors.d.ts.map +1 -0
  69. package/dist/core/errors.js +84 -0
  70. package/dist/core/errors.js.map +1 -0
  71. package/dist/core/rate-limiter.d.ts +31 -0
  72. package/dist/core/rate-limiter.d.ts.map +1 -0
  73. package/dist/core/rate-limiter.js +70 -0
  74. package/dist/core/rate-limiter.js.map +1 -0
  75. package/dist/core/types.d.ts +314 -0
  76. package/dist/core/types.d.ts.map +1 -0
  77. package/dist/core/types.js +19 -0
  78. package/dist/core/types.js.map +1 -0
  79. package/dist/core/unified-cache.d.ts +63 -0
  80. package/dist/core/unified-cache.d.ts.map +1 -0
  81. package/dist/core/unified-cache.js +114 -0
  82. package/dist/core/unified-cache.js.map +1 -0
  83. package/dist/index.d.ts +94 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +258 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/mcp/errors.d.ts +33 -0
  88. package/dist/mcp/errors.d.ts.map +1 -0
  89. package/dist/mcp/errors.js +86 -0
  90. package/dist/mcp/errors.js.map +1 -0
  91. package/dist/mcp/index.d.ts +62 -0
  92. package/dist/mcp/index.d.ts.map +1 -0
  93. package/dist/mcp/index.js +173 -0
  94. package/dist/mcp/index.js.map +1 -0
  95. package/dist/mcp/server.d.ts +17 -0
  96. package/dist/mcp/server.d.ts.map +1 -0
  97. package/dist/mcp/server.js +155 -0
  98. package/dist/mcp/server.js.map +1 -0
  99. package/dist/mcp/tools/guide.d.ts +12 -0
  100. package/dist/mcp/tools/guide.d.ts.map +1 -0
  101. package/dist/mcp/tools/guide.js +801 -0
  102. package/dist/mcp/tools/guide.js.map +1 -0
  103. package/dist/mcp/tools/index.d.ts +11 -0
  104. package/dist/mcp/tools/index.d.ts.map +1 -0
  105. package/dist/mcp/tools/index.js +27 -0
  106. package/dist/mcp/tools/index.js.map +1 -0
  107. package/dist/mcp/tools/market.d.ts +11 -0
  108. package/dist/mcp/tools/market.d.ts.map +1 -0
  109. package/dist/mcp/tools/market.js +314 -0
  110. package/dist/mcp/tools/market.js.map +1 -0
  111. package/dist/mcp/tools/order.d.ts +10 -0
  112. package/dist/mcp/tools/order.d.ts.map +1 -0
  113. package/dist/mcp/tools/order.js +258 -0
  114. package/dist/mcp/tools/order.js.map +1 -0
  115. package/dist/mcp/tools/trade.d.ts +38 -0
  116. package/dist/mcp/tools/trade.d.ts.map +1 -0
  117. package/dist/mcp/tools/trade.js +314 -0
  118. package/dist/mcp/tools/trade.js.map +1 -0
  119. package/dist/mcp/tools/trader.d.ts +11 -0
  120. package/dist/mcp/tools/trader.d.ts.map +1 -0
  121. package/dist/mcp/tools/trader.js +277 -0
  122. package/dist/mcp/tools/trader.js.map +1 -0
  123. package/dist/mcp/tools/wallet.d.ts +274 -0
  124. package/dist/mcp/tools/wallet.d.ts.map +1 -0
  125. package/dist/mcp/tools/wallet.js +579 -0
  126. package/dist/mcp/tools/wallet.js.map +1 -0
  127. package/dist/mcp/types.d.ts +413 -0
  128. package/dist/mcp/types.d.ts.map +1 -0
  129. package/dist/mcp/types.js +5 -0
  130. package/dist/mcp/types.js.map +1 -0
  131. package/dist/services/authorization-service.d.ts +97 -0
  132. package/dist/services/authorization-service.d.ts.map +1 -0
  133. package/dist/services/authorization-service.js +279 -0
  134. package/dist/services/authorization-service.js.map +1 -0
  135. package/dist/services/market-service.d.ts +108 -0
  136. package/dist/services/market-service.d.ts.map +1 -0
  137. package/dist/services/market-service.js +458 -0
  138. package/dist/services/market-service.js.map +1 -0
  139. package/dist/services/realtime-service.d.ts +82 -0
  140. package/dist/services/realtime-service.d.ts.map +1 -0
  141. package/dist/services/realtime-service.js +150 -0
  142. package/dist/services/realtime-service.js.map +1 -0
  143. package/dist/services/swap-service.d.ts +217 -0
  144. package/dist/services/swap-service.d.ts.map +1 -0
  145. package/dist/services/swap-service.js +695 -0
  146. package/dist/services/swap-service.js.map +1 -0
  147. package/dist/services/wallet-service.d.ts +94 -0
  148. package/dist/services/wallet-service.d.ts.map +1 -0
  149. package/dist/services/wallet-service.js +173 -0
  150. package/dist/services/wallet-service.js.map +1 -0
  151. package/dist/utils/price-utils.d.ts +153 -0
  152. package/dist/utils/price-utils.d.ts.map +1 -0
  153. package/dist/utils/price-utils.js +236 -0
  154. package/dist/utils/price-utils.js.map +1 -0
  155. package/docs/00-design.md +760 -0
  156. package/docs/01-mcp.md +2041 -0
  157. package/docs/02-API.md +1148 -0
  158. package/docs/e2e/01-trader-tools.md +159 -0
  159. package/docs/e2e/02-market-tools.md +180 -0
  160. package/docs/e2e/03-order-tools.md +166 -0
  161. package/docs/e2e/04-wallet-tools.md +224 -0
  162. package/docs/e2e/05-trading-tools.md +327 -0
  163. package/docs/e2e/06-integration-scenarios.md +481 -0
  164. package/docs/e2e/coordinator.md +376 -0
  165. package/examples/01-basic-usage.ts +68 -0
  166. package/examples/02-smart-money.ts +95 -0
  167. package/examples/03-market-analysis.ts +108 -0
  168. package/examples/04-kline-aggregation.ts +158 -0
  169. package/examples/05-follow-wallet-strategy.ts +156 -0
  170. package/examples/06-services-demo.ts +124 -0
  171. package/examples/07-realtime-websocket.ts +117 -0
  172. package/examples/08-trading-orders.ts +278 -0
  173. package/examples/09-rewards-tracking.ts +187 -0
  174. package/examples/10-ctf-operations.ts +336 -0
  175. package/examples/11-live-arbitrage-scan.ts +221 -0
  176. package/examples/12-trending-arb-monitor.ts +406 -0
  177. package/examples/README.md +179 -0
  178. package/package.json +62 -0
  179. package/scripts/README.md +163 -0
  180. package/scripts/approvals/approve-erc1155.ts +129 -0
  181. package/scripts/approvals/approve-neg-risk-erc1155.ts +149 -0
  182. package/scripts/approvals/approve-neg-risk.ts +102 -0
  183. package/scripts/approvals/check-all-allowances.ts +150 -0
  184. package/scripts/approvals/check-allowance.ts +129 -0
  185. package/scripts/approvals/check-ctf-approval.ts +158 -0
  186. package/scripts/datas/001-report.md +486 -0
  187. package/scripts/datas/clone-modal-screenshot.png +0 -0
  188. package/scripts/deposit/deposit-native-usdc.ts +179 -0
  189. package/scripts/deposit/deposit-usdc.ts +155 -0
  190. package/scripts/deposit/swap-usdc-to-usdce.ts +375 -0
  191. package/scripts/research/research-markets.ts +166 -0
  192. package/scripts/trading/check-orders.ts +50 -0
  193. package/scripts/trading/sell-nvidia-positions.ts +206 -0
  194. package/scripts/trading/test-order.ts +172 -0
  195. package/scripts/truth.md +440 -0
  196. package/scripts/verify/test-approve-trading.ts +98 -0
  197. package/scripts/verify/test-provider-fix.ts +43 -0
  198. package/scripts/verify/test-search-mcp.ts +113 -0
  199. package/scripts/verify/verify-all-apis.ts +160 -0
  200. package/scripts/wallet/check-wallet-balances.ts +75 -0
  201. package/scripts/wallet/test-wallet-operations.ts +191 -0
  202. package/scripts/wallet/verify-wallet-tools.ts +124 -0
  203. package/src/__tests__/clob-api.test.ts +301 -0
  204. package/src/__tests__/integration/bridge-client.integration.test.ts +314 -0
  205. package/src/__tests__/integration/clob-api.integration.test.ts +218 -0
  206. package/src/__tests__/integration/ctf-client.integration.test.ts +331 -0
  207. package/src/__tests__/integration/data-api.integration.test.ts +194 -0
  208. package/src/__tests__/integration/gamma-api.integration.test.ts +206 -0
  209. package/src/__tests__/test-utils.ts +170 -0
  210. package/src/clients/bridge-client.ts +841 -0
  211. package/src/clients/clob-api.ts +629 -0
  212. package/src/clients/ctf-client.ts +1216 -0
  213. package/src/clients/data-api.ts +469 -0
  214. package/src/clients/gamma-api.ts +597 -0
  215. package/src/clients/trading-client.ts +749 -0
  216. package/src/clients/websocket-manager.ts +267 -0
  217. package/src/core/cache-adapter-bridge.ts +94 -0
  218. package/src/core/cache.ts +85 -0
  219. package/src/core/errors.ts +117 -0
  220. package/src/core/rate-limiter.ts +74 -0
  221. package/src/core/types.ts +360 -0
  222. package/src/core/unified-cache.ts +153 -0
  223. package/src/index.ts +455 -0
  224. package/src/mcp/README.md +380 -0
  225. package/src/mcp/errors.ts +124 -0
  226. package/src/mcp/index.ts +309 -0
  227. package/src/mcp/server.ts +183 -0
  228. package/src/mcp/tools/guide.ts +821 -0
  229. package/src/mcp/tools/index.ts +73 -0
  230. package/src/mcp/tools/market.ts +363 -0
  231. package/src/mcp/tools/order.ts +326 -0
  232. package/src/mcp/tools/trade.ts +417 -0
  233. package/src/mcp/tools/trader.ts +322 -0
  234. package/src/mcp/tools/wallet.ts +683 -0
  235. package/src/mcp/types.ts +472 -0
  236. package/src/services/authorization-service.ts +357 -0
  237. package/src/services/market-service.ts +544 -0
  238. package/src/services/realtime-service.ts +196 -0
  239. package/src/services/swap-service.ts +896 -0
  240. package/src/services/wallet-service.ts +259 -0
  241. package/src/utils/price-utils.ts +307 -0
  242. package/tsconfig.json +8 -0
  243. package/vitest.config.ts +19 -0
  244. package/vitest.integration.config.ts +18 -0
@@ -0,0 +1,406 @@
1
+ /**
2
+ * Example 13: Trending Markets Arbitrage Monitor
3
+ *
4
+ * Real-time monitoring of trending Polymarket markets for arbitrage opportunities.
5
+ *
6
+ * IMPORTANT: Understanding Polymarket Orderbook
7
+ * =============================================
8
+ * Polymarket 订单簿的关键特性:买 YES @ P = 卖 NO @ (1-P)
9
+ * 因此同一订单会在两个订单簿中出现
10
+ *
11
+ * 正确的套利计算必须使用"有效价格":
12
+ * - effectiveBuyYes = min(YES.ask, 1 - NO.bid)
13
+ * - effectiveBuyNo = min(NO.ask, 1 - YES.bid)
14
+ * - effectiveSellYes = max(YES.bid, 1 - NO.ask)
15
+ * - effectiveSellNo = max(NO.bid, 1 - YES.ask)
16
+ *
17
+ * 详细文档见: docs/01-polymarket-orderbook-arbitrage.md
18
+ *
19
+ * Features:
20
+ * - Fetches trending markets from Gamma API
21
+ * - Continuously monitors orderbooks for arb opportunities
22
+ * - Uses correct effective price calculations
23
+ * - Detailed logging for debugging and analysis
24
+ * - Configurable scan interval and profit thresholds
25
+ *
26
+ * Run with:
27
+ * pnpm example:trending-arb
28
+ *
29
+ * Environment variables:
30
+ * SCAN_INTERVAL_MS - Scan interval in ms (default: 5000)
31
+ * MIN_PROFIT_THRESHOLD - Minimum profit % (default: 0.1)
32
+ * MAX_MARKETS - Max markets to monitor (default: 20)
33
+ */
34
+
35
+ import { PolymarketSDK, checkArbitrage, getEffectivePrices } from '../src/index.js';
36
+
37
+ // ===== Configuration =====
38
+ const CONFIG = {
39
+ scanIntervalMs: parseInt(process.env.SCAN_INTERVAL_MS || '5000'),
40
+ minProfitThreshold: parseFloat(process.env.MIN_PROFIT_THRESHOLD || '0.1') / 100, // Convert % to decimal
41
+ maxMarkets: parseInt(process.env.MAX_MARKETS || '20'),
42
+ refreshMarketsIntervalMs: 60000, // Refresh trending markets every minute
43
+ maxCycles: parseInt(process.env.MAX_CYCLES || '0'), // 0 = unlimited
44
+ };
45
+
46
+ // ===== Logging Utilities =====
47
+ function log(level: 'INFO' | 'WARN' | 'ERROR' | 'DEBUG' | 'SUCCESS', message: string, data?: unknown) {
48
+ const timestamp = new Date().toISOString();
49
+ const prefix = {
50
+ 'INFO': '📋',
51
+ 'WARN': '⚠️',
52
+ 'ERROR': '❌',
53
+ 'DEBUG': '🔍',
54
+ 'SUCCESS': '✅',
55
+ }[level];
56
+
57
+ console.log(`[${timestamp}] ${prefix} [${level}] ${message}`);
58
+ if (data !== undefined) {
59
+ if (typeof data === 'object') {
60
+ console.log(JSON.stringify(data, null, 2));
61
+ } else {
62
+ console.log(` → ${data}`);
63
+ }
64
+ }
65
+ }
66
+
67
+ function logSeparator(title?: string) {
68
+ if (title) {
69
+ console.log(`\n${'═'.repeat(20)} ${title} ${'═'.repeat(20)}`);
70
+ } else {
71
+ console.log('─'.repeat(60));
72
+ }
73
+ }
74
+
75
+ // ===== Types =====
76
+ interface MonitoredMarket {
77
+ conditionId: string;
78
+ question: string;
79
+ slug: string;
80
+ volume24h: number;
81
+ lastUpdate: number;
82
+ lastEffectiveLongCost?: number;
83
+ lastEffectiveShortRevenue?: number;
84
+ scanCount: number;
85
+ errorCount: number;
86
+ }
87
+
88
+ interface ScanResult {
89
+ timestamp: number;
90
+ market: MonitoredMarket;
91
+ yesAsk: number;
92
+ noAsk: number;
93
+ yesBid: number;
94
+ noBid: number;
95
+ // Effective prices (考虑镜像订单)
96
+ effectiveBuyYes: number;
97
+ effectiveBuyNo: number;
98
+ effectiveSellYes: number;
99
+ effectiveSellNo: number;
100
+ effectiveLongCost: number;
101
+ effectiveShortRevenue: number;
102
+ longArbProfit: number;
103
+ shortArbProfit: number;
104
+ yesSpread: number;
105
+ hasOpportunity: boolean;
106
+ opportunityType?: 'long' | 'short';
107
+ }
108
+
109
+ // ===== Monitor State =====
110
+ let markets: MonitoredMarket[] = [];
111
+ let scanCount = 0;
112
+ let opportunitiesFound = 0;
113
+ let totalScans = 0;
114
+ let lastMarketRefresh = 0;
115
+
116
+ // ===== Main Functions =====
117
+
118
+ async function fetchTrendingMarkets(sdk: PolymarketSDK): Promise<MonitoredMarket[]> {
119
+ log('INFO', `Fetching top ${CONFIG.maxMarkets} trending markets...`);
120
+
121
+ try {
122
+ const trendingMarkets = await sdk.gammaApi.getTrendingMarkets(CONFIG.maxMarkets);
123
+
124
+ const monitored: MonitoredMarket[] = trendingMarkets
125
+ .filter(m => m.conditionId)
126
+ .map(m => ({
127
+ conditionId: m.conditionId,
128
+ question: m.question || 'Unknown',
129
+ slug: m.slug || '',
130
+ volume24h: m.volume24hr || 0,
131
+ lastUpdate: Date.now(),
132
+ scanCount: 0,
133
+ errorCount: 0,
134
+ }));
135
+
136
+ log('SUCCESS', `Loaded ${monitored.length} trending markets`);
137
+
138
+ // Log market details
139
+ monitored.forEach((m, i) => {
140
+ log('DEBUG', ` ${i + 1}. ${m.question.slice(0, 50)}...`, {
141
+ conditionId: m.conditionId.slice(0, 20) + '...',
142
+ volume24h: `$${m.volume24h.toLocaleString()}`,
143
+ });
144
+ });
145
+
146
+ return monitored;
147
+ } catch (error) {
148
+ log('ERROR', 'Failed to fetch trending markets', error instanceof Error ? error.message : error);
149
+ return [];
150
+ }
151
+ }
152
+
153
+ async function scanMarket(sdk: PolymarketSDK, market: MonitoredMarket): Promise<ScanResult | null> {
154
+ try {
155
+ const orderbook = await sdk.clobApi.getProcessedOrderbook(market.conditionId);
156
+
157
+ market.scanCount++;
158
+ market.lastUpdate = Date.now();
159
+ market.lastEffectiveLongCost = orderbook.summary.effectiveLongCost;
160
+ market.lastEffectiveShortRevenue = orderbook.summary.effectiveShortRevenue;
161
+
162
+ const { effectivePrices } = orderbook.summary;
163
+
164
+ // 使用正确的有效价格检测套利
165
+ const arb = checkArbitrage(
166
+ orderbook.yes.ask,
167
+ orderbook.no.ask,
168
+ orderbook.yes.bid,
169
+ orderbook.no.bid
170
+ );
171
+
172
+ const hasOpportunity = arb !== null && arb.profit > CONFIG.minProfitThreshold;
173
+
174
+ return {
175
+ timestamp: Date.now(),
176
+ market,
177
+ yesAsk: orderbook.yes.ask,
178
+ noAsk: orderbook.no.ask,
179
+ yesBid: orderbook.yes.bid,
180
+ noBid: orderbook.no.bid,
181
+ // 有效价格
182
+ effectiveBuyYes: effectivePrices.effectiveBuyYes,
183
+ effectiveBuyNo: effectivePrices.effectiveBuyNo,
184
+ effectiveSellYes: effectivePrices.effectiveSellYes,
185
+ effectiveSellNo: effectivePrices.effectiveSellNo,
186
+ effectiveLongCost: orderbook.summary.effectiveLongCost,
187
+ effectiveShortRevenue: orderbook.summary.effectiveShortRevenue,
188
+ longArbProfit: orderbook.summary.longArbProfit,
189
+ shortArbProfit: orderbook.summary.shortArbProfit,
190
+ yesSpread: orderbook.summary.yesSpread,
191
+ hasOpportunity,
192
+ opportunityType: arb?.type,
193
+ };
194
+ } catch (error) {
195
+ market.errorCount++;
196
+ log('WARN', `Scan failed for ${market.question.slice(0, 30)}...`, error instanceof Error ? error.message : 'Unknown');
197
+ return null;
198
+ }
199
+ }
200
+
201
+ async function runScanCycle(sdk: PolymarketSDK): Promise<void> {
202
+ scanCount++;
203
+ const cycleStart = Date.now();
204
+
205
+ logSeparator(`SCAN CYCLE #${scanCount}`);
206
+ log('INFO', `Scanning ${markets.length} markets...`);
207
+
208
+ const results: ScanResult[] = [];
209
+ let successCount = 0;
210
+ let errorCount = 0;
211
+
212
+ for (const market of markets) {
213
+ const result = await scanMarket(sdk, market);
214
+ totalScans++;
215
+
216
+ if (result) {
217
+ successCount++;
218
+ results.push(result);
219
+
220
+ // Log each market scan result
221
+ const profitIndicator = result.hasOpportunity ? '🎯' :
222
+ result.longArbProfit > -0.01 ? '📈' :
223
+ result.shortArbProfit > -0.01 ? '📉' : '⏸️';
224
+
225
+ log('DEBUG', `${profitIndicator} ${market.question.slice(0, 40)}...`, {
226
+ // 有效价格计算
227
+ effectiveLongCost: result.effectiveLongCost.toFixed(4),
228
+ effectiveShortRevenue: result.effectiveShortRevenue.toFixed(4),
229
+ longArb: `${(result.longArbProfit * 100).toFixed(2)}%`,
230
+ shortArb: `${(result.shortArbProfit * 100).toFixed(2)}%`,
231
+ yesSpread: `${(result.yesSpread * 100).toFixed(2)}%`,
232
+ });
233
+ } else {
234
+ errorCount++;
235
+ }
236
+ }
237
+
238
+ // Find opportunities
239
+ const opportunities = results.filter(r => r.hasOpportunity);
240
+
241
+ if (opportunities.length > 0) {
242
+ opportunitiesFound += opportunities.length;
243
+
244
+ logSeparator('🚨 OPPORTUNITIES FOUND');
245
+
246
+ for (const opp of opportunities) {
247
+ log('SUCCESS', `${opp.opportunityType?.toUpperCase()} ARB OPPORTUNITY`, {
248
+ market: opp.market.question,
249
+ conditionId: opp.market.conditionId,
250
+ type: opp.opportunityType,
251
+ profit: `${(Math.max(opp.longArbProfit, opp.shortArbProfit) * 100).toFixed(3)}%`,
252
+ effectivePrices: {
253
+ buyYes: opp.effectiveBuyYes.toFixed(4),
254
+ buyNo: opp.effectiveBuyNo.toFixed(4),
255
+ sellYes: opp.effectiveSellYes.toFixed(4),
256
+ sellNo: opp.effectiveSellNo.toFixed(4),
257
+ },
258
+ costs: {
259
+ effectiveLongCost: opp.effectiveLongCost.toFixed(4),
260
+ effectiveShortRevenue: opp.effectiveShortRevenue.toFixed(4),
261
+ },
262
+ });
263
+
264
+ // Log execution strategy
265
+ if (opp.opportunityType === 'long') {
266
+ log('INFO', '📌 Strategy: Buy YES + Buy NO → Merge → Profit', {
267
+ step1: `Buy YES @ ${opp.effectiveBuyYes.toFixed(4)}`,
268
+ step2: `Buy NO @ ${opp.effectiveBuyNo.toFixed(4)}`,
269
+ step3: 'Merge tokens → 1 USDC',
270
+ profit: `${(opp.longArbProfit * 100).toFixed(3)}% per unit`,
271
+ });
272
+ } else {
273
+ log('INFO', '📌 Strategy: Split USDC → Sell YES + Sell NO → Profit', {
274
+ step1: 'Split 1 USDC → 1 YES + 1 NO',
275
+ step2: `Sell YES @ ${opp.effectiveSellYes.toFixed(4)}`,
276
+ step3: `Sell NO @ ${opp.effectiveSellNo.toFixed(4)}`,
277
+ profit: `${(opp.shortArbProfit * 100).toFixed(3)}% per unit`,
278
+ });
279
+ }
280
+ }
281
+ }
282
+
283
+ // Cycle summary
284
+ const cycleTime = Date.now() - cycleStart;
285
+ log('INFO', `Cycle #${scanCount} complete`, {
286
+ duration: `${cycleTime}ms`,
287
+ scanned: successCount,
288
+ errors: errorCount,
289
+ opportunities: opportunities.length,
290
+ });
291
+
292
+ // Show best spreads (closest to arb)
293
+ if (results.length > 0) {
294
+ const sortedByLongArb = [...results].sort((a, b) => b.longArbProfit - a.longArbProfit);
295
+ const sortedByShortArb = [...results].sort((a, b) => b.shortArbProfit - a.shortArbProfit);
296
+
297
+ log('DEBUG', 'Best Long Arb Candidates (by effective cost):', {
298
+ '1st': `${sortedByLongArb[0].market.question.slice(0, 30)}... → cost=${sortedByLongArb[0].effectiveLongCost.toFixed(4)} → ${(sortedByLongArb[0].longArbProfit * 100).toFixed(2)}%`,
299
+ '2nd': sortedByLongArb[1] ? `${sortedByLongArb[1].market.question.slice(0, 30)}... → cost=${sortedByLongArb[1].effectiveLongCost.toFixed(4)} → ${(sortedByLongArb[1].longArbProfit * 100).toFixed(2)}%` : 'N/A',
300
+ });
301
+
302
+ log('DEBUG', 'Best Short Arb Candidates (by effective revenue):', {
303
+ '1st': `${sortedByShortArb[0].market.question.slice(0, 30)}... → rev=${sortedByShortArb[0].effectiveShortRevenue.toFixed(4)} → ${(sortedByShortArb[0].shortArbProfit * 100).toFixed(2)}%`,
304
+ '2nd': sortedByShortArb[1] ? `${sortedByShortArb[1].market.question.slice(0, 30)}... → rev=${sortedByShortArb[1].effectiveShortRevenue.toFixed(4)} → ${(sortedByShortArb[1].shortArbProfit * 100).toFixed(2)}%` : 'N/A',
305
+ });
306
+
307
+ // Show spread analysis
308
+ const avgSpread = results.reduce((sum, r) => sum + r.yesSpread, 0) / results.length;
309
+ log('DEBUG', 'Market Efficiency:', {
310
+ avgYesSpread: `${(avgSpread * 100).toFixed(2)}%`,
311
+ interpretation: 'Spread = transaction cost, markets are efficient when spread > 0',
312
+ });
313
+ }
314
+ }
315
+
316
+ async function maybeRefreshMarkets(sdk: PolymarketSDK): Promise<void> {
317
+ const now = Date.now();
318
+ if (now - lastMarketRefresh > CONFIG.refreshMarketsIntervalMs) {
319
+ log('INFO', 'Refreshing trending markets list...');
320
+ const newMarkets = await fetchTrendingMarkets(sdk);
321
+ if (newMarkets.length > 0) {
322
+ markets = newMarkets;
323
+ lastMarketRefresh = now;
324
+ }
325
+ }
326
+ }
327
+
328
+ async function main(): Promise<void> {
329
+ console.clear();
330
+ logSeparator('TRENDING MARKETS ARBITRAGE MONITOR');
331
+
332
+ log('INFO', 'Configuration', {
333
+ scanInterval: `${CONFIG.scanIntervalMs}ms`,
334
+ minProfitThreshold: `${CONFIG.minProfitThreshold * 100}%`,
335
+ maxMarkets: CONFIG.maxMarkets,
336
+ refreshInterval: `${CONFIG.refreshMarketsIntervalMs / 1000}s`,
337
+ });
338
+
339
+ log('INFO', 'Understanding Arbitrage Calculation:', {
340
+ note: 'Uses effective prices considering mirror orders',
341
+ longArb: 'Profit when effectiveLongCost < 1.0',
342
+ shortArb: 'Profit when effectiveShortRevenue > 1.0',
343
+ docs: 'docs/01-polymarket-orderbook-arbitrage.md',
344
+ });
345
+
346
+ // Initialize SDK
347
+ log('INFO', 'Initializing PolymarketSDK...');
348
+ const sdk = new PolymarketSDK();
349
+ log('SUCCESS', 'SDK initialized');
350
+
351
+ // Fetch initial markets
352
+ markets = await fetchTrendingMarkets(sdk);
353
+ lastMarketRefresh = Date.now();
354
+
355
+ if (markets.length === 0) {
356
+ log('ERROR', 'No markets to monitor. Exiting.');
357
+ process.exit(1);
358
+ }
359
+
360
+ logSeparator('STARTING MONITOR LOOP');
361
+ log('INFO', `Press Ctrl+C to stop. Scanning every ${CONFIG.scanIntervalMs / 1000}s...`);
362
+
363
+ // Monitor loop
364
+ const runLoop = async () => {
365
+ try {
366
+ await maybeRefreshMarkets(sdk);
367
+ await runScanCycle(sdk);
368
+ } catch (error) {
369
+ log('ERROR', 'Scan cycle error', error instanceof Error ? error.message : error);
370
+ }
371
+
372
+ // Check if we've reached max cycles
373
+ if (CONFIG.maxCycles > 0 && scanCount >= CONFIG.maxCycles) {
374
+ logSeparator('MAX CYCLES REACHED');
375
+ log('INFO', 'Final Statistics', {
376
+ totalCycles: scanCount,
377
+ totalScans,
378
+ opportunitiesFound,
379
+ });
380
+ process.exit(0);
381
+ }
382
+
383
+ // Schedule next scan
384
+ setTimeout(runLoop, CONFIG.scanIntervalMs);
385
+ };
386
+
387
+ // Start loop
388
+ await runLoop();
389
+
390
+ // Handle shutdown
391
+ process.on('SIGINT', () => {
392
+ logSeparator('MONITOR SHUTDOWN');
393
+ log('INFO', 'Final Statistics', {
394
+ totalCycles: scanCount,
395
+ totalScans,
396
+ opportunitiesFound,
397
+ runtime: `${Math.round((Date.now() - lastMarketRefresh) / 1000)}s`,
398
+ });
399
+ process.exit(0);
400
+ });
401
+ }
402
+
403
+ main().catch(error => {
404
+ log('ERROR', 'Fatal error', error);
405
+ process.exit(1);
406
+ });
@@ -0,0 +1,179 @@
1
+ # Poly-SDK Examples
2
+
3
+ Comprehensive examples demonstrating the Polymarket SDK capabilities.
4
+
5
+ ## Running Examples
6
+
7
+ ```bash
8
+ # From poly-sdk directory
9
+ npx tsx examples/01-basic-usage.ts
10
+
11
+ # Or use pnpm scripts
12
+ pnpm example:basic # 01-basic-usage.ts
13
+ pnpm example:smart-money # 02-smart-money.ts
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Examples Overview
19
+
20
+ | # | File | Description | Auth Required |
21
+ |---|------|-------------|---------------|
22
+ | 01 | `basic-usage.ts` | Trending markets, orderbook data | No |
23
+ | 02 | `smart-money.ts` | Smart money wallet analysis | No |
24
+ | 03 | `market-analysis.ts` | Market search and analysis | No |
25
+ | 04 | `kline-aggregation.ts` | Price history and KLine data | No |
26
+ | 05 | `follow-wallet-strategy.ts` | Copy trading simulation | No |
27
+ | 06 | `services-demo.ts` | WalletService & MarketService | No |
28
+ | 07 | `realtime-websocket.ts` | Real-time orderbook updates | No |
29
+ | 08 | `trading-orders.ts` | Order placement and management | Yes |
30
+ | 09 | `rewards-tracking.ts` | Liquidity rewards tracking | Yes |
31
+ | 10 | `ctf-operations.ts` | Split/Merge/Redeem tokens | Yes |
32
+ | 11 | `live-arbitrage-scan.ts` | Scan markets for arbitrage | No |
33
+ | 12 | `trending-arb-monitor.ts` | Real-time arbitrage monitoring | No |
34
+
35
+ ---
36
+
37
+ ## Example Details
38
+
39
+ ### 01 - Basic Usage
40
+
41
+ Get started with the SDK. Fetches trending markets and orderbook data.
42
+
43
+ ```typescript
44
+ import { PolymarketSDK } from '@prediction-router/poly-sdk';
45
+ const sdk = new PolymarketSDK();
46
+ const trending = await sdk.gammaApi.getTrendingMarkets(5);
47
+ ```
48
+
49
+ ### 02 - Smart Money Analysis
50
+
51
+ Analyze wallet trading performance and identify profitable traders.
52
+
53
+ - Fetch wallet positions and activity
54
+ - Calculate P&L and win rate
55
+ - Identify high-performing wallets
56
+
57
+ ### 03 - Market Analysis
58
+
59
+ Search and analyze markets by various criteria.
60
+
61
+ - Search by keyword
62
+ - Filter by volume, liquidity
63
+ - Analyze market spreads
64
+
65
+ ### 04 - KLine Aggregation
66
+
67
+ Get price history for charting.
68
+
69
+ - Multi-timeframe candles (1m, 5m, 1h, 1d)
70
+ - OHLCV data
71
+ - Dual YES/NO price tracking
72
+
73
+ ### 05 - Follow Wallet Strategy
74
+
75
+ Simulate copy trading based on smart money signals.
76
+
77
+ - Monitor wallet activity
78
+ - Generate trade signals
79
+ - Backtest strategy performance
80
+
81
+ ### 06 - Services Demo
82
+
83
+ High-level service abstractions.
84
+
85
+ - `WalletService` - Wallet analysis helpers
86
+ - `MarketService` - Market data aggregation
87
+
88
+ ### 07 - Real-time WebSocket
89
+
90
+ Live orderbook streaming.
91
+
92
+ - Connect to Polymarket WebSocket
93
+ - Real-time price updates
94
+ - Orderbook change events
95
+
96
+ ### 08 - Trading Orders
97
+
98
+ Place and manage orders (requires private key).
99
+
100
+ ```bash
101
+ POLY_PRIVKEY=0x... npx tsx examples/08-trading-orders.ts
102
+ ```
103
+
104
+ - Create limit/market orders
105
+ - Cancel orders
106
+ - Check order status
107
+
108
+ ### 09 - Rewards Tracking
109
+
110
+ Track liquidity provider rewards.
111
+
112
+ - Earned rewards by market
113
+ - Order scoring metrics
114
+ - Reward rate analysis
115
+
116
+ ### 10 - CTF Operations
117
+
118
+ On-chain token operations (requires private key + USDC.e).
119
+
120
+ ```bash
121
+ POLY_PRIVKEY=0x... npx tsx examples/10-ctf-operations.ts
122
+ ```
123
+
124
+ **Critical:** Uses USDC.e (not native USDC):
125
+ | Token | Address | CTF Compatible |
126
+ |-------|---------|----------------|
127
+ | USDC.e | `0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174` | Yes |
128
+ | Native USDC | `0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359` | No |
129
+
130
+ Operations:
131
+ - **Split**: USDC.e → YES + NO tokens
132
+ - **Merge**: YES + NO → USDC.e (arbitrage profit)
133
+ - **Redeem**: Winning tokens → USDC.e
134
+
135
+ ### 11 - Live Arbitrage Scan
136
+
137
+ Scan markets for arbitrage opportunities (read-only).
138
+
139
+ - Fetches active markets
140
+ - Calculates effective prices
141
+ - Detects long/short arb opportunities
142
+
143
+ ### 12 - Trending Arbitrage Monitor
144
+
145
+ Continuous monitoring of trending markets.
146
+
147
+ - Real-time orderbook analysis
148
+ - Correct effective price calculation
149
+ - Configurable scan intervals
150
+
151
+ ---
152
+
153
+ ## Arbitrage Concepts
154
+
155
+ Polymarket orderbooks have a mirroring property:
156
+ - **Buying YES @ P = Selling NO @ (1-P)**
157
+
158
+ Correct effective prices:
159
+ ```
160
+ effectiveBuyYes = min(YES.ask, 1 - NO.bid)
161
+ effectiveBuyNo = min(NO.ask, 1 - YES.bid)
162
+ effectiveSellYes = max(YES.bid, 1 - NO.ask)
163
+ effectiveSellNo = max(NO.bid, 1 - YES.ask)
164
+ ```
165
+
166
+ | Arb Type | Condition | Action |
167
+ |----------|-----------|--------|
168
+ | Long | `effectiveBuyYes + effectiveBuyNo < 1` | Buy both, merge for $1 |
169
+ | Short | `effectiveSellYes + effectiveSellNo > 1` | Split $1, sell both |
170
+
171
+ ---
172
+
173
+ ## Environment Variables
174
+
175
+ | Variable | Description | Required For |
176
+ |----------|-------------|--------------|
177
+ | `POLY_PRIVKEY` | Private key for trading | 08, 09, 10 |
178
+ | `SCAN_INTERVAL_MS` | Arb scan interval (ms) | 12 |
179
+ | `PROFIT_THRESHOLD` | Min arb profit % | 11, 12 |
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@catalyst-team/poly-sdk",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "poly-mcp": "./dist/mcp/server.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ },
16
+ "./mcp": {
17
+ "types": "./dist/mcp/index.d.ts",
18
+ "import": "./dist/mcp/index.js"
19
+ },
20
+ "./mcp/server": {
21
+ "types": "./dist/mcp/server.d.ts",
22
+ "import": "./dist/mcp/server.js"
23
+ }
24
+ },
25
+ "dependencies": {
26
+ "@modelcontextprotocol/sdk": "^1.25.1",
27
+ "@nevuamarkets/poly-websockets": "^0.3.0",
28
+ "@polymarket/clob-client": "4.22.8",
29
+ "@types/ws": "^8.18.1",
30
+ "bottleneck": "^2.19.5",
31
+ "ethers": "5",
32
+ "ws": "^8.18.3",
33
+ "@prediction-router/cache": "0.1.0"
34
+ },
35
+ "devDependencies": {
36
+ "tsx": "^4.7.0",
37
+ "typescript": "^5.7.2",
38
+ "vitest": "^2.1.8"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc",
42
+ "mcp": "node dist/mcp/server.js",
43
+ "mcp:dev": "tsx src/mcp/server.ts",
44
+ "dev": "tsc --watch",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest",
47
+ "test:integration": "vitest run --config vitest.integration.config.ts",
48
+ "example:basic": "tsx examples/01-basic-usage.ts",
49
+ "example:smart-money": "tsx examples/02-smart-money.ts",
50
+ "example:market-analysis": "tsx examples/03-market-analysis.ts",
51
+ "example:kline": "tsx examples/04-kline-aggregation.ts",
52
+ "example:follow-wallet": "tsx examples/05-follow-wallet-strategy.ts",
53
+ "example:services": "tsx examples/06-services-demo.ts",
54
+ "example:realtime": "tsx examples/07-realtime-websocket.ts",
55
+ "example:trading": "tsx examples/08-trading-orders.ts",
56
+ "example:rewards": "tsx examples/09-rewards-tracking.ts",
57
+ "example:ctf": "tsx examples/10-ctf-operations.ts",
58
+ "example:arbitrage": "tsx examples/11-arbitrage-service.ts",
59
+ "example:live-arb": "tsx examples/12-live-arbitrage-scan.ts",
60
+ "example:trending-arb": "tsx examples/13-trending-arb-monitor.ts"
61
+ }
62
+ }