pmxt-core 2.10.0 → 2.12.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.
- package/dist/BaseExchange.d.ts +63 -2
- package/dist/BaseExchange.js +97 -1
- package/dist/exchanges/baozi/index.d.ts +3 -0
- package/dist/exchanges/baozi/index.js +4 -0
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/kalshi/index.d.ts +9 -2
- package/dist/exchanges/kalshi/index.js +84 -27
- package/dist/exchanges/kalshi/kalshi.test.js +180 -0
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/index.d.ts +8 -2
- package/dist/exchanges/limitless/index.js +66 -0
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/myriad/index.d.ts +6 -2
- package/dist/exchanges/myriad/index.js +32 -0
- 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/index.d.ts +6 -2
- package/dist/exchanges/polymarket/index.js +27 -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 +6 -2
- package/dist/exchanges/probable/index.js +23 -0
- package/dist/types.d.ts +3 -0
- package/dist/utils/throttler.d.ts +17 -0
- package/dist/utils/throttler.js +50 -0
- package/package.json +3 -3
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 } from './types';
|
|
2
2
|
import { ExecutionPriceResult } from './utils/math';
|
|
3
3
|
import { AxiosInstance } from 'axios';
|
|
4
4
|
export interface ApiEndpoint {
|
|
@@ -59,6 +59,21 @@ export interface TradesParams {
|
|
|
59
59
|
end?: Date;
|
|
60
60
|
limit?: number;
|
|
61
61
|
}
|
|
62
|
+
export interface MyTradesParams {
|
|
63
|
+
outcomeId?: string;
|
|
64
|
+
marketId?: string;
|
|
65
|
+
since?: Date;
|
|
66
|
+
until?: Date;
|
|
67
|
+
limit?: number;
|
|
68
|
+
cursor?: string;
|
|
69
|
+
}
|
|
70
|
+
export interface OrderHistoryParams {
|
|
71
|
+
marketId?: string;
|
|
72
|
+
since?: Date;
|
|
73
|
+
until?: Date;
|
|
74
|
+
limit?: number;
|
|
75
|
+
cursor?: string;
|
|
76
|
+
}
|
|
62
77
|
export type MarketFilterCriteria = {
|
|
63
78
|
text?: string;
|
|
64
79
|
searchIn?: ('title' | 'description' | 'category' | 'tags' | 'outcomes')[];
|
|
@@ -126,6 +141,9 @@ export interface ExchangeHas {
|
|
|
126
141
|
fetchBalance: ExchangeCapability;
|
|
127
142
|
watchOrderBook: ExchangeCapability;
|
|
128
143
|
watchTrades: ExchangeCapability;
|
|
144
|
+
fetchMyTrades: ExchangeCapability;
|
|
145
|
+
fetchClosedOrders: ExchangeCapability;
|
|
146
|
+
fetchAllOrders: ExchangeCapability;
|
|
129
147
|
}
|
|
130
148
|
export interface ExchangeCredentials {
|
|
131
149
|
apiKey?: string;
|
|
@@ -135,18 +153,39 @@ export interface ExchangeCredentials {
|
|
|
135
153
|
signatureType?: number | string;
|
|
136
154
|
funderAddress?: string;
|
|
137
155
|
}
|
|
156
|
+
export interface ExchangeOptions {
|
|
157
|
+
/**
|
|
158
|
+
* How long (ms) a market snapshot created by `fetchMarketsPaginated` remains valid
|
|
159
|
+
* before being discarded and re-fetched from the API on the next call.
|
|
160
|
+
* Defaults to 0 (no TTL — the snapshot is re-fetched on every initial call).
|
|
161
|
+
*/
|
|
162
|
+
snapshotTTL?: number;
|
|
163
|
+
}
|
|
164
|
+
/** Shape returned by fetchMarketsPaginated */
|
|
165
|
+
export interface PaginatedMarketsResult {
|
|
166
|
+
data: UnifiedMarket[];
|
|
167
|
+
total: number;
|
|
168
|
+
nextCursor?: string;
|
|
169
|
+
}
|
|
138
170
|
export declare abstract class PredictionMarketExchange {
|
|
139
171
|
[key: string]: any;
|
|
140
172
|
protected credentials?: ExchangeCredentials;
|
|
141
173
|
verbose: boolean;
|
|
142
174
|
http: AxiosInstance;
|
|
175
|
+
enableRateLimit: boolean;
|
|
176
|
+
private _rateLimit;
|
|
177
|
+
private _throttler;
|
|
178
|
+
private _snapshotTTL;
|
|
179
|
+
private _snapshot?;
|
|
180
|
+
get rateLimit(): number;
|
|
181
|
+
set rateLimit(value: number);
|
|
143
182
|
markets: Record<string, UnifiedMarket>;
|
|
144
183
|
marketsBySlug: Record<string, UnifiedMarket>;
|
|
145
184
|
loadedMarkets: boolean;
|
|
146
185
|
protected apiDescriptor?: ApiDescriptor;
|
|
147
186
|
private apiDescriptors;
|
|
148
187
|
readonly has: ExchangeHas;
|
|
149
|
-
constructor(credentials?: ExchangeCredentials);
|
|
188
|
+
constructor(credentials?: ExchangeCredentials, options?: ExchangeOptions);
|
|
150
189
|
abstract get name(): string;
|
|
151
190
|
/**
|
|
152
191
|
* Load and cache all markets from the exchange into `this.markets` and `this.marketsBySlug`.
|
|
@@ -208,6 +247,25 @@ export declare abstract class PredictionMarketExchange {
|
|
|
208
247
|
* markets = exchange.fetch_markets(slug='will-trump-win')
|
|
209
248
|
*/
|
|
210
249
|
fetchMarkets(params?: MarketFetchParams): Promise<UnifiedMarket[]>;
|
|
250
|
+
/**
|
|
251
|
+
* Fetch markets with cursor-based pagination backed by a stable in-memory snapshot.
|
|
252
|
+
*
|
|
253
|
+
* On the first call (or when no cursor is supplied), fetches all markets once and
|
|
254
|
+
* caches them. Subsequent calls with a cursor returned from a previous call slice
|
|
255
|
+
* directly from the cached snapshot — no additional API calls are made.
|
|
256
|
+
*
|
|
257
|
+
* The snapshot is invalidated after `snapshotTTL` ms (configured via `ExchangeOptions`
|
|
258
|
+
* in the constructor). A request using a cursor from an expired snapshot throws
|
|
259
|
+
* `'Cursor has expired'`.
|
|
260
|
+
*
|
|
261
|
+
* @param params.limit - Page size (default: return all markets)
|
|
262
|
+
* @param params.cursor - Opaque cursor returned by a previous call
|
|
263
|
+
* @returns PaginatedMarketsResult with data, total, and optional nextCursor
|
|
264
|
+
*/
|
|
265
|
+
fetchMarketsPaginated(params?: {
|
|
266
|
+
limit?: number;
|
|
267
|
+
cursor?: string;
|
|
268
|
+
}): Promise<PaginatedMarketsResult>;
|
|
211
269
|
/**
|
|
212
270
|
* Fetch events with optional keyword search.
|
|
213
271
|
* Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
|
|
@@ -445,6 +503,9 @@ export declare abstract class PredictionMarketExchange {
|
|
|
445
503
|
* orders = exchange.fetch_open_orders('FED-25JAN')
|
|
446
504
|
*/
|
|
447
505
|
fetchOpenOrders(marketId?: string): Promise<Order[]>;
|
|
506
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
507
|
+
fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
508
|
+
fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
448
509
|
/**
|
|
449
510
|
* Fetch current user positions across all markets.
|
|
450
511
|
*
|
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,26 @@ class PredictionMarketExchange {
|
|
|
35
53
|
fetchBalance: false,
|
|
36
54
|
watchOrderBook: false,
|
|
37
55
|
watchTrades: false,
|
|
56
|
+
fetchMyTrades: false,
|
|
57
|
+
fetchClosedOrders: false,
|
|
58
|
+
fetchAllOrders: false,
|
|
38
59
|
};
|
|
39
|
-
constructor(credentials) {
|
|
60
|
+
constructor(credentials, options) {
|
|
40
61
|
this.credentials = credentials;
|
|
62
|
+
this._snapshotTTL = options?.snapshotTTL ?? 0;
|
|
41
63
|
this.http = axios_1.default.create();
|
|
64
|
+
this._throttler = new throttler_1.Throttler({
|
|
65
|
+
refillRate: 1 / this._rateLimit,
|
|
66
|
+
capacity: 1,
|
|
67
|
+
delay: 1,
|
|
68
|
+
});
|
|
69
|
+
// Rate Limit Interceptor
|
|
70
|
+
this.http.interceptors.request.use(async (config) => {
|
|
71
|
+
if (this.enableRateLimit) {
|
|
72
|
+
await this._throttler.throttle();
|
|
73
|
+
}
|
|
74
|
+
return config;
|
|
75
|
+
});
|
|
42
76
|
// Request Interceptor
|
|
43
77
|
this.http.interceptors.request.use((config) => {
|
|
44
78
|
if (this.verbose) {
|
|
@@ -150,6 +184,59 @@ class PredictionMarketExchange {
|
|
|
150
184
|
async fetchMarkets(params) {
|
|
151
185
|
return this.fetchMarketsImpl(params);
|
|
152
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Fetch markets with cursor-based pagination backed by a stable in-memory snapshot.
|
|
189
|
+
*
|
|
190
|
+
* On the first call (or when no cursor is supplied), fetches all markets once and
|
|
191
|
+
* caches them. Subsequent calls with a cursor returned from a previous call slice
|
|
192
|
+
* directly from the cached snapshot — no additional API calls are made.
|
|
193
|
+
*
|
|
194
|
+
* The snapshot is invalidated after `snapshotTTL` ms (configured via `ExchangeOptions`
|
|
195
|
+
* in the constructor). A request using a cursor from an expired snapshot throws
|
|
196
|
+
* `'Cursor has expired'`.
|
|
197
|
+
*
|
|
198
|
+
* @param params.limit - Page size (default: return all markets)
|
|
199
|
+
* @param params.cursor - Opaque cursor returned by a previous call
|
|
200
|
+
* @returns PaginatedMarketsResult with data, total, and optional nextCursor
|
|
201
|
+
*/
|
|
202
|
+
async fetchMarketsPaginated(params) {
|
|
203
|
+
const limit = params?.limit;
|
|
204
|
+
const cursor = params?.cursor;
|
|
205
|
+
if (cursor) {
|
|
206
|
+
// Cursor encodes: snapshotId:offset
|
|
207
|
+
const sep = cursor.indexOf(':');
|
|
208
|
+
const snapshotId = cursor.substring(0, sep);
|
|
209
|
+
const offset = parseInt(cursor.substring(sep + 1), 10);
|
|
210
|
+
if (!this._snapshot ||
|
|
211
|
+
this._snapshot.id !== snapshotId ||
|
|
212
|
+
(this._snapshotTTL > 0 && Date.now() - this._snapshot.takenAt > this._snapshotTTL)) {
|
|
213
|
+
throw new Error('Cursor has expired');
|
|
214
|
+
}
|
|
215
|
+
const markets = this._snapshot.markets;
|
|
216
|
+
const slice = limit !== undefined ? markets.slice(offset, offset + limit) : markets.slice(offset);
|
|
217
|
+
const nextOffset = offset + slice.length;
|
|
218
|
+
const nextCursor = nextOffset < markets.length ? `${snapshotId}:${nextOffset}` : undefined;
|
|
219
|
+
return { data: slice, total: markets.length, nextCursor };
|
|
220
|
+
}
|
|
221
|
+
// No cursor — (re)fetch snapshot
|
|
222
|
+
if (!this._snapshot ||
|
|
223
|
+
this._snapshotTTL === 0 ||
|
|
224
|
+
Date.now() - this._snapshot.takenAt > this._snapshotTTL) {
|
|
225
|
+
const markets = await this.fetchMarketsImpl();
|
|
226
|
+
this._snapshot = {
|
|
227
|
+
markets,
|
|
228
|
+
takenAt: Date.now(),
|
|
229
|
+
id: Math.random().toString(36).slice(2),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const markets = this._snapshot.markets;
|
|
233
|
+
if (!limit) {
|
|
234
|
+
return { data: markets, total: markets.length, nextCursor: undefined };
|
|
235
|
+
}
|
|
236
|
+
const slice = markets.slice(0, limit);
|
|
237
|
+
const nextCursor = limit < markets.length ? `${this._snapshot.id}:${limit}` : undefined;
|
|
238
|
+
return { data: slice, total: markets.length, nextCursor };
|
|
239
|
+
}
|
|
153
240
|
/**
|
|
154
241
|
* Fetch events with optional keyword search.
|
|
155
242
|
* Events group related markets together (e.g., "Who will be Fed Chair?" contains multiple candidate markets).
|
|
@@ -444,6 +531,15 @@ class PredictionMarketExchange {
|
|
|
444
531
|
async fetchOpenOrders(marketId) {
|
|
445
532
|
throw new Error("Method fetchOpenOrders not implemented.");
|
|
446
533
|
}
|
|
534
|
+
async fetchMyTrades(params) {
|
|
535
|
+
throw new Error("Method fetchMyTrades not implemented.");
|
|
536
|
+
}
|
|
537
|
+
async fetchClosedOrders(params) {
|
|
538
|
+
throw new Error("Method fetchClosedOrders not implemented.");
|
|
539
|
+
}
|
|
540
|
+
async fetchAllOrders(params) {
|
|
541
|
+
throw new Error("Method fetchAllOrders not implemented.");
|
|
542
|
+
}
|
|
447
543
|
/**
|
|
448
544
|
* Fetch current user positions across all markets.
|
|
449
545
|
*
|
|
@@ -19,6 +19,9 @@ 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;
|
|
22
25
|
};
|
|
23
26
|
private auth?;
|
|
24
27
|
private connection;
|
|
@@ -28,6 +28,9 @@ 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,
|
|
31
34
|
};
|
|
32
35
|
auth;
|
|
33
36
|
connection;
|
|
@@ -43,6 +46,7 @@ class BaoziExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
43
46
|
credentials = options;
|
|
44
47
|
}
|
|
45
48
|
super(credentials);
|
|
49
|
+
this.rateLimit = 500;
|
|
46
50
|
rpcUrl = rpcUrl
|
|
47
51
|
|| process.env.BAOZI_RPC_URL
|
|
48
52
|
|| 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-02-
|
|
3
|
+
* Generated at: 2026-02-22T14:48:41.786Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const kalshiApiSpec: {
|
|
@@ -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-02-
|
|
6
|
+
* Generated at: 2026-02-22T14:48:41.786Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.kalshiApiSpec = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams } from '../../BaseExchange';
|
|
2
|
-
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, Balance, Order, Position, CreateOrderParams } from '../../types';
|
|
1
|
+
import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams, MyTradesParams, OrderHistoryParams } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Balance, Order, Position, CreateOrderParams } from '../../types';
|
|
3
3
|
import { KalshiWebSocketConfig } from './websocket';
|
|
4
4
|
export type { KalshiWebSocketConfig };
|
|
5
5
|
export interface KalshiExchangeOptions {
|
|
@@ -21,6 +21,9 @@ export declare class KalshiExchange extends PredictionMarketExchange {
|
|
|
21
21
|
fetchBalance: true;
|
|
22
22
|
watchOrderBook: true;
|
|
23
23
|
watchTrades: true;
|
|
24
|
+
fetchMyTrades: true;
|
|
25
|
+
fetchClosedOrders: true;
|
|
26
|
+
fetchAllOrders: true;
|
|
24
27
|
};
|
|
25
28
|
private auth?;
|
|
26
29
|
private wsConfig?;
|
|
@@ -39,7 +42,11 @@ export declare class KalshiExchange extends PredictionMarketExchange {
|
|
|
39
42
|
cancelOrder(orderId: string): Promise<Order>;
|
|
40
43
|
fetchOrder(orderId: string): Promise<Order>;
|
|
41
44
|
fetchOpenOrders(marketId?: string): Promise<Order[]>;
|
|
45
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
46
|
+
fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
47
|
+
fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
42
48
|
fetchPositions(): Promise<Position[]>;
|
|
49
|
+
private mapKalshiOrder;
|
|
43
50
|
private mapKalshiOrderStatus;
|
|
44
51
|
private ws?;
|
|
45
52
|
watchOrderBook(id: string, limit?: number): Promise<OrderBook>;
|
|
@@ -27,6 +27,9 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
27
27
|
fetchBalance: true,
|
|
28
28
|
watchOrderBook: true,
|
|
29
29
|
watchTrades: true,
|
|
30
|
+
fetchMyTrades: true,
|
|
31
|
+
fetchClosedOrders: true,
|
|
32
|
+
fetchAllOrders: true,
|
|
30
33
|
};
|
|
31
34
|
auth;
|
|
32
35
|
wsConfig;
|
|
@@ -44,6 +47,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
44
47
|
credentials = options;
|
|
45
48
|
}
|
|
46
49
|
super(credentials);
|
|
50
|
+
this.rateLimit = 100;
|
|
47
51
|
this.wsConfig = wsConfig;
|
|
48
52
|
if (credentials?.apiKey && credentials?.privateKey) {
|
|
49
53
|
this.auth = new auth_1.KalshiAuth(credentials);
|
|
@@ -205,20 +209,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
205
209
|
}
|
|
206
210
|
async fetchOrder(orderId) {
|
|
207
211
|
const data = await this.callApi('GetOrder', { order_id: orderId });
|
|
208
|
-
|
|
209
|
-
return {
|
|
210
|
-
id: order.order_id,
|
|
211
|
-
marketId: order.ticker,
|
|
212
|
-
outcomeId: order.ticker,
|
|
213
|
-
side: order.side === 'yes' ? 'buy' : 'sell',
|
|
214
|
-
type: order.type === 'limit' ? 'limit' : 'market',
|
|
215
|
-
price: order.yes_price ? order.yes_price / 100 : undefined,
|
|
216
|
-
amount: order.count,
|
|
217
|
-
status: this.mapKalshiOrderStatus(order.status),
|
|
218
|
-
filled: order.count - (order.remaining_count || 0),
|
|
219
|
-
remaining: order.remaining_count || 0,
|
|
220
|
-
timestamp: new Date(order.created_time).getTime(),
|
|
221
|
-
};
|
|
212
|
+
return this.mapKalshiOrder(data.order);
|
|
222
213
|
}
|
|
223
214
|
async fetchOpenOrders(marketId) {
|
|
224
215
|
const queryParams = { status: 'resting' };
|
|
@@ -227,20 +218,70 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
227
218
|
}
|
|
228
219
|
const data = await this.callApi('GetOrders', queryParams);
|
|
229
220
|
const orders = data.orders || [];
|
|
230
|
-
return orders.map((order) => (
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
221
|
+
return orders.map((order) => this.mapKalshiOrder(order));
|
|
222
|
+
}
|
|
223
|
+
async fetchMyTrades(params) {
|
|
224
|
+
const queryParams = {};
|
|
225
|
+
if (params?.outcomeId || params?.marketId) {
|
|
226
|
+
queryParams.ticker = (params.outcomeId || params.marketId).replace(/-NO$/, '');
|
|
227
|
+
}
|
|
228
|
+
if (params?.since)
|
|
229
|
+
queryParams.min_ts = Math.floor(params.since.getTime() / 1000);
|
|
230
|
+
if (params?.until)
|
|
231
|
+
queryParams.max_ts = Math.floor(params.until.getTime() / 1000);
|
|
232
|
+
if (params?.limit)
|
|
233
|
+
queryParams.limit = params.limit;
|
|
234
|
+
if (params?.cursor)
|
|
235
|
+
queryParams.cursor = params.cursor;
|
|
236
|
+
const data = await this.callApi('GetFills', queryParams);
|
|
237
|
+
return (data.fills || []).map((f) => ({
|
|
238
|
+
id: f.fill_id,
|
|
239
|
+
timestamp: new Date(f.created_time).getTime(),
|
|
240
|
+
price: f.yes_price / 100,
|
|
241
|
+
amount: f.count,
|
|
242
|
+
side: f.side === 'yes' ? 'buy' : 'sell',
|
|
243
|
+
orderId: f.order_id,
|
|
242
244
|
}));
|
|
243
245
|
}
|
|
246
|
+
async fetchClosedOrders(params) {
|
|
247
|
+
const queryParams = {};
|
|
248
|
+
if (params?.marketId)
|
|
249
|
+
queryParams.ticker = params.marketId;
|
|
250
|
+
if (params?.until)
|
|
251
|
+
queryParams.max_ts = Math.floor(params.until.getTime() / 1000);
|
|
252
|
+
if (params?.limit)
|
|
253
|
+
queryParams.limit = params.limit;
|
|
254
|
+
if (params?.cursor)
|
|
255
|
+
queryParams.cursor = params.cursor;
|
|
256
|
+
const data = await this.callApi('GetHistoricalOrders', queryParams);
|
|
257
|
+
return (data.orders || []).map((o) => this.mapKalshiOrder(o));
|
|
258
|
+
}
|
|
259
|
+
async fetchAllOrders(params) {
|
|
260
|
+
const queryParams = {};
|
|
261
|
+
if (params?.marketId)
|
|
262
|
+
queryParams.ticker = params.marketId;
|
|
263
|
+
if (params?.since)
|
|
264
|
+
queryParams.min_ts = Math.floor(params.since.getTime() / 1000);
|
|
265
|
+
if (params?.until)
|
|
266
|
+
queryParams.max_ts = Math.floor(params.until.getTime() / 1000);
|
|
267
|
+
if (params?.limit)
|
|
268
|
+
queryParams.limit = params.limit;
|
|
269
|
+
const historicalParams = { ...queryParams };
|
|
270
|
+
delete historicalParams.min_ts; // GetHistoricalOrders only supports max_ts
|
|
271
|
+
const [liveData, historicalData] = await Promise.all([
|
|
272
|
+
this.callApi('GetOrders', queryParams),
|
|
273
|
+
this.callApi('GetHistoricalOrders', historicalParams),
|
|
274
|
+
]);
|
|
275
|
+
const seen = new Set();
|
|
276
|
+
const all = [];
|
|
277
|
+
for (const o of [...(liveData.orders || []), ...(historicalData.orders || [])]) {
|
|
278
|
+
if (!seen.has(o.order_id)) {
|
|
279
|
+
seen.add(o.order_id);
|
|
280
|
+
all.push(this.mapKalshiOrder(o));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return all.sort((a, b) => b.timestamp - a.timestamp);
|
|
284
|
+
}
|
|
244
285
|
async fetchPositions() {
|
|
245
286
|
const data = await this.callApi('GetPositions');
|
|
246
287
|
const positions = data.market_positions || [];
|
|
@@ -259,9 +300,25 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
259
300
|
};
|
|
260
301
|
});
|
|
261
302
|
}
|
|
303
|
+
// Helper to map a raw Kalshi order object to a unified Order
|
|
304
|
+
mapKalshiOrder(order) {
|
|
305
|
+
return {
|
|
306
|
+
id: order.order_id,
|
|
307
|
+
marketId: order.ticker,
|
|
308
|
+
outcomeId: order.ticker,
|
|
309
|
+
side: order.side === 'yes' ? 'buy' : 'sell',
|
|
310
|
+
type: order.type === 'limit' ? 'limit' : 'market',
|
|
311
|
+
price: order.yes_price ? order.yes_price / 100 : undefined,
|
|
312
|
+
amount: order.count,
|
|
313
|
+
status: this.mapKalshiOrderStatus(order.status),
|
|
314
|
+
filled: order.count - (order.remaining_count || 0),
|
|
315
|
+
remaining: order.remaining_count || 0,
|
|
316
|
+
timestamp: new Date(order.created_time).getTime(),
|
|
317
|
+
};
|
|
318
|
+
}
|
|
262
319
|
// Helper to map Kalshi order status to unified status
|
|
263
320
|
mapKalshiOrderStatus(status) {
|
|
264
|
-
switch (status.toLowerCase()) {
|
|
321
|
+
switch ((status ?? '').toLowerCase()) {
|
|
265
322
|
case 'resting':
|
|
266
323
|
return 'open';
|
|
267
324
|
case 'canceled':
|
|
@@ -318,6 +318,186 @@ describe('KalshiExchange', () => {
|
|
|
318
318
|
});
|
|
319
319
|
});
|
|
320
320
|
});
|
|
321
|
+
describe('Trading History Methods', () => {
|
|
322
|
+
beforeEach(() => {
|
|
323
|
+
exchange = new kalshi_1.KalshiExchange(mockCredentials);
|
|
324
|
+
});
|
|
325
|
+
describe('fetchMyTrades', () => {
|
|
326
|
+
it('should map GetFills response to UserTrade array', async () => {
|
|
327
|
+
const mockResponse = {
|
|
328
|
+
data: {
|
|
329
|
+
fills: [
|
|
330
|
+
{
|
|
331
|
+
fill_id: 'fill-abc',
|
|
332
|
+
order_id: 'order-123',
|
|
333
|
+
created_time: '2026-01-13T12:00:00Z',
|
|
334
|
+
yes_price: 55,
|
|
335
|
+
count: 10,
|
|
336
|
+
side: 'yes',
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
fill_id: 'fill-def',
|
|
340
|
+
order_id: 'order-456',
|
|
341
|
+
created_time: '2026-01-13T13:00:00Z',
|
|
342
|
+
yes_price: 45,
|
|
343
|
+
count: 5,
|
|
344
|
+
side: 'no',
|
|
345
|
+
},
|
|
346
|
+
],
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
mockAxiosInstance.request.mockResolvedValue(mockResponse);
|
|
350
|
+
const trades = await exchange.fetchMyTrades();
|
|
351
|
+
expect(Array.isArray(trades)).toBe(true);
|
|
352
|
+
expect(trades).toHaveLength(2);
|
|
353
|
+
expect(trades[0].id).toBe('fill-abc');
|
|
354
|
+
expect(trades[0].orderId).toBe('order-123');
|
|
355
|
+
expect(trades[0].price).toBe(0.55); // 55 / 100
|
|
356
|
+
expect(trades[0].amount).toBe(10);
|
|
357
|
+
expect(trades[0].side).toBe('buy'); // 'yes' => 'buy'
|
|
358
|
+
expect(trades[1].id).toBe('fill-def');
|
|
359
|
+
expect(trades[1].side).toBe('sell'); // 'no' => 'sell'
|
|
360
|
+
expect(trades[1].price).toBe(0.45); // 45 / 100
|
|
361
|
+
});
|
|
362
|
+
it('should pass outcomeId as ticker (stripping -NO suffix) and date params', async () => {
|
|
363
|
+
const mockResponse = { data: { fills: [] } };
|
|
364
|
+
mockAxiosInstance.request.mockResolvedValue(mockResponse);
|
|
365
|
+
await exchange.fetchMyTrades({
|
|
366
|
+
outcomeId: 'TEST-MARKET-NO',
|
|
367
|
+
since: new Date('2026-01-01T00:00:00Z'),
|
|
368
|
+
until: new Date('2026-01-31T00:00:00Z'),
|
|
369
|
+
limit: 50,
|
|
370
|
+
});
|
|
371
|
+
expect(mockAxiosInstance.request).toHaveBeenCalledWith(expect.objectContaining({
|
|
372
|
+
params: expect.objectContaining({
|
|
373
|
+
ticker: 'TEST-MARKET', // -NO stripped
|
|
374
|
+
min_ts: Math.floor(new Date('2026-01-01T00:00:00Z').getTime() / 1000),
|
|
375
|
+
max_ts: Math.floor(new Date('2026-01-31T00:00:00Z').getTime() / 1000),
|
|
376
|
+
limit: 50,
|
|
377
|
+
}),
|
|
378
|
+
}));
|
|
379
|
+
});
|
|
380
|
+
it('should return empty array when fills is missing', async () => {
|
|
381
|
+
mockAxiosInstance.request.mockResolvedValue({ data: {} });
|
|
382
|
+
const trades = await exchange.fetchMyTrades();
|
|
383
|
+
expect(trades).toHaveLength(0);
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
describe('fetchClosedOrders', () => {
|
|
387
|
+
it('should map GetHistoricalOrders response to Order array', async () => {
|
|
388
|
+
const mockResponse = {
|
|
389
|
+
data: {
|
|
390
|
+
orders: [
|
|
391
|
+
{
|
|
392
|
+
order_id: 'hist-order-1',
|
|
393
|
+
ticker: 'TEST-MARKET',
|
|
394
|
+
side: 'yes',
|
|
395
|
+
type: 'limit',
|
|
396
|
+
yes_price: 60,
|
|
397
|
+
count: 8,
|
|
398
|
+
remaining_count: 0,
|
|
399
|
+
status: 'executed',
|
|
400
|
+
created_time: '2026-01-10T10:00:00Z',
|
|
401
|
+
},
|
|
402
|
+
],
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
mockAxiosInstance.request.mockResolvedValue(mockResponse);
|
|
406
|
+
const orders = await exchange.fetchClosedOrders();
|
|
407
|
+
expect(orders).toHaveLength(1);
|
|
408
|
+
expect(orders[0].id).toBe('hist-order-1');
|
|
409
|
+
expect(orders[0].marketId).toBe('TEST-MARKET');
|
|
410
|
+
expect(orders[0].side).toBe('buy'); // 'yes' => 'buy'
|
|
411
|
+
expect(orders[0].price).toBe(0.60); // 60 / 100
|
|
412
|
+
expect(orders[0].amount).toBe(8);
|
|
413
|
+
expect(orders[0].filled).toBe(8); // count - remaining_count (0)
|
|
414
|
+
expect(orders[0].remaining).toBe(0);
|
|
415
|
+
expect(orders[0].status).toBe('filled'); // 'executed' => 'filled'
|
|
416
|
+
});
|
|
417
|
+
it('should pass marketId as ticker and limit', async () => {
|
|
418
|
+
const mockResponse = { data: { orders: [] } };
|
|
419
|
+
mockAxiosInstance.request.mockResolvedValue(mockResponse);
|
|
420
|
+
await exchange.fetchClosedOrders({ marketId: 'TEST-MARKET', limit: 25 });
|
|
421
|
+
expect(mockAxiosInstance.request).toHaveBeenCalledWith(expect.objectContaining({
|
|
422
|
+
params: expect.objectContaining({
|
|
423
|
+
ticker: 'TEST-MARKET',
|
|
424
|
+
limit: 25,
|
|
425
|
+
}),
|
|
426
|
+
}));
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
describe('fetchAllOrders', () => {
|
|
430
|
+
it('should merge live and historical orders, dedup, and sort descending by timestamp', async () => {
|
|
431
|
+
const liveResponse = {
|
|
432
|
+
data: {
|
|
433
|
+
orders: [
|
|
434
|
+
{
|
|
435
|
+
order_id: 'order-live-1',
|
|
436
|
+
ticker: 'TEST',
|
|
437
|
+
side: 'yes',
|
|
438
|
+
type: 'limit',
|
|
439
|
+
yes_price: 50,
|
|
440
|
+
count: 5,
|
|
441
|
+
remaining_count: 5,
|
|
442
|
+
status: 'resting',
|
|
443
|
+
created_time: '2026-01-15T10:00:00Z',
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
// duplicate that also appears in historical
|
|
447
|
+
order_id: 'order-hist-1',
|
|
448
|
+
ticker: 'TEST',
|
|
449
|
+
side: 'no',
|
|
450
|
+
type: 'limit',
|
|
451
|
+
yes_price: 40,
|
|
452
|
+
count: 3,
|
|
453
|
+
remaining_count: 0,
|
|
454
|
+
status: 'executed',
|
|
455
|
+
created_time: '2026-01-10T08:00:00Z',
|
|
456
|
+
},
|
|
457
|
+
],
|
|
458
|
+
},
|
|
459
|
+
};
|
|
460
|
+
const historicalResponse = {
|
|
461
|
+
data: {
|
|
462
|
+
orders: [
|
|
463
|
+
{
|
|
464
|
+
order_id: 'order-hist-1', // duplicate
|
|
465
|
+
ticker: 'TEST',
|
|
466
|
+
side: 'no',
|
|
467
|
+
type: 'limit',
|
|
468
|
+
yes_price: 40,
|
|
469
|
+
count: 3,
|
|
470
|
+
remaining_count: 0,
|
|
471
|
+
status: 'executed',
|
|
472
|
+
created_time: '2026-01-10T08:00:00Z',
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
order_id: 'order-hist-2',
|
|
476
|
+
ticker: 'TEST',
|
|
477
|
+
side: 'yes',
|
|
478
|
+
type: 'limit',
|
|
479
|
+
yes_price: 55,
|
|
480
|
+
count: 10,
|
|
481
|
+
remaining_count: 0,
|
|
482
|
+
status: 'executed',
|
|
483
|
+
created_time: '2026-01-05T06:00:00Z',
|
|
484
|
+
},
|
|
485
|
+
],
|
|
486
|
+
},
|
|
487
|
+
};
|
|
488
|
+
mockAxiosInstance.request
|
|
489
|
+
.mockResolvedValueOnce(liveResponse)
|
|
490
|
+
.mockResolvedValueOnce(historicalResponse);
|
|
491
|
+
const orders = await exchange.fetchAllOrders();
|
|
492
|
+
// 3 unique orders (order-hist-1 deduped)
|
|
493
|
+
expect(orders).toHaveLength(3);
|
|
494
|
+
// sorted descending: order-live-1, order-hist-1, order-hist-2
|
|
495
|
+
expect(orders[0].id).toBe('order-live-1');
|
|
496
|
+
expect(orders[1].id).toBe('order-hist-1');
|
|
497
|
+
expect(orders[2].id).toBe('order-hist-2');
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
}); // Trading History Methods
|
|
321
501
|
describe('Order Status Mapping', () => {
|
|
322
502
|
beforeEach(() => {
|
|
323
503
|
exchange = new kalshi_1.KalshiExchange(mockCredentials);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
|
|
3
|
-
* Generated at: 2026-02-
|
|
3
|
+
* Generated at: 2026-02-22T14:48:41.831Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const limitlessApiSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.limitlessApiSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/limitless/Limitless.yaml
|
|
6
|
-
* Generated at: 2026-02-
|
|
6
|
+
* Generated at: 2026-02-22T14:48:41.831Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.limitlessApiSpec = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PredictionMarketExchange, MarketFetchParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams } from '../../BaseExchange';
|
|
2
|
-
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, Order, Position, Balance, CreateOrderParams } from '../../types';
|
|
1
|
+
import { PredictionMarketExchange, MarketFetchParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams, MyTradesParams, OrderHistoryParams } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Order, Position, Balance, CreateOrderParams } from '../../types';
|
|
3
3
|
import { LimitlessWebSocketConfig } from './websocket';
|
|
4
4
|
export type { LimitlessWebSocketConfig };
|
|
5
5
|
export interface LimitlessExchangeOptions {
|
|
@@ -21,6 +21,9 @@ export declare class LimitlessExchange extends PredictionMarketExchange {
|
|
|
21
21
|
fetchBalance: true;
|
|
22
22
|
watchOrderBook: true;
|
|
23
23
|
watchTrades: true;
|
|
24
|
+
fetchMyTrades: true;
|
|
25
|
+
fetchClosedOrders: true;
|
|
26
|
+
fetchAllOrders: true;
|
|
24
27
|
};
|
|
25
28
|
private auth?;
|
|
26
29
|
private client?;
|
|
@@ -42,6 +45,9 @@ export declare class LimitlessExchange extends PredictionMarketExchange {
|
|
|
42
45
|
cancelOrder(orderId: string): Promise<Order>;
|
|
43
46
|
fetchOrder(orderId: string): Promise<Order>;
|
|
44
47
|
fetchOpenOrders(marketId?: string): Promise<Order[]>;
|
|
48
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
49
|
+
fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
50
|
+
fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
45
51
|
fetchPositions(): Promise<Position[]>;
|
|
46
52
|
fetchBalance(): Promise<Balance[]>;
|
|
47
53
|
private ws?;
|
|
@@ -31,6 +31,9 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
31
31
|
fetchBalance: true,
|
|
32
32
|
watchOrderBook: true,
|
|
33
33
|
watchTrades: true,
|
|
34
|
+
fetchMyTrades: true,
|
|
35
|
+
fetchClosedOrders: true,
|
|
36
|
+
fetchAllOrders: true,
|
|
34
37
|
};
|
|
35
38
|
auth;
|
|
36
39
|
client;
|
|
@@ -53,6 +56,7 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
53
56
|
credentials = options;
|
|
54
57
|
}
|
|
55
58
|
super(credentials);
|
|
59
|
+
this.rateLimit = 200;
|
|
56
60
|
this.wsConfig = wsConfig;
|
|
57
61
|
// Initialize auth if API key or private key are provided
|
|
58
62
|
// API key is now the primary authentication method
|
|
@@ -225,6 +229,68 @@ class LimitlessExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
225
229
|
throw errors_1.limitlessErrorMapper.mapError(error);
|
|
226
230
|
}
|
|
227
231
|
}
|
|
232
|
+
async fetchMyTrades(params) {
|
|
233
|
+
const auth = this.ensureAuth();
|
|
234
|
+
try {
|
|
235
|
+
const response = await this.http.get('https://api.limitless.exchange/portfolio/trades', {
|
|
236
|
+
headers: { Authorization: `Bearer ${auth.getApiKey()}` },
|
|
237
|
+
});
|
|
238
|
+
const trades = Array.isArray(response.data) ? response.data : (response.data?.data || []);
|
|
239
|
+
return trades.map((t) => ({
|
|
240
|
+
id: t.id || String(t.timestamp),
|
|
241
|
+
timestamp: t.createdAt ? new Date(t.createdAt).getTime() : (t.timestamp || 0),
|
|
242
|
+
price: parseFloat(t.price || '0'),
|
|
243
|
+
amount: parseFloat(t.quantity || t.amount || '0'),
|
|
244
|
+
side: (t.side || '').toLowerCase() === 'buy' ? 'buy' : 'sell',
|
|
245
|
+
orderId: t.orderId,
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
throw errors_1.limitlessErrorMapper.mapError(error);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async fetchClosedOrders(params) {
|
|
253
|
+
const client = this.ensureClient();
|
|
254
|
+
if (!params?.marketId) {
|
|
255
|
+
console.warn('Limitless: fetchClosedOrders requires marketId (slug). Returning [].');
|
|
256
|
+
return [];
|
|
257
|
+
}
|
|
258
|
+
const orders = await client.getOrders(params.marketId, ['MATCHED']);
|
|
259
|
+
return orders.map((o) => ({
|
|
260
|
+
id: o.id,
|
|
261
|
+
marketId: params.marketId,
|
|
262
|
+
outcomeId: o.tokenId || 'unknown',
|
|
263
|
+
side: o.side.toLowerCase(),
|
|
264
|
+
type: 'limit',
|
|
265
|
+
price: parseFloat(o.price),
|
|
266
|
+
amount: parseFloat(o.quantity),
|
|
267
|
+
status: 'filled',
|
|
268
|
+
filled: parseFloat(o.quantity),
|
|
269
|
+
remaining: 0,
|
|
270
|
+
timestamp: o.createdAt ? new Date(o.createdAt).getTime() : Date.now(),
|
|
271
|
+
}));
|
|
272
|
+
}
|
|
273
|
+
async fetchAllOrders(params) {
|
|
274
|
+
const client = this.ensureClient();
|
|
275
|
+
if (!params?.marketId) {
|
|
276
|
+
console.warn('Limitless: fetchAllOrders requires marketId (slug). Returning [].');
|
|
277
|
+
return [];
|
|
278
|
+
}
|
|
279
|
+
const orders = await client.getOrders(params.marketId, ['LIVE', 'MATCHED']);
|
|
280
|
+
return orders.map((o) => ({
|
|
281
|
+
id: o.id,
|
|
282
|
+
marketId: params.marketId,
|
|
283
|
+
outcomeId: o.tokenId || 'unknown',
|
|
284
|
+
side: o.side.toLowerCase(),
|
|
285
|
+
type: 'limit',
|
|
286
|
+
price: parseFloat(o.price),
|
|
287
|
+
amount: parseFloat(o.quantity),
|
|
288
|
+
status: o.status === 'LIVE' ? 'open' : 'filled',
|
|
289
|
+
filled: o.status === 'MATCHED' ? parseFloat(o.quantity) : 0,
|
|
290
|
+
remaining: o.status === 'LIVE' ? parseFloat(o.quantity) : 0,
|
|
291
|
+
timestamp: o.createdAt ? new Date(o.createdAt).getTime() : Date.now(),
|
|
292
|
+
}));
|
|
293
|
+
}
|
|
228
294
|
async fetchPositions() {
|
|
229
295
|
const auth = this.ensureAuth();
|
|
230
296
|
const address = auth.getAddress();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
|
|
3
|
-
* Generated at: 2026-02-
|
|
3
|
+
* Generated at: 2026-02-22T14:48:41.842Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const myriadApiSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.myriadApiSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/myriad/myriad.yaml
|
|
6
|
-
* Generated at: 2026-02-
|
|
6
|
+
* Generated at: 2026-02-22T14:48:41.842Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.myriadApiSpec = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams } from '../../BaseExchange';
|
|
2
|
-
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, Balance, Order, Position, CreateOrderParams } from '../../types';
|
|
1
|
+
import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams, MyTradesParams } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Balance, Order, Position, CreateOrderParams } from '../../types';
|
|
3
3
|
export declare class MyriadExchange extends PredictionMarketExchange {
|
|
4
4
|
readonly has: {
|
|
5
5
|
fetchMarkets: true;
|
|
@@ -15,6 +15,9 @@ export declare class MyriadExchange extends PredictionMarketExchange {
|
|
|
15
15
|
fetchBalance: "emulated";
|
|
16
16
|
watchOrderBook: "emulated";
|
|
17
17
|
watchTrades: "emulated";
|
|
18
|
+
fetchMyTrades: true;
|
|
19
|
+
fetchClosedOrders: false;
|
|
20
|
+
fetchAllOrders: false;
|
|
18
21
|
};
|
|
19
22
|
private auth?;
|
|
20
23
|
private ws?;
|
|
@@ -29,6 +32,7 @@ export declare class MyriadExchange extends PredictionMarketExchange {
|
|
|
29
32
|
fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams): Promise<PriceCandle[]>;
|
|
30
33
|
fetchOrderBook(id: string): Promise<OrderBook>;
|
|
31
34
|
fetchTrades(id: string, params: TradesParams | HistoryFilterParams): Promise<Trade[]>;
|
|
35
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
32
36
|
createOrder(params: CreateOrderParams): Promise<Order>;
|
|
33
37
|
cancelOrder(_orderId: string): Promise<Order>;
|
|
34
38
|
fetchOrder(_orderId: string): Promise<Order>;
|
|
@@ -28,11 +28,15 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
28
28
|
fetchBalance: 'emulated',
|
|
29
29
|
watchOrderBook: 'emulated',
|
|
30
30
|
watchTrades: 'emulated',
|
|
31
|
+
fetchMyTrades: true,
|
|
32
|
+
fetchClosedOrders: false,
|
|
33
|
+
fetchAllOrders: false,
|
|
31
34
|
};
|
|
32
35
|
auth;
|
|
33
36
|
ws;
|
|
34
37
|
constructor(credentials) {
|
|
35
38
|
super(credentials);
|
|
39
|
+
this.rateLimit = 500;
|
|
36
40
|
if (credentials?.apiKey) {
|
|
37
41
|
this.auth = new auth_1.MyriadAuth(credentials);
|
|
38
42
|
}
|
|
@@ -118,6 +122,34 @@ class MyriadExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
118
122
|
side: t.action === 'buy' ? 'buy' : 'sell',
|
|
119
123
|
}));
|
|
120
124
|
}
|
|
125
|
+
async fetchMyTrades(params) {
|
|
126
|
+
const walletAddress = this.ensureAuth().walletAddress;
|
|
127
|
+
if (!walletAddress) {
|
|
128
|
+
throw new errors_2.AuthenticationError('fetchMyTrades requires a wallet address. Pass privateKey as the wallet address in credentials.', 'Myriad');
|
|
129
|
+
}
|
|
130
|
+
const queryParams = { address: walletAddress };
|
|
131
|
+
if (params?.marketId) {
|
|
132
|
+
const parts = params.marketId.split(':');
|
|
133
|
+
if (parts.length >= 2)
|
|
134
|
+
queryParams.market_id = parts[1];
|
|
135
|
+
}
|
|
136
|
+
if (params?.since)
|
|
137
|
+
queryParams.since = Math.floor(params.since.getTime() / 1000);
|
|
138
|
+
if (params?.until)
|
|
139
|
+
queryParams.until = Math.floor(params.until.getTime() / 1000);
|
|
140
|
+
if (params?.limit)
|
|
141
|
+
queryParams.limit = params.limit;
|
|
142
|
+
const data = await this.callApi('getUsersEvents', queryParams);
|
|
143
|
+
const events = data.data || data.events || [];
|
|
144
|
+
const tradeEvents = events.filter((e) => e.action === 'buy' || e.action === 'sell');
|
|
145
|
+
return tradeEvents.map((t, i) => ({
|
|
146
|
+
id: `${t.blockNumber || t.timestamp}-${i}`,
|
|
147
|
+
timestamp: (t.timestamp || 0) * 1000,
|
|
148
|
+
price: t.shares > 0 ? Number(t.value) / Number(t.shares) : 0,
|
|
149
|
+
amount: Number(t.shares || 0),
|
|
150
|
+
side: t.action === 'buy' ? 'buy' : 'sell',
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
121
153
|
// ------------------------------------------------------------------------
|
|
122
154
|
// Trading
|
|
123
155
|
// ------------------------------------------------------------------------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
|
|
3
|
-
* Generated at: 2026-02-
|
|
3
|
+
* Generated at: 2026-02-22T14:48:41.794Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const polymarketClobSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.polymarketClobSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketClobAPI.yaml
|
|
6
|
-
* Generated at: 2026-02-
|
|
6
|
+
* Generated at: 2026-02-22T14:48:41.794Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.polymarketClobSpec = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
|
|
3
|
-
* Generated at: 2026-02-
|
|
3
|
+
* Generated at: 2026-02-22T14:48:41.812Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const polymarketDataSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.polymarketDataSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/Polymarket_Data_API.yaml
|
|
6
|
-
* Generated at: 2026-02-
|
|
6
|
+
* Generated at: 2026-02-22T14:48:41.812Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.polymarketDataSpec = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
|
|
3
|
-
* Generated at: 2026-02-
|
|
3
|
+
* Generated at: 2026-02-22T14:48:41.808Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const polymarketGammaSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.polymarketGammaSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/polymarket/PolymarketGammaAPI.yaml
|
|
6
|
-
* Generated at: 2026-02-
|
|
6
|
+
* Generated at: 2026-02-22T14:48:41.808Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.polymarketGammaSpec = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams } from '../../BaseExchange';
|
|
2
|
-
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, Order, Position, Balance, CreateOrderParams } from '../../types';
|
|
1
|
+
import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, OHLCVParams, TradesParams, ExchangeCredentials, EventFetchParams, MyTradesParams } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Order, Position, Balance, CreateOrderParams } from '../../types';
|
|
3
3
|
import { PolymarketWebSocketConfig } from './websocket';
|
|
4
4
|
export type { PolymarketWebSocketConfig };
|
|
5
5
|
export interface PolymarketExchangeOptions {
|
|
@@ -21,6 +21,9 @@ export declare class PolymarketExchange extends PredictionMarketExchange {
|
|
|
21
21
|
fetchBalance: true;
|
|
22
22
|
watchOrderBook: true;
|
|
23
23
|
watchTrades: true;
|
|
24
|
+
fetchMyTrades: true;
|
|
25
|
+
fetchClosedOrders: false;
|
|
26
|
+
fetchAllOrders: false;
|
|
24
27
|
};
|
|
25
28
|
private auth?;
|
|
26
29
|
private wsConfig?;
|
|
@@ -71,6 +74,7 @@ export declare class PolymarketExchange extends PredictionMarketExchange {
|
|
|
71
74
|
cancelOrder(orderId: string): Promise<Order>;
|
|
72
75
|
fetchOrder(orderId: string): Promise<Order>;
|
|
73
76
|
fetchOpenOrders(marketId?: string): Promise<Order[]>;
|
|
77
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
74
78
|
fetchPositions(): Promise<Position[]>;
|
|
75
79
|
fetchBalance(): Promise<Balance[]>;
|
|
76
80
|
private ws?;
|
|
@@ -33,6 +33,9 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
33
33
|
fetchBalance: true,
|
|
34
34
|
watchOrderBook: true,
|
|
35
35
|
watchTrades: true,
|
|
36
|
+
fetchMyTrades: true,
|
|
37
|
+
fetchClosedOrders: false,
|
|
38
|
+
fetchAllOrders: false,
|
|
36
39
|
};
|
|
37
40
|
auth;
|
|
38
41
|
wsConfig;
|
|
@@ -52,6 +55,7 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
52
55
|
credentials = options;
|
|
53
56
|
}
|
|
54
57
|
super(credentials);
|
|
58
|
+
this.rateLimit = 200;
|
|
55
59
|
this.wsConfig = wsConfig;
|
|
56
60
|
// Initialize auth if credentials are provided
|
|
57
61
|
if (credentials?.privateKey) {
|
|
@@ -341,6 +345,29 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
341
345
|
throw errors_1.polymarketErrorMapper.mapError(error);
|
|
342
346
|
}
|
|
343
347
|
}
|
|
348
|
+
async fetchMyTrades(params) {
|
|
349
|
+
const auth = this.ensureAuth();
|
|
350
|
+
const address = await auth.getEffectiveFunderAddress();
|
|
351
|
+
const queryParams = { user: address };
|
|
352
|
+
if (params?.marketId)
|
|
353
|
+
queryParams.market = params.marketId;
|
|
354
|
+
if (params?.limit)
|
|
355
|
+
queryParams.limit = params.limit;
|
|
356
|
+
if (params?.since)
|
|
357
|
+
queryParams.start = Math.floor(params.since.getTime() / 1000);
|
|
358
|
+
if (params?.until)
|
|
359
|
+
queryParams.end = Math.floor(params.until.getTime() / 1000);
|
|
360
|
+
const data = await this.callApi('getTrades', queryParams);
|
|
361
|
+
const trades = Array.isArray(data) ? data : (data.data || []);
|
|
362
|
+
return trades.map((t) => ({
|
|
363
|
+
id: t.id || t.transactionHash || String(t.timestamp),
|
|
364
|
+
timestamp: typeof t.timestamp === 'number' ? t.timestamp * 1000 : Date.now(),
|
|
365
|
+
price: parseFloat(t.price || '0'),
|
|
366
|
+
amount: parseFloat(t.size || t.amount || '0'),
|
|
367
|
+
side: t.side === 'BUY' ? 'buy' : t.side === 'SELL' ? 'sell' : 'unknown',
|
|
368
|
+
orderId: t.orderId,
|
|
369
|
+
}));
|
|
370
|
+
}
|
|
344
371
|
async fetchPositions() {
|
|
345
372
|
try {
|
|
346
373
|
const auth = this.ensureAuth();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
|
|
3
|
-
* Generated at: 2026-02-
|
|
3
|
+
* Generated at: 2026-02-22T14:48:41.835Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const probableApiSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.probableApiSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/probable/probable.yaml
|
|
6
|
-
* Generated at: 2026-02-
|
|
6
|
+
* Generated at: 2026-02-22T14:48:41.835Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.probableApiSpec = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PredictionMarketExchange, MarketFetchParams, EventFetchParams, ExchangeCredentials, OHLCVParams, HistoryFilterParams, TradesParams } from '../../BaseExchange';
|
|
2
|
-
import { UnifiedMarket, UnifiedEvent, OrderBook, PriceCandle, Trade, Order, Position, Balance, CreateOrderParams } from '../../types';
|
|
1
|
+
import { PredictionMarketExchange, MarketFetchParams, EventFetchParams, ExchangeCredentials, OHLCVParams, HistoryFilterParams, TradesParams, MyTradesParams } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, UnifiedEvent, OrderBook, PriceCandle, Trade, UserTrade, Order, Position, Balance, CreateOrderParams } from '../../types';
|
|
3
3
|
import { ProbableWebSocketConfig } from './websocket';
|
|
4
4
|
export declare class ProbableExchange extends PredictionMarketExchange {
|
|
5
5
|
readonly has: {
|
|
@@ -16,6 +16,9 @@ export declare class ProbableExchange extends PredictionMarketExchange {
|
|
|
16
16
|
fetchBalance: true;
|
|
17
17
|
watchOrderBook: true;
|
|
18
18
|
watchTrades: false;
|
|
19
|
+
fetchMyTrades: true;
|
|
20
|
+
fetchClosedOrders: false;
|
|
21
|
+
fetchAllOrders: false;
|
|
19
22
|
};
|
|
20
23
|
private auth?;
|
|
21
24
|
private ws?;
|
|
@@ -66,6 +69,7 @@ export declare class ProbableExchange extends PredictionMarketExchange {
|
|
|
66
69
|
getEventBySlug(slug: string): Promise<UnifiedEvent | null>;
|
|
67
70
|
fetchOrderBook(id: string): Promise<OrderBook>;
|
|
68
71
|
fetchOHLCV(id: string, params: OHLCVParams | HistoryFilterParams): Promise<PriceCandle[]>;
|
|
72
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
69
73
|
createOrder(params: CreateOrderParams): Promise<Order>;
|
|
70
74
|
/**
|
|
71
75
|
* Cancel an order.
|
|
@@ -47,12 +47,16 @@ class ProbableExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
47
47
|
fetchBalance: true,
|
|
48
48
|
watchOrderBook: true,
|
|
49
49
|
watchTrades: false,
|
|
50
|
+
fetchMyTrades: true,
|
|
51
|
+
fetchClosedOrders: false,
|
|
52
|
+
fetchAllOrders: false,
|
|
50
53
|
};
|
|
51
54
|
auth;
|
|
52
55
|
ws;
|
|
53
56
|
wsConfig;
|
|
54
57
|
constructor(credentials, wsConfig) {
|
|
55
58
|
super(credentials);
|
|
59
|
+
this.rateLimit = 500;
|
|
56
60
|
this.wsConfig = wsConfig;
|
|
57
61
|
if (credentials?.privateKey && credentials?.apiKey && credentials?.apiSecret && credentials?.passphrase) {
|
|
58
62
|
this.auth = new auth_1.ProbableAuth(credentials);
|
|
@@ -178,6 +182,25 @@ class ProbableExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
178
182
|
}
|
|
179
183
|
return candles;
|
|
180
184
|
}
|
|
185
|
+
async fetchMyTrades(params) {
|
|
186
|
+
const auth = this.ensureAuth();
|
|
187
|
+
const address = auth.getAddress();
|
|
188
|
+
const queryParams = { user: address };
|
|
189
|
+
if (params?.limit)
|
|
190
|
+
queryParams.limit = params.limit;
|
|
191
|
+
const data = await this.callApi('getPublicApiV1Trades', queryParams);
|
|
192
|
+
const trades = Array.isArray(data) ? data : (data.data || []);
|
|
193
|
+
return trades.map((t) => ({
|
|
194
|
+
id: String(t.tradeId || t.id || t.timestamp),
|
|
195
|
+
timestamp: typeof t.time === 'number'
|
|
196
|
+
? (t.time > 1e12 ? t.time : t.time * 1000)
|
|
197
|
+
: Date.now(),
|
|
198
|
+
price: parseFloat(t.price || '0'),
|
|
199
|
+
amount: parseFloat(t.qty || t.size || t.amount || '0'),
|
|
200
|
+
side: (t.side || '').toLowerCase() === 'buy' ? 'buy' : 'sell',
|
|
201
|
+
orderId: t.orderId,
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
181
204
|
// --------------------------------------------------------------------------
|
|
182
205
|
// Trading Methods
|
|
183
206
|
// --------------------------------------------------------------------------
|
package/dist/types.d.ts
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare class Throttler {
|
|
2
|
+
private tokens;
|
|
3
|
+
private queue;
|
|
4
|
+
private running;
|
|
5
|
+
private lastTimestamp;
|
|
6
|
+
private refillRate;
|
|
7
|
+
private capacity;
|
|
8
|
+
private delay;
|
|
9
|
+
constructor(config: {
|
|
10
|
+
refillRate: number;
|
|
11
|
+
capacity: number;
|
|
12
|
+
delay: number;
|
|
13
|
+
});
|
|
14
|
+
throttle(cost?: number): Promise<void>;
|
|
15
|
+
private loop;
|
|
16
|
+
private sleep;
|
|
17
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Throttler = void 0;
|
|
4
|
+
class Throttler {
|
|
5
|
+
tokens = 0;
|
|
6
|
+
queue = [];
|
|
7
|
+
running = false;
|
|
8
|
+
lastTimestamp = 0;
|
|
9
|
+
refillRate;
|
|
10
|
+
capacity;
|
|
11
|
+
delay;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.refillRate = config.refillRate;
|
|
14
|
+
this.capacity = config.capacity;
|
|
15
|
+
this.delay = config.delay;
|
|
16
|
+
}
|
|
17
|
+
async throttle(cost = 1) {
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
this.queue.push({ resolve, cost });
|
|
20
|
+
if (!this.running) {
|
|
21
|
+
this.running = true;
|
|
22
|
+
this.loop();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
async loop() {
|
|
27
|
+
while (this.queue.length > 0) {
|
|
28
|
+
const now = Date.now();
|
|
29
|
+
if (this.lastTimestamp > 0) {
|
|
30
|
+
const elapsed = now - this.lastTimestamp;
|
|
31
|
+
this.tokens = Math.min(this.tokens + elapsed * this.refillRate, this.capacity);
|
|
32
|
+
}
|
|
33
|
+
this.lastTimestamp = now;
|
|
34
|
+
const head = this.queue[0];
|
|
35
|
+
if (this.tokens >= 0) {
|
|
36
|
+
this.tokens -= head.cost;
|
|
37
|
+
head.resolve();
|
|
38
|
+
this.queue.shift();
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
await this.sleep(this.delay);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
this.running = false;
|
|
45
|
+
}
|
|
46
|
+
sleep(ms) {
|
|
47
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.Throttler = Throttler;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmxt-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
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",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"test": "jest -c jest.config.js",
|
|
30
30
|
"server": "tsx watch src/server/index.ts",
|
|
31
31
|
"server:prod": "node dist/server/index.js",
|
|
32
|
-
"generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.
|
|
33
|
-
"generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.
|
|
32
|
+
"generate:sdk:python": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g python -o ../sdks/python/generated --package-name pmxt_internal --additional-properties=projectName=pmxt-internal,packageVersion=2.12.0,library=urllib3",
|
|
33
|
+
"generate:sdk:typescript": "npx @openapitools/openapi-generator-cli generate -i src/server/openapi.yaml -g typescript-fetch -o ../sdks/typescript/generated --additional-properties=npmName=pmxtjs,npmVersion=2.12.0,supportsES6=true,typescriptThreePlus=true && node ../sdks/typescript/scripts/fix-generated.js",
|
|
34
34
|
"fetch:openapi": "node scripts/fetch-openapi-specs.js",
|
|
35
35
|
"extract:jsdoc": "node ../scripts/extract-jsdoc.js",
|
|
36
36
|
"generate:docs": "npm run extract:jsdoc && node ../scripts/generate-api-docs.js",
|