pmxt-core 2.20.0 → 2.20.2
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/exchanges/baozi/fetcher.d.ts +40 -0
- package/dist/exchanges/baozi/fetcher.js +155 -0
- package/dist/exchanges/baozi/index.d.ts +2 -0
- package/dist/exchanges/baozi/index.js +60 -131
- package/dist/exchanges/baozi/normalizer.d.ts +14 -0
- package/dist/exchanges/baozi/normalizer.js +208 -0
- package/dist/exchanges/interfaces.d.ts +28 -0
- package/dist/exchanges/interfaces.js +2 -0
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/kalshi/fetcher.d.ts +126 -0
- package/dist/exchanges/kalshi/fetcher.js +313 -0
- package/dist/exchanges/kalshi/index.d.ts +6 -6
- package/dist/exchanges/kalshi/index.js +119 -202
- package/dist/exchanges/kalshi/normalizer.d.ts +25 -0
- package/dist/exchanges/kalshi/normalizer.js +294 -0
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/fetcher.d.ts +81 -0
- package/dist/exchanges/limitless/fetcher.js +238 -0
- package/dist/exchanges/limitless/index.d.ts +6 -9
- package/dist/exchanges/limitless/index.js +81 -79
- package/dist/exchanges/limitless/normalizer.d.ts +14 -0
- package/dist/exchanges/limitless/normalizer.js +117 -0
- package/dist/exchanges/limitless/websocket.d.ts +3 -0
- package/dist/exchanges/limitless/websocket.js +5 -4
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/myriad/fetcher.d.ts +73 -0
- package/dist/exchanges/myriad/fetcher.js +217 -0
- package/dist/exchanges/myriad/index.d.ts +2 -0
- package/dist/exchanges/myriad/index.js +40 -97
- package/dist/exchanges/myriad/normalizer.d.ts +14 -0
- package/dist/exchanges/myriad/normalizer.js +167 -0
- package/dist/exchanges/myriad/websocket.d.ts +3 -1
- package/dist/exchanges/myriad/websocket.js +4 -3
- package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
- package/dist/exchanges/polymarket/api-clob.js +1 -1
- package/dist/exchanges/polymarket/api-data.d.ts +1 -1
- package/dist/exchanges/polymarket/api-data.js +1 -1
- package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
- package/dist/exchanges/polymarket/api-gamma.js +1 -1
- package/dist/exchanges/polymarket/fetcher.d.ts +99 -0
- package/dist/exchanges/polymarket/fetcher.js +335 -0
- package/dist/exchanges/polymarket/index.d.ts +2 -0
- package/dist/exchanges/polymarket/index.js +80 -66
- package/dist/exchanges/polymarket/normalizer.d.ts +18 -0
- package/dist/exchanges/polymarket/normalizer.js +126 -0
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/fetcher.d.ts +106 -0
- package/dist/exchanges/probable/fetcher.js +357 -0
- package/dist/exchanges/probable/index.d.ts +3 -1
- package/dist/exchanges/probable/index.js +73 -105
- package/dist/exchanges/probable/normalizer.d.ts +14 -0
- package/dist/exchanges/probable/normalizer.js +109 -0
- package/dist/utils/error-mapper.d.ts +8 -0
- package/dist/utils/error-mapper.js +58 -26
- package/package.json +3 -3
- package/dist/exchanges/baozi/fetchEvents.d.ts +0 -8
- package/dist/exchanges/baozi/fetchEvents.js +0 -39
- package/dist/exchanges/baozi/fetchMarkets.d.ts +0 -5
- package/dist/exchanges/baozi/fetchMarkets.js +0 -160
- package/dist/exchanges/baozi/fetchOHLCV.d.ts +0 -6
- package/dist/exchanges/baozi/fetchOHLCV.js +0 -10
- package/dist/exchanges/baozi/fetchOrderBook.d.ts +0 -12
- package/dist/exchanges/baozi/fetchOrderBook.js +0 -36
- package/dist/exchanges/baozi/fetchTrades.d.ts +0 -6
- package/dist/exchanges/baozi/fetchTrades.js +0 -10
- package/dist/exchanges/kalshi/fetchEvents.d.ts +0 -5
- package/dist/exchanges/kalshi/fetchEvents.js +0 -196
- package/dist/exchanges/kalshi/fetchMarkets.d.ts +0 -6
- package/dist/exchanges/kalshi/fetchMarkets.js +0 -247
- package/dist/exchanges/kalshi/fetchOHLCV.d.ts +0 -3
- package/dist/exchanges/kalshi/fetchOHLCV.js +0 -97
- package/dist/exchanges/kalshi/fetchOrderBook.d.ts +0 -2
- package/dist/exchanges/kalshi/fetchOrderBook.js +0 -60
- package/dist/exchanges/kalshi/fetchTrades.d.ts +0 -3
- package/dist/exchanges/kalshi/fetchTrades.js +0 -33
- package/dist/exchanges/limitless/fetchEvents.d.ts +0 -4
- package/dist/exchanges/limitless/fetchEvents.js +0 -173
- package/dist/exchanges/limitless/fetchMarkets.d.ts +0 -3
- package/dist/exchanges/limitless/fetchMarkets.js +0 -152
- package/dist/exchanges/limitless/fetchOHLCV.d.ts +0 -7
- package/dist/exchanges/limitless/fetchOHLCV.js +0 -49
- package/dist/exchanges/limitless/fetchOrderBook.d.ts +0 -6
- package/dist/exchanges/limitless/fetchOrderBook.js +0 -41
- package/dist/exchanges/limitless/fetchTrades.d.ts +0 -8
- package/dist/exchanges/limitless/fetchTrades.js +0 -27
- package/dist/exchanges/myriad/fetchEvents.d.ts +0 -4
- package/dist/exchanges/myriad/fetchEvents.js +0 -48
- package/dist/exchanges/myriad/fetchMarkets.d.ts +0 -4
- package/dist/exchanges/myriad/fetchMarkets.js +0 -102
- package/dist/exchanges/myriad/fetchOHLCV.d.ts +0 -3
- package/dist/exchanges/myriad/fetchOHLCV.js +0 -83
- package/dist/exchanges/myriad/fetchOrderBook.d.ts +0 -2
- package/dist/exchanges/myriad/fetchOrderBook.js +0 -39
- package/dist/exchanges/polymarket/fetchEvents.d.ts +0 -4
- package/dist/exchanges/polymarket/fetchEvents.js +0 -135
- package/dist/exchanges/polymarket/fetchMarkets.d.ts +0 -4
- package/dist/exchanges/polymarket/fetchMarkets.js +0 -214
- package/dist/exchanges/polymarket/fetchOHLCV.d.ts +0 -7
- package/dist/exchanges/polymarket/fetchOHLCV.js +0 -98
- package/dist/exchanges/polymarket/fetchOrderBook.d.ts +0 -6
- package/dist/exchanges/polymarket/fetchOrderBook.js +0 -33
- package/dist/exchanges/polymarket/fetchTrades.d.ts +0 -9
- package/dist/exchanges/polymarket/fetchTrades.js +0 -43
- package/dist/exchanges/probable/fetchEvents.d.ts +0 -6
- package/dist/exchanges/probable/fetchEvents.js +0 -151
- package/dist/exchanges/probable/fetchMarkets.d.ts +0 -4
- package/dist/exchanges/probable/fetchMarkets.js +0 -239
- package/dist/exchanges/probable/fetchTrades.d.ts +0 -10
- package/dist/exchanges/probable/fetchTrades.js +0 -40
|
@@ -13,11 +13,8 @@ const api_1 = require("./api");
|
|
|
13
13
|
const auth_1 = require("./auth");
|
|
14
14
|
const client_1 = require("./client");
|
|
15
15
|
const errors_2 = require("./errors");
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const fetchOHLCV_1 = require("./fetchOHLCV");
|
|
19
|
-
const fetchOrderBook_1 = require("./fetchOrderBook");
|
|
20
|
-
const fetchTrades_1 = require("./fetchTrades");
|
|
16
|
+
const fetcher_1 = require("./fetcher");
|
|
17
|
+
const normalizer_1 = require("./normalizer");
|
|
21
18
|
const websocket_1 = require("./websocket");
|
|
22
19
|
class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
23
20
|
has = {
|
|
@@ -46,6 +43,8 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
46
43
|
client;
|
|
47
44
|
wsConfig;
|
|
48
45
|
ws;
|
|
46
|
+
fetcher;
|
|
47
|
+
normalizer;
|
|
49
48
|
constructor(options) {
|
|
50
49
|
// Support both old signature (credentials only) and new signature (options object)
|
|
51
50
|
let credentials;
|
|
@@ -86,27 +85,81 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
86
85
|
// Register implicit API for Limitless REST endpoints
|
|
87
86
|
const apiDescriptor = (0, openapi_1.parseOpenApiSpec)(api_1.limitlessApiSpec);
|
|
88
87
|
this.defineImplicitApi(apiDescriptor);
|
|
88
|
+
const ctx = {
|
|
89
|
+
http: this.http,
|
|
90
|
+
callApi: this.callApi.bind(this),
|
|
91
|
+
getHeaders: () => this.getHeaders(),
|
|
92
|
+
};
|
|
93
|
+
this.fetcher = new fetcher_1.LimitlessFetcher(ctx, this.http, this.auth?.getApiKey());
|
|
94
|
+
this.normalizer = new normalizer_1.LimitlessNormalizer();
|
|
89
95
|
}
|
|
90
96
|
get name() {
|
|
91
97
|
return 'Limitless';
|
|
92
98
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
99
|
+
getHeaders() {
|
|
100
|
+
return { 'Content-Type': 'application/json' };
|
|
101
|
+
}
|
|
102
|
+
// ------------------------------------------------------------------------
|
|
103
|
+
// Market Data (fetcher -> normalizer)
|
|
104
|
+
// ------------------------------------------------------------------------
|
|
105
|
+
async fetchMarketsImpl(params) {
|
|
106
|
+
const rawMarkets = await this.fetcher.fetchRawMarkets(params);
|
|
107
|
+
// Handle outcomeId filtering (client-side)
|
|
108
|
+
if (params?.outcomeId) {
|
|
109
|
+
return rawMarkets
|
|
110
|
+
.map((raw) => this.normalizer.normalizeMarket(raw))
|
|
111
|
+
.filter((m) => m !== null && m.outcomes.length > 0)
|
|
112
|
+
.filter(m => m.outcomes.some(o => o.outcomeId === params.outcomeId));
|
|
113
|
+
}
|
|
114
|
+
// Handle search results -- filter and limit
|
|
115
|
+
if (params?.query) {
|
|
116
|
+
return rawMarkets
|
|
117
|
+
.map((raw) => this.normalizer.normalizeMarket(raw))
|
|
118
|
+
.filter((m) => m !== null && m.outcomes.length > 0)
|
|
119
|
+
.slice(0, params?.limit || 250000);
|
|
120
|
+
}
|
|
121
|
+
// Default fetch -- normalize, filter, sort, apply offset/limit
|
|
122
|
+
const unifiedMarkets = rawMarkets
|
|
123
|
+
.map((raw) => this.normalizer.normalizeMarket(raw))
|
|
124
|
+
.filter((m) => m !== null && m.outcomes.length > 0);
|
|
125
|
+
if (params?.sort === 'volume') {
|
|
126
|
+
unifiedMarkets.sort((a, b) => (b.volume ?? 0) - (a.volume ?? 0));
|
|
127
|
+
}
|
|
128
|
+
const offset = params?.offset || 0;
|
|
129
|
+
const limit = params?.limit || 250000;
|
|
130
|
+
const marketsAfterOffset = offset > 0 ? unifiedMarkets.slice(offset) : unifiedMarkets;
|
|
131
|
+
return marketsAfterOffset.slice(0, limit);
|
|
132
|
+
}
|
|
133
|
+
async fetchEventsImpl(params) {
|
|
134
|
+
const rawEvents = await this.fetcher.fetchRawEvents(params);
|
|
135
|
+
return rawEvents
|
|
136
|
+
.map((raw) => this.normalizer.normalizeEvent(raw))
|
|
137
|
+
.filter((e) => e !== null);
|
|
138
|
+
}
|
|
96
139
|
async fetchOHLCV(id, params) {
|
|
97
|
-
|
|
140
|
+
const rawPrices = await this.fetcher.fetchRawOHLCV(id, params);
|
|
141
|
+
return this.normalizer.normalizeOHLCV(rawPrices, params);
|
|
98
142
|
}
|
|
99
143
|
async fetchOrderBook(id) {
|
|
100
|
-
|
|
144
|
+
const rawOrderBook = await this.fetcher.fetchRawOrderBook(id);
|
|
145
|
+
return this.normalizer.normalizeOrderBook(rawOrderBook, id);
|
|
101
146
|
}
|
|
102
147
|
async fetchTrades(id, params) {
|
|
103
|
-
// Deprecation warning
|
|
104
148
|
if ('resolution' in params && params.resolution !== undefined) {
|
|
105
149
|
console.warn('[pmxt] Warning: The "resolution" parameter is deprecated for fetchTrades() and will be ignored. ' +
|
|
106
150
|
'It will be removed in v3.0.0. Please remove it from your code.');
|
|
107
151
|
}
|
|
108
|
-
|
|
152
|
+
const rawTrades = await this.fetcher.fetchRawTrades(id, params);
|
|
153
|
+
return rawTrades.map((raw, i) => this.normalizer.normalizeTrade(raw, i));
|
|
109
154
|
}
|
|
155
|
+
async fetchMyTrades(params) {
|
|
156
|
+
const auth = this.ensureAuth();
|
|
157
|
+
const rawTrades = await this.fetcher.fetchRawMyTrades(params || {}, auth.getApiKey());
|
|
158
|
+
return rawTrades.map((raw, i) => this.normalizer.normalizeUserTrade(raw, i));
|
|
159
|
+
}
|
|
160
|
+
// ------------------------------------------------------------------------
|
|
161
|
+
// Trading (kept in SDK class -- uses LimitlessClient)
|
|
162
|
+
// ------------------------------------------------------------------------
|
|
110
163
|
async createOrder(params) {
|
|
111
164
|
const client = this.ensureClient();
|
|
112
165
|
try {
|
|
@@ -147,9 +200,6 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
147
200
|
throw errors_2.limitlessErrorMapper.mapError(error);
|
|
148
201
|
}
|
|
149
202
|
}
|
|
150
|
-
// ----------------------------------------------------------------------------
|
|
151
|
-
// Trading Methods
|
|
152
|
-
// ----------------------------------------------------------------------------
|
|
153
203
|
async cancelOrder(orderId) {
|
|
154
204
|
const client = this.ensureClient();
|
|
155
205
|
try {
|
|
@@ -172,18 +222,12 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
172
222
|
}
|
|
173
223
|
}
|
|
174
224
|
async fetchOrder(orderId) {
|
|
175
|
-
// Limitless API does not support fetching a single order by ID directly without the market slug.
|
|
176
|
-
// We would need to scan all markets or maintain a local cache.
|
|
177
|
-
// For now, we throw specific error.
|
|
178
225
|
throw new Error('Limitless: fetchOrder(id) is not supported directly. Use fetchOpenOrders(marketSlug).');
|
|
179
226
|
}
|
|
180
227
|
async fetchOpenOrders(marketId) {
|
|
181
228
|
const client = this.ensureClient();
|
|
182
229
|
try {
|
|
183
230
|
if (!marketId) {
|
|
184
|
-
// We cannot fetch ALL open orders globally efficiently on Limitless (no endpoint).
|
|
185
|
-
// We would need to fetch all active markets and query each.
|
|
186
|
-
// For this MVP, we return empty or throw. Returning empty to be "compliant" with interface but logging warning.
|
|
187
231
|
console.warn('Limitless: fetchOpenOrders requires marketId (slug) to be efficient. Returning [].');
|
|
188
232
|
return [];
|
|
189
233
|
}
|
|
@@ -206,26 +250,6 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
206
250
|
throw errors_2.limitlessErrorMapper.mapError(error);
|
|
207
251
|
}
|
|
208
252
|
}
|
|
209
|
-
async fetchMyTrades(params) {
|
|
210
|
-
const auth = this.ensureAuth();
|
|
211
|
-
try {
|
|
212
|
-
const response = await this.http.get('https://api.limitless.exchange/portfolio/trades', {
|
|
213
|
-
headers: { Authorization: `Bearer ${auth.getApiKey()}` },
|
|
214
|
-
});
|
|
215
|
-
const trades = Array.isArray(response.data) ? response.data : (response.data?.data || []);
|
|
216
|
-
return trades.map((t) => ({
|
|
217
|
-
id: t.id || String(t.timestamp),
|
|
218
|
-
timestamp: t.createdAt ? new Date(t.createdAt).getTime() : (t.timestamp || 0),
|
|
219
|
-
price: parseFloat(t.price || '0'),
|
|
220
|
-
amount: parseFloat(t.quantity || t.amount || '0'),
|
|
221
|
-
side: (t.side || '').toLowerCase() === 'buy' ? 'buy' : 'sell',
|
|
222
|
-
orderId: t.orderId,
|
|
223
|
-
}));
|
|
224
|
-
}
|
|
225
|
-
catch (error) {
|
|
226
|
-
throw errors_2.limitlessErrorMapper.mapError(error);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
253
|
async fetchClosedOrders(params) {
|
|
230
254
|
const client = this.ensureClient();
|
|
231
255
|
if (!params?.marketId) {
|
|
@@ -268,25 +292,18 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
268
292
|
timestamp: o.createdAt ? new Date(o.createdAt).getTime() : Date.now(),
|
|
269
293
|
}));
|
|
270
294
|
}
|
|
295
|
+
// ------------------------------------------------------------------------
|
|
296
|
+
// Positions & Balance (fetcher -> normalizer)
|
|
297
|
+
// ------------------------------------------------------------------------
|
|
271
298
|
async fetchPositions(address) {
|
|
272
|
-
// Public endpoint
|
|
299
|
+
// Public endpoint -- no auth needed when an address is explicitly supplied.
|
|
273
300
|
const account = address ?? this.ensureAuth().getAddress();
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
return data.map((p) => ({
|
|
277
|
-
marketId: p.market?.slug || p.conditionId,
|
|
278
|
-
outcomeId: p.asset,
|
|
279
|
-
outcomeLabel: p.outcome || 'Unknown',
|
|
280
|
-
size: parseFloat(p.size || '0'),
|
|
281
|
-
entryPrice: parseFloat(p.avgPrice || '0'),
|
|
282
|
-
currentPrice: parseFloat(p.curPrice || '0'),
|
|
283
|
-
unrealizedPnL: parseFloat(p.cashPnl || '0'),
|
|
284
|
-
realizedPnL: parseFloat(p.realizedPnl || '0'),
|
|
285
|
-
}));
|
|
301
|
+
const rawItems = await this.fetcher.fetchRawPositions(account);
|
|
302
|
+
return rawItems.map((raw) => this.normalizer.normalizePosition(raw));
|
|
286
303
|
}
|
|
287
304
|
async fetchBalance(address) {
|
|
288
305
|
try {
|
|
289
|
-
// When an external address is provided use on-chain RPC only
|
|
306
|
+
// When an external address is provided use on-chain RPC only -- no auth required.
|
|
290
307
|
const targetAddress = address ?? this.ensureAuth().getAddress();
|
|
291
308
|
return await this.getAddressOnChainBalance(targetAddress);
|
|
292
309
|
}
|
|
@@ -294,10 +311,11 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
294
311
|
throw errors_2.limitlessErrorMapper.mapError(error);
|
|
295
312
|
}
|
|
296
313
|
}
|
|
314
|
+
// ------------------------------------------------------------------------
|
|
315
|
+
// WebSocket
|
|
316
|
+
// ------------------------------------------------------------------------
|
|
297
317
|
async watchOrderBook(id, limit) {
|
|
298
318
|
const ws = this.ensureWs();
|
|
299
|
-
// Return the snapshot immediately (this allows the script to proceed)
|
|
300
|
-
// Future versions could implement a more sophisticated queueing system
|
|
301
319
|
return ws.watchOrderBook(id);
|
|
302
320
|
}
|
|
303
321
|
async watchTrades(id, address, since, limit) {
|
|
@@ -338,13 +356,10 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
338
356
|
* exchange.watch_user_positions(callback=lambda data: print('Position update:', data))
|
|
339
357
|
*/
|
|
340
358
|
async watchUserPositions(callback) {
|
|
341
|
-
this.ensureAuth();
|
|
359
|
+
this.ensureAuth();
|
|
342
360
|
const ws = this.ensureWs();
|
|
343
361
|
return ws.watchUserPositions(callback);
|
|
344
362
|
}
|
|
345
|
-
// ----------------------------------------------------------------------------
|
|
346
|
-
// WebSocket Methods
|
|
347
|
-
// ----------------------------------------------------------------------------
|
|
348
363
|
/**
|
|
349
364
|
* Watch user transactions in real-time (Limitless only).
|
|
350
365
|
* Requires API key authentication.
|
|
@@ -360,7 +375,7 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
360
375
|
* exchange.watch_user_transactions(callback=lambda data: print('Transaction:', data))
|
|
361
376
|
*/
|
|
362
377
|
async watchUserTransactions(callback) {
|
|
363
|
-
this.ensureAuth();
|
|
378
|
+
this.ensureAuth();
|
|
364
379
|
const ws = this.ensureWs();
|
|
365
380
|
return ws.watchUserTransactions(callback);
|
|
366
381
|
}
|
|
@@ -404,17 +419,9 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
404
419
|
mapImplicitApiError(error) {
|
|
405
420
|
throw errors_2.limitlessErrorMapper.mapError(error);
|
|
406
421
|
}
|
|
407
|
-
//
|
|
408
|
-
//
|
|
409
|
-
//
|
|
410
|
-
async fetchMarketsImpl(params) {
|
|
411
|
-
// Pass API key if available for authenticated requests
|
|
412
|
-
const apiKey = this.auth?.getApiKey();
|
|
413
|
-
return (0, fetchMarkets_1.fetchMarkets)(params, apiKey, this.callApi.bind(this));
|
|
414
|
-
}
|
|
415
|
-
async fetchEventsImpl(params) {
|
|
416
|
-
return (0, fetchEvents_1.fetchEvents)(params, this.callApi.bind(this), this.http);
|
|
417
|
-
}
|
|
422
|
+
// ------------------------------------------------------------------------
|
|
423
|
+
// Private helpers
|
|
424
|
+
// ------------------------------------------------------------------------
|
|
418
425
|
async getAddressOnChainBalance(targetAddress) {
|
|
419
426
|
// Query USDC balance directly from Base chain
|
|
420
427
|
const provider = new ethers_1.providers.JsonRpcProvider('https://mainnet.base.org');
|
|
@@ -439,9 +446,6 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
439
446
|
}
|
|
440
447
|
return this.client;
|
|
441
448
|
}
|
|
442
|
-
/**
|
|
443
|
-
* Ensure authentication is initialized before trading operations.
|
|
444
|
-
*/
|
|
445
449
|
ensureAuth() {
|
|
446
450
|
if (!this.auth) {
|
|
447
451
|
throw new errors_1.AuthenticationError('Trading operations require authentication. ' +
|
|
@@ -449,14 +453,12 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
449
453
|
}
|
|
450
454
|
return this.auth;
|
|
451
455
|
}
|
|
452
|
-
/**
|
|
453
|
-
* Initialize WebSocket with API key if available.
|
|
454
|
-
*/
|
|
455
456
|
ensureWs() {
|
|
456
457
|
if (!this.ws) {
|
|
457
458
|
const wsConfig = {
|
|
458
459
|
...this.wsConfig,
|
|
459
460
|
apiKey: this.auth?.getApiKey(),
|
|
461
|
+
fetchOrderBook: (id) => this.fetchOrderBook(id),
|
|
460
462
|
};
|
|
461
463
|
this.ws = new websocket_1.LimitlessWebSocket(this.callApi.bind(this), wsConfig);
|
|
462
464
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { OHLCVParams } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Position, Balance } from '../../types';
|
|
3
|
+
import { IExchangeNormalizer } from '../interfaces';
|
|
4
|
+
import { LimitlessRawMarket, LimitlessRawEvent, LimitlessRawPricePoint, LimitlessRawOrderBook } from './fetcher';
|
|
5
|
+
export declare class LimitlessNormalizer implements IExchangeNormalizer<LimitlessRawMarket, LimitlessRawEvent> {
|
|
6
|
+
normalizeMarket(raw: LimitlessRawMarket): UnifiedMarket | null;
|
|
7
|
+
normalizeEvent(raw: LimitlessRawEvent): UnifiedEvent | null;
|
|
8
|
+
normalizeOHLCV(rawPrices: LimitlessRawPricePoint[], params: OHLCVParams): PriceCandle[];
|
|
9
|
+
normalizeOrderBook(raw: LimitlessRawOrderBook, _id: string): OrderBook;
|
|
10
|
+
normalizeTrade(_raw: unknown, _index: number): Trade;
|
|
11
|
+
normalizeUserTrade(raw: unknown, _index: number): UserTrade;
|
|
12
|
+
normalizePosition(raw: unknown): Position;
|
|
13
|
+
normalizeBalance(raw: unknown): Balance[];
|
|
14
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LimitlessNormalizer = void 0;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
// Limitless uses USDC with 6 decimals
|
|
6
|
+
const USDC_DECIMALS = 6;
|
|
7
|
+
const USDC_SCALE = Math.pow(10, USDC_DECIMALS);
|
|
8
|
+
function convertSize(rawSize) {
|
|
9
|
+
return rawSize / USDC_SCALE;
|
|
10
|
+
}
|
|
11
|
+
class LimitlessNormalizer {
|
|
12
|
+
normalizeMarket(raw) {
|
|
13
|
+
return (0, utils_1.mapMarketToUnified)(raw);
|
|
14
|
+
}
|
|
15
|
+
normalizeEvent(raw) {
|
|
16
|
+
if (!raw)
|
|
17
|
+
return null;
|
|
18
|
+
let marketsList = [];
|
|
19
|
+
if (raw.markets && Array.isArray(raw.markets)) {
|
|
20
|
+
marketsList = raw.markets
|
|
21
|
+
.map((child) => (0, utils_1.mapMarketToUnified)(child))
|
|
22
|
+
.filter((m) => m !== null);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const unifiedMarket = (0, utils_1.mapMarketToUnified)(raw);
|
|
26
|
+
if (unifiedMarket)
|
|
27
|
+
marketsList = [unifiedMarket];
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
id: raw.slug,
|
|
31
|
+
title: raw.title || raw.question || '',
|
|
32
|
+
description: raw.description || '',
|
|
33
|
+
slug: raw.slug,
|
|
34
|
+
markets: marketsList,
|
|
35
|
+
volume24h: marketsList.reduce((sum, m) => sum + m.volume24h, 0),
|
|
36
|
+
volume: marketsList.some(m => m.volume !== undefined)
|
|
37
|
+
? marketsList.reduce((sum, m) => sum + (m.volume ?? 0), 0)
|
|
38
|
+
: undefined,
|
|
39
|
+
url: `https://limitless.exchange/markets/${raw.slug}`,
|
|
40
|
+
image: raw.logo || `https://limitless.exchange/api/og?slug=${raw.slug}`,
|
|
41
|
+
category: raw.categories?.[0],
|
|
42
|
+
tags: raw.tags || [],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
normalizeOHLCV(rawPrices, params) {
|
|
46
|
+
let candles = rawPrices.map((p) => {
|
|
47
|
+
const price = Number(p.price);
|
|
48
|
+
const ts = Number(p.timestamp);
|
|
49
|
+
return {
|
|
50
|
+
timestamp: ts,
|
|
51
|
+
open: price,
|
|
52
|
+
high: price,
|
|
53
|
+
low: price,
|
|
54
|
+
close: price,
|
|
55
|
+
volume: 0,
|
|
56
|
+
};
|
|
57
|
+
}).sort((a, b) => a.timestamp - b.timestamp);
|
|
58
|
+
if (params.start) {
|
|
59
|
+
candles = candles.filter((c) => c.timestamp >= params.start.getTime());
|
|
60
|
+
}
|
|
61
|
+
if (params.end) {
|
|
62
|
+
candles = candles.filter((c) => c.timestamp <= params.end.getTime());
|
|
63
|
+
}
|
|
64
|
+
if (params.limit) {
|
|
65
|
+
candles = candles.slice(0, params.limit);
|
|
66
|
+
}
|
|
67
|
+
return candles;
|
|
68
|
+
}
|
|
69
|
+
normalizeOrderBook(raw, _id) {
|
|
70
|
+
const bids = (raw.bids || []).map((level) => ({
|
|
71
|
+
price: parseFloat(String(level.price)),
|
|
72
|
+
size: convertSize(parseFloat(String(level.size))),
|
|
73
|
+
})).sort((a, b) => b.price - a.price);
|
|
74
|
+
const asks = (raw.asks || []).map((level) => ({
|
|
75
|
+
price: parseFloat(String(level.price)),
|
|
76
|
+
size: convertSize(parseFloat(String(level.size))),
|
|
77
|
+
})).sort((a, b) => a.price - b.price);
|
|
78
|
+
return {
|
|
79
|
+
bids,
|
|
80
|
+
asks,
|
|
81
|
+
timestamp: raw.timestamp || Date.now(),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
normalizeTrade(_raw, _index) {
|
|
85
|
+
// Limitless does not have a public market trades endpoint
|
|
86
|
+
throw new Error('Limitless normalizeTrade not supported: No public market trades API available.');
|
|
87
|
+
}
|
|
88
|
+
normalizeUserTrade(raw, _index) {
|
|
89
|
+
const t = raw;
|
|
90
|
+
return {
|
|
91
|
+
id: t.id || String(t.timestamp),
|
|
92
|
+
timestamp: t.createdAt ? new Date(t.createdAt).getTime() : (t.timestamp || 0),
|
|
93
|
+
price: parseFloat(t.price || '0'),
|
|
94
|
+
amount: parseFloat(t.quantity || t.amount || '0'),
|
|
95
|
+
side: (t.side || '').toLowerCase() === 'buy' ? 'buy' : 'sell',
|
|
96
|
+
orderId: t.orderId,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
normalizePosition(raw) {
|
|
100
|
+
const p = raw;
|
|
101
|
+
return {
|
|
102
|
+
marketId: p.market?.slug || p.conditionId,
|
|
103
|
+
outcomeId: p.asset,
|
|
104
|
+
outcomeLabel: p.outcome || 'Unknown',
|
|
105
|
+
size: parseFloat(p.size || '0'),
|
|
106
|
+
entryPrice: parseFloat(p.avgPrice || '0'),
|
|
107
|
+
currentPrice: parseFloat(p.curPrice || '0'),
|
|
108
|
+
unrealizedPnL: parseFloat(p.cashPnl || '0'),
|
|
109
|
+
realizedPnL: parseFloat(p.realizedPnl || '0'),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
normalizeBalance(raw) {
|
|
113
|
+
// Not used in the standard flow -- balance comes from on-chain RPC
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.LimitlessNormalizer = LimitlessNormalizer;
|
|
@@ -11,6 +11,8 @@ export interface LimitlessWebSocketConfig extends Partial<WebSocketConfig> {
|
|
|
11
11
|
reconnectDelay?: number;
|
|
12
12
|
/** Watcher subscription configurations */
|
|
13
13
|
watcherConfig?: WatcherConfig;
|
|
14
|
+
/** Callback to fetch an orderbook snapshot via REST (used as fallback) */
|
|
15
|
+
fetchOrderBook?: (id: string) => Promise<OrderBook>;
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Limitless WebSocket implementation using the official SDK.
|
|
@@ -25,6 +27,7 @@ export declare class LimitlessWebSocket {
|
|
|
25
27
|
private readonly watcher;
|
|
26
28
|
private config;
|
|
27
29
|
private callApi;
|
|
30
|
+
private readonly fetchOrderBookSnapshot;
|
|
28
31
|
private orderbookCallbacks;
|
|
29
32
|
private priceCallbacks;
|
|
30
33
|
private orderbookResolvers;
|
|
@@ -4,7 +4,6 @@ exports.LimitlessWebSocket = void 0;
|
|
|
4
4
|
const sdk_1 = require("@limitless-exchange/sdk");
|
|
5
5
|
const goldsky_1 = require("../../subscriber/external/goldsky");
|
|
6
6
|
const watcher_1 = require("../../subscriber/watcher");
|
|
7
|
-
const fetchOrderBook_1 = require("./fetchOrderBook");
|
|
8
7
|
// Limitless uses USDC with 6 decimals
|
|
9
8
|
const USDC_DECIMALS = 6;
|
|
10
9
|
const USDC_SCALE = Math.pow(10, USDC_DECIMALS);
|
|
@@ -27,6 +26,7 @@ class LimitlessWebSocket {
|
|
|
27
26
|
watcher;
|
|
28
27
|
config;
|
|
29
28
|
callApi;
|
|
29
|
+
fetchOrderBookSnapshot;
|
|
30
30
|
orderbookCallbacks = new Map();
|
|
31
31
|
priceCallbacks = new Map();
|
|
32
32
|
orderbookResolvers = new Map();
|
|
@@ -35,6 +35,7 @@ class LimitlessWebSocket {
|
|
|
35
35
|
constructor(callApi, config = {}) {
|
|
36
36
|
this.callApi = callApi;
|
|
37
37
|
this.config = config;
|
|
38
|
+
this.fetchOrderBookSnapshot = config.fetchOrderBook ?? (async () => this.getEmptyOrderbook());
|
|
38
39
|
// Initialize SDK WebSocket client
|
|
39
40
|
const wsConfig = {
|
|
40
41
|
url: config.url || 'wss://ws.limitless.exchange',
|
|
@@ -86,7 +87,7 @@ class LimitlessWebSocket {
|
|
|
86
87
|
if (!this.lastOrderbookTimestamps.has(marketSlug)) {
|
|
87
88
|
this.lastOrderbookTimestamps.set(marketSlug, Date.now());
|
|
88
89
|
try {
|
|
89
|
-
return await
|
|
90
|
+
return await this.fetchOrderBookSnapshot(marketSlug);
|
|
90
91
|
}
|
|
91
92
|
catch (err) {
|
|
92
93
|
console.warn(`[LimitlessWS] Failed to fetch initial snapshot:`, err);
|
|
@@ -103,7 +104,7 @@ class LimitlessWebSocket {
|
|
|
103
104
|
if (timeSinceLastUpdate > SNAPSHOT_REFRESH_INTERVAL) {
|
|
104
105
|
this.lastOrderbookTimestamps.set(marketSlug, Date.now());
|
|
105
106
|
try {
|
|
106
|
-
return await
|
|
107
|
+
return await this.fetchOrderBookSnapshot(marketSlug);
|
|
107
108
|
}
|
|
108
109
|
catch (err) {
|
|
109
110
|
console.warn(`[LimitlessWS] Failed to fetch refresh snapshot:`, err);
|
|
@@ -122,7 +123,7 @@ class LimitlessWebSocket {
|
|
|
122
123
|
// Timeout: fetch REST snapshot as fallback
|
|
123
124
|
try {
|
|
124
125
|
this.lastOrderbookTimestamps.set(marketSlug, Date.now());
|
|
125
|
-
const snapshot = await
|
|
126
|
+
const snapshot = await this.fetchOrderBookSnapshot(marketSlug);
|
|
126
127
|
resolve(snapshot);
|
|
127
128
|
}
|
|
128
129
|
catch (err) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
|
|
3
|
-
* Generated at: 2026-03-
|
|
3
|
+
* Generated at: 2026-03-14T21:28:31.889Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const myriadApiSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.myriadApiSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
|
|
6
|
-
* Generated at: 2026-03-
|
|
6
|
+
* Generated at: 2026-03-14T21:28:31.889Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.myriadApiSpec = {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { MarketFilterParams, EventFetchParams, OHLCVParams, TradesParams, MyTradesParams } from '../../BaseExchange';
|
|
2
|
+
import { IExchangeFetcher, FetcherContext } from '../interfaces';
|
|
3
|
+
export interface MyriadRawMarket {
|
|
4
|
+
id: number;
|
|
5
|
+
networkId: number;
|
|
6
|
+
title?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
slug?: string;
|
|
9
|
+
imageUrl?: string;
|
|
10
|
+
expiresAt?: string;
|
|
11
|
+
volume24h?: number;
|
|
12
|
+
volume?: number;
|
|
13
|
+
liquidity?: number;
|
|
14
|
+
questionId?: number;
|
|
15
|
+
topics?: string[];
|
|
16
|
+
outcomes?: MyriadRawOutcome[];
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
export interface MyriadRawOutcome {
|
|
20
|
+
id: number;
|
|
21
|
+
title?: string;
|
|
22
|
+
price?: number;
|
|
23
|
+
priceChange24h?: number;
|
|
24
|
+
price_charts?: Record<string, {
|
|
25
|
+
timeframe: string;
|
|
26
|
+
prices: {
|
|
27
|
+
value: number;
|
|
28
|
+
timestamp: number;
|
|
29
|
+
}[];
|
|
30
|
+
}>;
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
}
|
|
33
|
+
export interface MyriadRawQuestion {
|
|
34
|
+
id: number;
|
|
35
|
+
title?: string;
|
|
36
|
+
markets?: MyriadRawMarket[];
|
|
37
|
+
[key: string]: unknown;
|
|
38
|
+
}
|
|
39
|
+
export interface MyriadRawTradeEvent {
|
|
40
|
+
action?: string;
|
|
41
|
+
blockNumber?: number;
|
|
42
|
+
timestamp?: number;
|
|
43
|
+
value?: number;
|
|
44
|
+
shares?: number;
|
|
45
|
+
outcomeId?: number;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
}
|
|
48
|
+
export interface MyriadRawPortfolioItem {
|
|
49
|
+
networkId: number;
|
|
50
|
+
marketId: number;
|
|
51
|
+
outcomeId: number;
|
|
52
|
+
outcomeTitle?: string;
|
|
53
|
+
shares?: number;
|
|
54
|
+
price?: number;
|
|
55
|
+
profit?: number;
|
|
56
|
+
value?: number;
|
|
57
|
+
[key: string]: unknown;
|
|
58
|
+
}
|
|
59
|
+
export declare class MyriadFetcher implements IExchangeFetcher<MyriadRawMarket, MyriadRawQuestion> {
|
|
60
|
+
private readonly ctx;
|
|
61
|
+
constructor(ctx: FetcherContext);
|
|
62
|
+
fetchRawMarkets(params?: MarketFilterParams): Promise<MyriadRawMarket[]>;
|
|
63
|
+
fetchRawEvents(params: EventFetchParams): Promise<MyriadRawQuestion[]>;
|
|
64
|
+
fetchRawOHLCV(id: string, _params: OHLCVParams): Promise<MyriadRawMarket>;
|
|
65
|
+
fetchRawOrderBook(id: string): Promise<MyriadRawMarket>;
|
|
66
|
+
fetchRawTrades(id: string, params: TradesParams): Promise<MyriadRawTradeEvent[]>;
|
|
67
|
+
fetchRawMyTrades(params: MyTradesParams, walletAddress: string): Promise<MyriadRawTradeEvent[]>;
|
|
68
|
+
fetchRawPositions(walletAddress: string): Promise<MyriadRawPortfolioItem[]>;
|
|
69
|
+
fetchRawBalance(walletAddress: string): Promise<MyriadRawPortfolioItem[]>;
|
|
70
|
+
private fetchRawMarketById;
|
|
71
|
+
private fetchRawMarketBySlug;
|
|
72
|
+
private fetchRawQuestionById;
|
|
73
|
+
}
|