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.
- package/dist/BaseExchange.d.ts +118 -4
- package/dist/BaseExchange.js +160 -7
- package/dist/exchanges/baozi/fetchEvents.js +16 -11
- package/dist/exchanges/baozi/index.d.ts +5 -0
- package/dist/exchanges/baozi/index.js +6 -0
- package/dist/exchanges/kalshi/api.d.ts +7 -1
- package/dist/exchanges/kalshi/api.js +11 -2
- package/dist/exchanges/kalshi/config.d.ts +103 -0
- package/dist/exchanges/kalshi/config.js +144 -0
- package/dist/exchanges/kalshi/fetchEvents.d.ts +2 -2
- package/dist/exchanges/kalshi/fetchEvents.js +138 -67
- package/dist/exchanges/kalshi/fetchMarkets.d.ts +2 -2
- package/dist/exchanges/kalshi/fetchMarkets.js +36 -25
- package/dist/exchanges/kalshi/fetchOHLCV.d.ts +3 -3
- package/dist/exchanges/kalshi/fetchOHLCV.js +20 -17
- package/dist/exchanges/kalshi/fetchOrderBook.d.ts +2 -0
- package/dist/exchanges/kalshi/fetchOrderBook.js +60 -0
- package/dist/exchanges/kalshi/fetchTrades.d.ts +3 -0
- package/dist/exchanges/kalshi/fetchTrades.js +32 -0
- package/dist/exchanges/kalshi/index.d.ts +20 -4
- package/dist/exchanges/kalshi/index.js +171 -90
- package/dist/exchanges/kalshi/kalshi.test.js +440 -157
- package/dist/exchanges/kalshi/utils.d.ts +1 -3
- package/dist/exchanges/kalshi/utils.js +15 -16
- package/dist/exchanges/kalshi/websocket.d.ts +4 -3
- package/dist/exchanges/kalshi/websocket.js +87 -61
- package/dist/exchanges/kalshi-demo/index.d.ts +10 -0
- package/dist/exchanges/kalshi-demo/index.js +23 -0
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/fetchEvents.d.ts +2 -1
- package/dist/exchanges/limitless/fetchEvents.js +95 -49
- package/dist/exchanges/limitless/fetchOHLCV.d.ts +2 -2
- package/dist/exchanges/limitless/index.d.ts +11 -3
- package/dist/exchanges/limitless/index.js +69 -1
- package/dist/exchanges/limitless/utils.js +1 -0
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/myriad/fetchOHLCV.d.ts +2 -2
- package/dist/exchanges/myriad/index.d.ts +9 -3
- package/dist/exchanges/myriad/index.js +34 -0
- package/dist/exchanges/myriad/utils.js +5 -1
- package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
- package/dist/exchanges/polymarket/api-clob.js +1 -1
- package/dist/exchanges/polymarket/api-data.d.ts +1 -1
- package/dist/exchanges/polymarket/api-data.js +1 -1
- package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
- package/dist/exchanges/polymarket/api-gamma.js +1 -1
- package/dist/exchanges/polymarket/auth.js +3 -1
- package/dist/exchanges/polymarket/fetchEvents.js +116 -80
- package/dist/exchanges/polymarket/fetchOHLCV.d.ts +2 -2
- package/dist/exchanges/polymarket/index.d.ts +30 -6
- package/dist/exchanges/polymarket/index.js +101 -31
- package/dist/exchanges/polymarket/utils.js +1 -0
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/index.d.ts +45 -3
- package/dist/exchanges/probable/index.js +61 -0
- package/dist/exchanges/probable/utils.js +5 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -1
- package/dist/server/app.js +56 -48
- package/dist/server/utils/port-manager.js +1 -1
- package/dist/types.d.ts +29 -0
- package/dist/utils/throttler.d.ts +17 -0
- package/dist/utils/throttler.js +50 -0
- package/package.json +7 -4
package/dist/BaseExchange.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UnifiedMarket, UnifiedEvent, PriceCandle, CandleInterval, OrderBook, Trade, Order, Position, Balance, CreateOrderParams } from './types';
|
|
1
|
+
import { UnifiedMarket, UnifiedEvent, PriceCandle, CandleInterval, OrderBook, Trade, UserTrade, Order, Position, Balance, CreateOrderParams, BuiltOrder } from './types';
|
|
2
2
|
import { ExecutionPriceResult } from './utils/math';
|
|
3
3
|
import { AxiosInstance } from 'axios';
|
|
4
4
|
export interface ApiEndpoint {
|
|
@@ -37,6 +37,7 @@ export interface EventFetchParams {
|
|
|
37
37
|
query?: string;
|
|
38
38
|
limit?: number;
|
|
39
39
|
offset?: number;
|
|
40
|
+
sort?: 'volume' | 'liquidity' | 'newest';
|
|
40
41
|
status?: 'active' | 'inactive' | 'closed' | 'all';
|
|
41
42
|
searchIn?: 'title' | 'description' | 'both';
|
|
42
43
|
eventId?: string;
|
|
@@ -59,6 +60,21 @@ export interface TradesParams {
|
|
|
59
60
|
end?: Date;
|
|
60
61
|
limit?: number;
|
|
61
62
|
}
|
|
63
|
+
export interface MyTradesParams {
|
|
64
|
+
outcomeId?: string;
|
|
65
|
+
marketId?: string;
|
|
66
|
+
since?: Date;
|
|
67
|
+
until?: Date;
|
|
68
|
+
limit?: number;
|
|
69
|
+
cursor?: string;
|
|
70
|
+
}
|
|
71
|
+
export interface OrderHistoryParams {
|
|
72
|
+
marketId?: string;
|
|
73
|
+
since?: Date;
|
|
74
|
+
until?: Date;
|
|
75
|
+
limit?: number;
|
|
76
|
+
cursor?: string;
|
|
77
|
+
}
|
|
62
78
|
export type MarketFilterCriteria = {
|
|
63
79
|
text?: string;
|
|
64
80
|
searchIn?: ('title' | 'description' | 'category' | 'tags' | 'outcomes')[];
|
|
@@ -126,6 +142,11 @@ export interface ExchangeHas {
|
|
|
126
142
|
fetchBalance: ExchangeCapability;
|
|
127
143
|
watchOrderBook: ExchangeCapability;
|
|
128
144
|
watchTrades: ExchangeCapability;
|
|
145
|
+
fetchMyTrades: ExchangeCapability;
|
|
146
|
+
fetchClosedOrders: ExchangeCapability;
|
|
147
|
+
fetchAllOrders: ExchangeCapability;
|
|
148
|
+
buildOrder: ExchangeCapability;
|
|
149
|
+
submitOrder: ExchangeCapability;
|
|
129
150
|
}
|
|
130
151
|
export interface ExchangeCredentials {
|
|
131
152
|
apiKey?: string;
|
|
@@ -135,18 +156,39 @@ export interface ExchangeCredentials {
|
|
|
135
156
|
signatureType?: number | string;
|
|
136
157
|
funderAddress?: string;
|
|
137
158
|
}
|
|
159
|
+
export interface ExchangeOptions {
|
|
160
|
+
/**
|
|
161
|
+
* How long (ms) a market snapshot created by `fetchMarketsPaginated` remains valid
|
|
162
|
+
* before being discarded and re-fetched from the API on the next call.
|
|
163
|
+
* Defaults to 0 (no TTL — the snapshot is re-fetched on every initial call).
|
|
164
|
+
*/
|
|
165
|
+
snapshotTTL?: number;
|
|
166
|
+
}
|
|
167
|
+
/** Shape returned by fetchMarketsPaginated */
|
|
168
|
+
export interface PaginatedMarketsResult {
|
|
169
|
+
data: UnifiedMarket[];
|
|
170
|
+
total: number;
|
|
171
|
+
nextCursor?: string;
|
|
172
|
+
}
|
|
138
173
|
export declare abstract class PredictionMarketExchange {
|
|
139
174
|
[key: string]: any;
|
|
140
175
|
protected credentials?: ExchangeCredentials;
|
|
141
176
|
verbose: boolean;
|
|
142
177
|
http: AxiosInstance;
|
|
178
|
+
enableRateLimit: boolean;
|
|
179
|
+
private _rateLimit;
|
|
180
|
+
private _throttler;
|
|
181
|
+
private _snapshotTTL;
|
|
182
|
+
private _snapshot?;
|
|
183
|
+
get rateLimit(): number;
|
|
184
|
+
set rateLimit(value: number);
|
|
143
185
|
markets: Record<string, UnifiedMarket>;
|
|
144
186
|
marketsBySlug: Record<string, UnifiedMarket>;
|
|
145
187
|
loadedMarkets: boolean;
|
|
146
188
|
protected apiDescriptor?: ApiDescriptor;
|
|
147
189
|
private apiDescriptors;
|
|
148
190
|
readonly has: ExchangeHas;
|
|
149
|
-
constructor(credentials?: ExchangeCredentials);
|
|
191
|
+
constructor(credentials?: ExchangeCredentials, options?: ExchangeOptions);
|
|
150
192
|
abstract get name(): string;
|
|
151
193
|
/**
|
|
152
194
|
* Load and cache all markets from the exchange into `this.markets` and `this.marketsBySlug`.
|
|
@@ -208,12 +250,31 @@ export declare abstract class PredictionMarketExchange {
|
|
|
208
250
|
* markets = exchange.fetch_markets(slug='will-trump-win')
|
|
209
251
|
*/
|
|
210
252
|
fetchMarkets(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
|
|
253
|
+
/**
|
|
254
|
+
* Fetch markets with cursor-based pagination backed by a stable in-memory snapshot.
|
|
255
|
+
*
|
|
256
|
+
* On the first call (or when no cursor is supplied), fetches all markets once and
|
|
257
|
+
* caches them. Subsequent calls with a cursor returned from a previous call slice
|
|
258
|
+
* directly from the cached snapshot — no additional API calls are made.
|
|
259
|
+
*
|
|
260
|
+
* The snapshot is invalidated after `snapshotTTL` ms (configured via `ExchangeOptions`
|
|
261
|
+
* in the constructor). A request using a cursor from an expired snapshot throws
|
|
262
|
+
* `'Cursor has expired'`.
|
|
263
|
+
*
|
|
264
|
+
* @param params.limit - Page size (default: return all markets)
|
|
265
|
+
* @param params.cursor - Opaque cursor returned by a previous call
|
|
266
|
+
* @returns PaginatedMarketsResult with data, total, and optional nextCursor
|
|
267
|
+
*/
|
|
268
|
+
fetchMarketsPaginated(params?: {
|
|
269
|
+
limit?: number;
|
|
270
|
+
cursor?: string;
|
|
271
|
+
}): Promise<PaginatedMarketsResult>;
|
|
211
272
|
/**
|
|
212
273
|
* Fetch events with optional keyword search.
|
|
213
274
|
* Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
|
|
214
275
|
*
|
|
215
276
|
* @param params - Optional parameters for search and filtering
|
|
216
|
-
* @param params.query - Search keyword to filter events
|
|
277
|
+
* @param params.query - Search keyword to filter events. If omitted, returns top events by volume.
|
|
217
278
|
* @param params.limit - Maximum number of results
|
|
218
279
|
* @param params.offset - Pagination offset
|
|
219
280
|
* @param params.searchIn - Where to search ('title' | 'description' | 'both')
|
|
@@ -302,7 +363,7 @@ export declare abstract class PredictionMarketExchange {
|
|
|
302
363
|
* @notes Polymarket: outcomeId is the CLOB Token ID. Kalshi: outcomeId is the Market Ticker.
|
|
303
364
|
* @notes Resolution options: '1m' | '5m' | '15m' | '1h' | '6h' | '1d'
|
|
304
365
|
*/
|
|
305
|
-
fetchOHLCV(id: string, params: OHLCVParams
|
|
366
|
+
fetchOHLCV(id: string, params: OHLCVParams): Promise<PriceCandle[]>;
|
|
306
367
|
/**
|
|
307
368
|
* Fetch the current order book (bids/asks) for a specific outcome.
|
|
308
369
|
* Essential for calculating spread, depth, and execution prices.
|
|
@@ -391,6 +452,56 @@ export declare abstract class PredictionMarketExchange {
|
|
|
391
452
|
* )
|
|
392
453
|
*/
|
|
393
454
|
createOrder(params: CreateOrderParams): Promise<Order>;
|
|
455
|
+
/**
|
|
456
|
+
* Build an order payload without submitting it to the exchange.
|
|
457
|
+
* Returns the exchange-native signed order or request body for inspection,
|
|
458
|
+
* forwarding through a middleware layer, or deferred submission via submitOrder().
|
|
459
|
+
*
|
|
460
|
+
* @param params - Order parameters (same as createOrder)
|
|
461
|
+
* @returns A BuiltOrder containing the exchange-native payload
|
|
462
|
+
*
|
|
463
|
+
* @example-ts Build then inspect a Polymarket order
|
|
464
|
+
* const built = await exchange.buildOrder({
|
|
465
|
+
* marketId: market.marketId,
|
|
466
|
+
* outcomeId: market.yes.outcomeId,
|
|
467
|
+
* side: 'buy',
|
|
468
|
+
* type: 'limit',
|
|
469
|
+
* amount: 10,
|
|
470
|
+
* price: 0.55
|
|
471
|
+
* });
|
|
472
|
+
* console.log(built.signedOrder); // EIP-712 signed order struct
|
|
473
|
+
* const order = await exchange.submitOrder(built);
|
|
474
|
+
*
|
|
475
|
+
* @example-python Build then submit a Polymarket order
|
|
476
|
+
* built = exchange.build_order(
|
|
477
|
+
* market_id=market.market_id,
|
|
478
|
+
* outcome_id=market.yes.outcome_id,
|
|
479
|
+
* side='buy',
|
|
480
|
+
* type='limit',
|
|
481
|
+
* amount=10,
|
|
482
|
+
* price=0.55
|
|
483
|
+
* )
|
|
484
|
+
* print(built.signed_order)
|
|
485
|
+
* order = exchange.submit_order(built)
|
|
486
|
+
*/
|
|
487
|
+
buildOrder(params: CreateOrderParams): Promise<BuiltOrder>;
|
|
488
|
+
/**
|
|
489
|
+
* Submit a pre-built order returned by buildOrder().
|
|
490
|
+
*
|
|
491
|
+
* @param built - A BuiltOrder from buildOrder()
|
|
492
|
+
* @returns The submitted order
|
|
493
|
+
*
|
|
494
|
+
* @example-ts Submit a pre-built order
|
|
495
|
+
* const built = await exchange.buildOrder(params);
|
|
496
|
+
* const order = await exchange.submitOrder(built);
|
|
497
|
+
* console.log(`Order ${order.id}: ${order.status}`);
|
|
498
|
+
*
|
|
499
|
+
* @example-python Submit a pre-built order
|
|
500
|
+
* built = exchange.build_order(params)
|
|
501
|
+
* order = exchange.submit_order(built)
|
|
502
|
+
* print(f"Order {order.id}: {order.status}")
|
|
503
|
+
*/
|
|
504
|
+
submitOrder(built: BuiltOrder): Promise<Order>;
|
|
394
505
|
/**
|
|
395
506
|
* Cancel an existing open order.
|
|
396
507
|
*
|
|
@@ -445,6 +556,9 @@ export declare abstract class PredictionMarketExchange {
|
|
|
445
556
|
* orders = exchange.fetch_open_orders('FED-25JAN')
|
|
446
557
|
*/
|
|
447
558
|
fetchOpenOrders(marketId?: string): Promise<Order[]>;
|
|
559
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
560
|
+
fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
561
|
+
fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
448
562
|
/**
|
|
449
563
|
* Fetch current user positions across all markets.
|
|
450
564
|
*
|
package/dist/BaseExchange.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.PredictionMarketExchange = void 0;
|
|
7
7
|
const math_1 = require("./utils/math");
|
|
8
8
|
const errors_1 = require("./errors");
|
|
9
|
+
const throttler_1 = require("./utils/throttler");
|
|
9
10
|
const axios_1 = __importDefault(require("axios"));
|
|
10
11
|
// ----------------------------------------------------------------------------
|
|
11
12
|
// Base Exchange Class
|
|
@@ -14,6 +15,23 @@ class PredictionMarketExchange {
|
|
|
14
15
|
credentials;
|
|
15
16
|
verbose = false;
|
|
16
17
|
http;
|
|
18
|
+
enableRateLimit = true;
|
|
19
|
+
_rateLimit = 1000;
|
|
20
|
+
_throttler;
|
|
21
|
+
// Snapshot state for cursor-based pagination
|
|
22
|
+
_snapshotTTL;
|
|
23
|
+
_snapshot;
|
|
24
|
+
get rateLimit() {
|
|
25
|
+
return this._rateLimit;
|
|
26
|
+
}
|
|
27
|
+
set rateLimit(value) {
|
|
28
|
+
this._rateLimit = value;
|
|
29
|
+
this._throttler = new throttler_1.Throttler({
|
|
30
|
+
refillRate: 1 / value,
|
|
31
|
+
capacity: 1,
|
|
32
|
+
delay: 1,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
17
35
|
// Market Cache
|
|
18
36
|
markets = {};
|
|
19
37
|
marketsBySlug = {};
|
|
@@ -35,10 +53,32 @@ class PredictionMarketExchange {
|
|
|
35
53
|
fetchBalance: false,
|
|
36
54
|
watchOrderBook: false,
|
|
37
55
|
watchTrades: false,
|
|
56
|
+
fetchMyTrades: false,
|
|
57
|
+
fetchClosedOrders: false,
|
|
58
|
+
fetchAllOrders: false,
|
|
59
|
+
buildOrder: false,
|
|
60
|
+
submitOrder: false,
|
|
38
61
|
};
|
|
39
|
-
constructor(credentials) {
|
|
62
|
+
constructor(credentials, options) {
|
|
40
63
|
this.credentials = credentials;
|
|
41
|
-
this.
|
|
64
|
+
this._snapshotTTL = options?.snapshotTTL ?? 0;
|
|
65
|
+
this.http = axios_1.default.create({
|
|
66
|
+
headers: {
|
|
67
|
+
'User-Agent': `pmxt (https://github.com/pmxt-dev/pmxt)`
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
this._throttler = new throttler_1.Throttler({
|
|
71
|
+
refillRate: 1 / this._rateLimit,
|
|
72
|
+
capacity: 1,
|
|
73
|
+
delay: 1,
|
|
74
|
+
});
|
|
75
|
+
// Rate Limit Interceptor
|
|
76
|
+
this.http.interceptors.request.use(async (config) => {
|
|
77
|
+
if (this.enableRateLimit) {
|
|
78
|
+
await this._throttler.throttle();
|
|
79
|
+
}
|
|
80
|
+
return config;
|
|
81
|
+
});
|
|
42
82
|
// Request Interceptor
|
|
43
83
|
this.http.interceptors.request.use((config) => {
|
|
44
84
|
if (this.verbose) {
|
|
@@ -150,12 +190,65 @@ class PredictionMarketExchange {
|
|
|
150
190
|
async fetchMarkets(params) {
|
|
151
191
|
return this.fetchMarketsImpl(params);
|
|
152
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* Fetch markets with cursor-based pagination backed by a stable in-memory snapshot.
|
|
195
|
+
*
|
|
196
|
+
* On the first call (or when no cursor is supplied), fetches all markets once and
|
|
197
|
+
* caches them. Subsequent calls with a cursor returned from a previous call slice
|
|
198
|
+
* directly from the cached snapshot — no additional API calls are made.
|
|
199
|
+
*
|
|
200
|
+
* The snapshot is invalidated after `snapshotTTL` ms (configured via `ExchangeOptions`
|
|
201
|
+
* in the constructor). A request using a cursor from an expired snapshot throws
|
|
202
|
+
* `'Cursor has expired'`.
|
|
203
|
+
*
|
|
204
|
+
* @param params.limit - Page size (default: return all markets)
|
|
205
|
+
* @param params.cursor - Opaque cursor returned by a previous call
|
|
206
|
+
* @returns PaginatedMarketsResult with data, total, and optional nextCursor
|
|
207
|
+
*/
|
|
208
|
+
async fetchMarketsPaginated(params) {
|
|
209
|
+
const limit = params?.limit;
|
|
210
|
+
const cursor = params?.cursor;
|
|
211
|
+
if (cursor) {
|
|
212
|
+
// Cursor encodes: snapshotId:offset
|
|
213
|
+
const sep = cursor.indexOf(':');
|
|
214
|
+
const snapshotId = cursor.substring(0, sep);
|
|
215
|
+
const offset = parseInt(cursor.substring(sep + 1), 10);
|
|
216
|
+
if (!this._snapshot ||
|
|
217
|
+
this._snapshot.id !== snapshotId ||
|
|
218
|
+
(this._snapshotTTL > 0 && Date.now() - this._snapshot.takenAt > this._snapshotTTL)) {
|
|
219
|
+
throw new Error('Cursor has expired');
|
|
220
|
+
}
|
|
221
|
+
const markets = this._snapshot.markets;
|
|
222
|
+
const slice = limit !== undefined ? markets.slice(offset, offset + limit) : markets.slice(offset);
|
|
223
|
+
const nextOffset = offset + slice.length;
|
|
224
|
+
const nextCursor = nextOffset < markets.length ? `${snapshotId}:${nextOffset}` : undefined;
|
|
225
|
+
return { data: slice, total: markets.length, nextCursor };
|
|
226
|
+
}
|
|
227
|
+
// No cursor — (re)fetch snapshot
|
|
228
|
+
if (!this._snapshot ||
|
|
229
|
+
this._snapshotTTL === 0 ||
|
|
230
|
+
Date.now() - this._snapshot.takenAt > this._snapshotTTL) {
|
|
231
|
+
const markets = await this.fetchMarketsImpl();
|
|
232
|
+
this._snapshot = {
|
|
233
|
+
markets,
|
|
234
|
+
takenAt: Date.now(),
|
|
235
|
+
id: Math.random().toString(36).slice(2),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const markets = this._snapshot.markets;
|
|
239
|
+
if (!limit) {
|
|
240
|
+
return { data: markets, total: markets.length, nextCursor: undefined };
|
|
241
|
+
}
|
|
242
|
+
const slice = markets.slice(0, limit);
|
|
243
|
+
const nextCursor = limit < markets.length ? `${this._snapshot.id}:${limit}` : undefined;
|
|
244
|
+
return { data: slice, total: markets.length, nextCursor };
|
|
245
|
+
}
|
|
153
246
|
/**
|
|
154
247
|
* Fetch events with optional keyword search.
|
|
155
248
|
* Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
|
|
156
249
|
*
|
|
157
250
|
* @param params - Optional parameters for search and filtering
|
|
158
|
-
* @param params.query - Search keyword to filter events
|
|
251
|
+
* @param params.query - Search keyword to filter events. If omitted, returns top events by volume.
|
|
159
252
|
* @param params.limit - Maximum number of results
|
|
160
253
|
* @param params.offset - Pagination offset
|
|
161
254
|
* @param params.searchIn - Where to search ('title' | 'description' | 'both')
|
|
@@ -174,10 +267,7 @@ class PredictionMarketExchange {
|
|
|
174
267
|
* print(fed_event.title, len(fed_event.markets), 'markets')
|
|
175
268
|
*/
|
|
176
269
|
async fetchEvents(params) {
|
|
177
|
-
|
|
178
|
-
throw new Error("fetchEvents() requires a query, eventId, or slug parameter");
|
|
179
|
-
}
|
|
180
|
-
return this.fetchEventsImpl(params);
|
|
270
|
+
return this.fetchEventsImpl(params ?? {});
|
|
181
271
|
}
|
|
182
272
|
/**
|
|
183
273
|
* Fetch a single market by lookup parameters.
|
|
@@ -384,6 +474,60 @@ class PredictionMarketExchange {
|
|
|
384
474
|
async createOrder(params) {
|
|
385
475
|
throw new Error("Method createOrder not implemented.");
|
|
386
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Build an order payload without submitting it to the exchange.
|
|
479
|
+
* Returns the exchange-native signed order or request body for inspection,
|
|
480
|
+
* forwarding through a middleware layer, or deferred submission via submitOrder().
|
|
481
|
+
*
|
|
482
|
+
* @param params - Order parameters (same as createOrder)
|
|
483
|
+
* @returns A BuiltOrder containing the exchange-native payload
|
|
484
|
+
*
|
|
485
|
+
* @example-ts Build then inspect a Polymarket order
|
|
486
|
+
* const built = await exchange.buildOrder({
|
|
487
|
+
* marketId: market.marketId,
|
|
488
|
+
* outcomeId: market.yes.outcomeId,
|
|
489
|
+
* side: 'buy',
|
|
490
|
+
* type: 'limit',
|
|
491
|
+
* amount: 10,
|
|
492
|
+
* price: 0.55
|
|
493
|
+
* });
|
|
494
|
+
* console.log(built.signedOrder); // EIP-712 signed order struct
|
|
495
|
+
* const order = await exchange.submitOrder(built);
|
|
496
|
+
*
|
|
497
|
+
* @example-python Build then submit a Polymarket order
|
|
498
|
+
* built = exchange.build_order(
|
|
499
|
+
* market_id=market.market_id,
|
|
500
|
+
* outcome_id=market.yes.outcome_id,
|
|
501
|
+
* side='buy',
|
|
502
|
+
* type='limit',
|
|
503
|
+
* amount=10,
|
|
504
|
+
* price=0.55
|
|
505
|
+
* )
|
|
506
|
+
* print(built.signed_order)
|
|
507
|
+
* order = exchange.submit_order(built)
|
|
508
|
+
*/
|
|
509
|
+
async buildOrder(params) {
|
|
510
|
+
throw new Error("Method buildOrder not implemented.");
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Submit a pre-built order returned by buildOrder().
|
|
514
|
+
*
|
|
515
|
+
* @param built - A BuiltOrder from buildOrder()
|
|
516
|
+
* @returns The submitted order
|
|
517
|
+
*
|
|
518
|
+
* @example-ts Submit a pre-built order
|
|
519
|
+
* const built = await exchange.buildOrder(params);
|
|
520
|
+
* const order = await exchange.submitOrder(built);
|
|
521
|
+
* console.log(`Order ${order.id}: ${order.status}`);
|
|
522
|
+
*
|
|
523
|
+
* @example-python Submit a pre-built order
|
|
524
|
+
* built = exchange.build_order(params)
|
|
525
|
+
* order = exchange.submit_order(built)
|
|
526
|
+
* print(f"Order {order.id}: {order.status}")
|
|
527
|
+
*/
|
|
528
|
+
async submitOrder(built) {
|
|
529
|
+
throw new Error("Method submitOrder not implemented.");
|
|
530
|
+
}
|
|
387
531
|
/**
|
|
388
532
|
* Cancel an existing open order.
|
|
389
533
|
*
|
|
@@ -444,6 +588,15 @@ class PredictionMarketExchange {
|
|
|
444
588
|
async fetchOpenOrders(marketId) {
|
|
445
589
|
throw new Error("Method fetchOpenOrders not implemented.");
|
|
446
590
|
}
|
|
591
|
+
async fetchMyTrades(params) {
|
|
592
|
+
throw new Error("Method fetchMyTrades not implemented.");
|
|
593
|
+
}
|
|
594
|
+
async fetchClosedOrders(params) {
|
|
595
|
+
throw new Error("Method fetchClosedOrders not implemented.");
|
|
596
|
+
}
|
|
597
|
+
async fetchAllOrders(params) {
|
|
598
|
+
throw new Error("Method fetchAllOrders not implemented.");
|
|
599
|
+
}
|
|
447
600
|
/**
|
|
448
601
|
* Fetch current user positions across all markets.
|
|
449
602
|
*
|
|
@@ -16,17 +16,22 @@ async function fetchEvents(connection, params) {
|
|
|
16
16
|
status: params.status,
|
|
17
17
|
searchIn: params.searchIn,
|
|
18
18
|
});
|
|
19
|
-
return markets.map(m =>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
return markets.map(m => {
|
|
20
|
+
const unifiedEvent = {
|
|
21
|
+
id: m.marketId,
|
|
22
|
+
title: m.title,
|
|
23
|
+
description: m.description,
|
|
24
|
+
slug: m.marketId,
|
|
25
|
+
markets: [m],
|
|
26
|
+
volume24h: m.volume24h,
|
|
27
|
+
volume: m.volume,
|
|
28
|
+
url: m.url,
|
|
29
|
+
image: m.image,
|
|
30
|
+
category: m.category,
|
|
31
|
+
tags: m.tags,
|
|
32
|
+
};
|
|
33
|
+
return unifiedEvent;
|
|
34
|
+
});
|
|
30
35
|
}
|
|
31
36
|
catch (error) {
|
|
32
37
|
throw errors_1.baoziErrorMapper.mapError(error);
|
|
@@ -19,6 +19,11 @@ export declare class BaoziExchange extends PredictionMarketExchange {
|
|
|
19
19
|
fetchBalance: true;
|
|
20
20
|
watchOrderBook: true;
|
|
21
21
|
watchTrades: false;
|
|
22
|
+
fetchMyTrades: false;
|
|
23
|
+
fetchClosedOrders: false;
|
|
24
|
+
fetchAllOrders: false;
|
|
25
|
+
buildOrder: false;
|
|
26
|
+
submitOrder: false;
|
|
22
27
|
};
|
|
23
28
|
private auth?;
|
|
24
29
|
private connection;
|
|
@@ -28,6 +28,11 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
28
28
|
fetchBalance: true,
|
|
29
29
|
watchOrderBook: true,
|
|
30
30
|
watchTrades: false,
|
|
31
|
+
fetchMyTrades: false,
|
|
32
|
+
fetchClosedOrders: false,
|
|
33
|
+
fetchAllOrders: false,
|
|
34
|
+
buildOrder: false,
|
|
35
|
+
submitOrder: false,
|
|
31
36
|
};
|
|
32
37
|
auth;
|
|
33
38
|
connection;
|
|
@@ -43,6 +48,7 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
43
48
|
credentials = options;
|
|
44
49
|
}
|
|
45
50
|
super(credentials);
|
|
51
|
+
this.rateLimit = 500;
|
|
46
52
|
rpcUrl = rpcUrl
|
|
47
53
|
|| process.env.BAOZI_RPC_URL
|
|
48
54
|
|| process.env.HELIUS_RPC_URL
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
|
|
3
|
-
* Generated at: 2026-
|
|
3
|
+
* Generated at: 2026-03-04T17:45:20.579Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const kalshiApiSpec: {
|
|
@@ -11,6 +11,12 @@ export declare const kalshiApiSpec: {
|
|
|
11
11
|
};
|
|
12
12
|
servers: {
|
|
13
13
|
url: string;
|
|
14
|
+
variables: {
|
|
15
|
+
env: {
|
|
16
|
+
default: string;
|
|
17
|
+
enum: string[];
|
|
18
|
+
};
|
|
19
|
+
};
|
|
14
20
|
}[];
|
|
15
21
|
paths: {
|
|
16
22
|
"/historical/cutoff": {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.kalshiApiSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/kalshi/Kalshi.yaml
|
|
6
|
-
* Generated at: 2026-
|
|
6
|
+
* Generated at: 2026-03-04T17:45:20.579Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.kalshiApiSpec = {
|
|
@@ -14,7 +14,16 @@ exports.kalshiApiSpec = {
|
|
|
14
14
|
},
|
|
15
15
|
"servers": [
|
|
16
16
|
{
|
|
17
|
-
"url": "https://
|
|
17
|
+
"url": "https://{env}.elections.kalshi.com/trade-api/v2",
|
|
18
|
+
"variables": {
|
|
19
|
+
"env": {
|
|
20
|
+
"default": "api",
|
|
21
|
+
"enum": [
|
|
22
|
+
"api",
|
|
23
|
+
"demo-api"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
18
27
|
}
|
|
19
28
|
],
|
|
20
29
|
"paths": {
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kalshi runtime configuration.
|
|
3
|
+
*
|
|
4
|
+
* This file is hand-authored and is the single source of truth for:
|
|
5
|
+
* - Base URL constants for production and demo environments
|
|
6
|
+
* - API path constants (KALSHI_PATHS)
|
|
7
|
+
* - URL helper functions used by fetch functions and the exchange class
|
|
8
|
+
*
|
|
9
|
+
* The OpenAPI spec lives in core/specs/kalshi/Kalshi.yaml and is compiled
|
|
10
|
+
* into core/src/exchanges/kalshi/api.ts by `npm run fetch:openapi`.
|
|
11
|
+
* Do NOT put runtime config into api.ts — it will be overwritten.
|
|
12
|
+
*
|
|
13
|
+
* Environment mapping (aligns with the `{env}` server variable in Kalshi.yaml):
|
|
14
|
+
* env = "api" → production: https://api.elections.kalshi.com
|
|
15
|
+
* env = "demo-api" → demo/paper: https://demo-api.elections.kalshi.com
|
|
16
|
+
*/
|
|
17
|
+
export declare const KALSHI_PROD_API_URL = "https://api.elections.kalshi.com";
|
|
18
|
+
export declare const KALSHI_DEMO_API_URL = "https://demo-api.kalshi.co";
|
|
19
|
+
export declare const KALSHI_PROD_WS_URL = "wss://api.elections.kalshi.com/trade-api/ws/v2";
|
|
20
|
+
export declare const KALSHI_DEMO_WS_URL = "wss://demo-api.kalshi.co/trade-api/ws/v2";
|
|
21
|
+
export declare const KALSHI_PATHS: {
|
|
22
|
+
TRADE_API: string;
|
|
23
|
+
EVENTS: string;
|
|
24
|
+
SERIES: string;
|
|
25
|
+
PORTFOLIO: string;
|
|
26
|
+
MARKETS: string;
|
|
27
|
+
BALANCE: string;
|
|
28
|
+
ORDERS: string;
|
|
29
|
+
POSITIONS: string;
|
|
30
|
+
};
|
|
31
|
+
export interface KalshiApiConfig {
|
|
32
|
+
/** Base REST API URL — production or demo */
|
|
33
|
+
apiUrl: string;
|
|
34
|
+
/** WebSocket URL — production or demo */
|
|
35
|
+
wsUrl?: string;
|
|
36
|
+
/** Whether the demo environment is active */
|
|
37
|
+
demoMode: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Return a typed config object for the requested environment.
|
|
41
|
+
*
|
|
42
|
+
* @param demoMode - Pass `true` to target demo-api.elections.kalshi.com.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const config = getKalshiConfig(true);
|
|
47
|
+
* // config.apiUrl === "https://demo-api.elections.kalshi.com"
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function getKalshiConfig(demoMode?: boolean): KalshiApiConfig;
|
|
51
|
+
/**
|
|
52
|
+
* Build the full path (including `/trade-api/v2` prefix) for use in
|
|
53
|
+
* `KalshiAuth.getHeaders()` signing.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* getApiPath("/portfolio/balance")
|
|
58
|
+
* // → "/trade-api/v2/portfolio/balance"
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function getApiPath(operationPath: string): string;
|
|
62
|
+
/**
|
|
63
|
+
* Build the full URL for the events endpoint.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* getEventsUrl(baseUrl) // .../events
|
|
68
|
+
* getEventsUrl(baseUrl, ['FED-25']) // .../events/FED-25
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function getEventsUrl(baseUrl: string, pathSegments?: string[]): string;
|
|
72
|
+
/**
|
|
73
|
+
* Build the full URL for the series endpoint, with optional nested segments.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* getSeriesUrl(baseUrl) // .../series
|
|
78
|
+
* getSeriesUrl(baseUrl, 'FED') // .../series/FED
|
|
79
|
+
* getSeriesUrl(baseUrl, 'FED', ['markets', 'FED-B4.75', 'candlesticks'])
|
|
80
|
+
* // .../series/FED/markets/FED-B4.75/candlesticks
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function getSeriesUrl(baseUrl: string, seriesTicker?: string, pathSegments?: string[]): string;
|
|
84
|
+
/**
|
|
85
|
+
* Build the full URL for the portfolio endpoint.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* getPortfolioUrl(baseUrl, '/balance') // .../portfolio/balance
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare function getPortfolioUrl(baseUrl: string, subPath?: string): string;
|
|
93
|
+
/**
|
|
94
|
+
* Build the full URL for the markets endpoint, with optional nested segments.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* getMarketsUrl(baseUrl) // .../markets
|
|
99
|
+
* getMarketsUrl(baseUrl, 'FED-B4.75') // .../markets/FED-B4.75
|
|
100
|
+
* getMarketsUrl(baseUrl, 'FED-B4.75', ['orderbook']) // .../markets/FED-B4.75/orderbook
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare function getMarketsUrl(baseUrl: string, marketId?: string, pathSegments?: string[]): string;
|