@newyorkcompute/kalshi-core 0.2.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/dist/config.d.ts +61 -6
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +56 -5
- package/dist/config.js.map +1 -1
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +94 -0
- package/dist/config.test.js.map +1 -0
- package/dist/format.d.ts +71 -2
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +71 -2
- package/dist/format.js.map +1 -1
- package/dist/format.test.js +42 -1
- package/dist/format.test.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/mm/index.d.ts +10 -0
- package/dist/mm/index.d.ts.map +1 -0
- package/dist/mm/index.js +12 -0
- package/dist/mm/index.js.map +1 -0
- package/dist/mm/inventory.d.ts +70 -0
- package/dist/mm/inventory.d.ts.map +1 -0
- package/dist/mm/inventory.js +171 -0
- package/dist/mm/inventory.js.map +1 -0
- package/dist/mm/inventory.test.d.ts +2 -0
- package/dist/mm/inventory.test.d.ts.map +1 -0
- package/dist/mm/inventory.test.js +358 -0
- package/dist/mm/inventory.test.js.map +1 -0
- package/dist/mm/order-manager.d.ts +81 -0
- package/dist/mm/order-manager.d.ts.map +1 -0
- package/dist/mm/order-manager.js +216 -0
- package/dist/mm/order-manager.js.map +1 -0
- package/dist/mm/order-manager.test.d.ts +2 -0
- package/dist/mm/order-manager.test.d.ts.map +1 -0
- package/dist/mm/order-manager.test.js +333 -0
- package/dist/mm/order-manager.test.js.map +1 -0
- package/dist/mm/risk.d.ts +77 -0
- package/dist/mm/risk.d.ts.map +1 -0
- package/dist/mm/risk.js +179 -0
- package/dist/mm/risk.js.map +1 -0
- package/dist/mm/risk.test.d.ts +2 -0
- package/dist/mm/risk.test.d.ts.map +1 -0
- package/dist/mm/risk.test.js +297 -0
- package/dist/mm/risk.test.js.map +1 -0
- package/dist/mm/types.d.ts +128 -0
- package/dist/mm/types.d.ts.map +1 -0
- package/dist/mm/types.js +7 -0
- package/dist/mm/types.js.map +1 -0
- package/dist/websocket/auth.d.ts +35 -0
- package/dist/websocket/auth.d.ts.map +1 -0
- package/dist/websocket/auth.js +60 -0
- package/dist/websocket/auth.js.map +1 -0
- package/dist/websocket/auth.test.d.ts +2 -0
- package/dist/websocket/auth.test.d.ts.map +1 -0
- package/dist/websocket/auth.test.js +65 -0
- package/dist/websocket/auth.test.js.map +1 -0
- package/dist/websocket/client.d.ts +95 -0
- package/dist/websocket/client.d.ts.map +1 -0
- package/dist/websocket/client.js +358 -0
- package/dist/websocket/client.js.map +1 -0
- package/dist/websocket/index.d.ts +9 -0
- package/dist/websocket/index.d.ts.map +1 -0
- package/dist/websocket/index.js +9 -0
- package/dist/websocket/index.js.map +1 -0
- package/dist/websocket/types.d.ts +172 -0
- package/dist/websocket/types.d.ts.map +1 -0
- package/dist/websocket/types.js +12 -0
- package/dist/websocket/types.js.map +1 -0
- package/dist/websocket/types.test.d.ts +2 -0
- package/dist/websocket/types.test.d.ts.map +1 -0
- package/dist/websocket/types.test.js +17 -0
- package/dist/websocket/types.test.js.map +1 -0
- package/package.json +8 -4
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
+
import { RiskManager, DEFAULT_RISK_LIMITS } from "./risk.js";
|
|
3
|
+
import { InventoryTracker } from "./inventory.js";
|
|
4
|
+
describe("RiskManager", () => {
|
|
5
|
+
let risk;
|
|
6
|
+
let inventory;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
risk = new RiskManager();
|
|
9
|
+
inventory = new InventoryTracker();
|
|
10
|
+
});
|
|
11
|
+
describe("constructor", () => {
|
|
12
|
+
it("should use default limits", () => {
|
|
13
|
+
const limits = risk.getLimits();
|
|
14
|
+
expect(limits).toEqual(DEFAULT_RISK_LIMITS);
|
|
15
|
+
});
|
|
16
|
+
it("should allow custom limits", () => {
|
|
17
|
+
const customLimits = {
|
|
18
|
+
maxPositionPerMarket: 50,
|
|
19
|
+
maxDailyLoss: 1000,
|
|
20
|
+
};
|
|
21
|
+
const customRisk = new RiskManager(customLimits);
|
|
22
|
+
const limits = customRisk.getLimits();
|
|
23
|
+
expect(limits.maxPositionPerMarket).toBe(50);
|
|
24
|
+
expect(limits.maxDailyLoss).toBe(1000);
|
|
25
|
+
expect(limits.maxTotalExposure).toBe(DEFAULT_RISK_LIMITS.maxTotalExposure);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe("checkQuote", () => {
|
|
29
|
+
it("should allow valid quote", () => {
|
|
30
|
+
const quote = {
|
|
31
|
+
ticker: "TEST-MARKET",
|
|
32
|
+
side: "yes",
|
|
33
|
+
bidPrice: 45,
|
|
34
|
+
bidSize: 10,
|
|
35
|
+
askPrice: 55,
|
|
36
|
+
askSize: 10,
|
|
37
|
+
};
|
|
38
|
+
const result = risk.checkQuote(quote, inventory);
|
|
39
|
+
expect(result.allowed).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
it("should reject quote when halted", () => {
|
|
42
|
+
risk.halt("Test halt");
|
|
43
|
+
const quote = {
|
|
44
|
+
ticker: "TEST-MARKET",
|
|
45
|
+
side: "yes",
|
|
46
|
+
bidPrice: 45,
|
|
47
|
+
bidSize: 10,
|
|
48
|
+
askPrice: 55,
|
|
49
|
+
askSize: 10,
|
|
50
|
+
};
|
|
51
|
+
const result = risk.checkQuote(quote, inventory);
|
|
52
|
+
expect(result.allowed).toBe(false);
|
|
53
|
+
expect(result.reason).toContain("halted");
|
|
54
|
+
});
|
|
55
|
+
it("should reject quote with spread below minimum", () => {
|
|
56
|
+
const quote = {
|
|
57
|
+
ticker: "TEST-MARKET",
|
|
58
|
+
side: "yes",
|
|
59
|
+
bidPrice: 49,
|
|
60
|
+
bidSize: 10,
|
|
61
|
+
askPrice: 50, // Spread = 1, below default min of 2
|
|
62
|
+
askSize: 10,
|
|
63
|
+
};
|
|
64
|
+
const result = risk.checkQuote(quote, inventory);
|
|
65
|
+
expect(result.allowed).toBe(false);
|
|
66
|
+
expect(result.reason).toContain("Spread");
|
|
67
|
+
});
|
|
68
|
+
it("should reject quote with bid size exceeding max", () => {
|
|
69
|
+
const quote = {
|
|
70
|
+
ticker: "TEST-MARKET",
|
|
71
|
+
side: "yes",
|
|
72
|
+
bidPrice: 45,
|
|
73
|
+
bidSize: 100, // Exceeds default max of 25
|
|
74
|
+
askPrice: 55,
|
|
75
|
+
askSize: 10,
|
|
76
|
+
};
|
|
77
|
+
const result = risk.checkQuote(quote, inventory);
|
|
78
|
+
expect(result.allowed).toBe(false);
|
|
79
|
+
expect(result.reason).toContain("Bid size");
|
|
80
|
+
});
|
|
81
|
+
it("should reject quote with ask size exceeding max", () => {
|
|
82
|
+
const quote = {
|
|
83
|
+
ticker: "TEST-MARKET",
|
|
84
|
+
side: "yes",
|
|
85
|
+
bidPrice: 45,
|
|
86
|
+
bidSize: 10,
|
|
87
|
+
askPrice: 55,
|
|
88
|
+
askSize: 100, // Exceeds default max of 25
|
|
89
|
+
};
|
|
90
|
+
const result = risk.checkQuote(quote, inventory);
|
|
91
|
+
expect(result.allowed).toBe(false);
|
|
92
|
+
expect(result.reason).toContain("Ask size");
|
|
93
|
+
});
|
|
94
|
+
it("should reject quote that would exceed position limit", () => {
|
|
95
|
+
// Add existing position near limit
|
|
96
|
+
inventory.onFill({
|
|
97
|
+
orderId: "order1",
|
|
98
|
+
ticker: "TEST-MARKET",
|
|
99
|
+
side: "yes",
|
|
100
|
+
action: "buy",
|
|
101
|
+
count: 90, // Near default limit of 100
|
|
102
|
+
price: 50,
|
|
103
|
+
timestamp: new Date(),
|
|
104
|
+
});
|
|
105
|
+
const quote = {
|
|
106
|
+
ticker: "TEST-MARKET",
|
|
107
|
+
side: "yes",
|
|
108
|
+
bidPrice: 45,
|
|
109
|
+
bidSize: 20, // Would bring to 110, exceeding 100
|
|
110
|
+
askPrice: 55,
|
|
111
|
+
askSize: 20,
|
|
112
|
+
};
|
|
113
|
+
const result = risk.checkQuote(quote, inventory);
|
|
114
|
+
expect(result.allowed).toBe(false);
|
|
115
|
+
expect(result.reason).toContain("Position");
|
|
116
|
+
});
|
|
117
|
+
it("should reject quote that would exceed total exposure", () => {
|
|
118
|
+
const customRisk = new RiskManager({ maxTotalExposure: 50 });
|
|
119
|
+
// Add existing exposure
|
|
120
|
+
inventory.onFill({
|
|
121
|
+
orderId: "order1",
|
|
122
|
+
ticker: "MARKET-A",
|
|
123
|
+
side: "yes",
|
|
124
|
+
action: "buy",
|
|
125
|
+
count: 40,
|
|
126
|
+
price: 50,
|
|
127
|
+
timestamp: new Date(),
|
|
128
|
+
});
|
|
129
|
+
const quote = {
|
|
130
|
+
ticker: "MARKET-B",
|
|
131
|
+
side: "yes",
|
|
132
|
+
bidPrice: 45,
|
|
133
|
+
bidSize: 20, // Would bring total to 60, exceeding 50
|
|
134
|
+
askPrice: 55,
|
|
135
|
+
askSize: 20,
|
|
136
|
+
};
|
|
137
|
+
const result = customRisk.checkQuote(quote, inventory);
|
|
138
|
+
expect(result.allowed).toBe(false);
|
|
139
|
+
expect(result.reason).toContain("Total exposure");
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
describe("checkOrder", () => {
|
|
143
|
+
it("should allow valid order", () => {
|
|
144
|
+
const result = risk.checkOrder({ ticker: "TEST-MARKET", count: 10 }, inventory);
|
|
145
|
+
expect(result.allowed).toBe(true);
|
|
146
|
+
});
|
|
147
|
+
it("should reject order when halted", () => {
|
|
148
|
+
risk.halt("Test halt");
|
|
149
|
+
const result = risk.checkOrder({ ticker: "TEST-MARKET", count: 10 }, inventory);
|
|
150
|
+
expect(result.allowed).toBe(false);
|
|
151
|
+
});
|
|
152
|
+
it("should reject order exceeding max size", () => {
|
|
153
|
+
const result = risk.checkOrder({ ticker: "TEST-MARKET", count: 100 }, inventory);
|
|
154
|
+
expect(result.allowed).toBe(false);
|
|
155
|
+
expect(result.reason).toContain("Order size");
|
|
156
|
+
});
|
|
157
|
+
it("should reject order that would exceed position limit", () => {
|
|
158
|
+
// Add existing position near limit
|
|
159
|
+
inventory.onFill({
|
|
160
|
+
orderId: "order1",
|
|
161
|
+
ticker: "TEST-MARKET",
|
|
162
|
+
side: "yes",
|
|
163
|
+
action: "buy",
|
|
164
|
+
count: 95, // Near default limit of 100
|
|
165
|
+
price: 50,
|
|
166
|
+
timestamp: new Date(),
|
|
167
|
+
});
|
|
168
|
+
// Try to add 10 more - would exceed 100
|
|
169
|
+
const result = risk.checkOrder({ ticker: "TEST-MARKET", count: 10 }, inventory);
|
|
170
|
+
expect(result.allowed).toBe(false);
|
|
171
|
+
expect(result.reason).toContain("position limit");
|
|
172
|
+
});
|
|
173
|
+
it("should reject order that would exceed total exposure limit", () => {
|
|
174
|
+
const customRisk = new RiskManager({ maxTotalExposure: 50 });
|
|
175
|
+
// Add existing exposure
|
|
176
|
+
inventory.onFill({
|
|
177
|
+
orderId: "order1",
|
|
178
|
+
ticker: "MARKET-A",
|
|
179
|
+
side: "yes",
|
|
180
|
+
action: "buy",
|
|
181
|
+
count: 45,
|
|
182
|
+
price: 50,
|
|
183
|
+
timestamp: new Date(),
|
|
184
|
+
});
|
|
185
|
+
// Try to add 10 more in different market - would exceed 50
|
|
186
|
+
const result = customRisk.checkOrder({ ticker: "MARKET-B", count: 10 }, inventory);
|
|
187
|
+
expect(result.allowed).toBe(false);
|
|
188
|
+
expect(result.reason).toContain("total exposure");
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
describe("halt/resume", () => {
|
|
192
|
+
it("should halt trading", () => {
|
|
193
|
+
expect(risk.shouldHalt()).toBe(false);
|
|
194
|
+
risk.halt("Emergency stop");
|
|
195
|
+
expect(risk.shouldHalt()).toBe(true);
|
|
196
|
+
expect(risk.getHaltReason()).toBe("Emergency stop");
|
|
197
|
+
});
|
|
198
|
+
it("should resume trading", () => {
|
|
199
|
+
risk.halt("Emergency stop");
|
|
200
|
+
risk.resume();
|
|
201
|
+
expect(risk.shouldHalt()).toBe(false);
|
|
202
|
+
expect(risk.getHaltReason()).toBeUndefined();
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
describe("onFill", () => {
|
|
206
|
+
it("should track daily PnL", () => {
|
|
207
|
+
const fill = {
|
|
208
|
+
orderId: "order1",
|
|
209
|
+
ticker: "TEST-MARKET",
|
|
210
|
+
side: "yes",
|
|
211
|
+
action: "sell",
|
|
212
|
+
count: 10,
|
|
213
|
+
price: 55,
|
|
214
|
+
timestamp: new Date(),
|
|
215
|
+
};
|
|
216
|
+
risk.onFill(fill, 50); // 50 cents profit
|
|
217
|
+
expect(risk.getDailyPnL()).toBe(50);
|
|
218
|
+
});
|
|
219
|
+
it("should halt when daily loss limit reached", () => {
|
|
220
|
+
const customRisk = new RiskManager({ maxDailyLoss: 100 });
|
|
221
|
+
const fill = {
|
|
222
|
+
orderId: "order1",
|
|
223
|
+
ticker: "TEST-MARKET",
|
|
224
|
+
side: "yes",
|
|
225
|
+
action: "sell",
|
|
226
|
+
count: 10,
|
|
227
|
+
price: 40,
|
|
228
|
+
timestamp: new Date(),
|
|
229
|
+
};
|
|
230
|
+
customRisk.onFill(fill, -150); // 150 cents loss
|
|
231
|
+
expect(customRisk.shouldHalt()).toBe(true);
|
|
232
|
+
expect(customRisk.getHaltReason()).toContain("Daily loss limit");
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
describe("resetDaily", () => {
|
|
236
|
+
it("should reset daily PnL", () => {
|
|
237
|
+
const fill = {
|
|
238
|
+
orderId: "order1",
|
|
239
|
+
ticker: "TEST-MARKET",
|
|
240
|
+
side: "yes",
|
|
241
|
+
action: "sell",
|
|
242
|
+
count: 10,
|
|
243
|
+
price: 55,
|
|
244
|
+
timestamp: new Date(),
|
|
245
|
+
};
|
|
246
|
+
risk.onFill(fill, 50);
|
|
247
|
+
expect(risk.getDailyPnL()).toBe(50);
|
|
248
|
+
risk.resetDaily();
|
|
249
|
+
expect(risk.getDailyPnL()).toBe(0);
|
|
250
|
+
});
|
|
251
|
+
it("should not auto-resume if halted", () => {
|
|
252
|
+
risk.halt("Loss limit");
|
|
253
|
+
risk.resetDaily();
|
|
254
|
+
expect(risk.shouldHalt()).toBe(true);
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
describe("updateLimits", () => {
|
|
258
|
+
it("should update limits", () => {
|
|
259
|
+
risk.updateLimits({ maxPositionPerMarket: 200 });
|
|
260
|
+
expect(risk.getLimits().maxPositionPerMarket).toBe(200);
|
|
261
|
+
});
|
|
262
|
+
it("should preserve other limits", () => {
|
|
263
|
+
const originalMaxDaily = risk.getLimits().maxDailyLoss;
|
|
264
|
+
risk.updateLimits({ maxPositionPerMarket: 200 });
|
|
265
|
+
expect(risk.getLimits().maxDailyLoss).toBe(originalMaxDaily);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
describe("getStatus", () => {
|
|
269
|
+
it("should return correct status", () => {
|
|
270
|
+
inventory.onFill({
|
|
271
|
+
orderId: "order1",
|
|
272
|
+
ticker: "TEST-MARKET",
|
|
273
|
+
side: "yes",
|
|
274
|
+
action: "buy",
|
|
275
|
+
count: 50,
|
|
276
|
+
price: 50,
|
|
277
|
+
timestamp: new Date(),
|
|
278
|
+
});
|
|
279
|
+
const fill = {
|
|
280
|
+
orderId: "order2",
|
|
281
|
+
ticker: "TEST-MARKET",
|
|
282
|
+
side: "yes",
|
|
283
|
+
action: "sell",
|
|
284
|
+
count: 10,
|
|
285
|
+
price: 55,
|
|
286
|
+
timestamp: new Date(),
|
|
287
|
+
};
|
|
288
|
+
risk.onFill(fill, 50);
|
|
289
|
+
const status = risk.getStatus(inventory);
|
|
290
|
+
expect(status.halted).toBe(false);
|
|
291
|
+
expect(status.dailyPnL).toBe(50);
|
|
292
|
+
expect(status.totalExposure).toBe(50);
|
|
293
|
+
expect(status.utilizationPercent).toBe(10); // 50/500 * 100
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
//# sourceMappingURL=risk.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk.test.js","sourceRoot":"","sources":["../../src/mm/risk.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Market Maker Types
|
|
3
|
+
*
|
|
4
|
+
* Core types for the market making system.
|
|
5
|
+
*/
|
|
6
|
+
/** Order side (YES or NO contract) */
|
|
7
|
+
export type Side = "yes" | "no";
|
|
8
|
+
/** Order action (buy or sell) */
|
|
9
|
+
export type Action = "buy" | "sell";
|
|
10
|
+
/** Order status in lifecycle */
|
|
11
|
+
export type OrderStatus = "pending" | "open" | "partial" | "filled" | "cancelled" | "failed";
|
|
12
|
+
/**
|
|
13
|
+
* A managed order tracked by the OrderManager
|
|
14
|
+
*/
|
|
15
|
+
export interface ManagedOrder {
|
|
16
|
+
/** Kalshi order ID (assigned after placement) */
|
|
17
|
+
id?: string;
|
|
18
|
+
/** Client-generated order ID for tracking */
|
|
19
|
+
clientOrderId: string;
|
|
20
|
+
/** Market ticker */
|
|
21
|
+
ticker: string;
|
|
22
|
+
/** YES or NO */
|
|
23
|
+
side: Side;
|
|
24
|
+
/** Buy or sell */
|
|
25
|
+
action: Action;
|
|
26
|
+
/** Price in cents (1-99) */
|
|
27
|
+
price: number;
|
|
28
|
+
/** Number of contracts */
|
|
29
|
+
count: number;
|
|
30
|
+
/** Current order status */
|
|
31
|
+
status: OrderStatus;
|
|
32
|
+
/** When the order was created */
|
|
33
|
+
createdAt: Date;
|
|
34
|
+
/** Number of contracts filled */
|
|
35
|
+
filledCount: number;
|
|
36
|
+
/** Average fill price (cents) */
|
|
37
|
+
avgFillPrice?: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Quote generated by a strategy
|
|
41
|
+
*/
|
|
42
|
+
export interface Quote {
|
|
43
|
+
ticker: string;
|
|
44
|
+
side: Side;
|
|
45
|
+
/** Bid price in cents */
|
|
46
|
+
bidPrice: number;
|
|
47
|
+
/** Bid size in contracts */
|
|
48
|
+
bidSize: number;
|
|
49
|
+
/** Ask price in cents */
|
|
50
|
+
askPrice: number;
|
|
51
|
+
/** Ask size in contracts */
|
|
52
|
+
askSize: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Position in a single market
|
|
56
|
+
*/
|
|
57
|
+
export interface Position {
|
|
58
|
+
ticker: string;
|
|
59
|
+
/** Number of YES contracts held (positive = long, negative = short) */
|
|
60
|
+
yesContracts: number;
|
|
61
|
+
/** Number of NO contracts held (positive = long, negative = short) */
|
|
62
|
+
noContracts: number;
|
|
63
|
+
/** Net exposure: yesContracts - noContracts */
|
|
64
|
+
netExposure: number;
|
|
65
|
+
/** Total cost basis in cents */
|
|
66
|
+
costBasis: number;
|
|
67
|
+
/** Unrealized PnL in cents */
|
|
68
|
+
unrealizedPnL: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Risk limits configuration
|
|
72
|
+
*/
|
|
73
|
+
export interface RiskLimits {
|
|
74
|
+
/** Max contracts per market (absolute value) */
|
|
75
|
+
maxPositionPerMarket: number;
|
|
76
|
+
/** Max total contracts across all markets */
|
|
77
|
+
maxTotalExposure: number;
|
|
78
|
+
/** Max daily loss in cents before halting */
|
|
79
|
+
maxDailyLoss: number;
|
|
80
|
+
/** Max contracts per single order */
|
|
81
|
+
maxOrderSize: number;
|
|
82
|
+
/** Minimum spread to quote (cents) */
|
|
83
|
+
minSpread: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Result of a risk check
|
|
87
|
+
*/
|
|
88
|
+
export interface RiskCheckResult {
|
|
89
|
+
/** Whether the action is allowed */
|
|
90
|
+
allowed: boolean;
|
|
91
|
+
/** Reason if not allowed */
|
|
92
|
+
reason?: string;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Fill event from Kalshi
|
|
96
|
+
*/
|
|
97
|
+
export interface Fill {
|
|
98
|
+
/** Order ID that was filled */
|
|
99
|
+
orderId: string;
|
|
100
|
+
/** Market ticker */
|
|
101
|
+
ticker: string;
|
|
102
|
+
/** YES or NO */
|
|
103
|
+
side: Side;
|
|
104
|
+
/** Buy or sell */
|
|
105
|
+
action: Action;
|
|
106
|
+
/** Number of contracts filled */
|
|
107
|
+
count: number;
|
|
108
|
+
/** Fill price in cents */
|
|
109
|
+
price: number;
|
|
110
|
+
/** Timestamp */
|
|
111
|
+
timestamp: Date;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* PnL summary
|
|
115
|
+
*/
|
|
116
|
+
export interface PnLSummary {
|
|
117
|
+
/** Realized PnL today (cents) */
|
|
118
|
+
realizedToday: number;
|
|
119
|
+
/** Unrealized PnL (cents) */
|
|
120
|
+
unrealized: number;
|
|
121
|
+
/** Total PnL (cents) */
|
|
122
|
+
total: number;
|
|
123
|
+
/** Number of fills today */
|
|
124
|
+
fillsToday: number;
|
|
125
|
+
/** Total volume traded today (contracts) */
|
|
126
|
+
volumeToday: number;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/mm/types.ts"],"names":[],"mappings":"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"}
|
package/dist/mm/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/mm/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kalshi WebSocket Authentication
|
|
3
|
+
*
|
|
4
|
+
* Handles signature generation for authenticated WebSocket connections.
|
|
5
|
+
* Uses the same RSA-PSS signing as the REST API.
|
|
6
|
+
*/
|
|
7
|
+
/** WebSocket API path for signing */
|
|
8
|
+
declare const WS_PATH = "/trade-api/ws/v2";
|
|
9
|
+
/**
|
|
10
|
+
* Generate authentication headers for WebSocket connection
|
|
11
|
+
*
|
|
12
|
+
* The message to sign is: timestamp + method + path
|
|
13
|
+
* e.g., "1703702400000GET/trade-api/ws/v2"
|
|
14
|
+
*
|
|
15
|
+
* @param apiKeyId - Your Kalshi API key ID
|
|
16
|
+
* @param privateKeyPem - Your private key in PEM format
|
|
17
|
+
* @param timestamp - Unix timestamp in milliseconds
|
|
18
|
+
* @returns Headers object for WebSocket connection
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateWsAuthHeaders(apiKeyId: string, privateKeyPem: string, timestamp?: number): Record<string, string>;
|
|
21
|
+
/**
|
|
22
|
+
* Generate a signed WebSocket URL with auth params
|
|
23
|
+
*
|
|
24
|
+
* Some WebSocket implementations don't support custom headers,
|
|
25
|
+
* so we can pass auth as query parameters instead.
|
|
26
|
+
*
|
|
27
|
+
* @param baseUrl - WebSocket endpoint URL
|
|
28
|
+
* @param apiKeyId - Your Kalshi API key ID
|
|
29
|
+
* @param privateKey - Your private key in PEM format
|
|
30
|
+
* @returns Full WebSocket URL with auth parameters
|
|
31
|
+
*/
|
|
32
|
+
export declare function generateSignedWsUrl(baseUrl: string, apiKeyId: string, privateKey: string): string;
|
|
33
|
+
/** Export path for testing */
|
|
34
|
+
export { WS_PATH };
|
|
35
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/websocket/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,qCAAqC;AACrC,QAAA,MAAM,OAAO,qBAAqB,CAAC;AAEnC;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,SAAS,GAAE,MAAmB,GAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CASR;AAED,8BAA8B;AAC9B,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kalshi WebSocket Authentication
|
|
3
|
+
*
|
|
4
|
+
* Handles signature generation for authenticated WebSocket connections.
|
|
5
|
+
* Uses the same RSA-PSS signing as the REST API.
|
|
6
|
+
*/
|
|
7
|
+
import * as crypto from 'crypto';
|
|
8
|
+
/** WebSocket API path for signing */
|
|
9
|
+
const WS_PATH = '/trade-api/ws/v2';
|
|
10
|
+
/**
|
|
11
|
+
* Generate authentication headers for WebSocket connection
|
|
12
|
+
*
|
|
13
|
+
* The message to sign is: timestamp + method + path
|
|
14
|
+
* e.g., "1703702400000GET/trade-api/ws/v2"
|
|
15
|
+
*
|
|
16
|
+
* @param apiKeyId - Your Kalshi API key ID
|
|
17
|
+
* @param privateKeyPem - Your private key in PEM format
|
|
18
|
+
* @param timestamp - Unix timestamp in milliseconds
|
|
19
|
+
* @returns Headers object for WebSocket connection
|
|
20
|
+
*/
|
|
21
|
+
export function generateWsAuthHeaders(apiKeyId, privateKeyPem, timestamp = Date.now()) {
|
|
22
|
+
const timestampStr = timestamp.toString();
|
|
23
|
+
// Message format: timestamp + method + path
|
|
24
|
+
const message = timestampStr + 'GET' + WS_PATH;
|
|
25
|
+
// Convert PEM string to KeyObject (required for proper signing)
|
|
26
|
+
const privateKey = crypto.createPrivateKey(privateKeyPem);
|
|
27
|
+
// Sign using RSA-PSS with SHA-256
|
|
28
|
+
const signature = crypto.sign('sha256', Buffer.from(message), {
|
|
29
|
+
key: privateKey,
|
|
30
|
+
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
31
|
+
saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST,
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
'KALSHI-ACCESS-KEY': apiKeyId,
|
|
35
|
+
'KALSHI-ACCESS-SIGNATURE': signature.toString('base64'),
|
|
36
|
+
'KALSHI-ACCESS-TIMESTAMP': timestampStr,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Generate a signed WebSocket URL with auth params
|
|
41
|
+
*
|
|
42
|
+
* Some WebSocket implementations don't support custom headers,
|
|
43
|
+
* so we can pass auth as query parameters instead.
|
|
44
|
+
*
|
|
45
|
+
* @param baseUrl - WebSocket endpoint URL
|
|
46
|
+
* @param apiKeyId - Your Kalshi API key ID
|
|
47
|
+
* @param privateKey - Your private key in PEM format
|
|
48
|
+
* @returns Full WebSocket URL with auth parameters
|
|
49
|
+
*/
|
|
50
|
+
export function generateSignedWsUrl(baseUrl, apiKeyId, privateKey) {
|
|
51
|
+
const headers = generateWsAuthHeaders(apiKeyId, privateKey);
|
|
52
|
+
const url = new URL(baseUrl);
|
|
53
|
+
url.searchParams.set('api_key', headers['KALSHI-ACCESS-KEY']);
|
|
54
|
+
url.searchParams.set('signature', headers['KALSHI-ACCESS-SIGNATURE']);
|
|
55
|
+
url.searchParams.set('timestamp', headers['KALSHI-ACCESS-TIMESTAMP']);
|
|
56
|
+
return url.toString();
|
|
57
|
+
}
|
|
58
|
+
/** Export path for testing */
|
|
59
|
+
export { WS_PATH };
|
|
60
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/websocket/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,qCAAqC;AACrC,MAAM,OAAO,GAAG,kBAAkB,CAAC;AAEnC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAgB,EAChB,aAAqB,EACrB,YAAoB,IAAI,CAAC,GAAG,EAAE;IAE9B,MAAM,YAAY,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;IAE1C,4CAA4C;IAC5C,MAAM,OAAO,GAAG,YAAY,GAAG,KAAK,GAAG,OAAO,CAAC;IAE/C,gEAAgE;IAChE,MAAM,UAAU,GAAG,MAAM,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC;IAE1D,kCAAkC;IAClC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;QAC5D,GAAG,EAAE,UAAU;QACf,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,qBAAqB;QAC/C,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,sBAAsB;KACpD,CAAC,CAAC;IAEH,OAAO;QACL,mBAAmB,EAAE,QAAQ;QAC7B,yBAAyB,EAAE,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACvD,yBAAyB,EAAE,YAAY;KACxC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAe,EACf,QAAgB,EAChB,UAAkB;IAElB,MAAM,OAAO,GAAG,qBAAqB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAE5D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC9D,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC;IACtE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC;IAEtE,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED,8BAA8B;AAC9B,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.test.d.ts","sourceRoot":"","sources":["../../src/websocket/auth.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import * as crypto from 'crypto';
|
|
3
|
+
// Mock crypto module since we can't use real RSA keys in tests easily
|
|
4
|
+
vi.mock('crypto', async () => {
|
|
5
|
+
const actual = await vi.importActual('crypto');
|
|
6
|
+
return {
|
|
7
|
+
...actual,
|
|
8
|
+
createPrivateKey: vi.fn(() => 'mocked-key-object'),
|
|
9
|
+
sign: vi.fn(() => Buffer.from('mocked-signature-base64')),
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
import { generateWsAuthHeaders, generateSignedWsUrl, WS_PATH } from './auth.js';
|
|
13
|
+
describe('WebSocket Auth', () => {
|
|
14
|
+
describe('generateWsAuthHeaders', () => {
|
|
15
|
+
it('generates all required headers', () => {
|
|
16
|
+
const headers = generateWsAuthHeaders('test-api-key', 'fake-private-key');
|
|
17
|
+
expect(headers).toHaveProperty('KALSHI-ACCESS-KEY');
|
|
18
|
+
expect(headers).toHaveProperty('KALSHI-ACCESS-SIGNATURE');
|
|
19
|
+
expect(headers).toHaveProperty('KALSHI-ACCESS-TIMESTAMP');
|
|
20
|
+
});
|
|
21
|
+
it('uses the provided API key', () => {
|
|
22
|
+
const headers = generateWsAuthHeaders('my-api-key-123', 'fake-key');
|
|
23
|
+
expect(headers['KALSHI-ACCESS-KEY']).toBe('my-api-key-123');
|
|
24
|
+
});
|
|
25
|
+
it('uses the provided timestamp', () => {
|
|
26
|
+
const timestamp = 1703721600000; // Fixed timestamp
|
|
27
|
+
const headers = generateWsAuthHeaders('test-key', 'fake-key', timestamp);
|
|
28
|
+
expect(headers['KALSHI-ACCESS-TIMESTAMP']).toBe('1703721600000');
|
|
29
|
+
});
|
|
30
|
+
it('returns a signature', () => {
|
|
31
|
+
const headers = generateWsAuthHeaders('test-key', 'fake-key');
|
|
32
|
+
expect(headers['KALSHI-ACCESS-SIGNATURE']).toBeDefined();
|
|
33
|
+
expect(headers['KALSHI-ACCESS-SIGNATURE'].length).toBeGreaterThan(0);
|
|
34
|
+
});
|
|
35
|
+
it('signs the correct message format (timestamp + GET + path)', () => {
|
|
36
|
+
const timestamp = 1703721600000;
|
|
37
|
+
generateWsAuthHeaders('test-key', 'fake-key-pem', timestamp);
|
|
38
|
+
// Verify crypto.createPrivateKey was called with the PEM
|
|
39
|
+
expect(crypto.createPrivateKey).toHaveBeenCalledWith('fake-key-pem');
|
|
40
|
+
// Verify crypto.sign was called with correct message format
|
|
41
|
+
expect(crypto.sign).toHaveBeenCalledWith('sha256', Buffer.from(`${timestamp}GET${WS_PATH}`), expect.objectContaining({
|
|
42
|
+
key: 'mocked-key-object',
|
|
43
|
+
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
44
|
+
}));
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('generateSignedWsUrl', () => {
|
|
48
|
+
it('appends auth parameters to URL', () => {
|
|
49
|
+
const url = generateSignedWsUrl('wss://api.example.com/ws', 'test-api-key', 'fake-key');
|
|
50
|
+
expect(url).toContain('api_key=test-api-key');
|
|
51
|
+
expect(url).toContain('signature=');
|
|
52
|
+
expect(url).toContain('timestamp=');
|
|
53
|
+
});
|
|
54
|
+
it('preserves the base URL', () => {
|
|
55
|
+
const url = generateSignedWsUrl('wss://api.elections.kalshi.com/trade-api/ws/v2', 'test-key', 'fake-key');
|
|
56
|
+
expect(url.startsWith('wss://api.elections.kalshi.com/trade-api/ws/v2')).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
it('properly encodes parameters', () => {
|
|
59
|
+
const url = generateSignedWsUrl('wss://api.example.com/ws', 'test+key', 'fake-key');
|
|
60
|
+
// URL should properly encode the + character
|
|
61
|
+
expect(url).toContain('api_key=test%2Bkey');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=auth.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.test.js","sourceRoot":"","sources":["../../src/websocket/auth.test.ts"],"names":[],"mappings":"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"}
|