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
@@ -7,93 +7,129 @@ exports.fetchEvents = fetchEvents;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const utils_1 = require("./utils");
9
9
  const errors_1 = require("./errors");
10
+ function mapRawEventToUnified(event) {
11
+ const markets = [];
12
+ if (event.markets && Array.isArray(event.markets)) {
13
+ for (const market of event.markets) {
14
+ const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market, { useQuestionAsCandidateFallback: true });
15
+ if (unifiedMarket) {
16
+ markets.push(unifiedMarket);
17
+ }
18
+ }
19
+ }
20
+ const unifiedEvent = {
21
+ id: event.id || event.slug,
22
+ title: event.title,
23
+ description: event.description || '',
24
+ slug: event.slug,
25
+ markets: markets,
26
+ volume24h: markets.reduce((sum, m) => sum + m.volume24h, 0),
27
+ volume: markets.some(m => m.volume !== undefined) ? markets.reduce((sum, m) => sum + (m.volume ?? 0), 0) : undefined,
28
+ url: `https://polymarket.com/event/${event.slug}`,
29
+ image: event.image || `https://polymarket.com/api/og?slug=${event.slug}`,
30
+ category: event.category || event.tags?.[0]?.label,
31
+ tags: event.tags?.map((t) => t.label) || []
32
+ };
33
+ return unifiedEvent;
34
+ }
10
35
  async function fetchEvents(params, http = axios_1.default) {
11
36
  try {
12
- if (!params.query) {
13
- throw new Error("Query is required for Polymarket event search");
14
- }
15
37
  const limit = params.limit || 10000;
16
- const status = params.status || 'active';
17
- const queryParams = {
18
- q: params.query,
19
- limit_per_type: 50,
20
- sort: 'volume',
21
- ascending: false
22
- };
23
- const fetchWithStatus = async (eventStatus) => {
24
- const currentParams = { ...queryParams, events_status: eventStatus };
25
- return (0, utils_1.paginateSearchParallel)(utils_1.GAMMA_SEARCH_URL, currentParams, limit * 10, http);
26
- };
27
- // Client-side filtering logic
28
- // The API returns active events when querying for 'closed' status sometimes.
29
- // We must strictly filter based on the event's `active` and `closed` properties.
30
- const filterActive = (e) => e.active === true;
31
- const filterClosed = (e) => e.closed === true;
32
- let events = [];
33
- if (status === 'all') {
34
- const [activeEvents, closedEvents] = await Promise.all([
35
- fetchWithStatus('active'),
36
- fetchWithStatus('closed')
37
- ]);
38
- // Merge and de-duplicate by ID
39
- const seenIds = new Set();
40
- events = [...activeEvents, ...closedEvents].filter(event => {
41
- const id = event.id || event.slug;
42
- if (seenIds.has(id))
43
- return false;
44
- seenIds.add(id);
45
- return true;
46
- });
38
+ // Handle eventId or slug lookup (direct API call)
39
+ if (params.eventId || params.slug) {
40
+ const queryParams = params.eventId ? { id: params.eventId } : { slug: params.slug };
41
+ const response = await http.get(utils_1.GAMMA_API_URL, { params: queryParams });
42
+ const events = response.data;
43
+ if (!events || events.length === 0)
44
+ return [];
45
+ return events.map(mapRawEventToUnified).slice(0, limit);
47
46
  }
48
- else if (status === 'active') {
49
- const rawEvents = await fetchWithStatus('active');
50
- events = rawEvents.filter(filterActive);
47
+ // Handle query-based search (uses the /public-search endpoint)
48
+ if (params.query) {
49
+ return await searchEvents(params, limit, http);
51
50
  }
52
- else if (status === 'inactive' || status === 'closed') {
53
- // Polymarket sometimes returns active events when querying for closed
54
- // So we fetch 'closed' but strictly filter
55
- const rawEvents = await fetchWithStatus('closed');
56
- events = rawEvents.filter(filterClosed);
57
- }
58
- // Client-side filtering to ensure title matches (API does fuzzy search)
59
- const lowerQuery = params.query.toLowerCase();
60
- const searchIn = params.searchIn || 'title';
61
- const filteredEvents = events.filter((event) => {
62
- const titleMatch = (event.title || '').toLowerCase().includes(lowerQuery);
63
- const descMatch = (event.description || '').toLowerCase().includes(lowerQuery);
64
- if (searchIn === 'title')
65
- return titleMatch;
66
- if (searchIn === 'description')
67
- return descMatch;
68
- return titleMatch || descMatch; // 'both'
69
- });
70
- // Map events to UnifiedEvent
71
- const unifiedEvents = filteredEvents.map((event) => {
72
- const markets = [];
73
- if (event.markets && Array.isArray(event.markets)) {
74
- for (const market of event.markets) {
75
- const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market, { useQuestionAsCandidateFallback: true });
76
- if (unifiedMarket) {
77
- markets.push(unifiedMarket);
78
- }
79
- }
80
- }
81
- const unifiedEvent = {
82
- id: event.id || event.slug,
83
- title: event.title,
84
- description: event.description || '',
85
- slug: event.slug,
86
- markets: markets,
87
- url: `https://polymarket.com/event/${event.slug}`,
88
- image: event.image || `https://polymarket.com/api/og?slug=${event.slug}`,
89
- category: event.category || event.tags?.[0]?.label,
90
- tags: event.tags?.map((t) => t.label) || []
91
- };
92
- return unifiedEvent;
93
- });
94
- return unifiedEvents.slice(0, limit);
51
+ // Default: fetch top events list from the Gamma /events endpoint (no query required)
52
+ return await fetchEventsDefault(params, limit, http);
95
53
  }
96
54
  catch (error) {
97
55
  throw errors_1.polymarketErrorMapper.mapError(error);
98
56
  }
99
57
  }
58
+ async function searchEvents(params, limit, http) {
59
+ let sortParam = 'volume';
60
+ if (params.sort === 'newest')
61
+ sortParam = 'startDate';
62
+ if (params.sort === 'liquidity')
63
+ sortParam = 'liquidity';
64
+ const queryParams = {
65
+ q: params.query,
66
+ limit_per_type: 50,
67
+ sort: sortParam,
68
+ ascending: false
69
+ };
70
+ const status = params.status || 'active';
71
+ const fetchWithStatus = async (eventStatus) => {
72
+ const currentParams = { ...queryParams, events_status: eventStatus };
73
+ return (0, utils_1.paginateSearchParallel)(utils_1.GAMMA_SEARCH_URL, currentParams, limit * 10, http);
74
+ };
75
+ const filterActive = (e) => e.active === true;
76
+ const filterClosed = (e) => e.closed === true;
77
+ let events = [];
78
+ if (status === 'all') {
79
+ const [activeEvents, closedEvents] = await Promise.all([
80
+ fetchWithStatus('active'),
81
+ fetchWithStatus('closed')
82
+ ]);
83
+ const seenIds = new Set();
84
+ events = [...activeEvents, ...closedEvents].filter(event => {
85
+ const id = event.id || event.slug;
86
+ if (seenIds.has(id))
87
+ return false;
88
+ seenIds.add(id);
89
+ return true;
90
+ });
91
+ }
92
+ else if (status === 'active') {
93
+ const rawEvents = await fetchWithStatus('active');
94
+ events = rawEvents.filter(filterActive);
95
+ }
96
+ else if (status === 'inactive' || status === 'closed') {
97
+ const rawEvents = await fetchWithStatus('closed');
98
+ events = rawEvents.filter(filterClosed);
99
+ }
100
+ const lowerQuery = params.query.toLowerCase();
101
+ const searchIn = params.searchIn || 'title';
102
+ const filteredEvents = events.filter((event) => {
103
+ const titleMatch = (event.title || '').toLowerCase().includes(lowerQuery);
104
+ const descMatch = (event.description || '').toLowerCase().includes(lowerQuery);
105
+ if (searchIn === 'title')
106
+ return titleMatch;
107
+ if (searchIn === 'description')
108
+ return descMatch;
109
+ return titleMatch || descMatch;
110
+ });
111
+ return filteredEvents.map(mapRawEventToUnified).slice(0, limit);
112
+ }
113
+ async function fetchEventsDefault(params, limit, http) {
114
+ const status = params.status || 'active';
115
+ let sortParam = 'volume';
116
+ if (params.sort === 'newest')
117
+ sortParam = 'startDate';
118
+ else if (params.sort === 'liquidity')
119
+ sortParam = 'liquidity';
120
+ const queryParams = {
121
+ order: sortParam,
122
+ ascending: false,
123
+ };
124
+ if (status === 'active') {
125
+ queryParams.active = 'true';
126
+ queryParams.closed = 'false';
127
+ }
128
+ else if (status === 'closed' || status === 'inactive') {
129
+ queryParams.active = 'false';
130
+ queryParams.closed = 'true';
131
+ }
132
+ // 'all' — no status filter applied
133
+ const events = await (0, utils_1.paginateParallel)(utils_1.GAMMA_API_URL, queryParams, http, limit);
134
+ return events.map(mapRawEventToUnified).slice(0, limit);
135
+ }
@@ -1,7 +1,7 @@
1
- import { HistoryFilterParams, OHLCVParams } from '../../BaseExchange';
1
+ import { OHLCVParams } from '../../BaseExchange';
2
2
  import { PriceCandle } from '../../types';
3
3
  /**
4
4
  * Fetch historical price data (OHLCV candles) for a specific token.
5
5
  * @param id - The CLOB token ID (e.g., outcome token ID)
6
6
  */
7
- export declare function fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams, callApi: (operationId: string, params?: Record<string, any>) => Promise<any>): Promise<PriceCandle[]>;
7
+ export declare function fetchOHLCV(id: string, params: OHLCVParams, callApi: (operationId: string, params?: Record<string, any>) => Promise<any>): Promise<PriceCandle[]>;
@@ -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, BuiltOrder } from '../../types';
3
3
  import { PolymarketWebSocketConfig } from './websocket';
