pmxtjs 2.1.3 → 2.2.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/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/pmxt/client.js +2 -1
- package/dist/esm/pmxt/models.d.ts +16 -1
- package/dist/esm/pmxt/models.js +56 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -1
- package/dist/pmxt/client.js +2 -1
- package/dist/pmxt/models.d.ts +16 -1
- package/dist/pmxt/models.js +58 -0
- package/generated/package.json +1 -1
- package/generated/src/apis/DefaultApi.js +812 -0
- package/generated/src/apis/index.js +19 -0
- package/generated/src/index.js +21 -0
- package/generated/src/models/Balance.js +54 -0
- package/generated/src/models/BaseRequest.js +49 -0
- package/generated/src/models/BaseResponse.js +51 -0
- package/generated/src/models/CancelOrderRequest.js +53 -0
- package/generated/src/models/CreateOrder200Response.js +54 -0
- package/generated/src/models/CreateOrderParams.js +85 -0
- package/generated/src/models/CreateOrderRequest.js +54 -0
- package/generated/src/models/ErrorDetail.js +48 -0
- package/generated/src/models/ErrorResponse.js +51 -0
- package/generated/src/models/EventFetchParams.js +63 -0
- package/generated/src/models/ExchangeCredentials.js +59 -0
- package/generated/src/models/ExchangeCredentialsSignatureType.js +49 -0
- package/generated/src/models/ExecutionPriceResult.js +52 -0
- package/generated/src/models/FetchBalance200Response.js +54 -0
- package/generated/src/models/FetchEvents200Response.js +54 -0
- package/generated/src/models/FetchEventsRequest.js +52 -0
- package/generated/src/models/FetchMarkets200Response.js +54 -0
- package/generated/src/models/FetchMarketsRequest.js +52 -0
- package/generated/src/models/FetchOHLCV200Response.js +54 -0
- package/generated/src/models/FetchOHLCVRequest.js +54 -0
- package/generated/src/models/FetchOHLCVRequestArgsInner.js +56 -0
- package/generated/src/models/FetchOpenOrders200Response.js +54 -0
- package/generated/src/models/FetchOpenOrdersRequest.js +51 -0
- package/generated/src/models/FetchOrderBook200Response.js +54 -0
- package/generated/src/models/FetchOrderBookRequest.js +53 -0
- package/generated/src/models/FetchPositions200Response.js +54 -0
- package/generated/src/models/FetchPositionsRequest.js +51 -0
- package/generated/src/models/FetchTrades200Response.js +54 -0
- package/generated/src/models/FetchTradesRequest.js +54 -0
- package/generated/src/models/FilterEventsRequest.js +54 -0
- package/generated/src/models/FilterEventsRequestArgsInner.js +67 -0
- package/generated/src/models/FilterMarketsRequest.js +54 -0
- package/generated/src/models/FilterMarketsRequestArgsInner.js +67 -0
- package/generated/src/models/FilterMarketsRequestArgsInnerOneOf.js +47 -0
- package/generated/src/models/GetExecutionPrice200Response.js +53 -0
- package/generated/src/models/GetExecutionPriceDetailed200Response.js +54 -0
- package/generated/src/models/GetExecutionPriceRequest.js +54 -0
- package/generated/src/models/GetExecutionPriceRequestArgsInner.js +62 -0
- package/generated/src/models/HealthCheck200Response.js +50 -0
- package/generated/src/models/HistoryFilterParams.js +68 -0
- package/generated/src/models/MarketFilterParams.js +79 -0
- package/generated/src/models/MarketOutcome.js +56 -0
- package/generated/src/models/Order.js +95 -0
- package/generated/src/models/OrderBook.js +53 -0
- package/generated/src/models/OrderLevel.js +50 -0
- package/generated/src/models/Position.js +62 -0
- package/generated/src/models/PriceCandle.js +58 -0
- package/generated/src/models/Trade.js +65 -0
- package/generated/src/models/UnifiedEvent.js +65 -0
- package/generated/src/models/UnifiedMarket.js +81 -0
- package/generated/src/models/WatchOrderBookRequest.js +54 -0
- package/generated/src/models/WatchOrderBookRequestArgsInner.js +49 -0
- package/generated/src/models/WatchPricesRequest.js +53 -0
- package/generated/src/models/WatchTradesRequest.js +54 -0
- package/generated/src/models/WatchUserPositionsRequest.js +49 -0
- package/generated/src/models/index.js +73 -0
- package/generated/src/runtime.js +338 -0
- package/index.ts +1 -0
- package/package.json +2 -2
- package/pmxt/client.js +957 -0
- package/pmxt/client.ts +2 -1
- package/pmxt/models.js +60 -0
- package/pmxt/models.ts +60 -1
- package/pmxt/server-manager.js +204 -0
package/pmxt/client.js
ADDED
|
@@ -0,0 +1,957 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Exchange client implementations.
|
|
4
|
+
*
|
|
5
|
+
* This module provides clean, TypeScript-friendly wrappers around the auto-generated
|
|
6
|
+
* OpenAPI client, matching the Python API exactly.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.Limitless = exports.Kalshi = exports.Polymarket = exports.Exchange = void 0;
|
|
10
|
+
const index_js_1 = require("../generated/src/index.js");
|
|
11
|
+
const models_js_1 = require("./models.js");
|
|
12
|
+
const server_manager_js_1 = require("./server-manager.js");
|
|
13
|
+
// Converter functions
|
|
14
|
+
function convertMarket(raw) {
|
|
15
|
+
const outcomes = (raw.outcomes || []).map((o) => ({
|
|
16
|
+
outcomeId: o.outcomeId,
|
|
17
|
+
label: o.label,
|
|
18
|
+
price: o.price,
|
|
19
|
+
priceChange24h: o.priceChange24h,
|
|
20
|
+
metadata: o.metadata,
|
|
21
|
+
}));
|
|
22
|
+
const convertOutcome = (o) => o ? ({
|
|
23
|
+
outcomeId: o.outcomeId,
|
|
24
|
+
label: o.label,
|
|
25
|
+
price: o.price,
|
|
26
|
+
priceChange24h: o.priceChange24h,
|
|
27
|
+
metadata: o.metadata,
|
|
28
|
+
}) : undefined;
|
|
29
|
+
return {
|
|
30
|
+
marketId: raw.marketId,
|
|
31
|
+
title: raw.title,
|
|
32
|
+
outcomes,
|
|
33
|
+
volume24h: raw.volume24h || 0,
|
|
34
|
+
liquidity: raw.liquidity || 0,
|
|
35
|
+
url: raw.url,
|
|
36
|
+
description: raw.description,
|
|
37
|
+
resolutionDate: raw.resolutionDate ? new Date(raw.resolutionDate) : undefined,
|
|
38
|
+
volume: raw.volume,
|
|
39
|
+
openInterest: raw.openInterest,
|
|
40
|
+
image: raw.image,
|
|
41
|
+
category: raw.category,
|
|
42
|
+
tags: raw.tags,
|
|
43
|
+
yes: convertOutcome(raw.yes),
|
|
44
|
+
no: convertOutcome(raw.no),
|
|
45
|
+
up: convertOutcome(raw.up),
|
|
46
|
+
down: convertOutcome(raw.down),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function convertCandle(raw) {
|
|
50
|
+
return {
|
|
51
|
+
timestamp: raw.timestamp,
|
|
52
|
+
open: raw.open,
|
|
53
|
+
high: raw.high,
|
|
54
|
+
low: raw.low,
|
|
55
|
+
close: raw.close,
|
|
56
|
+
volume: raw.volume,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function convertOrderBook(raw) {
|
|
60
|
+
const bids = (raw.bids || []).map((b) => ({
|
|
61
|
+
price: b.price,
|
|
62
|
+
size: b.size,
|
|
63
|
+
}));
|
|
64
|
+
const asks = (raw.asks || []).map((a) => ({
|
|
65
|
+
price: a.price,
|
|
66
|
+
size: a.size,
|
|
67
|
+
}));
|
|
68
|
+
return {
|
|
69
|
+
bids,
|
|
70
|
+
asks,
|
|
71
|
+
timestamp: raw.timestamp,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function convertTrade(raw) {
|
|
75
|
+
return {
|
|
76
|
+
id: raw.id,
|
|
77
|
+
timestamp: raw.timestamp,
|
|
78
|
+
price: raw.price,
|
|
79
|
+
amount: raw.amount,
|
|
80
|
+
side: raw.side || "unknown",
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function convertOrder(raw) {
|
|
84
|
+
return {
|
|
85
|
+
id: raw.id,
|
|
86
|
+
marketId: raw.marketId,
|
|
87
|
+
outcomeId: raw.outcomeId,
|
|
88
|
+
side: raw.side,
|
|
89
|
+
type: raw.type,
|
|
90
|
+
amount: raw.amount,
|
|
91
|
+
status: raw.status,
|
|
92
|
+
filled: raw.filled,
|
|
93
|
+
remaining: raw.remaining,
|
|
94
|
+
timestamp: raw.timestamp,
|
|
95
|
+
price: raw.price,
|
|
96
|
+
fee: raw.fee,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function convertPosition(raw) {
|
|
100
|
+
return {
|
|
101
|
+
marketId: raw.marketId,
|
|
102
|
+
outcomeId: raw.outcomeId,
|
|
103
|
+
outcomeLabel: raw.outcomeLabel,
|
|
104
|
+
size: raw.size,
|
|
105
|
+
entryPrice: raw.entryPrice,
|
|
106
|
+
currentPrice: raw.currentPrice,
|
|
107
|
+
unrealizedPnL: raw.unrealizedPnL,
|
|
108
|
+
realizedPnL: raw.realizedPnL,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function convertBalance(raw) {
|
|
112
|
+
return {
|
|
113
|
+
currency: raw.currency,
|
|
114
|
+
total: raw.total,
|
|
115
|
+
available: raw.available,
|
|
116
|
+
locked: raw.locked,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function convertEvent(raw) {
|
|
120
|
+
const markets = models_js_1.MarketList.from((raw.markets || []).map(convertMarket));
|
|
121
|
+
return {
|
|
122
|
+
id: raw.id,
|
|
123
|
+
title: raw.title,
|
|
124
|
+
description: raw.description,
|
|
125
|
+
slug: raw.slug,
|
|
126
|
+
markets,
|
|
127
|
+
url: raw.url,
|
|
128
|
+
image: raw.image,
|
|
129
|
+
category: raw.category,
|
|
130
|
+
tags: raw.tags,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Base class for prediction market exchanges.
|
|
135
|
+
*
|
|
136
|
+
* This provides a unified interface for interacting with different
|
|
137
|
+
* prediction market platforms (Polymarket, Kalshi, etc.).
|
|
138
|
+
*/
|
|
139
|
+
class Exchange {
|
|
140
|
+
constructor(exchangeName, options = {}) {
|
|
141
|
+
this.exchangeName = exchangeName.toLowerCase();
|
|
142
|
+
this.apiKey = options.apiKey;
|
|
143
|
+
this.privateKey = options.privateKey;
|
|
144
|
+
this.proxyAddress = options.proxyAddress;
|
|
145
|
+
this.signatureType = options.signatureType;
|
|
146
|
+
let baseUrl = options.baseUrl || "http://localhost:3847";
|
|
147
|
+
const autoStartServer = options.autoStartServer !== false;
|
|
148
|
+
// Initialize server manager
|
|
149
|
+
this.serverManager = new server_manager_js_1.ServerManager({ baseUrl });
|
|
150
|
+
// Configure the API client with the initial base URL (will be updated if port changes)
|
|
151
|
+
this.config = new index_js_1.Configuration({ basePath: baseUrl });
|
|
152
|
+
this.api = new index_js_1.DefaultApi(this.config);
|
|
153
|
+
// Initialize the server connection asynchronously
|
|
154
|
+
this.initPromise = this.initializeServer(autoStartServer);
|
|
155
|
+
}
|
|
156
|
+
async initializeServer(autoStartServer) {
|
|
157
|
+
if (autoStartServer) {
|
|
158
|
+
try {
|
|
159
|
+
await this.serverManager.ensureServerRunning();
|
|
160
|
+
// Get the actual port the server is running on
|
|
161
|
+
// (may differ from default if default port was busy)
|
|
162
|
+
const actualPort = this.serverManager.getRunningPort();
|
|
163
|
+
const newBaseUrl = `http://localhost:${actualPort}`;
|
|
164
|
+
const accessToken = this.serverManager.getAccessToken();
|
|
165
|
+
const headers = {};
|
|
166
|
+
if (accessToken) {
|
|
167
|
+
headers['x-pmxt-access-token'] = accessToken;
|
|
168
|
+
}
|
|
169
|
+
// Update API client with actual base URL
|
|
170
|
+
this.config = new index_js_1.Configuration({
|
|
171
|
+
basePath: newBaseUrl,
|
|
172
|
+
headers
|
|
173
|
+
});
|
|
174
|
+
this.api = new index_js_1.DefaultApi(this.config);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
throw new Error(`Failed to start PMXT server: ${error}\n\n` +
|
|
178
|
+
`Please ensure 'pmxt-core' is installed: npm install -g pmxt-core\n` +
|
|
179
|
+
`Or start the server manually: pmxt-server`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
handleResponse(response) {
|
|
184
|
+
if (!response.success) {
|
|
185
|
+
const error = response.error || {};
|
|
186
|
+
throw new Error(error.message || "Unknown error");
|
|
187
|
+
}
|
|
188
|
+
return response.data;
|
|
189
|
+
}
|
|
190
|
+
getCredentials() {
|
|
191
|
+
if (!this.apiKey && !this.privateKey) {
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
apiKey: this.apiKey,
|
|
196
|
+
privateKey: this.privateKey,
|
|
197
|
+
funderAddress: this.proxyAddress,
|
|
198
|
+
signatureType: this.signatureType,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
// Market Data Methods
|
|
202
|
+
/**
|
|
203
|
+
* Get active markets from the exchange.
|
|
204
|
+
*
|
|
205
|
+
* @param params - Optional filter parameters
|
|
206
|
+
* @returns List of unified markets
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```typescript
|
|
210
|
+
* const markets = await exchange.fetchMarkets({ limit: 20, sort: "volume" });
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
async fetchMarkets(params) {
|
|
214
|
+
await this.initPromise;
|
|
215
|
+
try {
|
|
216
|
+
const args = [];
|
|
217
|
+
if (params) {
|
|
218
|
+
args.push(params);
|
|
219
|
+
}
|
|
220
|
+
const requestBody = {
|
|
221
|
+
args,
|
|
222
|
+
credentials: this.getCredentials()
|
|
223
|
+
};
|
|
224
|
+
const response = await this.api.fetchMarkets({
|
|
225
|
+
exchange: this.exchangeName,
|
|
226
|
+
fetchMarketsRequest: requestBody,
|
|
227
|
+
});
|
|
228
|
+
const data = this.handleResponse(response);
|
|
229
|
+
return data.map(convertMarket);
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
throw new Error(`Failed to fetch markets: ${error}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Get historical price candles.
|
|
237
|
+
*
|
|
238
|
+
* @param outcomeId - Outcome ID (from market.outcomes[].outcomeId)
|
|
239
|
+
* @param params - History filter parameters
|
|
240
|
+
* @returns List of price candles
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* const markets = await exchange.fetchMarkets({ query: "Trump" });
|
|
245
|
+
* const outcomeId = markets[0].outcomes[0].outcomeId;
|
|
246
|
+
* const candles = await exchange.fetchOHLCV(outcomeId, {
|
|
247
|
+
* resolution: "1h",
|
|
248
|
+
* limit: 100
|
|
249
|
+
* });
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
async fetchOHLCV(outcomeId, params) {
|
|
253
|
+
await this.initPromise;
|
|
254
|
+
try {
|
|
255
|
+
const paramsDict = { resolution: params.resolution };
|
|
256
|
+
if (params.start) {
|
|
257
|
+
paramsDict.start = params.start.toISOString();
|
|
258
|
+
}
|
|
259
|
+
if (params.end) {
|
|
260
|
+
paramsDict.end = params.end.toISOString();
|
|
261
|
+
}
|
|
262
|
+
if (params.limit) {
|
|
263
|
+
paramsDict.limit = params.limit;
|
|
264
|
+
}
|
|
265
|
+
const requestBody = {
|
|
266
|
+
args: [outcomeId, paramsDict],
|
|
267
|
+
credentials: this.getCredentials()
|
|
268
|
+
};
|
|
269
|
+
const response = await this.api.fetchOHLCV({
|
|
270
|
+
exchange: this.exchangeName,
|
|
271
|
+
fetchOHLCVRequest: requestBody,
|
|
272
|
+
});
|
|
273
|
+
const data = this.handleResponse(response);
|
|
274
|
+
return data.map(convertCandle);
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
throw new Error(`Failed to fetch OHLCV: ${error}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Get current order book for an outcome.
|
|
282
|
+
*
|
|
283
|
+
* @param outcomeId - Outcome ID
|
|
284
|
+
* @returns Current order book
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```typescript
|
|
288
|
+
* const orderBook = await exchange.fetchOrderBook(outcomeId);
|
|
289
|
+
* console.log(`Best bid: ${orderBook.bids[0].price}`);
|
|
290
|
+
* console.log(`Best ask: ${orderBook.asks[0].price}`);
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
async fetchOrderBook(outcomeId) {
|
|
294
|
+
await this.initPromise;
|
|
295
|
+
try {
|
|
296
|
+
const requestBody = {
|
|
297
|
+
args: [outcomeId],
|
|
298
|
+
credentials: this.getCredentials()
|
|
299
|
+
};
|
|
300
|
+
const response = await this.api.fetchOrderBook({
|
|
301
|
+
exchange: this.exchangeName,
|
|
302
|
+
fetchOrderBookRequest: requestBody,
|
|
303
|
+
});
|
|
304
|
+
const data = this.handleResponse(response);
|
|
305
|
+
return convertOrderBook(data);
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
throw new Error(`Failed to fetch order book: ${error}`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get trade history for an outcome.
|
|
313
|
+
*
|
|
314
|
+
* Note: Polymarket requires API key.
|
|
315
|
+
*
|
|
316
|
+
* @param outcomeId - Outcome ID
|
|
317
|
+
* @param params - History filter parameters
|
|
318
|
+
* @returns List of trades
|
|
319
|
+
*/
|
|
320
|
+
async fetchTrades(outcomeId, params) {
|
|
321
|
+
await this.initPromise;
|
|
322
|
+
try {
|
|
323
|
+
const paramsDict = { resolution: params.resolution };
|
|
324
|
+
if (params.limit) {
|
|
325
|
+
paramsDict.limit = params.limit;
|
|
326
|
+
}
|
|
327
|
+
const requestBody = {
|
|
328
|
+
args: [outcomeId, paramsDict],
|
|
329
|
+
credentials: this.getCredentials()
|
|
330
|
+
};
|
|
331
|
+
const response = await this.api.fetchTrades({
|
|
332
|
+
exchange: this.exchangeName,
|
|
333
|
+
fetchTradesRequest: requestBody,
|
|
334
|
+
});
|
|
335
|
+
const data = this.handleResponse(response);
|
|
336
|
+
return data.map(convertTrade);
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
throw new Error(`Failed to fetch trades: ${error}`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// WebSocket Streaming Methods
|
|
343
|
+
/**
|
|
344
|
+
* Watch real-time order book updates via WebSocket.
|
|
345
|
+
*
|
|
346
|
+
* Returns a promise that resolves with the next order book update.
|
|
347
|
+
* Call repeatedly in a loop to stream updates (CCXT Pro pattern).
|
|
348
|
+
*
|
|
349
|
+
* @param outcomeId - Outcome ID to watch
|
|
350
|
+
* @param limit - Optional depth limit for order book
|
|
351
|
+
* @returns Next order book update
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ```typescript
|
|
355
|
+
* // Stream order book updates
|
|
356
|
+
* while (true) {
|
|
357
|
+
* const orderBook = await exchange.watchOrderBook(outcomeId);
|
|
358
|
+
* console.log(`Best bid: ${orderBook.bids[0].price}`);
|
|
359
|
+
* console.log(`Best ask: ${orderBook.asks[0].price}`);
|
|
360
|
+
* }
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
async watchOrderBook(outcomeId, limit) {
|
|
364
|
+
await this.initPromise;
|
|
365
|
+
try {
|
|
366
|
+
const args = [outcomeId];
|
|
367
|
+
if (limit !== undefined) {
|
|
368
|
+
args.push(limit);
|
|
369
|
+
}
|
|
370
|
+
const requestBody = {
|
|
371
|
+
args,
|
|
372
|
+
credentials: this.getCredentials()
|
|
373
|
+
};
|
|
374
|
+
const response = await this.api.watchOrderBook({
|
|
375
|
+
exchange: this.exchangeName,
|
|
376
|
+
watchOrderBookRequest: requestBody,
|
|
377
|
+
});
|
|
378
|
+
const data = this.handleResponse(response);
|
|
379
|
+
return convertOrderBook(data);
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
throw new Error(`Failed to watch order book: ${error}`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Watch real-time trade updates via WebSocket.
|
|
387
|
+
*
|
|
388
|
+
* Returns a promise that resolves with the next trade(s).
|
|
389
|
+
* Call repeatedly in a loop to stream updates (CCXT Pro pattern).
|
|
390
|
+
*
|
|
391
|
+
* @param outcomeId - Outcome ID to watch
|
|
392
|
+
* @param since - Optional timestamp to filter trades from
|
|
393
|
+
* @param limit - Optional limit for number of trades
|
|
394
|
+
* @returns Next trade update(s)
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* ```typescript
|
|
398
|
+
* // Stream trade updates
|
|
399
|
+
* while (true) {
|
|
400
|
+
* const trades = await exchange.watchTrades(outcomeId);
|
|
401
|
+
* for (const trade of trades) {
|
|
402
|
+
* console.log(`Trade: ${trade.price} @ ${trade.amount}`);
|
|
403
|
+
* }
|
|
404
|
+
* }
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
async watchTrades(outcomeId, since, limit) {
|
|
408
|
+
await this.initPromise;
|
|
409
|
+
try {
|
|
410
|
+
const args = [outcomeId];
|
|
411
|
+
if (since !== undefined) {
|
|
412
|
+
args.push(since);
|
|
413
|
+
}
|
|
414
|
+
if (limit !== undefined) {
|
|
415
|
+
args.push(limit);
|
|
416
|
+
}
|
|
417
|
+
const requestBody = {
|
|
418
|
+
args,
|
|
419
|
+
credentials: this.getCredentials()
|
|
420
|
+
};
|
|
421
|
+
const response = await this.api.watchTrades({
|
|
422
|
+
exchange: this.exchangeName,
|
|
423
|
+
watchTradesRequest: requestBody,
|
|
424
|
+
});
|
|
425
|
+
const data = this.handleResponse(response);
|
|
426
|
+
return data.map(convertTrade);
|
|
427
|
+
}
|
|
428
|
+
catch (error) {
|
|
429
|
+
throw new Error(`Failed to watch trades: ${error}`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// Trading Methods (require authentication)
|
|
433
|
+
/**
|
|
434
|
+
* Create a new order.
|
|
435
|
+
*
|
|
436
|
+
* @param params - Order parameters
|
|
437
|
+
* @returns Created order
|
|
438
|
+
*
|
|
439
|
+
* @example
|
|
440
|
+
* ```typescript
|
|
441
|
+
* const order = await exchange.createOrder({
|
|
442
|
+
* marketId: "663583",
|
|
443
|
+
* outcomeId: "10991849...",
|
|
444
|
+
* side: "buy",
|
|
445
|
+
* type: "limit",
|
|
446
|
+
* amount: 10,
|
|
447
|
+
* price: 0.55
|
|
448
|
+
* });
|
|
449
|
+
* ```
|
|
450
|
+
*/
|
|
451
|
+
async createOrder(params) {
|
|
452
|
+
await this.initPromise;
|
|
453
|
+
try {
|
|
454
|
+
const paramsDict = {
|
|
455
|
+
marketId: params.marketId,
|
|
456
|
+
outcomeId: params.outcomeId,
|
|
457
|
+
side: params.side,
|
|
458
|
+
type: params.type,
|
|
459
|
+
amount: params.amount,
|
|
460
|
+
};
|
|
461
|
+
if (params.price !== undefined) {
|
|
462
|
+
paramsDict.price = params.price;
|
|
463
|
+
}
|
|
464
|
+
if (params.fee !== undefined) {
|
|
465
|
+
paramsDict.fee = params.fee;
|
|
466
|
+
}
|
|
467
|
+
const requestBody = {
|
|
468
|
+
args: [paramsDict],
|
|
469
|
+
credentials: this.getCredentials()
|
|
470
|
+
};
|
|
471
|
+
const response = await this.api.createOrder({
|
|
472
|
+
exchange: this.exchangeName,
|
|
473
|
+
createOrderRequest: requestBody,
|
|
474
|
+
});
|
|
475
|
+
const data = this.handleResponse(response);
|
|
476
|
+
return convertOrder(data);
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
throw new Error(`Failed to create order: ${error}`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Cancel an open order.
|
|
484
|
+
*
|
|
485
|
+
* @param orderId - Order ID to cancel
|
|
486
|
+
* @returns Cancelled order
|
|
487
|
+
*/
|
|
488
|
+
async cancelOrder(orderId) {
|
|
489
|
+
await this.initPromise;
|
|
490
|
+
try {
|
|
491
|
+
const requestBody = {
|
|
492
|
+
args: [orderId],
|
|
493
|
+
credentials: this.getCredentials()
|
|
494
|
+
};
|
|
495
|
+
const response = await this.api.cancelOrder({
|
|
496
|
+
exchange: this.exchangeName,
|
|
497
|
+
cancelOrderRequest: requestBody,
|
|
498
|
+
});
|
|
499
|
+
const data = this.handleResponse(response);
|
|
500
|
+
return convertOrder(data);
|
|
501
|
+
}
|
|
502
|
+
catch (error) {
|
|
503
|
+
throw new Error(`Failed to cancel order: ${error}`);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Get details of a specific order.
|
|
508
|
+
*
|
|
509
|
+
* @param orderId - Order ID
|
|
510
|
+
* @returns Order details
|
|
511
|
+
*/
|
|
512
|
+
async fetchOrder(orderId) {
|
|
513
|
+
await this.initPromise;
|
|
514
|
+
try {
|
|
515
|
+
const requestBody = {
|
|
516
|
+
args: [orderId],
|
|
517
|
+
credentials: this.getCredentials()
|
|
518
|
+
};
|
|
519
|
+
const response = await this.api.fetchOrder({
|
|
520
|
+
exchange: this.exchangeName,
|
|
521
|
+
cancelOrderRequest: requestBody,
|
|
522
|
+
});
|
|
523
|
+
const data = this.handleResponse(response);
|
|
524
|
+
return convertOrder(data);
|
|
525
|
+
}
|
|
526
|
+
catch (error) {
|
|
527
|
+
throw new Error(`Failed to fetch order: ${error}`);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Get all open orders, optionally filtered by market.
|
|
532
|
+
*
|
|
533
|
+
* @param marketId - Optional market ID to filter by
|
|
534
|
+
* @returns List of open orders
|
|
535
|
+
*/
|
|
536
|
+
async fetchOpenOrders(marketId) {
|
|
537
|
+
await this.initPromise;
|
|
538
|
+
try {
|
|
539
|
+
const args = [];
|
|
540
|
+
if (marketId) {
|
|
541
|
+
args.push(marketId);
|
|
542
|
+
}
|
|
543
|
+
const requestBody = {
|
|
544
|
+
args,
|
|
545
|
+
credentials: this.getCredentials()
|
|
546
|
+
};
|
|
547
|
+
const response = await this.api.fetchOpenOrders({
|
|
548
|
+
exchange: this.exchangeName,
|
|
549
|
+
fetchOpenOrdersRequest: requestBody,
|
|
550
|
+
});
|
|
551
|
+
const data = this.handleResponse(response);
|
|
552
|
+
return data.map(convertOrder);
|
|
553
|
+
}
|
|
554
|
+
catch (error) {
|
|
555
|
+
throw new Error(`Failed to fetch open orders: ${error}`);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
// Account Methods
|
|
559
|
+
/**
|
|
560
|
+
* Get current positions across all markets.
|
|
561
|
+
*
|
|
562
|
+
* @returns List of positions
|
|
563
|
+
*/
|
|
564
|
+
async fetchPositions() {
|
|
565
|
+
await this.initPromise;
|
|
566
|
+
try {
|
|
567
|
+
const requestBody = {
|
|
568
|
+
args: [],
|
|
569
|
+
credentials: this.getCredentials()
|
|
570
|
+
};
|
|
571
|
+
const response = await this.api.fetchPositions({
|
|
572
|
+
exchange: this.exchangeName,
|
|
573
|
+
fetchPositionsRequest: requestBody,
|
|
574
|
+
});
|
|
575
|
+
const data = this.handleResponse(response);
|
|
576
|
+
return data.map(convertPosition);
|
|
577
|
+
}
|
|
578
|
+
catch (error) {
|
|
579
|
+
throw new Error(`Failed to fetch positions: ${error}`);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Get account balance.
|
|
584
|
+
*
|
|
585
|
+
* @returns List of balances (by currency)
|
|
586
|
+
*/
|
|
587
|
+
async fetchBalance() {
|
|
588
|
+
await this.initPromise;
|
|
589
|
+
try {
|
|
590
|
+
const requestBody = {
|
|
591
|
+
args: [],
|
|
592
|
+
credentials: this.getCredentials()
|
|
593
|
+
};
|
|
594
|
+
const response = await this.api.fetchBalance({
|
|
595
|
+
exchange: this.exchangeName,
|
|
596
|
+
fetchPositionsRequest: requestBody,
|
|
597
|
+
});
|
|
598
|
+
const data = this.handleResponse(response);
|
|
599
|
+
return data.map(convertBalance);
|
|
600
|
+
}
|
|
601
|
+
catch (error) {
|
|
602
|
+
throw new Error(`Failed to fetch balance: ${error}`);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Calculate the average execution price for a given amount by walking the order book.
|
|
607
|
+
* Uses the sidecar server for calculation to ensure consistency.
|
|
608
|
+
*
|
|
609
|
+
* @param orderBook - The current order book
|
|
610
|
+
* @param side - 'buy' or 'sell'
|
|
611
|
+
* @param amount - The amount to execute
|
|
612
|
+
* @returns The volume-weighted average price, or 0 if insufficient liquidity
|
|
613
|
+
*/
|
|
614
|
+
async getExecutionPrice(orderBook, side, amount) {
|
|
615
|
+
const result = await this.getExecutionPriceDetailed(orderBook, side, amount);
|
|
616
|
+
return result.fullyFilled ? result.price : 0;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Calculate detailed execution price information.
|
|
620
|
+
* Uses the sidecar server for calculation to ensure consistency.
|
|
621
|
+
*
|
|
622
|
+
* @param orderBook - The current order book
|
|
623
|
+
* @param side - 'buy' or 'sell'
|
|
624
|
+
* @param amount - The amount to execute
|
|
625
|
+
* @returns Detailed execution result
|
|
626
|
+
*/
|
|
627
|
+
async getExecutionPriceDetailed(orderBook, side, amount) {
|
|
628
|
+
await this.initPromise;
|
|
629
|
+
try {
|
|
630
|
+
const body = {
|
|
631
|
+
args: [orderBook, side, amount]
|
|
632
|
+
};
|
|
633
|
+
const credentials = this.getCredentials();
|
|
634
|
+
if (credentials) {
|
|
635
|
+
body.credentials = credentials;
|
|
636
|
+
}
|
|
637
|
+
const url = `${this.config.basePath}/api/${this.exchangeName}/getExecutionPriceDetailed`;
|
|
638
|
+
const response = await fetch(url, {
|
|
639
|
+
method: 'POST',
|
|
640
|
+
headers: {
|
|
641
|
+
'Content-Type': 'application/json',
|
|
642
|
+
...this.config.headers
|
|
643
|
+
},
|
|
644
|
+
body: JSON.stringify(body)
|
|
645
|
+
});
|
|
646
|
+
if (!response.ok) {
|
|
647
|
+
const error = await response.json().catch(() => ({}));
|
|
648
|
+
throw new Error(error.error?.message || response.statusText);
|
|
649
|
+
}
|
|
650
|
+
const json = await response.json();
|
|
651
|
+
return this.handleResponse(json);
|
|
652
|
+
}
|
|
653
|
+
catch (error) {
|
|
654
|
+
throw new Error(`Failed to get execution price: ${error}`);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
// ----------------------------------------------------------------------------
|
|
658
|
+
// Filtering Methods
|
|
659
|
+
// ----------------------------------------------------------------------------
|
|
660
|
+
/**
|
|
661
|
+
* Filter markets based on criteria or custom function.
|
|
662
|
+
*
|
|
663
|
+
* @param markets - Array of markets to filter
|
|
664
|
+
* @param criteria - Filter criteria object, string (simple text search), or predicate function
|
|
665
|
+
* @returns Filtered array of markets
|
|
666
|
+
*
|
|
667
|
+
* @example Simple text search
|
|
668
|
+
* api.filterMarkets(markets, 'Trump')
|
|
669
|
+
*
|
|
670
|
+
* @example Advanced filtering
|
|
671
|
+
* api.filterMarkets(markets, {
|
|
672
|
+
* text: 'Trump',
|
|
673
|
+
* searchIn: ['title', 'tags'],
|
|
674
|
+
* volume24h: { min: 10000 },
|
|
675
|
+
* category: 'Politics',
|
|
676
|
+
* price: { outcome: 'yes', max: 0.5 }
|
|
677
|
+
* })
|
|
678
|
+
*
|
|
679
|
+
* @example Custom predicate
|
|
680
|
+
* api.filterMarkets(markets, m => m.liquidity > 5000 && m.yes?.price < 0.3)
|
|
681
|
+
*/
|
|
682
|
+
filterMarkets(markets, criteria) {
|
|
683
|
+
// Handle predicate function
|
|
684
|
+
if (typeof criteria === 'function') {
|
|
685
|
+
return markets.filter(criteria);
|
|
686
|
+
}
|
|
687
|
+
// Handle simple string search
|
|
688
|
+
if (typeof criteria === 'string') {
|
|
689
|
+
const lowerQuery = criteria.toLowerCase();
|
|
690
|
+
return markets.filter(m => m.title.toLowerCase().includes(lowerQuery));
|
|
691
|
+
}
|
|
692
|
+
// Handle criteria object
|
|
693
|
+
return markets.filter(market => {
|
|
694
|
+
// Text search
|
|
695
|
+
if (criteria.text) {
|
|
696
|
+
const lowerQuery = criteria.text.toLowerCase();
|
|
697
|
+
const searchIn = criteria.searchIn || ['title'];
|
|
698
|
+
let textMatch = false;
|
|
699
|
+
for (const field of searchIn) {
|
|
700
|
+
if (field === 'title' && market.title?.toLowerCase().includes(lowerQuery)) {
|
|
701
|
+
textMatch = true;
|
|
702
|
+
break;
|
|
703
|
+
}
|
|
704
|
+
if (field === 'description' && market.description?.toLowerCase().includes(lowerQuery)) {
|
|
705
|
+
textMatch = true;
|
|
706
|
+
break;
|
|
707
|
+
}
|
|
708
|
+
if (field === 'category' && market.category?.toLowerCase().includes(lowerQuery)) {
|
|
709
|
+
textMatch = true;
|
|
710
|
+
break;
|
|
711
|
+
}
|
|
712
|
+
if (field === 'tags' && market.tags?.some(tag => tag.toLowerCase().includes(lowerQuery))) {
|
|
713
|
+
textMatch = true;
|
|
714
|
+
break;
|
|
715
|
+
}
|
|
716
|
+
if (field === 'outcomes' && market.outcomes?.some(o => o.label.toLowerCase().includes(lowerQuery))) {
|
|
717
|
+
textMatch = true;
|
|
718
|
+
break;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
if (!textMatch)
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
// Category filter
|
|
725
|
+
if (criteria.category && market.category !== criteria.category) {
|
|
726
|
+
return false;
|
|
727
|
+
}
|
|
728
|
+
// Tags filter (match ANY of the provided tags)
|
|
729
|
+
if (criteria.tags && criteria.tags.length > 0) {
|
|
730
|
+
const hasMatchingTag = criteria.tags.some(tag => market.tags?.some(marketTag => marketTag.toLowerCase() === tag.toLowerCase()));
|
|
731
|
+
if (!hasMatchingTag)
|
|
732
|
+
return false;
|
|
733
|
+
}
|
|
734
|
+
// Volume24h filter
|
|
735
|
+
if (criteria.volume24h) {
|
|
736
|
+
if (criteria.volume24h.min !== undefined && market.volume24h < criteria.volume24h.min) {
|
|
737
|
+
return false;
|
|
738
|
+
}
|
|
739
|
+
if (criteria.volume24h.max !== undefined && market.volume24h > criteria.volume24h.max) {
|
|
740
|
+
return false;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
// Volume filter
|
|
744
|
+
if (criteria.volume) {
|
|
745
|
+
if (criteria.volume.min !== undefined && (market.volume || 0) < criteria.volume.min) {
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
if (criteria.volume.max !== undefined && (market.volume || 0) > criteria.volume.max) {
|
|
749
|
+
return false;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
// Liquidity filter
|
|
753
|
+
if (criteria.liquidity) {
|
|
754
|
+
if (criteria.liquidity.min !== undefined && market.liquidity < criteria.liquidity.min) {
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
if (criteria.liquidity.max !== undefined && market.liquidity > criteria.liquidity.max) {
|
|
758
|
+
return false;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
// OpenInterest filter
|
|
762
|
+
if (criteria.openInterest) {
|
|
763
|
+
if (criteria.openInterest.min !== undefined && (market.openInterest || 0) < criteria.openInterest.min) {
|
|
764
|
+
return false;
|
|
765
|
+
}
|
|
766
|
+
if (criteria.openInterest.max !== undefined && (market.openInterest || 0) > criteria.openInterest.max) {
|
|
767
|
+
return false;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
// ResolutionDate filter
|
|
771
|
+
if (criteria.resolutionDate && market.resolutionDate) {
|
|
772
|
+
const resDate = market.resolutionDate;
|
|
773
|
+
if (criteria.resolutionDate.before && resDate >= criteria.resolutionDate.before) {
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
if (criteria.resolutionDate.after && resDate <= criteria.resolutionDate.after) {
|
|
777
|
+
return false;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
// Price filter (for binary markets)
|
|
781
|
+
if (criteria.price) {
|
|
782
|
+
const outcome = market[criteria.price.outcome];
|
|
783
|
+
if (!outcome)
|
|
784
|
+
return false;
|
|
785
|
+
if (criteria.price.min !== undefined && outcome.price < criteria.price.min) {
|
|
786
|
+
return false;
|
|
787
|
+
}
|
|
788
|
+
if (criteria.price.max !== undefined && outcome.price > criteria.price.max) {
|
|
789
|
+
return false;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
// Price change filter
|
|
793
|
+
if (criteria.priceChange24h) {
|
|
794
|
+
const outcome = market[criteria.priceChange24h.outcome];
|
|
795
|
+
if (!outcome || outcome.priceChange24h === undefined)
|
|
796
|
+
return false;
|
|
797
|
+
if (criteria.priceChange24h.min !== undefined && outcome.priceChange24h < criteria.priceChange24h.min) {
|
|
798
|
+
return false;
|
|
799
|
+
}
|
|
800
|
+
if (criteria.priceChange24h.max !== undefined && outcome.priceChange24h > criteria.priceChange24h.max) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
return true;
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Filter events based on criteria or custom function.
|
|
809
|
+
*
|
|
810
|
+
* @param events - Array of events to filter
|
|
811
|
+
* @param criteria - Filter criteria object, string (simple text search), or predicate function
|
|
812
|
+
* @returns Filtered array of events
|
|
813
|
+
*
|
|
814
|
+
* @example Simple text search
|
|
815
|
+
* api.filterEvents(events, 'Trump')
|
|
816
|
+
*
|
|
817
|
+
* @example Advanced filtering
|
|
818
|
+
* api.filterEvents(events, {
|
|
819
|
+
* text: 'Election',
|
|
820
|
+
* searchIn: ['title', 'tags'],
|
|
821
|
+
* category: 'Politics',
|
|
822
|
+
* marketCount: { min: 5 }
|
|
823
|
+
* })
|
|
824
|
+
*
|
|
825
|
+
* @example Custom predicate
|
|
826
|
+
* api.filterEvents(events, e => e.markets.length > 10)
|
|
827
|
+
*/
|
|
828
|
+
filterEvents(events, criteria) {
|
|
829
|
+
// Handle predicate function
|
|
830
|
+
if (typeof criteria === 'function') {
|
|
831
|
+
return events.filter(criteria);
|
|
832
|
+
}
|
|
833
|
+
// Handle simple string search
|
|
834
|
+
if (typeof criteria === 'string') {
|
|
835
|
+
const lowerQuery = criteria.toLowerCase();
|
|
836
|
+
return events.filter(e => e.title.toLowerCase().includes(lowerQuery));
|
|
837
|
+
}
|
|
838
|
+
// Handle criteria object
|
|
839
|
+
return events.filter(event => {
|
|
840
|
+
// Text search
|
|
841
|
+
if (criteria.text) {
|
|
842
|
+
const lowerQuery = criteria.text.toLowerCase();
|
|
843
|
+
const searchIn = criteria.searchIn || ['title'];
|
|
844
|
+
let textMatch = false;
|
|
845
|
+
for (const field of searchIn) {
|
|
846
|
+
if (field === 'title' && event.title?.toLowerCase().includes(lowerQuery)) {
|
|
847
|
+
textMatch = true;
|
|
848
|
+
break;
|
|
849
|
+
}
|
|
850
|
+
if (field === 'description' && event.description?.toLowerCase().includes(lowerQuery)) {
|
|
851
|
+
textMatch = true;
|
|
852
|
+
break;
|
|
853
|
+
}
|
|
854
|
+
if (field === 'category' && event.category?.toLowerCase().includes(lowerQuery)) {
|
|
855
|
+
textMatch = true;
|
|
856
|
+
break;
|
|
857
|
+
}
|
|
858
|
+
if (field === 'tags' && event.tags?.some(tag => tag.toLowerCase().includes(lowerQuery))) {
|
|
859
|
+
textMatch = true;
|
|
860
|
+
break;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
if (!textMatch)
|
|
864
|
+
return false;
|
|
865
|
+
}
|
|
866
|
+
// Category filter
|
|
867
|
+
if (criteria.category && event.category !== criteria.category) {
|
|
868
|
+
return false;
|
|
869
|
+
}
|
|
870
|
+
// Tags filter (match ANY of the provided tags)
|
|
871
|
+
if (criteria.tags && criteria.tags.length > 0) {
|
|
872
|
+
const hasMatchingTag = criteria.tags.some(tag => event.tags?.some(eventTag => eventTag.toLowerCase() === tag.toLowerCase()));
|
|
873
|
+
if (!hasMatchingTag)
|
|
874
|
+
return false;
|
|
875
|
+
}
|
|
876
|
+
// Market count filter
|
|
877
|
+
if (criteria.marketCount) {
|
|
878
|
+
const count = event.markets.length;
|
|
879
|
+
if (criteria.marketCount.min !== undefined && count < criteria.marketCount.min) {
|
|
880
|
+
return false;
|
|
881
|
+
}
|
|
882
|
+
if (criteria.marketCount.max !== undefined && count > criteria.marketCount.max) {
|
|
883
|
+
return false;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
// Total volume filter
|
|
887
|
+
if (criteria.totalVolume) {
|
|
888
|
+
const totalVolume = event.markets.reduce((sum, m) => sum + m.volume24h, 0);
|
|
889
|
+
if (criteria.totalVolume.min !== undefined && totalVolume < criteria.totalVolume.min) {
|
|
890
|
+
return false;
|
|
891
|
+
}
|
|
892
|
+
if (criteria.totalVolume.max !== undefined && totalVolume > criteria.totalVolume.max) {
|
|
893
|
+
return false;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
return true;
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
exports.Exchange = Exchange;
|
|
901
|
+
class Polymarket extends Exchange {
|
|
902
|
+
constructor(options = {}) {
|
|
903
|
+
// Default to gnosis-safe signature type
|
|
904
|
+
const polyOptions = {
|
|
905
|
+
signatureType: 'gnosis-safe',
|
|
906
|
+
...options
|
|
907
|
+
};
|
|
908
|
+
super("polymarket", polyOptions);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
exports.Polymarket = Polymarket;
|
|
912
|
+
/**
|
|
913
|
+
* Kalshi exchange client.
|
|
914
|
+
*
|
|
915
|
+
* @example
|
|
916
|
+
* ```typescript
|
|
917
|
+
* // Public data (no auth)
|
|
918
|
+
* const kalshi = new Kalshi();
|
|
919
|
+
* const markets = await kalshi.fetchMarkets({ query: "Fed rates" });
|
|
920
|
+
*
|
|
921
|
+
* // Trading (requires auth)
|
|
922
|
+
* const kalshi = new Kalshi({
|
|
923
|
+
* apiKey: process.env.KALSHI_API_KEY,
|
|
924
|
+
* privateKey: process.env.KALSHI_PRIVATE_KEY
|
|
925
|
+
* });
|
|
926
|
+
* const balance = await kalshi.fetchBalance();
|
|
927
|
+
* ```
|
|
928
|
+
*/
|
|
929
|
+
class Kalshi extends Exchange {
|
|
930
|
+
constructor(options = {}) {
|
|
931
|
+
super("kalshi", options);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
exports.Kalshi = Kalshi;
|
|
935
|
+
/**
|
|
936
|
+
* Limitless exchange client.
|
|
937
|
+
*
|
|
938
|
+
* @example
|
|
939
|
+
* ```typescript
|
|
940
|
+
* // Public data (no auth)
|
|
941
|
+
* const limitless = new Limitless();
|
|
942
|
+
* const markets = await limitless.fetchMarkets({ query: "Trump" });
|
|
943
|
+
*
|
|
944
|
+
* // Trading (requires auth)
|
|
945
|
+
* const limitless = new Limitless({
|
|
946
|
+
* apiKey: process.env.LIMITLESS_API_KEY,
|
|
947
|
+
* privateKey: process.env.LIMITLESS_PRIVATE_KEY
|
|
948
|
+
* });
|
|
949
|
+
* const balance = await limitless.fetchBalance();
|
|
950
|
+
* ```
|
|
951
|
+
*/
|
|
952
|
+
class Limitless extends Exchange {
|
|
953
|
+
constructor(options = {}) {
|
|
954
|
+
super("limitless", options);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
exports.Limitless = Limitless;
|