pmxtjs 0.1.1 → 0.1.2

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.
@@ -0,0 +1,88 @@
1
+ # Prediction Market API Reference
2
+
3
+ This project implements a **Unified Interface** for interacting with multiple prediction market exchanges (Kalshi, Polymarket) identically.
4
+
5
+ ## Usage
6
+
7
+ All components are available directly from the `pmxt` library.
8
+
9
+ ```typescript
10
+ import {
11
+ PolymarketExchange,
12
+ KalshiExchange
13
+ } from './pmxt';
14
+
15
+ const polymarket = new PolymarketExchange();
16
+ const kalshi = new KalshiExchange();
17
+ ```
18
+
19
+ ## 1. Unified Interface (`PredictionMarketExchange`)
20
+
21
+ All exchanges implement this core interface for discovery.
22
+
23
+ ### `fetchMarkets(params?)`
24
+ Retrieves active markets normalized into a standard format.
25
+ - **Input**: `limit`, `sort` ('volume' | 'liquidity' | 'newest')
26
+ - **Output**: `Promise<UnifiedMarket[]>`
27
+
28
+ ### `searchMarkets(query, params?)`
29
+ Search markets by title/description across the exchange(s).
30
+ - **Input**: `query` (string), `limit`
31
+ - **Output**: `Promise<UnifiedMarket[]>`
32
+
33
+ ---
34
+
35
+ ## 2. Deep-Dive Interface (Exchange Only)
36
+
37
+ Methods available on specific exchange instances (`KalshiExchange`, `PolymarketExchange`) for detailed data.
38
+
39
+ ### `getMarketHistory(id, params)`
40
+ Fetches OHLCV candlesticks.
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.
46
+
47
+ ### `getOrderBook(id)`
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).
51
+
52
+ ### `getTradeHistory(id, params)`
53
+ Fetches the "Tape" (raw transaction history).
54
+ - **Input**: `id`, `limit`.
55
+ - **Output**: `Promise<Trade[]>`
56
+ - **Note**:
57
+ - **Kalshi**: Publicly accessible for all tickers.
58
+ - **Polymarket**: Requires L2 Authentication (API Key). Without a key, this method will throw an unauthorized error. Use `getMarketHistory` for public historical data.
59
+
60
+ ---
61
+
62
+ ## 3. Data Models
63
+
64
+ ### `UnifiedMarket` (The Standard Atom)
65
+ ```typescript
66
+ {
67
+ id: string; // Exchange-specific ID
68
+ title: string; // "Who will win the election?"
69
+ description: string; // Detailed context/rules of the market
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
+ ];
79
+ resolutionDate: Date;
80
+ volume24h: number;
81
+ liquidity: number;
82
+ url: string;
83
+ image?: string; // Optional: Thumbnail URL
84
+ category?: string; // Optional: Primary category (e.g., "Politics")
85
+ tags?: string[]; // Optional: Searchable tags
86
+ }
87
+ ```
88
+
@@ -0,0 +1,39 @@
1
+ import { UnifiedMarket, PriceCandle, CandleInterval, OrderBook, Trade } from './types';
2
+ export interface MarketFilterParams {
3
+ limit?: number;
4
+ offset?: number;
5
+ sort?: 'volume' | 'liquidity' | 'newest';
6
+ }
7
+ export interface HistoryFilterParams {
8
+ resolution: CandleInterval;
9
+ start?: Date;
10
+ end?: Date;
11
+ limit?: number;
12
+ }
13
+ export declare abstract class PredictionMarketExchange {
14
+ abstract get name(): string;
15
+ /**
16
+ * Fetch all relevant markets from the source.
17
+ */
18
+ abstract fetchMarkets(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
19
+ /**
20
+ * Search for markets matching a keyword query.
21
+ * Searches across title and description fields.
22
+ */
23
+ abstract searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]>;
24
+ /**
25
+ * Fetch historical price data for a specific market or outcome.
26
+ * @param id - The market ID or specific outcome ID/Token ID depending on the exchange
27
+ */
28
+ getMarketHistory(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
29
+ /**
30
+ * Fetch the current order book (bids/asks) for a specific outcome.
31
+ * Essential for calculating localized spread and depth.
32
+ */
33
+ getOrderBook(id: string): Promise<OrderBook>;
34
+ /**
35
+ * Fetch raw trade history.
36
+ * Useful for generating synthetic OHLCV candles if the exchange doesn't provide them natively.
37
+ */
38
+ getTradeHistory(id: string, params: HistoryFilterParams): Promise<Trade[]>;
39
+ }
@@ -0,0 +1,20 @@
1
+ import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams } from '../BaseExchange';
2
+ import { UnifiedMarket, PriceCandle, OrderBook, Trade } from '../types';
3
+ export declare class KalshiExchange extends PredictionMarketExchange {
4
+ get name(): string;
5
+ private baseUrl;
6
+ fetchMarkets(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
7
+ private fetchActiveEvents;
8
+ private mapMarketToUnified;
9
+ searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]>;
10
+ /**
11
+ * Fetch specific markets by their event ticker.
12
+ * Useful for looking up a specific event from a URL.
13
+ * @param eventTicker - The event ticker (e.g. "FED-25JAN" or "PRES-2024")
14
+ */
15
+ getMarketsBySlug(eventTicker: string): Promise<UnifiedMarket[]>;
16
+ private mapIntervalToKalshi;
17
+ getMarketHistory(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
18
+ getOrderBook(id: string): Promise<OrderBook>;
19
+ getTradeHistory(id: string, params: HistoryFilterParams): Promise<Trade[]>;
20
+ }
@@ -31,7 +31,6 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
31
31
  }
