pmxt-core 2.11.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 } from './types';
2
2
  import { ExecutionPriceResult } from './utils/math';
3
3
  import { AxiosInstance } from 'axios';
4
4
  export interface ApiEndpoint {
@@ -59,6 +59,21 @@ export interface TradesParams {
59
59
  end?: Date;
60
60
  limit?: number;
61
61
  }
62
+ export interface MyTradesParams {
63
+ outcomeId?: string;
64
+ marketId?: string;
65
+ since?: Date;
66
+ until?: Date;
67
+ limit?: number;
68
+ cursor?: string;
69
+ }
70
+ export interface OrderHistoryParams {
71
+ marketId?: string;
72
+ since?: Date;
73
+ until?: Date;
74
+ limit?: number;
75
+ cursor?: string;
76
+ }
62
77
  export type MarketFilterCriteria = {
63
78
  text?: string;
64
79
  searchIn?: ('title' | 'description' | 'category' | 'tags' | 'outcomes')[];
@@ -126,6 +141,9 @@ export interface ExchangeHas {
126
141
  fetchBalance: ExchangeCapability;
127
142
  watchOrderBook: ExchangeCapability;
128
143
  watchTrades: ExchangeCapability;
144
+ fetchMyTrades: ExchangeCapability;
145
+ fetchClosedOrders: ExchangeCapability;
146
+ fetchAllOrders: ExchangeCapability;
129
147
  }
130
148
  export interface ExchangeCredentials {
131
149
  apiKey?: string;
@@ -135,6 +153,20 @@ export interface ExchangeCredentials {
135
153
  signatureType?: number | string;
136
154
  funderAddress?: string;
137
155
  }
156
+ export interface ExchangeOptions {
157
+ /**
158
+ * How long (ms) a market snapshot created by `fetchMarketsPaginated` remains valid
159
+ * before being discarded and re-fetched from the API on the next call.
160
+ * Defaults to 0 (no TTL — the snapshot is re-fetched on every initial call).
161
+ */
162
+ snapshotTTL?: number;
163
+ }
164
+ /** Shape returned by fetchMarketsPaginated */
165
+ export interface PaginatedMarketsResult {
166
+ data: UnifiedMarket[];
167
+ total: number;
168
+ nextCursor?: string;
169
+ }
138
170
  export declare abstract class PredictionMarketExchange {
139
171
  [key: string]: any;
140
172
  protected credentials?: ExchangeCredentials;
@@ -143,6 +175,8 @@ export declare abstract class PredictionMarketExchange {
143
175
  enableRateLimit: boolean;
144
176
  private _rateLimit;
145
177
  private _throttler;
178
+ private _snapshotTTL;
179
+ private _snapshot?;
146
180
  get rateLimit(): number;
147
181
  set rateLimit(value: number);
148
182
  markets: Record<string, UnifiedMarket>;
@@ -151,7 +185,7 @@ export declare abstract class PredictionMarketExchange {
151
185
  protected apiDescriptor?: ApiDescriptor;
152
186
  private apiDescriptors;
153
187
  readonly has: ExchangeHas;
154
- constructor(credentials?: ExchangeCredentials);
188
+ constructor(credentials?: ExchangeCredentials, options?: ExchangeOptions);
155
189
  abstract get name(): string;
156
190
  /**
157
191
  * Load and cache all markets from the exchange into `this.markets` and `this.marketsBySlug`.
@@ -213,6 +247,25 @@ export declare abstract class PredictionMarketExchange {
213
247
  * markets = exchange.fetch_markets(slug='will-trump-win')
214
248
  */
215
249
  fetchMarkets(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
250
+ /**
251
+ * Fetch markets with cursor-based pagination backed by a stable in-memory snapshot.
252
+ *
253
+ * On the first call (or when no cursor is supplied), fetches all markets once and
254
+ * caches them. Subsequent calls with a cursor returned from a previous call slice
255
+ * directly from the cached snapshot — no additional API calls are made.
256
+ *
257
+ * The snapshot is invalidated after `snapshotTTL` ms (configured via `ExchangeOptions`
258
+ * in the constructor). A request using a cursor from an expired snapshot throws
259
+ * `'Cursor has expired'`.
260
+ *
261
+ * @param params.limit - Page size (default: return all markets)
262
+ * @param params.cursor - Opaque cursor returned by a previous call
263
+ * @returns PaginatedMarketsResult with data, total, and optional nextCursor
264
+ */
265
+ fetchMarketsPaginated(params?: {
266
+ limit?: number;
267
+ cursor?: string;
268
+ }): Promise<PaginatedMarketsResult>;
216
269
  /**
217
270
  * Fetch events with optional keyword search.
218
271
  * Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
@@ -450,6 +503,9 @@ export declare abstract class PredictionMarketExchange {
450
503
  * orders = exchange.fetch_open_orders('FED-25JAN')
451
504
  */
452
505
  fetchOpenOrders(marketId?: string): Promise<Order[]>;
506
+ fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
507
+ fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]>;
508
+ fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]>;
453
509
  /**
454
510
  * Fetch current user positions across all markets.
455
511
  *
@@ -18,6 +18,9 @@ class PredictionMarketExchange {
18
18
  enableRateLimit = true;
19
19
  _rateLimit = 1000;
20
20
  _throttler;
21
+ // Snapshot state for cursor-based pagination
22
+ _snapshotTTL;
23
+ _snapshot;
21
24
  get rateLimit() {
22
25
  return this._rateLimit;
23
26
  }
@@ -50,9 +53,13 @@ class PredictionMarketExchange {
50
53
  fetchBalance: false,
51
54
  watchOrderBook: false,
52
55
  watchTrades: false,
56
+ fetchMyTrades: false,
57
+ fetchClosedOrders: false,
58
+ fetchAllOrders: false,
53
59
  };
54
- constructor(credentials) {
60
+ constructor(credentials, options) {
55
61
  this.credentials = credentials;
62
+ this._snapshotTTL = options?.snapshotTTL ?? 0;
56
63
  this.http = axios_1.default.create();
57
64
  this._throttler = new throttler_1.Throttler({
58
65
  refillRate: 1 / this._rateLimit,
@@ -177,6 +184,59 @@ class PredictionMarketExchange {
177
184
  async fetchMarkets(params) {
178
185
  return this.fetchMarketsImpl(params);
179
186
  }
187
+ /**
188
+ * Fetch markets with cursor-based pagination backed by a stable in-memory snapshot.
189
+ *
190
+ * On the first call (or when no cursor is supplied), fetches all markets once and
191
+ * caches them. Subsequent calls with a cursor returned from a previous call slice
192
+ * directly from the cached snapshot — no additional API calls are made.
193
+ *
194
+ * The snapshot is invalidated after `snapshotTTL` ms (configured via `ExchangeOptions`
195
+ * in the constructor). A request using a cursor from an expired snapshot throws
196
+ * `'Cursor has expired'`.
197
+ *
198
+ * @param params.limit - Page size (default: return all markets)
199
+ * @param params.cursor - Opaque cursor returned by a previous call
200
+ * @returns PaginatedMarketsResult with data, total, and optional nextCursor
201
+ */
202
+ async fetchMarketsPaginated(params) {
203
+ const limit = params?.limit;
204
+ const cursor = params?.cursor;
205
+ if (cursor) {
206
+ // Cursor encodes: snapshotId:offset
207
+ const sep = cursor.indexOf(':');
208
+ const snapshotId = cursor.substring(0, sep);
209
+ const offset = parseInt(cursor.substring(sep + 1), 10);
210
+ if (!this._snapshot ||
211
+ this._snapshot.id !== snapshotId ||
212
+ (this._snapshotTTL > 0 && Date.now() - this._snapshot.takenAt > this._snapshotTTL)) {
213
+ throw new Error('Cursor has expired');
214
+ }
215
+ const markets = this._snapshot.markets;
216
+ const slice = limit !== undefined ? markets.slice(offset, offset + limit) : markets.slice(offset);
217
+ const nextOffset = offset + slice.length;
218
+ const nextCursor = nextOffset < markets.length ? `${snapshotId}:${nextOffset}` : undefined;
219
+ return { data: slice, total: markets.length, nextCursor };
220
+ }
221
+ // No cursor — (re)fetch snapshot
222
+ if (!this._snapshot ||
223
+ this._snapshotTTL === 0 ||
224
+ Date.now() - this._snapshot.takenAt > this._snapshotTTL) {
225
+ const markets = await this.fetchMarketsImpl();
226
+ this._snapshot = {
227
+ markets,
228
+ takenAt: Date.now(),
229
+ id: Math.random().toString(36).slice(2),
230
+ };
231
+ }
232
+ const markets = this._snapshot.markets;
233
+ if (!limit) {
234
+ return { data: markets, total: markets.length, nextCursor: undefined };
235
+ }
236
+ const slice = markets.slice(0, limit);
237
+ const nextCursor = limit < markets.length ? `${this._snapshot.id}:${limit}` : undefined;
238
+ return { data: slice, total: markets.length, nextCursor };
239
+ }
180
240
  /**
181
241
  * Fetch events with optional keyword search.
182
242
  * Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
@@ -471,6 +531,15 @@ class PredictionMarketExchange {
471
531
  async fetchOpenOrders(marketId) {
472
532
  throw new Error("Method fetchOpenOrders not implemented.");
473
533
  }
534
+ async fetchMyTrades(params) {
535
+ throw new Error("Method fetchMyTrades not implemented.");
536
+ }
537
+ async fetchClosedOrders(params) {
538
+ throw new Error("Method fetchClosedOrders not implemented.");
539
+ }
540
+ async fetchAllOrders(params) {
541
+ throw new Error("Method fetchAllOrders not implemented.");
542
+ }
474
543
  /**
475
544
  * Fetch current user positions across all markets.
476
545
  *
@@ -19,6 +19,9 @@ 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;
22
25
  };
23
26
  private auth?;
24
27
  private connection;
@@ -28,6 +28,9 @@ 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,
31
34
  };
32
35
  auth;
33
36
  connection;
@@ -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-22T07:47:40.083Z
3
+ * Generated at: 2026-02-22T14:48:41.786Z
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-02-22T07:47:40.083Z
6
+ * Generated at: 2026-02-22T14:48:41.786Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.kalshiApiSpec = {
@@ -1,5 +1,5 @@
1
- import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams } from '../../BaseExchange';
2
- import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, Balance, Order, Position, CreateOrderParams } from '../../types';
1
+ import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams, MyTradesParams, OrderHistoryParams } from '../../BaseExchange';
2
+ import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Balance, Order, Position, CreateOrderParams } from '../../types';
3
3
  import { KalshiWebSocketConfig } from './websocket';
4
4
  export type { KalshiWebSocketConfig };
5
5
  export interface KalshiExchangeOptions {
@@ -21,6 +21,9 @@ export declare class KalshiExchange extends PredictionMarketExchange {
21
21
  fetchBalance: true;
22
22
  watchOrderBook: true;
23
23
  watchTrades: true;
24
+ fetchMyTrades: true;
25
+ fetchClosedOrders: true;
26
+ fetchAllOrders: true;
24
27
  };
25
28
  private auth?;
26
29
  private wsConfig?;
@@ -39,7 +42,11 @@ export declare class KalshiExchange extends PredictionMarketExchange {
39
42
  cancelOrder(orderId: string): Promise<Order>;
40
43
  fetchOrder(orderId: string): Promise<Order>;
41
44
  fetchOpenOrders(marketId?: string): Promise<Order[]>;
45
+ fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
46
+ fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]>;
47
+ fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]>;
42
48
  fetchPositions(): Promise<Position[]>;
49
+ private mapKalshiOrder;
43
50
  private mapKalshiOrderStatus;
44
51
  private ws?;
45
52
  watchOrderBook(id: string, limit?: number): Promise<OrderBook>;
@@ -27,6 +27,9 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
27
27
  fetchBalance: true,
28
28
  watchOrderBook: true,
29
29
  watchTrades: true,
30
+ fetchMyTrades: true,
31
+ fetchClosedOrders: true,
32
+ fetchAllOrders: true,
30
33
  };
31
34
  auth;
32
35
  wsConfig;
@@ -206,20 +209,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
206
209
  }
207
210
  async fetchOrder(orderId) {
208
211
  const data = await this.callApi('GetOrder', { order_id: orderId });
209
- const order = data.order;
210
- return {
211
- id: order.order_id,
212
- marketId: order.ticker,
213
- outcomeId: order.ticker,
214
- side: order.side === 'yes' ? 'buy' : 'sell',
215
- type: order.type === 'limit' ? 'limit' : 'market',
216
- price: order.yes_price ? order.yes_price / 100 : undefined,
217
- amount: order.count,
218
- status: this.mapKalshiOrderStatus(order.status),
219
- filled: order.count - (order.remaining_count || 0),
220
- remaining: order.remaining_count || 0,
221
- timestamp: new Date(order.created_time).getTime(),
222
- };
212
+ return this.mapKalshiOrder(data.order);
223
213
  }
224
214
  async fetchOpenOrders(marketId) {
225
215
  const queryParams = { status: 'resting' };
@@ -228,20 +218,70 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
228
218
  }
229
219
  const data = await this.callApi('GetOrders', queryParams);
230
220
  const orders = data.orders || [];
231
- return orders.map((order) => ({
232
- id: order.order_id,
233
- marketId: order.ticker,
234
- outcomeId: order.ticker,
235
- side: order.side === 'yes' ? 'buy' : 'sell',
236
- type: order.type === 'limit' ? 'limit' : 'market',
237
- price: order.yes_price ? order.yes_price / 100 : undefined,
238
- amount: order.count,
239
- status: 'open',
240
- filled: order.count - (order.remaining_count || 0),
241
- remaining: order.remaining_count || 0,
242
- timestamp: new Date(order.created_time).getTime(),
221
+ return orders.map((order) => this.mapKalshiOrder(order));
222
+ }
223
+ async fetchMyTrades(params) {
224
+ const queryParams = {};
225
+ if (params?.outcomeId || params?.marketId) {
226
+ queryParams.ticker = (params.outcomeId || params.marketId).replace(/-NO$/, '');
227
+ }
228
+ if (params?.since)
229
+ queryParams.min_ts = Math.floor(params.since.getTime() / 1000);
230
+ if (params?.until)
231
+ queryParams.max_ts = Math.floor(params.until.getTime() / 1000);
232
+ if (params?.limit)
233
+ queryParams.limit = params.limit;
234
+ if (params?.cursor)
235
+ queryParams.cursor = params.cursor;
236
+ const data = await this.callApi('GetFills', queryParams);
237
+ return (data.fills || []).map((f) => ({
238
+ id: f.fill_id,
239
+ timestamp: new Date(f.created_time).getTime(),
240
+ price: f.yes_price / 100,
241
+ amount: f.count,
242
+ side: f.side === 'yes' ? 'buy' : 'sell',
243
+ orderId: f.order_id,
243
244
  }));
244
245
  }
246
+ async fetchClosedOrders(params) {
247
+ const queryParams = {};
248
+ if (params?.marketId)
249
+ queryParams.ticker = params.marketId;
250
+ if (params?.until)
251
+ queryParams.max_ts = Math.floor(params.until.getTime() / 1000);
252
+ if (params?.limit)
253
+ queryParams.limit = params.limit;
254
+ if (params?.cursor)
255
+ queryParams.cursor = params.cursor;
256
+ const data = await this.callApi('GetHistoricalOrders', queryParams);
257
+ return (data.orders || []).map((o) => this.mapKalshiOrder(o));
258
+ }
259
+ async fetchAllOrders(params) {
260
+ const queryParams = {};
261
+ if (params?.marketId)
262
+ queryParams.ticker = params.marketId;
263
+ if (params?.since)
264
+ queryParams.min_ts = Math.floor(params.since.getTime() / 1000);
265
+ if (params?.until)
266
+ queryParams.max_ts = Math.floor(params.until.getTime() / 1000);
267
+ if (params?.limit)
268
+ queryParams.limit = params.limit;
269
+ const historicalParams = { ...queryParams };
270
+ delete historicalParams.min_ts; // GetHistoricalOrders only supports max_ts
271
+ const [liveData, historicalData] = await Promise.all([
272
+ this.callApi('GetOrders', queryParams),
273
+ this.callApi('GetHistoricalOrders', historicalParams),
274
+ ]);
275
+ const seen = new Set();
276
+ const all = [];
277
+ for (const o of [...(liveData.orders || []), ...(historicalData.orders || [])]) {
278
+ if (!seen.has(o.order_id)) {
279
+ seen.add(o.order_id);
280
+ all.push(this.mapKalshiOrder(o));
281
+ }
282
+ }
283
+ return all.sort((a, b) => b.timestamp - a.timestamp);
284
+ }
245
285
  async fetchPositions() {
246
286
  const data = await this.callApi('GetPositions');
247
287
  const positions = data.market_positions || [];
@@ -260,9 +300,25 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
260
300
  };
261
301
  });
262
302
  }
303
+ // Helper to map a raw Kalshi order object to a unified Order
304
+ mapKalshiOrder(order) {
305
+ return {
306
+ id: order.order_id,
307
+ marketId: order.ticker,
308
+ outcomeId: order.ticker,
309
+ side: order.side === 'yes' ? 'buy' : 'sell',
310
+ type: order.type === 'limit' ? 'limit' : 'market',
311
+ price: order.yes_price ? order.yes_price / 100 : undefined,
312
+ amount: order.count,
313
+ status: this.mapKalshiOrderStatus(order.status),
314
+ filled: order.count - (order.remaining_count || 0),
315
+ remaining: order.remaining_count || 0,
316
+ timestamp: new Date(order.created_time).getTime(),
317
+ };
318
+ }
263
319
  // Helper to map Kalshi order status to unified status
264
320
  mapKalshiOrderStatus(status) {
265
- switch (status.toLowerCase()) {
321
+ switch ((status ?? '').toLowerCase()) {
266
322
  case 'resting':
267
323
  return 'open';
268
324
  case 'canceled':
@@ -318,6 +318,186 @@ describe('KalshiExchange', () => {
318
318
  });
319
319
  });
320
320
  });
321
+ describe('Trading History Methods', () => {
322
+ beforeEach(() => {
323
+ exchange = new kalshi_1.KalshiExchange(mockCredentials);
324
+ });
325
+ describe('fetchMyTrades', () => {
326
+ it('should map GetFills response to UserTrade array', async () => {
327
+ const mockResponse = {
328
+ data: {
329
+ fills: [
330
+ {
331
+ fill_id: 'fill-abc',
332
+ order_id: 'order-123',
333
+ created_time: '2026-01-13T12:00:00Z',
334
+ yes_price: 55,
335
+ count: 10,
336
+ side: 'yes',
337
+ },
338
+ {
339
+ fill_id: 'fill-def',
340
+ order_id: 'order-456',
341
+ created_time: '2026-01-13T13:00:00Z',
342
+ yes_price: 45,
343
+ count: 5,
344
+ side: 'no',
345
+ },
346
+ ],
347
+ },
348
+ };
349
+ mockAxiosInstance.request.mockResolvedValue(mockResponse);
350
+ const trades = await exchange.fetchMyTrades();
351
+ expect(Array.isArray(trades)).toBe(true);
352
+ expect(trades).toHaveLength(2);
353
+ expect(trades[0].id).toBe('fill-abc');
354
+ expect(trades[0].orderId).toBe('order-123');
355
+ expect(trades[0].price).toBe(0.55); // 55 / 100
356
+ expect(trades[0].amount).toBe(10);
357
+ expect(trades[0].side).toBe('buy'); // 'yes' => 'buy'
358
+ expect(trades[1].id).toBe('fill-def');
359
+ expect(trades[1].side).toBe('sell'); // 'no' => 'sell'
360
+ expect(trades[1].price).toBe(0.45); // 45 / 100
361
+ });
362
+ it('should pass outcomeId as ticker (stripping -NO suffix) and date params', async () => {
363
+ const mockResponse = { data: { fills: [] } };
364
+ mockAxiosInstance.request.mockResolvedValue(mockResponse);
365
+ await exchange.fetchMyTrades({
366
+ outcomeId: 'TEST-MARKET-NO',
367
+ since: new Date('2026-01-01T00:00:00Z'),
368
+ until: new Date('2026-01-31T00:00:00Z'),
369
+ limit: 50,
370
+ });
371
+ expect(mockAxiosInstance.request).toHaveBeenCalledWith(expect.objectContaining({
372
+ params: expect.objectContaining({
373
+ ticker: 'TEST-MARKET', // -NO stripped
374
+ min_ts: Math.floor(new Date('2026-01-01T00:00:00Z').getTime() / 1000),
375
+ max_ts: Math.floor(new Date('2026-01-31T00:00:00Z').getTime() / 1000),
376
+ limit: 50,
377
+ }),
378
+ }));
379
+ });
380
+ it('should return empty array when fills is missing', async () => {
381
+ mockAxiosInstance.request.mockResolvedValue({ data: {} });
382
+ const trades = await exchange.fetchMyTrades();
383
+ expect(trades).toHaveLength(0);
384
+ });
385
+ });
386
+ describe('fetchClosedOrders', () => {
387
+ it('should map GetHistoricalOrders response to Order array', async () => {
388
+ const mockResponse = {
389
+ data: {
390
+ orders: [
391
+ {
392
+ order_id: 'hist-order-1',
393
+ ticker: 'TEST-MARKET',
394
+ side: 'yes',
395
+ type: 'limit',
396
+ yes_price: 60,
397
+ count: 8,
398
+ remaining_count: 0,
399
+ status: 'executed',
400
+ created_time: '2026-01-10T10:00:00Z',
401
+ },
402
+ ],
403
+ },
404
+ };
405
+ mockAxiosInstance.request.mockResolvedValue(mockResponse);
406
+ const orders = await exchange.fetchClosedOrders();
407
+ expect(orders).toHaveLength(1);
408
+ expect(orders[0].id).toBe('hist-order-1');
409
+ expect(orders[0].marketId).toBe('TEST-MARKET');
410
+ expect(orders[0].side).toBe('buy'); // 'yes' => 'buy'
411
+ expect(orders[0].price).toBe(0.60); // 60 / 100
412
+ expect(orders[0].amount).toBe(8);
413
+ expect(orders[0].filled).toBe(8); // count - remaining_count (0)
414
+ expect(orders[0].remaining).toBe(0);
415
+ expect(orders[0].status).toBe('filled'); // 'executed' => 'filled'
416
+ });
417
+ it('should pass marketId as ticker and limit', async () => {
418
+ const mockResponse = { data: { orders: [] } };
419
+ mockAxiosInstance.request.mockResolvedValue(mockResponse);
420
+ await exchange.fetchClosedOrders({ marketId: 'TEST-MARKET', limit: 25 });
421
+ expect(mockAxiosInstance.request).toHaveBeenCalledWith(expect.objectContaining({
422
+ params: expect.objectContaining({
423
+ ticker: 'TEST-MARKET',
424
+ limit: 25,
425
+ }),
426
+ }));
427
+ });
428
+ });
429
+ describe('fetchAllOrders', () => {
430
+ it('should merge live and historical orders, dedup, and sort descending by timestamp', async () => {
431
+ const liveResponse = {
432
+ data: {
433
+ orders: [
434
+ {
435
+ order_id: 'order-live-1',
436
+ ticker: 'TEST',
437
+ side: 'yes',
438
+ type: 'limit',
439
+ yes_price: 50,
440
+ count: 5,
441
+ remaining_count: 5,
442
+ status: 'resting',
443
+ created_time: '2026-01-15T10:00:00Z',
444
+ },
445
+ {
446
+ // duplicate that also appears in historical
447
+ order_id: 'order-hist-1',
448
+ ticker: 'TEST',
449
+ side: 'no',
450
+ type: 'limit',
451
+ yes_price: 40,
452
+ count: 3,
453
+ remaining_count: 0,
454
+ status: 'executed',
455
+ created_time: '2026-01-10T08:00:00Z',
456
+ },
457
+ ],
458
+ },
459
+ };
460
+ const historicalResponse = {
461
+ data: {
462
+ orders: [
463
+ {
464
+ order_id: 'order-hist-1', // duplicate
465
+ ticker: 'TEST',
466
+ side: 'no',
467
+ type: 'limit',
468
+ yes_price: 40,
469
+ count: 3,
470
+ remaining_count: 0,
471
+ status: 'executed',
472
+ created_time: '2026-01-10T08:00:00Z',
473
+ },
474
+ {
475
+ order_id: 'order-hist-2',
476
+ ticker: 'TEST',
477
+ side: 'yes',
478
+ type: 'limit',
479
+ yes_price: 55,
480
+ count: 10,
481
+ remaining_count: 0,
482
+ status: 'executed',
483
+ created_time: '2026-01-05T06:00:00Z',
484
+ },
485
+ ],
486
+ },
487
+ };
488
+ mockAxiosInstance.request
489
+ .mockResolvedValueOnce(liveResponse)
490
+ .mockResolvedValueOnce(historicalResponse);
491
+ const orders = await exchange.fetchAllOrders();
492
+ // 3 unique orders (order-hist-1 deduped)
493
+ expect(orders).toHaveLength(3);
494
+ // sorted descending: order-live-1, order-hist-1, order-hist-2
495
+ expect(orders[0].id).toBe('order-live-1');
496
+ expect(orders[1].id).toBe('order-hist-1');
497
+ expect(orders[2].id).toBe('order-hist-2');
498
+ });
499
+ });
500
+ }); // Trading History Methods
321
501
  describe('Order Status Mapping', () => {
322
502
  beforeEach(() => {
323
503
  exchange = new kalshi_1.KalshiExchange(mockCredentials);
@@ -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-02-22T07:47:40.130Z
3
+ * Generated at: 2026-02-22T14:48:41.831Z
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-02-22T07:47:40.130Z
6
+ * Generated at: 2026-02-22T14:48:41.831Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.limitlessApiSpec = {
@@ -1,5 +1,5 @@
1
- import { PredictionMarketExchange, MarketFetchParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams } from '../../BaseExchange';
2
- import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, Order, Position, Balance, CreateOrderParams } from '../../types';
1
+ import { PredictionMarketExchange, MarketFetchParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams, MyTradesParams, OrderHistoryParams } from '../../BaseExchange';
2
+ import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Order, Position, Balance, CreateOrderParams } from '../../types';
3
3
  import { LimitlessWebSocketConfig } from './websocket';
4
4
  export type { LimitlessWebSocketConfig };
5
5
  export interface LimitlessExchangeOptions {
@@ -21,6 +21,9 @@ export declare class LimitlessExchange extends PredictionMarketExchange {
21
21
  fetchBalance: true;
22
22
  watchOrderBook: true;
23
23
  watchTrades: true;
24
+ fetchMyTrades: true;
25
+ fetchClosedOrders: true;
26
+ fetchAllOrders: true;
24
27
  };
25
28
  private auth?;
26
29
  private client?;
@@ -42,6 +45,9 @@ export declare class LimitlessExchange extends PredictionMarketExchange {
42
45
  cancelOrder(orderId: string): Promise<Order>;
43
46
  fetchOrder(orderId: string): Promise<Order>;
44
47
  fetchOpenOrders(marketId?: string): Promise<Order[]>;
48
+ fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
49
+ fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]>;
50
+ fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]>;
45
51
  fetchPositions(): Promise<Position[]>;
46
52
  fetchBalance(): Promise<Balance[]>;
47
53
  private ws?;
@@ -31,6 +31,9 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
31
31
  fetchBalance: true,
32
32
  watchOrderBook: true,
33
33
  watchTrades: true,
34
+ fetchMyTrades: true,
35
+ fetchClosedOrders: true,
36
+ fetchAllOrders: true,
34
37
  };
35
38
  auth;
36
39
  client;
@@ -226,6 +229,68 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
226
229
  throw errors_1.limitlessErrorMapper.mapError(error);
227
230
  }
228
231
  }
232
+ async fetchMyTrades(params) {
233
+ const auth = this.ensureAuth();
234
+ try {
235
+ const response = await this.http.get('https://api.limitless.exchange/portfolio/trades', {
236
+ headers: { Authorization: `Bearer ${auth.getApiKey()}` },
237
+ });
238
+ const trades = Array.isArray(response.data) ? response.data : (response.data?.data || []);
239
+ return trades.map((t) => ({
240
+ id: t.id || String(t.timestamp),
241
+ timestamp: t.createdAt ? new Date(t.createdAt).getTime() : (t.timestamp || 0),
242
+ price: parseFloat(t.price || '0'),
243
+ amount: parseFloat(t.quantity || t.amount || '0'),
244
+ side: (t.side || '').toLowerCase() === 'buy' ? 'buy' : 'sell',
245
+ orderId: t.orderId,
246
+ }));
247
+ }
248
+ catch (error) {
249
+ throw errors_1.limitlessErrorMapper.mapError(error);
250
+ }
251
+ }
252
+ async fetchClosedOrders(params) {
253
+ const client = this.ensureClient();
254
+ if (!params?.marketId) {
255
+ console.warn('Limitless: fetchClosedOrders requires marketId (slug). Returning [].');
256
+ return [];
257
+ }
258
+ const orders = await client.getOrders(params.marketId, ['MATCHED']);
259
+ return orders.map((o) => ({
260
+ id: o.id,
261
+ marketId: params.marketId,
262
+ outcomeId: o.tokenId || 'unknown',
263
+ side: o.side.toLowerCase(),
264
+ type: 'limit',
265
+ price: parseFloat(o.price),
266
+ amount: parseFloat(o.quantity),
267
+ status: 'filled',
268
+ filled: parseFloat(o.quantity),
269
+ remaining: 0,
270
+ timestamp: o.createdAt ? new Date(o.createdAt).getTime() : Date.now(),
271
+ }));
272
+ }
273
+ async fetchAllOrders(params) {
274
+ const client = this.ensureClient();
275
+ if (!params?.marketId) {
276
+ console.warn('Limitless: fetchAllOrders requires marketId (slug). Returning [].');
277
+ return [];
278
+ }
279
+ const orders = await client.getOrders(params.marketId, ['LIVE', 'MATCHED']);
280
+ return orders.map((o) => ({
281
+ id: o.id,
282
+ marketId: params.marketId,
283
+ outcomeId: o.tokenId || 'unknown',
284
+ side: o.side.toLowerCase(),
285
+ type: 'limit',
286
+ price: parseFloat(o.price),
287
+ amount: parseFloat(o.quantity),
288
+ status: o.status === 'LIVE' ? 'open' : 'filled',
289
+ filled: o.status === 'MATCHED' ? parseFloat(o.quantity) : 0,
290
+ remaining: o.status === 'LIVE' ? parseFloat(o.quantity) : 0,
291
+ timestamp: o.createdAt ? new Date(o.createdAt).getTime() : Date.now(),
292
+ }));
293
+ }
229
294
  async fetchPositions() {
230
295
  const auth = this.ensureAuth();
231
296
  const address = auth.getAddress();
@@ -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-02-22T07:47:40.144Z
3
+ * Generated at: 2026-02-22T14:48:41.842Z
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-02-22T07:47:40.144Z
6
+ * Generated at: 2026-02-22T14:48:41.842Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.myriadApiSpec = {
@@ -1,5 +1,5 @@
1
- import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams } from '../../BaseExchange';
2
- import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, Balance, Order, Position, CreateOrderParams } from '../../types';
1
+ import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams, MyTradesParams } from '../../BaseExchange';
2
+ import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Balance, Order, Position, CreateOrderParams } from '../../types';
3
3
  export declare class MyriadExchange extends PredictionMarketExchange {
4
4
  readonly has: {
5
5
  fetchMarkets: true;
@@ -15,6 +15,9 @@ export declare class MyriadExchange extends PredictionMarketExchange {
15
15
  fetchBalance: "emulated";
16
16
  watchOrderBook: "emulated";
17
17
  watchTrades: "emulated";
18
+ fetchMyTrades: true;
19
+ fetchClosedOrders: false;
20
+ fetchAllOrders: false;
18
21
  };
19
22
  private auth?;
20
23
  private ws?;
@@ -29,6 +32,7 @@ export declare class MyriadExchange extends PredictionMarketExchange {
29
32
  fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams): Promise<PriceCandle[]>;
30
33
  fetchOrderBook(id: string): Promise<OrderBook>;
31
34
  fetchTrades(id: string, params: TradesParams | HistoryFilterParams): Promise<Trade[]>;
35
+ fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
32
36
  createOrder(params: CreateOrderParams): Promise<Order>;
33
37
  cancelOrder(_orderId: string): Promise<Order>;
34
38
  fetchOrder(_orderId: string): Promise<Order>;
@@ -28,6 +28,9 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
28
28
  fetchBalance: 'emulated',
29
29
  watchOrderBook: 'emulated',
30
30
  watchTrades: 'emulated',
31
+ fetchMyTrades: true,
32
+ fetchClosedOrders: false,
33
+ fetchAllOrders: false,
31
34
  };
32
35
  auth;
33
36
  ws;
@@ -119,6 +122,34 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
119
122
  side: t.action === 'buy' ? 'buy' : 'sell',
120
123
  }));
121
124
  }
125
+ async fetchMyTrades(params) {
126
+ const walletAddress = this.ensureAuth().walletAddress;
127
+ if (!walletAddress) {
128
+ throw new errors_2.AuthenticationError('fetchMyTrades requires a wallet address. Pass privateKey as the wallet address in credentials.', 'Myriad');
129
+ }
130
+ const queryParams = { address: walletAddress };
131
+ if (params?.marketId) {
132
+ const parts = params.marketId.split(':');
133
+ if (parts.length >= 2)
134
+ queryParams.market_id = parts[1];
135
+ }
136
+ if (params?.since)
137
+ queryParams.since = Math.floor(params.since.getTime() / 1000);
138
+ if (params?.until)
139
+ queryParams.until = Math.floor(params.until.getTime() / 1000);
140
+ if (params?.limit)
141
+ queryParams.limit = params.limit;
142
+ const data = await this.callApi('getUsersEvents', queryParams);
143
+ const events = data.data || data.events || [];
144
+ const tradeEvents = events.filter((e) => e.action === 'buy' || e.action === 'sell');
145
+ return tradeEvents.map((t, i) => ({
146
+ id: `${t.blockNumber || t.timestamp}-${i}`,
147
+ timestamp: (t.timestamp || 0) * 1000,
148
+ price: t.shares > 0 ? Number(t.value) / Number(t.shares) : 0,
149
+ amount: Number(t.shares || 0),
150
+ side: t.action === 'buy' ? 'buy' : 'sell',
151
+ }));
152
+ }
122
153
  // ------------------------------------------------------------------------
123
154
  // Trading
124
155
  // ------------------------------------------------------------------------
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
3
- * Generated at: 2026-02-22T07:47:40.090Z
3
+ * Generated at: 2026-02-22T14:48:41.794Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketClobSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketClobSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
6
- * Generated at: 2026-02-22T07:47:40.090Z
6
+ * Generated at: 2026-02-22T14:48:41.794Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketClobSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
3
- * Generated at: 2026-02-22T07:47:40.108Z
3
+ * Generated at: 2026-02-22T14:48:41.812Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketDataSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketDataSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
6
- * Generated at: 2026-02-22T07:47:40.108Z
6
+ * Generated at: 2026-02-22T14:48:41.812Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketDataSpec = {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
3
- * Generated at: 2026-02-22T07:47:40.103Z
3
+ * Generated at: 2026-02-22T14:48:41.808Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const polymarketGammaSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.polymarketGammaSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
6
- * Generated at: 2026-02-22T07:47:40.103Z
6
+ * Generated at: 2026-02-22T14:48:41.808Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.polymarketGammaSpec = {
@@ -1,5 +1,5 @@
1
- import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams } from '../../BaseExchange';
2
- import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, Order, Position, Balance, CreateOrderParams } from '../../types';
1
+ import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams, MyTradesParams } from '../../BaseExchange';
2
+ import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Order, Position, Balance, CreateOrderParams } from '../../types';
3
3
  import { PolymarketWebSocketConfig } from './websocket';
4
4
  export type { PolymarketWebSocketConfig };
5
5
  export interface PolymarketExchangeOptions {
@@ -21,6 +21,9 @@ export declare class PolymarketExchange extends PredictionMarketExchange {
21
21
  fetchBalance: true;
22
22
  watchOrderBook: true;
23
23
  watchTrades: true;
24
+ fetchMyTrades: true;
25
+ fetchClosedOrders: false;
26
+ fetchAllOrders: false;
24
27
  };
25
28
  private auth?;
26
29
  private wsConfig?;
@@ -71,6 +74,7 @@ export declare class PolymarketExchange extends PredictionMarketExchange {
71
74
  cancelOrder(orderId: string): Promise<Order>;
72
75
  fetchOrder(orderId: string): Promise<Order>;
73
76
  fetchOpenOrders(marketId?: string): Promise<Order[]>;
77
+ fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
74
78
  fetchPositions(): Promise<Position[]>;
75
79
  fetchBalance(): Promise<Balance[]>;
76
80
  private ws?;
@@ -33,6 +33,9 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
33
33
  fetchBalance: true,
34
34
  watchOrderBook: true,
35
35
  watchTrades: true,
36
+ fetchMyTrades: true,
37
+ fetchClosedOrders: false,
38
+ fetchAllOrders: false,
36
39
  };
37
40
  auth;
38
41
  wsConfig;
@@ -342,6 +345,29 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
342
345
  throw errors_1.polymarketErrorMapper.mapError(error);
343
346
  }
344
347
  }
348
+ async fetchMyTrades(params) {
349
+ const auth = this.ensureAuth();
350
+ const address = await auth.getEffectiveFunderAddress();
351
+ const queryParams = { user: address };
352
+ if (params?.marketId)
353
+ queryParams.market = params.marketId;
354
+ if (params?.limit)
355
+ queryParams.limit = params.limit;
356
+ if (params?.since)
357
+ queryParams.start = Math.floor(params.since.getTime() / 1000);
358
+ if (params?.until)
359
+ queryParams.end = Math.floor(params.until.getTime() / 1000);
360
+ const data = await this.callApi('getTrades', queryParams);
361
+ const trades = Array.isArray(data) ? data : (data.data || []);
362
+ return trades.map((t) => ({
363
+ id: t.id || t.transactionHash || String(t.timestamp),
364
+ timestamp: typeof t.timestamp === 'number' ? t.timestamp * 1000 : Date.now(),
365
+ price: parseFloat(t.price || '0'),
366
+ amount: parseFloat(t.size || t.amount || '0'),
367
+ side: t.side === 'BUY' ? 'buy' : t.side === 'SELL' ? 'sell' : 'unknown',
368
+ orderId: t.orderId,
369
+ }));
370
+ }
345
371
  async fetchPositions() {
346
372
  try {
347
373
  const auth = this.ensureAuth();
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
3
- * Generated at: 2026-02-22T07:47:40.137Z
3
+ * Generated at: 2026-02-22T14:48:41.835Z
4
4
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
5
5
  */
6
6
  export declare const probableApiSpec: {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.probableApiSpec = void 0;
4
4
  /**
5
5
  * Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
6
- * Generated at: 2026-02-22T07:47:40.137Z
6
+ * Generated at: 2026-02-22T14:48:41.835Z
7
7
  * Do not edit manually -- run "npm run fetch:openapi" to regenerate.
8
8
  */
9
9
  exports.probableApiSpec = {
@@ -1,5 +1,5 @@
1
- import { PredictionMarketExchange, MarketFetchParams, EventFetchParams, ExchangeCredentials, OHLCVParams, HistoryFilterParams, TradesParams } from '../../BaseExchange';
2
- import { UnifiedMarket, UnifiedEvent, OrderBook, PriceCandle, Trade, Order, Position, Balance, CreateOrderParams } from '../../types';
1
+ import { PredictionMarketExchange, MarketFetchParams, EventFetchParams, ExchangeCredentials, OHLCVParams, HistoryFilterParams, TradesParams, MyTradesParams } from '../../BaseExchange';
2
+ import { UnifiedMarket, UnifiedEvent, OrderBook, PriceCandle, Trade, UserTrade, Order, Position, Balance, CreateOrderParams } from '../../types';
3
3
  import { ProbableWebSocketConfig } from './websocket';
4
4
  export declare class ProbableExchange extends PredictionMarketExchange {
5
5
  readonly has: {
@@ -16,6 +16,9 @@ export declare class ProbableExchange extends PredictionMarketExchange {
16
16
  fetchBalance: true;
17
17
  watchOrderBook: true;
18
18
  watchTrades: false;
19
+ fetchMyTrades: true;
20
+ fetchClosedOrders: false;
21
+ fetchAllOrders: false;
19
22
  };
20
23
  private auth?;
21
24
  private ws?;
@@ -66,6 +69,7 @@ export declare class ProbableExchange extends PredictionMarketExchange {
66
69
  getEventBySlug(slug: string): Promise<UnifiedEvent | null>;
67
70
  fetchOrderBook(id: string): Promise<OrderBook>;
68
71
  fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams): Promise<PriceCandle[]>;
72
+ fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
69
73
  createOrder(params: CreateOrderParams): Promise<Order>;
70
74
  /**
71
75
  * Cancel an order.
@@ -47,6 +47,9 @@ class ProbableExchange extends BaseExchange_1.PredictionMarketExchange {
47
47
  fetchBalance: true,
48
48
  watchOrderBook: true,
49
49
  watchTrades: false,
50
+ fetchMyTrades: true,
51
+ fetchClosedOrders: false,
52
+ fetchAllOrders: false,
50
53
  };
51
54
  auth;
52
55
  ws;
@@ -179,6 +182,25 @@ class ProbableExchange extends BaseExchange_1.PredictionMarketExchange {
179
182
  }
180
183
  return candles;
181
184
  }
185
+ async fetchMyTrades(params) {
186
+ const auth = this.ensureAuth();
187
+ const address = auth.getAddress();
188
+ const queryParams = { user: address };
189
+ if (params?.limit)
190
+ queryParams.limit = params.limit;
191
+ const data = await this.callApi('getPublicApiV1Trades', queryParams);
192
+ const trades = Array.isArray(data) ? data : (data.data || []);
193
+ return trades.map((t) => ({
194
+ id: String(t.tradeId || t.id || t.timestamp),
195
+ timestamp: typeof t.time === 'number'
196
+ ? (t.time > 1e12 ? t.time : t.time * 1000)
197
+ : Date.now(),
198
+ price: parseFloat(t.price || '0'),
199
+ amount: parseFloat(t.qty || t.size || t.amount || '0'),
200
+ side: (t.side || '').toLowerCase() === 'buy' ? 'buy' : 'sell',
201
+ orderId: t.orderId,
202
+ }));
203
+ }
182
204
  // --------------------------------------------------------------------------
183
205
  // Trading Methods
184
206
  // --------------------------------------------------------------------------
package/dist/types.d.ts CHANGED
@@ -66,6 +66,9 @@ export interface Trade {
66
66
  amount: number;
67
67
  side: 'buy' | 'sell' | 'unknown';
68
68
  }
69
+ export interface UserTrade extends Trade {
70
+ orderId?: string;
71
+ }
69
72
  export interface Order {
70
73
  id: string;
71
74
  marketId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxt-core",
3
- "version": "2.11.0",
3
+ "version": "2.12.0",
4
4
  "description": "pmxt is a unified prediction market data API. The ccxt for prediction markets.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -29,8 +29,8 @@
29
29
  "test": "jest -c jest.config.js",
30
30
  "server": "tsx watch src/server/index.ts",
31
31
  "server:prod": "node dist/server/index.js",
32
- "generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.11.0,library=urllib3",
33
- "generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.11.0,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.js",
32
+ "generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.12.0,library=urllib3",
33
+ "generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.12.0,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.js",
34
34
  "fetch:openapi": "node scripts/fetch-openapi-specs.js",
35
35
  "extract:jsdoc": "node ../scripts/extract-jsdoc.js",
36
36
  "generate:docs": "npm run extract:jsdoc && node ../scripts/generate-api-docs.js",