pmxt-core 2.9.2 → 2.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/BaseExchange.d.ts +118 -4
  2. package/dist/BaseExchange.js +160 -7
  3. package/dist/exchanges/baozi/fetchEvents.js +16 -11
  4. package/dist/exchanges/baozi/index.d.ts +5 -0
  5. package/dist/exchanges/baozi/index.js +6 -0
  6. package/dist/exchanges/kalshi/api.d.ts +7 -1
  7. package/dist/exchanges/kalshi/api.js +11 -2
  8. package/dist/exchanges/kalshi/config.d.ts +103 -0
  9. package/dist/exchanges/kalshi/config.js +144 -0
  10. package/dist/exchanges/kalshi/fetchEvents.d.ts +2 -2
  11. package/dist/exchanges/kalshi/fetchEvents.js +138 -67
  12. package/dist/exchanges/kalshi/fetchMarkets.d.ts +2 -2
  13. package/dist/exchanges/kalshi/fetchMarkets.js +36 -25
  14. package/dist/exchanges/kalshi/fetchOHLCV.d.ts +3 -3
  15. package/dist/exchanges/kalshi/fetchOHLCV.js +20 -17
  16. package/dist/exchanges/kalshi/fetchOrderBook.d.ts +2 -0
  17. package/dist/exchanges/kalshi/fetchOrderBook.js +60 -0
  18. package/dist/exchanges/kalshi/fetchTrades.d.ts +3 -0
  19. package/dist/exchanges/kalshi/fetchTrades.js +32 -0
  20. package/dist/exchanges/kalshi/index.d.ts +20 -4
  21. package/dist/exchanges/kalshi/index.js +171 -90
  22. package/dist/exchanges/kalshi/kalshi.test.js +440 -157
  23. package/dist/exchanges/kalshi/utils.d.ts +1 -3
  24. package/dist/exchanges/kalshi/utils.js +15 -16
  25. package/dist/exchanges/kalshi/websocket.d.ts +4 -3
  26. package/dist/exchanges/kalshi/websocket.js +87 -61
  27. package/dist/exchanges/kalshi-demo/index.d.ts +10 -0
  28. package/dist/exchanges/kalshi-demo/index.js +23 -0
  29. package/dist/exchanges/limitless/api.d.ts +1 -1
  30. package/dist/exchanges/limitless/api.js +1 -1
  31. package/dist/exchanges/limitless/fetchEvents.d.ts +2 -1
  32. package/dist/exchanges/limitless/fetchEvents.js +95 -49
  33. package/dist/exchanges/limitless/fetchOHLCV.d.ts +2 -2
  34. package/dist/exchanges/limitless/index.d.ts +11 -3
  35. package/dist/exchanges/limitless/index.js +69 -1
  36. package/dist/exchanges/limitless/utils.js +1 -0
  37. package/dist/exchanges/myriad/api.d.ts +1 -1
  38. package/dist/exchanges/myriad/api.js +1 -1
  39. package/dist/exchanges/myriad/fetchOHLCV.d.ts +2 -2
  40. package/dist/exchanges/myriad/index.d.ts +9 -3
  41. package/dist/exchanges/myriad/index.js +34 -0
  42. package/dist/exchanges/myriad/utils.js +5 -1
  43. package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
  44. package/dist/exchanges/polymarket/api-clob.js +1 -1
  45. package/dist/exchanges/polymarket/api-data.d.ts +1 -1
  46. package/dist/exchanges/polymarket/api-data.js +1 -1
  47. package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
  48. package/dist/exchanges/polymarket/api-gamma.js +1 -1
  49. package/dist/exchanges/polymarket/auth.js +3 -1
  50. package/dist/exchanges/polymarket/fetchEvents.js +116 -80
  51. package/dist/exchanges/polymarket/fetchOHLCV.d.ts +2 -2
  52. package/dist/exchanges/polymarket/index.d.ts +30 -6
  53. package/dist/exchanges/polymarket/index.js +101 -31
  54. package/dist/exchanges/polymarket/utils.js +1 -0
  55. package/dist/exchanges/probable/api.d.ts +1 -1
  56. package/dist/exchanges/probable/api.js +1 -1
  57. package/dist/exchanges/probable/index.d.ts +45 -3
  58. package/dist/exchanges/probable/index.js +61 -0
  59. package/dist/exchanges/probable/utils.js +5 -1
  60. package/dist/index.d.ts +4 -0
  61. package/dist/index.js +5 -1
  62. package/dist/server/app.js +56 -48
  63. package/dist/server/utils/port-manager.js +1 -1
  64. package/dist/types.d.ts +29 -0
  65. package/dist/utils/throttler.d.ts +17 -0
  66. package/dist/utils/throttler.js +50 -0
  67. package/package.json +7 -4
