pmxtjs 0.3.0 → 0.4.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/API_REFERENCE.md +448 -51
- package/dist/BaseExchange.d.ts +38 -3
- package/dist/BaseExchange.js +43 -1
- package/dist/exchanges/Kalshi.js +10 -2
- package/dist/exchanges/Polymarket.js +12 -4
- package/dist/exchanges/kalshi/auth.d.ts +23 -0
- package/dist/exchanges/kalshi/auth.js +99 -0
- package/dist/exchanges/kalshi/fetchMarkets.d.ts +3 -0
- package/dist/exchanges/kalshi/fetchMarkets.js +84 -0
- package/dist/exchanges/kalshi/fetchOHLCV.d.ts +3 -0
- package/dist/exchanges/kalshi/fetchOHLCV.js +78 -0
- package/dist/exchanges/kalshi/fetchOrderBook.d.ts +2 -0
- package/dist/exchanges/kalshi/fetchOrderBook.js +32 -0
- package/dist/exchanges/kalshi/fetchTrades.d.ts +3 -0
- package/dist/exchanges/kalshi/fetchTrades.js +31 -0
- package/dist/exchanges/kalshi/getMarketsBySlug.d.ts +7 -0
- package/dist/exchanges/kalshi/getMarketsBySlug.js +46 -0
- package/dist/exchanges/kalshi/index.d.ts +21 -0
- package/dist/exchanges/kalshi/index.js +273 -0
- package/dist/exchanges/kalshi/kalshi.test.d.ts +1 -0
- package/dist/exchanges/kalshi/kalshi.test.js +309 -0
- package/dist/exchanges/kalshi/searchMarkets.d.ts +3 -0
- package/dist/exchanges/kalshi/searchMarkets.js +28 -0
- package/dist/exchanges/kalshi/utils.d.ts +4 -0
- package/dist/exchanges/kalshi/utils.js +70 -0
- package/dist/exchanges/polymarket/auth.d.ts +32 -0
- package/dist/exchanges/polymarket/auth.js +98 -0
- package/dist/exchanges/polymarket/fetchMarkets.d.ts +3 -0
- package/dist/exchanges/polymarket/fetchMarkets.js +75 -0
- package/dist/exchanges/polymarket/fetchOHLCV.d.ts +7 -0
- package/dist/exchanges/polymarket/fetchOHLCV.js +73 -0
- package/dist/exchanges/polymarket/fetchOrderBook.d.ts +6 -0
- package/dist/exchanges/polymarket/fetchOrderBook.js +38 -0
- package/dist/exchanges/polymarket/fetchPositions.d.ts +2 -0
- package/dist/exchanges/polymarket/fetchPositions.js +27 -0
- package/dist/exchanges/polymarket/fetchTrades.d.ts +11 -0
- package/dist/exchanges/polymarket/fetchTrades.js +59 -0
- package/dist/exchanges/polymarket/getMarketsBySlug.d.ts +7 -0
- package/dist/exchanges/polymarket/getMarketsBySlug.js +39 -0
- package/dist/exchanges/polymarket/index.d.ts +23 -0
- package/dist/exchanges/polymarket/index.js +216 -0
- package/dist/exchanges/polymarket/searchMarkets.d.ts +3 -0
- package/dist/exchanges/polymarket/searchMarkets.js +35 -0
- package/dist/exchanges/polymarket/utils.d.ts +7 -0
- package/dist/exchanges/polymarket/utils.js +95 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +8 -8
- package/dist/types.d.ts +38 -0
- package/package.json +5 -1
- package/readme.md +44 -24
|
@@ -149,8 +149,8 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
149
149
|
}
|
|
150
150
|
async searchMarkets(query, params) {
|
|
151
151
|
// Polymarket Gamma API doesn't support native search
|
|
152
|
-
// Fetch
|
|
153
|
-
const searchLimit =
|
|
152
|
+
// Fetch all active markets and filter client-side
|
|
153
|
+
const searchLimit = 100000; // Fetch all markets for comprehensive search
|
|
154
154
|
try {
|
|
155
155
|
// Fetch markets with a higher limit
|
|
156
156
|
const markets = await this.fetchMarkets({
|
|
@@ -159,8 +159,16 @@ class PolymarketExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
159
159
|
});
|
|
160
160
|
// Client-side text filtering
|
|
161
161
|
const lowerQuery = query.toLowerCase();
|
|
162
|
-
const
|
|
163
|
-
|
|
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
|
+
});
|
|
164
172
|
// Apply limit to filtered results
|
|
165
173
|
const limit = params?.limit || 20;
|
|
166
174
|
return filtered.slice(0, limit);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ExchangeCredentials } from '../../BaseExchange';
|
|
2
|
+
/**
|
|
3
|
+
* Manages Kalshi authentication using RSA-PSS signatures.
|
|
4
|
+
* Reference: https://docs.kalshi.com/getting_started/quick_start_authenticated_requests
|
|
5
|
+
*/
|
|
6
|
+
export declare class KalshiAuth {
|
|
7
|
+
private credentials;
|
|
8
|
+
constructor(credentials: ExchangeCredentials);
|
|
9
|
+
private validateCredentials;
|
|
10
|
+
/**
|
|
11
|
+
* Generates the required headers for an authenticated request.
|
|
12
|
+
*
|
|
13
|
+
* @param method The HTTP method (e.g., "GET", "POST").
|
|
14
|
+
* @param path The request path (e.g., "/trade-api/v2/portfolio/orders").
|
|
15
|
+
* @returns An object containing the authentication headers.
|
|
16
|
+
*/
|
|
17
|
+
getHeaders(method: string, path: string): Record<string, string>;
|
|
18
|
+
/**
|
|
19
|
+
* Signs the request using RSA-PSS.
|
|
20
|
+
* The message to sign is: timestamp + method + path
|
|
21
|
+
*/
|
|
22
|
+
private signRequest;
|
|
23
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.KalshiAuth = void 0;
|
|
37
|
+
const crypto = __importStar(require("crypto"));
|
|
38
|
+
/**
|
|
39
|
+
* Manages Kalshi authentication using RSA-PSS signatures.
|
|
40
|
+
* Reference: https://docs.kalshi.com/getting_started/quick_start_authenticated_requests
|
|
41
|
+
*/
|
|
42
|
+
class KalshiAuth {
|
|
43
|
+
constructor(credentials) {
|
|
44
|
+
this.credentials = credentials;
|
|
45
|
+
this.validateCredentials();
|
|
46
|
+
}
|
|
47
|
+
validateCredentials() {
|
|
48
|
+
if (!this.credentials.apiKey) {
|
|
49
|
+
throw new Error('Kalshi requires an apiKey (Key ID) for authentication');
|
|
50
|
+
}
|
|
51
|
+
if (!this.credentials.privateKey) {
|
|
52
|
+
throw new Error('Kalshi requires a privateKey (RSA Private Key) for authentication');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generates the required headers for an authenticated request.
|
|
57
|
+
*
|
|
58
|
+
* @param method The HTTP method (e.g., "GET", "POST").
|
|
59
|
+
* @param path The request path (e.g., "/trade-api/v2/portfolio/orders").
|
|
60
|
+
* @returns An object containing the authentication headers.
|
|
61
|
+
*/
|
|
62
|
+
getHeaders(method, path) {
|
|
63
|
+
const timestamp = Date.now().toString();
|
|
64
|
+
const signature = this.signRequest(timestamp, method, path);
|
|
65
|
+
return {
|
|
66
|
+
'KALSHI-ACCESS-KEY': this.credentials.apiKey,
|
|
67
|
+
'KALSHI-ACCESS-TIMESTAMP': timestamp,
|
|
68
|
+
'KALSHI-ACCESS-SIGNATURE': signature,
|
|
69
|
+
'Content-Type': 'application/json'
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Signs the request using RSA-PSS.
|
|
74
|
+
* The message to sign is: timestamp + method + path
|
|
75
|
+
*/
|
|
76
|
+
signRequest(timestamp, method, path) {
|
|
77
|
+
const payload = `${timestamp}${method}${path}`;
|
|
78
|
+
try {
|
|
79
|
+
const signer = crypto.createSign('SHA256');
|
|
80
|
+
signer.update(payload);
|
|
81
|
+
// Allow input of private key in both raw string or PEM format
|
|
82
|
+
// If it's a raw key without headers, accessing it might be tricky with implicit types,
|
|
83
|
+
// but standard PEM is best. We assume the user provides a valid PEM.
|
|
84
|
+
const privateKey = this.credentials.privateKey;
|
|
85
|
+
// Kalshi uses RSA-PSS for signing
|
|
86
|
+
const signature = signer.sign({
|
|
87
|
+
key: privateKey,
|
|
88
|
+
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
89
|
+
saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST
|
|
90
|
+
}, 'base64');
|
|
91
|
+
return signature;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error('Error signing Kalshi request:', error);
|
|
95
|
+
throw new Error(`Failed to sign Kalshi request: ${error.message}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.KalshiAuth = KalshiAuth;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fetchMarkets = fetchMarkets;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const utils_1 = require("./utils");
|
|
9
|
+
async function fetchActiveEvents(targetMarketCount) {
|
|
10
|
+
let allEvents = [];
|
|
11
|
+
let totalMarketCount = 0;
|
|
12
|
+
let cursor = null;
|
|
13
|
+
let page = 0;
|
|
14
|
+
// Note: Kalshi API uses cursor-based pagination which requires sequential fetching.
|
|
15
|
+
// We cannot parallelize requests for a single list because we need the cursor from page N to fetch page N+1.
|
|
16
|
+
// To optimize, we use the maximum allowed limit (200) and fetch until exhaustion.
|
|
17
|
+
const MAX_PAGES = 1000; // Safety cap against infinite loops
|
|
18
|
+
const BATCH_SIZE = 200; // Max limit per Kalshi API docs
|
|
19
|
+
do {
|
|
20
|
+
try {
|
|
21
|
+
// console.log(`Fetching Kalshi page ${page + 1}...`);
|
|
22
|
+
const queryParams = {
|
|
23
|
+
limit: BATCH_SIZE,
|
|
24
|
+
with_nested_markets: true,
|
|
25
|
+
status: 'open' // Filter to open markets to improve relevance and speed
|
|
26
|
+
};
|
|
27
|
+
if (cursor)
|
|
28
|
+
queryParams.cursor = cursor;
|
|
29
|
+
const response = await axios_1.default.get(utils_1.KALSHI_API_URL, { params: queryParams });
|
|
30
|
+
const events = response.data.events || [];
|
|
31
|
+
if (events.length === 0)
|
|
32
|
+
break;
|
|
33
|
+
allEvents = allEvents.concat(events);
|
|
34
|
+
// Count markets in this batch for early termination
|
|
35
|
+
if (targetMarketCount) {
|
|
36
|
+
for (const event of events) {
|
|
37
|
+
totalMarketCount += (event.markets || []).length;
|
|
38
|
+
}
|
|
39
|
+
// Early termination: if we have enough markets, stop fetching
|
|
40
|
+
if (totalMarketCount >= targetMarketCount * 2) {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
cursor = response.data.cursor;
|
|
45
|
+
page++;
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
console.error(`Error fetching Kalshi page ${page}:`, e);
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
} while (cursor && page < MAX_PAGES);
|
|
52
|
+
return allEvents;
|
|
53
|
+
}
|
|
54
|
+
async function fetchMarkets(params) {
|
|
55
|
+
const limit = params?.limit || 50;
|
|
56
|
+
try {
|
|
57
|
+
// Fetch active events with nested markets
|
|
58
|
+
// For small limits, we can optimize by fetching fewer pages
|
|
59
|
+
const allEvents = await fetchActiveEvents(limit);
|
|
60
|
+
// Extract ALL markets from all events
|
|
61
|
+
const allMarkets = [];
|
|
62
|
+
for (const event of allEvents) {
|
|
63
|
+
const markets = event.markets || [];
|
|
64
|
+
for (const market of markets) {
|
|
65
|
+
const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market);
|
|
66
|
+
if (unifiedMarket) {
|
|
67
|
+
allMarkets.push(unifiedMarket);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Sort by 24h volume
|
|
72
|
+
if (params?.sort === 'volume') {
|
|
73
|
+
allMarkets.sort((a, b) => b.volume24h - a.volume24h);
|
|
74
|
+
}
|
|
75
|
+
else if (params?.sort === 'liquidity') {
|
|
76
|
+
allMarkets.sort((a, b) => b.liquidity - a.liquidity);
|
|
77
|
+
}
|
|
78
|
+
return allMarkets.slice(0, limit);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error("Error fetching Kalshi data:", error);
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fetchOHLCV = fetchOHLCV;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const utils_1 = require("./utils");
|
|
9
|
+
async function fetchOHLCV(id, params) {
|
|
10
|
+
try {
|
|
11
|
+
// Kalshi API expects uppercase tickers
|
|
12
|
+
// Handle virtual "-NO" suffix by stripping it (fetching the underlying market history)
|
|
13
|
+
const cleanedId = id.replace(/-NO$/, '');
|
|
14
|
+
const normalizedId = cleanedId.toUpperCase();
|
|
15
|
+
const interval = (0, utils_1.mapIntervalToKalshi)(params.resolution);
|
|
16
|
+
// Heuristic for series_ticker
|
|
17
|
+
const parts = normalizedId.split('-');
|
|
18
|
+
if (parts.length < 2) {
|
|
19
|
+
throw new Error(`Invalid Kalshi Ticker format: "${id}". Expected format like "FED-25JAN29-B4.75".`);
|
|
20
|
+
}
|
|
21
|
+
const seriesTicker = parts.slice(0, -1).join('-');
|
|
22
|
+
const url = `https://api.elections.kalshi.com/trade-api/v2/series/${seriesTicker}/markets/${normalizedId}/candlesticks`;
|
|
23
|
+
const queryParams = { period_interval: interval };
|
|
24
|
+
const now = Math.floor(Date.now() / 1000);
|
|
25
|
+
let startTs = now - (24 * 60 * 60);
|
|
26
|
+
let endTs = now;
|
|
27
|
+
if (params.start) {
|
|
28
|
+
startTs = Math.floor(params.start.getTime() / 1000);
|
|
29
|
+
}
|
|
30
|
+
if (params.end) {
|
|
31
|
+
endTs = Math.floor(params.end.getTime() / 1000);
|
|
32
|
+
if (!params.start) {
|
|
33
|
+
startTs = endTs - (24 * 60 * 60);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
queryParams.start_ts = startTs;
|
|
37
|
+
queryParams.end_ts = endTs;
|
|
38
|
+
const response = await axios_1.default.get(url, { params: queryParams });
|
|
39
|
+
const candles = response.data.candlesticks || [];
|
|
40
|
+
const mappedCandles = candles.map((c) => {
|
|
41
|
+
// Priority:
|
|
42
|
+
// 1. Transaction price (close)
|
|
43
|
+
// 2. Mid price (average of yes_ask and yes_bid close)
|
|
44
|
+
// 3. Fallback to 0 if everything is missing
|
|
45
|
+
const p = c.price || {};
|
|
46
|
+
const ask = c.yes_ask || {};
|
|
47
|
+
const bid = c.yes_bid || {};
|
|
48
|
+
const getVal = (field) => {
|
|
49
|
+
if (p[field] !== null && p[field] !== undefined)
|
|
50
|
+
return p[field];
|
|
51
|
+
if (ask[field] !== null && bid[field] !== null && ask[field] !== undefined && bid[field] !== undefined) {
|
|
52
|
+
return (ask[field] + bid[field]) / 2;
|
|
53
|
+
}
|
|
54
|
+
return p.previous || 0;
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
timestamp: c.end_period_ts * 1000,
|
|
58
|
+
open: getVal('open') / 100,
|
|
59
|
+
high: getVal('high') / 100,
|
|
60
|
+
low: getVal('low') / 100,
|
|
61
|
+
close: getVal('close') / 100,
|
|
62
|
+
volume: c.volume || 0
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
if (params.limit && mappedCandles.length > params.limit) {
|
|
66
|
+
return mappedCandles.slice(-params.limit);
|
|
67
|
+
}
|
|
68
|
+
return mappedCandles;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (axios_1.default.isAxiosError(error) && error.response) {
|
|
72
|
+
const apiError = error.response.data?.error || error.response.data?.message || "Unknown API Error";
|
|
73
|
+
throw new Error(`Kalshi History API Error (${error.response.status}): ${apiError}. Used Ticker: ${id}`);
|
|
74
|
+
}
|
|
75
|
+
console.error(`Unexpected error fetching Kalshi history for ${id}:`, error);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fetchOrderBook = fetchOrderBook;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
async function fetchOrderBook(id) {
|
|
9
|
+
try {
|
|
10
|
+
const ticker = id.replace(/-NO$/, '');
|
|
11
|
+
const url = `https://api.elections.kalshi.com/trade-api/v2/markets/${ticker}/orderbook`;
|
|
12
|
+
const response = await axios_1.default.get(url);
|
|
13
|
+
const data = response.data.orderbook;
|
|
14
|
+
// Structure: { yes: [[price, qty], ...], no: [[price, qty], ...] }
|
|
15
|
+
const bids = (data.yes || []).map((level) => ({
|
|
16
|
+
price: level[0] / 100,
|
|
17
|
+
size: level[1]
|
|
18
|
+
}));
|
|
19
|
+
const asks = (data.no || []).map((level) => ({
|
|
20
|
+
price: (100 - level[0]) / 100,
|
|
21
|
+
size: level[1]
|
|
22
|
+
}));
|
|
23
|
+
// Sort bids desc, asks asc
|
|
24
|
+
bids.sort((a, b) => b.price - a.price);
|
|
25
|
+
asks.sort((a, b) => a.price - b.price);
|
|
26
|
+
return { bids, asks, timestamp: Date.now() };
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error(`Error fetching Kalshi orderbook for ${id}:`, error);
|
|
30
|
+
return { bids: [], asks: [] };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fetchTrades = fetchTrades;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
async function fetchTrades(id, params) {
|
|
9
|
+
try {
|
|
10
|
+
const ticker = id.replace(/-NO$/, '');
|
|
11
|
+
const url = `https://api.elections.kalshi.com/trade-api/v2/markets/trades`;
|
|
12
|
+
const response = await axios_1.default.get(url, {
|
|
13
|
+
params: {
|
|
14
|
+
ticker: ticker,
|
|
15
|
+
limit: params.limit || 100
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const trades = response.data.trades || [];
|
|
19
|
+
return trades.map((t) => ({
|
|
20
|
+
id: t.trade_id,
|
|
21
|
+
timestamp: new Date(t.created_time).getTime(),
|
|
22
|
+
price: t.yes_price / 100,
|
|
23
|
+
amount: t.count,
|
|
24
|
+
side: t.taker_side === 'yes' ? 'buy' : 'sell'
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error(`Error fetching Kalshi trades for ${id}:`, error);
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { UnifiedMarket } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Fetch specific markets by their event ticker.
|
|
4
|
+
* Useful for looking up a specific event from a URL.
|
|
5
|
+
* @param eventTicker - The event ticker (e.g. "FED-25JAN" or "PRES-2024")
|
|
6
|
+
*/
|
|
7
|
+
export declare function getMarketsBySlug(eventTicker: string): Promise<UnifiedMarket[]>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getMarketsBySlug = getMarketsBySlug;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const utils_1 = require("./utils");
|
|
9
|
+
/**
|
|
10
|
+
* Fetch specific markets by their event ticker.
|
|
11
|
+
* Useful for looking up a specific event from a URL.
|
|
12
|
+
* @param eventTicker - The event ticker (e.g. "FED-25JAN" or "PRES-2024")
|
|
13
|
+
*/
|
|
14
|
+
async function getMarketsBySlug(eventTicker) {
|
|
15
|
+
try {
|
|
16
|
+
// Kalshi API expects uppercase tickers, but URLs use lowercase
|
|
17
|
+
const normalizedTicker = eventTicker.toUpperCase();
|
|
18
|
+
const url = `https://api.elections.kalshi.com/trade-api/v2/events/${normalizedTicker}`;
|
|
19
|
+
const response = await axios_1.default.get(url, {
|
|
20
|
+
params: { with_nested_markets: true }
|
|
21
|
+
});
|
|
22
|
+
const event = response.data.event;
|
|
23
|
+
if (!event)
|
|
24
|
+
return [];
|
|
25
|
+
const unifiedMarkets = [];
|
|
26
|
+
const markets = event.markets || [];
|
|
27
|
+
for (const market of markets) {
|
|
28
|
+
const unifiedMarket = (0, utils_1.mapMarketToUnified)(event, market);
|
|
29
|
+
if (unifiedMarket) {
|
|
30
|
+
unifiedMarkets.push(unifiedMarket);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return unifiedMarkets;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (axios_1.default.isAxiosError(error) && error.response) {
|
|
37
|
+
if (error.response.status === 404) {
|
|
38
|
+
throw new Error(`Kalshi event not found: "${eventTicker}". Check that the event ticker is correct.`);
|
|
39
|
+
}
|
|
40
|
+
const apiError = error.response.data?.error || error.response.data?.message || "Unknown API Error";
|
|
41
|
+
throw new Error(`Kalshi API Error (${error.response.status}): ${apiError}. Event Ticker: ${eventTicker}`);
|
|
42
|
+
}
|
|
43
|
+
console.error(`Unexpected error fetching Kalshi event ${eventTicker}:`, error);
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { PredictionMarketExchange, MarketFilterParams, HistoryFilterParams, ExchangeCredentials } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, PriceCandle, OrderBook, Trade, Balance, Order, Position, CreateOrderParams } from '../../types';
|
|
3
|
+
export declare class KalshiExchange extends PredictionMarketExchange {
|
|
4
|
+
private auth?;
|
|
5
|
+
constructor(credentials?: ExchangeCredentials);
|
|
6
|
+
get name(): string;
|
|
7
|
+
private ensureAuth;
|
|
8
|
+
fetchMarkets(params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
9
|
+
searchMarkets(query: string, params?: MarketFilterParams): Promise<UnifiedMarket[]>;
|
|
10
|
+
getMarketsBySlug(slug: string): Promise<UnifiedMarket[]>;
|
|
11
|
+
fetchOHLCV(id: string, params: HistoryFilterParams): Promise<PriceCandle[]>;
|
|
12
|
+
fetchOrderBook(id: string): Promise<OrderBook>;
|
|
13
|
+
fetchTrades(id: string, params: HistoryFilterParams): Promise<Trade[]>;
|
|
14
|
+
fetchBalance(): Promise<Balance[]>;
|
|
15
|
+
createOrder(params: CreateOrderParams): Promise<Order>;
|
|
16
|
+
cancelOrder(orderId: string): Promise<Order>;
|
|
17
|
+
fetchOrder(orderId: string): Promise<Order>;
|
|
18
|
+
fetchOpenOrders(marketId?: string): Promise<Order[]>;
|
|
19
|
+
fetchPositions(): Promise<Position[]>;
|
|
20
|
+
private mapKalshiOrderStatus;
|
|
21
|
+
}
|