32
32
  }
33
33
  }
34
- console.log(`Extracted ${allMarkets.length} markets from ${allEvents.length} events.`);
35
34
  // Sort by 24h volume
36
35
  if (params?.sort === 'volume') {
37
36
  allMarkets.sort((a, b) => b.volume24h - a.volume24h);
@@ -77,25 +76,18 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
77
76
  totalMarketCount += (event.markets || []).length;
78
77
  }
79
78
  // Early termination: if we have enough markets, stop fetching
80
- // Add a buffer (2x) to ensure we have enough after filtering/sorting
81
79
  if (totalMarketCount >= targetMarketCount * 2) {
82
- console.log(`Early termination: collected ${totalMarketCount} markets (target: ${targetMarketCount})`);
83
80
  break;
84
81
  }
85
82
  }
86
83
  cursor = response.data.cursor;
87
84
  page++;
88
- // Log progress every few pages to avoid spam
89
- if (page % 5 === 0) {
90
- console.log(`Fetched ${page} pages (${allEvents.length} events) from Kalshi...`);
91
- }
92
85
  }
93
86
  catch (e) {
94
87
  console.error(`Error fetching Kalshi page ${page}:`, e);
95
88
  break;
96
89
  }
97
90
  } while (cursor && page < MAX_PAGES);
98
- console.log(`Finished fetching Kalshi: ${allEvents.length} total events across ${page} pages.`);
99
91
  return allEvents;
100
92
  }
101
93
  mapMarketToUnified(event, market) {
@@ -0,0 +1,38 @@
1
+ import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams } from '../BaseExchange';
2
+ import { UnifiedMarket, PriceCandle, OrderBook, Trade } from '../types';
3
+ export declare class PolymarketExchange extends PredictionMarketExchange {
4
+ get name(): string;
5
+ private readonly baseUrl;
6
+ private readonly clobUrl;
7
+ fetchMarkets(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
8
+ searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]>;
9
+ /**
10
+ * Fetch specific markets by their URL slug.
11
+ * Useful for looking up a specific event from a URL.
12
+ * @param slug - The event slug (e.g. "will-fed-cut-rates-in-march")
13
+ */
14
+ getMarketsBySlug(slug: string): Promise<UnifiedMarket[]>;
15
+ /**
16
+ * Map our generic CandleInterval to Polymarket's fidelity (in minutes)
17
+ */
18
+ private mapIntervalToFidelity;
19
+ /**
20
+ * Fetch historical price data (OHLCV candles) for a specific token.
21
+ * @param id - The CLOB token ID (e.g., outcome token ID)
22
+ */
23
+ getMarketHistory(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
24
+ /**
25
+ * Fetch the current order book for a specific token.
26
+ * @param id - The CLOB token ID
27
+ */
28
+ getOrderBook(id: string): Promise<OrderBook>;
29
+ /**
30
+ * Fetch raw trade history for a specific token.
31
+ * @param id - The CLOB token ID
32
+ *
33
+ * NOTE: Polymarket's /trades endpoint currently requires L2 Authentication (API Key).
34
+ * This method will return an empty array if an API key is not provided in headers.
35
+ * Use getMarketHistory for public historical price data instead.
36
+ */
37
+ getTradeHistory(id: string, params: HistoryFilterParams): Promise<Trade[]>;
38
+ }
@@ -64,7 +64,6 @@ 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(`Failed to parse outcomes for market ${market.id}`, e);
68
67
  }
69
68
  // Extract CLOB token IDs for granular operations
70
69
  let clobTokenIds = [];
@@ -72,7 +71,6 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
72
71
  clobTokenIds = typeof market.clobTokenIds === 'string' ? JSON.parse(market.clobTokenIds) : (market.clobTokenIds || []);
73
72
  }
74
73
  catch (e) {
75
- console.warn(`Failed to parse clobTokenIds for market ${market.id}`, e);
76
74
  }
77
75
  // Extract candidate/option name from market question for better outcome labels
78
76
  let candidateName = null;
@@ -202,9 +200,7 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
202
200
  outcomePrices = typeof market.outcomePrices === 'string' ? JSON.parse(market.outcomePrices) : (market.outcomePrices || []);
203
201
  clobTokenIds = typeof market.clobTokenIds === 'string' ? JSON.parse(market.clobTokenIds) : (market.clobTokenIds || []);
