@newyorkcompute/kalshi-core 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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -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 +9 -2
- package/dist/websocket/auth.d.ts.map +1 -1
- package/dist/websocket/auth.js +18 -13
- package/dist/websocket/auth.js.map +1 -1
- package/dist/websocket/auth.test.js +15 -6
- package/dist/websocket/auth.test.js.map +1 -1
- package/dist/websocket/client.d.ts.map +1 -1
- package/dist/websocket/client.js +6 -0
- package/dist/websocket/client.js.map +1 -1
- package/dist/websocket/types.d.ts +13 -1
- package/dist/websocket/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
+
import { InventoryTracker } from "./inventory.js";
|
|
3
|
+
describe("InventoryTracker", () => {
|
|
4
|
+
let tracker;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
tracker = new InventoryTracker();
|
|
7
|
+
});
|
|
8
|
+
describe("onFill", () => {
|
|
9
|
+
it("should add YES contracts on buy", () => {
|
|
10
|
+
const fill = {
|
|
11
|
+
orderId: "order1",
|
|
12
|
+
ticker: "TEST-MARKET",
|
|
13
|
+
side: "yes",
|
|
14
|
+
action: "buy",
|
|
15
|
+
count: 10,
|
|
16
|
+
price: 50,
|
|
17
|
+
timestamp: new Date(),
|
|
18
|
+
};
|
|
19
|
+
tracker.onFill(fill);
|
|
20
|
+
const position = tracker.getPosition("TEST-MARKET");
|
|
21
|
+
expect(position).toBeDefined();
|
|
22
|
+
expect(position.yesContracts).toBe(10);
|
|
23
|
+
expect(position.noContracts).toBe(0);
|
|
24
|
+
expect(position.netExposure).toBe(10);
|
|
25
|
+
});
|
|
26
|
+
it("should subtract YES contracts on sell", () => {
|
|
27
|
+
// First buy
|
|
28
|
+
tracker.onFill({
|
|
29
|
+
orderId: "order1",
|
|
30
|
+
ticker: "TEST-MARKET",
|
|
31
|
+
side: "yes",
|
|
32
|
+
action: "buy",
|
|
33
|
+
count: 10,
|
|
34
|
+
price: 50,
|
|
35
|
+
timestamp: new Date(),
|
|
36
|
+
});
|
|
37
|
+
// Then sell
|
|
38
|
+
tracker.onFill({
|
|
39
|
+
orderId: "order2",
|
|
40
|
+
ticker: "TEST-MARKET",
|
|
41
|
+
side: "yes",
|
|
42
|
+
action: "sell",
|
|
43
|
+
count: 5,
|
|
44
|
+
price: 55,
|
|
45
|
+
timestamp: new Date(),
|
|
46
|
+
});
|
|
47
|
+
const position = tracker.getPosition("TEST-MARKET");
|
|
48
|
+
expect(position.yesContracts).toBe(5);
|
|
49
|
+
expect(position.netExposure).toBe(5);
|
|
50
|
+
});
|
|
51
|
+
it("should add NO contracts on buy", () => {
|
|
52
|
+
const fill = {
|
|
53
|
+
orderId: "order1",
|
|
54
|
+
ticker: "TEST-MARKET",
|
|
55
|
+
side: "no",
|
|
56
|
+
action: "buy",
|
|
57
|
+
count: 10,
|
|
58
|
+
price: 50,
|
|
59
|
+
timestamp: new Date(),
|
|
60
|
+
};
|
|
61
|
+
tracker.onFill(fill);
|
|
62
|
+
const position = tracker.getPosition("TEST-MARKET");
|
|
63
|
+
expect(position.noContracts).toBe(10);
|
|
64
|
+
expect(position.yesContracts).toBe(0);
|
|
65
|
+
expect(position.netExposure).toBe(-10); // Negative because NO
|
|
66
|
+
});
|
|
67
|
+
it("should track multiple markets independently", () => {
|
|
68
|
+
tracker.onFill({
|
|
69
|
+
orderId: "order1",
|
|
70
|
+
ticker: "MARKET-A",
|
|
71
|
+
side: "yes",
|
|
72
|
+
action: "buy",
|
|
73
|
+
count: 10,
|
|
74
|
+
price: 50,
|
|
75
|
+
timestamp: new Date(),
|
|
76
|
+
});
|
|
77
|
+
tracker.onFill({
|
|
78
|
+
orderId: "order2",
|
|
79
|
+
ticker: "MARKET-B",
|
|
80
|
+
side: "yes",
|
|
81
|
+
action: "buy",
|
|
82
|
+
count: 20,
|
|
83
|
+
price: 60,
|
|
84
|
+
timestamp: new Date(),
|
|
85
|
+
});
|
|
86
|
+
expect(tracker.getPosition("MARKET-A").yesContracts).toBe(10);
|
|
87
|
+
expect(tracker.getPosition("MARKET-B").yesContracts).toBe(20);
|
|
88
|
+
});
|
|
89
|
+
it("should update daily stats", () => {
|
|
90
|
+
tracker.onFill({
|
|
91
|
+
orderId: "order1",
|
|
92
|
+
ticker: "TEST-MARKET",
|
|
93
|
+
side: "yes",
|
|
94
|
+
action: "buy",
|
|
95
|
+
count: 10,
|
|
96
|
+
price: 50,
|
|
97
|
+
timestamp: new Date(),
|
|
98
|
+
});
|
|
99
|
+
tracker.onFill({
|
|
100
|
+
orderId: "order2",
|
|
101
|
+
ticker: "TEST-MARKET",
|
|
102
|
+
side: "yes",
|
|
103
|
+
action: "buy",
|
|
104
|
+
count: 5,
|
|
105
|
+
price: 55,
|
|
106
|
+
timestamp: new Date(),
|
|
107
|
+
});
|
|
108
|
+
const summary = tracker.getPnLSummary();
|
|
109
|
+
expect(summary.fillsToday).toBe(2);
|
|
110
|
+
expect(summary.volumeToday).toBe(15);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
describe("getTotalExposure", () => {
|
|
114
|
+
it("should return 0 with no positions", () => {
|
|
115
|
+
expect(tracker.getTotalExposure()).toBe(0);
|
|
116
|
+
});
|
|
117
|
+
it("should sum absolute exposures across markets", () => {
|
|
118
|
+
tracker.onFill({
|
|
119
|
+
orderId: "order1",
|
|
120
|
+
ticker: "MARKET-A",
|
|
121
|
+
side: "yes",
|
|
122
|
+
action: "buy",
|
|
123
|
+
count: 10,
|
|
124
|
+
price: 50,
|
|
125
|
+
timestamp: new Date(),
|
|
126
|
+
});
|
|
127
|
+
tracker.onFill({
|
|
128
|
+
orderId: "order2",
|
|
129
|
+
ticker: "MARKET-B",
|
|
130
|
+
side: "no",
|
|
131
|
+
action: "buy",
|
|
132
|
+
count: 5,
|
|
133
|
+
price: 50,
|
|
134
|
+
timestamp: new Date(),
|
|
135
|
+
});
|
|
136
|
+
// A: +10 yes = +10 exposure
|
|
137
|
+
// B: +5 no = -5 exposure (absolute = 5)
|
|
138
|
+
expect(tracker.getTotalExposure()).toBe(15);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
describe("getNetExposure", () => {
|
|
142
|
+
it("should return 0 for unknown ticker", () => {
|
|
143
|
+
expect(tracker.getNetExposure("UNKNOWN")).toBe(0);
|
|
144
|
+
});
|
|
145
|
+
it("should return correct net exposure", () => {
|
|
146
|
+
tracker.onFill({
|
|
147
|
+
orderId: "order1",
|
|
148
|
+
ticker: "TEST-MARKET",
|
|
149
|
+
side: "yes",
|
|
150
|
+
action: "buy",
|
|
151
|
+
count: 10,
|
|
152
|
+
price: 50,
|
|
153
|
+
timestamp: new Date(),
|
|
154
|
+
});
|
|
155
|
+
expect(tracker.getNetExposure("TEST-MARKET")).toBe(10);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe("getAllPositions", () => {
|
|
159
|
+
it("should return empty array with no positions", () => {
|
|
160
|
+
expect(tracker.getAllPositions()).toEqual([]);
|
|
161
|
+
});
|
|
162
|
+
it("should return all positions", () => {
|
|
163
|
+
tracker.onFill({
|
|
164
|
+
orderId: "order1",
|
|
165
|
+
ticker: "MARKET-A",
|
|
166
|
+
side: "yes",
|
|
167
|
+
action: "buy",
|
|
168
|
+
count: 10,
|
|
169
|
+
price: 50,
|
|
170
|
+
timestamp: new Date(),
|
|
171
|
+
});
|
|
172
|
+
tracker.onFill({
|
|
173
|
+
orderId: "order2",
|
|
174
|
+
ticker: "MARKET-B",
|
|
175
|
+
side: "yes",
|
|
176
|
+
action: "buy",
|
|
177
|
+
count: 20,
|
|
178
|
+
price: 60,
|
|
179
|
+
timestamp: new Date(),
|
|
180
|
+
});
|
|
181
|
+
const positions = tracker.getAllPositions();
|
|
182
|
+
expect(positions).toHaveLength(2);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
describe("resetDaily", () => {
|
|
186
|
+
it("should reset daily stats", () => {
|
|
187
|
+
tracker.onFill({
|
|
188
|
+
orderId: "order1",
|
|
189
|
+
ticker: "TEST-MARKET",
|
|
190
|
+
side: "yes",
|
|
191
|
+
action: "buy",
|
|
192
|
+
count: 10,
|
|
193
|
+
price: 50,
|
|
194
|
+
timestamp: new Date(),
|
|
195
|
+
});
|
|
196
|
+
tracker.resetDaily();
|
|
197
|
+
const summary = tracker.getPnLSummary();
|
|
198
|
+
expect(summary.fillsToday).toBe(0);
|
|
199
|
+
expect(summary.volumeToday).toBe(0);
|
|
200
|
+
expect(summary.realizedToday).toBe(0);
|
|
201
|
+
});
|
|
202
|
+
it("should preserve positions after reset", () => {
|
|
203
|
+
tracker.onFill({
|
|
204
|
+
orderId: "order1",
|
|
205
|
+
ticker: "TEST-MARKET",
|
|
206
|
+
side: "yes",
|
|
207
|
+
action: "buy",
|
|
208
|
+
count: 10,
|
|
209
|
+
price: 50,
|
|
210
|
+
timestamp: new Date(),
|
|
211
|
+
});
|
|
212
|
+
tracker.resetDaily();
|
|
213
|
+
const position = tracker.getPosition("TEST-MARKET");
|
|
214
|
+
expect(position.yesContracts).toBe(10);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
describe("clear", () => {
|
|
218
|
+
it("should remove all positions", () => {
|
|
219
|
+
tracker.onFill({
|
|
220
|
+
orderId: "order1",
|
|
221
|
+
ticker: "TEST-MARKET",
|
|
222
|
+
side: "yes",
|
|
223
|
+
action: "buy",
|
|
224
|
+
count: 10,
|
|
225
|
+
price: 50,
|
|
226
|
+
timestamp: new Date(),
|
|
227
|
+
});
|
|
228
|
+
tracker.clear();
|
|
229
|
+
expect(tracker.getAllPositions()).toEqual([]);
|
|
230
|
+
expect(tracker.getPosition("TEST-MARKET")).toBeUndefined();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
describe("initializeFromPortfolio", () => {
|
|
234
|
+
it("should initialize positions from portfolio data", () => {
|
|
235
|
+
tracker.initializeFromPortfolio([
|
|
236
|
+
{ ticker: "MARKET-A", yesContracts: 10, noContracts: 0, costBasis: 500 },
|
|
237
|
+
{ ticker: "MARKET-B", yesContracts: 0, noContracts: 5, costBasis: 250 },
|
|
238
|
+
]);
|
|
239
|
+
const posA = tracker.getPosition("MARKET-A");
|
|
240
|
+
expect(posA.yesContracts).toBe(10);
|
|
241
|
+
expect(posA.netExposure).toBe(10);
|
|
242
|
+
const posB = tracker.getPosition("MARKET-B");
|
|
243
|
+
expect(posB.noContracts).toBe(5);
|
|
244
|
+
expect(posB.netExposure).toBe(-5);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
describe("getPnLSummary with currentPrices", () => {
|
|
248
|
+
it("should calculate unrealized PnL for YES position", () => {
|
|
249
|
+
// Buy 10 YES @ 50¢ = 500¢ cost
|
|
250
|
+
tracker.onFill({
|
|
251
|
+
orderId: "order1",
|
|
252
|
+
ticker: "TEST-MARKET",
|
|
253
|
+
side: "yes",
|
|
254
|
+
action: "buy",
|
|
255
|
+
count: 10,
|
|
256
|
+
price: 50,
|
|
257
|
+
timestamp: new Date(),
|
|
258
|
+
});
|
|
259
|
+
// Current price is 60¢ - unrealized profit = 10 * (60 - 50) = 100¢
|
|
260
|
+
const prices = new Map([["TEST-MARKET", 60]]);
|
|
261
|
+
const summary = tracker.getPnLSummary(prices);
|
|
262
|
+
expect(summary.unrealized).toBe(100);
|
|
263
|
+
expect(summary.total).toBe(100);
|
|
264
|
+
});
|
|
265
|
+
it("should calculate unrealized PnL for NO position", () => {
|
|
266
|
+
// Buy 10 NO @ 40¢ = 400¢ cost
|
|
267
|
+
tracker.onFill({
|
|
268
|
+
orderId: "order1",
|
|
269
|
+
ticker: "TEST-MARKET",
|
|
270
|
+
side: "no",
|
|
271
|
+
action: "buy",
|
|
272
|
+
count: 10,
|
|
273
|
+
price: 40,
|
|
274
|
+
timestamp: new Date(),
|
|
275
|
+
});
|
|
276
|
+
// Current YES price is 50¢, so NO value = 10 * (100-50) = 500¢
|
|
277
|
+
// Unrealized = 500 - 400 = 100¢
|
|
278
|
+
const prices = new Map([["TEST-MARKET", 50]]);
|
|
279
|
+
const summary = tracker.getPnLSummary(prices);
|
|
280
|
+
expect(summary.unrealized).toBe(100);
|
|
281
|
+
});
|
|
282
|
+
it("should skip positions with zero exposure", () => {
|
|
283
|
+
tracker.initializeFromPortfolio([
|
|
284
|
+
{ ticker: "MARKET-A", yesContracts: 0, noContracts: 0, costBasis: 0 },
|
|
285
|
+
]);
|
|
286
|
+
const prices = new Map([["MARKET-A", 50]]);
|
|
287
|
+
const summary = tracker.getPnLSummary(prices);
|
|
288
|
+
expect(summary.unrealized).toBe(0);
|
|
289
|
+
});
|
|
290
|
+
it("should skip markets without current price", () => {
|
|
291
|
+
tracker.onFill({
|
|
292
|
+
orderId: "order1",
|
|
293
|
+
ticker: "TEST-MARKET",
|
|
294
|
+
side: "yes",
|
|
295
|
+
action: "buy",
|
|
296
|
+
count: 10,
|
|
297
|
+
price: 50,
|
|
298
|
+
timestamp: new Date(),
|
|
299
|
+
});
|
|
300
|
+
// Empty prices map
|
|
301
|
+
const prices = new Map();
|
|
302
|
+
const summary = tracker.getPnLSummary(prices);
|
|
303
|
+
expect(summary.unrealized).toBe(0);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
describe("sell NO contracts", () => {
|
|
307
|
+
it("should subtract NO contracts on sell", () => {
|
|
308
|
+
// First buy NO
|
|
309
|
+
tracker.onFill({
|
|
310
|
+
orderId: "order1",
|
|
311
|
+
ticker: "TEST-MARKET",
|
|
312
|
+
side: "no",
|
|
313
|
+
action: "buy",
|
|
314
|
+
count: 10,
|
|
315
|
+
price: 40,
|
|
316
|
+
timestamp: new Date(),
|
|
317
|
+
});
|
|
318
|
+
// Then sell NO
|
|
319
|
+
tracker.onFill({
|
|
320
|
+
orderId: "order2",
|
|
321
|
+
ticker: "TEST-MARKET",
|
|
322
|
+
side: "no",
|
|
323
|
+
action: "sell",
|
|
324
|
+
count: 5,
|
|
325
|
+
price: 45,
|
|
326
|
+
timestamp: new Date(),
|
|
327
|
+
});
|
|
328
|
+
const position = tracker.getPosition("TEST-MARKET");
|
|
329
|
+
expect(position.noContracts).toBe(5);
|
|
330
|
+
expect(position.netExposure).toBe(-5);
|
|
331
|
+
});
|
|
332
|
+
it("should calculate realized PnL when selling NO", () => {
|
|
333
|
+
// Buy 10 NO @ 40¢
|
|
334
|
+
tracker.onFill({
|
|
335
|
+
orderId: "order1",
|
|
336
|
+
ticker: "TEST-MARKET",
|
|
337
|
+
side: "no",
|
|
338
|
+
action: "buy",
|
|
339
|
+
count: 10,
|
|
340
|
+
price: 40,
|
|
341
|
+
timestamp: new Date(),
|
|
342
|
+
});
|
|
343
|
+
// Sell 5 NO @ 50¢ - profit = 5 * (50 - 40) = 50¢
|
|
344
|
+
tracker.onFill({
|
|
345
|
+
orderId: "order2",
|
|
346
|
+
ticker: "TEST-MARKET",
|
|
347
|
+
side: "no",
|
|
348
|
+
action: "sell",
|
|
349
|
+
count: 5,
|
|
350
|
+
price: 50,
|
|
351
|
+
timestamp: new Date(),
|
|
352
|
+
});
|
|
353
|
+
const summary = tracker.getPnLSummary();
|
|
354
|
+
expect(summary.realizedToday).toBeGreaterThan(0);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
//# sourceMappingURL=inventory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inventory.test.js","sourceRoot":"","sources":["../../src/mm/inventory.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Order Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages the lifecycle of orders for market making.
|
|
5
|
+
* Handles placement, cancellation, and tracking of orders.
|
|
6
|
+
*/
|
|
7
|
+
import type { OrdersApi } from "kalshi-typescript";
|
|
8
|
+
import type { ManagedOrder, Side, Action, OrderStatus, Quote } from "./types.js";
|
|
9
|
+
/** Input for creating a new order */
|
|
10
|
+
export interface CreateOrderInput {
|
|
11
|
+
ticker: string;
|
|
12
|
+
side: Side;
|
|
13
|
+
action: Action;
|
|
14
|
+
price: number;
|
|
15
|
+
count: number;
|
|
16
|
+
}
|
|
17
|
+
/** Result of order placement */
|
|
18
|
+
export interface PlaceOrderResult {
|
|
19
|
+
success: boolean;
|
|
20
|
+
order?: ManagedOrder;
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* OrderManager handles order lifecycle for market making
|
|
25
|
+
*/
|
|
26
|
+
export declare class OrderManager {
|
|
27
|
+
private orders;
|
|
28
|
+
private ordersApi;
|
|
29
|
+
constructor(ordersApi: OrdersApi);
|
|
30
|
+
/**
|
|
31
|
+
* Place a new order
|
|
32
|
+
*/
|
|
33
|
+
place(input: CreateOrderInput): Promise<PlaceOrderResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Place multiple orders (for two-sided quotes)
|
|
36
|
+
*/
|
|
37
|
+
placeBulk(inputs: CreateOrderInput[]): Promise<PlaceOrderResult[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Cancel a specific order by client order ID
|
|
40
|
+
*/
|
|
41
|
+
cancel(clientOrderId: string): Promise<boolean>;
|
|
42
|
+
/**
|
|
43
|
+
* Cancel all orders, optionally filtered by ticker
|
|
44
|
+
*/
|
|
45
|
+
cancelAll(ticker?: string): Promise<number>;
|
|
46
|
+
/**
|
|
47
|
+
* Get all active (open/partial) orders
|
|
48
|
+
*/
|
|
49
|
+
getActive(ticker?: string): ManagedOrder[];
|
|
50
|
+
/**
|
|
51
|
+
* Get all orders (including filled/cancelled)
|
|
52
|
+
*/
|
|
53
|
+
getAll(): ManagedOrder[];
|
|
54
|
+
/**
|
|
55
|
+
* Get order by client order ID
|
|
56
|
+
*/
|
|
57
|
+
get(clientOrderId: string): ManagedOrder | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Update order status (called when we receive fill/cancel events)
|
|
60
|
+
*/
|
|
61
|
+
updateStatus(clientOrderId: string, status: OrderStatus, filledCount?: number, avgFillPrice?: number): void;
|
|
62
|
+
/**
|
|
63
|
+
* Update quotes for a market (cancel old, place new)
|
|
64
|
+
*
|
|
65
|
+
* This is the main method for market making - it atomically updates
|
|
66
|
+
* the bid/ask quotes for a given market.
|
|
67
|
+
*/
|
|
68
|
+
updateQuote(quote: Quote): Promise<{
|
|
69
|
+
cancelled: number;
|
|
70
|
+
placed: PlaceOrderResult[];
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Clean up old completed orders (keep memory bounded)
|
|
74
|
+
*/
|
|
75
|
+
cleanup(maxAge?: number): number;
|
|
76
|
+
/**
|
|
77
|
+
* Map Kalshi order status to our internal status
|
|
78
|
+
*/
|
|
79
|
+
private mapKalshiStatus;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=order-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"order-manager.d.ts","sourceRoot":"","sources":["../../src/mm/order-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EACV,YAAY,EACZ,IAAI,EACJ,MAAM,EACN,WAAW,EACX,KAAK,EACN,MAAM,YAAY,CAAC;AAEpB,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,gCAAgC;AAChC,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AASD;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,SAAS,CAAY;gBAEjB,SAAS,EAAE,SAAS;IAIhC;;OAEG;IACG,KAAK,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA6C/D;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAKxE;;OAEG;IACG,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBrD;;OAEG;IACG,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBjD;;OAEG;IACH,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE;IAa1C;;OAEG;IACH,MAAM,IAAI,YAAY,EAAE;IAIxB;;OAEG;IACH,GAAG,CAAC,aAAa,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIpD;;OAEG;IACH,YAAY,CACV,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,WAAW,EACnB,WAAW,CAAC,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,GACpB,IAAI;IAaP;;;;;OAKG;IACG,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC;QACvC,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,gBAAgB,EAAE,CAAC;KAC5B,CAAC;IAkCF;;OAEG;IACH,OAAO,CAAC,MAAM,GAAE,MAA4B,GAAG,MAAM;IAgBrD;;OAEG;IACH,OAAO,CAAC,eAAe;CAexB"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Order Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages the lifecycle of orders for market making.
|
|
5
|
+
* Handles placement, cancellation, and tracking of orders.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Generates a unique client order ID
|
|
9
|
+
*/
|
|
10
|
+
function generateClientOrderId() {
|
|
11
|
+
return `mm-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* OrderManager handles order lifecycle for market making
|
|
15
|
+
*/
|
|
16
|
+
export class OrderManager {
|
|
17
|
+
orders = new Map();
|
|
18
|
+
ordersApi;
|
|
19
|
+
constructor(ordersApi) {
|
|
20
|
+
this.ordersApi = ordersApi;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Place a new order
|
|
24
|
+
*/
|
|
25
|
+
async place(input) {
|
|
26
|
+
const clientOrderId = generateClientOrderId();
|
|
27
|
+
// Create managed order (pending)
|
|
28
|
+
const managedOrder = {
|
|
29
|
+
clientOrderId,
|
|
30
|
+
ticker: input.ticker,
|
|
31
|
+
side: input.side,
|
|
32
|
+
action: input.action,
|
|
33
|
+
price: input.price,
|
|
34
|
+
count: input.count,
|
|
35
|
+
status: "pending",
|
|
36
|
+
createdAt: new Date(),
|
|
37
|
+
filledCount: 0,
|
|
38
|
+
};
|
|
39
|
+
this.orders.set(clientOrderId, managedOrder);
|
|
40
|
+
try {
|
|
41
|
+
// Place via Kalshi API
|
|
42
|
+
const response = await this.ordersApi.createOrder({
|
|
43
|
+
ticker: input.ticker,
|
|
44
|
+
type: "limit",
|
|
45
|
+
side: input.side,
|
|
46
|
+
action: input.action,
|
|
47
|
+
yes_price: input.side === "yes" ? input.price : undefined,
|
|
48
|
+
no_price: input.side === "no" ? input.price : undefined,
|
|
49
|
+
count: input.count,
|
|
50
|
+
client_order_id: clientOrderId,
|
|
51
|
+
});
|
|
52
|
+
// Update with Kalshi order ID
|
|
53
|
+
const kalshiOrder = response.data.order;
|
|
54
|
+
managedOrder.id = kalshiOrder?.order_id;
|
|
55
|
+
managedOrder.status = this.mapKalshiStatus(kalshiOrder?.status);
|
|
56
|
+
return { success: true, order: managedOrder };
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
managedOrder.status = "failed";
|
|
60
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
61
|
+
return { success: false, order: managedOrder, error: errorMessage };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Place multiple orders (for two-sided quotes)
|
|
66
|
+
*/
|
|
67
|
+
async placeBulk(inputs) {
|
|
68
|
+
// Place in parallel for speed
|
|
69
|
+
return Promise.all(inputs.map((input) => this.place(input)));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Cancel a specific order by client order ID
|
|
73
|
+
*/
|
|
74
|
+
async cancel(clientOrderId) {
|
|
75
|
+
const order = this.orders.get(clientOrderId);
|
|
76
|
+
if (!order || !order.id) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
await this.ordersApi.cancelOrder(order.id);
|
|
81
|
+
order.status = "cancelled";
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Order may already be filled or cancelled
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Cancel all orders, optionally filtered by ticker
|
|
91
|
+
*/
|
|
92
|
+
async cancelAll(ticker) {
|
|
93
|
+
const ordersToCancel = this.getActive(ticker);
|
|
94
|
+
let cancelledCount = 0;
|
|
95
|
+
// Cancel in parallel
|
|
96
|
+
const results = await Promise.allSettled(ordersToCancel.map((order) => this.cancel(order.clientOrderId)));
|
|
97
|
+
for (const result of results) {
|
|
98
|
+
if (result.status === "fulfilled" && result.value) {
|
|
99
|
+
cancelledCount++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return cancelledCount;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get all active (open/partial) orders
|
|
106
|
+
*/
|
|
107
|
+
getActive(ticker) {
|
|
108
|
+
const activeStatuses = ["pending", "open", "partial"];
|
|
109
|
+
const result = [];
|
|
110
|
+
for (const order of this.orders.values()) {
|
|
111
|
+
if (!activeStatuses.includes(order.status))
|
|
112
|
+
continue;
|
|
113
|
+
if (ticker && order.ticker !== ticker)
|
|
114
|
+
continue;
|
|
115
|
+
result.push(order);
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get all orders (including filled/cancelled)
|
|
121
|
+
*/
|
|
122
|
+
getAll() {
|
|
123
|
+
return Array.from(this.orders.values());
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get order by client order ID
|
|
127
|
+
*/
|
|
128
|
+
get(clientOrderId) {
|
|
129
|
+
return this.orders.get(clientOrderId);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Update order status (called when we receive fill/cancel events)
|
|
133
|
+
*/
|
|
134
|
+
updateStatus(clientOrderId, status, filledCount, avgFillPrice) {
|
|
135
|
+
const order = this.orders.get(clientOrderId);
|
|
136
|
+
if (!order)
|
|
137
|
+
return;
|
|
138
|
+
order.status = status;
|
|
139
|
+
if (filledCount !== undefined) {
|
|
140
|
+
order.filledCount = filledCount;
|
|
141
|
+
}
|
|
142
|
+
if (avgFillPrice !== undefined) {
|
|
143
|
+
order.avgFillPrice = avgFillPrice;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Update quotes for a market (cancel old, place new)
|
|
148
|
+
*
|
|
149
|
+
* This is the main method for market making - it atomically updates
|
|
150
|
+
* the bid/ask quotes for a given market.
|
|
151
|
+
*/
|
|
152
|
+
async updateQuote(quote) {
|
|
153
|
+
// 1. Cancel existing orders for this ticker
|
|
154
|
+
const cancelled = await this.cancelAll(quote.ticker);
|
|
155
|
+
// 2. Place new bid and ask orders
|
|
156
|
+
const orders = [];
|
|
157
|
+
// Bid (buy YES at bid price)
|
|
158
|
+
if (quote.bidSize > 0 && quote.bidPrice >= 1 && quote.bidPrice <= 99) {
|
|
159
|
+
orders.push({
|
|
160
|
+
ticker: quote.ticker,
|
|
161
|
+
side: quote.side,
|
|
162
|
+
action: "buy",
|
|
163
|
+
price: quote.bidPrice,
|
|
164
|
+
count: quote.bidSize,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// Ask (sell YES at ask price, or buy NO)
|
|
168
|
+
if (quote.askSize > 0 && quote.askPrice >= 1 && quote.askPrice <= 99) {
|
|
169
|
+
orders.push({
|
|
170
|
+
ticker: quote.ticker,
|
|
171
|
+
side: quote.side,
|
|
172
|
+
action: "sell",
|
|
173
|
+
price: quote.askPrice,
|
|
174
|
+
count: quote.askSize,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const placed = await this.placeBulk(orders);
|
|
178
|
+
return { cancelled, placed };
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Clean up old completed orders (keep memory bounded)
|
|
182
|
+
*/
|
|
183
|
+
cleanup(maxAge = 24 * 60 * 60 * 1000) {
|
|
184
|
+
const now = Date.now();
|
|
185
|
+
const completedStatuses = ["filled", "cancelled", "failed"];
|
|
186
|
+
let removed = 0;
|
|
187
|
+
for (const [id, order] of this.orders) {
|
|
188
|
+
if (!completedStatuses.includes(order.status))
|
|
189
|
+
continue;
|
|
190
|
+
if (now - order.createdAt.getTime() > maxAge) {
|
|
191
|
+
this.orders.delete(id);
|
|
192
|
+
removed++;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return removed;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Map Kalshi order status to our internal status
|
|
199
|
+
*/
|
|
200
|
+
mapKalshiStatus(status) {
|
|
201
|
+
switch (status?.toLowerCase()) {
|
|
202
|
+
case "resting":
|
|
203
|
+
return "open";
|
|
204
|
+
case "pending":
|
|
205
|
+
return "pending";
|
|
206
|
+
case "executed":
|
|
207
|
+
return "filled";
|
|
208
|
+
case "canceled":
|
|
209
|
+
case "cancelled":
|
|
210
|
+
return "cancelled";
|
|
211
|
+
default:
|
|
212
|
+
return "pending";
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=order-manager.js.map
|