@@ -1,4 +1,4 @@
1
- import { UnifiedMarket, UnifiedEvent, PriceCandle, CandleInterval, OrderBook, Trade, Order, Position, Balance, CreateOrderParams } from './types';
1
+ import { UnifiedMarket, UnifiedEvent, PriceCandle, CandleInterval, OrderBook, Trade, UserTrade, Order, Position, Balance, CreateOrderParams, BuiltOrder } from './types';
2
2
  import { ExecutionPriceResult } from './utils/math';
3
3
  import { AxiosInstance } from 'axios';
4
4
  export interface ApiEndpoint {
@@ -37,6 +37,7 @@ export interface EventFetchParams {
37
37
  query?: string;
38
38
  limit?: number;
39
39
  offset?: number;
40
+ sort?: 'volume' | 'liquidity' | 'newest';
40
41
  status?: 'active' | 'inactive' | 'closed' | 'all';
41
42
  searchIn?: 'title' | 'description' | 'both';
42
43
  eventId?: string;
@@ -59,6 +60,21 @@ export interface TradesParams {
59
60
  end?: Date;
60
61
  limit?: number;
61
62
  }
63
+ export interface MyTradesParams {
64
+ outcomeId?: string;
65
+ marketId?: string;
66
+ since?: Date;
67
+ until?: Date;
68
+ limit?: number;
69
+ cursor?: string;
70
+ }
71
+ export interface OrderHistoryParams {
72
+ marketId?: string;
73
+ since?: Date;
74
+ until?: Date;
75
+ limit?: number;
76
+ cursor?: string;
77
+ }
62
78
  export type MarketFilterCriteria = {
63
79
  text?: string;
64
80
  searchIn?: ('title' | 'description' | 'category' | 'tags' | 'outcomes')[];
@@ -126,6 +142,11 @@ export interface ExchangeHas {
126
142
  fetchBalance: ExchangeCapability;
127
143
  watchOrderBook: ExchangeCapability;
128
144
  watchTrades: ExchangeCapability;
145
+ fetchMyTrades: ExchangeCapability;
146
+ fetchClosedOrders: ExchangeCapability;
147
+ fetchAllOrders: ExchangeCapability;
148
+ buildOrder: ExchangeCapability;
149
+ submitOrder: ExchangeCapability;
129
150
  }
130
151
  export interface ExchangeCredentials {
131
152
  apiKey?: string;
@@ -135,18 +156,39 @@ export interface ExchangeCredentials {
135
156
  signatureType?: number | string;
136
157
  funderAddress?: string;
137
158
  }
159
+ export interface ExchangeOptions {
160
+ /**
161
+ * How long (ms) a market snapshot created by `fetchMarketsPaginated` remains valid
162
+ * before being discarded and re-fetched from the API on the next call.
163
+ * Defaults to 0 (no TTL — the snapshot is re-fetched on every initial call).
164
+ */
165
+ snapshotTTL?: number;
166
+ }
167
+ /** Shape returned by fetchMarketsPaginated */
168
+ export interface PaginatedMarketsResult {
169
+ data: UnifiedMarket[];
170
+ total: number;
171
+ nextCursor?: string;
172
+ }
138
173
  export declare abstract class PredictionMarketExchange {
139
174
  [key: string]: any;
140
175
  protected credentials?: ExchangeCredentials;
141
176
  verbose: boolean;
142
177
  http: AxiosInstance;
178
+ enableRateLimit: boolean;
179
+ private _rateLimit;
180
+ private _throttler;
181
+ private _snapshotTTL;
182
+ private _snapshot?;
183
+ get rateLimit(): number;
184
+ set rateLimit(value: number);
143
185
  markets: Record<string, UnifiedMarket>;
144
186
  marketsBySlug: Record<string, UnifiedMarket>;
145
187
  loadedMarkets: boolean;
146
188
  protected apiDescriptor?: ApiDescriptor;
147
189
  private apiDescriptors;
148
190
  readonly has: ExchangeHas;
149
- constructor(credentials?: ExchangeCredentials);
191
+ constructor(credentials?: ExchangeCredentials, options?: ExchangeOptions);
150
192
  abstract get name(): string;
151
193
  /**
152
194
  * Load and cache all markets from the exchange into `this.markets` and `this.marketsBySlug`.
@@ -208,12 +250,31 @@ export declare abstract class PredictionMarketExchange {
208
250
  * markets = exchange.fetch_markets(slug='will-trump-win')
209
251
  */
210
252
  fetchMarkets(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
253
+ /**
254
+ * Fetch markets with cursor-based pagination backed by a stable in-memory snapshot.
255
+ *
256
+ * On the first call (or when no cursor is supplied), fetches all markets once and
257
+ * caches them. Subsequent calls with a cursor returned from a previous call slice
258
+ * directly from the cached snapshot — no additional API calls are made.
259
+ *
260
+ * The snapshot is invalidated after `snapshotTTL` ms (configured via `ExchangeOptions`
261
+ * in the constructor). A request using a cursor from an expired snapshot throws
262
+ * `'Cursor has expired'`.
263
+ *
264
+ * @param params.limit - Page size (default: return all markets)
265
+ * @param params.cursor - Opaque cursor returned by a previous call
266
+ * @returns PaginatedMarketsResult with data, total, and optional nextCursor
267
+ */
268
+ fetchMarketsPaginated(params?: {
269
+ limit?: number;
270
+ cursor?: string;
271
+ }): Promise<PaginatedMarketsResult>;
211
272
  /**
212
273
  * Fetch events with optional keyword search.
213
274
  * Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
214
275
  *
215
276
  * @param params - Optional parameters for search and filtering
216
- * @param params.query - Search keyword to filter events (required)
277
+ * @param params.query - Search keyword to filter events. If omitted, returns top events by volume.
217
278
  * @param params.limit - Maximum number of results
218
279
  * @param params.offset - Pagination offset
219
280
  * @param params.searchIn - Where to search ('title' | 'description' | 'both')
@@ -302,7 +363,7 @@ export declare abstract class PredictionMarketExchange {
302
363
  * @notes Polymarket: outcomeId is the CLOB Token ID. Kalshi: outcomeId is the Market Ticker.
303
364
  * @notes Resolution options: '1m' | '5m' | '15m' | '1h' | '6h' | '1d'
304
365
  */
305
- fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams): Promise<PriceCandle[]>;
366
+ fetchOHLCV(id: string, params: OHLCVParams): Promise<PriceCandle[]>;
306
367
  /**
307
368
  * Fetch the current order book (bids/asks) for a specific outcome.
308
369
  * Essential for calculating spread, depth, and execution prices.
@@ -391,6 +452,56 @@ export declare abstract class PredictionMarketExchange {
391
452
  * )
392
453
  */
393
454
  createOrder(params: CreateOrderParams): Promise<Order>;
455
+ /**
456
+ * Build an order payload without submitting it to the exchange.
457
+ * Returns the exchange-native signed order or request body for inspection,
458
+ * forwarding through a middleware layer, or deferred submission via submitOrder().
459
+ *
460
+ * @param params - Order parameters (same as createOrder)
461
+ * @returns A BuiltOrder containing the exchange-native payload
462
+ *
463
+ * @example-ts Build then inspect a Polymarket order
464
+ * const built = await exchange.buildOrder({
465
+ * marketId: market.marketId,
466
+ * outcomeId: market.yes.outcomeId,
467
+ * side: 'buy',
468
+ * type: 'limit',
469
+ * amount: 10,
470
+ * price: 0.55
471
+ * });
472
+ * console.log(built.signedOrder); // EIP-712 signed order struct
473
+ * const order = await exchange.submitOrder(built);
474
+ *
475
+ * @example-python Build then submit a Polymarket order
476
+ * built = exchange.build_order(
477
+ * market_id=market.market_id,
478
+ * outcome_id=market.yes.outcome_id,
479
+ * side='buy',
480
+ * type='limit',
481
+ * amount=10,
482
+ * price=0.55
483
+ * )
484
+ * print(built.signed_order)
485
+ * order = exchange.submit_order(built)
486
+ */
487
+ buildOrder(params: CreateOrderParams): Promise<BuiltOrder>;
488
+ /**
489
+ * Submit a pre-built order returned by buildOrder().
490
+ *
491
+ * @param built - A BuiltOrder from buildOrder()
492
+ * @returns The submitted order
493
+ *
494
+ * @example-ts Submit a pre-built order
495
+ * const built = await exchange.buildOrder(params);
496
+ * const order = await exchange.submitOrder(built);
497
+ * console.log(`Order ${order.id}: ${order.status}`);
498
+ *
499
+ * @example-python Submit a pre-built order
500
+ * built = exchange.build_order(params)
501
+ * order = exchange.submit_order(built)
502
+ * print(f"Order {order.id}: {order.status}")
503
+ */
504
+ submitOrder(built: BuiltOrder): Promise<Order>;
394
505
  /**
395
506
  * Cancel an existing open order.
396
507
  *
@@ -445,6 +556,9 @@ export declare abstract class PredictionMarketExchange {
445
556
  * orders = exchange.fetch_open_orders('FED-25JAN')
446
557
  */
447
558
  fetchOpenOrders(marketId?: string): Promise<Order[]>;
559
+ fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
560
+ fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]>;
561
+ fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]>;
448
562
  /**
449
563
  * Fetch current user positions across all markets.
450
564
  *
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.PredictionMarketExchange = void 0;
7
7
  const math_1 = require("./utils/math");
8
8
  const errors_1 = require("./errors");
9
+ const throttler_1 = require("./utils/throttler");
9
10
  const axios_1 = __importDefault(require("axios"));
10
11
  // ----------------------------------------------------------------------------
11
12
  // Base Exchange Class
@@ -14,6 +15,23 @@ class PredictionMarketExchange {
14
15
  credentials;
15
16
  verbose = false;
16
17
  http;
18
+ enableRateLimit = true;
19
+ _rateLimit = 1000;
20
+ _throttler;
21
+ // Snapshot state for cursor-based pagination
22
+ _snapshotTTL;
23
+ _snapshot;
24
+ get rateLimit() {
25
+ return this._rateLimit;
26
+ }
27
+ set rateLimit(value) {
28
+ this._rateLimit = value;
29
+ this._throttler = new throttler_1.Throttler({
30
+ refillRate: 1 / value,
31
+ capacity: 1,
32
+ delay: 1,
33
+ });
34
+ }
17
35
  // Market Cache
18
36
  markets = {};
19
37
  marketsBySlug = {};
@@ -35,10 +53,32 @@ class PredictionMarketExchange {
35
53
  fetchBalance: false,
36
54
  watchOrderBook: false,
37
55
  watchTrades: false,
56
+ fetchMyTrades: false,
57
+ fetchClosedOrders: false,
58
+ fetchAllOrders: false,
59
+ buildOrder: false,
60
+ submitOrder: false,
38
61
  };
39
- constructor(credentials) {
62
+ constructor(credentials, options) {
40
63
  this.credentials = credentials;
41
- this.http = axios_1.default.create();
64
+ this._snapshotTTL = options?.snapshotTTL ?? 0;
65
+ this.http = axios_1.default.create({
66
+ headers: {
67
+ 'User-Agent': `pmxt (https://github.com/pmxt-dev/pmxt)`
68
+ }
69
+ });
70
+ this._throttler = new throttler_1.Throttler({
71
+ refillRate: 1 / this._rateLimit,
72
+ capacity: 1,
73
+ delay: 1,
74
+ });
75
+ // Rate Limit Interceptor
76
+ this.http.interceptors.request.use(async (config) => {
77
+ if (this.enableRateLimit) {
78
+ await this._throttler.throttle();
79
+ }
80
+ return config;
81
+ });
42
82
  // Request Interceptor
43
83
  this.http.interceptors.request.use((config) => {
44
84
  if (this.verbose) {
@@ -150,12 +190,65 @@ class PredictionMarketExchange {
150
190
  async fetchMarkets(params) {
151
191
  return this.fetchMarketsImpl(params);
152
192
  }
193
+ /**
194
+ * Fetch markets with cursor-based pagination backed by a stable in-memory snapshot.
195
+ *
196
+ * On the first call (or when no cursor is supplied), fetches all markets once and
197
+ * caches them. Subsequent calls with a cursor returned from a previous call slice
198
+ * directly from the cached snapshot — no additional API calls are made.
199
+ *
200
+ * The snapshot is invalidated after `snapshotTTL` ms (configured via `ExchangeOptions`
201
+ * in the constructor). A request using a cursor from an expired snapshot throws
202
+ * `'Cursor has expired'`.
203
+ *
204
+ * @param params.limit - Page size (default: return all markets)
205
+ * @param params.cursor - Opaque cursor returned by a previous call
206
+ * @returns PaginatedMarketsResult with data, total, and optional nextCursor
207
+ */
208
+ async fetchMarketsPaginated(params) {
209
+ const limit = params?.limit;
210
+ const cursor = params?.cursor;
211
+ if (cursor) {
212
+ // Cursor encodes: snapshotId:offset
213
+ const sep = cursor.indexOf(':');
214
+ const snapshotId = cursor.substring(0, sep);
215
+ const offset = parseInt(cursor.substring(sep + 1), 10);
216
+ if (!this._snapshot ||
217
+ this._snapshot.id !== snapshotId ||
218
+ (this._snapshotTTL > 0 && Date.now() - this._snapshot.takenAt > this._snapshotTTL)) {
219
+ throw new Error('Cursor has expired');
220
+ }
221
+ const markets = this._snapshot.markets;
222
+ const slice = limit !== undefined ? markets.slice(offset, offset + limit) : markets.slice(offset);
223
+ const nextOffset = offset + slice.length;
224
+ const nextCursor = nextOffset < markets.length ? `${snapshotId}:${nextOffset}` : undefined;
225
+ return { data: slice, total: markets.length, nextCursor };
226
+ }
227
+ // No cursor — (re)fetch snapshot
228
+ if (!this._snapshot ||
229
+ this._snapshotTTL === 0 ||
230
+ Date.now() - this._snapshot.takenAt > this._snapshotTTL) {
231
+ const markets = await this.fetchMarketsImpl();
232
+ this._snapshot = {
233
+ markets,
234
+ takenAt: Date.now(),
235
+ id: Math.random().toString(36).slice(2),
236
+ };
237
+ }
238
+ const markets = this._snapshot.markets;
239
+ if (!limit) {
240
+ return { data: markets, total: markets.length, nextCursor: undefined };
241
+ }
242
+ const slice = markets.slice(0, limit);
243
+ const nextCursor = limit < markets.length ? `${this._snapshot.id}:${limit}` : undefined;
244
+ return { data: slice, total: markets.length, nextCursor };
245
+ }
153
246
  /**
154
247
  * Fetch events with optional keyword search.
155
248
  * Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
156
249
  *
157
250
  * @param params - Optional parameters for search and filtering
158
- * @param params.query - Search keyword to filter events (required)
251
+ * @param params.query - Search keyword to filter events. If omitted, returns top events by volume.
159
252
  * @param params.limit - Maximum number of results
160
253
  * @param params.offset - Pagination offset
161
254
  * @param params.searchIn - Where to search ('title' | 'description' | 'both')
@@ -174,10 +267,7 @@ class PredictionMarketExchange {
174
267
  * print(fed_event.title, len(fed_event.markets), 'markets')
175
268
  */
176
269
  async fetchEvents(params) {
177
- if (!params?.query && !params?.eventId && !params?.slug) {
178
- throw new Error("fetchEvents() requires a query, eventId, or slug parameter");
179
- }
180
- return this.fetchEventsImpl(params);
270
+ return this.fetchEventsImpl(params ?? {});
181
271
  }
182
272
  /**
183
273
  * Fetch a single market by lookup parameters.
@@ -384,6 +474,60 @@ class PredictionMarketExchange {
384
474
  async createOrder(params) {
385
475
  throw new Error("Method createOrder not implemented.");
386
476
  }
477
+ /**
478
+ * Build an order payload without submitting it to the exchange.
479
+ * Returns the exchange-native signed order or request body for inspection,
480
+ * forwarding through a middleware layer, or deferred submission via submitOrder().
481
+ *
482
+ * @param params - Order parameters (same as createOrder)
483
+ * @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
+ */
509
+ async buildOrder(params) {
510
+ throw new Error("Method buildOrder not implemented.");
511
+ }
512
+ /**
513
+ * Submit a pre-built order returned by buildOrder().
514
+ *
515
+ * @param built - A BuiltOrder from buildOrder()
516
+ * @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
+ */
528
+ async submitOrder(built) {
529
+ throw new Error("Method submitOrder not implemented.");
530
+ }
387
531
  /**
388
532
  * Cancel an existing open order.
389
533
  *
@@ -444,6 +588,15 @@ class PredictionMarketExchange {
444
588
  async fetchOpenOrders(marketId) {
445
589
  throw new Error("Method fetchOpenOrders not implemented.");
446
590
  }
591
+ async fetchMyTrades(params) {
592
+ throw new Error("Method fetchMyTrades not implemented.");
593
+ }
594
+ async fetchClosedOrders(params) {
595
+ throw new Error("Method fetchClosedOrders not implemented.");
596
+ }
597
+ async fetchAllOrders(params) {
598
+ throw new Error("Method fetchAllOrders not implemented.");
599
+ }
447
600
  /**
448
601
  * Fetch current user positions across all markets.
449
602
  *
@@ -16,17 +16,22 @@ async function fetchEvents(connection, params) {
16
16
  status: params.status,
17
17
  searchIn: params.searchIn,
18
18
  });
19
- return markets.map(m => ({
20
- id: m.marketId,
21
- title: m.title,
22
- description: m.description,
23
- slug: m.marketId,
24
- markets: [m],
25
- url: m.url,
26
- image: m.image,
27
- category: m.category,
28
- tags: m.tags,
29
- }));
19
+ return markets.map(m => {
20
+ const unifiedEvent = {
21
+ id: m.marketId,
22
+ title: m.title,
23
+ description: m.description,
24
+ slug: m.marketId,
25
+ markets: [m],
26
+ volume24h: m.volume24h,
27
+ volume: m.volume,
28
+ url: m.url,
29
+ image: m.image,
30
+ category: m.category,
31
+ tags: m.tags,
32
+ };
33
+ return unifiedEvent;
34
+ });
30
35
  }
31
36
  catch (error) {
32
37
  throw errors_1.baoziErrorMapper.mapError(error);
@@ -19,6 +19,11 @@ export declare class BaoziExchange extends PredictionMarketExchange {
19
19
  fetchBalance: true;
20
20
  watchOrderBook: true;
21
21
  watchTrades: false;
22
+ fetchMyTrades: false;
23
+ fetchClosedOrders: false;
24
+ fetchAllOrders: false;
25
+ buildOrder: false;
26
+ submitOrder: false;
22
27
  };
23
28
  private auth?;
24
29
  private connection;
@@ -28,6 +28,11 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
28
28
  fetchBalance: true,
29
29
  watchOrderBook: true,
30
30
  watchTrades: false,
31
+ fetchMyTrades: false,
32
+ fetchClosedOrders: false,
33
+ fetchAllOrders: false,
34
+ buildOrder: false,
35
+ submitOrder: false,
31
36
  };
32
37
  auth;
33
38
  connection;
@@ -43,6 +48,7 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
43
48
  credentials = options;
44
49
  }
45
50
  super(credentials);
51
+ this.rateLimit = 500;
46
52
  rpcUrl = rpcUrl
47
53
  || process.env.BAOZI_RPC_URL
48
54
  || process.env.HELIUS_RPC_URL
@@ -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-02-19T07:57:20.394Z
3
+ * Generated at: 2026-03-04T17:45:20.579Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const kalshiApiSpec: {
@@ -11,6 +11,12 @@ export declare const kalshiApiSpec: {
11
11
  };
12
12
  servers: {
13
13
  url: string;
14
+ variables: {
15
+ env: {
16
+ default: string;
17
+ enum: string[];
18
+ };
19
+ };
14
20
  }[];
15
21
  paths: {
16
22
  "/historical/cutoff": {
@@ -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-02-19T07:57:20.394Z
6
+ * Generated at: 2026-03-04T17:45:20.579Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.kalshiApiSpec = {
@@ -14,7 +14,16 @@ exports.kalshiApiSpec = {
14
14
  },
15
15
  "servers": [
16
16
  {
17
- "url": "https://api.elections.kalshi.com/trade-api/v2"
17
+ "url": "https://{env}.elections.kalshi.com/trade-api/v2",
18
+ "variables": {
19
+ "env": {
20
+ "default": "api",
21
+ "enum": [
22
+ "api",
23
+ "demo-api"
24
+ ]
25
+ }
26
+ }
18
27
  }
19
28
  ],
20
29
  "paths": {
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Kalshi runtime configuration.
3
+ *
4
+ * This file is hand-authored and is the single source of truth for:
5
+ * - Base URL constants for production and demo environments
6
+ * - API path constants (KALSHI_PATHS)
7
+ * - URL helper functions used by fetch functions and the exchange class
8
+ *
9
+ * The OpenAPI spec lives in core/specs/kalshi/Kalshi.yaml and is compiled
10
+ * into core/src/exchanges/kalshi/api.ts by `npm run fetch:openapi`.
11
+ * Do NOT put runtime config into api.ts — it will be overwritten.
12
+ *
13
+ * Environment mapping (aligns with the `{env}` server variable in Kalshi.yaml):
14
+ * env = "api" → production: https://api.elections.kalshi.com
15
+ * env = "demo-api" → demo/paper: https://demo-api.elections.kalshi.com
16
+ */
17
+ export declare const KALSHI_PROD_API_URL = "https://api.elections.kalshi.com";
18
+ export declare const KALSHI_DEMO_API_URL = "https://demo-api.kalshi.co";
19
+ export declare const KALSHI_PROD_WS_URL = "wss://api.elections.kalshi.com/trade-api/ws/v2";
20
+ export declare const KALSHI_DEMO_WS_URL = "wss://demo-api.kalshi.co/trade-api/ws/v2";
21
+ export declare const KALSHI_PATHS: {
22
+ TRADE_API: string;
23
+ EVENTS: string;
24
+ SERIES: string;
25
+ PORTFOLIO: string;
26
+ MARKETS: string;
27
+ BALANCE: string;
28
+ ORDERS: string;
29
+ POSITIONS: string;
30
+ };
31
+ export interface KalshiApiConfig {
32
+ /** Base REST API URL — production or demo */
33
+ apiUrl: string;
34
+ /** WebSocket URL — production or demo */
35
+ wsUrl?: string;
36
+ /** Whether the demo environment is active */
37
+ demoMode: boolean;
38
+ }
39
+ /**
40
+ * Return a typed config object for the requested environment.
41
+ *
42
+ * @param demoMode - Pass `true` to target demo-api.elections.kalshi.com.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const config = getKalshiConfig(true);
47
+ * // config.apiUrl === "https://demo-api.elections.kalshi.com"
48
+ * ```
49
+ */
50
+ export declare function getKalshiConfig(demoMode?: boolean): KalshiApiConfig;
51
+ /**
52
+ * Build the full path (including `/trade-api/v2` prefix) for use in
53
+ * `KalshiAuth.getHeaders()` signing.
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * getApiPath("/portfolio/balance")
58
+ * // → "/trade-api/v2/portfolio/balance"
59
+ * ```
60
+ */
61
+ export declare function getApiPath(operationPath: string): string;
62
+ /**
63
+ * Build the full URL for the events endpoint.
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * getEventsUrl(baseUrl) // .../events
68
+ * getEventsUrl(baseUrl, ['FED-25']) // .../events/FED-25
69
+ * ```
70
+ */
71
+ export declare function getEventsUrl(baseUrl: string, pathSegments?: string[]): string;
72
+ /**
73
+ * Build the full URL for the series endpoint, with optional nested segments.
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * getSeriesUrl(baseUrl) // .../series
78
+ * getSeriesUrl(baseUrl, 'FED') // .../series/FED
79
+ * getSeriesUrl(baseUrl, 'FED', ['markets', 'FED-B4.75', 'candlesticks'])
80
+ * // .../series/FED/markets/FED-B4.75/candlesticks
81
+ * ```
82
+ */
83
+ export declare function getSeriesUrl(baseUrl: string, seriesTicker?: string, pathSegments?: string[]): string;
84
+ /**
85
+ * Build the full URL for the portfolio endpoint.
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * getPortfolioUrl(baseUrl, '/balance') // .../portfolio/balance
90
+ * ```
91
+ */
92
+ export declare function getPortfolioUrl(baseUrl: string, subPath?: string): string;
93
+ /**
94
+ * Build the full URL for the markets endpoint, with optional nested segments.
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * getMarketsUrl(baseUrl) // .../markets
99
+ * getMarketsUrl(baseUrl, 'FED-B4.75') // .../markets/FED-B4.75
100
+ * getMarketsUrl(baseUrl, 'FED-B4.75', ['orderbook']) // .../markets/FED-B4.75/orderbook
101
+ * ```
102
+ */
103
+ export declare function getMarketsUrl(baseUrl: string, marketId?: string, pathSegments?: string[]): string;