pmxtjs 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/{src/BaseExchange.ts → dist/BaseExchange.d.ts} +4 -22
  2. package/dist/BaseExchange.js +30 -0
  3. package/dist/exchanges/Kalshi.d.ts +20 -0
  4. package/{src/exchanges/Kalshi.ts → dist/exchanges/Kalshi.js} +75 -114
  5. package/dist/exchanges/Polymarket.d.ts +38 -0
  6. package/{src/exchanges/Polymarket.ts → dist/exchanges/Polymarket.js} +105 -146
  7. package/{src/index.ts → dist/index.d.ts} +0 -1
  8. package/dist/index.js +20 -0
  9. package/{src/types.ts → dist/types.d.ts} +3 -17
  10. package/dist/types.js +5 -0
  11. package/package.json +9 -1
  12. package/readme.md +62 -0
  13. package/coverage/clover.xml +0 -334
  14. package/coverage/coverage-final.json +0 -4
  15. package/coverage/lcov-report/base.css +0 -224
  16. package/coverage/lcov-report/block-navigation.js +0 -87
  17. package/coverage/lcov-report/favicon.png +0 -0
  18. package/coverage/lcov-report/index.html +0 -131
  19. package/coverage/lcov-report/pmxt/BaseExchange.ts.html +0 -256
  20. package/coverage/lcov-report/pmxt/exchanges/Kalshi.ts.html +0 -1132
  21. package/coverage/lcov-report/pmxt/exchanges/Polymarket.ts.html +0 -1456
  22. package/coverage/lcov-report/pmxt/exchanges/index.html +0 -131
  23. package/coverage/lcov-report/pmxt/index.html +0 -116
  24. package/coverage/lcov-report/prettify.css +0 -1
  25. package/coverage/lcov-report/prettify.js +0 -2
  26. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  27. package/coverage/lcov-report/sorter.js +0 -210
  28. package/coverage/lcov-report/src/BaseExchange.ts.html +0 -256
  29. package/coverage/lcov-report/src/exchanges/Kalshi.ts.html +0 -1132
  30. package/coverage/lcov-report/src/exchanges/Polymarket.ts.html +0 -1456
  31. package/coverage/lcov-report/src/exchanges/index.html +0 -131
  32. package/coverage/lcov-report/src/index.html +0 -116
  33. package/coverage/lcov.info +0 -766
  34. package/examples/get_event_prices.ts +0 -37
  35. package/examples/historical_prices.ts +0 -117
  36. package/examples/orderbook.ts +0 -102
  37. package/examples/recent_trades.ts +0 -29
  38. package/examples/search_events.ts +0 -68
  39. package/examples/search_market.ts +0 -29
  40. package/jest.config.js +0 -11
  41. package/pmxt-0.1.0.tgz +0 -0
  42. package/test/exchanges/kalshi/ApiErrors.test.ts +0 -132
  43. package/test/exchanges/kalshi/EmptyResponse.test.ts +0 -44
  44. package/test/exchanges/kalshi/FetchAndNormalizeMarkets.test.ts +0 -56
  45. package/test/exchanges/kalshi/LiveApi.integration.test.ts +0 -40
  46. package/test/exchanges/kalshi/MarketHistory.test.ts +0 -185
  47. package/test/exchanges/kalshi/OrderBook.test.ts +0 -149
  48. package/test/exchanges/kalshi/SearchMarkets.test.ts +0 -174
  49. package/test/exchanges/kalshi/VolumeFallback.test.ts +0 -44
  50. package/test/exchanges/polymarket/DataValidation.test.ts +0 -271
  51. package/test/exchanges/polymarket/ErrorHandling.test.ts +0 -34
  52. package/test/exchanges/polymarket/FetchAndNormalizeMarkets.test.ts +0 -68
  53. package/test/exchanges/polymarket/GetMarketsBySlug.test.ts +0 -268
  54. package/test/exchanges/polymarket/LiveApi.integration.test.ts +0 -44
  55. package/test/exchanges/polymarket/MarketHistory.test.ts +0 -207
  56. package/test/exchanges/polymarket/OrderBook.test.ts +0 -167
  57. package/test/exchanges/polymarket/RequestParameters.test.ts +0 -39
  58. package/test/exchanges/polymarket/SearchMarkets.test.ts +0 -176
  59. package/test/exchanges/polymarket/TradeHistory.test.ts +0 -248
  60. package/tsconfig.json +0 -12
