pmxt-core 2.51.2 → 2.51.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API_REFERENCE.md +17 -28
- package/bin/pmxt-ensure-server +22 -1
- package/bin/pmxt-ensure-server.js +64 -3
- package/dist/BaseExchange.d.ts +34 -0
- package/dist/BaseExchange.js +44 -2
- package/dist/exchanges/hyperliquid/normalizer.js +1 -1
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/kalshi/fetcher.js +13 -0
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/opinion/api.d.ts +1 -1
- package/dist/exchanges/opinion/api.js +1 -1
- package/dist/exchanges/polymarket/api-clob.d.ts +1 -1
- package/dist/exchanges/polymarket/api-clob.js +1 -1
- package/dist/exchanges/polymarket/api-data.d.ts +1 -1
- package/dist/exchanges/polymarket/api-data.js +1 -1
- package/dist/exchanges/polymarket/api-gamma.d.ts +1 -1
- package/dist/exchanges/polymarket/api-gamma.js +1 -1
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/rain/fetcher.d.ts +2 -1
- package/dist/exchanges/rain/fetcher.js +5 -6
- package/dist/exchanges/rain/index.js +5 -1
- package/dist/exchanges/smarkets/fetcher.js +16 -6
- package/dist/server/openapi.yaml +14 -2
- package/dist/types.d.ts +2 -0
- package/package.json +3 -3
package/API_REFERENCE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Prediction Market API Reference
|
|
2
2
|
|
|
3
|
-
A unified interface for interacting with multiple prediction market exchanges
|
|
3
|
+
A unified interface for interacting with multiple prediction market exchanges and venues through one interface.
|
|
4
4
|
|
|
5
5
|
## Installation & Usage
|
|
6
6
|
|
|
@@ -8,33 +8,22 @@ A unified interface for interacting with multiple prediction market exchanges (K
|
|
|
8
8
|
npm install pmxtjs
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
###
|
|
11
|
+
### Import Styles
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
import
|
|
14
|
+
import { Polymarket, Kalshi } from 'pmxtjs';
|
|
15
15
|
|
|
16
|
-
const
|
|
17
|
-
const kalshi = new
|
|
16
|
+
const polymarket = new Polymarket();
|
|
17
|
+
const kalshi = new Kalshi();
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
### Note for ESM Users
|
|
21
|
-
|
|
22
|
-
**pmxt is currently CommonJS-only.** If you're using `"type": "module"` in your `package.json`, you have two options:
|
|
23
|
-
|
|
24
|
-
**Option 1: Default import (recommended)**
|
|
25
20
|
```typescript
|
|
26
21
|
import pmxt from 'pmxtjs';
|
|
27
|
-
const poly = new pmxt.Polymarket();
|
|
28
|
-
```
|
|
29
22
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const pmxt = await import('pmxtjs');
|
|
33
|
-
const poly = new pmxt.default.Polymarket();
|
|
23
|
+
const polymarket = new pmxt.Polymarket();
|
|
24
|
+
const kalshi = new pmxt.Kalshi();
|
|
34
25
|
```
|
|
35
26
|
|
|
36
|
-
**Note**: Named exports like `import { Polymarket } from 'pmxtjs'` will **not work** in ESM projects.
|
|
37
|
-
|
|
38
27
|
---
|
|
39
28
|
|
|
40
29
|
## Core Methods
|
|
@@ -46,8 +35,8 @@ Get active markets from an exchange. This is the unified method for all market f
|
|
|
46
35
|
- `limit`: Number of results (default: 20)
|
|
47
36
|
- `offset`: Pagination offset
|
|
48
37
|
- `sort`: 'volume' | 'liquidity' | 'newest'
|
|
49
|
-
- `query`: Search text
|
|
50
|
-
- `slug`: Market slug or ticker
|
|
38
|
+
- `query`: Search text
|
|
39
|
+
- `slug`: Market slug or ticker
|
|
51
40
|
|
|
52
41
|
```typescript
|
|
53
42
|
// 1. Fetch recent markets
|
|
@@ -56,13 +45,13 @@ const markets = await polymarket.fetchMarkets({
|
|
|
56
45
|
sort: 'volume'
|
|
57
46
|
});
|
|
58
47
|
|
|
59
|
-
// 2. Search by text
|
|
48
|
+
// 2. Search by text
|
|
60
49
|
const results = await kalshi.fetchMarkets({
|
|
61
50
|
query: 'Fed rates',
|
|
62
51
|
limit: 10
|
|
63
52
|
});
|
|
64
53
|
|
|
65
|
-
// 3. Fetch by slug/ticker
|
|
54
|
+
// 3. Fetch by slug/ticker
|
|
66
55
|
const market = await polymarket.fetchMarkets({
|
|
67
56
|
slug: 'who-will-trump-nominate-as-fed-chair'
|
|
68
57
|
});
|
|
@@ -140,7 +129,7 @@ Calculate the volume-weighted average price for a given amount. Returns `0` if t
|
|
|
140
129
|
|
|
141
130
|
```typescript
|
|
142
131
|
const orderBook = await polymarket.fetchOrderBook(outcomeId);
|
|
143
|
-
const price =
|
|
132
|
+
const price = polymarket.getExecutionPrice(orderBook, 'buy', 100);
|
|
144
133
|
console.log(`Average price for 100 shares: ${price}`);
|
|
145
134
|
```
|
|
146
135
|
|
|
@@ -148,7 +137,7 @@ console.log(`Average price for 100 shares: ${price}`);
|
|
|
148
137
|
Calculate detailed execution price information, including partial fills.
|
|
149
138
|
|
|
150
139
|
```typescript
|
|
151
|
-
const detailed =
|
|
140
|
+
const detailed = polymarket.getExecutionPriceDetailed(orderBook, 'buy', 100);
|
|
152
141
|
console.log(`Average Price: ${detailed.price}`);
|
|
153
142
|
console.log(`Filled Amount: ${detailed.filledAmount}`);
|
|
154
143
|
console.log(`Fully Filled: ${detailed.fullyFilled}`);
|
|
@@ -275,10 +264,10 @@ console.log(`Spread: ${(spread * 100).toFixed(2)}%`);
|
|
|
275
264
|
|
|
276
265
|
```typescript
|
|
277
266
|
try {
|
|
278
|
-
const
|
|
267
|
+
const market = await kalshi.fetchMarket({ slug: 'INVALID-TICKER' });
|
|
268
|
+
console.log(market.title);
|
|
279
269
|
} catch (error) {
|
|
280
|
-
//
|
|
281
|
-
// Polymarket: Returns empty array []
|
|
270
|
+
// Throws MarketNotFound when no market matches the lookup
|
|
282
271
|
console.error(error.message);
|
|
283
272
|
}
|
|
284
273
|
```
|
|
@@ -310,7 +299,7 @@ import pmxt, {
|
|
|
310
299
|
|
|
311
300
|
## Authentication & Trading
|
|
312
301
|
|
|
313
|
-
|
|
302
|
+
Authenticated trading is available on venues that expose trading APIs. You must provide the venue-specific credentials when initializing the exchange; the examples below show Polymarket and Kalshi.
|
|
314
303
|
|
|
315
304
|
### Polymarket Authentication
|
|
316
305
|
|
package/bin/pmxt-ensure-server
CHANGED
|
@@ -39,7 +39,7 @@ function isServerRunning() {
|
|
|
39
39
|
// Check if process exists
|
|
40
40
|
try {
|
|
41
41
|
process.kill(pid, 0); // Signal 0 checks existence without killing
|
|
42
|
-
return { running: true, port };
|
|
42
|
+
return { running: true, pid, port };
|
|
43
43
|
} catch (err) {
|
|
44
44
|
// Process doesn't exist, remove stale lock file
|
|
45
45
|
fs.unlinkSync(LOCK_FILE);
|
|
@@ -50,6 +50,26 @@ function isServerRunning() {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Remove the lock we just proved unhealthy, without deleting a newer sidecar's
|
|
55
|
+
* lock if another launcher won the race and replaced it first.
|
|
56
|
+
*/
|
|
57
|
+
function removeLockFileIfMatches(staleLock) {
|
|
58
|
+
try {
|
|
59
|
+
if (!fs.existsSync(LOCK_FILE)) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const currentLock = JSON.parse(fs.readFileSync(LOCK_FILE, 'utf-8'));
|
|
63
|
+
if (currentLock.pid === staleLock.pid && currentLock.port === staleLock.port) {
|
|
64
|
+
fs.unlinkSync(LOCK_FILE);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
53
73
|
/**
|
|
54
74
|
* Wait for server to respond to health check
|
|
55
75
|
*/
|
|
@@ -196,6 +216,7 @@ async function main() {
|
|
|
196
216
|
} catch (err) {
|
|
197
217
|
// Server process exists but not responding, try to start fresh
|
|
198
218
|
console.error('Server process exists but not responding, starting fresh...');
|
|
219
|
+
removeLockFileIfMatches(serverStatus);
|
|
199
220
|
}
|
|
200
221
|
}
|
|
201
222
|
|
|
@@ -39,7 +39,7 @@ function isServerRunning() {
|
|
|
39
39
|
// Check if process exists
|
|
40
40
|
try {
|
|
41
41
|
process.kill(pid, 0); // Signal 0 checks existence without killing
|
|
42
|
-
return { running: true, port };
|
|
42
|
+
return { running: true, pid, port };
|
|
43
43
|
} catch (err) {
|
|
44
44
|
// Process doesn't exist, remove stale lock file
|
|
45
45
|
fs.unlinkSync(LOCK_FILE);
|
|
@@ -50,6 +50,26 @@ function isServerRunning() {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Remove the lock we just proved unhealthy, without deleting a newer sidecar's
|
|
55
|
+
* lock if another launcher won the race and replaced it first.
|
|
56
|
+
*/
|
|
57
|
+
function removeLockFileIfMatches(staleLock) {
|
|
58
|
+
try {
|
|
59
|
+
if (!fs.existsSync(LOCK_FILE)) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const currentLock = JSON.parse(fs.readFileSync(LOCK_FILE, 'utf-8'));
|
|
63
|
+
if (currentLock.pid === staleLock.pid && currentLock.port === staleLock.port) {
|
|
64
|
+
fs.unlinkSync(LOCK_FILE);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
53
73
|
/**
|
|
54
74
|
* Wait for server to respond to health check
|
|
55
75
|
*/
|
|
@@ -85,6 +105,44 @@ function waitForHealth(port, timeout = HEALTH_CHECK_TIMEOUT) {
|
|
|
85
105
|
});
|
|
86
106
|
}
|
|
87
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Wait for the lock file to appear, then health-check the port it specifies.
|
|
110
|
+
*
|
|
111
|
+
* The sidecar may bind a non-default port when the default is occupied by an
|
|
112
|
+
* orphan. Polling DEFAULT_PORT would be fooled by the orphan, so we wait for
|
|
113
|
+
* the new sidecar to write its lock file and health-check THAT port.
|
|
114
|
+
*/
|
|
115
|
+
function waitForLockAndHealth(timeout = HEALTH_CHECK_TIMEOUT) {
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
const startTime = Date.now();
|
|
118
|
+
|
|
119
|
+
const poll = () => {
|
|
120
|
+
if (Date.now() - startTime > timeout) {
|
|
121
|
+
return reject(new Error('Server health check timeout (lock file never appeared)'));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
if (fs.existsSync(LOCK_FILE)) {
|
|
126
|
+
const lockData = JSON.parse(fs.readFileSync(LOCK_FILE, 'utf-8'));
|
|
127
|
+
const port = lockData.port || DEFAULT_PORT;
|
|
128
|
+
// Lock file appeared — now health-check the actual port
|
|
129
|
+
const remaining = timeout - (Date.now() - startTime);
|
|
130
|
+
waitForHealth(port, Math.max(remaining, 1000))
|
|
131
|
+
.then(resolve)
|
|
132
|
+
.catch(reject);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
} catch (err) {
|
|
136
|
+
// Lock file partially written or unreadable — retry
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
setTimeout(poll, HEALTH_CHECK_INTERVAL);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
poll();
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
88
146
|
/**
|
|
89
147
|
* Start the PMXT server
|
|
90
148
|
*/
|
|
@@ -136,8 +194,10 @@ async function startServer() {
|
|
|
136
194
|
// Detach from parent process
|
|
137
195
|
serverProcess.unref();
|
|
138
196
|
|
|
139
|
-
// Wait for
|
|
140
|
-
|
|
197
|
+
// Wait for the sidecar to write its lock file, then health-check
|
|
198
|
+
// the actual port it bound (which may differ from DEFAULT_PORT if
|
|
199
|
+
// an orphan sidecar is occupying it).
|
|
200
|
+
await waitForLockAndHealth();
|
|
141
201
|
}
|
|
142
202
|
|
|
143
203
|
/**
|
|
@@ -156,6 +216,7 @@ async function main() {
|
|
|
156
216
|
} catch (err) {
|
|
157
217
|
// Server process exists but not responding, try to start fresh
|
|
158
218
|
console.error('Server process exists but not responding, starting fresh...');
|
|
219
|
+
removeLockFileIfMatches(serverStatus);
|
|
159
220
|
}
|
|
160
221
|
}
|
|
161
222
|
|
package/dist/BaseExchange.d.ts
CHANGED
|
@@ -627,8 +627,42 @@ export declare abstract class PredictionMarketExchange {
|
|
|
627
627
|
* @returns Array of open orders
|
|
628
628
|
*/
|
|
629
629
|
fetchOpenOrders(marketId?: string): Promise<Order[]>;
|
|
630
|
+
/**
|
|
631
|
+
* Fetch authenticated user trade history.
|
|
632
|
+
*
|
|
633
|
+
* @param params - Optional trade history filters
|
|
634
|
+
* @param params.outcomeId - Filter by outcome token ID
|
|
635
|
+
* @param params.marketId - Filter by market ID or ticker
|
|
636
|
+
* @param params.since - Start timestamp or ISO date
|
|
637
|
+
* @param params.until - End timestamp or ISO date
|
|
638
|
+
* @param params.limit - Maximum number of trades
|
|
639
|
+
* @param params.cursor - Pagination cursor
|
|
640
|
+
* @returns Array of user trades
|
|
641
|
+
*/
|
|
630
642
|
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
643
|
+
/**
|
|
644
|
+
* Fetch authenticated closed orders.
|
|
645
|
+
*
|
|
646
|
+
* @param params - Optional order history filters
|
|
647
|
+
* @param params.marketId - Filter by market ID or ticker
|
|
648
|
+
* @param params.since - Start timestamp or ISO date
|
|
649
|
+
* @param params.until - End timestamp or ISO date
|
|
650
|
+
* @param params.limit - Maximum number of orders
|
|
651
|
+
* @param params.cursor - Pagination cursor
|
|
652
|
+
* @returns Array of closed orders
|
|
653
|
+
*/
|
|
631
654
|
fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
655
|
+
/**
|
|
656
|
+
* Fetch authenticated order history across open and closed orders.
|
|
657
|
+
*
|
|
658
|
+
* @param params - Optional order history filters
|
|
659
|
+
* @param params.marketId - Filter by market ID or ticker
|
|
660
|
+
* @param params.since - Start timestamp or ISO date
|
|
661
|
+
* @param params.until - End timestamp or ISO date
|
|
662
|
+
* @param params.limit - Maximum number of orders
|
|
663
|
+
* @param params.cursor - Pagination cursor
|
|
664
|
+
* @returns Array of orders
|
|
665
|
+
*/
|
|
632
666
|
fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
633
667
|
/**
|
|
634
668
|
* Fetch current user positions across all markets.
|
package/dist/BaseExchange.js
CHANGED
|
@@ -213,7 +213,13 @@ class PredictionMarketExchange {
|
|
|
213
213
|
return limit !== undefined ? filtered.slice(start, start + limit) : filtered.slice(start);
|
|
214
214
|
}
|
|
215
215
|
const { limit, offset, ...venueParams } = fetchParams;
|
|
216
|
-
const
|
|
216
|
+
const hasVenueParams = Object.keys(venueParams).length > 0;
|
|
217
|
+
const shouldForwardSimpleLimit = limit !== undefined && offset === undefined && !hasVenueParams;
|
|
218
|
+
const markets = await this.fetchMarketsImpl(shouldForwardSimpleLimit
|
|
219
|
+
? { limit }
|
|
220
|
+
: hasVenueParams
|
|
221
|
+
? venueParams
|
|
222
|
+
: undefined);
|
|
217
223
|
const start = offset ?? 0;
|
|
218
224
|
return limit !== undefined ? markets.slice(start, start + limit) : markets.slice(start);
|
|
219
225
|
}
|
|
@@ -357,7 +363,9 @@ class PredictionMarketExchange {
|
|
|
357
363
|
return limit !== undefined ? filtered.slice(start, start + limit) : filtered.slice(start);
|
|
358
364
|
}
|
|
359
365
|
const { limit, offset, ...venueParams } = fetchParams;
|
|
360
|
-
const
|
|
366
|
+
const hasVenueParams = Object.keys(venueParams).length > 0;
|
|
367
|
+
const shouldForwardSimpleLimit = limit !== undefined && offset === undefined && !hasVenueParams;
|
|
368
|
+
const events = await this.fetchEventsImpl(shouldForwardSimpleLimit ? { limit } : venueParams);
|
|
361
369
|
const start = offset ?? 0;
|
|
362
370
|
return limit !== undefined ? events.slice(start, start + limit) : events.slice(start);
|
|
363
371
|
}
|
|
@@ -607,12 +615,46 @@ class PredictionMarketExchange {
|
|
|
607
615
|
async fetchOpenOrders(marketId) {
|
|
608
616
|
throw new Error("Method fetchOpenOrders not implemented.");
|
|
609
617
|
}
|
|
618
|
+
/**
|
|
619
|
+
* Fetch authenticated user trade history.
|
|
620
|
+
*
|
|
621
|
+
* @param params - Optional trade history filters
|
|
622
|
+
* @param params.outcomeId - Filter by outcome token ID
|
|
623
|
+
* @param params.marketId - Filter by market ID or ticker
|
|
624
|
+
* @param params.since - Start timestamp or ISO date
|
|
625
|
+
* @param params.until - End timestamp or ISO date
|
|
626
|
+
* @param params.limit - Maximum number of trades
|
|
627
|
+
* @param params.cursor - Pagination cursor
|
|
628
|
+
* @returns Array of user trades
|
|
629
|
+
*/
|
|
610
630
|
async fetchMyTrades(params) {
|
|
611
631
|
throw new Error("Method fetchMyTrades not implemented.");
|
|
612
632
|
}
|
|
633
|
+
/**
|
|
634
|
+
* Fetch authenticated closed orders.
|
|
635
|
+
*
|
|
636
|
+
* @param params - Optional order history filters
|
|
637
|
+
* @param params.marketId - Filter by market ID or ticker
|
|
638
|
+
* @param params.since - Start timestamp or ISO date
|
|
639
|
+
* @param params.until - End timestamp or ISO date
|
|
640
|
+
* @param params.limit - Maximum number of orders
|
|
641
|
+
* @param params.cursor - Pagination cursor
|
|
642
|
+
* @returns Array of closed orders
|
|
643
|
+
*/
|
|
613
644
|
async fetchClosedOrders(params) {
|
|
614
645
|
throw new Error("Method fetchClosedOrders not implemented.");
|
|
615
646
|
}
|
|
647
|
+
/**
|
|
648
|
+
* Fetch authenticated order history across open and closed orders.
|
|
649
|
+
*
|
|
650
|
+
* @param params - Optional order history filters
|
|
651
|
+
* @param params.marketId - Filter by market ID or ticker
|
|
652
|
+
* @param params.since - Start timestamp or ISO date
|
|
653
|
+
* @param params.until - End timestamp or ISO date
|
|
654
|
+
* @param params.limit - Maximum number of orders
|
|
655
|
+
* @param params.cursor - Pagination cursor
|
|
656
|
+
* @returns Array of orders
|
|
657
|
+
*/
|
|
616
658
|
async fetchAllOrders(params) {
|
|
617
659
|
throw new Error("Method fetchAllOrders not implemented.");
|
|
618
660
|
}
|
|
@@ -175,7 +175,7 @@ class HyperliquidNormalizer {
|
|
|
175
175
|
description: outcome.description,
|
|
176
176
|
slug: `hl-${outcomeId}`,
|
|
177
177
|
outcomes,
|
|
178
|
-
resolutionDate: expiryDate
|
|
178
|
+
resolutionDate: expiryDate,
|
|
179
179
|
volume24h: raw.volume24h ?? 0,
|
|
180
180
|
liquidity: 0,
|
|
181
181
|
url: buildMarketUrl(outcomeId),
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-24T09:17:49.567Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-24T09:17:49.567Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.kalshiApiSpec = {
|
|
@@ -64,6 +64,19 @@ class KalshiFetcher {
|
|
|
64
64
|
return this.fetchAllWithSeriesTicker(params.series);
|
|
65
65
|
}
|
|
66
66
|
const status = params?.status || 'active';
|
|
67
|
+
const hasBoundedDefaultRead = status === 'active' &&
|
|
68
|
+
(params.limit !== undefined || params.cursor !== undefined) &&
|
|
69
|
+
!params.query &&
|
|
70
|
+
params.offset === undefined &&
|
|
71
|
+
params.sort === undefined &&
|
|
72
|
+
params.searchIn === undefined &&
|
|
73
|
+
params.category === undefined &&
|
|
74
|
+
params.tags === undefined &&
|
|
75
|
+
params.filter === undefined;
|
|
76
|
+
if (hasBoundedDefaultRead) {
|
|
77
|
+
const page = await this.fetchRawEventPage(params);
|
|
78
|
+
return page.events;
|
|
79
|
+
}
|
|
67
80
|
if (status === 'all') {
|
|
68
81
|
const openEvents = await this.fetchAllWithStatus('open');
|
|
69
82
|
const closedEvents = await this.fetchAllWithStatus('closed');
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-24T09:17:49.606Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-24T09:17:49.606Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.limitlessApiSpec = {
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-24T09:17:49.618Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-24T09:17:49.618Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.myriadApiSpec = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/opinion/opinion-openapi.yaml
|
|
3
|
-
* Generated at: 2026-06-
|
|
3
|
+
* Generated at: 2026-06-24T09:17:49.621Z
|
|
4
4
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
5
5
|
*/
|
|
6
6
|
export declare const opinionApiSpec: {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.opinionApiSpec = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Auto-generated from /home/runner/work/pmxt/pmxt/core/specs/opinion/opinion-openapi.yaml
|
|
6
|
-
* Generated at: 2026-06-
|
|
6
|
+
* Generated at: 2026-06-24T09:17:49.621Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.opinionApiSpec = {
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-24T09:17:49.575Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-24T09:17:49.575Z
|
|
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-06-
|
|
3
|
+
* Generated at: 2026-06-24T09:17:49.588Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-24T09:17:49.588Z
|
|
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-06-
|
|
3
|
+
* Generated at: 2026-06-24T09:17:49.586Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-24T09:17:49.586Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.polymarketGammaSpec = {
|
|
@@ -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-06-
|
|
3
|
+
* Generated at: 2026-06-24T09:17:49.613Z
|
|
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-06-
|
|
6
|
+
* Generated at: 2026-06-24T09:17:49.613Z
|
|
7
7
|
* Do not edit manually -- run "npm run fetch:openapi" to regenerate.
|
|
8
8
|
*/
|
|
9
9
|
exports.probableApiSpec = {
|
|
@@ -6,6 +6,7 @@ export interface RainFetcherConfig {
|
|
|
6
6
|
subgraphApiKey?: string;
|
|
7
7
|
rpcUrl?: string;
|
|
8
8
|
wsRpcUrl?: string;
|
|
9
|
+
sdk?: RainSdk;
|
|
9
10
|
}
|
|
10
11
|
export type RainRawMarket = Awaited<ReturnType<RainClient['getPublicMarkets']>>[number];
|
|
11
12
|
export type RainRawMarketDetails = Awaited<ReturnType<RainClient['getMarketDetails']>>;
|
|
@@ -38,7 +39,7 @@ export declare class RainFetcher {
|
|
|
38
39
|
status?: string;
|
|
39
40
|
}): Promise<RainMarketWithDetails[]>;
|
|
40
41
|
fetchRawMarket(marketId: string): Promise<RainMarketWithDetails | null>;
|
|
41
|
-
fetchRawOHLCV(
|
|
42
|
+
fetchRawOHLCV(marketAddress: string, optionIndex: number, _interval: string, _limit?: number): Promise<RainRawPriceHistory | null>;
|
|
42
43
|
fetchRawPositions(walletAddress: string): Promise<RainRawPositions>;
|
|
43
44
|
fetchRawBalance(walletAddress: string, tokenAddresses: string[]): Promise<RainRawBalance>;
|
|
44
45
|
fetchRawMarketTrades(marketAddress: string, limit?: number): Promise<RainRawMarketTransactions | null>;
|
|
@@ -23,7 +23,7 @@ class RainFetcher {
|
|
|
23
23
|
}
|
|
24
24
|
async getClient() {
|
|
25
25
|
if (!this.client) {
|
|
26
|
-
const sdk = await loadSdk();
|
|
26
|
+
const sdk = this.config.sdk ?? await loadSdk();
|
|
27
27
|
this.client = new sdk.Rain({
|
|
28
28
|
environment: this.config.environment ?? 'production',
|
|
29
29
|
rpcUrl: this.config.rpcUrl,
|
|
@@ -91,16 +91,15 @@ class RainFetcher {
|
|
|
91
91
|
throw errors_1.rainErrorMapper.mapError(error);
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
-
async fetchRawOHLCV(
|
|
94
|
+
async fetchRawOHLCV(marketAddress, optionIndex, _interval, _limit) {
|
|
95
95
|
if (!this.config.subgraphUrl)
|
|
96
96
|
return null;
|
|
97
97
|
try {
|
|
98
98
|
const client = await this.getClient();
|
|
99
99
|
return await client.getPriceHistory({
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
limit,
|
|
100
|
+
marketAddress: marketAddress,
|
|
101
|
+
interval: _interval,
|
|
102
|
+
option: optionIndex,
|
|
104
103
|
});
|
|
105
104
|
}
|
|
106
105
|
catch (error) {
|
|
@@ -96,7 +96,11 @@ class RainExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
96
96
|
const marketId = parts[1];
|
|
97
97
|
const choiceIndex = Number(parts[2]);
|
|
98
98
|
const interval = normalizer_1.RainNormalizer.mapInterval(params.resolution);
|
|
99
|
-
const
|
|
99
|
+
const market = await this.fetcher.fetchRawMarket(marketId);
|
|
100
|
+
const contractAddress = market?.details?.contractAddress;
|
|
101
|
+
if (!contractAddress)
|
|
102
|
+
return [];
|
|
103
|
+
const raw = await this.fetcher.fetchRawOHLCV(contractAddress, choiceIndex, interval, params.limit);
|
|
100
104
|
return this.normalizer.normalizeOHLCV(raw, params.limit);
|
|
101
105
|
}
|
|
102
106
|
async fetchOrderBook(outcomeId, _limit, _params) {
|
|
@@ -40,12 +40,19 @@ class SmarketsFetcher {
|
|
|
40
40
|
if (params.eventId) {
|
|
41
41
|
return this.fetchEnrichedEventById(params.eventId);
|
|
42
42
|
}
|
|
43
|
+
if (params.limit !== undefined && params.limit <= 0) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
43
46
|
const stateFilter = this.mapEventStatus(params?.status || 'active');
|
|
47
|
+
const requestedLimit = params.limit === undefined
|
|
48
|
+
? undefined
|
|
49
|
+
: Math.max(1, Math.floor(params.limit));
|
|
44
50
|
const rawEvents = await this.fetchPaginatedEvents({
|
|
45
51
|
state: stateFilter,
|
|
46
52
|
type_scope: ['single_event'],
|
|
47
53
|
with_new_type: true,
|
|
48
|
-
|
|
54
|
+
...(requestedLimit === undefined ? {} : { limit: Math.min(requestedLimit, BATCH_SIZE) }),
|
|
55
|
+
}, requestedLimit);
|
|
49
56
|
return this.enrichEvents(rawEvents);
|
|
50
57
|
}
|
|
51
58
|
catch (error) {
|
|
@@ -153,11 +160,8 @@ class SmarketsFetcher {
|
|
|
153
160
|
const contracts = contractsData.contracts || [];
|
|
154
161
|
if (contracts.length === 0)
|
|
155
162
|
return [];
|
|
156
|
-
// Step 2: Fetch volumes for this market
|
|
157
|
-
const
|
|
158
|
-
market_ids: [marketId],
|
|
159
|
-
});
|
|
160
|
-
const volumes = volumeData.volumes || [];
|
|
163
|
+
// Step 2: Fetch optional authenticated volumes for this market.
|
|
164
|
+
const volumes = await this.fetchVolumesByMarketIds([marketId]);
|
|
161
165
|
// Step 3: We need the event_id. The contracts have market_id but not event_id.
|
|
162
166
|
// Use the events/markets endpoint by searching for events that contain this market.
|
|
163
167
|
// The most reliable approach: fetch all active events and find the one that owns
|
|
@@ -201,6 +205,8 @@ class SmarketsFetcher {
|
|
|
201
205
|
}];
|
|
202
206
|
}
|
|
203
207
|
async fetchAllEnrichedEvents(params) {
|
|
208
|
+
if (params?.limit !== undefined && params.limit <= 0)
|
|
209
|
+
return [];
|
|
204
210
|
const stateFilter = this.mapEventStatus(params?.status || 'active');
|
|
205
211
|
const limit = params?.limit || 1000;
|
|
206
212
|
const rawEvents = await this.fetchPaginatedEvents({
|
|
@@ -318,6 +324,10 @@ class SmarketsFetcher {
|
|
|
318
324
|
async fetchVolumesByMarketIds(marketIds) {
|
|
319
325
|
if (marketIds.length === 0)
|
|
320
326
|
return [];
|
|
327
|
+
const headers = this.ctx.getHeaders();
|
|
328
|
+
const hasAuthHeader = Object.entries(headers).some(([key, value]) => key.toLowerCase() === 'authorization' && String(value).trim().length > 0);
|
|
329
|
+
if (!hasAuthHeader)
|
|
330
|
+
return [];
|
|
321
331
|
const batches = this.batchArray(marketIds, MARKET_ID_BATCH_SIZE);
|
|
322
332
|
const results = await Promise.all(batches.map(async (batch) => {
|
|
323
333
|
try {
|
package/dist/server/openapi.yaml
CHANGED
|
@@ -1142,6 +1142,7 @@ paths:
|
|
|
1142
1142
|
type: array
|
|
1143
1143
|
items:
|
|
1144
1144
|
$ref: '#/components/schemas/UserTrade'
|
|
1145
|
+
description: Fetch authenticated user trade history.
|
|
1145
1146
|
'/api/{exchange}/fetchClosedOrders':
|
|
1146
1147
|
get:
|
|
1147
1148
|
summary: Fetch Closed Orders
|
|
@@ -1194,6 +1195,7 @@ paths:
|
|
|
1194
1195
|
type: array
|
|
1195
1196
|
items:
|
|
1196
1197
|
$ref: '#/components/schemas/Order'
|
|
1198
|
+
description: Fetch authenticated closed orders.
|
|
1197
1199
|
'/api/{exchange}/fetchAllOrders':
|
|
1198
1200
|
get:
|
|
1199
1201
|
summary: Fetch All Orders
|
|
@@ -1246,6 +1248,7 @@ paths:
|
|
|
1246
1248
|
type: array
|
|
1247
1249
|
items:
|
|
1248
1250
|
$ref: '#/components/schemas/Order'
|
|
1251
|
+
description: Fetch authenticated order history across open and closed orders.
|
|
1249
1252
|
'/api/{exchange}/fetchPositions':
|
|
1250
1253
|
get:
|
|
1251
1254
|
summary: Fetch Positions
|
|
@@ -3639,6 +3642,15 @@ components:
|
|
|
3639
3642
|
price:
|
|
3640
3643
|
type: number
|
|
3641
3644
|
description: Required for limit orders
|
|
3645
|
+
denom:
|
|
3646
|
+
type: string
|
|
3647
|
+
enum:
|
|
3648
|
+
- usdc
|
|
3649
|
+
- shares
|
|
3650
|
+
description: 'Hosted mode: amount unit.'
|
|
3651
|
+
slippage_pct:
|
|
3652
|
+
type: number
|
|
3653
|
+
description: 'Hosted mode: maximum market-order slippage percentage.'
|
|
3642
3654
|
fee:
|
|
3643
3655
|
type: number
|
|
3644
3656
|
description: 'Optional fee rate (e.g., 1000 for 0.1%)'
|
|
@@ -4488,7 +4500,7 @@ x-sdk-constructors:
|
|
|
4488
4500
|
type: string
|
|
4489
4501
|
description: Private key for authentication
|
|
4490
4502
|
polymarket_us:
|
|
4491
|
-
className:
|
|
4503
|
+
className: PolymarketUS
|
|
4492
4504
|
params:
|
|
4493
4505
|
- name: pmxt_api_key
|
|
4494
4506
|
tsName: pmxtApiKey
|
|
@@ -4533,7 +4545,7 @@ x-sdk-constructors:
|
|
|
4533
4545
|
type: string
|
|
4534
4546
|
description: API secret for authentication
|
|
4535
4547
|
suibets:
|
|
4536
|
-
className:
|
|
4548
|
+
className: SuiBets
|
|
4537
4549
|
params:
|
|
4538
4550
|
- name: pmxt_api_key
|
|
4539
4551
|
tsName: pmxtApiKey
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmxt-core",
|
|
3
|
-
"version": "2.51.
|
|
3
|
+
"version": "2.51.3",
|
|
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.51.
|
|
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.51.
|
|
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.51.3,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.51.3,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",
|