4
4
  export type { PolymarketWebSocketConfig };
5
5
  export interface PolymarketExchangeOptions {
@@ -21,6 +21,11 @@ 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;
27
+ buildOrder: true;
28
+ submitOrder: true;
24
29
  };
25
30
  private auth?;
26
31
  private wsConfig?;
@@ -38,7 +43,7 @@ export declare class PolymarketExchange extends PredictionMarketExchange {
38
43
  protected mapImplicitApiError(error: any): any;
39
44
  protected fetchMarketsImpl(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
40
45
  protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
41
- fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams): Promise<PriceCandle[]>;
46
+ fetchOHLCV(id: string, params: OHLCVParams): Promise<PriceCandle[]>;
42
47
  fetchOrderBook(id: string): Promise<OrderBook>;
43
48
  fetchTrades(id: string, params: TradesParams | HistoryFilterParams): Promise<Trade[]>;
44
49
  /**
@@ -46,15 +51,34 @@ export declare class PolymarketExchange extends PredictionMarketExchange {
46
51
  */
47
52
  private ensureAuth;
48
53
  /**
49
- * Pre-warm the SDK's internal caches for a token by fetching tick size,
50
- * fee rate, and neg-risk in parallel. Call this when you start watching
51
- * a market so that subsequent createOrder calls hit only POST /order.
54
+ * Pre-warm the SDK's internal caches for a market outcome.
55
+ *
56
+ * Fetches tick size, fee rate, and neg-risk in parallel so that subsequent
57
+ * `createOrder` calls skip those lookups and hit only `POST /order`.
58
+ * Call this when you start watching a market.
59
+ *
60
+ * @param outcomeId - The CLOB Token ID for the outcome (use `outcome.outcomeId`)
61
+ *
62
+ * @example-ts Pre-warm before placing orders
63
+ * const markets = await exchange.fetchMarkets({ query: 'Trump' });
64
+ * const outcomeId = markets[0].outcomes[0].outcomeId;
65
+ * await exchange.preWarmMarket(outcomeId);
66
+ * // Subsequent createOrder calls are faster
67
+ *
68
+ * @example-python Pre-warm before placing orders
69
+ * markets = exchange.fetch_markets(query='Trump')
70
+ * outcome_id = markets[0].outcomes[0].outcome_id
71
+ * exchange.pre_warm_market(outcome_id)
72
+ * # Subsequent create_order calls are faster
52
73
  */
53
74
  preWarmMarket(outcomeId: string): Promise<void>;
75
+ buildOrder(params: CreateOrderParams): Promise<BuiltOrder>;
76
+ submitOrder(built: BuiltOrder): Promise<Order>;
54
77
  createOrder(params: CreateOrderParams): Promise<Order>;
55
78
  cancelOrder(orderId: string): Promise<Order>;
56
79
  fetchOrder(orderId: string): Promise<Order>;
57
80
  fetchOpenOrders(marketId?: string): Promise<Order[]>;
81
+ fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
58
82
  fetchPositions(): Promise<Position[]>;
59
83
  fetchBalance(): Promise<Balance[]>;
60
84
  private ws?;
@@ -33,6 +33,11 @@ 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,
39
+ buildOrder: true,
40
+ submitOrder: true,
36
41
  };
