@catalyst-team/poly-sdk 0.2.0 → 0.2.1
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/LICENSE +1 -1
- package/README.en.md +8 -44
- package/README.md +5 -3
- package/README.zh-CN.md +502 -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/{src/core/types.ts → dist/core/types.d.ts} +169 -215
- 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 +93 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +255 -0
- package/dist/index.js.map +1 -0
- package/dist/services/arbitrage-service.d.ts +408 -0
- package/dist/services/arbitrage-service.d.ts.map +1 -0
- package/dist/services/arbitrage-service.js +1422 -0
- package/dist/services/arbitrage-service.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/package.json +7 -2
- package/docs/00-design.md +0 -760
- package/docs/02-API.md +0 -1148
- package/docs/arb/test-plan.md +0 -387
- package/docs/arb/test-results.md +0 -336
- package/docs/arbitrage.md +0 -754
- package/docs/reports/smart-money-analysis-2025-12-23-cn.md +0 -840
- package/examples/01-basic-usage.ts +0 -68
- package/examples/02-smart-money.ts +0 -95
- package/examples/03-market-analysis.ts +0 -108
- package/examples/04-kline-aggregation.ts +0 -158
- package/examples/05-follow-wallet-strategy.ts +0 -156
- package/examples/06-services-demo.ts +0 -124
- package/examples/07-realtime-websocket.ts +0 -117
- package/examples/08-trading-orders.ts +0 -278
- package/examples/09-rewards-tracking.ts +0 -187
- package/examples/10-ctf-operations.ts +0 -336
- package/examples/11-live-arbitrage-scan.ts +0 -221
- package/examples/12-trending-arb-monitor.ts +0 -406
- package/examples/13-arbitrage-service.ts +0 -211
- package/examples/README.md +0 -179
- package/scripts/README.md +0 -163
- package/scripts/approvals/approve-erc1155.ts +0 -129
- package/scripts/approvals/approve-neg-risk-erc1155.ts +0 -149
- package/scripts/approvals/approve-neg-risk.ts +0 -102
- package/scripts/approvals/check-all-allowances.ts +0 -150
- package/scripts/approvals/check-allowance.ts +0 -129
- package/scripts/approvals/check-ctf-approval.ts +0 -158
- package/scripts/arb/faze-bo3-arb.ts +0 -385
- package/scripts/arb/settle-position.ts +0 -190
- package/scripts/arb/token-rebalancer.ts +0 -420
- package/scripts/arb-tests/01-unit-tests.ts +0 -495
- package/scripts/arb-tests/02-integration-tests.ts +0 -412
- package/scripts/arb-tests/03-e2e-tests.ts +0 -503
- package/scripts/arb-tests/README.md +0 -109
- package/scripts/datas/001-report.md +0 -486
- package/scripts/datas/clone-modal-screenshot.png +0 -0
- package/scripts/deposit/deposit-native-usdc.ts +0 -179
- package/scripts/deposit/deposit-usdc.ts +0 -155
- package/scripts/deposit/swap-usdc-to-usdce.ts +0 -375
- package/scripts/research/research-markets.ts +0 -166
- package/scripts/trading/check-orders.ts +0 -50
- package/scripts/trading/sell-nvidia-positions.ts +0 -206
- package/scripts/trading/test-order.ts +0 -172
- package/scripts/verify/test-approve-trading.ts +0 -98
- package/scripts/verify/test-provider-fix.ts +0 -43
- package/scripts/verify/test-search-mcp.ts +0 -113
- package/scripts/verify/verify-all-apis.ts +0 -160
- package/scripts/wallet/check-wallet-balances.ts +0 -75
- package/scripts/wallet/test-wallet-operations.ts +0 -191
- package/scripts/wallet/verify-wallet-tools.ts +0 -124
- package/src/__tests__/clob-api.test.ts +0 -301
- package/src/__tests__/integration/bridge-client.integration.test.ts +0 -314
- package/src/__tests__/integration/clob-api.integration.test.ts +0 -218
- package/src/__tests__/integration/ctf-client.integration.test.ts +0 -331
- package/src/__tests__/integration/data-api.integration.test.ts +0 -194
- package/src/__tests__/integration/gamma-api.integration.test.ts +0 -206
- package/src/__tests__/test-utils.ts +0 -170
- package/src/clients/bridge-client.ts +0 -841
- package/src/clients/clob-api.ts +0 -629
- package/src/clients/ctf-client.ts +0 -1216
- package/src/clients/data-api.ts +0 -469
- package/src/clients/gamma-api.ts +0 -597
- package/src/clients/trading-client.ts +0 -749
- package/src/clients/websocket-manager.ts +0 -267
- package/src/core/cache-adapter-bridge.ts +0 -94
- package/src/core/cache.ts +0 -85
- package/src/core/errors.ts +0 -117
- package/src/core/rate-limiter.ts +0 -74
- package/src/core/unified-cache.ts +0 -153
- package/src/index.ts +0 -461
- package/src/services/arbitrage-service.ts +0 -1807
- package/src/services/authorization-service.ts +0 -357
- package/src/services/market-service.ts +0 -544
- package/src/services/realtime-service.ts +0 -196
- package/src/services/swap-service.ts +0 -896
- package/src/services/wallet-service.ts +0 -259
- package/src/utils/price-utils.ts +0 -307
- package/tsconfig.json +0 -8
- package/vitest.config.ts +0 -19
- package/vitest.integration.config.ts +0 -18
|
@@ -1,412 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env npx tsx
|
|
2
|
-
/**
|
|
3
|
-
* Integration Tests for ArbitrageService
|
|
4
|
-
*
|
|
5
|
-
* Tests the complete workflow without requiring private key:
|
|
6
|
-
* 1. Service initialization (monitor-only mode)
|
|
7
|
-
* 2. Market scanning (scanMarkets)
|
|
8
|
-
* 3. Quick scan (quickScan)
|
|
9
|
-
* 4. WebSocket connection and orderbook updates
|
|
10
|
-
*
|
|
11
|
-
* Environment:
|
|
12
|
-
* No POLY_PRIVKEY required - runs in monitor-only mode
|
|
13
|
-
*
|
|
14
|
-
* Run with:
|
|
15
|
-
* npx tsx packages/poly-sdk/scripts/arb-tests/02-integration-tests.ts
|
|
16
|
-
*
|
|
17
|
-
* This script performs REAL API calls to Polymarket services.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { ArbitrageService } from '../../src/index.js';
|
|
21
|
-
import type { ArbitrageMarketConfig } from '../../src/index.js';
|
|
22
|
-
|
|
23
|
-
// ===== Test Results Tracking =====
|
|
24
|
-
|
|
25
|
-
interface TestResult {
|
|
26
|
-
name: string;
|
|
27
|
-
passed: boolean;
|
|
28
|
-
error?: string;
|
|
29
|
-
duration: number;
|
|
30
|
-
details?: any;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const results: TestResult[] = [];
|
|
34
|
-
|
|
35
|
-
function recordTest(name: string, passed: boolean, duration: number, error?: string, details?: any): void {
|
|
36
|
-
results.push({ name, passed, error, duration, details });
|
|
37
|
-
|
|
38
|
-
const status = passed ? '✅ PASS' : '❌ FAIL';
|
|
39
|
-
const time = `(${duration}ms)`;
|
|
40
|
-
|
|
41
|
-
console.log(`${status} ${name} ${time}`);
|
|
42
|
-
if (error) {
|
|
43
|
-
console.log(` Error: ${error}`);
|
|
44
|
-
}
|
|
45
|
-
if (details && passed) {
|
|
46
|
-
console.log(` ${JSON.stringify(details)}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function runTest(name: string, testFn: () => Promise<any>): Promise<boolean> {
|
|
51
|
-
const startTime = Date.now();
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
const result = await testFn();
|
|
55
|
-
const duration = Date.now() - startTime;
|
|
56
|
-
recordTest(name, true, duration, undefined, result);
|
|
57
|
-
return true;
|
|
58
|
-
} catch (error: any) {
|
|
59
|
-
const duration = Date.now() - startTime;
|
|
60
|
-
recordTest(name, false, duration, error.message);
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ===== Test Suite =====
|
|
66
|
-
|
|
67
|
-
async function main() {
|
|
68
|
-
console.log('╔════════════════════════════════════════════════════════════════╗');
|
|
69
|
-
console.log('║ ArbitrageService - Integration Test Suite ║');
|
|
70
|
-
console.log('╚════════════════════════════════════════════════════════════════╝');
|
|
71
|
-
console.log();
|
|
72
|
-
console.log('Running in monitor-only mode (no private key required)');
|
|
73
|
-
console.log('This test suite performs REAL API calls to Polymarket.\n');
|
|
74
|
-
|
|
75
|
-
let arbService: ArbitrageService;
|
|
76
|
-
let testMarket: ArbitrageMarketConfig | undefined;
|
|
77
|
-
|
|
78
|
-
// ===== Test 1: Service Initialization =====
|
|
79
|
-
console.log('═══════════════════════════════════════════════════════════════');
|
|
80
|
-
console.log('Test 1: ArbitrageService Initialization');
|
|
81
|
-
console.log('═══════════════════════════════════════════════════════════════\n');
|
|
82
|
-
|
|
83
|
-
await runTest('Initialize ArbitrageService (monitor-only)', async () => {
|
|
84
|
-
arbService = new ArbitrageService({
|
|
85
|
-
privateKey: undefined, // Monitor-only mode
|
|
86
|
-
profitThreshold: 0.005,
|
|
87
|
-
minTradeSize: 5,
|
|
88
|
-
maxTradeSize: 100,
|
|
89
|
-
autoExecute: false,
|
|
90
|
-
enableLogging: true,
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
return { mode: 'monitor-only', configured: true };
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
// ===== Test 2: Market Scanning =====
|
|
97
|
-
console.log('\n═══════════════════════════════════════════════════════════════');
|
|
98
|
-
console.log('Test 2: Market Scanning');
|
|
99
|
-
console.log('═══════════════════════════════════════════════════════════════\n');
|
|
100
|
-
|
|
101
|
-
let scanResults: any[] = [];
|
|
102
|
-
|
|
103
|
-
await runTest('scanMarkets() with basic criteria', async () => {
|
|
104
|
-
scanResults = await arbService.scanMarkets(
|
|
105
|
-
{
|
|
106
|
-
minVolume24h: 5000,
|
|
107
|
-
limit: 20,
|
|
108
|
-
},
|
|
109
|
-
0.003 // 0.3% min profit
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
if (!Array.isArray(scanResults)) {
|
|
113
|
-
throw new Error('scanMarkets did not return array');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return {
|
|
117
|
-
totalScanned: scanResults.length,
|
|
118
|
-
withOpportunities: scanResults.filter(r => r.arbType !== 'none').length,
|
|
119
|
-
};
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
await runTest('Validate ScanResult structure', async () => {
|
|
123
|
-
if (scanResults.length === 0) {
|
|
124
|
-
throw new Error('No markets returned from scan');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const sample = scanResults[0];
|
|
128
|
-
|
|
129
|
-
// Check required fields
|
|
130
|
-
const requiredFields = [
|
|
131
|
-
'market',
|
|
132
|
-
'arbType',
|
|
133
|
-
'profitRate',
|
|
134
|
-
'profitPercent',
|
|
135
|
-
'effectivePrices',
|
|
136
|
-
'volume24h',
|
|
137
|
-
'availableSize',
|
|
138
|
-
'score',
|
|
139
|
-
'description',
|
|
140
|
-
];
|
|
141
|
-
|
|
142
|
-
for (const field of requiredFields) {
|
|
143
|
-
if (!(field in sample)) {
|
|
144
|
-
throw new Error(`Missing required field: ${field}`);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Check market config structure
|
|
149
|
-
const marketFields = ['name', 'conditionId', 'yesTokenId', 'noTokenId'];
|
|
150
|
-
for (const field of marketFields) {
|
|
151
|
-
if (!(field in sample.market)) {
|
|
152
|
-
throw new Error(`Missing market field: ${field}`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Check effective prices structure
|
|
157
|
-
const priceFields = ['buyYes', 'buyNo', 'sellYes', 'sellNo', 'longCost', 'shortRevenue'];
|
|
158
|
-
for (const field of priceFields) {
|
|
159
|
-
if (!(field in sample.effectivePrices)) {
|
|
160
|
-
throw new Error(`Missing effectivePrices field: ${field}`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
marketName: sample.market.name.slice(0, 40),
|
|
166
|
-
arbType: sample.arbType,
|
|
167
|
-
profitPercent: sample.profitPercent.toFixed(2) + '%',
|
|
168
|
-
};
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// Find a market with opportunity for further testing
|
|
172
|
-
const opportunityMarkets = scanResults.filter(r => r.arbType !== 'none');
|
|
173
|
-
if (opportunityMarkets.length > 0) {
|
|
174
|
-
testMarket = opportunityMarkets[0].market;
|
|
175
|
-
|
|
176
|
-
await runTest('Identify market with arbitrage opportunity', async () => {
|
|
177
|
-
return {
|
|
178
|
-
market: testMarket!.name.slice(0, 40),
|
|
179
|
-
type: opportunityMarkets[0].arbType,
|
|
180
|
-
profit: opportunityMarkets[0].profitPercent.toFixed(2) + '%',
|
|
181
|
-
};
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// ===== Test 3: Quick Scan =====
|
|
186
|
-
console.log('\n═══════════════════════════════════════════════════════════════');
|
|
187
|
-
console.log('Test 3: Quick Scan');
|
|
188
|
-
console.log('═══════════════════════════════════════════════════════════════\n');
|
|
189
|
-
|
|
190
|
-
await runTest('quickScan() with default parameters', async () => {
|
|
191
|
-
const quickResults = await arbService.quickScan(0.005, 10);
|
|
192
|
-
|
|
193
|
-
if (!Array.isArray(quickResults)) {
|
|
194
|
-
throw new Error('quickScan did not return array');
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return {
|
|
198
|
-
totalFound: quickResults.length,
|
|
199
|
-
topProfit: quickResults.length > 0
|
|
200
|
-
? quickResults[0].profitPercent.toFixed(2) + '%'
|
|
201
|
-
: 'N/A',
|
|
202
|
-
};
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
await runTest('quickScan() with high profit threshold', async () => {
|
|
206
|
-
const quickResults = await arbService.quickScan(0.02, 5); // 2% threshold
|
|
207
|
-
|
|
208
|
-
return {
|
|
209
|
-
totalFound: quickResults.length,
|
|
210
|
-
threshold: '2%',
|
|
211
|
-
};
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// ===== Test 4: WebSocket Connection =====
|
|
215
|
-
console.log('\n═══════════════════════════════════════════════════════════════');
|
|
216
|
-
console.log('Test 4: WebSocket Connection and Orderbook Updates');
|
|
217
|
-
console.log('═══════════════════════════════════════════════════════════════\n');
|
|
218
|
-
|
|
219
|
-
// Select the highest volume market for WebSocket testing (more likely to have activity)
|
|
220
|
-
const sortedByVolume = [...scanResults].sort((a, b) => b.volume24h - a.volume24h);
|
|
221
|
-
if (!testMarket && sortedByVolume.length > 0) {
|
|
222
|
-
// Prefer markets with good orderbook depth
|
|
223
|
-
const goodMarket = sortedByVolume.find(r => r.availableSize > 50);
|
|
224
|
-
testMarket = goodMarket?.market || sortedByVolume[0].market;
|
|
225
|
-
const selectedResult = goodMarket || sortedByVolume[0];
|
|
226
|
-
console.log(`ℹ️ Selected highest volume market for WebSocket test:`);
|
|
227
|
-
console.log(` ${testMarket.name.slice(0, 50)}`);
|
|
228
|
-
console.log(` Volume 24h: $${selectedResult.volume24h.toLocaleString()}`);
|
|
229
|
-
console.log(` Available Size: ${selectedResult.availableSize.toFixed(2)}\n`);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (!testMarket) {
|
|
233
|
-
console.log('⚠️ Skipping WebSocket tests - no markets available');
|
|
234
|
-
recordTest('WebSocket test (skipped)', false, 0, 'No markets available for testing');
|
|
235
|
-
} else {
|
|
236
|
-
let wsConnected = false;
|
|
237
|
-
let orderbookUpdates = 0;
|
|
238
|
-
let receivedOpportunity = false;
|
|
239
|
-
|
|
240
|
-
// Set up event listeners - listen for orderbookUpdate (emitted on every book update)
|
|
241
|
-
arbService.on('orderbookUpdate', () => {
|
|
242
|
-
orderbookUpdates++;
|
|
243
|
-
if (orderbookUpdates === 1) {
|
|
244
|
-
console.log(` 📈 First orderbook update received!`);
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
arbService.on('opportunity', (opp) => {
|
|
249
|
-
receivedOpportunity = true;
|
|
250
|
-
console.log(` 📊 Opportunity detected: ${opp.type} arb, +${opp.profitPercent.toFixed(2)}%`);
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
arbService.on('error', (error) => {
|
|
254
|
-
console.log(` ⚠️ Error: ${error.message}`);
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
// Wait for orderbookUpdate events (not opportunity which is rare)
|
|
258
|
-
const waitForOrderbookUpdate = (): Promise<number> => {
|
|
259
|
-
return new Promise((resolve) => {
|
|
260
|
-
// Check immediately if we already have updates
|
|
261
|
-
if (orderbookUpdates > 0) {
|
|
262
|
-
resolve(orderbookUpdates);
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Poll for updates
|
|
267
|
-
const checkInterval = setInterval(() => {
|
|
268
|
-
if (orderbookUpdates > 0) {
|
|
269
|
-
clearInterval(checkInterval);
|
|
270
|
-
resolve(orderbookUpdates);
|
|
271
|
-
}
|
|
272
|
-
}, 500);
|
|
273
|
-
|
|
274
|
-
// Timeout after 30 seconds
|
|
275
|
-
setTimeout(() => {
|
|
276
|
-
clearInterval(checkInterval);
|
|
277
|
-
resolve(orderbookUpdates);
|
|
278
|
-
}, 30000);
|
|
279
|
-
});
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
await runTest('Start monitoring market via WebSocket', async () => {
|
|
283
|
-
console.log(` Monitoring: ${testMarket!.name.slice(0, 50)}...`);
|
|
284
|
-
|
|
285
|
-
await arbService.start(testMarket!);
|
|
286
|
-
wsConnected = true;
|
|
287
|
-
|
|
288
|
-
return { market: testMarket!.name.slice(0, 40) };
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
if (wsConnected) {
|
|
292
|
-
await runTest('WebSocket connection and orderbook updates', async () => {
|
|
293
|
-
console.log(' Waiting up to 30 seconds for orderbook updates...');
|
|
294
|
-
|
|
295
|
-
const updateCount = await waitForOrderbookUpdate();
|
|
296
|
-
|
|
297
|
-
// Also check the orderbook state directly
|
|
298
|
-
const orderbook = arbService.getOrderbook();
|
|
299
|
-
const hasYesData = orderbook.yesBids.length > 0 || orderbook.yesAsks.length > 0;
|
|
300
|
-
const hasNoData = orderbook.noBids.length > 0 || orderbook.noAsks.length > 0;
|
|
301
|
-
|
|
302
|
-
return {
|
|
303
|
-
connected: true,
|
|
304
|
-
orderbookUpdates: updateCount,
|
|
305
|
-
hasYesData,
|
|
306
|
-
hasNoData,
|
|
307
|
-
lastUpdate: orderbook.lastUpdate > 0 ? new Date(orderbook.lastUpdate).toISOString() : 'never',
|
|
308
|
-
note: updateCount > 0
|
|
309
|
-
? `Received ${updateCount} orderbook updates`
|
|
310
|
-
: 'No updates received (market may be inactive during test window)',
|
|
311
|
-
};
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
await runTest('Verify orderbook data populated', async () => {
|
|
315
|
-
const orderbook = arbService.getOrderbook();
|
|
316
|
-
|
|
317
|
-
// Check if orderbook has any data
|
|
318
|
-
const totalLevels = orderbook.yesBids.length + orderbook.yesAsks.length +
|
|
319
|
-
orderbook.noBids.length + orderbook.noAsks.length;
|
|
320
|
-
|
|
321
|
-
if (totalLevels === 0 && orderbookUpdates === 0) {
|
|
322
|
-
// If no updates received, this is expected
|
|
323
|
-
return {
|
|
324
|
-
status: 'no_data',
|
|
325
|
-
note: 'No orderbook data (market inactive or no WebSocket updates)',
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return {
|
|
330
|
-
status: 'populated',
|
|
331
|
-
yesBids: orderbook.yesBids.length,
|
|
332
|
-
yesAsks: orderbook.yesAsks.length,
|
|
333
|
-
noBids: orderbook.noBids.length,
|
|
334
|
-
noAsks: orderbook.noAsks.length,
|
|
335
|
-
lastUpdate: new Date(orderbook.lastUpdate).toISOString(),
|
|
336
|
-
};
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
await runTest('Verify service statistics', async () => {
|
|
340
|
-
const stats = arbService.getStats();
|
|
341
|
-
|
|
342
|
-
if (!stats) {
|
|
343
|
-
throw new Error('getStats() returned null/undefined');
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
const requiredStats = [
|
|
347
|
-
'opportunitiesDetected',
|
|
348
|
-
'executionsAttempted',
|
|
349
|
-
'executionsSucceeded',
|
|
350
|
-
'totalProfit',
|
|
351
|
-
'runningTimeMs',
|
|
352
|
-
];
|
|
353
|
-
|
|
354
|
-
for (const field of requiredStats) {
|
|
355
|
-
if (!(field in stats)) {
|
|
356
|
-
throw new Error(`Missing stats field: ${field}`);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
return {
|
|
361
|
-
opportunities: stats.opportunitiesDetected,
|
|
362
|
-
executions: `${stats.executionsSucceeded}/${stats.executionsAttempted}`,
|
|
363
|
-
profit: `$${stats.totalProfit.toFixed(2)}`,
|
|
364
|
-
runningTime: `${(stats.runningTimeMs / 1000).toFixed(1)}s`,
|
|
365
|
-
orderbookUpdatesReceived: orderbookUpdates,
|
|
366
|
-
};
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
await runTest('Stop monitoring and clean up', async () => {
|
|
370
|
-
await arbService.stop();
|
|
371
|
-
wsConnected = false;
|
|
372
|
-
|
|
373
|
-
return { stopped: true };
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// ===== Test Summary =====
|
|
379
|
-
console.log('\n╔════════════════════════════════════════════════════════════════╗');
|
|
380
|
-
console.log('║ Test Summary ║');
|
|
381
|
-
console.log('╚════════════════════════════════════════════════════════════════╝\n');
|
|
382
|
-
|
|
383
|
-
const totalTests = results.length;
|
|
384
|
-
const passedTests = results.filter(r => r.passed).length;
|
|
385
|
-
const failedTests = totalTests - passedTests;
|
|
386
|
-
|
|
387
|
-
console.log(`Total Tests: ${totalTests}`);
|
|
388
|
-
console.log(`Passed: ${passedTests} ✅`);
|
|
389
|
-
console.log(`Failed: ${failedTests} ${failedTests > 0 ? '❌' : ''}`);
|
|
390
|
-
console.log(`Success Rate: ${((passedTests / totalTests) * 100).toFixed(1)}%`);
|
|
391
|
-
|
|
392
|
-
if (failedTests > 0) {
|
|
393
|
-
console.log('\nFailed Tests:');
|
|
394
|
-
results.filter(r => !r.passed).forEach(r => {
|
|
395
|
-
console.log(` - ${r.name}`);
|
|
396
|
-
console.log(` ${r.error}`);
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
console.log('\n═══════════════════════════════════════════════════════════════\n');
|
|
401
|
-
|
|
402
|
-
// Exit with appropriate code
|
|
403
|
-
process.exit(failedTests > 0 ? 1 : 0);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// ===== Error Handling =====
|
|
407
|
-
|
|
408
|
-
main().catch((error) => {
|
|
409
|
-
console.error('\n❌ Fatal Error:', error.message);
|
|
410
|
-
console.error(error.stack);
|
|
411
|
-
process.exit(1);
|
|
412
|
-
});
|