pmxtjs 0.2.1 → 0.3.1
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 +222 -56
- package/dist/BaseExchange.d.ts +5 -4
- package/dist/BaseExchange.js +6 -6
- package/dist/exchanges/Kalshi.d.ts +3 -3
- package/dist/exchanges/Kalshi.js +38 -13
- package/dist/exchanges/Polymarket.d.ts +4 -4
- package/dist/exchanges/Polymarket.js +20 -9
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -0
- package/package.json +1 -1
- package/readme.md +11 -25
package/API_REFERENCE.md
CHANGED
|
@@ -1,88 +1,254 @@
|
|
|
1
1
|
# Prediction Market API Reference
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A unified interface for interacting with multiple prediction market exchanges (Kalshi, Polymarket) identically.
|
|
4
4
|
|
|
5
|
-
## Usage
|
|
5
|
+
## Installation & Usage
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm install pmxtjs
|
|
9
|
+
```
|
|
8
10
|
|
|
9
11
|
```typescript
|
|
10
|
-
import
|
|
11
|
-
PolymarketExchange,
|
|
12
|
-
KalshiExchange
|
|
13
|
-
} from './pmxt';
|
|
12
|
+
import pmxt from 'pmxtjs';
|
|
14
13
|
|
|
15
|
-
const polymarket = new
|
|
16
|
-
const kalshi = new
|
|
14
|
+
const polymarket = new pmxt.polymarket();
|
|
15
|
+
const kalshi = new pmxt.kalshi();
|
|
17
16
|
```
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
---
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
## Core Methods
|
|
22
21
|
|
|
23
22
|
### `fetchMarkets(params?)`
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
Get active markets from an exchange.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
const markets = await polymarket.fetchMarkets({
|
|
27
|
+
limit: 20,
|
|
28
|
+
offset: 0,
|
|
29
|
+
sort: 'volume' // 'volume' | 'liquidity' | 'newest'
|
|
30
|
+
});
|
|
31
|
+
```
|
|
27
32
|
|
|
28
33
|
### `searchMarkets(query, params?)`
|
|
29
|
-
Search markets by
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
Search markets by keyword. By default, searches only in titles.
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
const results = await kalshi.searchMarkets('Fed rates', {
|
|
38
|
+
limit: 10,
|
|
39
|
+
searchIn: 'title' // 'title' (default) | 'description' | 'both'
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### `getMarketsBySlug(slug)`
|
|
44
|
+
Fetch markets by URL slug/ticker.
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// Polymarket: use URL slug
|
|
48
|
+
const polyMarkets = await polymarket.getMarketsBySlug('who-will-trump-nominate-as-fed-chair');
|
|
49
|
+
|
|
50
|
+
// Kalshi: use event ticker (auto-uppercased)
|
|
51
|
+
const kalshiMarkets = await kalshi.getMarketsBySlug('FED-25JAN');
|
|
52
|
+
```
|
|
32
53
|
|
|
33
54
|
---
|
|
34
55
|
|
|
35
|
-
##
|
|
56
|
+
## Deep-Dive Methods
|
|
57
|
+
|
|
58
|
+
### `fetchOHLCV(outcomeId, params)`
|
|
59
|
+
Get historical price candles.
|
|
60
|
+
|
|
61
|
+
**CRITICAL**: Use `outcome.id`, not `market.id`.
|
|
62
|
+
- **Polymarket**: `outcome.id` is the CLOB Token ID
|
|
63
|
+
- **Kalshi**: `outcome.id` is the Market Ticker
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const markets = await polymarket.searchMarkets('Trump');
|
|
67
|
+
const outcomeId = markets[0].outcomes[0].id; // Get the outcome ID
|
|
68
|
+
|
|
69
|
+
const candles = await polymarket.fetchOHLCV(outcomeId, {
|
|
70
|
+
resolution: '1h', // '1m' | '5m' | '15m' | '1h' | '6h' | '1d'
|
|
71
|
+
start: new Date('2024-01-01'),
|
|
72
|
+
end: new Date('2024-01-31'),
|
|
73
|
+
limit: 100
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `fetchOrderBook(outcomeId)`
|
|
78
|
+
Get current bids/asks.
|
|
36
79
|
|
|
37
|
-
|
|
80
|
+
```typescript
|
|
81
|
+
const orderBook = await kalshi.fetchOrderBook('FED-25JAN');
|
|
82
|
+
console.log('Best bid:', orderBook.bids[0].price);
|
|
83
|
+
console.log('Best ask:', orderBook.asks[0].price);
|
|
84
|
+
```
|
|
38
85
|
|
|
39
|
-
### `
|
|
40
|
-
|
|
41
|
-
- **Input**: `id`, `resolution` (1m, 1h, 1d), `start`, `end`.
|
|
42
|
-
- **Output**: `Promise<PriceCandle[]>`
|
|
43
|
-
- **Important**:
|
|
44
|
-
- **Kalshi**: Uses the Market Ticker (e.g., `FED-25DEC`). Returns **native OHLCV** (Open/High/Low/Close data is distinct).
|
|
45
|
-
- **Polymarket**: Uses the **CLOB Token ID** found in `outcome.metadata.clobTokenId`. Returns **synthetic candles** (Open=High=Low=Close) derived from raw price points.
|
|
86
|
+
### `fetchTrades(outcomeId, params)`
|
|
87
|
+
Get trade history.
|
|
46
88
|
|
|
47
|
-
|
|
48
|
-
Fetches live Bids/Asks.
|
|
49
|
-
- **Input**: `id` (Ticker for Kalshi, Token ID for Polymarket).
|
|
50
|
-
- **Output**: `Promise<OrderBook>` (Normalized: "No" bids becomes "Yes" asks).
|
|
89
|
+
**Note**: Polymarket requires API key. Use `fetchOHLCV` for public historical data.
|
|
51
90
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
- **Polymarket**: Requires L2 Authentication (API Key). Without a key, this method will throw an unauthorized error. Use `getMarketHistory` for public historical data.
|
|
91
|
+
```typescript
|
|
92
|
+
const trades = await kalshi.fetchTrades('FED-25JAN', {
|
|
93
|
+
resolution: '1h',
|
|
94
|
+
limit: 100
|
|
95
|
+
});
|
|
96
|
+
```
|
|
59
97
|
|
|
60
98
|
---
|
|
61
99
|
|
|
62
|
-
##
|
|
100
|
+
## Data Models
|
|
63
101
|
|
|
64
|
-
### `UnifiedMarket`
|
|
102
|
+
### `UnifiedMarket`
|
|
65
103
|
```typescript
|
|
66
104
|
{
|
|
67
|
-
id: string;
|
|
68
|
-
title: string;
|
|
69
|
-
description: string;
|
|
70
|
-
outcomes: [
|
|
71
|
-
|
|
72
|
-
id: string,
|
|
73
|
-
label: "Trump",
|
|
74
|
-
price: 0.52,
|
|
75
|
-
priceChange24h: 0.05, // Optional: Change in price over last 24h
|
|
76
|
-
metadata: { ... } // Exchange-specific keys (clobTokenId)
|
|
77
|
-
}
|
|
78
|
-
];
|
|
105
|
+
id: string; // Market ID
|
|
106
|
+
title: string;
|
|
107
|
+
description: string;
|
|
108
|
+
outcomes: MarketOutcome[]; // All tradeable outcomes
|
|
109
|
+
|
|
79
110
|
resolutionDate: Date;
|
|
80
|
-
volume24h: number;
|
|
81
|
-
|
|
111
|
+
volume24h: number; // USD
|
|
112
|
+
volume?: number; // Total volume (USD)
|
|
113
|
+
liquidity: number; // USD
|
|
114
|
+
openInterest?: number; // USD
|
|
115
|
+
|
|
82
116
|
url: string;
|
|
83
|
-
image?: string;
|
|
84
|
-
category?: string;
|
|
85
|
-
tags?: string[];
|
|
117
|
+
image?: string;
|
|
118
|
+
category?: string;
|
|
119
|
+
tags?: string[];
|
|
86
120
|
}
|
|
87
121
|
```
|
|
88
122
|
|
|
123
|
+
### `MarketOutcome`
|
|
124
|
+
```typescript
|
|
125
|
+
{
|
|
126
|
+
id: string; // ⚠️ Use this for fetchOHLCV/fetchOrderBook/fetchTrades
|
|
127
|
+
// Polymarket: CLOB Token ID
|
|
128
|
+
// Kalshi: Market Ticker
|
|
129
|
+
label: string; // "Trump", "Yes", etc.
|
|
130
|
+
price: number; // 0.0 to 1.0 (probability)
|
|
131
|
+
priceChange24h?: number;
|
|
132
|
+
metadata?: {
|
|
133
|
+
clobTokenId?: string; // Polymarket only
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Other Types
|
|
139
|
+
```typescript
|
|
140
|
+
interface PriceCandle {
|
|
141
|
+
timestamp: number; // Unix ms
|
|
142
|
+
open: number; // 0.0 to 1.0
|
|
143
|
+
high: number;
|
|
144
|
+
low: number;
|
|
145
|
+
close: number;
|
|
146
|
+
volume?: number;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
interface OrderBook {
|
|
150
|
+
bids: OrderLevel[]; // Sorted high to low
|
|
151
|
+
asks: OrderLevel[]; // Sorted low to high
|
|
152
|
+
timestamp?: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
interface OrderLevel {
|
|
156
|
+
price: number; // 0.0 to 1.0
|
|
157
|
+
size: number; // Contracts
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
interface Trade {
|
|
161
|
+
id: string;
|
|
162
|
+
timestamp: number; // Unix ms
|
|
163
|
+
price: number; // 0.0 to 1.0
|
|
164
|
+
amount: number;
|
|
165
|
+
side: 'buy' | 'sell' | 'unknown';
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Complete Workflow Example
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// 1. Search for markets
|
|
175
|
+
const markets = await polymarket.searchMarkets('Fed Chair');
|
|
176
|
+
const market = markets[0];
|
|
177
|
+
|
|
178
|
+
// 2. Get outcome details
|
|
179
|
+
const outcome = market.outcomes[0];
|
|
180
|
+
console.log(`${outcome.label}: ${(outcome.price * 100).toFixed(1)}%`);
|
|
181
|
+
|
|
182
|
+
// 3. Fetch historical data (use outcome.id!)
|
|
183
|
+
const candles = await polymarket.fetchOHLCV(outcome.id, {
|
|
184
|
+
resolution: '1d',
|
|
185
|
+
limit: 30
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// 4. Get current order book
|
|
189
|
+
const orderBook = await polymarket.fetchOrderBook(outcome.id);
|
|
190
|
+
const spread = orderBook.asks[0].price - orderBook.bids[0].price;
|
|
191
|
+
console.log(`Spread: ${(spread * 100).toFixed(2)}%`);
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Exchange Differences
|
|
197
|
+
|
|
198
|
+
| Feature | Polymarket | Kalshi |
|
|
199
|
+
|---------|-----------|--------|
|
|
200
|
+
| **Sorting** | Server-side | Client-side (slower for large sets) |
|
|
201
|
+
| **Market ID** | UUID | Event Ticker (e.g., "PRES-2024") |
|
|
202
|
+
| **Outcome ID** | CLOB Token ID | Market Ticker (e.g., "FED-25JAN") |
|
|
203
|
+
| **OHLCV Quality** | Synthetic (O=H=L=C) | Native (distinct values) |
|
|
204
|
+
| **Auth Required** | Only for `fetchTrades()` | No (all public) |
|
|
205
|
+
| **Slug Format** | lowercase-with-hyphens | UPPERCASE (auto-normalized) |
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Error Handling
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
try {
|
|
213
|
+
const markets = await kalshi.getMarketsBySlug('INVALID-TICKER');
|
|
214
|
+
} catch (error) {
|
|
215
|
+
// Kalshi: "Event not found: INVALID-TICKER"
|
|
216
|
+
// Polymarket: Returns empty array []
|
|
217
|
+
console.error(error.message);
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Common Errors**:
|
|
222
|
+
- `404`: Market/event doesn't exist
|
|
223
|
+
- `401`: Missing API key (Polymarket `fetchTrades`)
|
|
224
|
+
- `429`: Rate limited
|
|
225
|
+
- `500`: Exchange API issue
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Type Exports
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
import pmxt, {
|
|
233
|
+
UnifiedMarket,
|
|
234
|
+
MarketOutcome,
|
|
235
|
+
PriceCandle,
|
|
236
|
+
OrderBook,
|
|
237
|
+
Trade,
|
|
238
|
+
CandleInterval,
|
|
239
|
+
MarketFilterParams,
|
|
240
|
+
HistoryFilterParams
|
|
241
|
+
} from 'pmxtjs';
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Quick Reference
|
|
247
|
+
|
|
248
|
+
- **Prices**: Always 0.0-1.0 (multiply by 100 for %)
|
|
249
|
+
- **Timestamps**: Unix milliseconds
|
|
250
|
+
- **Volumes**: USD
|
|
251
|
+
- **IDs**: Use `outcome.id` for deep-dive methods, not `market.id`
|
|
252
|
+
|
|
253
|
+
For more examples, see [`examples/`](examples/).
|
|
254
|
+
|
package/dist/BaseExchange.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export interface MarketFilterParams {
|
|
|
3
3
|
limit?: number;
|
|
4
4
|
offset?: number;
|
|
5
5
|
sort?: 'volume' | 'liquidity' | 'newest';
|
|
6
|
+
searchIn?: 'title' | 'description' | 'both';
|
|
6
7
|
}
|
|
7
8
|
export interface HistoryFilterParams {
|
|
8
9
|
resolution: CandleInterval;
|
|
@@ -18,22 +19,22 @@ export declare abstract class PredictionMarketExchange {
|
|
|
18
19
|
abstract fetchMarkets(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
19
20
|
/**
|
|
20
21
|
* Search for markets matching a keyword query.
|
|
21
|
-
*
|
|
22
|
+
* By default, searches only in market titles. Use params.searchIn to search descriptions or both.
|
|
22
23
|
*/
|
|
23
24
|
abstract searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
24
25
|
/**
|
|
25
26
|
* Fetch historical price data for a specific market outcome.
|
|
26
27
|
* @param id - The Outcome ID (MarketOutcome.id). This should be the ID of the specific tradeable asset.
|
|
27
28
|
*/
|
|
28
|
-
|
|
29
|
+
fetchOHLCV(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
|
|
29
30
|
/**
|
|
30
31
|
* Fetch the current order book (bids/asks) for a specific outcome.
|
|
31
32
|
* Essential for calculating localized spread and depth.
|
|
32
33
|
*/
|
|
33
|
-
|
|
34
|
+
fetchOrderBook(id: string): Promise<OrderBook>;
|
|
34
35
|
/**
|
|
35
36
|
* Fetch raw trade history.
|
|
36
37
|
* Useful for generating synthetic OHLCV candles if the exchange doesn't provide them natively.
|
|
37
38
|
*/
|
|
38
|
-
|
|
39
|
+
fetchTrades(id: string, params: HistoryFilterParams): Promise<Trade[]>;
|
|
39
40
|
}
|
package/dist/BaseExchange.js
CHANGED
|
@@ -9,22 +9,22 @@ class PredictionMarketExchange {
|
|
|
9
9
|
* Fetch historical price data for a specific market outcome.
|
|
10
10
|
* @param id - The Outcome ID (MarketOutcome.id). This should be the ID of the specific tradeable asset.
|
|
11
11
|
*/
|
|
12
|
-
async
|
|
13
|
-
throw new Error("Method
|
|
12
|
+
async fetchOHLCV(id, params) {
|
|
13
|
+
throw new Error("Method fetchOHLCV not implemented.");
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Fetch the current order book (bids/asks) for a specific outcome.
|
|
17
17
|
* Essential for calculating localized spread and depth.
|
|
18
18
|
*/
|
|
19
|
-
async
|
|
20
|
-
throw new Error("Method
|
|
19
|
+
async fetchOrderBook(id) {
|
|
20
|
+
throw new Error("Method fetchOrderBook not implemented.");
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Fetch raw trade history.
|
|
24
24
|
* Useful for generating synthetic OHLCV candles if the exchange doesn't provide them natively.
|
|
25
25
|
*/
|
|
26
|
-
async
|
|
27
|
-
throw new Error("Method
|
|
26
|
+
async fetchTrades(id, params) {
|
|
27
|
+
throw new Error("Method fetchTrades not implemented.");
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
exports.PredictionMarketExchange = PredictionMarketExchange;
|
|
@@ -14,7 +14,7 @@ export declare class KalshiExchange extends PredictionMarketExchange {
|
|
|
14
14
|
*/
|
|
15
15
|
getMarketsBySlug(eventTicker: string): Promise<UnifiedMarket[]>;
|
|
16
16
|
private mapIntervalToKalshi;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
fetchOHLCV(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
|
|
18
|
+
fetchOrderBook(id: string): Promise<OrderBook>;
|
|
19
|
+
fetchTrades(id: string, params: HistoryFilterParams): Promise<Trade[]>;
|
|
20
20
|
}
|
package/dist/exchanges/Kalshi.js
CHANGED
|
@@ -149,8 +149,16 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
149
149
|
try {
|
|
150
150
|
const markets = await this.fetchMarkets({ ...params, limit: fetchLimit });
|
|
151
151
|
const lowerQuery = query.toLowerCase();
|
|
152
|
-
const
|
|
153
|
-
|
|
152
|
+
const searchIn = params?.searchIn || 'title'; // Default to title-only search
|
|
153
|
+
const filtered = markets.filter(market => {
|
|
154
|
+
const titleMatch = (market.title || '').toLowerCase().includes(lowerQuery);
|
|
155
|
+
const descMatch = (market.description || '').toLowerCase().includes(lowerQuery);
|
|
156
|
+
if (searchIn === 'title')
|
|
157
|
+
return titleMatch;
|
|
158
|
+
if (searchIn === 'description')
|
|
159
|
+
return descMatch;
|
|
160
|
+
return titleMatch || descMatch; // 'both'
|
|
161
|
+
});
|
|
154
162
|
const limit = params?.limit || 20;
|
|
155
163
|
return filtered.slice(0, limit);
|
|
156
164
|
}
|
|
@@ -208,7 +216,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
208
216
|
};
|
|
209
217
|
return mapping[interval];
|
|
210
218
|
}
|
|
211
|
-
async
|
|
219
|
+
async fetchOHLCV(id, params) {
|
|
212
220
|
try {
|
|
213
221
|
// Kalshi API expects uppercase tickers
|
|
214
222
|
// Handle virtual "-NO" suffix by stripping it (fetching the underlying market history)
|
|
@@ -239,14 +247,31 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
239
247
|
queryParams.end_ts = endTs;
|
|
240
248
|
const response = await axios_1.default.get(url, { params: queryParams });
|
|
241
249
|
const candles = response.data.candlesticks || [];
|
|
242
|
-
const mappedCandles = candles.map((c) =>
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
+
const mappedCandles = candles.map((c) => {
|
|
251
|
+
// Priority:
|
|
252
|
+
// 1. Transaction price (close)
|
|
253
|
+
// 2. Mid price (average of yes_ask and yes_bid close)
|
|
254
|
+
// 3. Fallback to 0 if everything is missing
|
|
255
|
+
const p = c.price || {};
|
|
256
|
+
const ask = c.yes_ask || {};
|
|
257
|
+
const bid = c.yes_bid || {};
|
|
258
|
+
const getVal = (field) => {
|
|
259
|
+
if (p[field] !== null && p[field] !== undefined)
|
|
260
|
+
return p[field];
|
|
261
|
+
if (ask[field] !== null && bid[field] !== null && ask[field] !== undefined && bid[field] !== undefined) {
|
|
262
|
+
return (ask[field] + bid[field]) / 2;
|
|
263
|
+
}
|
|
264
|
+
return p.previous || 0;
|
|
265
|
+
};
|
|
266
|
+
return {
|
|
267
|
+
timestamp: c.end_period_ts * 1000,
|
|
268
|
+
open: getVal('open') / 100,
|
|
269
|
+
high: getVal('high') / 100,
|
|
270
|
+
low: getVal('low') / 100,
|
|
271
|
+
close: getVal('close') / 100,
|
|
272
|
+
volume: c.volume || 0
|
|
273
|
+
};
|
|
274
|
+
});
|
|
250
275
|
if (params.limit && mappedCandles.length > params.limit) {
|
|
251
276
|
return mappedCandles.slice(-params.limit);
|
|
252
277
|
}
|
|
@@ -261,7 +286,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
261
286
|
throw error;
|
|
262
287
|
}
|
|
263
288
|
}
|
|
264
|
-
async
|
|
289
|
+
async fetchOrderBook(id) {
|
|
265
290
|
try {
|
|
266
291
|
const ticker = id.replace(/-NO$/, '');
|
|
267
292
|
const url = `https://api.elections.kalshi.com/trade-api/v2/markets/${ticker}/orderbook`;
|
|
@@ -286,7 +311,7 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
286
311
|
return { bids: [], asks: [] };
|
|
287
312
|
}
|
|
288
313
|
}
|
|
289
|
-
async
|
|
314
|
+
async fetchTrades(id, params) {
|
|
290
315
|
try {
|
|
291
316
|
const ticker = id.replace(/-NO$/, '');
|
|
292
317
|
const url = `https://api.elections.kalshi.com/trade-api/v2/markets/trades`;
|
|
@@ -20,19 +20,19 @@ export declare class PolymarketExchange extends PredictionMarketExchange {
|
|
|
20
20
|
* Fetch historical price data (OHLCV candles) for a specific token.
|
|
21
21
|
* @param id - The CLOB token ID (e.g., outcome token ID)
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
fetchOHLCV(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
|
|
24
24
|
/**
|
|
25
25
|
* Fetch the current order book for a specific token.
|
|
26
26
|
* @param id - The CLOB token ID
|
|
27
27
|
*/
|
|
28
|
-
|
|
28
|
+
fetchOrderBook(id: string): Promise<OrderBook>;
|
|
29
29
|
/**
|
|
30
30
|
* Fetch raw trade history for a specific token.
|
|
31
31
|
* @param id - The CLOB token ID
|
|
32
32
|
*
|
|
33
33
|
* NOTE: Polymarket's /trades endpoint currently requires L2 Authentication (API Key).
|
|
34
34
|
* This method will return an empty array if an API key is not provided in headers.
|
|
35
|
-
* Use
|
|
35
|
+
* Use fetchOHLCV for public historical price data instead.
|
|
36
36
|
*/
|
|
37
|
-
|
|
37
|
+
fetchTrades(id: string, params: HistoryFilterParams): Promise<Trade[]>;
|
|
38
38
|
}
|
|
@@ -64,6 +64,7 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
64
64
|
outcomePrices = typeof market.outcomePrices === 'string' ? JSON.parse(market.outcomePrices) : (market.outcomePrices || []);
|
|
65
65
|
}
|
|
66
66
|
catch (e) {
|
|
67
|
+
console.warn(`Error parsing outcomes for market ${market.id}:`, e);
|
|
67
68
|
}
|
|
68
69
|
// Extract CLOB token IDs for granular operations
|
|
69
70
|
let clobTokenIds = [];
|
|
@@ -148,8 +149,8 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
148
149
|
}
|
|
149
150
|
async searchMarkets(query, params) {
|
|
150
151
|
// Polymarket Gamma API doesn't support native search
|
|
151
|
-
// Fetch
|
|
152
|
-
const searchLimit =
|
|
152
|
+
// Fetch all active markets and filter client-side
|
|
153
|
+
const searchLimit = 100000; // Fetch all markets for comprehensive search
|
|
153
154
|
try {
|
|
154
155
|
// Fetch markets with a higher limit
|
|
155
156
|
const markets = await this.fetchMarkets({
|
|
@@ -158,8 +159,16 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
158
159
|
});
|
|
159
160
|
// Client-side text filtering
|
|
160
161
|
const lowerQuery = query.toLowerCase();
|
|
161
|
-
const
|
|
162
|
-
|
|
162
|
+
const searchIn = params?.searchIn || 'title'; // Default to title-only search
|
|
163
|
+
const filtered = markets.filter(market => {
|
|
164
|
+
const titleMatch = (market.title || '').toLowerCase().includes(lowerQuery);
|
|
165
|
+
const descMatch = (market.description || '').toLowerCase().includes(lowerQuery);
|
|
166
|
+
if (searchIn === 'title')
|
|
167
|
+
return titleMatch;
|
|
168
|
+
if (searchIn === 'description')
|
|
169
|
+
return descMatch;
|
|
170
|
+
return titleMatch || descMatch; // 'both'
|
|
171
|
+
});
|
|
163
172
|
// Apply limit to filtered results
|
|
164
173
|
const limit = params?.limit || 20;
|
|
165
174
|
return filtered.slice(0, limit);
|
|
@@ -201,7 +210,9 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
201
210
|
outcomePrices = typeof market.outcomePrices === 'string' ? JSON.parse(market.outcomePrices) : (market.outcomePrices || []);
|
|
202
211
|
clobTokenIds = typeof market.clobTokenIds === 'string' ? JSON.parse(market.clobTokenIds) : (market.clobTokenIds || []);
|
|
203
212
|
}
|
|
204
|
-
catch (e) {
|
|
213
|
+
catch (e) {
|
|
214
|
+
console.warn(`Error parsing outcomes for market ${market.id}:`, e);
|
|
215
|
+
}
|
|
205
216
|
let candidateName = market.groupItemTitle;
|
|
206
217
|
if (!candidateName && market.question)
|
|
207
218
|
candidateName = market.question;
|
|
@@ -271,7 +282,7 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
271
282
|
* Fetch historical price data (OHLCV candles) for a specific token.
|
|
272
283
|
* @param id - The CLOB token ID (e.g., outcome token ID)
|
|
273
284
|
*/
|
|
274
|
-
async
|
|
285
|
+
async fetchOHLCV(id, params) {
|
|
275
286
|
// ID Validation: Polymarket CLOB requires a Token ID (long numeric string) not a Market ID
|
|
276
287
|
if (id.length < 10 && /^\d+$/.test(id)) {
|
|
277
288
|
throw new Error(`Invalid ID for Polymarket history: "${id}". You provided a Market ID, but Polymarket's CLOB API requires a Token ID. Ensure you are using 'outcome.id'.`);
|
|
@@ -336,7 +347,7 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
336
347
|
* Fetch the current order book for a specific token.
|
|
337
348
|
* @param id - The CLOB token ID
|
|
338
349
|
*/
|
|
339
|
-
async
|
|
350
|
+
async fetchOrderBook(id) {
|
|
340
351
|
try {
|
|
341
352
|
const response = await axios_1.default.get(`${this.clobUrl}/book`, {
|
|
342
353
|
params: { token_id: id }
|
|
@@ -368,9 +379,9 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
368
379
|
*
|
|
369
380
|
* NOTE: Polymarket's /trades endpoint currently requires L2 Authentication (API Key).
|
|
370
381
|
* This method will return an empty array if an API key is not provided in headers.
|
|
371
|
-
* Use
|
|
382
|
+
* Use fetchOHLCV for public historical price data instead.
|
|
372
383
|
*/
|
|
373
|
-
async
|
|
384
|
+
async fetchTrades(id, params) {
|
|
374
385
|
// ID Validation
|
|
375
386
|
if (id.length < 10 && /^\d+$/.test(id)) {
|
|
376
387
|
throw new Error(`Invalid ID for Polymarket trades: "${id}". You provided a Market ID, but Polymarket's CLOB API requires a Token ID.`);
|
package/dist/index.d.ts
CHANGED
|
@@ -2,3 +2,12 @@ export * from './BaseExchange';
|
|
|
2
2
|
export * from './types';
|
|
3
3
|
export * from './exchanges/Polymarket';
|
|
4
4
|
export * from './exchanges/Kalshi';
|
|
5
|
+
import { PolymarketExchange } from './exchanges/Polymarket';
|
|
6
|
+
import { KalshiExchange } from './exchanges/Kalshi';
|
|
7
|
+
declare const pmxt: {
|
|
8
|
+
polymarket: typeof PolymarketExchange;
|
|
9
|
+
kalshi: typeof KalshiExchange;
|
|
10
|
+
Polymarket: typeof PolymarketExchange;
|
|
11
|
+
Kalshi: typeof KalshiExchange;
|
|
12
|
+
};
|
|
13
|
+
export default pmxt;
|
package/dist/index.js
CHANGED
|
@@ -18,3 +18,12 @@ __exportStar(require("./BaseExchange"), exports);
|
|
|
18
18
|
__exportStar(require("./types"), exports);
|
|
19
19
|
__exportStar(require("./exchanges/Polymarket"), exports);
|
|
20
20
|
__exportStar(require("./exchanges/Kalshi"), exports);
|
|
21
|
+
const Polymarket_1 = require("./exchanges/Polymarket");
|
|
22
|
+
const Kalshi_1 = require("./exchanges/Kalshi");
|
|
23
|
+
const pmxt = {
|
|
24
|
+
polymarket: Polymarket_1.PolymarketExchange,
|
|
25
|
+
kalshi: Kalshi_1.KalshiExchange,
|
|
26
|
+
Polymarket: Polymarket_1.PolymarketExchange,
|
|
27
|
+
Kalshi: Kalshi_1.KalshiExchange
|
|
28
|
+
};
|
|
29
|
+
exports.default = pmxt;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -54,33 +54,19 @@ Different prediction market platforms have different APIs, data formats, and con
|
|
|
54
54
|
|
|
55
55
|
## Quick Example
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
Get the current price for any market in seconds:
|
|
58
58
|
|
|
59
59
|
```typescript
|
|
60
|
-
import
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
polyResults.slice(0, 10).forEach(m => {
|
|
71
|
-
const label = m.outcomes[0]?.label || 'Unknown';
|
|
72
|
-
console.log(`[${m.id}] ${m.title} - ${label} (Vol24h: $${m.volume24h.toLocaleString()})`);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// Kalshi
|
|
76
|
-
const kalshi = new KalshiExchange();
|
|
77
|
-
const kalshiResults = await kalshi.searchMarkets(query);
|
|
78
|
-
|
|
79
|
-
console.log(`\n--- Kalshi Found ${kalshiResults.length} ---`);
|
|
80
|
-
kalshiResults.slice(0, 10).forEach(m => {
|
|
81
|
-
const label = m.outcomes[0]?.label || 'Unknown';
|
|
82
|
-
console.log(`[${m.id}] ${m.title} - ${label} (Vol24h: $${m.volume24h.toLocaleString()})`);
|
|
83
|
-
});
|
|
60
|
+
import pmxt from 'pmxtjs';
|
|
61
|
+
|
|
62
|
+
async function main() {
|
|
63
|
+
const poly = new pmxt.polymarket();
|
|
64
|
+
const [market] = await poly.searchMarkets('Trump');
|
|
65
|
+
|
|
66
|
+
console.log(`${market.title} - ${market.outcomes[0].label}: ${marketoutcomes[0].price * 100}%`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
main();
|
|
84
70
|
```
|
|
85
71
|
|
|
86
72
|
## Installation
|