37
42
  auth;
38
43
  wsConfig;
@@ -52,7 +57,18 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
52
57
  credentials = options;
53
58
  }
54
59
  super(credentials);
60
+ this.rateLimit = 200;
55
61
  this.wsConfig = wsConfig;
62
+ // Add browser-mimicking headers to help pass Cloudflare bot detection on the Gamma API.
63
+ // Origin/Referer make requests look like same-site CORS calls from the Polymarket frontend.
64
+ Object.assign(this.http.defaults.headers.common, {
65
+ 'Accept': 'application/json, */*',
66
+ 'Accept-Language': 'en-US,en;q=0.9',
67
+ 'Origin': 'https://polymarket.com',
68
+ 'Referer': 'https://polymarket.com/',
69
+ 'sec-fetch-mode': 'cors',
70
+ 'sec-fetch-site': 'same-site',
71
+ });
56
72
  // Initialize auth if credentials are provided
57
73
  if (credentials?.privateKey) {
58
74
  this.auth = new auth_1.PolymarketAuth(credentials);
@@ -142,17 +158,20 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
142
158
  markets.push(unified);
143
159
  }
144
160
  }
145
- return {
161
+ const unifiedEvent = {
146
162
  id: event.id || event.slug,
147
163
  title: event.title,
148
164
  description: event.description || '',
149
165
  slug: event.slug,
150
166
  markets,
167
+ volume24h: markets.reduce((sum, m) => sum + m.volume24h, 0),
168
+ volume: markets.some(m => m.volume !== undefined) ? markets.reduce((sum, m) => sum + (m.volume ?? 0), 0) : undefined,
151
169
  url: `https://polymarket.com/event/${event.slug}`,
152
170
  image: event.image || `https://polymarket.com/api/og?slug=${event.slug}`,
153
171
  category: event.category || event.tags?.[0]?.label,
154
172
  tags: event.tags?.map((t) => t.label) || [],
155
173
  };
174
+ return unifiedEvent;
156
175
  });
