pmxt-core 2.20.0 → 2.20.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.
- package/dist/exchanges/baozi/fetcher.d.ts +40 -0
- package/dist/exchanges/baozi/fetcher.js +155 -0
- package/dist/exchanges/baozi/index.d.ts +2 -0
- package/dist/exchanges/baozi/index.js +60 -131
- package/dist/exchanges/baozi/normalizer.d.ts +14 -0
- package/dist/exchanges/baozi/normalizer.js +208 -0
- package/dist/exchanges/interfaces.d.ts +28 -0
- package/dist/exchanges/interfaces.js +2 -0
- package/dist/exchanges/kalshi/api.d.ts +1 -1
- package/dist/exchanges/kalshi/api.js +1 -1
- package/dist/exchanges/kalshi/fetcher.d.ts +126 -0
- package/dist/exchanges/kalshi/fetcher.js +313 -0
- package/dist/exchanges/kalshi/index.d.ts +6 -6
- package/dist/exchanges/kalshi/index.js +119 -202
- package/dist/exchanges/kalshi/normalizer.d.ts +25 -0
- package/dist/exchanges/kalshi/normalizer.js +294 -0
- package/dist/exchanges/limitless/api.d.ts +1 -1
- package/dist/exchanges/limitless/api.js +1 -1
- package/dist/exchanges/limitless/fetcher.d.ts +81 -0
- package/dist/exchanges/limitless/fetcher.js +238 -0
- package/dist/exchanges/limitless/index.d.ts +6 -9
- package/dist/exchanges/limitless/index.js +81 -79
- package/dist/exchanges/limitless/normalizer.d.ts +14 -0
- package/dist/exchanges/limitless/normalizer.js +117 -0
- package/dist/exchanges/limitless/websocket.d.ts +3 -0
- package/dist/exchanges/limitless/websocket.js +5 -4
- package/dist/exchanges/myriad/api.d.ts +1 -1
- package/dist/exchanges/myriad/api.js +1 -1
- package/dist/exchanges/myriad/fetcher.d.ts +73 -0
- package/dist/exchanges/myriad/fetcher.js +217 -0
- package/dist/exchanges/myriad/index.d.ts +2 -0
- package/dist/exchanges/myriad/index.js +40 -97
- package/dist/exchanges/myriad/normalizer.d.ts +14 -0
- package/dist/exchanges/myriad/normalizer.js +167 -0
- package/dist/exchanges/myriad/websocket.d.ts +3 -1
- package/dist/exchanges/myriad/websocket.js +4 -3
- 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/polymarket/fetcher.d.ts +99 -0
- package/dist/exchanges/polymarket/fetcher.js +335 -0
- package/dist/exchanges/polymarket/index.d.ts +2 -0
- package/dist/exchanges/polymarket/index.js +80 -66
- package/dist/exchanges/polymarket/normalizer.d.ts +18 -0
- package/dist/exchanges/polymarket/normalizer.js +126 -0
- package/dist/exchanges/probable/api.d.ts +1 -1
- package/dist/exchanges/probable/api.js +1 -1
- package/dist/exchanges/probable/fetcher.d.ts +106 -0
- package/dist/exchanges/probable/fetcher.js +357 -0
- package/dist/exchanges/probable/index.d.ts +3 -1
- package/dist/exchanges/probable/index.js +73 -105
- package/dist/exchanges/probable/normalizer.d.ts +14 -0
- package/dist/exchanges/probable/normalizer.js +109 -0
- package/dist/utils/error-mapper.d.ts +8 -0
- package/dist/utils/error-mapper.js +58 -26
- package/package.json +3 -3
- package/dist/exchanges/baozi/fetchEvents.d.ts +0 -8
- package/dist/exchanges/baozi/fetchEvents.js +0 -39
- package/dist/exchanges/baozi/fetchMarkets.d.ts +0 -5
- package/dist/exchanges/baozi/fetchMarkets.js +0 -160
- package/dist/exchanges/baozi/fetchOHLCV.d.ts +0 -6
- package/dist/exchanges/baozi/fetchOHLCV.js +0 -10
- package/dist/exchanges/baozi/fetchOrderBook.d.ts +0 -12
- package/dist/exchanges/baozi/fetchOrderBook.js +0 -36
- package/dist/exchanges/baozi/fetchTrades.d.ts +0 -6
- package/dist/exchanges/baozi/fetchTrades.js +0 -10
- package/dist/exchanges/kalshi/fetchEvents.d.ts +0 -5
- package/dist/exchanges/kalshi/fetchEvents.js +0 -196
- package/dist/exchanges/kalshi/fetchMarkets.d.ts +0 -6
- package/dist/exchanges/kalshi/fetchMarkets.js +0 -247
- package/dist/exchanges/kalshi/fetchOHLCV.d.ts +0 -3
- package/dist/exchanges/kalshi/fetchOHLCV.js +0 -97
- package/dist/exchanges/kalshi/fetchOrderBook.d.ts +0 -2
- package/dist/exchanges/kalshi/fetchOrderBook.js +0 -60
- package/dist/exchanges/kalshi/fetchTrades.d.ts +0 -3
- package/dist/exchanges/kalshi/fetchTrades.js +0 -33
- package/dist/exchanges/limitless/fetchEvents.d.ts +0 -4
- package/dist/exchanges/limitless/fetchEvents.js +0 -173
- package/dist/exchanges/limitless/fetchMarkets.d.ts +0 -3
- package/dist/exchanges/limitless/fetchMarkets.js +0 -152
- package/dist/exchanges/limitless/fetchOHLCV.d.ts +0 -7
- package/dist/exchanges/limitless/fetchOHLCV.js +0 -49
- package/dist/exchanges/limitless/fetchOrderBook.d.ts +0 -6
- package/dist/exchanges/limitless/fetchOrderBook.js +0 -41
- package/dist/exchanges/limitless/fetchTrades.d.ts +0 -8
- package/dist/exchanges/limitless/fetchTrades.js +0 -27
- package/dist/exchanges/myriad/fetchEvents.d.ts +0 -4
- package/dist/exchanges/myriad/fetchEvents.js +0 -48
- package/dist/exchanges/myriad/fetchMarkets.d.ts +0 -4
- package/dist/exchanges/myriad/fetchMarkets.js +0 -102
- package/dist/exchanges/myriad/fetchOHLCV.d.ts +0 -3
- package/dist/exchanges/myriad/fetchOHLCV.js +0 -83
- package/dist/exchanges/myriad/fetchOrderBook.d.ts +0 -2
- package/dist/exchanges/myriad/fetchOrderBook.js +0 -39
- package/dist/exchanges/polymarket/fetchEvents.d.ts +0 -4
- package/dist/exchanges/polymarket/fetchEvents.js +0 -135
- package/dist/exchanges/polymarket/fetchMarkets.d.ts +0 -4
- package/dist/exchanges/polymarket/fetchMarkets.js +0 -214
- package/dist/exchanges/polymarket/fetchOHLCV.d.ts +0 -7
- package/dist/exchanges/polymarket/fetchOHLCV.js +0 -98
- package/dist/exchanges/polymarket/fetchOrderBook.d.ts +0 -6
- package/dist/exchanges/polymarket/fetchOrderBook.js +0 -33
- package/dist/exchanges/polymarket/fetchTrades.d.ts +0 -9
- package/dist/exchanges/polymarket/fetchTrades.js +0 -43
- package/dist/exchanges/probable/fetchEvents.d.ts +0 -6
- package/dist/exchanges/probable/fetchEvents.js +0 -151
- package/dist/exchanges/probable/fetchMarkets.d.ts +0 -4
- package/dist/exchanges/probable/fetchMarkets.js +0 -239
- package/dist/exchanges/probable/fetchTrades.d.ts +0 -10
- package/dist/exchanges/probable/fetchTrades.js +0 -40
|
@@ -36,6 +36,8 @@ export declare class KalshiExchange extends PredictionMarketExchange {
|
|
|
36
36
|
private auth?;
|
|
37
37
|
private wsConfig?;
|
|
38
38
|
private config;
|
|
39
|
+
private readonly fetcher;
|
|
40
|
+
private readonly normalizer;
|
|
39
41
|
constructor(options?: ExchangeCredentials | KalshiExchangeOptions);
|
|
40
42
|
get name(): string;
|
|
41
43
|
protected sign(method: string, path: string, _params: Record<string, any>): Record<string, string>;
|
|
@@ -47,18 +49,16 @@ export declare class KalshiExchange extends PredictionMarketExchange {
|
|
|
47
49
|
fetchOrderBook(id: string): Promise<OrderBook>;
|
|
48
50
|
fetchTrades(id: string, params: TradesParams | HistoryFilterParams): Promise<Trade[]>;
|
|
49
51
|
fetchBalance(): Promise<Balance[]>;
|
|
52
|
+
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
53
|
+
fetchPositions(): Promise<Position[]>;
|
|
54
|
+
fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
55
|
+
fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
50
56
|
buildOrder(params: CreateOrderParams): Promise<BuiltOrder>;
|
|
51
57
|
submitOrder(built: BuiltOrder): Promise<Order>;
|
|
52
58
|
createOrder(params: CreateOrderParams): Promise<Order>;
|
|
53
59
|
cancelOrder(orderId: string): Promise<Order>;
|
|
54
60
|
fetchOrder(orderId: string): Promise<Order>;
|
|
55
61
|
fetchOpenOrders(marketId?: string): Promise<Order[]>;
|
|
56
|
-
fetchMyTrades(params?: MyTradesParams): Promise<UserTrade[]>;
|
|
57
|
-
fetchClosedOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
58
|
-
fetchAllOrders(params?: OrderHistoryParams): Promise<Order[]>;
|
|
59
|
-
fetchPositions(): Promise<Position[]>;
|
|
60
|
-
private mapKalshiOrder;
|
|
61
|
-
private mapKalshiOrderStatus;
|
|
62
62
|
private ws?;
|
|
63
63
|
watchOrderBook(id: string, limit?: number): Promise<OrderBook>;
|
|
64
64
|
watchTrades(id: string, address?: string, since?: number, limit?: number): Promise<Trade[]>;
|
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.KalshiExchange = void 0;
|
|
4
4
|
const BaseExchange_1 = require("../../BaseExchange");
|
|
5
|
-
const fetchMarkets_1 = require("./fetchMarkets");
|
|
6
|
-
const fetchEvents_1 = require("./fetchEvents");
|
|
7
|
-
const fetchOHLCV_1 = require("./fetchOHLCV");
|
|
8
5
|
const auth_1 = require("./auth");
|
|
9
6
|
const validation_1 = require("../../utils/validation");
|
|
10
7
|
const websocket_1 = require("./websocket");
|
|
@@ -13,7 +10,8 @@ const errors_2 = require("../../errors");
|
|
|
13
10
|
const openapi_1 = require("../../utils/openapi");
|
|
14
11
|
const api_1 = require("./api");
|
|
15
12
|
const config_1 = require("./config");
|
|
16
|
-
const
|
|
13
|
+
const fetcher_1 = require("./fetcher");
|
|
14
|
+
const normalizer_1 = require("./normalizer");
|
|
17
15
|
class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
18
16
|
has = {
|
|
19
17
|
fetchMarkets: true,
|
|
@@ -40,19 +38,18 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
40
38
|
auth;
|
|
41
39
|
wsConfig;
|
|
42
40
|
config;
|
|
41
|
+
fetcher;
|
|
42
|
+
normalizer;
|
|
43
43
|
constructor(options) {
|
|
44
|
-
// Support both old signature (credentials only) and new signature (options object)
|
|
45
44
|
let credentials;
|
|
46
45
|
let wsConfig;
|
|
47
46
|
let demoMode = false;
|
|
48
47
|
if (options && "credentials" in options) {
|
|
49
|
-
// New signature: KalshiExchangeOptions / KalshiInternalOptions
|
|
50
48
|
credentials = options.credentials;
|
|
51
49
|
wsConfig = options.websocket;
|
|
52
50
|
demoMode = options.demoMode || false;
|
|
53
51
|
}
|
|
54
52
|
else {
|
|
55
|
-
// Old signature: ExchangeCredentials directly
|
|
56
53
|
credentials = options;
|
|
57
54
|
}
|
|
58
55
|
super(credentials);
|
|
@@ -64,6 +61,13 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
64
61
|
}
|
|
65
62
|
const descriptor = (0, openapi_1.parseOpenApiSpec)(api_1.kalshiApiSpec, this.config.apiUrl + config_1.KALSHI_PATHS.TRADE_API);
|
|
66
63
|
this.defineImplicitApi(descriptor);
|
|
64
|
+
const ctx = {
|
|
65
|
+
http: this.http,
|
|
66
|
+
callApi: this.callApi.bind(this),
|
|
67
|
+
getHeaders: () => ({}),
|
|
68
|
+
};
|
|
69
|
+
this.fetcher = new fetcher_1.KalshiFetcher(ctx);
|
|
70
|
+
this.normalizer = new normalizer_1.KalshiNormalizer();
|
|
67
71
|
}
|
|
68
72
|
get name() {
|
|
69
73
|
return "Kalshi";
|
|
@@ -73,16 +77,11 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
73
77
|
// ----------------------------------------------------------------------------
|
|
74
78
|
sign(method, path, _params) {
|
|
75
79
|
const auth = this.ensureAuth();
|
|
76
|
-
// The implicit API passes just the spec path (e.g. /portfolio/balance),
|
|
77
|
-
// but Kalshi's signature requires the full path including /trade-api/v2.
|
|
78
80
|
return auth.getHeaders(method, "/trade-api/v2" + path);
|
|
79
81
|
}
|
|
80
82
|
mapImplicitApiError(error) {
|
|
81
83
|
throw errors_1.kalshiErrorMapper.mapError(error);
|
|
82
84
|
}
|
|
83
|
-
// ----------------------------------------------------------------------------
|
|
84
|
-
// Helpers
|
|
85
|
-
// ----------------------------------------------------------------------------
|
|
86
85
|
ensureAuth() {
|
|
87
86
|
if (!this.auth) {
|
|
88
87
|
throw new errors_2.AuthenticationError("Trading operations require authentication. " +
|
|
@@ -91,86 +90,128 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
91
90
|
return this.auth;
|
|
92
91
|
}
|
|
93
92
|
// ----------------------------------------------------------------------------
|
|
94
|
-
// Market Data
|
|
93
|
+
// Market Data (fetcher -> normalizer)
|
|
95
94
|
// ----------------------------------------------------------------------------
|
|
96
95
|
async fetchMarketsImpl(params) {
|
|
97
|
-
|
|
96
|
+
const rawEvents = await this.fetcher.fetchRawMarkets(params);
|
|
97
|
+
const allMarkets = [];
|
|
98
|
+
for (const event of rawEvents) {
|
|
99
|
+
const markets = this.normalizer.normalizeMarketsFromEvent(event);
|
|
100
|
+
allMarkets.push(...markets);
|
|
101
|
+
}
|
|
102
|
+
// Query-based search (client-side filtering)
|
|
103
|
+
if (params?.query) {
|
|
104
|
+
const lowerQuery = params.query.toLowerCase();
|
|
105
|
+
const searchIn = params?.searchIn || 'title';
|
|
106
|
+
const filtered = allMarkets.filter((market) => {
|
|
107
|
+
const titleMatch = (market.title || '').toLowerCase().includes(lowerQuery);
|
|
108
|
+
const descMatch = (market.description || '').toLowerCase().includes(lowerQuery);
|
|
109
|
+
if (searchIn === 'title')
|
|
110
|
+
return titleMatch;
|
|
111
|
+
if (searchIn === 'description')
|
|
112
|
+
return descMatch;
|
|
113
|
+
return titleMatch || descMatch;
|
|
114
|
+
});
|
|
115
|
+
return filtered.slice(0, params?.limit || 250000);
|
|
116
|
+
}
|
|
117
|
+
// Client-side sort
|
|
118
|
+
if (params?.sort === 'volume') {
|
|
119
|
+
allMarkets.sort((a, b) => b.volume24h - a.volume24h);
|
|
120
|
+
}
|
|
121
|
+
else if (params?.sort === 'liquidity') {
|
|
122
|
+
allMarkets.sort((a, b) => b.liquidity - a.liquidity);
|
|
123
|
+
}
|
|
124
|
+
const offset = params?.offset || 0;
|
|
125
|
+
const limit = params?.limit || 250000;
|
|
126
|
+
return allMarkets.slice(offset, offset + limit);
|
|
98
127
|
}
|
|
99
128
|
async fetchEventsImpl(params) {
|
|
100
|
-
|
|
129
|
+
const rawEvents = await this.fetcher.fetchRawEvents(params);
|
|
130
|
+
const limit = params?.limit || 10000;
|
|
131
|
+
const query = (params?.query || '').toLowerCase();
|
|
132
|
+
const filtered = query
|
|
133
|
+
? rawEvents.filter((event) => (event.title || '').toLowerCase().includes(query))
|
|
134
|
+
: rawEvents;
|
|
135
|
+
const sort = params?.sort || 'volume';
|
|
136
|
+
const sorted = (0, normalizer_1.sortRawEvents)(filtered, sort);
|
|
137
|
+
return sorted
|
|
138
|
+
.map((raw) => this.normalizer.normalizeEvent(raw))
|
|
139
|
+
.filter((e) => e !== null)
|
|
140
|
+
.slice(0, limit);
|
|
101
141
|
}
|
|
102
142
|
async fetchOHLCV(id, params) {
|
|
103
|
-
|
|
143
|
+
const rawCandles = await this.fetcher.fetchRawOHLCV(id, params);
|
|
144
|
+
return this.normalizer.normalizeOHLCV(rawCandles, params);
|
|
104
145
|
}
|
|
105
146
|
async fetchOrderBook(id) {
|
|
106
147
|
(0, validation_1.validateIdFormat)(id, "OrderBook");
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
const data = (await this.callApi("GetMarketOrderbook", { ticker }))
|
|
110
|
-
.orderbook_fp;
|
|
111
|
-
let bids;
|
|
112
|
-
let asks;
|
|
113
|
-
if (isNoOutcome) {
|
|
114
|
-
bids = (data.no_dollars || []).map((level) => ({
|
|
115
|
-
price: parseFloat(level[0]),
|
|
116
|
-
size: parseFloat(level[1]),
|
|
117
|
-
}));
|
|
118
|
-
asks = (data.yes_dollars || []).map((level) => ({
|
|
119
|
-
price: Math.round((1 - parseFloat(level[0])) * 10000) / 10000,
|
|
120
|
-
size: parseFloat(level[1]),
|
|
121
|
-
}));
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
bids = (data.yes_dollars || []).map((level) => ({
|
|
125
|
-
price: parseFloat(level[0]),
|
|
126
|
-
size: parseFloat(level[1]),
|
|
127
|
-
}));
|
|
128
|
-
asks = (data.no_dollars || []).map((level) => ({
|
|
129
|
-
price: Math.round((1 - parseFloat(level[0])) * 10000) / 10000,
|
|
130
|
-
size: parseFloat(level[1]),
|
|
131
|
-
}));
|
|
132
|
-
}
|
|
133
|
-
bids.sort((a, b) => b.price - a.price);
|
|
134
|
-
asks.sort((a, b) => a.price - b.price);
|
|
135
|
-
return { bids, asks, timestamp: Date.now() };
|
|
148
|
+
const raw = await this.fetcher.fetchRawOrderBook(id);
|
|
149
|
+
return this.normalizer.normalizeOrderBook(raw, id);
|
|
136
150
|
}
|
|
137
151
|
async fetchTrades(id, params) {
|
|
138
152
|
if ("resolution" in params && params.resolution !== undefined) {
|
|
139
153
|
console.warn('[pmxt] Warning: The "resolution" parameter is deprecated for fetchTrades() and will be ignored. ' +
|
|
140
154
|
"It will be removed in v3.0.0. Please remove it from your code.");
|
|
141
155
|
}
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
ticker,
|
|
145
|
-
limit: params.limit || 100,
|
|
146
|
-
});
|
|
147
|
-
const trades = data.trades || [];
|
|
148
|
-
return trades.map((t) => ({
|
|
149
|
-
id: t.trade_id,
|
|
150
|
-
timestamp: new Date(t.created_time).getTime(),
|
|
151
|
-
price: (0, price_1.fromKalshiCents)(t.yes_price),
|
|
152
|
-
amount: t.count,
|
|
153
|
-
side: t.taker_side === "yes" ? "buy" : "sell",
|
|
154
|
-
}));
|
|
156
|
+
const rawTrades = await this.fetcher.fetchRawTrades(id, params);
|
|
157
|
+
return rawTrades.map((raw, i) => this.normalizer.normalizeTrade(raw, i));
|
|
155
158
|
}
|
|
156
159
|
// ----------------------------------------------------------------------------
|
|
157
|
-
// User Data
|
|
160
|
+
// User Data (fetcher -> normalizer)
|
|
158
161
|
// ----------------------------------------------------------------------------
|
|
159
162
|
async fetchBalance() {
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
163
|
+
const raw = await this.fetcher.fetchRawBalance();
|
|
164
|
+
return this.normalizer.normalizeBalance(raw);
|
|
165
|
+
}
|
|
166
|
+
async fetchMyTrades(params) {
|
|
167
|
+
const rawFills = await this.fetcher.fetchRawMyTrades(params || {});
|
|
168
|
+
return rawFills.map((raw, i) => this.normalizer.normalizeUserTrade(raw, i));
|
|
169
|
+
}
|
|
170
|
+
async fetchPositions() {
|
|
171
|
+
const rawPositions = await this.fetcher.fetchRawPositions();
|
|
172
|
+
return rawPositions.map((raw) => this.normalizer.normalizePosition(raw));
|
|
173
|
+
}
|
|
174
|
+
async fetchClosedOrders(params) {
|
|
175
|
+
const queryParams = {};
|
|
176
|
+
if (params?.marketId)
|
|
177
|
+
queryParams.ticker = params.marketId;
|
|
178
|
+
if (params?.until)
|
|
179
|
+
queryParams.max_ts = Math.floor(params.until.getTime() / 1000);
|
|
180
|
+
if (params?.limit)
|
|
181
|
+
queryParams.limit = params.limit;
|
|
182
|
+
if (params?.cursor)
|
|
183
|
+
queryParams.cursor = params.cursor;
|
|
184
|
+
const rawOrders = await this.fetcher.fetchRawHistoricalOrders(queryParams);
|
|
185
|
+
return rawOrders.map((o) => this.normalizer.normalizeOrder(o));
|
|
186
|
+
}
|
|
187
|
+
async fetchAllOrders(params) {
|
|
188
|
+
const queryParams = {};
|
|
189
|
+
if (params?.marketId)
|
|
190
|
+
queryParams.ticker = params.marketId;
|
|
191
|
+
if (params?.since)
|
|
192
|
+
queryParams.min_ts = Math.floor(params.since.getTime() / 1000);
|
|
193
|
+
if (params?.until)
|
|
194
|
+
queryParams.max_ts = Math.floor(params.until.getTime() / 1000);
|
|
195
|
+
if (params?.limit)
|
|
196
|
+
queryParams.limit = params.limit;
|
|
197
|
+
const historicalParams = { ...queryParams };
|
|
198
|
+
delete historicalParams.min_ts;
|
|
199
|
+
const [liveOrders, historicalOrders] = await Promise.all([
|
|
200
|
+
this.fetcher.fetchRawOrders(queryParams),
|
|
201
|
+
this.fetcher.fetchRawHistoricalOrders(historicalParams),
|
|
202
|
+
]);
|
|
203
|
+
const seen = new Set();
|
|
204
|
+
const all = [];
|
|
205
|
+
for (const o of [...liveOrders, ...historicalOrders]) {
|
|
206
|
+
if (!seen.has(o.order_id)) {
|
|
207
|
+
seen.add(o.order_id);
|
|
208
|
+
all.push(this.normalizer.normalizeOrder(o));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return all.sort((a, b) => b.timestamp - a.timestamp);
|
|
171
212
|
}
|
|
172
213
|
// ----------------------------------------------------------------------------
|
|
173
|
-
// Trading
|
|
214
|
+
// Trading
|
|
174
215
|
// ----------------------------------------------------------------------------
|
|
175
216
|
async buildOrder(params) {
|
|
176
217
|
const isYesSide = params.side === "buy";
|
|
@@ -191,15 +232,11 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
191
232
|
body.no_price = priceInCents;
|
|
192
233
|
}
|
|
193
234
|
}
|
|
194
|
-
return {
|
|
195
|
-
exchange: this.name,
|
|
196
|
-
params,
|
|
197
|
-
raw: body,
|
|
198
|
-
};
|
|
235
|
+
return { exchange: this.name, params, raw: body };
|
|
199
236
|
}
|
|
200
237
|
async submitOrder(built) {
|
|
201
238
|
const data = await this.callApi("CreateOrder", built.raw);
|
|
202
|
-
return this.
|
|
239
|
+
return this.normalizer.normalizeOrder(data.order);
|
|
203
240
|
}
|
|
204
241
|
async createOrder(params) {
|
|
205
242
|
const built = await this.buildOrder(params);
|
|
@@ -223,160 +260,40 @@ class KalshiExchange extends BaseExchange_1.PredictionMarketExchange {
|
|
|
223
260
|
}
|
|
224
261
|
async fetchOrder(orderId) {
|
|
225
262
|
const data = await this.callApi("GetOrder", { order_id: orderId });
|
|
226
|
-
return this.
|
|
263
|
+
return this.normalizer.normalizeOrder(data.order);
|
|
227
264
|
}
|
|
228
265
|
async fetchOpenOrders(marketId) {
|
|
229
266
|
const queryParams = { status: "resting" };
|
|
230
|
-
if (marketId)
|
|
267
|
+
if (marketId)
|
|
231
268
|
queryParams.ticker = marketId;
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
const orders = data.orders || [];
|
|
235
|
-
return orders.map((order) => this.mapKalshiOrder(order));
|
|
236
|
-
}
|
|
237
|
-
async fetchMyTrades(params) {
|
|
238
|
-
const queryParams = {};
|
|
239
|
-
if (params?.outcomeId || params?.marketId) {
|
|
240
|
-
queryParams.ticker = (params.outcomeId || params.marketId).replace(/-NO$/, "");
|
|
241
|
-
}
|
|
242
|
-
if (params?.since)
|
|
243
|
-
queryParams.min_ts = Math.floor(params.since.getTime() / 1000);
|
|
244
|
-
if (params?.until)
|
|
245
|
-
queryParams.max_ts = Math.floor(params.until.getTime() / 1000);
|
|
246
|
-
if (params?.limit)
|
|
247
|
-
queryParams.limit = params.limit;
|
|
248
|
-
if (params?.cursor)
|
|
249
|
-
queryParams.cursor = params.cursor;
|
|
250
|
-
const data = await this.callApi("GetFills", queryParams);
|
|
251
|
-
return (data.fills || []).map((f) => ({
|
|
252
|
-
id: f.fill_id,
|
|
253
|
-
timestamp: new Date(f.created_time).getTime(),
|
|
254
|
-
price: (0, price_1.fromKalshiCents)(f.yes_price),
|
|
255
|
-
amount: f.count,
|
|
256
|
-
side: f.side === "yes" ? "buy" : "sell",
|
|
257
|
-
orderId: f.order_id,
|
|
258
|
-
}));
|
|
259
|
-
}
|
|
260
|
-
async fetchClosedOrders(params) {
|
|
261
|
-
const queryParams = {};
|
|
262
|
-
if (params?.marketId)
|
|
263
|
-
queryParams.ticker = params.marketId;
|
|
264
|
-
if (params?.until)
|
|
265
|
-
queryParams.max_ts = Math.floor(params.until.getTime() / 1000);
|
|
266
|
-
if (params?.limit)
|
|
267
|
-
queryParams.limit = params.limit;
|
|
268
|
-
if (params?.cursor)
|
|
269
|
-
queryParams.cursor = params.cursor;
|
|
270
|
-
const data = await this.callApi("GetHistoricalOrders", queryParams);
|
|
271
|
-
return (data.orders || []).map((o) => this.mapKalshiOrder(o));
|
|
272
|
-
}
|
|
273
|
-
async fetchAllOrders(params) {
|
|
274
|
-
const queryParams = {};
|
|
275
|
-
if (params?.marketId)
|
|
276
|
-
queryParams.ticker = params.marketId;
|
|
277
|
-
if (params?.since)
|
|
278
|
-
queryParams.min_ts = Math.floor(params.since.getTime() / 1000);
|
|
279
|
-
if (params?.until)
|
|
280
|
-
queryParams.max_ts = Math.floor(params.until.getTime() / 1000);
|
|
281
|
-
if (params?.limit)
|
|
282
|
-
queryParams.limit = params.limit;
|
|
283
|
-
const historicalParams = { ...queryParams };
|
|
284
|
-
delete historicalParams.min_ts; // GetHistoricalOrders only supports max_ts
|
|
285
|
-
const [liveData, historicalData] = await Promise.all([
|
|
286
|
-
this.callApi("GetOrders", queryParams),
|
|
287
|
-
this.callApi("GetHistoricalOrders", historicalParams),
|
|
288
|
-
]);
|
|
289
|
-
const seen = new Set();
|
|
290
|
-
const all = [];
|
|
291
|
-
for (const o of [
|
|
292
|
-
...(liveData.orders || []),
|
|
293
|
-
...(historicalData.orders || []),
|
|
294
|
-
]) {
|
|
295
|
-
if (!seen.has(o.order_id)) {
|
|
296
|
-
seen.add(o.order_id);
|
|
297
|
-
all.push(this.mapKalshiOrder(o));
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
return all.sort((a, b) => b.timestamp - a.timestamp);
|
|
301
|
-
}
|
|
302
|
-
async fetchPositions() {
|
|
303
|
-
const data = await this.callApi("GetPositions");
|
|
304
|
-
const positions = data.market_positions || [];
|
|
305
|
-
return positions.map((pos) => {
|
|
306
|
-
const absPosition = Math.abs(pos.position);
|
|
307
|
-
const entryPrice = absPosition > 0 ? pos.total_cost / absPosition / 100 : 0;
|
|
308
|
-
return {
|
|
309
|
-
marketId: pos.ticker,
|
|
310
|
-
outcomeId: pos.ticker,
|
|
311
|
-
outcomeLabel: pos.ticker,
|
|
312
|
-
size: pos.position,
|
|
313
|
-
entryPrice,
|
|
314
|
-
currentPrice: pos.market_price ? pos.market_price / 100 : entryPrice,
|
|
315
|
-
unrealizedPnL: pos.market_exposure ? pos.market_exposure / 100 : 0,
|
|
316
|
-
realizedPnL: pos.realized_pnl ? pos.realized_pnl / 100 : 0,
|
|
317
|
-
};
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
// Helper to map a raw Kalshi order object to a unified Order
|
|
321
|
-
mapKalshiOrder(order) {
|
|
322
|
-
return {
|
|
323
|
-
id: order.order_id,
|
|
324
|
-
marketId: order.ticker,
|
|
325
|
-
outcomeId: order.ticker,
|
|
326
|
-
side: order.side === "yes" ? "buy" : "sell",
|
|
327
|
-
type: order.type === "limit" ? "limit" : "market",
|
|
328
|
-
price: order.yes_price ? order.yes_price / 100 : undefined,
|
|
329
|
-
amount: order.count,
|
|
330
|
-
status: this.mapKalshiOrderStatus(order.status),
|
|
331
|
-
filled: order.count - (order.remaining_count || 0),
|
|
332
|
-
remaining: order.remaining_count || 0,
|
|
333
|
-
timestamp: new Date(order.created_time).getTime(),
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
// Helper to map Kalshi order status to unified status
|
|
337
|
-
mapKalshiOrderStatus(status) {
|
|
338
|
-
switch ((status ?? "").toLowerCase()) {
|
|
339
|
-
case "resting":
|
|
340
|
-
return "open";
|
|
341
|
-
case "canceled":
|
|
342
|
-
case "cancelled":
|
|
343
|
-
return "cancelled";
|
|
344
|
-
case "executed":
|
|
345
|
-
case "filled":
|
|
346
|
-
return "filled";
|
|
347
|
-
default:
|
|
348
|
-
return "open";
|
|
349
|
-
}
|
|
269
|
+
const rawOrders = await this.fetcher.fetchRawOrders(queryParams);
|
|
270
|
+
return rawOrders.map((o) => this.normalizer.normalizeOrder(o));
|
|
350
271
|
}
|
|
351
272
|
// ----------------------------------------------------------------------------
|
|
352
|
-
// WebSocket
|
|
273
|
+
// WebSocket
|
|
353
274
|
// ----------------------------------------------------------------------------
|
|
354
275
|
ws;
|
|
355
276
|
async watchOrderBook(id, limit) {
|
|
356
277
|
const auth = this.ensureAuth();
|
|
357
278
|
if (!this.ws) {
|
|
358
|
-
// Merge wsConfig with wsUrl from config
|
|
359
279
|
const wsConfigWithUrl = {
|
|
360
280
|
...this.wsConfig,
|
|
361
281
|
wsUrl: this.wsConfig?.wsUrl || this.config.wsUrl,
|
|
362
282
|
};
|
|
363
283
|
this.ws = new websocket_1.KalshiWebSocket(auth, wsConfigWithUrl);
|
|
364
284
|
}
|
|
365
|
-
// Normalize ticker (strip -NO suffix if present)
|
|
366
285
|
const marketTicker = id.replace(/-NO$/, "");
|
|
367
286
|
return this.ws.watchOrderBook(marketTicker);
|
|
368
287
|
}
|
|
369
288
|
async watchTrades(id, address, since, limit) {
|
|
370
289
|
const auth = this.ensureAuth();
|
|
371
290
|
if (!this.ws) {
|
|
372
|
-
// Merge wsConfig with wsUrl from config
|
|
373
291
|
const wsConfigWithUrl = {
|
|
374
292
|
...this.wsConfig,
|
|
375
293
|
wsUrl: this.wsConfig?.wsUrl || this.config.wsUrl,
|
|
376
294
|
};
|
|
377
295
|
this.ws = new websocket_1.KalshiWebSocket(auth, wsConfigWithUrl);
|
|
378
296
|
}
|
|
379
|
-
// Normalize ticker (strip -NO suffix if present)
|
|
380
297
|
const marketTicker = id.replace(/-NO$/, "");
|
|
381
298
|
return this.ws.watchTrades(marketTicker);
|
|
382
299
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { OHLCVParams } from '../../BaseExchange';
|
|
2
|
+
import { UnifiedMarket, UnifiedEvent, PriceCandle, OrderBook, Trade, UserTrade, Position, Balance } from '../../types';
|
|
3
|
+
import { IExchangeNormalizer } from '../interfaces';
|
|
4
|
+
import { KalshiRawEvent, KalshiRawMarket, KalshiRawCandlestick, KalshiRawTrade, KalshiRawFill, KalshiRawOrder, KalshiRawPosition, KalshiRawOrderBookFp } from './fetcher';
|
|
5
|
+
export declare class KalshiNormalizer implements IExchangeNormalizer<KalshiRawEvent, KalshiRawEvent> {
|
|
6
|
+
normalizeMarket(raw: KalshiRawEvent): UnifiedMarket | null;
|
|
7
|
+
normalizeMarketsFromEvent(rawEvent: KalshiRawEvent): UnifiedMarket[];
|
|
8
|
+
normalizeRawMarket(event: KalshiRawEvent, market: KalshiRawMarket): UnifiedMarket | null;
|
|
9
|
+
normalizeEvent(raw: KalshiRawEvent): UnifiedEvent | null;
|
|
10
|
+
normalizeOHLCV(rawCandles: KalshiRawCandlestick[], params: OHLCVParams): PriceCandle[];
|
|
11
|
+
normalizeOrderBook(raw: {
|
|
12
|
+
orderbook_fp: KalshiRawOrderBookFp;
|
|
13
|
+
}, id: string): OrderBook;
|
|
14
|
+
normalizeTrade(raw: KalshiRawTrade, _index: number): Trade;
|
|
15
|
+
normalizeUserTrade(raw: KalshiRawFill, _index: number): UserTrade;
|
|
16
|
+
normalizeOrder(raw: KalshiRawOrder): import('../../types').Order;
|
|
17
|
+
normalizePosition(raw: KalshiRawPosition): Position;
|
|
18
|
+
normalizeBalance(raw: {
|
|
19
|
+
balance: number;
|
|
20
|
+
portfolio_value: number;
|
|
21
|
+
}): Balance[];
|
|
22
|
+
private mapOrderStatus;
|
|
23
|
+
private deriveEventDescription;
|
|
24
|
+
}
|
|
25
|
+
export declare function sortRawEvents(events: any[], sort: string): any[];
|