pmxtjs 2.8.0 → 2.9.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.
@@ -104,14 +104,16 @@ export class ServerManager {
104
104
  }
105
105
  }
106
106
  // Locate pmxt-ensure-server
107
- let launcherPath = 'pmxt-ensure-server'; // Default to PATH
107
+ const isWindows = process.platform === 'win32';
108
+ const launcherName = isWindows ? 'pmxt-ensure-server.js' : 'pmxt-ensure-server';
109
+ let launcherPath = launcherName; // Default to PATH
108
110
  try {
109
111
  // Try to resolve from pmxt-core dependency
110
112
  // For CommonJS build (which is primary), we can use require directly
111
113
  // For ESM build, this will be transpiled appropriately
112
114
  const corePackageJson = require.resolve('pmxt-core/package.json');
113
115
  const coreDir = dirname(corePackageJson);
114
- const binPath = join(coreDir, 'bin', 'pmxt-ensure-server');
116
+ const binPath = join(coreDir, 'bin', launcherName);
115
117
  if (existsSync(binPath)) {
116
118
  launcherPath = binPath;
117
119
  }
@@ -122,8 +124,11 @@ export class ServerManager {
122
124
  }
123
125
  // Try to start the server using pmxt-ensure-server
124
126
  const { spawn } = await import("child_process");
127
+ // On Windows, .js scripts must be run via node explicitly
128
+ const spawnCmd = launcherPath.endsWith('.js') ? 'node' : launcherPath;
129
+ const spawnArgs = launcherPath.endsWith('.js') ? [launcherPath] : [];
125
130
  try {
126
- const proc = spawn(launcherPath, [], {
131
+ const proc = spawn(spawnCmd, spawnArgs, {
127
132
  detached: true,
128
133
  stdio: "ignore",
129
134
  });
@@ -140,14 +140,16 @@ class ServerManager {
140
140
  }
141
141
  }
142
142
  // Locate pmxt-ensure-server
143
- let launcherPath = 'pmxt-ensure-server'; // Default to PATH
143
+ const isWindows = process.platform === 'win32';
144
+ const launcherName = isWindows ? 'pmxt-ensure-server.js' : 'pmxt-ensure-server';
145
+ let launcherPath = launcherName; // Default to PATH
144
146
  try {
145
147
  // Try to resolve from pmxt-core dependency
146
148
  // For CommonJS build (which is primary), we can use require directly
147
149
  // For ESM build, this will be transpiled appropriately
148
150
  const corePackageJson = require.resolve('pmxt-core/package.json');
149
151
  const coreDir = (0, path_1.dirname)(corePackageJson);
150
- const binPath = (0, path_1.join)(coreDir, 'bin', 'pmxt-ensure-server');
152
+ const binPath = (0, path_1.join)(coreDir, 'bin', launcherName);
151
153
  if ((0, fs_1.existsSync)(binPath)) {
152
154
  launcherPath = binPath;
153
155
  }
@@ -158,8 +160,11 @@ class ServerManager {
158
160
  }
159
161
  // Try to start the server using pmxt-ensure-server
160
162
  const { spawn } = await Promise.resolve().then(() => __importStar(require("child_process")));
163
+ // On Windows, .js scripts must be run via node explicitly
164
+ const spawnCmd = launcherPath.endsWith('.js') ? 'node' : launcherPath;
165
+ const spawnArgs = launcherPath.endsWith('.js') ? [launcherPath] : [];
161
166
  try {
162
- const proc = spawn(launcherPath, [], {
167
+ const proc = spawn(spawnCmd, spawnArgs, {
163
168
  detached: true,
164
169
  stdio: "ignore",
165
170
  });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "description": "OpenAPI client for pmxtjs",
5
5
  "author": "OpenAPI-Generator",
6
6
  "repository": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "description": "Unified prediction market data API - The ccxt for prediction markets",
5
5
  "author": "PMXT Contributors",
6
6
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "unified"
43
43
  ],
44
44
  "dependencies": {
45
- "pmxt-core": "2.8.0"
45
+ "pmxt-core": "2.9.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/jest": "^30.0.0",
@@ -130,7 +130,9 @@ export class ServerManager {
130
130
  }
131
131
 
132
132
  // Locate pmxt-ensure-server
133
- let launcherPath = 'pmxt-ensure-server'; // Default to PATH
133
+ const isWindows = process.platform === 'win32';
134
+ const launcherName = isWindows ? 'pmxt-ensure-server.js' : 'pmxt-ensure-server';
135
+ let launcherPath = launcherName; // Default to PATH
134
136
 
135
137
  try {
136
138
  // Try to resolve from pmxt-core dependency
@@ -138,7 +140,7 @@ export class ServerManager {
138
140
  // For ESM build, this will be transpiled appropriately
139
141
  const corePackageJson = require.resolve('pmxt-core/package.json');
140
142
  const coreDir = dirname(corePackageJson);
141
- const binPath = join(coreDir, 'bin', 'pmxt-ensure-server');
143
+ const binPath = join(coreDir, 'bin', launcherName);
142
144
 
143
145
  if (existsSync(binPath)) {
144
146
  launcherPath = binPath;
@@ -151,8 +153,12 @@ export class ServerManager {
151
153
  // Try to start the server using pmxt-ensure-server
152
154
  const { spawn } = await import("child_process");
153
155
 
156
+ // On Windows, .js scripts must be run via node explicitly
157
+ const spawnCmd = launcherPath.endsWith('.js') ? 'node' : launcherPath;
158
+ const spawnArgs = launcherPath.endsWith('.js') ? [launcherPath] : [];
159
+
154
160
  try {
155
- const proc = spawn(launcherPath, [], {
161
+ const proc = spawn(spawnCmd, spawnArgs, {
156
162
  detached: true,
157
163
  stdio: "ignore",
158
164
  });
package/pmxt/client.js DELETED
@@ -1,957 +0,0 @@
1
- "use strict";
2
- /**
3
- * Exchange client implementations.
4
- *
5
- * This module provides clean, TypeScript-friendly wrappers around the auto-generated
6
- * OpenAPI client, matching the Python API exactly.
7
- */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.Limitless = exports.Kalshi = exports.Polymarket = exports.Exchange = void 0;
10
- const index_js_1 = require("../generated/src/index.js");
11
- const models_js_1 = require("./models.js");
12
- const server_manager_js_1 = require("./server-manager.js");
13
- // Converter functions
14
- function convertMarket(raw) {
15
- const outcomes = (raw.outcomes || []).map((o) => ({
16
- outcomeId: o.outcomeId,
17
- label: o.label,
18
- price: o.price,
19
- priceChange24h: o.priceChange24h,
20
- metadata: o.metadata,
21
- }));
22
- const convertOutcome = (o) => o ? ({
23
- outcomeId: o.outcomeId,
24
- label: o.label,
25
- price: o.price,
26
- priceChange24h: o.priceChange24h,
27
- metadata: o.metadata,
28
- }) : undefined;
29
- return {
30
- marketId: raw.marketId,
31
- title: raw.title,
32
- outcomes,
33
- volume24h: raw.volume24h || 0,
34
- liquidity: raw.liquidity || 0,
35
- url: raw.url,
36
- description: raw.description,
37
- resolutionDate: raw.resolutionDate ? new Date(raw.resolutionDate) : undefined,
38
- volume: raw.volume,
39
- openInterest: raw.openInterest,
40
- image: raw.image,
41
- category: raw.category,
42
- tags: raw.tags,
43
- yes: convertOutcome(raw.yes),
44
- no: convertOutcome(raw.no),
45
- up: convertOutcome(raw.up),
46
- down: convertOutcome(raw.down),
47
- };
48
- }
49
- function convertCandle(raw) {
50
- return {
51
- timestamp: raw.timestamp,
52
- open: raw.open,
53
- high: raw.high,
54
- low: raw.low,
55
- close: raw.close,
56
- volume: raw.volume,
57
- };
58
- }
59
- function convertOrderBook(raw) {
60
- const bids = (raw.bids || []).map((b) => ({
61
- price: b.price,
62
- size: b.size,
63
- }));
64
- const asks = (raw.asks || []).map((a) => ({
65
- price: a.price,
66
- size: a.size,
67
- }));
68
- return {
69
- bids,
70
- asks,
71
- timestamp: raw.timestamp,
72
- };
73
- }
74
- function convertTrade(raw) {
75
- return {
76
- id: raw.id,
77
- timestamp: raw.timestamp,
78
- price: raw.price,
79
- amount: raw.amount,
80
- side: raw.side || "unknown",
81
- };
82
- }
83
- function convertOrder(raw) {
84
- return {
85
- id: raw.id,
86
- marketId: raw.marketId,
87
- outcomeId: raw.outcomeId,
88
- side: raw.side,
89
- type: raw.type,
90
- amount: raw.amount,
91
- status: raw.status,
92
- filled: raw.filled,
93
- remaining: raw.remaining,
94
- timestamp: raw.timestamp,
95
- price: raw.price,
96
- fee: raw.fee,
97
- };
98
- }
99
- function convertPosition(raw) {
100
- return {
101
- marketId: raw.marketId,
102
- outcomeId: raw.outcomeId,
103
- outcomeLabel: raw.outcomeLabel,
104
- size: raw.size,
105
- entryPrice: raw.entryPrice,
106
- currentPrice: raw.currentPrice,
107
- unrealizedPnL: raw.unrealizedPnL,
108
- realizedPnL: raw.realizedPnL,
109
- };
110
- }
111
- function convertBalance(raw) {
112
- return {
113
- currency: raw.currency,
114
- total: raw.total,
115
- available: raw.available,
116
- locked: raw.locked,
117
- };
118
- }
119
- function convertEvent(raw) {
120
- const markets = models_js_1.MarketList.from((raw.markets || []).map(convertMarket));
121
- return {
122
- id: raw.id,
123
- title: raw.title,
124
- description: raw.description,
125
- slug: raw.slug,
126
- markets,
127
- url: raw.url,
128
- image: raw.image,
129
- category: raw.category,
130
- tags: raw.tags,
131
- };
132
- }
133
- /**
134
- * Base class for prediction market exchanges.
135
- *
136
- * This provides a unified interface for interacting with different
137
- * prediction market platforms (Polymarket, Kalshi, etc.).
138
- */
139
- class Exchange {
140
- constructor(exchangeName, options = {}) {
141
- this.exchangeName = exchangeName.toLowerCase();
142
- this.apiKey = options.apiKey;
143
- this.privateKey = options.privateKey;
144
- this.proxyAddress = options.proxyAddress;
145
- this.signatureType = options.signatureType;
146
- let baseUrl = options.baseUrl || "http://localhost:3847";
147
- const autoStartServer = options.autoStartServer !== false;
148
- // Initialize server manager
149
- this.serverManager = new server_manager_js_1.ServerManager({ baseUrl });
150
- // Configure the API client with the initial base URL (will be updated if port changes)
151
- this.config = new index_js_1.Configuration({ basePath: baseUrl });
152
- this.api = new index_js_1.DefaultApi(this.config);
153
- // Initialize the server connection asynchronously
154
- this.initPromise = this.initializeServer(autoStartServer);
155
- }
156
- async initializeServer(autoStartServer) {
157
- if (autoStartServer) {
158
- try {
159
- await this.serverManager.ensureServerRunning();
160
- // Get the actual port the server is running on
161
- // (may differ from default if default port was busy)
162
- const actualPort = this.serverManager.getRunningPort();
163
- const newBaseUrl = `http://localhost:${actualPort}`;
164
- const accessToken = this.serverManager.getAccessToken();
165
- const headers = {};
166
- if (accessToken) {
167
- headers['x-pmxt-access-token'] = accessToken;
168
- }
169
- // Update API client with actual base URL
170
- this.config = new index_js_1.Configuration({
171
- basePath: newBaseUrl,
172
- headers
173
- });
174
- this.api = new index_js_1.DefaultApi(this.config);
175
- }
176
- catch (error) {
177
- throw new Error(`Failed to start PMXT server: ${error}\n\n` +
178
- `Please ensure 'pmxt-core' is installed: npm install -g pmxt-core\n` +
179
- `Or start the server manually: pmxt-server`);
180
- }
181
- }
182
- }
183
- handleResponse(response) {
184
- if (!response.success) {
185
- const error = response.error || {};
186
- throw new Error(error.message || "Unknown error");
187
- }
188
- return response.data;
189
- }
190
- getCredentials() {
191
- if (!this.apiKey && !this.privateKey) {
192
- return undefined;
193
- }
194
- return {
195
- apiKey: this.apiKey,
196
- privateKey: this.privateKey,
197
- funderAddress: this.proxyAddress,
198
- signatureType: this.signatureType,
199
- };
200
- }
201
- // Market Data Methods
202
- /**
203
- * Get active markets from the exchange.
204
- *
205
- * @param params - Optional filter parameters
206
- * @returns List of unified markets
207
- *
208
- * @example
209
- * ```typescript
210
- * const markets = await exchange.fetchMarkets({ limit: 20, sort: "volume" });
211
- * ```
212
- */
213
- async fetchMarkets(params) {
214
- await this.initPromise;
215
- try {
216
- const args = [];
217
- if (params) {
218
- args.push(params);
219
- }
220
- const requestBody = {
221
- args,
222
- credentials: this.getCredentials()
223
- };
224
- const response = await this.api.fetchMarkets({
225
- exchange: this.exchangeName,
226
- fetchMarketsRequest: requestBody,
227
- });
228
- const data = this.handleResponse(response);
229
- return data.map(convertMarket);
230
- }
231
- catch (error) {
232
- throw new Error(`Failed to fetch markets: ${error}`);
233
- }
234
- }
235
- /**
236
- * Get historical price candles.
237
- *
238
- * @param outcomeId - Outcome ID (from market.outcomes[].outcomeId)
239
- * @param params - History filter parameters
240
- * @returns List of price candles
241
- *
242
- * @example
243
- * ```typescript
244
- * const markets = await exchange.fetchMarkets({ query: "Trump" });
245
- * const outcomeId = markets[0].outcomes[0].outcomeId;
246
- * const candles = await exchange.fetchOHLCV(outcomeId, {
247
- * resolution: "1h",
248
- * limit: 100
249
- * });
250
- * ```
251
- */
252
- async fetchOHLCV(outcomeId, params) {
253
- await this.initPromise;
254
- try {
255
- const paramsDict = { resolution: params.resolution };
256
- if (params.start) {
257
- paramsDict.start = params.start.toISOString();
258
- }
259
- if (params.end) {
260
- paramsDict.end = params.end.toISOString();
261
- }
262
- if (params.limit) {
263
- paramsDict.limit = params.limit;
264
- }
265
- const requestBody = {
266
- args: [outcomeId, paramsDict],
267
- credentials: this.getCredentials()
268
- };
269
- const response = await this.api.fetchOHLCV({
270
- exchange: this.exchangeName,
271
- fetchOHLCVRequest: requestBody,
272
- });
273
- const data = this.handleResponse(response);
274
- return data.map(convertCandle);
275
- }
276
- catch (error) {
277
- throw new Error(`Failed to fetch OHLCV: ${error}`);
278
- }
279
- }
280
- /**
281
- * Get current order book for an outcome.
282
- *
283
- * @param outcomeId - Outcome ID
284
- * @returns Current order book
285
- *
286
- * @example
287
- * ```typescript
288
- * const orderBook = await exchange.fetchOrderBook(outcomeId);
289
- * console.log(`Best bid: ${orderBook.bids[0].price}`);
290
- * console.log(`Best ask: ${orderBook.asks[0].price}`);
291
- * ```
292
- */
293
- async fetchOrderBook(outcomeId) {
294
- await this.initPromise;
295
- try {
296
- const requestBody = {
297
- args: [outcomeId],
298
- credentials: this.getCredentials()
299
- };
300
- const response = await this.api.fetchOrderBook({
301
- exchange: this.exchangeName,
302
- fetchOrderBookRequest: requestBody,
303
- });
304
- const data = this.handleResponse(response);
305
- return convertOrderBook(data);
306
- }
307
- catch (error) {
308
- throw new Error(`Failed to fetch order book: ${error}`);
309
- }
310
- }
311
- /**
312
- * Get trade history for an outcome.
313
- *
314
- * Note: Polymarket requires API key.
315
- *
316
- * @param outcomeId - Outcome ID
317
- * @param params - History filter parameters
318
- * @returns List of trades
319
- */
320
- async fetchTrades(outcomeId, params) {
321
- await this.initPromise;
322
- try {
323
- const paramsDict = { resolution: params.resolution };
324
- if (params.limit) {
325
- paramsDict.limit = params.limit;
326
- }
327
- const requestBody = {
328
- args: [outcomeId, paramsDict],
329
- credentials: this.getCredentials()
330
- };
331
- const response = await this.api.fetchTrades({
332
- exchange: this.exchangeName,
333
- fetchTradesRequest: requestBody,
334
- });
335
- const data = this.handleResponse(response);
336
- return data.map(convertTrade);
337
- }
338
- catch (error) {
339
- throw new Error(`Failed to fetch trades: ${error}`);
340
- }
341
- }
342
- // WebSocket Streaming Methods
343
- /**
344
- * Watch real-time order book updates via WebSocket.
345
- *
346
- * Returns a promise that resolves with the next order book update.
347
- * Call repeatedly in a loop to stream updates (CCXT Pro pattern).
348
- *
349
- * @param outcomeId - Outcome ID to watch
350
- * @param limit - Optional depth limit for order book
351
- * @returns Next order book update
352
- *
353
- * @example
354
- * ```typescript
355
- * // Stream order book updates
356
- * while (true) {
357
- * const orderBook = await exchange.watchOrderBook(outcomeId);
358
- * console.log(`Best bid: ${orderBook.bids[0].price}`);
359
- * console.log(`Best ask: ${orderBook.asks[0].price}`);
360
- * }
361
- * ```
362
- */
363
- async watchOrderBook(outcomeId, limit) {
364
- await this.initPromise;
365
- try {
366
- const args = [outcomeId];
367
- if (limit !== undefined) {
368
- args.push(limit);
369
- }
370
- const requestBody = {
371
- args,
372
- credentials: this.getCredentials()
373
- };
374
- const response = await this.api.watchOrderBook({
375
- exchange: this.exchangeName,
376
- watchOrderBookRequest: requestBody,
377
- });
378
- const data = this.handleResponse(response);
379
- return convertOrderBook(data);
380
- }
381
- catch (error) {
382
- throw new Error(`Failed to watch order book: ${error}`);
383
- }
384
- }
385
- /**
386
- * Watch real-time trade updates via WebSocket.
387
- *
388
- * Returns a promise that resolves with the next trade(s).
389
- * Call repeatedly in a loop to stream updates (CCXT Pro pattern).
390
- *
391
- * @param outcomeId - Outcome ID to watch
392
- * @param since - Optional timestamp to filter trades from
393
- * @param limit - Optional limit for number of trades
394
- * @returns Next trade update(s)
395
- *
396
- * @example
397
- * ```typescript
398
- * // Stream trade updates
399
- * while (true) {
400
- * const trades = await exchange.watchTrades(outcomeId);
401
- * for (const trade of trades) {
402
- * console.log(`Trade: ${trade.price} @ ${trade.amount}`);
403
- * }
404
- * }
405
- * ```
406
- */
407
- async watchTrades(outcomeId, since, limit) {
408
- await this.initPromise;
409
- try {
410
- const args = [outcomeId];
411
- if (since !== undefined) {
412
- args.push(since);
413
- }
414
- if (limit !== undefined) {
415
- args.push(limit);
416
- }
417
- const requestBody = {
418
- args,
419
- credentials: this.getCredentials()
420
- };
421
- const response = await this.api.watchTrades({
422
- exchange: this.exchangeName,
423
- watchTradesRequest: requestBody,
424
- });
425
- const data = this.handleResponse(response);
426
- return data.map(convertTrade);
427
- }
428
- catch (error) {
429
- throw new Error(`Failed to watch trades: ${error}`);
430
- }
431
- }
432
- // Trading Methods (require authentication)
433
- /**
434
- * Create a new order.
435
- *
436
- * @param params - Order parameters
437
- * @returns Created order
438
- *
439
- * @example
440
- * ```typescript
441
- * const order = await exchange.createOrder({
442
- * marketId: "663583",
443
- * outcomeId: "10991849...",
444
- * side: "buy",
445
- * type: "limit",
446
- * amount: 10,
447
- * price: 0.55
448
- * });
449
- * ```
450
- */
451
- async createOrder(params) {
452
- await this.initPromise;
453
- try {
454
- const paramsDict = {
455
- marketId: params.marketId,
456
- outcomeId: params.outcomeId,
457
- side: params.side,
458
- type: params.type,
459
- amount: params.amount,
460
- };
461
- if (params.price !== undefined) {
462
- paramsDict.price = params.price;
463
- }
464
- if (params.fee !== undefined) {
465
- paramsDict.fee = params.fee;
466
- }
467
- const requestBody = {
468
- args: [paramsDict],
469
- credentials: this.getCredentials()
470
- };
471
- const response = await this.api.createOrder({
472
- exchange: this.exchangeName,
473
- createOrderRequest: requestBody,
474
- });
475
- const data = this.handleResponse(response);
476
- return convertOrder(data);
477
- }
478
- catch (error) {
479
- throw new Error(`Failed to create order: ${error}`);
480
- }
481
- }
482
- /**
483
- * Cancel an open order.
484
- *
485
- * @param orderId - Order ID to cancel
486
- * @returns Cancelled order
487
- */
488
- async cancelOrder(orderId) {
489
- await this.initPromise;
490
- try {
491
- const requestBody = {
492
- args: [orderId],
493
- credentials: this.getCredentials()
494
- };
495
- const response = await this.api.cancelOrder({
496
- exchange: this.exchangeName,
497
- cancelOrderRequest: requestBody,
498
- });
499
- const data = this.handleResponse(response);
500
- return convertOrder(data);
501
- }
502
- catch (error) {
503
- throw new Error(`Failed to cancel order: ${error}`);
504
- }
505
- }
506
- /**
507
- * Get details of a specific order.
508
- *
509
- * @param orderId - Order ID
510
- * @returns Order details
511
- */
512
- async fetchOrder(orderId) {
513
- await this.initPromise;
514
- try {
515
- const requestBody = {
516
- args: [orderId],
517
- credentials: this.getCredentials()
518
- };
519
- const response = await this.api.fetchOrder({
520
- exchange: this.exchangeName,
521
- cancelOrderRequest: requestBody,
522
- });
523
- const data = this.handleResponse(response);
524
- return convertOrder(data);
525
- }
526
- catch (error) {
527
- throw new Error(`Failed to fetch order: ${error}`);
528
- }
529
- }
530
- /**
531
- * Get all open orders, optionally filtered by market.
532
- *
533
- * @param marketId - Optional market ID to filter by
534
- * @returns List of open orders
535
- */
536
- async fetchOpenOrders(marketId) {
537
- await this.initPromise;
538
- try {
539
- const args = [];
540
- if (marketId) {
541
- args.push(marketId);
542
- }
543
- const requestBody = {
544
- args,
545
- credentials: this.getCredentials()
546
- };
547
- const response = await this.api.fetchOpenOrders({
548
- exchange: this.exchangeName,
549
- fetchOpenOrdersRequest: requestBody,
550
- });
551
- const data = this.handleResponse(response);
552
- return data.map(convertOrder);
553
- }
554
- catch (error) {
555
- throw new Error(`Failed to fetch open orders: ${error}`);
556
- }
557
- }
558
- // Account Methods
559
- /**
560
- * Get current positions across all markets.
561
- *
562
- * @returns List of positions
563
- */
564
- async fetchPositions() {
565
- await this.initPromise;
566
- try {
567
- const requestBody = {
568
- args: [],
569
- credentials: this.getCredentials()
570
- };
571
- const response = await this.api.fetchPositions({
572
- exchange: this.exchangeName,
573
- fetchPositionsRequest: requestBody,
574
- });
575
- const data = this.handleResponse(response);
576
- return data.map(convertPosition);
577
- }
578
- catch (error) {
579
- throw new Error(`Failed to fetch positions: ${error}`);
580
- }
581
- }
582
- /**
583
- * Get account balance.
584
- *
585
- * @returns List of balances (by currency)
586
- */
587
- async fetchBalance() {
588
- await this.initPromise;
589
- try {
590
- const requestBody = {
591
- args: [],
592
- credentials: this.getCredentials()
593
- };
594
- const response = await this.api.fetchBalance({
595
- exchange: this.exchangeName,
596
- fetchPositionsRequest: requestBody,
597
- });
598
- const data = this.handleResponse(response);
599
- return data.map(convertBalance);
600
- }
601
- catch (error) {
602
- throw new Error(`Failed to fetch balance: ${error}`);
603
- }
604
- }
605
- /**
606
- * Calculate the average execution price for a given amount by walking the order book.
607
- * Uses the sidecar server for calculation to ensure consistency.
608
- *
609
- * @param orderBook - The current order book
610
- * @param side - 'buy' or 'sell'
611
- * @param amount - The amount to execute
612
- * @returns The volume-weighted average price, or 0 if insufficient liquidity
613
- */
614
- async getExecutionPrice(orderBook, side, amount) {
615
- const result = await this.getExecutionPriceDetailed(orderBook, side, amount);
616
- return result.fullyFilled ? result.price : 0;
617
- }
618
- /**
619
- * Calculate detailed execution price information.
620
- * Uses the sidecar server for calculation to ensure consistency.
621
- *
622
- * @param orderBook - The current order book
623
- * @param side - 'buy' or 'sell'
624
- * @param amount - The amount to execute
625
- * @returns Detailed execution result
626
- */
627
- async getExecutionPriceDetailed(orderBook, side, amount) {
628
- await this.initPromise;
629
- try {
630
- const body = {
631
- args: [orderBook, side, amount]
632
- };
633
- const credentials = this.getCredentials();
634
- if (credentials) {
635
- body.credentials = credentials;
636
- }
637
- const url = `${this.config.basePath}/api/${this.exchangeName}/getExecutionPriceDetailed`;
638
- const response = await fetch(url, {
639
- method: 'POST',
640
- headers: {
641
- 'Content-Type': 'application/json',
642
- ...this.config.headers
643
- },
644
- body: JSON.stringify(body)
645
- });
646
- if (!response.ok) {
647
- const error = await response.json().catch(() => ({}));
648
- throw new Error(error.error?.message || response.statusText);
649
- }
650
- const json = await response.json();
651
- return this.handleResponse(json);
652
- }
653
- catch (error) {
654
- throw new Error(`Failed to get execution price: ${error}`);
655
- }
656
- }
657
- // ----------------------------------------------------------------------------
658
- // Filtering Methods
659
- // ----------------------------------------------------------------------------
660
- /**
661
- * Filter markets based on criteria or custom function.
662
- *
663
- * @param markets - Array of markets to filter
664
- * @param criteria - Filter criteria object, string (simple text search), or predicate function
665
- * @returns Filtered array of markets
666
- *
667
- * @example Simple text search
668
- * api.filterMarkets(markets, 'Trump')
669
- *
670
- * @example Advanced filtering
671
- * api.filterMarkets(markets, {
672
- * text: 'Trump',
673
- * searchIn: ['title', 'tags'],
674
- * volume24h: { min: 10000 },
675
- * category: 'Politics',
676
- * price: { outcome: 'yes', max: 0.5 }
677
- * })
678
- *
679
- * @example Custom predicate
680
- * api.filterMarkets(markets, m => m.liquidity > 5000 && m.yes?.price < 0.3)
681
- */
682
- filterMarkets(markets, criteria) {
683
- // Handle predicate function
684
- if (typeof criteria === 'function') {
685
- return markets.filter(criteria);
686
- }
687
- // Handle simple string search
688
- if (typeof criteria === 'string') {
689
- const lowerQuery = criteria.toLowerCase();
690
- return markets.filter(m => m.title.toLowerCase().includes(lowerQuery));
691
- }
692
- // Handle criteria object
693
- return markets.filter(market => {
694
- // Text search
695
- if (criteria.text) {
696
- const lowerQuery = criteria.text.toLowerCase();
697
- const searchIn = criteria.searchIn || ['title'];
698
- let textMatch = false;
699
- for (const field of searchIn) {
700
- if (field === 'title' && market.title?.toLowerCase().includes(lowerQuery)) {
701
- textMatch = true;
702
- break;
703
- }
704
- if (field === 'description' && market.description?.toLowerCase().includes(lowerQuery)) {
705
- textMatch = true;
706
- break;
707
- }
708
- if (field === 'category' && market.category?.toLowerCase().includes(lowerQuery)) {
709
- textMatch = true;
710
- break;
711
- }
712
- if (field === 'tags' && market.tags?.some(tag => tag.toLowerCase().includes(lowerQuery))) {
713
- textMatch = true;
714
- break;
715
- }
716
- if (field === 'outcomes' && market.outcomes?.some(o => o.label.toLowerCase().includes(lowerQuery))) {
717
- textMatch = true;
718
- break;
719
- }
720
- }
721
- if (!textMatch)
722
- return false;
723
- }
724
- // Category filter
725
- if (criteria.category && market.category !== criteria.category) {
726
- return false;
727
- }
728
- // Tags filter (match ANY of the provided tags)
729
- if (criteria.tags && criteria.tags.length > 0) {
730
- const hasMatchingTag = criteria.tags.some(tag => market.tags?.some(marketTag => marketTag.toLowerCase() === tag.toLowerCase()));
731
- if (!hasMatchingTag)
732
- return false;
733
- }
734
- // Volume24h filter
735
- if (criteria.volume24h) {
736
- if (criteria.volume24h.min !== undefined && market.volume24h < criteria.volume24h.min) {
737
- return false;
738
- }
739
- if (criteria.volume24h.max !== undefined && market.volume24h > criteria.volume24h.max) {
740
- return false;
741
- }
742
- }
743
- // Volume filter
744
- if (criteria.volume) {
745
- if (criteria.volume.min !== undefined && (market.volume || 0) < criteria.volume.min) {
746
- return false;
747
- }
748
- if (criteria.volume.max !== undefined && (market.volume || 0) > criteria.volume.max) {
749
- return false;
750
- }
751
- }
752
- // Liquidity filter
753
- if (criteria.liquidity) {
754
- if (criteria.liquidity.min !== undefined && market.liquidity < criteria.liquidity.min) {
755
- return false;
756
- }
757
- if (criteria.liquidity.max !== undefined && market.liquidity > criteria.liquidity.max) {
758
- return false;
759
- }
760
- }
761
- // OpenInterest filter
762
- if (criteria.openInterest) {
763
- if (criteria.openInterest.min !== undefined && (market.openInterest || 0) < criteria.openInterest.min) {
764
- return false;
765
- }
766
- if (criteria.openInterest.max !== undefined && (market.openInterest || 0) > criteria.openInterest.max) {
767
- return false;
768
- }
769
- }
770
- // ResolutionDate filter
771
- if (criteria.resolutionDate && market.resolutionDate) {
772
- const resDate = market.resolutionDate;
773
- if (criteria.resolutionDate.before && resDate >= criteria.resolutionDate.before) {
774
- return false;
775
- }
776
- if (criteria.resolutionDate.after && resDate <= criteria.resolutionDate.after) {
777
- return false;
778
- }
779
- }
780
- // Price filter (for binary markets)
781
- if (criteria.price) {
782
- const outcome = market[criteria.price.outcome];
783
- if (!outcome)
784
- return false;
785
- if (criteria.price.min !== undefined && outcome.price < criteria.price.min) {
786
- return false;
787
- }
788
- if (criteria.price.max !== undefined && outcome.price > criteria.price.max) {
789
- return false;
790
- }
791
- }
792
- // Price change filter
793
- if (criteria.priceChange24h) {
794
- const outcome = market[criteria.priceChange24h.outcome];
795
- if (!outcome || outcome.priceChange24h === undefined)
796
- return false;
797
- if (criteria.priceChange24h.min !== undefined && outcome.priceChange24h < criteria.priceChange24h.min) {
798
- return false;
799
- }
800
- if (criteria.priceChange24h.max !== undefined && outcome.priceChange24h > criteria.priceChange24h.max) {
801
- return false;
802
- }
803
- }
804
- return true;
805
- });
806
- }
807
- /**
808
- * Filter events based on criteria or custom function.
809
- *
810
- * @param events - Array of events to filter
811
- * @param criteria - Filter criteria object, string (simple text search), or predicate function
812
- * @returns Filtered array of events
813
- *
814
- * @example Simple text search
815
- * api.filterEvents(events, 'Trump')
816
- *
817
- * @example Advanced filtering
818
- * api.filterEvents(events, {
819
- * text: 'Election',
820
- * searchIn: ['title', 'tags'],
821
- * category: 'Politics',
822
- * marketCount: { min: 5 }
823
- * })
824
- *
825
- * @example Custom predicate
826
- * api.filterEvents(events, e => e.markets.length > 10)
827
- */
828
- filterEvents(events, criteria) {
829
- // Handle predicate function
830
- if (typeof criteria === 'function') {
831
- return events.filter(criteria);
832
- }
833
- // Handle simple string search
834
- if (typeof criteria === 'string') {
835
- const lowerQuery = criteria.toLowerCase();
836
- return events.filter(e => e.title.toLowerCase().includes(lowerQuery));
837
- }
838
- // Handle criteria object
839
- return events.filter(event => {
840
- // Text search
841
- if (criteria.text) {
842
- const lowerQuery = criteria.text.toLowerCase();
843
- const searchIn = criteria.searchIn || ['title'];
844
- let textMatch = false;
845
- for (const field of searchIn) {
846
- if (field === 'title' && event.title?.toLowerCase().includes(lowerQuery)) {
847
- textMatch = true;
848
- break;
849
- }
850
- if (field === 'description' && event.description?.toLowerCase().includes(lowerQuery)) {
851
- textMatch = true;
852
- break;
853
- }
854
- if (field === 'category' && event.category?.toLowerCase().includes(lowerQuery)) {
855
- textMatch = true;
856
- break;
857
- }
858
- if (field === 'tags' && event.tags?.some(tag => tag.toLowerCase().includes(lowerQuery))) {
859
- textMatch = true;
860
- break;
861
- }
862
- }
863
- if (!textMatch)
864
- return false;
865
- }
866
- // Category filter
867
- if (criteria.category && event.category !== criteria.category) {
868
- return false;
869
- }
870
- // Tags filter (match ANY of the provided tags)
871
- if (criteria.tags && criteria.tags.length > 0) {
872
- const hasMatchingTag = criteria.tags.some(tag => event.tags?.some(eventTag => eventTag.toLowerCase() === tag.toLowerCase()));
873
- if (!hasMatchingTag)
874
- return false;
875
- }
876
- // Market count filter
877
- if (criteria.marketCount) {
878
- const count = event.markets.length;
879
- if (criteria.marketCount.min !== undefined && count < criteria.marketCount.min) {
880
- return false;
881
- }
882
- if (criteria.marketCount.max !== undefined && count > criteria.marketCount.max) {
883
- return false;
884
- }
885
- }
886
- // Total volume filter
887
- if (criteria.totalVolume) {
888
- const totalVolume = event.markets.reduce((sum, m) => sum + m.volume24h, 0);
889
- if (criteria.totalVolume.min !== undefined && totalVolume < criteria.totalVolume.min) {
890
- return false;
891
- }
892
- if (criteria.totalVolume.max !== undefined && totalVolume > criteria.totalVolume.max) {
893
- return false;
894
- }
895
- }
896
- return true;
897
- });
898
- }
899
- }
900
- exports.Exchange = Exchange;
901
- class Polymarket extends Exchange {
902
- constructor(options = {}) {
903
- // Default to gnosis-safe signature type
904
- const polyOptions = {
905
- signatureType: 'gnosis-safe',
906
- ...options
907
- };
908
- super("polymarket", polyOptions);
909
- }
910
- }
911
- exports.Polymarket = Polymarket;
912
- /**
913
- * Kalshi exchange client.
914
- *
915
- * @example
916
- * ```typescript
917
- * // Public data (no auth)
918
- * const kalshi = new Kalshi();
919
- * const markets = await kalshi.fetchMarkets({ query: "Fed rates" });
920
- *
921
- * // Trading (requires auth)
922
- * const kalshi = new Kalshi({
923
- * apiKey: process.env.KALSHI_API_KEY,
924
- * privateKey: process.env.KALSHI_PRIVATE_KEY
925
- * });
926
- * const balance = await kalshi.fetchBalance();
927
- * ```
928
- */
929
- class Kalshi extends Exchange {
930
- constructor(options = {}) {
931
- super("kalshi", options);
932
- }
933
- }
934
- exports.Kalshi = Kalshi;
935
- /**
936
- * Limitless exchange client.
937
- *
938
- * @example
939
- * ```typescript
940
- * // Public data (no auth)
941
- * const limitless = new Limitless();
942
- * const markets = await limitless.fetchMarkets({ query: "Trump" });
943
- *
944
- * // Trading (requires auth)
945
- * const limitless = new Limitless({
946
- * apiKey: process.env.LIMITLESS_API_KEY,
947
- * privateKey: process.env.LIMITLESS_PRIVATE_KEY
948
- * });
949
- * const balance = await limitless.fetchBalance();
950
- * ```
951
- */
952
- class Limitless extends Exchange {
953
- constructor(options = {}) {
954
- super("limitless", options);
955
- }
956
- }
957
- exports.Limitless = Limitless;
package/pmxt/models.js DELETED
@@ -1,60 +0,0 @@
1
- "use strict";
2
- /**
3
- * Data models for PMXT TypeScript SDK.
4
- *
5
- * These are clean TypeScript interfaces that provide a user-friendly API.
6
- */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.MarketList = void 0;
9
- /**
10
- * A list of UnifiedMarket objects with a convenience match() method.
11
- * Extends Array so all standard array operations work unchanged.
12
- */
13
- class MarketList extends Array {
14
- /**
15
- * Find a single market by case-insensitive substring match.
16
- *
17
- * @param query - Substring to search for
18
- * @param searchIn - Fields to search in (default: ['title'])
19
- * @returns The matching UnifiedMarket
20
- * @throws Error if zero or multiple markets match
21
- */
22
- match(query, searchIn) {
23
- const fields = searchIn || ['title'];
24
- const lowerQuery = query.toLowerCase();
25
- const matches = [];
26
- for (const m of this) {
27
- for (const field of fields) {
28
- if (field === 'title' && m.title?.toLowerCase().includes(lowerQuery)) {
29
- matches.push(m);
30
- break;
31
- }
32
- if (field === 'description' && m.description?.toLowerCase().includes(lowerQuery)) {
33
- matches.push(m);
34
- break;
35
- }
36
- if (field === 'category' && m.category?.toLowerCase().includes(lowerQuery)) {
37
- matches.push(m);
38
- break;
39
- }
40
- if (field === 'tags' && m.tags?.some(t => t.toLowerCase().includes(lowerQuery))) {
41
- matches.push(m);
42
- break;
43
- }
44
- if (field === 'outcomes' && m.outcomes?.some(o => o.label.toLowerCase().includes(lowerQuery))) {
45
- matches.push(m);
46
- break;
47
- }
48
- }
49
- }
50
- if (matches.length === 0) {
51
- throw new Error(`No markets matching '${query}'`);
52
- }
53
- if (matches.length > 1) {
54
- const titles = matches.map(m => m.title);
55
- throw new Error(`Multiple markets matching '${query}': ${JSON.stringify(titles)}`);
56
- }
57
- return matches[0];
58
- }
59
- }
60
- exports.MarketList = MarketList;
@@ -1,204 +0,0 @@
1
- "use strict";
2
- /**
3
- * Server manager for PMXT TypeScript SDK.
4
- *
5
- * Handles automatic server startup and health checks.
6
- */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.ServerManager = void 0;
9
- const index_js_1 = require("../generated/src/index.js");
10
- const fs_1 = require("fs");
11
- const os_1 = require("os");
12
- const path_1 = require("path");
13
- class ServerManager {
14
- constructor(options = {}) {
15
- this.baseUrl = options.baseUrl || `http://localhost:${ServerManager.DEFAULT_PORT}`;
16
- this.maxRetries = options.maxRetries || 30;
17
- this.retryDelayMs = options.retryDelayMs || 1000;
18
- this.lockPath = (0, path_1.join)((0, os_1.homedir)(), '.pmxt', 'server.lock');
19
- const config = new index_js_1.Configuration({ basePath: this.baseUrl });
20
- this.api = new index_js_1.DefaultApi(config);
21
- }
22
- /**
23
- * Read server information from lock file.
24
- */
25
- getServerInfo() {
26
- try {
27
- if (!(0, fs_1.existsSync)(this.lockPath)) {
28
- return null;
29
- }
30
- const content = (0, fs_1.readFileSync)(this.lockPath, 'utf-8');
31
- return JSON.parse(content);
32
- }
33
- catch {
34
- return null;
35
- }
36
- }
37
- /**
38
- * Get the actual port the server is running on.
39
- *
40
- * This reads the lock file to determine the actual port,
41
- * which may differ from the default if the default port was busy.
42
- */
43
- getRunningPort() {
44
- const info = this.getServerInfo();
45
- return info?.port || ServerManager.DEFAULT_PORT;
46
- }
47
- /**
48
- * Get the access token from the lock file.
49
- */
50
- getAccessToken() {
51
- const info = this.getServerInfo();
52
- return info?.accessToken;
53
- }
54
- /**
55
- * Check if the server is running.
56
- */
57
- async isServerRunning() {
58
- // Read lock file to get current port
59
- const port = this.getRunningPort();
60
- try {
61
- // Use native fetch to check health on the actual running port
62
- // This avoids issues where this.api is configured with the wrong port
63
- const response = await fetch(`http://localhost:${port}/health`);
64
- if (response.ok) {
65
- const data = await response.json();
66
- return data.status === "ok";
67
- }
68
- return false;
69
- }
70
- catch (error) {
71
- return false;
72
- }
73
- }
74
- /**
75
- * Wait for the server to be ready.
76
- */
77
- async waitForServer() {
78
- for (let i = 0; i < this.maxRetries; i++) {
79
- if (await this.isServerRunning()) {
80
- return;
81
- }
82
- await new Promise((resolve) => setTimeout(resolve, this.retryDelayMs));
83
- }
84
- throw new Error(`Server did not start within ${(this.maxRetries * this.retryDelayMs) / 1000}s`);
85
- }
86
- /**
87
- * Ensure the server is running, starting it if necessary.
88
- */
89
- async ensureServerRunning() {
90
- // Check for force restart
91
- if (process.env.PMXT_ALWAYS_RESTART === '1') {
92
- await this.killOldServer();
93
- }
94
- // Check if already running and version matches
95
- if (await this.isServerRunning()) {
96
- if (await this.isVersionMismatch()) {
97
- await this.killOldServer();
98
- }
99
- else {
100
- return;
101
- }
102
- }
103
- // Locate pmxt-ensure-server
104
- let launcherPath = 'pmxt-ensure-server'; // Default to PATH
105
- try {
106
- // Try to resolve from pmxt-core dependency
107
- // For CommonJS build (which is primary), we can use require directly
108
- // For ESM build, this will be transpiled appropriately
109
- const corePackageJson = require.resolve('pmxt-core/package.json');
110
- const coreDir = (0, path_1.dirname)(corePackageJson);
111
- const binPath = (0, path_1.join)(coreDir, 'bin', 'pmxt-ensure-server');
112
- if ((0, fs_1.existsSync)(binPath)) {
113
- launcherPath = binPath;
114
- }
115
- }
116
- catch (error) {
117
- // If resolution fails, fall back to PATH
118
- // This could happen in dev environments where pmxt-core is globally installed
119
- }
120
- // Try to start the server using pmxt-ensure-server
121
- const { spawn } = await Promise.resolve().then(() => require("child_process"));
122
- try {
123
- const proc = spawn(launcherPath, [], {
124
- detached: true,
125
- stdio: "ignore",
126
- });
127
- proc.unref();
128
- // Wait for server to be ready
129
- await this.waitForServer();
130
- }
131
- catch (error) {
132
- throw new Error(`Failed to start PMXT server: ${error}\n\n` +
133
- `Please ensure 'pmxt-core' is installed: npm install -g pmxt-core\n` +
134
- `Or start the server manually: pmxt-server`);
135
- }
136
- }
137
- async isVersionMismatch() {
138
- const info = this.getServerInfo();
139
- if (!info || !info.version) {
140
- return true; // Old server without version
141
- }
142
- try {
143
- // 1. Try to find package.json relative to the installed location (Production)
144
- let corePackageJsonPath;
145
- try {
146
- corePackageJsonPath = require.resolve('pmxt-core/package.json');
147
- }
148
- catch {
149
- // 2. Try dev path (Monorepo)
150
- const devPath = (0, path_1.join)((0, path_1.dirname)(__dirname), '../../core/package.json');
151
- if ((0, fs_1.existsSync)(devPath)) {
152
- corePackageJsonPath = devPath;
153
- }
154
- }
155
- if (corePackageJsonPath && (0, fs_1.existsSync)(corePackageJsonPath)) {
156
- const content = (0, fs_1.readFileSync)(corePackageJsonPath, 'utf-8');
157
- const pkg = JSON.parse(content);
158
- // Check if running version starts with package version
159
- // (Server version might have extra hash in dev mode)
160
- if (pkg.version && !info.version.startsWith(pkg.version)) {
161
- return true;
162
- }
163
- }
164
- }
165
- catch {
166
- // Ignore errors
167
- }
168
- return false;
169
- }
170
- /**
171
- * Stop the currently running server.
172
- */
173
- async stop() {
174
- await this.killOldServer();
175
- }
176
- /**
177
- * Restart the server.
178
- */
179
- async restart() {
180
- await this.stop();
181
- await this.ensureServerRunning();
182
- }
183
- async killOldServer() {
184
- const info = this.getServerInfo();
185
- if (info && info.pid) {
186
- try {
187
- process.kill(info.pid, 'SIGTERM');
188
- // Brief wait
189
- await new Promise(resolve => setTimeout(resolve, 500));
190
- }
191
- catch {
192
- // Ignore
193
- }
194
- }
195
- // Remove lock file (best effort)
196
- try {
197
- const { unlinkSync } = await Promise.resolve().then(() => require('fs'));
198
- unlinkSync(this.lockPath);
199
- }
200
- catch { }
201
- }
202
- }
203
- exports.ServerManager = ServerManager;
204
- ServerManager.DEFAULT_PORT = 3847;