157
176
  }
158
177
  return (0, fetchEvents_1.fetchEvents)(params, this.http);
@@ -185,9 +204,25 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
185
204
  return this.auth;
186
205
  }
187
206
  /**
188
- * Pre-warm the SDK's internal caches for a token by fetching tick size,
189
- * fee rate, and neg-risk in parallel. Call this when you start watching
190
- * a market so that subsequent createOrder calls hit only POST /order.
207
+ * Pre-warm the SDK's internal caches for a market outcome.
208
+ *
209
+ * Fetches tick size, fee rate, and neg-risk in parallel so that subsequent
210
+ * `createOrder` calls skip those lookups and hit only `POST /order`.
211
+ * Call this when you start watching a market.
212
+ *
213
+ * @param outcomeId - The CLOB Token ID for the outcome (use `outcome.outcomeId`)
214
+ *
215
+ * @example-ts Pre-warm before placing orders
216
+ * const markets = await exchange.fetchMarkets({ query: 'Trump' });
217
+ * const outcomeId = markets[0].outcomes[0].outcomeId;
218
+ * await exchange.preWarmMarket(outcomeId);
219
+ * // Subsequent createOrder calls are faster
220
+ *
221
+ * @example-python Pre-warm before placing orders
222
+ * markets = exchange.fetch_markets(query='Trump')
223
+ * outcome_id = markets[0].outcomes[0].outcome_id
224
+ * exchange.pre_warm_market(outcome_id)
225
+ * # Subsequent create_order calls are faster
191
226
  */
192
227
  async preWarmMarket(outcomeId) {
193
228
  const auth = this.ensureAuth();
@@ -198,59 +233,71 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
198
233
  client.getNegRisk(outcomeId),
199
234
  ]);
