pmxt-core 2.6.0 → 2.8.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.
Files changed (63) hide show
  1. package/dist/BaseExchange.d.ts +14 -0
  2. package/dist/BaseExchange.js +76 -0
  3. package/dist/exchanges/kalshi/fetchEvents.d.ts +2 -1
  4. package/dist/exchanges/kalshi/fetchEvents.js +6 -6
  5. package/dist/exchanges/kalshi/fetchMarkets.d.ts +2 -1
  6. package/dist/exchanges/kalshi/fetchMarkets.js +22 -24
  7. package/dist/exchanges/kalshi/fetchOHLCV.d.ts +2 -1
  8. package/dist/exchanges/kalshi/fetchOHLCV.js +2 -2
  9. package/dist/exchanges/kalshi/fetchOrderBook.d.ts +2 -1
  10. package/dist/exchanges/kalshi/fetchOrderBook.js +2 -2
  11. package/dist/exchanges/kalshi/fetchTrades.d.ts +2 -1
  12. package/dist/exchanges/kalshi/fetchTrades.js +2 -2
  13. package/dist/exchanges/kalshi/index.js +11 -15
  14. package/dist/exchanges/kalshi/kalshi.test.js +47 -18
  15. package/dist/exchanges/limitless/fetchEvents.d.ts +2 -1
  16. package/dist/exchanges/limitless/fetchEvents.js +6 -4
  17. package/dist/exchanges/limitless/fetchMarkets.d.ts +2 -1
  18. package/dist/exchanges/limitless/fetchMarkets.js +7 -7
  19. package/dist/exchanges/limitless/fetchOHLCV.d.ts +2 -1
  20. package/dist/exchanges/limitless/fetchOHLCV.js +2 -2
  21. package/dist/exchanges/limitless/fetchOrderBook.d.ts +2 -1
  22. package/dist/exchanges/limitless/fetchOrderBook.js +2 -2
  23. package/dist/exchanges/limitless/fetchTrades.d.ts +2 -1
  24. package/dist/exchanges/limitless/fetchTrades.js +5 -1
  25. package/dist/exchanges/limitless/index.js +5 -5
  26. package/dist/exchanges/myriad/fetchEvents.d.ts +2 -1
  27. package/dist/exchanges/myriad/fetchEvents.js +6 -6
  28. package/dist/exchanges/myriad/fetchMarkets.d.ts +2 -1
  29. package/dist/exchanges/myriad/fetchMarkets.js +10 -10
  30. package/dist/exchanges/myriad/fetchOHLCV.d.ts +2 -1
  31. package/dist/exchanges/myriad/fetchOHLCV.js +2 -2
  32. package/dist/exchanges/myriad/fetchOrderBook.d.ts +2 -1
  33. package/dist/exchanges/myriad/fetchOrderBook.js +2 -2
  34. package/dist/exchanges/myriad/fetchTrades.d.ts +2 -1
  35. package/dist/exchanges/myriad/fetchTrades.js +2 -2
  36. package/dist/exchanges/myriad/index.js +8 -12
  37. package/dist/exchanges/polymarket/fetchEvents.d.ts +2 -1
  38. package/dist/exchanges/polymarket/fetchEvents.js +8 -8
  39. package/dist/exchanges/polymarket/fetchMarkets.d.ts +2 -1
  40. package/dist/exchanges/polymarket/fetchMarkets.js +19 -19
  41. package/dist/exchanges/polymarket/fetchOHLCV.d.ts +2 -1
  42. package/dist/exchanges/polymarket/fetchOHLCV.js +2 -2
  43. package/dist/exchanges/polymarket/fetchOrderBook.d.ts +2 -1
  44. package/dist/exchanges/polymarket/fetchOrderBook.js +2 -2
  45. package/dist/exchanges/polymarket/fetchTrades.d.ts +2 -1
  46. package/dist/exchanges/polymarket/fetchTrades.js +2 -2
  47. package/dist/exchanges/polymarket/index.js +5 -5
  48. package/dist/exchanges/polymarket/utils.d.ts +2 -2
  49. package/dist/exchanges/polymarket/utils.js +7 -42
  50. package/dist/exchanges/probable/fetchEvents.d.ts +4 -3
  51. package/dist/exchanges/probable/fetchEvents.js +13 -13
  52. package/dist/exchanges/probable/fetchMarkets.d.ts +2 -1
  53. package/dist/exchanges/probable/fetchMarkets.js +16 -16
  54. package/dist/exchanges/probable/fetchOHLCV.d.ts +2 -1
  55. package/dist/exchanges/probable/fetchOHLCV.js +2 -2
  56. package/dist/exchanges/probable/fetchOrderBook.d.ts +2 -1
  57. package/dist/exchanges/probable/fetchOrderBook.js +2 -2
  58. package/dist/exchanges/probable/fetchTrades.d.ts +2 -2
  59. package/dist/exchanges/probable/fetchTrades.js +5 -1
  60. package/dist/exchanges/probable/index.js +7 -7
  61. package/dist/server/app.js +9 -0
  62. package/dist/types.d.ts +1 -0
  63. package/package.json +4 -4
