pmxtjs 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/BaseExchange.d.ts +2 -2
- package/dist/BaseExchange.js +2 -2
- package/dist/exchanges/Kalshi.js +9 -5
- package/dist/exchanges/Polymarket.js +4 -3
- package/package.json +6 -5
- package/readme.md +51 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 qoery.com
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/BaseExchange.d.ts
CHANGED
|
@@ -22,8 +22,8 @@ export declare abstract class PredictionMarketExchange {
|
|
|
22
22
|
*/
|
|
23
23
|
abstract searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
24
24
|
/**
|
|
25
|
-
* Fetch historical price data for a specific market
|
|
26
|
-
* @param id - The
|
|
25
|
+
* Fetch historical price data for a specific market outcome.
|
|
26
|
+
* @param id - The Outcome ID (MarketOutcome.id). This should be the ID of the specific tradeable asset.
|
|
27
27
|
*/
|
|
28
28
|
getMarketHistory(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
|
|
29
29
|
/**
|
package/dist/BaseExchange.js
CHANGED
|
@@ -6,8 +6,8 @@ exports.PredictionMarketExchange = void 0;
|
|
|
6
6
|
// ----------------------------------------------------------------------------
|
|
7
7
|
class PredictionMarketExchange {
|
|
8
8
|
/**
|
|
9
|
-
* Fetch historical price data for a specific market
|
|
10
|
-
* @param id - The
|
|
9
|
+
* Fetch historical price data for a specific market outcome.
|
|
10
|
+
* @param id - The Outcome ID (MarketOutcome.id). This should be the ID of the specific tradeable asset.
|
|
11
11
|
*/
|
|
12
12
|
async getMarketHistory(id, params) {
|
|
13
13
|
throw new Error("Method getMarketHistory not implemented.");
|
package/dist/exchanges/Kalshi.js
CHANGED
|
@@ -116,13 +116,13 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
116
116
|
}
|
|
117
117
|
const outcomes = [
|
|
118
118
|
{
|
|
119
|
-
id:
|
|
119
|
+
id: market.ticker, // The actual market ticker (primary tradeable)
|
|
120
120
|
label: candidateName || 'Yes',
|
|
121
121
|
price: price,
|
|
122
122
|
priceChange24h: priceChange
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
|
-
id:
|
|
125
|
+
id: `${market.ticker}-NO`, // Virtual ID for the No outcome
|
|
126
126
|
label: candidateName ? `Not ${candidateName}` : 'No',
|
|
127
127
|
price: 1 - price,
|
|
128
128
|
priceChange24h: -priceChange // Inverse change for No? simplified assumption
|
|
@@ -211,7 +211,9 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
211
211
|
async getMarketHistory(id, params) {
|
|
212
212
|
try {
|
|
213
213
|
// Kalshi API expects uppercase tickers
|
|
214
|
-
|
|
214
|
+
// Handle virtual "-NO" suffix by stripping it (fetching the underlying market history)
|
|
215
|
+
const cleanedId = id.replace(/-NO$/, '');
|
|
216
|
+
const normalizedId = cleanedId.toUpperCase();
|
|
215
217
|
const interval = this.mapIntervalToKalshi(params.resolution);
|
|
216
218
|
// Heuristic for series_ticker
|
|
217
219
|
const parts = normalizedId.split('-');
|
|
@@ -261,7 +263,8 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
261
263
|
}
|
|
262
264
|
async getOrderBook(id) {
|
|
263
265
|
try {
|
|
264
|
-
const
|
|
266
|
+
const ticker = id.replace(/-NO$/, '');
|
|
267
|
+
const url = `https://api.elections.kalshi.com/trade-api/v2/markets/${ticker}/orderbook`;
|
|
265
268
|
const response = await axios_1.default.get(url);
|
|
266
269
|
const data = response.data.orderbook;
|
|
267
270
|
// Structure: { yes: [[price, qty], ...], no: [[price, qty], ...] }
|
|
@@ -285,10 +288,11 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
285
288
|
}
|
|
286
289
|
async getTradeHistory(id, params) {
|
|
287
290
|
try {
|
|
291
|
+
const ticker = id.replace(/-NO$/, '');
|
|
288
292
|
const url = `https://api.elections.kalshi.com/trade-api/v2/markets/trades`;
|
|
289
293
|
const response = await axios_1.default.get(url, {
|
|
290
294
|
params: {
|
|
291
|
-
ticker:
|
|
295
|
+
ticker: ticker,
|
|
292
296
|
limit: params.limit || 100
|
|
293
297
|
}
|
|
294
298
|
});
|
|
@@ -95,11 +95,12 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
95
95
|
priceChange = Number(market.oneDayPriceChange || 0);
|
|
96
96
|
}
|
|
97
97
|
outcomes.push({
|
|
98
|
-
id: String(index),
|
|
98
|
+
id: clobTokenIds[index] || String(index), // Use CLOB Token ID as the primary ID
|
|
99
99
|
label: outcomeLabel,
|
|
100
100
|
price: parseFloat(rawPrice) || 0,
|
|
101
101
|
priceChange24h: priceChange,
|
|
102
102
|
metadata: {
|
|
103
|
+
// clobTokenId is now the main ID, but keeping it in metadata for backward compat if needed
|
|
103
104
|
clobTokenId: clobTokenIds[index]
|
|
104
105
|
}
|
|
105
106
|
});
|
|
@@ -218,7 +219,7 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
218
219
|
priceChange = Number(market.oneDayPriceChange || 0);
|
|
219
220
|
}
|
|
220
221
|
outcomes.push({
|
|
221
|
-
id: String(index),
|
|
222
|
+
id: clobTokenIds[index] || String(index),
|
|
222
223
|
label: outcomeLabel,
|
|
223
224
|
price: parseFloat(outcomePrices[index] || "0") || 0,
|
|
224
225
|
priceChange24h: priceChange,
|
|
@@ -273,7 +274,7 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
273
274
|
async getMarketHistory(id, params) {
|
|
274
275
|
// ID Validation: Polymarket CLOB requires a Token ID (long numeric string) not a Market ID
|
|
275
276
|
if (id.length < 10 && /^\d+$/.test(id)) {
|
|
276
|
-
throw new Error(`Invalid ID for Polymarket history: "${id}". You provided a Market ID, but Polymarket's CLOB API requires a Token ID.
|
|
277
|
+
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'.`);
|
|
277
278
|
}
|
|
278
279
|
try {
|
|
279
280
|
const fidelity = this.mapIntervalToFidelity(params.resolution);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmxtjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "pmxt is a unified prediction market data API. The ccxt for prediction markets.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -18,14 +18,15 @@
|
|
|
18
18
|
},
|
|
19
19
|
"keywords": [],
|
|
20
20
|
"author": "",
|
|
21
|
-
"license": "
|
|
21
|
+
"license": "MIT",
|
|
22
22
|
"type": "commonjs",
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"axios": "^1.7.9",
|
|
25
|
+
"jest": "^30.2.0",
|
|
25
26
|
"tsx": "^4.21.0"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
|
-
"
|
|
29
|
-
"
|
|
29
|
+
"@types/node": "^25.0.3",
|
|
30
|
+
"typescript": "^5.9.3"
|
|
30
31
|
}
|
|
31
|
-
}
|
|
32
|
+
}
|
package/readme.md
CHANGED
|
@@ -1,7 +1,53 @@
|
|
|
1
|
-
# pmxt
|
|
1
|
+
# pmxt [](https://twitter.com/intent/tweet?text=The%20ccxt%20for%20prediction%20markets.&url=https://github.com/qoery-com/pmxt&hashtags=predictionmarkets,trading)
|
|
2
2
|
|
|
3
3
|
**The ccxt for prediction markets.** A unified API for accessing prediction market data across multiple exchanges.
|
|
4
4
|
|
|
5
|
+
<img width="3840" height="2160" alt="plot" src="https://github.com/user-attachments/assets/ed77d244-c95f-4fe0-a7a7-89af713c053f" />
|
|
6
|
+
|
|
7
|
+
<div align="center">
|
|
8
|
+
<table>
|
|
9
|
+
<tr>
|
|
10
|
+
<td rowspan="3">
|
|
11
|
+
<a href="https://www.producthunt.com/products/qoery-python-sdk?embed=true&utm_source=badge-featured&utm_medium=badge&utm_campaign=badge-qoery-python-sdk" target="_blank" rel="noopener noreferrer"><img alt="Qoery Python SDK - 50% cheaper crypto data. Now in Python. | Product Hunt" width="250" height="54" src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1056631&theme=light&t=1767263265752"></a>
|
|
12
|
+
</td>
|
|
13
|
+
<td>
|
|
14
|
+
<img src="https://img.shields.io/github/watchers/qoery-com/pmxt?style=social" alt="GitHub watchers">
|
|
15
|
+
</td>
|
|
16
|
+
<td>
|
|
17
|
+
<a href="https://www.npmjs.com/package/pmxtjs"><img src="https://img.shields.io/npm/dt/pmxtjs" alt="Downloads"></a>
|
|
18
|
+
</td>
|
|
19
|
+
</tr>
|
|
20
|
+
<tr>
|
|
21
|
+
<td>
|
|
22
|
+
<img src="https://img.shields.io/github/forks/qoery-com/pmxt?style=social" alt="GitHub forks">
|
|
23
|
+
</td>
|
|
24
|
+
<td>
|
|
25
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
|
|
26
|
+
</td>
|
|
27
|
+
</tr>
|
|
28
|
+
<tr>
|
|
29
|
+
<td>
|
|
30
|
+
<a href="https://github.com/qoery-com/pmxt/stargazers"><img src="https://img.shields.io/github/stars/qoery-com/pmxt?refresh=1" alt="GitHub stars"></a>
|
|
31
|
+
</td>
|
|
32
|
+
<td>
|
|
33
|
+
<!-- Space for future badge -->
|
|
34
|
+
</td>
|
|
35
|
+
</tr>
|
|
36
|
+
</table>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<img src="https://polymarket.com/favicon.ico" alt="Polymarket" width="40" height="40">
|
|
41
|
+
|
|
42
|
+
<img src="https://kalshi.com/favicon.ico" alt="Kalshi" width="40" height="40">
|
|
43
|
+
|
|
44
|
+
<img src="https://manifold.markets/logo.svg" alt="Manifold Markets" width="40" height="40">
|
|
45
|
+
|
|
46
|
+
<img src="https://metaculus.com/favicon.ico" alt="Metaculus" width="40" height="40">
|
|
47
|
+
|
|
48
|
+
<img src="https://predictit.org/favicon.ico" alt="PredictIt" width="40" height="40">
|
|
49
|
+
</p>
|
|
50
|
+
|
|
5
51
|
## Why pmxt?
|
|
6
52
|
|
|
7
53
|
Different prediction market platforms have different APIs, data formats, and conventions. pmxt provides a single, consistent interface to work with all of them.
|
|
@@ -13,7 +59,7 @@ Search for markets across Polymarket and Kalshi using the same API:
|
|
|
13
59
|
```typescript
|
|
14
60
|
import { PolymarketExchange, KalshiExchange } from 'pmxtjs';
|
|
15
61
|
|
|
16
|
-
const query = process.argv[2] || 'Fed';
|
|
62
|
+
const query = process.argv[2] || 'Who will Trump nominate as Fed Chair?';
|
|
17
63
|
console.log(`Searching for "${query}"...\n`);
|
|
18
64
|
|
|
19
65
|
// Polymarket
|
|
@@ -60,3 +106,6 @@ Check out the [examples](pmxt/examples/) directory for more use cases:
|
|
|
60
106
|
- Historical prices
|
|
61
107
|
- Event price tracking
|
|
62
108
|
- Recent trades
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
[](https://github.com/qoery-com/pmxt/stargazers)
|