200
235
  }
201
- async createOrder(params) {
236
+ async buildOrder(params) {
202
237
  try {
203
238
  const auth = this.ensureAuth();
204
239
  const client = await auth.getClobClient();
205
- // Map side to Polymarket enum
206
240
  const side = params.side.toUpperCase() === 'BUY' ? clob_client_1.Side.BUY : clob_client_1.Side.SELL;
207
- // For limit orders, price is required
208
- if (params.type === 'limit' && !params.price) {
209
- throw new Error('Price is required for limit orders');
210
- }
211
- // For market orders, use max slippage: 0.99 for BUY (willing to pay up to 99%), 0.01 for SELL (willing to accept down to 1%)
212
241
  const price = params.price || (side === clob_client_1.Side.BUY ? 0.99 : 0.01);
213
- // Use provided tickSize, or let the SDK resolve it from its own cache / API
214
242
  const tickSize = params.tickSize ? params.tickSize.toString() : undefined;
215
243
  const orderArgs = {
216
244
  tokenID: params.outcomeId,
217
- price: price,
218
- side: side,
245
+ price,
246
+ side,
219
247
  size: params.amount,
220
248
  };
221
- if (params.fee !== undefined && params.fee !== null) {
249
+ if (params.fee != null)
222
250
  orderArgs.feeRateBps = params.fee;
223
- }
224
251
  const options = {};
225
- if (tickSize) {
252
+ if (tickSize)
226
253
  options.tickSize = tickSize;
227
- }
228
- if (params.negRisk !== undefined) {
254
+ if (params.negRisk !== undefined)
229
255
  options.negRisk = params.negRisk;
230
- }
231
- const response = await client.createAndPostOrder(orderArgs, options);
256
+ const signedOrder = await client.createOrder(orderArgs, options);
257
+ return {
258
+ exchange: this.name,
259
+ params,
260
+ signedOrder: signedOrder,
261
+ raw: signedOrder,
262
+ };
263
+ }
264
+ catch (error) {
265
+ throw errors_1.polymarketErrorMapper.mapError(error);
266
+ }
267
+ }
268
+ async submitOrder(built) {
269
+ try {
270
+ const auth = this.ensureAuth();
271
+ const client = await auth.getClobClient();
272
+ const response = await client.postOrder(built.raw);
232
273
  if (!response || !response.success) {
233
- throw new Error(`${response?.errorMsg || 'Order placement failed'} (Response: ${JSON.stringify(response)})`);
274
+ throw new Error(`${response?.errorMsg || 'Order submission failed'} (Response: ${JSON.stringify(response)})`);
234
275
  }
276
+ const side = built.params.side.toUpperCase() === 'BUY' ? clob_client_1.Side.BUY : clob_client_1.Side.SELL;
277
+ const price = built.params.price || (side === clob_client_1.Side.BUY ? 0.99 : 0.01);
235
278
  return {
236
279
  id: response.orderID,
237
- marketId: params.marketId,
238
- outcomeId: params.outcomeId,
239
- side: params.side,
240
- type: params.type,
241
- price: price,
242
- amount: params.amount,
280
+ marketId: built.params.marketId,
281
+ outcomeId: built.params.outcomeId,
282
+ side: built.params.side,
283
+ type: built.params.type,
284
+ price,
285
+ amount: built.params.amount,
243
286
  status: 'open',
244
287
  filled: 0,
245
- remaining: params.amount,
246
- fee: params.fee,
247
- timestamp: Date.now()
288
+ remaining: built.params.amount,
289
+ fee: built.params.fee,
290
+ timestamp: Date.now(),
248
291
  };
249
292
  }
250
293
  catch (error) {
251
294
  throw errors_1.polymarketErrorMapper.mapError(error);
252
295
  }
253
296
  }
297
+ async createOrder(params) {
298
+ const built = await this.buildOrder(params);
299
+ return this.submitOrder(built);
300
+ }
254
301
  async cancelOrder(orderId) {
255
302
  try {
256
303
  const auth = this.ensureAuth();
@@ -325,6 +372,29 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
325
372
  throw errors_1.polymarketErrorMapper.mapError(error);
326
373
  }
327
374
  }
375
+ async fetchMyTrades(params) {
376
+ const auth = this.ensureAuth();
377
+ const address = await auth.getEffectiveFunderAddress();
378
+ const queryParams = { user: address };
379
+ if (params?.marketId)
380
+ queryParams.market = params.marketId;
381
+ if (params?.limit)
382
+ queryParams.limit = params.limit;
383
+ if (params?.since)
384
+ queryParams.start = Math.floor(params.since.getTime() / 1000);
385
+ if (params?.until)
386
+ queryParams.end = Math.floor(params.until.getTime() / 1000);
387
+ const data = await this.callApi('getTrades', queryParams);
388
+ const trades = Array.isArray(data) ? data : (data.data || []);
389
+ return trades.map((t) => ({
390
+ id: t.id || t.transactionHash || String(t.timestamp),
391
+ timestamp: typeof t.timestamp === 'number' ? t.timestamp * 1000 : Date.now(),
392
+ price: parseFloat(t.price || '0'),
393
+ amount: parseFloat(t.size || t.amount || '0'),
394
+ side: t.side === 'BUY' ? 'buy' : t.side === 'SELL' ? 'sell' : 'unknown',
395
+ orderId: t.orderId,
396
+ }));
397
+ }
328
398
  async fetchPositions() {
329
399
  try {
330
400
  const auth = this.ensureAuth();
@@ -76,6 +76,7 @@ function mapMarketToUnified(event, market, options = {}) {
76
76
  const um = {
77
77
  id: market.id,
78
78
  marketId: market.id,
79
+ eventId: event.id || event.slug,
79
80
  title: market.question ? `${event.title} - ${market.question}` : event.title,
80
81
  description: market.description || event.description,
81
82
  outcomes: outcomes,
@@ -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-19T07:57:20.610Z
3
+ * Generated at: 2026-03-04T17:45:20.626Z
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-19T07:57:20.610Z
6
+ * Generated at: 2026-03-04T17:45:20.626Z
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,11 @@ 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;
22
+ buildOrder: false;
23
+ submitOrder: false;
19
24
  };
20
25
  private auth?;
21
26
  private ws?;
@@ -26,10 +31,47 @@ export declare class ProbableExchange extends PredictionMarketExchange {
26
31
  private ensureAuth;
27
32
  protected fetchMarketsImpl(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
28
33
  protected fetchEventsImpl(params: EventFetchParams): Promise<UnifiedEvent[]>;
34
+ /**
35
+ * Fetch a single event by its numeric ID (Probable only).
36
+ *
37
+ * @param id - The numeric event ID
38
+ * @returns The UnifiedEvent, or null if not found
39
+ *
40
+ * @example-ts Get event by ID
41
+ * const event = await exchange.getEventById('42');
42
+ * if (event) {
43
+ * console.log(event.title);
44
+ * console.log(event.markets.length, 'markets');
45
+ * }
46
+ *
47
+ * @example-python Get event by ID
48
+ * event = exchange.get_event_by_id('42')
49
+ * if event:
50
+ * print(event.title)
51
+ * print(len(event.markets), 'markets')
52
+ */
29
53
  getEventById(id: string): Promise<UnifiedEvent | null>;
54
+ /**
55
+ * Fetch a single event by its URL slug (Probable only).
56
+ *
57
+ * @param slug - The event's URL slug (e.g. `"trump-2024-election"`)
58
+ * @returns The UnifiedEvent, or null if not found
59
+ *
60
+ * @example-ts Get event by slug
61
+ * const event = await exchange.getEventBySlug('trump-2024-election');
62
+ * if (event) {
63
+ * console.log(event.title);
64
+ * }
65
+ *
66
+ * @example-python Get event by slug
67
+ * event = exchange.get_event_by_slug('trump-2024-election')
68
+ * if event:
69
+ * print(event.title)
70
+ */
30
71
  getEventBySlug(slug: string): Promise<UnifiedEvent | null>;
31
72
  fetchOrderBook(id: string): Promise<OrderBook>;
32
- fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams): Promise<PriceCandle[]>;
73
+ fetchOHLCV(id: string, params: OHLCVParams): Promise<PriceCandle[]>;
74
+ fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
33
75
  createOrder(params: CreateOrderParams): Promise<Order>;
34
76
  /**
35
77
  * Cancel an order.