@@ -1,103 +1,99 @@
1
- import axios from 'axios';
2
- import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams } from '../BaseExchange';
3
- import { UnifiedMarket, MarketOutcome, PriceCandle, CandleInterval, OrderBook, Trade } from '../types';
4
-
5
- export class PolymarketExchange extends PredictionMarketExchange {
6
- get name(): string {
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PolymarketExchange = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const BaseExchange_1 = require("../BaseExchange");
9
+ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
10
+ constructor() {
11
+ super(...arguments);
12
+ // Utilizing the Gamma API for rich metadata and list view data
13
+ this.baseUrl = 'https://gamma-api.polymarket.com/events';
14
+ // CLOB API for orderbook, trades, and timeseries
15
+ this.clobUrl = 'https://clob.polymarket.com';
16
+ }
17
+ get name() {
7
18
  return 'Polymarket';
8
19
  }
9
-
10
- // Utilizing the Gamma API for rich metadata and list view data
11
- private readonly baseUrl = 'https://gamma-api.polymarket.com/events';
12
- // CLOB API for orderbook, trades, and timeseries
13
- private readonly clobUrl = 'https://clob.polymarket.com';
14
-
15
- async fetchMarkets(params?: MarketFilterParams): Promise<UnifiedMarket[]> {
16
- const limit = params?.limit || 200; // Higher default for better coverage
20
+ async fetchMarkets(params) {
21
+ const limit = params?.limit || 200; // Higher default for better coverage
17
22
  const offset = params?.offset || 0;
18
-
19
23
  // Map generic sort params to Polymarket Gamma API params
20
- let queryParams: any = {
24
+ let queryParams = {
21
25
  active: 'true',
22
26
  closed: 'false',
23
27
  limit: limit,
24
28
  offset: offset,
25
29
  };
26
-
27
30
  // Gamma API uses 'order' and 'ascending' for sorting
28
31
  if (params?.sort === 'volume') {
29
32
  queryParams.order = 'volume';
30
33
  queryParams.ascending = 'false';
31
- } else if (params?.sort === 'newest') {
34
+ }
35
+ else if (params?.sort === 'newest') {
32
36
  queryParams.order = 'startDate';
33
37
  queryParams.ascending = 'false';
34
- } else if (params?.sort === 'liquidity') {
38
+ }
39
+ else if (params?.sort === 'liquidity') {
35
40
  // queryParams.order = 'liquidity';
36
- } else {
41
+ }
42
+ else {
37
43
  // Default: do not send order param to avoid 422
38
44
  }
39
-
40
45
  try {
41
46
  // Fetch active events from Gamma
42
- const response = await axios.get(this.baseUrl, {
47
+ const response = await axios_1.default.get(this.baseUrl, {
43
48
  params: queryParams
44
49
  });
45
-
46
50
  const events = response.data;
47
- const unifiedMarkets: UnifiedMarket[] = [];
48
-
51
+ const unifiedMarkets = [];
49
52
  for (const event of events) {
50
53
  // Each event is a container (e.g. "US Election").
51
54
  // It contains specific "markets" (e.g. "Winner", "Pop Vote").
52
- if (!event.markets) continue;
53
-
55
+ if (!event.markets)
56
+ continue;
54
57
  for (const market of event.markets) {
55
- const outcomes: MarketOutcome[] = [];
56
-
58
+ const outcomes = [];
57
59
  // Polymarket Gamma often returns 'outcomes' and 'outcomePrices' as stringified JSON keys.
58
- let outcomeLabels: string[] = [];
59
- let outcomePrices: string[] = [];
60
-
60
+ let outcomeLabels = [];
61
+ let outcomePrices = [];
61
62
  try {
62
63
  outcomeLabels = typeof market.outcomes === 'string' ? JSON.parse(market.outcomes) : (market.outcomes || []);
63
64
  outcomePrices = typeof market.outcomePrices === 'string' ? JSON.parse(market.outcomePrices) : (market.outcomePrices || []);
64
- } catch (e) {
65
- console.warn(`Failed to parse outcomes for market ${market.id}`, e);
66
65
  }
67
-
66
+ catch (e) {
67
+ }
68
68
  // Extract CLOB token IDs for granular operations
69
- let clobTokenIds: string[] = [];
69
+ let clobTokenIds = [];
70
70
  try {
71
71
  clobTokenIds = typeof market.clobTokenIds === 'string' ? JSON.parse(market.clobTokenIds) : (market.clobTokenIds || []);
72
- } catch (e) {
73
- console.warn(`Failed to parse clobTokenIds for market ${market.id}`, e);
74
72
  }
75
-
73
+ catch (e) {
74
+ }
76
75
  // Extract candidate/option name from market question for better outcome labels
77
- let candidateName: string | null = null;
76
+ let candidateName = null;
78
77
  if (market.question && market.groupItemTitle) {
79
78
  candidateName = market.groupItemTitle;
80
79
  }
81
-
82
80
  if (outcomeLabels.length > 0) {
83
- outcomeLabels.forEach((label: string, index: number) => {
81
+ outcomeLabels.forEach((label, index) => {
84
82
  const rawPrice = outcomePrices[index] || "0";
85
-
86
83
  // For Yes/No markets with specific candidates, use the candidate name
87
84
  let outcomeLabel = label;
88
85
  if (candidateName && label.toLowerCase() === 'yes') {
89
86
  outcomeLabel = candidateName;
90
- } else if (candidateName && label.toLowerCase() === 'no') {
87
+ }
88
+ else if (candidateName && label.toLowerCase() === 'no') {
91
89
  outcomeLabel = `Not ${candidateName}`;
92
90
  }
93
-
94
91
  // 24h Price Change
95
92
  // Polymarket API provides 'oneDayPriceChange' on the market object
96
93
  let priceChange = 0;
97
94
  if (index === 0 || label.toLowerCase() === 'yes' || (candidateName && label === candidateName)) {
98
95
  priceChange = Number(market.oneDayPriceChange || 0);
99
96
  }
100
-
101
97
  outcomes.push({
102
98
  id: String(index),
103
99
  label: outcomeLabel,
@@ -109,7 +105,6 @@ export class PolymarketExchange extends PredictionMarketExchange {
109
105
  });
110
106
  });
111
107
  }
112
-
113
108
  unifiedMarkets.push({
114
109
  id: market.id,
115
110
  title: market.question ? `${event.title} - ${market.question}` : event.title,
@@ -123,115 +118,105 @@ export class PolymarketExchange extends PredictionMarketExchange {
123
118
  url: `https://polymarket.com/event/${event.slug}`,
124
119
  image: event.image || market.image || `https://polymarket.com/api/og?slug=${event.slug}`,
125
120
  category: event.category || event.tags?.[0]?.label,
126
- tags: event.tags?.map((t: any) => t.label) || []
121
+ tags: event.tags?.map((t) => t.label) || []
127
122
  });
128
123
  }
129
124
  }
130
-
131
125
  // Client-side Sort capability to ensure contract fulfillment
132
126
  // Often API filters are "good effort" or apply to the 'event' but not the 'market'
133
127
  if (params?.sort === 'volume') {
134
128
  unifiedMarkets.sort((a, b) => b.volume24h - a.volume24h);
135
- } else if (params?.sort === 'newest') {
129
+ }
130
+ else if (params?.sort === 'newest') {
136
131
  // unifiedMarkets.sort((a, b) => b.resolutionDate.getTime() - a.resolutionDate.getTime()); // Not quite 'newest'
137
- } else if (params?.sort === 'liquidity') {
132
+ }
133
+ else if (params?.sort === 'liquidity') {
138
134
  unifiedMarkets.sort((a, b) => b.liquidity - a.liquidity);
139
- } else {
135
+ }
136
+ else {
140
137
  // Default volume sort
141
138
  unifiedMarkets.sort((a, b) => b.volume24h - a.volume24h);
142
139
  }
143
-
144
140
  // Respect limit strictly after flattening
145
141
  return unifiedMarkets.slice(0, limit);
146
-
147
- } catch (error) {
142
+ }
143
+ catch (error) {
148
144
  console.error("Error fetching Polymarket data:", error);
149
145
  return [];
150
146
  }
151
147
  }
152
-
153
- async searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]> {
148
+ async searchMarkets(query, params) {
154
149
  // Polymarket Gamma API doesn't support native search
155
150
  // Fetch a larger batch and filter client-side
156
151
  const searchLimit = 100; // Fetch more markets to search through
157
-
158
152
  try {
159
153
  // Fetch markets with a higher limit
160
154
  const markets = await this.fetchMarkets({
161
155
  ...params,
162
156
  limit: searchLimit
163
157
  });
164
-
165
158
  // Client-side text filtering
166
159
  const lowerQuery = query.toLowerCase();
167
- const filtered = markets.filter(market =>
168
- market.title.toLowerCase().includes(lowerQuery) ||
169
- market.description.toLowerCase().includes(lowerQuery)
170
- );
171
-
160
+ const filtered = markets.filter(market => market.title.toLowerCase().includes(lowerQuery) ||
161
+ market.description.toLowerCase().includes(lowerQuery));
172
162
  // Apply limit to filtered results
173
163
  const limit = params?.limit || 20;
174
164
  return filtered.slice(0, limit);
175
-
176
- } catch (error) {
165
+ }
166
+ catch (error) {
177
167
  console.error("Error searching Polymarket data:", error);
178
168
  return [];
179
169
  }
180
170
  }
181
-
182
171
  /**
183
172
  * Fetch specific markets by their URL slug.
184
173
  * Useful for looking up a specific event from a URL.
185
174
  * @param slug - The event slug (e.g. "will-fed-cut-rates-in-march")
186
175
  */
187
- async getMarketsBySlug(slug: string): Promise<UnifiedMarket[]> {
176
+ async getMarketsBySlug(slug) {
188
177
  try {
189
- const response = await axios.get(this.baseUrl, {
178
+ const response = await axios_1.default.get(this.baseUrl, {
190
179
  params: { slug: slug }
191
180
  });
192
-
193
181
  const events = response.data;
194
- if (!events || events.length === 0) return [];
195
-
182
+ if (!events || events.length === 0)
183
+ return [];
196
184
  // We can reuse the logic from fetchMarkets if we extract it,
197
185
  // but for now I'll duplicate the extraction logic to keep it self-contained
198
186
  // and avoid safe refactoring risks.
199
187
  // Actually, fetchMarkets is built to work with the Gamma response structure.
200
188
  // So we can manually map the response using the same logic.
201
-
202
- const unifiedMarkets: UnifiedMarket[] = [];
203
-
189
+ const unifiedMarkets = [];
204
190
  for (const event of events) {
205
- if (!event.markets) continue;
206
-
191
+ if (!event.markets)
192
+ continue;
207
193
  for (const market of event.markets) {
208
- const outcomes: MarketOutcome[] = [];
209
- let outcomeLabels: string[] = [];
210
- let outcomePrices: string[] = [];
211
- let clobTokenIds: string[] = [];
212
-
194
+ const outcomes = [];
195
+ let outcomeLabels = [];
196
+ let outcomePrices = [];
197
+ let clobTokenIds = [];
213
198
  try {
214
199
  outcomeLabels = typeof market.outcomes === 'string' ? JSON.parse(market.outcomes) : (market.outcomes || []);
215
200
  outcomePrices = typeof market.outcomePrices === 'string' ? JSON.parse(market.outcomePrices) : (market.outcomePrices || []);
216
201
  clobTokenIds = typeof market.clobTokenIds === 'string' ? JSON.parse(market.clobTokenIds) : (market.clobTokenIds || []);
217
- } catch (e) { console.warn(`Parse error for market ${market.id}`, e); }
218
-
202
+ }
203
+ catch (e) { /* ignore */ }
219
204
  let candidateName = market.groupItemTitle;
220
- if (!candidateName && market.question) candidateName = market.question;
221
-
205
+ if (!candidateName && market.question)
206
+ candidateName = market.question;
222
207
  if (outcomeLabels.length > 0) {
223
- outcomeLabels.forEach((label: string, index: number) => {
208
+ outcomeLabels.forEach((label, index) => {
224
209
  let outcomeLabel = label;
225
210
  // Clean up Yes/No labels if candidate name is available
226
- if (candidateName && label.toLowerCase() === 'yes') outcomeLabel = candidateName;
227
- else if (candidateName && label.toLowerCase() === 'no') outcomeLabel = `Not ${candidateName}`;
228
-
211
+ if (candidateName && label.toLowerCase() === 'yes')
212
+ outcomeLabel = candidateName;
213
+ else if (candidateName && label.toLowerCase() === 'no')
214
+ outcomeLabel = `Not ${candidateName}`;
229
215
  // 24h Price Change Logic
230
216
  let priceChange = 0;
231
217
  if (index === 0 || label.toLowerCase() === 'yes' || (candidateName && label === candidateName)) {
232
218
  priceChange = Number(market.oneDayPriceChange || 0);
233
219
  }
234
-
235
220
  outcomes.push({
236
221
  id: String(index),
237
222
  label: outcomeLabel,
@@ -243,7 +228,6 @@ export class PolymarketExchange extends PredictionMarketExchange {
243
228
  });
244
229
  });
245
230
  }
246
-
247
231
  unifiedMarkets.push({
248
232
  id: market.id,
249
233
  title: event.title,
@@ -257,23 +241,22 @@ export class PolymarketExchange extends PredictionMarketExchange {
257
241
  url: `https://polymarket.com/event/${event.slug}`,
258
242
  image: event.image || market.image,
259
243
  category: event.category || event.tags?.[0]?.label,
260
- tags: event.tags?.map((t: any) => t.label) || []
244
+ tags: event.tags?.map((t) => t.label) || []
261
245
  });
262
246
  }
263
247
  }
264
248
  return unifiedMarkets;
265
-
266
- } catch (error) {
249
+ }
250
+ catch (error) {
267
251
  console.error(`Error fetching Polymarket slug ${slug}:`, error);
268
252
  return [];
269
253
  }
270
254
  }
271
-
272
255
  /**
273
256
  * Map our generic CandleInterval to Polymarket's fidelity (in minutes)
274
257
  */
275
- private mapIntervalToFidelity(interval: CandleInterval): number {
276
- const mapping: Record<CandleInterval, number> = {
258
+ mapIntervalToFidelity(interval) {
259
+ const mapping = {
277
260
  '1m': 1,
278
261
  '5m': 5,
279
262
  '15m': 15,
@@ -283,26 +266,22 @@ export class PolymarketExchange extends PredictionMarketExchange {
283
266
  };
284
267
  return mapping[interval];
285
268
  }
286
-
287
269
  /**
288
270
  * Fetch historical price data (OHLCV candles) for a specific token.
289
271
  * @param id - The CLOB token ID (e.g., outcome token ID)
290
272
  */
291
- async getMarketHistory(id: string, params: HistoryFilterParams): Promise<PriceCandle[]> {
273
+ async getMarketHistory(id, params) {
292
274
  // ID Validation: Polymarket CLOB requires a Token ID (long numeric string) not a Market ID
293
275
  if (id.length < 10 && /^\d+$/.test(id)) {
294
276
  throw new Error(`Invalid ID for Polymarket history: "${id}". You provided a Market ID, but Polymarket's CLOB API requires a Token ID. Use outcome.metadata.clobTokenId instead.`);
295
277
  }
296
-
297
278
  try {
298
279
  const fidelity = this.mapIntervalToFidelity(params.resolution);
299
280
  const nowTs = Math.floor(Date.now() / 1000);
300
-
301
281
  // 1. Smart Lookback Calculation
302
282
  // If start/end not provided, calculate window based on limit * resolution
303
283
  let startTs = params.start ? Math.floor(params.start.getTime() / 1000) : 0;
304
284
  let endTs = params.end ? Math.floor(params.end.getTime() / 1000) : nowTs;
305
-
306
285
  if (!params.start) {
307
286
  // Default limit is usually 20 in the example, but safety margin is good.
308
287
  // If limit is not set, we default to 100 candles.
@@ -311,29 +290,23 @@ export class PolymarketExchange extends PredictionMarketExchange {
311
290
  const durationSeconds = count * fidelity * 60;
312
291
  startTs = endTs - durationSeconds;
313
292
  }
314
-
315
- const queryParams: any = {
293
+ const queryParams = {
316
294
  market: id,
317
295
  fidelity: fidelity,
318
296
  startTs: startTs,
319
297
  endTs: endTs
320
298
  };
321
-
322
- const response = await axios.get(`${this.clobUrl}/prices-history`, {
299
+ const response = await axios_1.default.get(`${this.clobUrl}/prices-history`, {
323
300
  params: queryParams
324
301
  });
325
-
326
302
  const history = response.data.history || [];
327
-
328
303
  // 2. Align Timestamps (Snap to Grid)
329
304
  // Polymarket returns random tick timestamps (e.g. 1:00:21).
330
305
  // We want to normalize this to the start of the bucket (1:00:00).
331
306
  const resolutionMs = fidelity * 60 * 1000;
332
-
333
- const candles: PriceCandle[] = history.map((item: any) => {
307
+ const candles = history.map((item) => {
334
308
  const rawMs = item.t * 1000;
335
309
  const snappedMs = Math.floor(rawMs / resolutionMs) * resolutionMs;
336
-
337
310
  return {
338
311
  timestamp: snappedMs, // Aligned timestamp
339
312
  open: item.p,
@@ -343,16 +316,14 @@ export class PolymarketExchange extends PredictionMarketExchange {
343
316
  volume: undefined
344
317
  };
345
318
  });
346
-
347
319
  // Apply limit if specified
348
320
  if (params.limit && candles.length > params.limit) {
349
321
  return candles.slice(-params.limit);
350
322
  }
351
-
352
323
  return candles;
353
-
354
- } catch (error: any) {
355
- if (axios.isAxiosError(error) && error.response) {
324
+ }
325
+ catch (error) {
326
+ if (axios_1.default.isAxiosError(error) && error.response) {
356
327
  const apiError = error.response.data?.error || error.response.data?.message || "Unknown API Error";
357
328
  throw new Error(`Polymarket History API Error (${error.response.status}): ${apiError}. Used ID: ${id}`);
358
329
  }
@@ -360,61 +331,53 @@ export class PolymarketExchange extends PredictionMarketExchange {
360
331
  throw error;
361
332
  }
362
333
  }
363
-
364
334
  /**
365
335
  * Fetch the current order book for a specific token.
366
336
  * @param id - The CLOB token ID
367
337
  */
368
- async getOrderBook(id: string): Promise<OrderBook> {
338
+ async getOrderBook(id) {
369
339
  try {
370
- const response = await axios.get(`${this.clobUrl}/book`, {
340
+ const response = await axios_1.default.get(`${this.clobUrl}/book`, {
371
341
  params: { token_id: id }
372
342
  });
373
-
374
343
  const data = response.data;
375
-
376
344
  // Response format: { bids: [{price: "0.52", size: "100"}], asks: [...] }
377
- const bids = (data.bids || []).map((level: any) => ({
345
+ const bids = (data.bids || []).map((level) => ({
378
346
  price: parseFloat(level.price),
379
347
  size: parseFloat(level.size)
380
- })).sort((a: { price: number, size: number }, b: { price: number, size: number }) => b.price - a.price); // Sort Bids Descending (Best/Highest first)
381
-
382
- const asks = (data.asks || []).map((level: any) => ({
348
+ })).sort((a, b) => b.price - a.price); // Sort Bids Descending (Best/Highest first)
349
+ const asks = (data.asks || []).map((level) => ({
383
350
  price: parseFloat(level.price),
384
351
  size: parseFloat(level.size)
385
- })).sort((a: { price: number, size: number }, b: { price: number, size: number }) => a.price - b.price); // Sort Asks Ascending (Best/Lowest first)
386
-
352
+ })).sort((a, b) => a.price - b.price); // Sort Asks Ascending (Best/Lowest first)
387
353
  return {
388
354
  bids,
389
355
  asks,
390
356
  timestamp: data.timestamp ? new Date(data.timestamp).getTime() : Date.now()
391
357
  };
392
-
393
- } catch (error) {
358
+ }
359
+ catch (error) {
394
360
  console.error(`Error fetching Polymarket orderbook for ${id}:`, error);
395
361
  return { bids: [], asks: [] };
396
362
  }
397
363
  }
398
-
399
364
  /**
400
365
  * Fetch raw trade history for a specific token.
401
366
  * @param id - The CLOB token ID
402
- *
367
+ *
403
368
  * NOTE: Polymarket's /trades endpoint currently requires L2 Authentication (API Key).
404
369
  * This method will return an empty array if an API key is not provided in headers.
405
370
  * Use getMarketHistory for public historical price data instead.
406
371
  */
407
- async getTradeHistory(id: string, params: HistoryFilterParams): Promise<Trade[]> {
372
+ async getTradeHistory(id, params) {
408
373
  // ID Validation
409
374
  if (id.length < 10 && /^\d+$/.test(id)) {
410
375
  throw new Error(`Invalid ID for Polymarket trades: "${id}". You provided a Market ID, but Polymarket's CLOB API requires a Token ID.`);
411
376
  }
412
-
413
377
  try {
414
- const queryParams: any = {
378
+ const queryParams = {
415
379
  market: id
416
380
  };
417
-
418
381
  // Add time filters if provided
419
382
  if (params.start) {
420
383
  queryParams.after = Math.floor(params.start.getTime() / 1000);
@@ -422,31 +385,26 @@ export class PolymarketExchange extends PredictionMarketExchange {
422
385
  if (params.end) {
423
386
  queryParams.before = Math.floor(params.end.getTime() / 1000);
424
387
  }
425
-
426
- const response = await axios.get(`${this.clobUrl}/trades`, {
388
+ const response = await axios_1.default.get(`${this.clobUrl}/trades`, {
427
389
  params: queryParams
428
390
  });
429
-
430
391
  // Response is an array of trade objects
431
392
  const trades = response.data || [];
432
-
433
- const mappedTrades: Trade[] = trades.map((trade: any) => ({
393
+ const mappedTrades = trades.map((trade) => ({
434
394
  id: trade.id || `${trade.timestamp}-${trade.price}`,
435
395
  timestamp: trade.timestamp * 1000, // Convert to milliseconds
436
396
  price: parseFloat(trade.price),
437
397
  amount: parseFloat(trade.size || trade.amount || 0),
438
398
  side: trade.side === 'BUY' ? 'buy' : trade.side === 'SELL' ? 'sell' : 'unknown'
439
399
  }));
440
-
441
400
  // Apply limit if specified
442
401
  if (params.limit && mappedTrades.length > params.limit) {
443
402
  return mappedTrades.slice(-params.limit); // Return most recent N trades
444
403
  }
445
-
446
404
  return mappedTrades;
447
-
448
- } catch (error: any) {
449
- if (axios.isAxiosError(error) && error.response) {
405
+ }
406
+ catch (error) {
407
+ if (axios_1.default.isAxiosError(error) && error.response) {
450
408
  const apiError = error.response.data?.error || error.response.data?.message || "Unknown API Error";
451
409
  throw new Error(`Polymarket Trades API Error (${error.response.status}): ${apiError}. Used ID: ${id}`);
452
410
  }
@@ -455,3 +413,4 @@ export class PolymarketExchange extends PredictionMarketExchange {
455
413
  }
456
414
  }
457
415
  }
416
+ exports.PolymarketExchange = PolymarketExchange;
@@ -2,4 +2,3 @@ export * from './BaseExchange';
2
2
  export * from './types';
3
3
  export * from './exchanges/Polymarket';
4
4
  export * from './exchanges/Kalshi';
5
-
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./BaseExchange"), exports);
18
+ __exportStar(require("./types"), exports);
19
+ __exportStar(require("./exchanges/Polymarket"), exports);
20
+ __exportStar(require("./exchanges/Kalshi"), exports);
@@ -1,8 +1,3 @@
1
-
2
- // ----------------------------------------------------------------------------
3
- // Core Data Models
4
- // ----------------------------------------------------------------------------
5
-
6
1
  export interface MarketOutcome {
7
2
  id: string;
8
3
  label: string;
@@ -10,28 +5,22 @@ export interface MarketOutcome {
10
5
  priceChange24h?: number;
11
6
  metadata?: Record<string, any>;
12
7
  }
13
-
14
8
  export interface UnifiedMarket {
15
9
  id: string;
16
10
  title: string;
17
11
  description: string;
18
12
  outcomes: MarketOutcome[];
19
-
20
13
  resolutionDate: Date;
21
14
  volume24h: number;
22
- volume?: number; // Total / Lifetime volume
15
+ volume?: number;
23
16
  liquidity: number;
24
17
  openInterest?: number;
25
-
26
18
  url: string;
27
19
  image?: string;
28
-
29
20
  category?: string;
30
21
  tags?: string[];
31
22
  }
32
-
33
23
  export type CandleInterval = '1m' | '5m' | '15m' | '1h' | '6h' | '1d';
34
-
35
24
  export interface PriceCandle {
36
25
  timestamp: number;
37
26
  open: number;
@@ -40,18 +29,15 @@ export interface PriceCandle {
40
29
  close: number;
41
30
  volume?: number;
42
31
  }
43
-
44
32
  export interface OrderLevel {
45
- price: number; // 0.0 to 1.0 (probability)
46
- size: number; // contracts/shares
33
+ price: number;
34
+ size: number;
47
35
  }
48
-
49
36
  export interface OrderBook {
50
37
  bids: OrderLevel[];
51
38
  asks: OrderLevel[];
52
39
  timestamp?: number;
53
40
  }
54
-
55
41
  export interface Trade {
56
42
  id: string;
57
43
  timestamp: number;
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ // ----------------------------------------------------------------------------
3
+ // Core Data Models
4
+ // ----------------------------------------------------------------------------
5
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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",
7
+ "files": [
8
+ "dist",
9
+ "API_REFERENCE.md"
10
+ ],
7
11
  "directories": {
8
12
  "example": "examples",
9
13
  "test": "test"
@@ -19,5 +23,9 @@
19
23
  "dependencies": {
20
24
  "axios": "^1.7.9",
21
25
  "tsx": "^4.21.0"
26
+ },
27
+ "devDependencies": {
28
+ "typescript": "^5.9.3",
29
+ "@types/node": "^25.0.3"
22
30
  }
23
31
  }