@@ -1,5 +1,6 @@
1
1
  import { UnifiedMarket, UnifiedEvent, PriceCandle, CandleInterval, OrderBook, Trade, Order, Position, Balance, CreateOrderParams } from './types';
2
2
  import { ExecutionPriceResult } from './utils/math';
3
+ import { AxiosInstance } from 'axios';
3
4
  export interface MarketFilterParams {
4
5
  limit?: number;
5
6
  offset?: number;
@@ -120,9 +121,22 @@ export interface ExchangeCredentials {
120
121
  }
121
122
  export declare abstract class PredictionMarketExchange {
122
123
  protected credentials?: ExchangeCredentials;
124
+ verbose: boolean;
125
+ http: AxiosInstance;
126
+ markets: Record<string, UnifiedMarket>;
127
+ marketsBySlug: Record<string, UnifiedMarket>;
128
+ loadedMarkets: boolean;
123
129
  readonly has: ExchangeHas;
124
130
  constructor(credentials?: ExchangeCredentials);
125
131
  abstract get name(): string;
132
+ /**
133
+ * Load and cache markets from the exchange.
134
+ * This method populates `this.markets` and `this.marketsBySlug`.
135
+ *
136
+ * @param reload - Force a reload of markets from the API even if already loaded
137
+ * @returns Dictionary of markets indexed by marketId
138
+ */
139
+ loadMarkets(reload?: boolean): Promise<Record<string, UnifiedMarket>>;
126
140
  /**
127
141
  * Fetch markets with optional filtering, search, or slug lookup.
128
142
  * This is the primary method for retrieving markets.
@@ -1,13 +1,23 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.PredictionMarketExchange = void 0;
4
7
  const math_1 = require("./utils/math");
5
8
  const errors_1 = require("./errors");
9
+ const axios_1 = __importDefault(require("axios"));
6
10
  // ----------------------------------------------------------------------------
7
11
  // Base Exchange Class
8
12
  // ----------------------------------------------------------------------------
9
13
  class PredictionMarketExchange {
10
14
  credentials;
15
+ verbose = false;
16
+ http;
17
+ // Market Cache
18
+ markets = {};
19
+ marketsBySlug = {};
20
+ loadedMarkets = false;
11
21
  has = {
12
22
  fetchMarkets: false,
13
23
  fetchEvents: false,
@@ -25,6 +35,63 @@ class PredictionMarketExchange {
25
35
  };
26
36
  constructor(credentials) {
27
37
  this.credentials = credentials;
38
+ this.http = axios_1.default.create();
39
+ // Request Interceptor
40
+ this.http.interceptors.request.use((config) => {
41
+ if (this.verbose) {
42
+ console.log(`\n[pmxt] → ${config.method?.toUpperCase()} ${config.url}`);
43
+ if (config.params)
44
+ console.log('[pmxt] params:', config.params);
45
+ if (config.data)
46
+ console.log('[pmxt] body:', JSON.stringify(config.data, null, 2));
47
+ }
48
+ return config;
49
+ });
50
+ // Response Interceptor
51
+ this.http.interceptors.response.use((response) => {
52
+ if (this.verbose) {
53
+ console.log(`\n[pmxt] ← ${response.status} ${response.statusText} ${response.config.url}`);
54
+ // console.log('[pmxt] response:', JSON.stringify(response.data, null, 2));
55
+ // Commented out full body log to avoid spam, but headers might be useful
56
+ }
57
+ return response;
58
+ }, (error) => {
59
+ if (this.verbose) {
60
+ console.log(`\n[pmxt] ✖ REQUEST FAILED: ${error.config?.url}`);
61
+ console.log('[pmxt] error:', error.message);
62
+ if (error.response) {
63
+ console.log('[pmxt] status:', error.response.status);
64
+ console.log('[pmxt] data:', JSON.stringify(error.response.data, null, 2));
65
+ }
66
+ }
67
+ return Promise.reject(error);
68
+ });
69
+ }
70
+ /**
71
+ * Load and cache markets from the exchange.
72
+ * This method populates `this.markets` and `this.marketsBySlug`.
73
+ *
74
+ * @param reload - Force a reload of markets from the API even if already loaded
75
+ * @returns Dictionary of markets indexed by marketId
76
+ */
77
+ async loadMarkets(reload = false) {
78
+ if (this.loadedMarkets && !reload) {
79
+ return this.markets;
80
+ }
81
+ // Fetch all markets (implementation dependent, usually fetches active markets)
82
+ const markets = await this.fetchMarkets();
83
+ // Reset caches
84
+ this.markets = {};
85
+ this.marketsBySlug = {};
86
+ for (const market of markets) {
87
+ this.markets[market.marketId] = market;
88
+ // Some exchanges provide slugs, if so cache them
89
+ if (market.slug) {
90
+ this.marketsBySlug[market.slug] = market;
91
+ }
92
+ }
93
+ this.loadedMarkets = true;
94
+ return this.markets;
28
95
  }
29
96
  /**
30
97
  * Fetch markets with optional filtering, search, or slug lookup.
@@ -105,6 +172,15 @@ class PredictionMarketExchange {
105
172
  * market = exchange.fetch_market(market_id='663583')
106
173
  */
107
174
  async fetchMarket(params) {
175
+ // Try to fetch from cache first if we have loaded markets and have an ID/slug
176
+ if (this.loadedMarkets) {
177
+ if (params?.marketId && this.markets[params.marketId]) {
178
+ return this.markets[params.marketId];
179
+ }
180
+ if (params?.slug && this.marketsBySlug[params.slug]) {
181
+ return this.marketsBySlug[params.slug];
182
+ }
183
+ }
108
184
  const markets = await this.fetchMarkets(params);
109
185
  if (markets.length === 0) {
110
186
  const identifier = params?.marketId || params?.outcomeId || params?.slug || params?.eventId || params?.query || 'unknown';
@@ -1,3 +1,4 @@
1
1
  import { EventFetchParams } from '../../BaseExchange';
2
2
  import { UnifiedEvent } from '../../types';
3
- export declare function fetchEvents(params: EventFetchParams): Promise<UnifiedEvent[]>;
3
+ import { AxiosInstance } from 'axios';
4
+ export declare function fetchEvents(params: EventFetchParams, http?: AxiosInstance): Promise<UnifiedEvent[]>;
@@ -7,10 +7,10 @@ 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
- async function fetchEventByTicker(eventTicker) {
10
+ async function fetchEventByTicker(eventTicker, http) {
11
11
  const normalizedTicker = eventTicker.toUpperCase();
12
12
  const url = `https://api.elections.kalshi.com/trade-api/v2/events/${normalizedTicker}`;
13
- const response = await axios_1.default.get(url, {
13
+ const response = await http.get(url, {
14
14
  params: { with_nested_markets: true }
15
15
  });
16
16
  const event = response.data.event;
@@ -38,15 +38,15 @@ async function fetchEventByTicker(eventTicker) {
38
38
  };
39
39
  return [unifiedEvent];
40
40
  }
41
- async function fetchEvents(params) {
41
+ async function fetchEvents(params, http = axios_1.default) {
42
42
  try {
43
43
  // Handle eventId lookup (direct API call)
44
44
  if (params.eventId) {
45
- return await fetchEventByTicker(params.eventId);
45
+ return await fetchEventByTicker(params.eventId, http);
46
46
  }
47
47
  // Handle slug lookup (slug IS the event ticker on Kalshi)
48
48
  if (params.slug) {
49
- return await fetchEventByTicker(params.slug);
49
+ return await fetchEventByTicker(params.slug, http);
50
50
  }
51
51
  const status = params?.status || 'active';
52
52
  const limit = params?.limit || 10000;
@@ -65,7 +65,7 @@ async function fetchEvents(params) {
65
65
  };
66
66
  if (cursor)
67
67
  queryParams.cursor = cursor;
68
- const response = await axios_1.default.get(utils_1.KALSHI_API_URL, { params: queryParams });
68
+ const response = await http.get(utils_1.KALSHI_API_URL, { params: queryParams });
69
69
  const events = response.data.events || [];
70
70
  if (events.length === 0)
71
71
  break;
@@ -1,4 +1,5 @@
1
+ import { AxiosInstance } from 'axios';
1
2
  import { MarketFetchParams } from '../../BaseExchange';
2
3
  import { UnifiedMarket } from '../../types';
3
4
  export declare function resetCache(): void;
4
- export declare function fetchMarkets(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
5
+ export declare function fetchMarkets(params?: MarketFetchParams, http?: AxiosInstance): Promise<UnifiedMarket[]>;
@@ -8,7 +8,7 @@ exports.fetchMarkets = fetchMarkets;
8
8
  const axios_1 = __importDefault(require("axios"));
9
9
  const utils_1 = require("./utils");
10
10
  const errors_1 = require("./errors");
11
- async function fetchActiveEvents(targetMarketCount, status = 'open') {
11
+ async function fetchActiveEvents(http, targetMarketCount, status = 'open') {
12
12
  let allEvents = [];
13
13
  let totalMarketCount = 0;
14
14
  let cursor = null;
@@ -27,7 +27,7 @@ async function fetchActiveEvents(targetMarketCount, status = 'open') {
27
27
  };
28
28
  if (cursor)
29
29
  queryParams.cursor = cursor;
30
- const response = await axios_1.default.get(utils_1.KALSHI_API_URL, { params: queryParams });
30
+ const response = await http.get(utils_1.KALSHI_API_URL, { params: queryParams });
31
31
  const events = response.data.events || [];
32
32
  if (events.length === 0)
33
33
  break;
@@ -56,9 +56,9 @@ async function fetchActiveEvents(targetMarketCount, status = 'open') {
56
56
  } while (cursor && page < MAX_PAGES);
57
57
  return allEvents;
58
58
  }
59
- async function fetchSeriesMap() {
59
+ async function fetchSeriesMap(http) {
60
60
  try {
61
- const response = await axios_1.default.get(utils_1.KALSHI_SERIES_URL);
61
+ const response = await http.get(utils_1.KALSHI_SERIES_URL);
62
62
  const seriesList = response.data.series || [];
63
63
  const map = new Map();
64
64
  for (const series of seriesList) {
@@ -83,41 +83,41 @@ function resetCache() {
83
83
  cachedSeriesMap = null;
84
84
  lastCacheTime = 0;
85
85
  }
86
- async function fetchMarkets(params) {
86
+ async function fetchMarkets(params, http = axios_1.default) {
87
87
  try {
88
88
  // Handle marketId lookup (Kalshi marketId is the ticker)
89
89
  if (params?.marketId) {
90
- return await fetchMarketsBySlug(params.marketId);
90
+ return await fetchMarketsBySlug(params.marketId, http);
91
91
  }
92
92
  // Handle slug-based lookup (event ticker)
93
93
  if (params?.slug) {
94
- return await fetchMarketsBySlug(params.slug);
94
+ return await fetchMarketsBySlug(params.slug, http);
95
95
  }
96
96
  // Handle outcomeId lookup (strip -NO suffix, use as ticker)
97
97
  if (params?.outcomeId) {
98
98
  const ticker = params.outcomeId.replace(/-NO$/, '');
99
- return await fetchMarketsBySlug(ticker);
99
+ return await fetchMarketsBySlug(ticker, http);
100
100
  }
101
101
  // Handle eventId lookup (event ticker works the same way)
102
102
  if (params?.eventId) {
103
- return await fetchMarketsBySlug(params.eventId);
103
+ return await fetchMarketsBySlug(params.eventId, http);
104
104
  }
105
105
  // Handle query-based search
106
106
  if (params?.query) {
107
- return await searchMarkets(params.query, params);
107
+ return await searchMarkets(params.query, params, http);
108
108
  }
109
109
  // Default: fetch markets
110
- return await fetchMarketsDefault(params);
110
+ return await fetchMarketsDefault(params, http);
111
111
  }
112
112
  catch (error) {
113
113
  throw errors_1.kalshiErrorMapper.mapError(error);
114
114
  }
115
115
  }
116
- async function fetchMarketsBySlug(eventTicker) {
116
+ async function fetchMarketsBySlug(eventTicker, http) {
117
117
  // Kalshi API expects uppercase tickers, but URLs use lowercase
118
118
  const normalizedTicker = eventTicker.toUpperCase();
119
119
  const url = `https://api.elections.kalshi.com/trade-api/v2/events/${normalizedTicker}`;
120
- const response = await axios_1.default.get(url, {
120
+ const response = await http.get(url, {
121
121
  params: { with_nested_markets: true }
122
122
  });
123
123
  const event = response.data.event;
@@ -127,7 +127,7 @@ async function fetchMarketsBySlug(eventTicker) {
127
127
  if (event.series_ticker) {
128
128
  try {
129
129
  const seriesUrl = `${utils_1.KALSHI_SERIES_URL}/${event.series_ticker}`;
130
- const seriesResponse = await axios_1.default.get(seriesUrl);
130
+ const seriesResponse = await http.get(seriesUrl);
131
131
  const series = seriesResponse.data.series;
132
132
  if (series && series.tags && series.tags.length > 0) {
133
133
  if (!event.tags || event.tags.length === 0) {
@@ -149,10 +149,10 @@ async function fetchMarketsBySlug(eventTicker) {
149
149
  }
150
150
  return unifiedMarkets;
151
151
  }
152
- async function searchMarkets(query, params) {
152
+ async function searchMarkets(query, params, http) {
153
153
  // We must fetch ALL markets to search them locally since we don't have server-side search
154
- const searchLimit = 10000;
155
- const markets = await fetchMarketsDefault({ ...params, limit: searchLimit });
154
+ const searchLimit = 250000;
155
+ const markets = await fetchMarketsDefault({ ...params, limit: searchLimit }, http);
156
156
  const lowerQuery = query.toLowerCase();
157
157
  const searchIn = params?.searchIn || 'title'; // Default to title-only search
158
158
  const filtered = markets.filter(market => {
@@ -164,11 +164,11 @@ async function searchMarkets(query, params) {
164
164
  return descMatch;
165
165
  return titleMatch || descMatch; // 'both'
166
166
  });
167
- const limit = params?.limit || 10000;
167
+ const limit = params?.limit || 250000;
168
168
  return filtered.slice(0, limit);
169
169
  }
170
- async function fetchMarketsDefault(params) {
171
- const limit = params?.limit || 10000;
170
+ async function fetchMarketsDefault(params, http) {
171
+ const limit = params?.limit || 250000;
172
172
  const offset = params?.offset || 0;
173
173
  const now = Date.now();
174
174
  const status = params?.status || 'active'; // Default to 'active'
@@ -196,13 +196,11 @@ async function fetchMarketsDefault(params) {
196
196
  const isSorted = params?.sort && (params.sort === 'volume' || params.sort === 'liquidity');
197
197
  const fetchLimit = isSorted ? 1000 : limit;
198
198
  const [allEvents, fetchedSeriesMap] = await Promise.all([
199
- fetchActiveEvents(fetchLimit, apiStatus),
200
- fetchSeriesMap()
199
+ fetchActiveEvents(http, fetchLimit, apiStatus),
200
+ fetchSeriesMap(http)
201
201
  ]);
202
202
  events = allEvents;
203
203
  seriesMap = fetchedSeriesMap;
204
- events = allEvents;
205
- seriesMap = fetchedSeriesMap;
206
204
  // Cache the dataset ONLY if:
207
205
  // 1. We fetched a comprehensive set (>= 1000)
208
206
  // 2. It's the standard 'open' status query
@@ -1,3 +1,4 @@
1
+ import { AxiosInstance } from 'axios';
1
2
  import { HistoryFilterParams, OHLCVParams } from '../../BaseExchange';
2
3
  import { PriceCandle } from '../../types';
3
- export declare function fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams): Promise<PriceCandle[]>;
4
+ export declare function fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams, http?: AxiosInstance): Promise<PriceCandle[]>;
@@ -8,7 +8,7 @@ const axios_1 = __importDefault(require("axios"));
8
8
  const utils_1 = require("./utils");
9
9
  const validation_1 = require("../../utils/validation");
10
10
  const errors_1 = require("./errors");
11
- async function fetchOHLCV(id, params) {
11
+ async function fetchOHLCV(id, params, http = axios_1.default) {
12
12
  (0, validation_1.validateIdFormat)(id, 'OHLCV');
13
13
  // Validate resolution is provided
14
14
  if (!params.resolution) {
@@ -57,7 +57,7 @@ async function fetchOHLCV(id, params) {
57
57
  }
58
58
  queryParams.start_ts = startTs;
59
59
  queryParams.end_ts = endTs;
60
- const response = await axios_1.default.get(url, { params: queryParams });
60
+ const response = await http.get(url, { params: queryParams });
61
61
  const candles = response.data.candlesticks || [];
62
62
  const mappedCandles = candles.map((c) => {
63
63
  // Priority:
@@ -1,2 +1,3 @@
1
+ import { AxiosInstance } from 'axios';
1
2
  import { OrderBook } from '../../types';
2
- export declare function fetchOrderBook(id: string): Promise<OrderBook>;
3
+ export declare function fetchOrderBook(id: string, http?: AxiosInstance): Promise<OrderBook>;
@@ -7,14 +7,14 @@ exports.fetchOrderBook = fetchOrderBook;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const validation_1 = require("../../utils/validation");
9
9
  const errors_1 = require("./errors");
10
- async function fetchOrderBook(id) {
10
+ async function fetchOrderBook(id, http = axios_1.default) {
11
11
  (0, validation_1.validateIdFormat)(id, 'OrderBook');
12
12
  try {
13
13
  // Check if this is a NO outcome request
14
14
  const isNoOutcome = id.endsWith('-NO');
15
15
  const ticker = id.replace(/-NO$/, '');
16
16
  const url = `https://api.elections.kalshi.com/trade-api/v2/markets/${ticker}/orderbook`;
17
- const response = await axios_1.default.get(url);
17
+ const response = await http.get(url);
18
18
  const data = response.data.orderbook;
19
19
  // Structure: { yes: [[price, qty], ...], no: [[price, qty], ...] }
20
20
  // Kalshi returns bids at their actual prices (not inverted)
@@ -1,3 +1,4 @@
1
+ import { AxiosInstance } from 'axios';
1
2
  import { HistoryFilterParams, TradesParams } from '../../BaseExchange';
2
3
  import { Trade } from '../../types';
3
- export declare function fetchTrades(id: string, params: TradesParams | HistoryFilterParams): Promise<Trade[]>;
4
+ export declare function fetchTrades(id: string, params: TradesParams | HistoryFilterParams, http?: AxiosInstance): Promise<Trade[]>;
@@ -6,11 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.fetchTrades = fetchTrades;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const errors_1 = require("./errors");
9
- async function fetchTrades(id, params) {
9
+ async function fetchTrades(id, params, http = axios_1.default) {
10
10
  try {
11
11
  const ticker = id.replace(/-NO$/, '');
12
12
  const url = `https://api.elections.kalshi.com/trade-api/v2/markets/trades`;
13
- const response = await axios_1.default.get(url, {
13
+ const response = await http.get(url, {
14
14
  params: {
15
15
  ticker: ticker,
16
16
  limit: params.limit || 100
@@ -1,10 +1,6 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.KalshiExchange = void 0;
7
- const axios_1 = __importDefault(require("axios"));
8
4
  const BaseExchange_1 = require("../../BaseExchange");
9
5
  const fetchMarkets_1 = require("./fetchMarkets");
10
6
  const fetchEvents_1 = require("./fetchEvents");
@@ -72,16 +68,16 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
72
68
  // Market Data Methods - Implementation for CCXT-style API
73
69
  // ----------------------------------------------------------------------------
74
70
  async fetchMarketsImpl(params) {
75
- return (0, fetchMarkets_1.fetchMarkets)(params);
71
+ return (0, fetchMarkets_1.fetchMarkets)(params, this.http);
76
72
  }
77
73
  async fetchEventsImpl(params) {
78
- return (0, fetchEvents_1.fetchEvents)(params);
74
+ return (0, fetchEvents_1.fetchEvents)(params, this.http);
79
75
  }
80
76
  async fetchOHLCV(id, params) {
81
- return (0, fetchOHLCV_1.fetchOHLCV)(id, params);
77
+ return (0, fetchOHLCV_1.fetchOHLCV)(id, params, this.http);
82
78
  }
83
79
  async fetchOrderBook(id) {
84
- return (0, fetchOrderBook_1.fetchOrderBook)(id);
80
+ return (0, fetchOrderBook_1.fetchOrderBook)(id, this.http);
85
81
  }
86
82
  async fetchTrades(id, params) {
87
83
  // Deprecation warning
@@ -89,7 +85,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
89
85
  console.warn('[pmxt] Warning: The "resolution" parameter is deprecated for fetchTrades() and will be ignored. ' +
90
86
  'It will be removed in v3.0.0. Please remove it from your code.');
91
87
  }
92
- return (0, fetchTrades_1.fetchTrades)(id, params);
88
+ return (0, fetchTrades_1.fetchTrades)(id, params, this.http);
93
89
  }
94
90
  // ----------------------------------------------------------------------------
95
91
  // User Data Methods
@@ -103,7 +99,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
103
99
  // TODO: Make base URL configurable in credentials
104
100
  const baseUrl = this.getBaseUrl();
105
101
  const headers = auth.getHeaders('GET', path);
106
- const response = await axios_1.default.get(`${baseUrl}${path}`, { headers });
102
+ const response = await this.http.get(`${baseUrl}${path}`, { headers });
107
103
  // Kalshi response structure:
108
104
  // - balance: Available balance in cents (for trading)
109
105
  // - portfolio_value: Total portfolio value in cents (includes positions)
@@ -154,7 +150,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
154
150
  kalshiOrder.no_price = priceInCents;
155
151
  }
156
152
  }
157
- const response = await axios_1.default.post(`${baseUrl}${path}`, kalshiOrder, { headers });
153
+ const response = await this.http.post(`${baseUrl}${path}`, kalshiOrder, { headers });
158
154
  const order = response.data.order;
159
155
  return {
160
156
  id: order.order_id,
@@ -180,7 +176,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
180
176
  const path = `/trade-api/v2/portfolio/orders/${orderId}`;
181
177
  const baseUrl = this.getBaseUrl();
182
178
  const headers = auth.getHeaders('DELETE', path);
183
- const response = await axios_1.default.delete(`${baseUrl}${path}`, { headers });
179
+ const response = await this.http.delete(`${baseUrl}${path}`, { headers });
184
180
  const order = response.data.order;
185
181
  return {
186
182
  id: order.order_id,
@@ -205,7 +201,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
205
201
  const path = `/trade-api/v2/portfolio/orders/${orderId}`;
206
202
  const baseUrl = this.getBaseUrl();
207
203
  const headers = auth.getHeaders('GET', path);
208
- const response = await axios_1.default.get(`${baseUrl}${path}`, { headers });
204
+ const response = await this.http.get(`${baseUrl}${path}`, { headers });
209
205
  const order = response.data.order;
210
206
  return {
211
207
  id: order.order_id,
@@ -237,7 +233,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
237
233
  const baseUrl = this.getBaseUrl();
238
234
  // Sign only the base path, not the query parameters
239
235
  const headers = auth.getHeaders('GET', basePath);
240
- const response = await axios_1.default.get(`${baseUrl}${basePath}${queryParams}`, { headers });
236
+ const response = await this.http.get(`${baseUrl}${basePath}${queryParams}`, { headers });
241
237
  const orders = response.data.orders || [];
242
238
  return orders.map((order) => ({
243
239
  id: order.order_id,
@@ -263,7 +259,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
263
259
  const path = '/trade-api/v2/portfolio/positions';
264
260
  const baseUrl = this.getBaseUrl();
265
261
  const headers = auth.getHeaders('GET', path);
266
- const response = await axios_1.default.get(`${baseUrl}${path}`, { headers });
262
+ const response = await this.http.get(`${baseUrl}${path}`, { headers });
267
263
  const positions = response.data.market_positions || [];
268
264
  return positions.map((pos) => {
269
265
  const absPosition = Math.abs(pos.position);
@@ -6,8 +6,33 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const kalshi_1 = require("../kalshi");
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const auth_1 = require("./auth");
9
- // Mock axios
10
- jest.mock('axios');
9
+ // Jest hoisting means we can't use outer variables in jest.mock factory
10
+ // unless they start with 'mock'. However, let's just define it inline to be safe and simple.
11
+ // To access the inner methods, we'll grab the instance returned by axios.create().
12
+ jest.mock('axios', () => {
13
+ const mockInstance = {
14
+ interceptors: {
15
+ request: { use: jest.fn() },
16
+ response: { use: jest.fn() },
17
+ },
18
+ get: jest.fn(),
19
+ post: jest.fn(),
20
+ delete: jest.fn(),
21
+ defaults: { headers: { common: {} } },
22
+ };
23
+ const mockAxios = {
24
+ create: jest.fn(() => mockInstance),
25
+ };
26
+ // Support both default and named exports
27
+ return {
28
+ __esModule: true,
29
+ ...mockAxios,
30
+ default: mockAxios,
31
+ };
32
+ });
33
+ // Access the mocked instance for assertions
34
+ // Since our factory returns the same object reference, this works.
35
+ const mockAxiosInstance = axios_1.default.create();
11
36
  const mockedAxios = axios_1.default;
12
37
  // Mock KalshiAuth
13
38
  jest.mock('./auth');
@@ -20,6 +45,10 @@ describe('KalshiExchange', () => {
20
45
  };
21
46
  beforeEach(() => {
22
47
  jest.clearAllMocks();
48
+ // Reset the mock instance methods to ensure clean state
49
+ mockAxiosInstance.get.mockReset();
50
+ mockAxiosInstance.post.mockReset();
51
+ mockAxiosInstance.delete.mockReset();
23
52
  // Mock the getHeaders method
24
53
  MockedKalshiAuth.prototype.getHeaders = jest.fn().mockReturnValue({
25
54
  'KALSHI-ACCESS-KEY': 'test-api-key',
@@ -56,7 +85,7 @@ describe('KalshiExchange', () => {
56
85
  ]
57
86
  }
58
87
  };
59
- mockedAxios.get.mockResolvedValue(mockResponse);
88
+ mockAxiosInstance.get.mockResolvedValue(mockResponse);
60
89
  const markets = await exchange.fetchMarkets();
61
90
  expect(markets).toBeDefined();
62
91
  });
@@ -88,9 +117,9 @@ describe('KalshiExchange', () => {
88
117
  }
89
118
  }
90
119
  };
91
- mockedAxios.post.mockResolvedValue(mockResponse);
120
+ mockAxiosInstance.post.mockResolvedValue(mockResponse);
92
121
  const order = await exchange.createOrder(orderParams);
93
- expect(mockedAxios.post).toHaveBeenCalledWith('https://api.elections.kalshi.com/trade-api/v2/portfolio/orders', expect.objectContaining({
122
+ expect(mockAxiosInstance.post).toHaveBeenCalledWith('https://api.elections.kalshi.com/trade-api/v2/portfolio/orders', expect.objectContaining({
94
123
  ticker: 'TEST-MARKET',
95
124
  side: 'yes',
96
125
  action: 'buy',
@@ -123,9 +152,9 @@ describe('KalshiExchange', () => {
123
152
  }
124
153
  }
125
154
  };
126
- mockedAxios.post.mockResolvedValue(mockResponse);
155
+ mockAxiosInstance.post.mockResolvedValue(mockResponse);
127
156
  await exchange.createOrder(orderParams);
128
- expect(mockedAxios.post).toHaveBeenCalledWith('https://api.elections.kalshi.com/trade-api/v2/portfolio/orders', expect.objectContaining({
157
+ expect(mockAxiosInstance.post).toHaveBeenCalledWith('https://api.elections.kalshi.com/trade-api/v2/portfolio/orders', expect.objectContaining({
129
158
  ticker: 'TEST-MARKET',
130
159
  side: 'no',
131
160
  action: 'sell',
@@ -153,18 +182,18 @@ describe('KalshiExchange', () => {
153
182
  ]
154
183
  }
155
184
  };
156
- mockedAxios.get.mockResolvedValue(mockResponse);
185
+ mockAxiosInstance.get.mockResolvedValue(mockResponse);
157
186
  await exchange.fetchOpenOrders();
158
187
  // Verify the request URL includes query params
159
- expect(mockedAxios.get).toHaveBeenCalledWith('https://api.elections.kalshi.com/trade-api/v2/portfolio/orders?status=resting', expect.any(Object));
188
+ expect(mockAxiosInstance.get).toHaveBeenCalledWith('https://api.elections.kalshi.com/trade-api/v2/portfolio/orders?status=resting', expect.any(Object));
160
189
  // Verify getHeaders was called with base path only (no query params)
161
190
  expect(MockedKalshiAuth.prototype.getHeaders).toHaveBeenCalledWith('GET', '/trade-api/v2/portfolio/orders');
162
191
  });
163
192
  it('should include ticker in query params when marketId provided', async () => {
164
193
  const mockResponse = { data: { orders: [] } };
165
- mockedAxios.get.mockResolvedValue(mockResponse);
194
+ mockAxiosInstance.get.mockResolvedValue(mockResponse);
166
195
  await exchange.fetchOpenOrders('TEST-MARKET');
167
- expect(mockedAxios.get).toHaveBeenCalledWith('https://api.elections.kalshi.com/trade-api/v2/portfolio/orders?status=resting&ticker=TEST-MARKET', expect.any(Object));
196
+ expect(mockAxiosInstance.get).toHaveBeenCalledWith('https://api.elections.kalshi.com/trade-api/v2/portfolio/orders?status=resting&ticker=TEST-MARKET', expect.any(Object));
168
197
  });
169
198
  });
170
199
  describe('fetchPositions', () => {
@@ -182,7 +211,7 @@ describe('KalshiExchange', () => {
182
211
  ]
183
212
  }
184
213
  };
185
- mockedAxios.get.mockResolvedValue(mockResponse);
214
+ mockAxiosInstance.get.mockResolvedValue(mockResponse);
186
215
  const positions = await exchange.fetchPositions();
187
216
  expect(positions).toHaveLength(1);
188
217
  expect(positions[0].size).toBe(0);
@@ -202,7 +231,7 @@ describe('KalshiExchange', () => {
202
231
  ]
203
232
  }
204
233
  };
205
- mockedAxios.get.mockResolvedValue(mockResponse);
234
+ mockAxiosInstance.get.mockResolvedValue(mockResponse);
206
235
  const positions = await exchange.fetchPositions();
207
236
  expect(positions).toHaveLength(1);
208
237
  expect(positions[0].size).toBe(10);
@@ -224,7 +253,7 @@ describe('KalshiExchange', () => {
224
253
  ]
225
254
  }
226
255
  };
227
- mockedAxios.get.mockResolvedValue(mockResponse);
256
+ mockAxiosInstance.get.mockResolvedValue(mockResponse);
228
257
  const positions = await exchange.fetchPositions();
229
258
  expect(positions[0].size).toBe(-5); // Negative for short
230
259
  expect(Math.abs(positions[0].size)).toBe(5); // Absolute value
@@ -238,7 +267,7 @@ describe('KalshiExchange', () => {
238
267
  portfolio_value: 15000 // $150.00 total
239
268
  }
240
269
  };
241
- mockedAxios.get.mockResolvedValue(mockResponse);
270
+ mockAxiosInstance.get.mockResolvedValue(mockResponse);
242
271
  const balances = await exchange.fetchBalance();
243
272
  expect(balances).toHaveLength(1);
244
273
  expect(balances[0].currency).toBe('USD');
@@ -261,7 +290,7 @@ describe('KalshiExchange', () => {
261
290
  }
262
291
  }
263
292
  };
264
- mockedAxios.delete.mockResolvedValue(mockResponse);
293
+ mockAxiosInstance.delete.mockResolvedValue(mockResponse);
265
294
  const order = await exchange.cancelOrder('order-123');
266
295
  expect(order.status).toBe('cancelled');
267
296
  expect(order.filled).toBe(5); // count - remaining_count
@@ -285,7 +314,7 @@ describe('KalshiExchange', () => {
285
314
  }
286
315
  }
287
316
  };
288
- mockedAxios.get.mockResolvedValue(mockResponse);
317
+ mockAxiosInstance.get.mockResolvedValue(mockResponse);
289
318
  const order = await exchange.fetchOrder('order-123');
290
319
  expect(order.status).toBe('open');
291
320
  });
@@ -301,7 +330,7 @@ describe('KalshiExchange', () => {
301
330
  }
302
331
  }
303
332
  };
304
- mockedAxios.get.mockResolvedValue(mockResponse);
333
+ mockAxiosInstance.get.mockResolvedValue(mockResponse);
305
334
  const order = await exchange.fetchOrder('order-123');
306
335
  expect(order.status).toBe('filled');
307
336
  });