204
202
  }
205
- catch (e) {
206
- console.warn(`Parse error for market ${market.id}`, e);
207
- }
203
+ catch (e) { /* ignore */ }
208
204
  let candidateName = market.groupItemTitle;
209
205
  if (!candidateName && market.question)
210
206
  candidateName = market.question;
@@ -0,0 +1,4 @@
1
+ export * from './BaseExchange';
2
+ export * from './types';
3
+ export * from './exchanges/Polymarket';
4
+ export * from './exchanges/Kalshi';
@@ -0,0 +1,47 @@
1
+ export interface MarketOutcome {
2
+ id: string;
3
+ label: string;
4
+ price: number;
5
+ priceChange24h?: number;
6
+ metadata?: Record<string, any>;
7
+ }
8
+ export interface UnifiedMarket {
9
+ id: string;
10
+ title: string;
11
+ description: string;
12
+ outcomes: MarketOutcome[];
13
+ resolutionDate: Date;
14
+ volume24h: number;
15
+ volume?: number;
16
+ liquidity: number;
17
+ openInterest?: number;
18
+ url: string;
19
+ image?: string;
20
+ category?: string;
21
+ tags?: string[];
22
+ }
23
+ export type CandleInterval = '1m' | '5m' | '15m' | '1h' | '6h' | '1d';
24
+ export interface PriceCandle {
25
+ timestamp: number;
26
+ open: number;
27
+ high: number;
28
+ low: number;
29
+ close: number;
30
+ volume?: number;
31
+ }
32
+ export interface OrderLevel {
33
+ price: number;
34
+ size: number;
35
+ }
36
+ export interface OrderBook {
37
+ bids: OrderLevel[];
38
+ asks: OrderLevel[];
39
+ timestamp?: number;
40
+ }
41
+ export interface Trade {
42
+ id: string;
43
+ timestamp: number;
44
+ price: number;
45
+ amount: number;
46
+ side: 'buy' | 'sell' | 'unknown';
47
+ }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "pmxtjs",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
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",
7
7
  "files": [
8
- "dist"
8
+ "dist",
9
+ "API_REFERENCE.md"
9
10
  ],
10
11
  "directories": {
11
12
  "example": "examples",
@@ -22,5 +23,9 @@
22
23
  "dependencies": {
23
24
  "axios": "^1.7.9",
24
25
  "tsx": "^4.21.0"
26
+ },
27
+ "devDependencies": {
28
+ "typescript": "^5.9.3",
29
+ "@types/node": "^25.0.3"
25
30
  }
26
31
  }
package/readme.md ADDED
@@ -0,0 +1,62 @@
1
+ # pmxt
2
+
3
+ **The ccxt for prediction markets.** A unified API for accessing prediction market data across multiple exchanges.
4
+
5
+ ## Why pmxt?
6
+
7
+ Different prediction market platforms have different APIs, data formats, and conventions. pmxt provides a single, consistent interface to work with all of them.
8
+
9
+ ## Quick Example
10
+
11
+ Search for markets across Polymarket and Kalshi using the same API:
12
+
13
+ ```typescript
14
+ import { PolymarketExchange, KalshiExchange } from 'pmxtjs';
15
+
16
+ const query = process.argv[2] || 'Fed';
17
+ console.log(`Searching for "${query}"...\n`);
18
+
19
+ // Polymarket
20
+ const polymarket = new PolymarketExchange();
21
+ const polyResults = await polymarket.searchMarkets(query, { sort: 'volume' });
22
+
23
+ console.log(`--- Polymarket Found ${polyResults.length} ---`);
24
+ polyResults.slice(0, 10).forEach(m => {
25
+ const label = m.outcomes[0]?.label || 'Unknown';
26
+ console.log(`[${m.id}] ${m.title} - ${label} (Vol24h: $${m.volume24h.toLocaleString()})`);
27
+ });
28
+
29
+ // Kalshi
30
+ const kalshi = new KalshiExchange();
31
+ const kalshiResults = await kalshi.searchMarkets(query);
32
+
33
+ console.log(`\n--- Kalshi Found ${kalshiResults.length} ---`);
34
+ kalshiResults.slice(0, 10).forEach(m => {
35
+ const label = m.outcomes[0]?.label || 'Unknown';
36
+ console.log(`[${m.id}] ${m.title} - ${label} (Vol24h: $${m.volume24h.toLocaleString()})`);
37
+ });
38
+ ```
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ npm install pmxtjs
44
+ ```
45
+
46
+ ## Supported Exchanges
47
+
48
+ - Polymarket
49
+ - Kalshi
50
+
51
+ ## Documentation
52
+
53
+ See the [API Reference](pmxt/API_REFERENCE.md) for detailed documentation and more examples.
54
+
55
+ ## Examples
56
+
57
+ Check out the [examples](pmxt/examples/) directory for more use cases:
58
+ - Market search
59
+ - Order book data
60
+ - Historical prices
61
+ - Event price tracking
62
+ - Recent trades