pmxt-core 2.27.5 → 2.27.7
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/BaseExchange.d.ts +0 -331
- package/dist/BaseExchange.js +0 -331
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/kalshi/normalizer.d.ts +3 -0
- package/dist/exchanges/kalshi/normalizer.js +57 -23
- package/dist/exchanges/kalshi/utils.js +11 -5
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/index.d.ts +0 -30
- package/dist/exchanges/limitless/index.js +0 -30
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/opinion/api.d.ts +1 -1
- package/dist/exchanges/opinion/api.js +1 -1
- 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/index.d.ts +0 -12
- package/dist/exchanges/polymarket/index.js +0 -12
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/index.d.ts +0 -24
- package/dist/exchanges/probable/index.js +0 -24
- package/dist/server/openapi.yaml +195 -0
- package/package.json +3 -3
package/dist/BaseExchange.js
CHANGED
|
@@ -137,18 +137,6 @@ class PredictionMarketExchange {
|
|
|
137
137
|
*
|
|
138
138
|
* @param reload - Force a fresh fetch from the API even if markets are already loaded
|
|
139
139
|
* @returns Dictionary of markets indexed by marketId
|
|
140
|
-
*
|
|
141
|
-
* @example-ts Stable pagination
|
|
142
|
-
* await exchange.loadMarkets();
|
|
143
|
-
* const all = Object.values(exchange.markets);
|
|
144
|
-
* const page1 = all.slice(0, 100);
|
|
145
|
-
* const page2 = all.slice(100, 200);
|
|
146
|
-
*
|
|
147
|
-
* @example-python Stable pagination
|
|
148
|
-
* exchange.load_markets()
|
|
149
|
-
* all = list(exchange.markets.values())
|
|
150
|
-
* page1 = all[:100]
|
|
151
|
-
* page2 = all[100:200]
|
|
152
140
|
*/
|
|
153
141
|
async loadMarkets(reload = false) {
|
|
154
142
|
if (this.loadedMarkets && !reload) {
|
|
@@ -187,20 +175,6 @@ class PredictionMarketExchange {
|
|
|
187
175
|
* across pages, use `loadMarkets()` and paginate over `Object.values(exchange.markets)`.
|
|
188
176
|
*
|
|
189
177
|
* @note Some exchanges (like Limitless) may only support status 'active' for search results.
|
|
190
|
-
*
|
|
191
|
-
* @example-ts Fetch markets
|
|
192
|
-
* const markets = await exchange.fetchMarkets({ query: 'Trump', limit: 10000 });
|
|
193
|
-
* console.log(markets[0].title);
|
|
194
|
-
*
|
|
195
|
-
* @example-ts Get market by slug
|
|
196
|
-
* const markets = await exchange.fetchMarkets({ slug: 'will-trump-win' });
|
|
197
|
-
*
|
|
198
|
-
* @example-python Fetch markets
|
|
199
|
-
* markets = exchange.fetch_markets(query='Trump', limit=10000)
|
|
200
|
-
* print(markets[0].title)
|
|
201
|
-
*
|
|
202
|
-
* @example-python Get market by slug
|
|
203
|
-
* markets = exchange.fetch_markets(slug='will-trump-win')
|
|
204
178
|
*/
|
|
205
179
|
async fetchMarkets(params) {
|
|
206
180
|
return this.fetchMarketsImpl(params);
|
|
@@ -270,16 +244,6 @@ class PredictionMarketExchange {
|
|
|
270
244
|
* @returns Array of unified events
|
|
271
245
|
*
|
|
272
246
|
* @note Some exchanges (like Limitless) may only support status 'active' for search results.
|
|
273
|
-
*
|
|
274
|
-
* @example-ts Search events
|
|
275
|
-
* const events = await exchange.fetchEvents({ query: 'Fed Chair' });
|
|
276
|
-
* const fedEvent = events[0];
|
|
277
|
-
* console.log(fedEvent.title, fedEvent.markets.length, 'markets');
|
|
278
|
-
*
|
|
279
|
-
* @example-python Search events
|
|
280
|
-
* events = exchange.fetch_events(query='Fed Chair')
|
|
281
|
-
* fed_event = events[0]
|
|
282
|
-
* print(fed_event.title, len(fed_event.markets), 'markets')
|
|
283
247
|
*/
|
|
284
248
|
async fetchEvents(params) {
|
|
285
249
|
return this.fetchEventsImpl(params ?? {});
|
|
@@ -291,15 +255,6 @@ class PredictionMarketExchange {
|
|
|
291
255
|
* @param params - Lookup parameters (marketId, outcomeId, slug, etc.)
|
|
292
256
|
* @returns A single unified market
|
|
293
257
|
* @throws MarketNotFound if no market matches the parameters
|
|
294
|
-
*
|
|
295
|
-
* @example-ts Fetch by market ID
|
|
296
|
-
* const market = await exchange.fetchMarket({ marketId: '663583' });
|
|
297
|
-
*
|
|
298
|
-
* @example-ts Fetch by outcome ID
|
|
299
|
-
* const market = await exchange.fetchMarket({ outcomeId: '10991849...' });
|
|
300
|
-
*
|
|
301
|
-
* @example-python Fetch by market ID
|
|
302
|
-
* market = exchange.fetch_market(market_id='663583')
|
|
303
258
|
*/
|
|
304
259
|
async fetchMarket(params) {
|
|
305
260
|
// Try to fetch from cache first if we have loaded markets and have an ID/slug
|
|
@@ -328,12 +283,6 @@ class PredictionMarketExchange {
|
|
|
328
283
|
* @param params - Lookup parameters (eventId, slug, query)
|
|
329
284
|
* @returns A single unified event
|
|
330
285
|
* @throws EventNotFound if no event matches the parameters
|
|
331
|
-
*
|
|
332
|
-
* @example-ts Fetch by event ID
|
|
333
|
-
* const event = await exchange.fetchEvent({ eventId: 'TRUMP25DEC' });
|
|
334
|
-
*
|
|
335
|
-
* @example-python Fetch by event ID
|
|
336
|
-
* event = exchange.fetch_event(event_id='TRUMP25DEC')
|
|
337
286
|
*/
|
|
338
287
|
async fetchEvent(params) {
|
|
339
288
|
const events = await this.fetchEvents(params);
|
|
@@ -350,21 +299,6 @@ class PredictionMarketExchange {
|
|
|
350
299
|
* @param params - OHLCV parameters including resolution (required)
|
|
351
300
|
* @returns Array of price candles
|
|
352
301
|
*
|
|
353
|
-
* @example-ts Fetch hourly candles
|
|
354
|
-
* const markets = await exchange.fetchMarkets({ query: 'Trump' });
|
|
355
|
-
* const outcomeId = markets[0].yes.outcomeId;
|
|
356
|
-
* const candles = await exchange.fetchOHLCV(outcomeId, {
|
|
357
|
-
* resolution: '1h',
|
|
358
|
-
* limit: 100
|
|
359
|
-
* });
|
|
360
|
-
* console.log(`Latest close: ${candles[candles.length - 1].close}`);
|
|
361
|
-
*
|
|
362
|
-
* @example-python Fetch hourly candles
|
|
363
|
-
* markets = exchange.fetch_markets(query='Trump')
|
|
364
|
-
* outcome_id = markets[0].yes.outcome_id
|
|
365
|
-
* candles = exchange.fetch_ohlcv(outcome_id, resolution='1h', limit=100)
|
|
366
|
-
* print(f"Latest close: {candles[-1].close}")
|
|
367
|
-
*
|
|
368
302
|
* @notes **CRITICAL**: Use `outcome.outcomeId` (TS) / `outcome.outcome_id` (Python), not the market ID.
|
|
369
303
|
* @notes Polymarket: outcomeId is the CLOB Token ID. Kalshi: outcomeId is the Market Ticker.
|
|
370
304
|
* @notes Resolution options: '1m' | '5m' | '15m' | '1h' | '6h' | '1d'
|
|
@@ -378,18 +312,6 @@ class PredictionMarketExchange {
|
|
|
378
312
|
*
|
|
379
313
|
* @param id - The Outcome ID (outcomeId)
|
|
380
314
|
* @returns Current order book with bids and asks
|
|
381
|
-
*
|
|
382
|
-
* @example-ts Fetch order book
|
|
383
|
-
* const book = await exchange.fetchOrderBook(outcome.outcomeId);
|
|
384
|
-
* console.log(`Best bid: ${book.bids[0].price}`);
|
|
385
|
-
* console.log(`Best ask: ${book.asks[0].price}`);
|
|
386
|
-
* console.log(`Spread: ${(book.asks[0].price - book.bids[0].price) * 100}%`);
|
|
387
|
-
*
|
|
388
|
-
* @example-python Fetch order book
|
|
389
|
-
* book = exchange.fetch_order_book(outcome.outcome_id)
|
|
390
|
-
* print(f"Best bid: {book.bids[0].price}")
|
|
391
|
-
* print(f"Best ask: {book.asks[0].price}")
|
|
392
|
-
* print(f"Spread: {(book.asks[0].price - book.bids[0].price) * 100:.2f}%")
|
|
393
315
|
*/
|
|
394
316
|
async fetchOrderBook(id) {
|
|
395
317
|
throw new Error("Method fetchOrderBook not implemented.");
|
|
@@ -401,17 +323,6 @@ class PredictionMarketExchange {
|
|
|
401
323
|
* @param params - Trade filter parameters
|
|
402
324
|
* @returns Array of recent trades
|
|
403
325
|
*
|
|
404
|
-
* @example-ts Fetch recent trades
|
|
405
|
-
* const trades = await exchange.fetchTrades(outcome.outcomeId, { limit: 100 });
|
|
406
|
-
* for (const trade of trades) {
|
|
407
|
-
* console.log(`${trade.side} ${trade.amount} @ ${trade.price}`);
|
|
408
|
-
* }
|
|
409
|
-
*
|
|
410
|
-
* @example-python Fetch recent trades
|
|
411
|
-
* trades = exchange.fetch_trades(outcome.outcome_id, limit=100)
|
|
412
|
-
* for trade in trades:
|
|
413
|
-
* print(f"{trade.side} {trade.amount} @ {trade.price}")
|
|
414
|
-
*
|
|
415
326
|
* @notes Polymarket requires an API key for trade history. Use fetchOHLCV for public historical data.
|
|
416
327
|
*/
|
|
417
328
|
async fetchTrades(id, params) {
|
|
@@ -427,46 +338,6 @@ class PredictionMarketExchange {
|
|
|
427
338
|
*
|
|
428
339
|
* @param params - Order parameters
|
|
429
340
|
* @returns The created order
|
|
430
|
-
*
|
|
431
|
-
* @example-ts Place a limit order
|
|
432
|
-
* const order = await exchange.createOrder({
|
|
433
|
-
* marketId: market.marketId,
|
|
434
|
-
* outcomeId: market.yes.outcomeId,
|
|
435
|
-
* side: 'buy',
|
|
436
|
-
* type: 'limit',
|
|
437
|
-
* amount: 10,
|
|
438
|
-
* price: 0.55
|
|
439
|
-
* });
|
|
440
|
-
* console.log(`Order ${order.id}: ${order.status}`);
|
|
441
|
-
*
|
|
442
|
-
* @example-ts Place a market order
|
|
443
|
-
* const order = await exchange.createOrder({
|
|
444
|
-
* marketId: market.marketId,
|
|
445
|
-
* outcomeId: market.yes.outcomeId,
|
|
446
|
-
* side: 'buy',
|
|
447
|
-
* type: 'market',
|
|
448
|
-
* amount: 5
|
|
449
|
-
* });
|
|
450
|
-
*
|
|
451
|
-
* @example-python Place a limit order
|
|
452
|
-
* order = exchange.create_order(
|
|
453
|
-
* market_id=market.market_id,
|
|
454
|
-
* outcome_id=market.yes.outcome_id,
|
|
455
|
-
* side='buy',
|
|
456
|
-
* type='limit',
|
|
457
|
-
* amount=10,
|
|
458
|
-
* price=0.55
|
|
459
|
-
* )
|
|
460
|
-
* print(f"Order {order.id}: {order.status}")
|
|
461
|
-
*
|
|
462
|
-
* @example-python Place a market order
|
|
463
|
-
* order = exchange.create_order(
|
|
464
|
-
* market_id=market.market_id,
|
|
465
|
-
* outcome_id=market.yes.outcome_id,
|
|
466
|
-
* side='buy',
|
|
467
|
-
* type='market',
|
|
468
|
-
* amount=5
|
|
469
|
-
* )
|
|
470
341
|
*/
|
|
471
342
|
async createOrder(params) {
|
|
472
343
|
throw new Error("Method createOrder not implemented.");
|
|
@@ -481,30 +352,6 @@ class PredictionMarketExchange {
|
|
|
481
352
|
*
|
|
482
353
|
* @param params - Order parameters (same as createOrder)
|
|
483
354
|
* @returns A BuiltOrder containing the exchange-native payload
|
|
484
|
-
*
|
|
485
|
-
* @example-ts Build then inspect a Polymarket order
|
|
486
|
-
* const built = await exchange.buildOrder({
|
|
487
|
-
* marketId: market.marketId,
|
|
488
|
-
* outcomeId: market.yes.outcomeId,
|
|
489
|
-
* side: 'buy',
|
|
490
|
-
* type: 'limit',
|
|
491
|
-
* amount: 10,
|
|
492
|
-
* price: 0.55
|
|
493
|
-
* });
|
|
494
|
-
* console.log(built.signedOrder); // EIP-712 signed order struct
|
|
495
|
-
* const order = await exchange.submitOrder(built);
|
|
496
|
-
*
|
|
497
|
-
* @example-python Build then submit a Polymarket order
|
|
498
|
-
* built = exchange.build_order(
|
|
499
|
-
* market_id=market.market_id,
|
|
500
|
-
* outcome_id=market.yes.outcome_id,
|
|
501
|
-
* side='buy',
|
|
502
|
-
* type='limit',
|
|
503
|
-
* amount=10,
|
|
504
|
-
* price=0.55
|
|
505
|
-
* )
|
|
506
|
-
* print(built.signed_order)
|
|
507
|
-
* order = exchange.submit_order(built)
|
|
508
355
|
*/
|
|
509
356
|
async buildOrder(params) {
|
|
510
357
|
throw new Error('Method buildOrder not implemented.');
|
|
@@ -514,16 +361,6 @@ class PredictionMarketExchange {
|
|
|
514
361
|
*
|
|
515
362
|
* @param built - A BuiltOrder from buildOrder()
|
|
516
363
|
* @returns The submitted order
|
|
517
|
-
*
|
|
518
|
-
* @example-ts Submit a pre-built order
|
|
519
|
-
* const built = await exchange.buildOrder(params);
|
|
520
|
-
* const order = await exchange.submitOrder(built);
|
|
521
|
-
* console.log(`Order ${order.id}: ${order.status}`);
|
|
522
|
-
*
|
|
523
|
-
* @example-python Submit a pre-built order
|
|
524
|
-
* built = exchange.build_order(params)
|
|
525
|
-
* order = exchange.submit_order(built)
|
|
526
|
-
* print(f"Order {order.id}: {order.status}")
|
|
527
364
|
*/
|
|
528
365
|
async submitOrder(built) {
|
|
529
366
|
throw new Error('Method submitOrder not implemented.');
|
|
@@ -533,14 +370,6 @@ class PredictionMarketExchange {
|
|
|
533
370
|
*
|
|
534
371
|
* @param orderId - The order ID to cancel
|
|
535
372
|
* @returns The cancelled order
|
|
536
|
-
*
|
|
537
|
-
* @example-ts Cancel an order
|
|
538
|
-
* const cancelled = await exchange.cancelOrder('order-123');
|
|
539
|
-
* console.log(cancelled.status); // 'cancelled'
|
|
540
|
-
*
|
|
541
|
-
* @example-python Cancel an order
|
|
542
|
-
* cancelled = exchange.cancel_order('order-123')
|
|
543
|
-
* print(cancelled.status) # 'cancelled'
|
|
544
373
|
*/
|
|
545
374
|
async cancelOrder(orderId) {
|
|
546
375
|
throw new Error("Method cancelOrder not implemented.");
|
|
@@ -550,14 +379,6 @@ class PredictionMarketExchange {
|
|
|
550
379
|
*
|
|
551
380
|
* @param orderId - The order ID to look up
|
|
552
381
|
* @returns The order details
|
|
553
|
-
*
|
|
554
|
-
* @example-ts Fetch order status
|
|
555
|
-
* const order = await exchange.fetchOrder('order-456');
|
|
556
|
-
* console.log(`Filled: ${order.filled}/${order.amount}`);
|
|
557
|
-
*
|
|
558
|
-
* @example-python Fetch order status
|
|
559
|
-
* order = exchange.fetch_order('order-456')
|
|
560
|
-
* print(f"Filled: {order.filled}/{order.amount}")
|
|
561
382
|
*/
|
|
562
383
|
async fetchOrder(orderId) {
|
|
563
384
|
throw new Error("Method fetchOrder not implemented.");
|
|
@@ -567,23 +388,6 @@ class PredictionMarketExchange {
|
|
|
567
388
|
*
|
|
568
389
|
* @param marketId - Optional market ID to filter by
|
|
569
390
|
* @returns Array of open orders
|
|
570
|
-
*
|
|
571
|
-
* @example-ts Fetch all open orders
|
|
572
|
-
* const orders = await exchange.fetchOpenOrders();
|
|
573
|
-
* for (const order of orders) {
|
|
574
|
-
* console.log(`${order.side} ${order.amount} @ ${order.price}`);
|
|
575
|
-
* }
|
|
576
|
-
*
|
|
577
|
-
* @example-ts Fetch orders for a specific market
|
|
578
|
-
* const orders = await exchange.fetchOpenOrders('FED-25JAN');
|
|
579
|
-
*
|
|
580
|
-
* @example-python Fetch all open orders
|
|
581
|
-
* orders = exchange.fetch_open_orders()
|
|
582
|
-
* for order in orders:
|
|
583
|
-
* print(f"{order.side} {order.amount} @ {order.price}")
|
|
584
|
-
*
|
|
585
|
-
* @example-python Fetch orders for a specific market
|
|
586
|
-
* orders = exchange.fetch_open_orders('FED-25JAN')
|
|
587
391
|
*/
|
|
588
392
|
async fetchOpenOrders(marketId) {
|
|
589
393
|
throw new Error("Method fetchOpenOrders not implemented.");
|
|
@@ -602,19 +406,6 @@ class PredictionMarketExchange {
|
|
|
602
406
|
*
|
|
603
407
|
* @param address - Optional public wallet address
|
|
604
408
|
* @returns Array of user positions
|
|
605
|
-
*
|
|
606
|
-
* @example-ts Fetch positions
|
|
607
|
-
* const positions = await exchange.fetchPositions();
|
|
608
|
-
* for (const pos of positions) {
|
|
609
|
-
* console.log(`${pos.outcomeLabel}: ${pos.size} @ $${pos.entryPrice}`);
|
|
610
|
-
* console.log(`Unrealized P&L: $${pos.unrealizedPnL.toFixed(2)}`);
|
|
611
|
-
* }
|
|
612
|
-
*
|
|
613
|
-
* @example-python Fetch positions
|
|
614
|
-
* positions = exchange.fetch_positions()
|
|
615
|
-
* for pos in positions:
|
|
616
|
-
* print(f"{pos.outcome_label}: {pos.size} @ ${pos.entry_price}")
|
|
617
|
-
* print(f"Unrealized P&L: ${pos.unrealized_pnl:.2f}")
|
|
618
409
|
*/
|
|
619
410
|
async fetchPositions(address) {
|
|
620
411
|
throw new Error("Method fetchPositions not implemented.");
|
|
@@ -624,14 +415,6 @@ class PredictionMarketExchange {
|
|
|
624
415
|
*
|
|
625
416
|
* @param address - Optional public wallet address
|
|
626
417
|
* @returns Array of account balances
|
|
627
|
-
*
|
|
628
|
-
* @example-ts Fetch balance
|
|
629
|
-
* const balances = await exchange.fetchBalance();
|
|
630
|
-
* console.log(`Available: $${balances[0].available}`);
|
|
631
|
-
*
|
|
632
|
-
* @example-python Fetch balance
|
|
633
|
-
* balances = exchange.fetch_balance()
|
|
634
|
-
* print(f"Available: ${balances[0].available}")
|
|
635
418
|
*/
|
|
636
419
|
async fetchBalance(address) {
|
|
637
420
|
throw new Error("Method fetchBalance not implemented.");
|
|
@@ -644,16 +427,6 @@ class PredictionMarketExchange {
|
|
|
644
427
|
* @param side - 'buy' or 'sell'
|
|
645
428
|
* @param amount - Number of contracts to simulate
|
|
646
429
|
* @returns Average execution price, or 0 if insufficient liquidity
|
|
647
|
-
*
|
|
648
|
-
* @example-ts Get execution price
|
|
649
|
-
* const book = await exchange.fetchOrderBook(outcome.outcomeId);
|
|
650
|
-
* const price = exchange.getExecutionPrice(book, 'buy', 100);
|
|
651
|
-
* console.log(`Avg price for 100 contracts: ${price}`);
|
|
652
|
-
*
|
|
653
|
-
* @example-python Get execution price
|
|
654
|
-
* book = exchange.fetch_order_book(outcome.outcome_id)
|
|
655
|
-
* price = exchange.get_execution_price(book, 'buy', 100)
|
|
656
|
-
* print(f"Avg price for 100 contracts: {price}")
|
|
657
430
|
*/
|
|
658
431
|
getExecutionPrice(orderBook, side, amount) {
|
|
659
432
|
return (0, math_1.getExecutionPrice)(orderBook, side, amount);
|
|
@@ -665,20 +438,6 @@ class PredictionMarketExchange {
|
|
|
665
438
|
* @param side - 'buy' or 'sell'
|
|
666
439
|
* @param amount - Number of contracts to simulate
|
|
667
440
|
* @returns Detailed execution result with price, filled amount, and fill status
|
|
668
|
-
*
|
|
669
|
-
* @example-ts Get detailed execution price
|
|
670
|
-
* const book = await exchange.fetchOrderBook(outcome.outcomeId);
|
|
671
|
-
* const result = exchange.getExecutionPriceDetailed(book, 'buy', 100);
|
|
672
|
-
* console.log(`Price: ${result.price}`);
|
|
673
|
-
* console.log(`Filled: ${result.filledAmount}/${100}`);
|
|
674
|
-
* console.log(`Fully filled: ${result.fullyFilled}`);
|
|
675
|
-
*
|
|
676
|
-
* @example-python Get detailed execution price
|
|
677
|
-
* book = exchange.fetch_order_book(outcome.outcome_id)
|
|
678
|
-
* result = exchange.get_execution_price_detailed(book, 'buy', 100)
|
|
679
|
-
* print(f"Price: {result.price}")
|
|
680
|
-
* print(f"Filled: {result.filled_amount}/100")
|
|
681
|
-
* print(f"Fully filled: {result.fully_filled}")
|
|
682
441
|
*/
|
|
683
442
|
getExecutionPriceDetailed(orderBook, side, amount) {
|
|
684
443
|
return (0, math_1.getExecutionPriceDetailed)(orderBook, side, amount);
|
|
@@ -690,36 +449,6 @@ class PredictionMarketExchange {
|
|
|
690
449
|
* @param markets - Array of markets to filter
|
|
691
450
|
* @param criteria - Filter criteria: string (text search), object (structured), or function (predicate)
|
|
692
451
|
* @returns Filtered array of markets
|
|
693
|
-
*
|
|
694
|
-
* @example-ts Simple text search
|
|
695
|
-
* const filtered = exchange.filterMarkets(markets, 'Trump');
|
|
696
|
-
*
|
|
697
|
-
* @example-ts Advanced criteria
|
|
698
|
-
* const undervalued = exchange.filterMarkets(markets, {
|
|
699
|
-
* text: 'Election',
|
|
700
|
-
* volume24h: { min: 10000 },
|
|
701
|
-
* price: { outcome: 'yes', max: 0.4 }
|
|
702
|
-
* });
|
|
703
|
-
*
|
|
704
|
-
* @example-ts Custom predicate
|
|
705
|
-
* const volatile = exchange.filterMarkets(markets,
|
|
706
|
-
* m => m.yes?.priceChange24h < -0.1
|
|
707
|
-
* );
|
|
708
|
-
*
|
|
709
|
-
* @example-python Simple text search
|
|
710
|
-
* filtered = exchange.filter_markets(markets, 'Trump')
|
|
711
|
-
*
|
|
712
|
-
* @example-python Advanced criteria
|
|
713
|
-
* undervalued = exchange.filter_markets(markets, {
|
|
714
|
-
* 'text': 'Election',
|
|
715
|
-
* 'volume_24h': {'min': 10000},
|
|
716
|
-
* 'price': {'outcome': 'yes', 'max': 0.4}
|
|
717
|
-
* })
|
|
718
|
-
*
|
|
719
|
-
* @example-python Custom predicate
|
|
720
|
-
* volatile = exchange.filter_markets(markets,
|
|
721
|
-
* lambda m: m.yes and m.yes.price_change_24h < -0.1
|
|
722
|
-
* )
|
|
723
452
|
*/
|
|
724
453
|
filterMarkets(markets, criteria) {
|
|
725
454
|
// Handle predicate function
|
|
@@ -856,18 +585,6 @@ class PredictionMarketExchange {
|
|
|
856
585
|
* @param events - Array of events to filter
|
|
857
586
|
* @param criteria - Filter criteria: string (text search), object (structured), or function (predicate)
|
|
858
587
|
* @returns Filtered array of events
|
|
859
|
-
*
|
|
860
|
-
* @example-ts Filter by category
|
|
861
|
-
* const filtered = exchange.filterEvents(events, {
|
|
862
|
-
* category: 'Politics',
|
|
863
|
-
* marketCount: { min: 5 }
|
|
864
|
-
* });
|
|
865
|
-
*
|
|
866
|
-
* @example-python Filter by category
|
|
867
|
-
* filtered = exchange.filter_events(events, {
|
|
868
|
-
* 'category': 'Politics',
|
|
869
|
-
* 'market_count': {'min': 5}
|
|
870
|
-
* })
|
|
871
588
|
*/
|
|
872
589
|
filterEvents(events, criteria) {
|
|
873
590
|
// Handle predicate function
|
|
@@ -947,17 +664,6 @@ class PredictionMarketExchange {
|
|
|
947
664
|
* @param id - The Outcome ID to watch
|
|
948
665
|
* @param limit - Optional limit for orderbook depth
|
|
949
666
|
* @returns Promise that resolves with the current orderbook state
|
|
950
|
-
*
|
|
951
|
-
* @example-ts Stream order book
|
|
952
|
-
* while (true) {
|
|
953
|
-
* const book = await exchange.watchOrderBook(outcome.outcomeId);
|
|
954
|
-
* console.log(`Bid: ${book.bids[0]?.price} Ask: ${book.asks[0]?.price}`);
|
|
955
|
-
* }
|
|
956
|
-
*
|
|
957
|
-
* @example-python Stream order book
|
|
958
|
-
* while True:
|
|
959
|
-
* book = exchange.watch_order_book(outcome.outcome_id)
|
|
960
|
-
* print(f"Bid: {book.bids[0].price} Ask: {book.asks[0].price}")
|
|
961
667
|
*/
|
|
962
668
|
async watchOrderBook(id, limit) {
|
|
963
669
|
throw new Error(`watchOrderBook() is not supported by ${this.name}`);
|
|
@@ -974,20 +680,6 @@ class PredictionMarketExchange {
|
|
|
974
680
|
* @param since - Optional timestamp to filter trades from
|
|
975
681
|
* @param limit - Optional limit for number of trades
|
|
976
682
|
* @returns Promise that resolves with recent trades
|
|
977
|
-
*
|
|
978
|
-
* @example-ts Stream trades
|
|
979
|
-
* while (true) {
|
|
980
|
-
* const trades = await exchange.watchTrades(outcome.outcomeId);
|
|
981
|
-
* for (const trade of trades) {
|
|
982
|
-
* console.log(`${trade.side} ${trade.amount} @ ${trade.price}`);
|
|
983
|
-
* }
|
|
984
|
-
* }
|
|
985
|
-
*
|
|
986
|
-
* @example-python Stream trades
|
|
987
|
-
* while True:
|
|
988
|
-
* trades = exchange.watch_trades(outcome.outcome_id)
|
|
989
|
-
* for trade in trades:
|
|
990
|
-
* print(f"{trade.side} {trade.amount} @ {trade.price}")
|
|
991
683
|
*/
|
|
992
684
|
async watchTrades(id, address, since, limit) {
|
|
993
685
|
throw new Error(`watchTrades() is not supported by ${this.name}`);
|
|
@@ -1000,17 +692,6 @@ class PredictionMarketExchange {
|
|
|
1000
692
|
* @param address - Public wallet address to watch
|
|
1001
693
|
* @param types - Subset of activity to watch (default: all types)
|
|
1002
694
|
* @returns Promise that resolves with the latest SubscribedAddressSnapshot snapshot
|
|
1003
|
-
*
|
|
1004
|
-
* @example-ts Stream wallet activity
|
|
1005
|
-
* while (true) {
|
|
1006
|
-
* const activity = await exchange.watchAddress('0xabc...', ['trades', 'positions']);
|
|
1007
|
-
* console.log(activity.trades, activity.positions);
|
|
1008
|
-
* }
|
|
1009
|
-
*
|
|
1010
|
-
* @example-python Stream wallet activity
|
|
1011
|
-
* while True:
|
|
1012
|
-
* activity = exchange.watch_address('0xabc...', ['trades', 'positions'])
|
|
1013
|
-
* print(activity.trades, activity.positions)
|
|
1014
695
|
*/
|
|
1015
696
|
async watchAddress(address, types) {
|
|
1016
697
|
throw new Error(`watchAddress() is not supported by ${this.name}`);
|
|
@@ -1019,12 +700,6 @@ class PredictionMarketExchange {
|
|
|
1019
700
|
* Stop watching a previously registered wallet address and release its resource updates.
|
|
1020
701
|
*
|
|
1021
702
|
* @param address - Public wallet address to stop watching
|
|
1022
|
-
*
|
|
1023
|
-
* @example-ts Stop watching
|
|
1024
|
-
* await exchange.unwatchAddress('0xabc...');
|
|
1025
|
-
*
|
|
1026
|
-
* @example-python Stop watching
|
|
1027
|
-
* exchange.unwatch_address('0xabc...')
|
|
1028
703
|
*/
|
|
1029
704
|
async unwatchAddress(address) {
|
|
1030
705
|
throw new Error(`unwatchAddress() is not supported by ${this.name}`);
|
|
@@ -1032,12 +707,6 @@ class PredictionMarketExchange {
|
|
|
1032
707
|
/**
|
|
1033
708
|
* Close all WebSocket connections and clean up resources.
|
|
1034
709
|
* Call this when you're done streaming to properly release connections.
|
|
1035
|
-
*
|
|
1036
|
-
* @example-ts Close connections
|
|
1037
|
-
* await exchange.close();
|
|
1038
|
-
*
|
|
1039
|
-
* @example-python Close connections
|
|
1040
|
-
* exchange.close()
|
|
1041
710
|
*/
|
|
1042
711
|
async close() {
|
|
1043
712
|
// Default implementation: no-op
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
|
|
3
|
-
* Generated at: 2026-04-
|
|
3
|
+
* Generated at: 2026-04-10T08:47:55.754Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const kalshiApiSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.kalshiApiSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
|
|
6
|
-
* Generated at: 2026-04-
|
|
6
|
+
* Generated at: 2026-04-10T08:47:55.754Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.kalshiApiSpec = {
|
|
@@ -21,5 +21,8 @@ export declare class KalshiNormalizer implements IExchangeNormalizer<KalshiRawEv
|
|
|
21
21
|
}): Balance[];
|
|
22
22
|
private mapOrderStatus;
|
|
23
23
|
private deriveEventDescription;
|
|
24
|
+
private deriveOutcomeLabel;
|
|
25
|
+
private cleanLabel;
|
|
26
|
+
private templateRule;
|
|
24
27
|
}
|
|
25
28
|
export declare function sortRawEvents(events: any[], sort: string): any[];
|
|
@@ -34,10 +34,7 @@ class KalshiNormalizer {
|
|
|
34
34
|
else if (market.yes_ask) {
|
|
35
35
|
price = (0, price_1.fromKalshiCents)(market.yes_ask);
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
if (market.subtitle || market.yes_sub_title) {
|
|
39
|
-
candidateName = (market.subtitle || market.yes_sub_title);
|
|
40
|
-
}
|
|
37
|
+
const candidateName = this.deriveOutcomeLabel(market);
|
|
41
38
|
let priceChange = 0;
|
|
42
39
|
if (market.previous_price_dollars !== undefined && market.last_price_dollars !== undefined) {
|
|
43
40
|
priceChange = market.last_price_dollars - market.previous_price_dollars;
|
|
@@ -261,27 +258,64 @@ class KalshiNormalizer {
|
|
|
261
258
|
return '';
|
|
262
259
|
if (texts.length === 1)
|
|
263
260
|
return texts[0];
|
|
264
|
-
|
|
265
|
-
for (const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
261
|
+
const templates = new Map();
|
|
262
|
+
for (const market of markets) {
|
|
263
|
+
const rawRule = typeof market?.rules_primary === 'string' ? market.rules_primary : '';
|
|
264
|
+
if (!rawRule)
|
|
265
|
+
continue;
|
|
266
|
+
const candidate = this.deriveOutcomeLabel(market);
|
|
267
|
+
const templated = this.templateRule(rawRule, candidate);
|
|
268
|
+
templates.set(templated, (templates.get(templated) ?? 0) + 1);
|
|
270
269
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
270
|
+
// Only consider templates that actually contain the {x} placeholder so
|
|
271
|
+
// that a rule we failed to template (e.g. candidate name missing) can
|
|
272
|
+
// never win the vote and leak a specific name into the event description.
|
|
273
|
+
if (templates.size > 0) {
|
|
274
|
+
let bestTemplate = null;
|
|
275
|
+
let bestCount = 0;
|
|
276
|
+
for (const [template, count] of templates.entries()) {
|
|
277
|
+
if (!template.includes('{x}'))
|
|
278
|
+
continue;
|
|
279
|
+
if (count > bestCount) {
|
|
280
|
+
bestTemplate = template;
|
|
281
|
+
bestCount = count;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (bestTemplate)
|
|
285
|
+
return bestTemplate;
|
|
278
286
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
287
|
+
return texts[0];
|
|
288
|
+
}
|
|
289
|
+
deriveOutcomeLabel(market) {
|
|
290
|
+
const yesSubtitle = this.cleanLabel(market.yes_sub_title);
|
|
291
|
+
if (yesSubtitle)
|
|
292
|
+
return yesSubtitle;
|
|
293
|
+
const subtitle = this.cleanLabel(market.subtitle);
|
|
294
|
+
if (subtitle)
|
|
295
|
+
return subtitle;
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
cleanLabel(value) {
|
|
299
|
+
if (typeof value !== 'string')
|
|
300
|
+
return null;
|
|
301
|
+
const trimmed = value.trim();
|
|
302
|
+
if (!trimmed)
|
|
303
|
+
return null;
|
|
304
|
+
// Some Kalshi markets use structural subtitles like ":: Democratic".
|
|
305
|
+
if (trimmed.startsWith('::'))
|
|
306
|
+
return null;
|
|
307
|
+
return trimmed;
|
|
308
|
+
}
|
|
309
|
+
templateRule(rule, candidateName) {
|
|
310
|
+
if (!candidateName)
|
|
311
|
+
return rule;
|
|
312
|
+
const escaped = candidateName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
313
|
+
// Unicode-aware word boundaries so non-ASCII candidate names (Jose,
|
|
314
|
+
// Muller, O'Brien, etc.) still template correctly. JavaScript's \b is
|
|
315
|
+
// ASCII-only and would silently fail on such names.
|
|
316
|
+
const matcher = new RegExp(`(?<![\\p{L}\\p{N}])${escaped}(?![\\p{L}\\p{N}])`, 'gu');
|
|
317
|
+
const replaced = rule.replace(matcher, '{x}');
|
|
318
|
+
return replaced === rule ? rule : replaced;
|
|
285
319
|
}
|
|
286
320
|
}
|
|
287
321
|
exports.KalshiNormalizer = KalshiNormalizer;
|
|
@@ -18,11 +18,17 @@ function mapMarketToUnified(event, market) {
|
|
|
18
18
|
else if (market.yes_ask) {
|
|
19
19
|
price = (0, price_1.fromKalshiCents)(market.yes_ask);
|
|
20
20
|
}
|
|
21
|
-
// Extract candidate name
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
// Extract candidate name. Prefer explicit outcome subtitle and ignore
|
|
22
|
+
// structural labels such as ":: Democratic".
|
|
23
|
+
const cleanLabel = (value) => {
|
|
24
|
+
if (typeof value !== "string")
|
|
25
|
+
return null;
|
|
26
|
+
const trimmed = value.trim();
|
|
27
|
+
if (!trimmed || trimmed.startsWith("::"))
|
|
28
|
+
return null;
|
|
29
|
+
return trimmed;
|
|
30
|
+
};
|
|
31
|
+
const candidateName = cleanLabel(market.yes_sub_title) ?? cleanLabel(market.subtitle);
|
|
26
32
|
// Calculate 24h change
|
|
27
33
|
let priceChange = 0;
|
|
28
34
|
if (market.previous_price_dollars !== undefined &&
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
|
|
3
|
-
* Generated at: 2026-04-
|
|
3
|
+
* Generated at: 2026-04-10T08:47:55.810Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const limitlessApiSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.limitlessApiSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
|
|
6
|
-
* Generated at: 2026-04-
|
|
6
|
+
* Generated at: 2026-04-10T08:47:55.810Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.limitlessApiSpec = {
|