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,57 +1,39 @@
1
1
  import { UnifiedMarket, PriceCandle, CandleInterval, OrderBook, Trade } from './types';
2
-
3
2
  export interface MarketFilterParams {
4
3
  limit?: number;
5
4
  offset?: number;
6
5
  sort?: 'volume' | 'liquidity' | 'newest';
7
6
  }
8
-
9
7
  export interface HistoryFilterParams {
10
8
  resolution: CandleInterval;
11
9
  start?: Date;
12
10
  end?: Date;
13
11
  limit?: number;
14
12
  }
15
-
16
- // ----------------------------------------------------------------------------
17
- // Base Exchange Class
18
- // ----------------------------------------------------------------------------
19
-
20
- export abstract class PredictionMarketExchange {
13
+ export declare abstract class PredictionMarketExchange {
21
14
  abstract get name(): string;
22
-
23
15
  /**
24
16
  * Fetch all relevant markets from the source.
25
17
  */
26
18
  abstract fetchMarkets(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
27
-
28
19
  /**
29
20
  * Search for markets matching a keyword query.
30
21
  * Searches across title and description fields.
31
22
  */
32
23
  abstract searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]>;
33
-
34
24
  /**
35
25
  * Fetch historical price data for a specific market or outcome.
36
26
  * @param id - The market ID or specific outcome ID/Token ID depending on the exchange
37
27
  */
38
- async getMarketHistory(id: string, params: HistoryFilterParams): Promise<PriceCandle[]> {
39
- throw new Error("Method getMarketHistory not implemented.");
40
- }
41
-
28
+ getMarketHistory(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
42
29
  /**
43
30
  * Fetch the current order book (bids/asks) for a specific outcome.
44
31
  * Essential for calculating localized spread and depth.
45
32
  */
46
- async getOrderBook(id: string): Promise<OrderBook> {
47
- throw new Error("Method getOrderBook not implemented.");
48
- }
49
-
33
+ getOrderBook(id: string): Promise<OrderBook>;
50
34
  /**
51
35
  * Fetch raw trade history.
52
36
  * Useful for generating synthetic OHLCV candles if the exchange doesn't provide them natively.
53
37
  */
54
- async getTradeHistory(id: string, params: HistoryFilterParams): Promise<Trade[]> {
55
- throw new Error("Method getTradeHistory not implemented.");
56
- }
38
+ getTradeHistory(id: string, params: HistoryFilterParams): Promise<Trade[]>;
57
39
  }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PredictionMarketExchange = void 0;
4
+ // ----------------------------------------------------------------------------
5
+ // Base Exchange Class
6
+ // ----------------------------------------------------------------------------
7
+ class PredictionMarketExchange {
8
+ /**
9
+ * Fetch historical price data for a specific market or outcome.
10
+ * @param id - The market ID or specific outcome ID/Token ID depending on the exchange
11
+ */
12
+ async getMarketHistory(id, params) {
13
+ throw new Error("Method getMarketHistory not implemented.");
14
+ }
15
+ /**
16
+ * Fetch the current order book (bids/asks) for a specific outcome.
17
+ * Essential for calculating localized spread and depth.
18
+ */
19
+ async getOrderBook(id) {
20
+ throw new Error("Method getOrderBook not implemented.");
21
+ }
22
+ /**
23
+ * Fetch raw trade history.
24
+ * Useful for generating synthetic OHLCV candles if the exchange doesn't provide them natively.
25
+ */
26
+ async getTradeHistory(id, params) {
27
+ throw new Error("Method getTradeHistory not implemented.");
28
+ }
29
+ }
30
+ exports.PredictionMarketExchange = PredictionMarketExchange;
@@ -0,0 +1,20 @@
1
+ import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams } from '../BaseExchange';
2
+ import { UnifiedMarket, PriceCandle, OrderBook, Trade } from '../types';
3
+ export declare class KalshiExchange extends PredictionMarketExchange {
4
+ get name(): string;
5
+ private baseUrl;
6
+ fetchMarkets(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
7
+ private fetchActiveEvents;
8
+ private mapMarketToUnified;
9
+ searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]>;
10
+ /**
11
+ * Fetch specific markets by their event ticker.
12
+ * Useful for looking up a specific event from a URL.
13
+ * @param eventTicker - The event ticker (e.g. "FED-25JAN" or "PRES-2024")
14
+ */
15
+ getMarketsBySlug(eventTicker: string): Promise<UnifiedMarket[]>;
16
+ private mapIntervalToKalshi;
17
+ getMarketHistory(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
18
+ getOrderBook(id: string): Promise<OrderBook>;
19
+ getTradeHistory(id: string, params: HistoryFilterParams): Promise<Trade[]>;
20
+ }
@@ -1,24 +1,27 @@
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 KalshiExchange 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.KalshiExchange = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const BaseExchange_1 = require("../BaseExchange");
9
+ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
10
+ constructor() {
11
+ super(...arguments);
12
+ this.baseUrl = "https://api.elections.kalshi.com/trade-api/v2/events";
13
+ }
14
+ get name() {
7
15
  return "Kalshi";
8
16
  }
9
- private baseUrl = "https://api.elections.kalshi.com/trade-api/v2/events";
10
-
11
- async fetchMarkets(params?: MarketFilterParams): Promise<UnifiedMarket[]> {
17
+ async fetchMarkets(params) {
12
18
  const limit = params?.limit || 50;
13
-
14
19
  try {
15
20
  // Fetch active events with nested markets
16
21
  // For small limits, we can optimize by fetching fewer pages
17
22
  const allEvents = await this.fetchActiveEvents(limit);
18
-
19
23
  // Extract ALL markets from all events
20
- const allMarkets: UnifiedMarket[] = [];
21
-
24
+ const allMarkets = [];
22
25
  for (const event of allEvents) {
23
26
  const markets = event.markets || [];
24
27
  for (const market of markets) {
@@ -28,112 +31,90 @@ export class KalshiExchange extends PredictionMarketExchange {
28
31
  }
29
32
  }
30
33
  }
31
-
32
- console.log(`Extracted ${allMarkets.length} markets from ${allEvents.length} events.`);
33
-
34
34
  // Sort by 24h volume
35
35
  if (params?.sort === 'volume') {
36
36
  allMarkets.sort((a, b) => b.volume24h - a.volume24h);
37
- } else if (params?.sort === 'liquidity') {
37
+ }
38
+ else if (params?.sort === 'liquidity') {
38
39
  allMarkets.sort((a, b) => b.liquidity - a.liquidity);
39
40
  }
40
-
41
41
  return allMarkets.slice(0, limit);
42
-
43
- } catch (error) {
42
+ }
43
+ catch (error) {
44
44
  console.error("Error fetching Kalshi data:", error);
45
45
  return [];
46
46
  }
47
47
  }
48
-
49
- private async fetchActiveEvents(targetMarketCount?: number): Promise<any[]> {
50
- let allEvents: any[] = [];
48
+ async fetchActiveEvents(targetMarketCount) {
49
+ let allEvents = [];
51
50
  let totalMarketCount = 0;
52
51
  let cursor = null;
53
52
  let page = 0;
54
-
55
53
  // Note: Kalshi API uses cursor-based pagination which requires sequential fetching.
56
54
  // We cannot parallelize requests for a single list because we need the cursor from page N to fetch page N+1.
57
55
  // To optimize, we use the maximum allowed limit (200) and fetch until exhaustion.
58
-
59
56
  const MAX_PAGES = 1000; // Safety cap against infinite loops
60
57
  const BATCH_SIZE = 200; // Max limit per Kalshi API docs
61
-
62
58
  do {
63
59
  try {
64
60
  // console.log(`Fetching Kalshi page ${page + 1}...`);
65
- const queryParams: any = {
61
+ const queryParams = {
66
62
  limit: BATCH_SIZE,
67
63
  with_nested_markets: true,
68
64
  status: 'open' // Filter to open markets to improve relevance and speed
69
65
  };
70
- if (cursor) queryParams.cursor = cursor;
71
-
72
- const response = await axios.get(this.baseUrl, { params: queryParams });
66
+ if (cursor)
67
+ queryParams.cursor = cursor;
68
+ const response = await axios_1.default.get(this.baseUrl, { params: queryParams });
73
69
  const events = response.data.events || [];
74
-
75
- if (events.length === 0) break;
76
-
70
+ if (events.length === 0)
71
+ break;
77
72
  allEvents = allEvents.concat(events);
78
-
79
73
  // Count markets in this batch for early termination
80
74
  if (targetMarketCount) {
81
75
  for (const event of events) {
82
76
  totalMarketCount += (event.markets || []).length;
83
77
  }
84
-
85
78
  // Early termination: if we have enough markets, stop fetching
86
- // Add a buffer (2x) to ensure we have enough after filtering/sorting
87
79
  if (totalMarketCount >= targetMarketCount * 2) {
88
- console.log(`Early termination: collected ${totalMarketCount} markets (target: ${targetMarketCount})`);
89
80
  break;
90
81
  }
91
82
  }
92
-
93
83
  cursor = response.data.cursor;
94
84
  page++;
95
-
96
- // Log progress every few pages to avoid spam
97
- if (page % 5 === 0) {
98
- console.log(`Fetched ${page} pages (${allEvents.length} events) from Kalshi...`);
99
- }
100
-
101
- } catch (e) {
85
+ }
86
+ catch (e) {
102
87
  console.error(`Error fetching Kalshi page ${page}:`, e);
103
88
  break;
104
89
  }
105
90
  } while (cursor && page < MAX_PAGES);
106
-
107
- console.log(`Finished fetching Kalshi: ${allEvents.length} total events across ${page} pages.`);
108
91
  return allEvents;
109
92
  }
110
-
111
- private mapMarketToUnified(event: any, market: any): UnifiedMarket | null {
112
- if (!market) return null;
113
-
93
+ mapMarketToUnified(event, market) {
94
+ if (!market)
95
+ return null;
114
96
  // Calculate price
115
97
  let price = 0.5;
116
98
  if (market.last_price) {
117
99
  price = market.last_price / 100;
118
- } else if (market.yes_ask && market.yes_bid) {
100
+ }
101
+ else if (market.yes_ask && market.yes_bid) {
119
102
  price = (market.yes_ask + market.yes_bid) / 200;
120
- } else if (market.yes_ask) {
103
+ }
104
+ else if (market.yes_ask) {
121
105
  price = market.yes_ask / 100;
122
106
  }
123
-
124
107
  // Extract candidate name
125
- let candidateName: string | null = null;
108
+ let candidateName = null;
126
109
  if (market.subtitle || market.yes_sub_title) {
127
110
  candidateName = market.subtitle || market.yes_sub_title;
128
111
  }
129
-
130
112
  // Calculate 24h change
131
113
  let priceChange = 0;
132
114
  if (market.previous_price_dollars !== undefined && market.last_price_dollars !== undefined) {
133
115
  priceChange = market.last_price_dollars - market.previous_price_dollars;
134
116
  }
135
-
136
- const outcomes: MarketOutcome[] = [
117
+ const outcomes = [
137
118
  {
138
119
  id: 'yes',
139
120
  label: candidateName || 'Yes',
@@ -147,7 +128,6 @@ export class KalshiExchange extends PredictionMarketExchange {
147
128
  priceChange24h: -priceChange // Inverse change for No? simplified assumption
148
129
  }
149
130
  ];
150
-
151
131
  return {
152
132
  id: market.ticker,
153
133
  title: event.title,
@@ -163,56 +143,50 @@ export class KalshiExchange extends PredictionMarketExchange {
163
143
  tags: event.tags || []
164
144
  };
165
145
  }
166
-
167
- async searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]> {
146
+ async searchMarkets(query, params) {
168
147
  // We must fetch ALL markets to search them locally since we don't have server-side search
169
148
  const fetchLimit = 100000;
170
149
  try {
171
150
  const markets = await this.fetchMarkets({ ...params, limit: fetchLimit });
172
151
  const lowerQuery = query.toLowerCase();
173
- const filtered = markets.filter(market =>
174
- market.title.toLowerCase().includes(lowerQuery) ||
175
- market.description.toLowerCase().includes(lowerQuery)
176
- );
152
+ const filtered = markets.filter(market => market.title.toLowerCase().includes(lowerQuery) ||
153
+ market.description.toLowerCase().includes(lowerQuery));
177
154
  const limit = params?.limit || 20;
178
155
  return filtered.slice(0, limit);
179
- } catch (error) {
156
+ }
157
+ catch (error) {
180
158
  console.error("Error searching Kalshi data:", error);
181
159
  return [];
182
160
  }
183
161
  }
184
-
185
162
  /**
186
163
  * Fetch specific markets by their event ticker.
187
164
  * Useful for looking up a specific event from a URL.
188
165
  * @param eventTicker - The event ticker (e.g. "FED-25JAN" or "PRES-2024")
189
166
  */
190
- async getMarketsBySlug(eventTicker: string): Promise<UnifiedMarket[]> {
167
+ async getMarketsBySlug(eventTicker) {
191
168
  try {
192
169
  // Kalshi API expects uppercase tickers, but URLs use lowercase
193
170
  const normalizedTicker = eventTicker.toUpperCase();
194
171
  const url = `https://api.elections.kalshi.com/trade-api/v2/events/${normalizedTicker}`;
195
- const response = await axios.get(url, {
172
+ const response = await axios_1.default.get(url, {
196
173
  params: { with_nested_markets: true }
197
174
  });
198
-
199
175
  const event = response.data.event;
200
- if (!event) return [];
201
-
202
- const unifiedMarkets: UnifiedMarket[] = [];
176
+ if (!event)
177
+ return [];
178
+ const unifiedMarkets = [];
203
179
  const markets = event.markets || [];
204
-
205
180
  for (const market of markets) {
206
181
  const unifiedMarket = this.mapMarketToUnified(event, market);
207
182
  if (unifiedMarket) {
208
183
  unifiedMarkets.push(unifiedMarket);
209
184
  }
210
185
  }
211
-
212
186
  return unifiedMarkets;
213
-
214
- } catch (error: any) {
215
- if (axios.isAxiosError(error) && error.response) {
187
+ }
188
+ catch (error) {
189
+ if (axios_1.default.isAxiosError(error) && error.response) {
216
190
  if (error.response.status === 404) {
217
191
  throw new Error(`Kalshi event not found: "${eventTicker}". Check that the event ticker is correct.`);
218
192
  }
@@ -223,9 +197,8 @@ export class KalshiExchange extends PredictionMarketExchange {
223
197
  throw error;
224
198
  }
225
199
  }
226
-
227
- private mapIntervalToKalshi(interval: CandleInterval): number {
228
- const mapping: Record<CandleInterval, number> = {
200
+ mapIntervalToKalshi(interval) {
201
+ const mapping = {
229
202
  '1m': 1,
230
203
  '5m': 1,
231
204
  '15m': 1,
@@ -235,13 +208,11 @@ export class KalshiExchange extends PredictionMarketExchange {
235
208
  };
236
209
  return mapping[interval];
237
210
  }
238
-
239
- async getMarketHistory(id: string, params: HistoryFilterParams): Promise<PriceCandle[]> {
211
+ async getMarketHistory(id, params) {
240
212
  try {
241
213
  // Kalshi API expects uppercase tickers
242
214
  const normalizedId = id.toUpperCase();
243
215
  const interval = this.mapIntervalToKalshi(params.resolution);
244
-
245
216
  // Heuristic for series_ticker
246
217
  const parts = normalizedId.split('-');
247
218
  if (parts.length < 2) {
@@ -249,13 +220,10 @@ export class KalshiExchange extends PredictionMarketExchange {
249
220
  }
250
221
  const seriesTicker = parts.slice(0, -1).join('-');
251
222
  const url = `https://api.elections.kalshi.com/trade-api/v2/series/${seriesTicker}/markets/${normalizedId}/candlesticks`;
252
-
253
- const queryParams: any = { period_interval: interval };
254
-
223
+ const queryParams = { period_interval: interval };
255
224
  const now = Math.floor(Date.now() / 1000);
256
225
  let startTs = now - (24 * 60 * 60);
257
226
  let endTs = now;
258
-
259
227
  if (params.start) {
260
228
  startTs = Math.floor(params.start.getTime() / 1000);
261
229
  }
@@ -265,14 +233,11 @@ export class KalshiExchange extends PredictionMarketExchange {
265
233
  startTs = endTs - (24 * 60 * 60);
266
234
  }
267
235
  }
268
-
269
236
  queryParams.start_ts = startTs;
270
237
  queryParams.end_ts = endTs;
271
-
272
- const response = await axios.get(url, { params: queryParams });
238
+ const response = await axios_1.default.get(url, { params: queryParams });
273
239
  const candles = response.data.candlesticks || [];
274
-
275
- const mappedCandles: PriceCandle[] = candles.map((c: any) => ({
240
+ const mappedCandles = candles.map((c) => ({
276
241
  timestamp: c.end_period_ts * 1000,
277
242
  open: (c.price.open || 0) / 100,
278
243
  high: (c.price.high || 0) / 100,
@@ -280,13 +245,13 @@ export class KalshiExchange extends PredictionMarketExchange {
280
245
  close: (c.price.close || 0) / 100,
281
246
  volume: c.volume
282
247
  }));
283
-
284
248
  if (params.limit && mappedCandles.length > params.limit) {
285
249
  return mappedCandles.slice(-params.limit);
286
250
  }
287
251
  return mappedCandles;
288
- } catch (error: any) {
289
- if (axios.isAxiosError(error) && error.response) {
252
+ }
253
+ catch (error) {
254
+ if (axios_1.default.isAxiosError(error) && error.response) {
290
255
  const apiError = error.response.data?.error || error.response.data?.message || "Unknown API Error";
291
256
  throw new Error(`Kalshi History API Error (${error.response.status}): ${apiError}. Used Ticker: ${id}`);
292
257
  }
@@ -294,56 +259,52 @@ export class KalshiExchange extends PredictionMarketExchange {
294
259
  throw error;
295
260
  }
296
261
  }
297
-
298
- async getOrderBook(id: string): Promise<OrderBook> {
262
+ async getOrderBook(id) {
299
263
  try {
300
264
  const url = `https://api.elections.kalshi.com/trade-api/v2/markets/${id}/orderbook`;
301
- const response = await axios.get(url);
265
+ const response = await axios_1.default.get(url);
302
266
  const data = response.data.orderbook;
303
-
304
267
  // Structure: { yes: [[price, qty], ...], no: [[price, qty], ...] }
305
- const bids = (data.yes || []).map((level: number[]) => ({
268
+ const bids = (data.yes || []).map((level) => ({
306
269
  price: level[0] / 100,
307
270
  size: level[1]
308
271
  }));
309
-
310
- const asks = (data.no || []).map((level: number[]) => ({
272
+ const asks = (data.no || []).map((level) => ({
311
273
  price: (100 - level[0]) / 100,
312
274
  size: level[1]
313
275
  }));
314
-
315
276
  // Sort bids desc, asks asc
316
- bids.sort((a: any, b: any) => b.price - a.price);
317
- asks.sort((a: any, b: any) => a.price - b.price);
318
-
277
+ bids.sort((a, b) => b.price - a.price);
278
+ asks.sort((a, b) => a.price - b.price);
319
279
  return { bids, asks, timestamp: Date.now() };
320
- } catch (error) {
280
+ }
281
+ catch (error) {
321
282
  console.error(`Error fetching Kalshi orderbook for ${id}:`, error);
322
283
  return { bids: [], asks: [] };
323
284
  }
324
285
  }
325
-
326
- async getTradeHistory(id: string, params: HistoryFilterParams): Promise<Trade[]> {
286
+ async getTradeHistory(id, params) {
327
287
  try {
328
288
  const url = `https://api.elections.kalshi.com/trade-api/v2/markets/trades`;
329
- const response = await axios.get(url, {
289
+ const response = await axios_1.default.get(url, {
330
290
  params: {
331
291
  ticker: id,
332
292
  limit: params.limit || 100
333
293
  }
334
294
  });
335
295
  const trades = response.data.trades || [];
336
-
337
- return trades.map((t: any) => ({
296
+ return trades.map((t) => ({
338
297
  id: t.trade_id,
339
298
  timestamp: new Date(t.created_time).getTime(),
340
299
  price: t.yes_price / 100,
341
300
  amount: t.count,
342
301
  side: t.taker_side === 'yes' ? 'buy' : 'sell'
343
302
  }));
344
- } catch (error) {
303
+ }
304
+ catch (error) {
345
305
  console.error(`Error fetching Kalshi trades for ${id}:`, error);
346
306
  return [];
347
307
  }
348
308
  }
349
309
  }
310
+ exports.KalshiExchange = KalshiExchange;
@@ -0,0 +1,38 @@
1
+ import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams } from '../BaseExchange';
2
+ import { UnifiedMarket, PriceCandle, OrderBook, Trade } from '../types';
3
+ export declare class PolymarketExchange extends PredictionMarketExchange {
4
+ get name(): string;
5
+ private readonly baseUrl;
6
+ private readonly clobUrl;
7
+ fetchMarkets(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
8
+ searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]>;
9
+ /**
10
+ * Fetch specific markets by their URL slug.
11
+ * Useful for looking up a specific event from a URL.
12
+ * @param slug - The event slug (e.g. "will-fed-cut-rates-in-march")
13
+ */
14
+ getMarketsBySlug(slug: string): Promise<UnifiedMarket[]>;
15
+ /**
16
+ * Map our generic CandleInterval to Polymarket's fidelity (in minutes)
17
+ */
18
+ private mapIntervalToFidelity;
19
+ /**
20
+ * Fetch historical price data (OHLCV candles) for a specific token.
21
+ * @param id - The CLOB token ID (e.g., outcome token ID)
22
+ */
23
+ getMarketHistory(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
24
+ /**
25
+ * Fetch the current order book for a specific token.
26
+ * @param id - The CLOB token ID
27
+ */
28
+ getOrderBook(id: string): Promise<OrderBook>;
29
+ /**
30
+ * Fetch raw trade history for a specific token.
31
+ * @param id - The CLOB token ID
32
+ *
33
+ * NOTE: Polymarket's /trades endpoint currently requires L2 Authentication (API Key).
34
+ * This method will return an empty array if an API key is not provided in headers.
35
+ * Use getMarketHistory for public historical price data instead.
36
+ */
37
+ getTradeHistory(id: string, params: HistoryFilterParams): Promise<Trade[]>;
38
+ }