@jsnw/kalshi-client 0.0.1 → 0.2.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.cjs +271 -13
- package/dist/index.d.cts +567 -121
- package/dist/index.d.mts +567 -121
- package/dist/index.mjs +252 -14
- package/package.json +5 -4
package/dist/index.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
import { v4 } from "uuid";
|
|
4
4
|
import { WebSocket } from "ws";
|
|
5
5
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
6
|
+
import { ApiClient as ApiClient$1, createRouter } from "@jsnw/api-client";
|
|
6
7
|
//#region src/request-signer.ts
|
|
7
8
|
var RequestSigner = class {
|
|
8
9
|
privkey;
|
|
@@ -77,8 +78,39 @@ const primitives$fixedPointSchema = z.string().regex(/^\d{1,14}\.\d{2,8}$/);
|
|
|
77
78
|
const primitives$orderSideSchema = z.enum(["yes", "no"]);
|
|
78
79
|
const primitives$bookSideSchema = z.enum(["bid", "ask"]);
|
|
79
80
|
const primitives$orderActionSchema = z.enum(["buy", "sell"]);
|
|
81
|
+
const primitives$rateLimitBucketMetaSchema = z.object({
|
|
82
|
+
refill_rate: z.number(),
|
|
83
|
+
bucket_capacity: z.number()
|
|
84
|
+
});
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/schemas/http.ts
|
|
87
|
+
const http$errorMessageSchema = z.object({
|
|
88
|
+
code: z.number(),
|
|
89
|
+
message: z.string().optional(),
|
|
90
|
+
details: z.any().optional(),
|
|
91
|
+
service: z.any().optional()
|
|
92
|
+
});
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region src/schemas/account.ts
|
|
95
|
+
const account$accountTierSchema = z.enum([
|
|
96
|
+
"basic",
|
|
97
|
+
"advanced",
|
|
98
|
+
"expert",
|
|
99
|
+
"premier",
|
|
100
|
+
"paragon",
|
|
101
|
+
"prime",
|
|
102
|
+
"prestige"
|
|
103
|
+
]);
|
|
104
|
+
const account$subaccountSchema = z.number().min(0).max(63).default(0);
|
|
105
|
+
const account$accountGrantSchema = z.object({
|
|
106
|
+
exchange_instance: z.enum(["event_contract", "margined"]),
|
|
107
|
+
level: account$accountTierSchema,
|
|
108
|
+
source: z.enum(["volume", "manual"]),
|
|
109
|
+
expires_ts: z.number().nullable().default(null)
|
|
110
|
+
});
|
|
80
111
|
//#endregion
|
|
81
112
|
//#region src/schemas/orders.ts
|
|
113
|
+
const orders$clientOrderIdSchema = z.string().nullable().optional();
|
|
82
114
|
const orders$orderStatusSchema = z.enum([
|
|
83
115
|
"resting",
|
|
84
116
|
"canceled",
|
|
@@ -86,17 +118,22 @@ const orders$orderStatusSchema = z.enum([
|
|
|
86
118
|
]);
|
|
87
119
|
const orders$orderTypeSchema = z.enum(["limit", "market"]);
|
|
88
120
|
const orders$selfTradePreventionTypeSchema = z.enum(["taker_at_cross", "maker"]);
|
|
121
|
+
const orders$timeInForceSchema = z.enum([
|
|
122
|
+
"fill_or_kill",
|
|
123
|
+
"good_till_canceled",
|
|
124
|
+
"immediate_or_cancel"
|
|
125
|
+
]);
|
|
89
126
|
const orders$orderDetailedSchema = z.object({
|
|
90
127
|
order_id: z.uuid(),
|
|
91
128
|
user_id: z.uuid(),
|
|
92
|
-
|
|
93
|
-
order_group_id: z.
|
|
129
|
+
client_order_id: orders$clientOrderIdSchema,
|
|
130
|
+
order_group_id: z.string().nullable().optional(),
|
|
131
|
+
subaccount_number: account$subaccountSchema,
|
|
94
132
|
exchange_index: z.number().min(0).default(0),
|
|
95
|
-
client_order_id: z.string(),
|
|
96
133
|
ticker: z.string(),
|
|
134
|
+
type: orders$orderTypeSchema,
|
|
97
135
|
outcome_side: primitives$orderSideSchema,
|
|
98
136
|
book_side: primitives$bookSideSchema,
|
|
99
|
-
type: orders$orderTypeSchema,
|
|
100
137
|
status: orders$orderStatusSchema,
|
|
101
138
|
yes_price_dollars: primitives$fixedPointSchema,
|
|
102
139
|
no_price_dollars: primitives$fixedPointSchema,
|
|
@@ -107,11 +144,11 @@ const orders$orderDetailedSchema = z.object({
|
|
|
107
144
|
maker_fill_cost_dollars: primitives$fixedPointSchema,
|
|
108
145
|
taker_fees_dollars: primitives$fixedPointSchema,
|
|
109
146
|
maker_fees_dollars: primitives$fixedPointSchema,
|
|
110
|
-
self_trade_prevention_type: orders$selfTradePreventionTypeSchema
|
|
147
|
+
self_trade_prevention_type: orders$selfTradePreventionTypeSchema,
|
|
111
148
|
cancel_order_on_pause: z.boolean(),
|
|
112
149
|
created_time: z.iso.datetime(),
|
|
113
|
-
|
|
114
|
-
|
|
150
|
+
last_update_time: z.iso.datetime().nullable().optional(),
|
|
151
|
+
expiration_time: z.iso.datetime().nullable().optional()
|
|
115
152
|
});
|
|
116
153
|
const orders$orderWsSchema = orders$orderDetailedSchema.omit({
|
|
117
154
|
exchange_index: true,
|
|
@@ -124,12 +161,32 @@ const orders$orderWsSchema = orders$orderDetailedSchema.omit({
|
|
|
124
161
|
last_updated_ts_ms: z.number().positive().optional(),
|
|
125
162
|
expiration_ts_ms: z.number().positive().optional()
|
|
126
163
|
});
|
|
164
|
+
const orders$createOrderDtoSchema = z.object({
|
|
165
|
+
client_order_id: z.string().optional(),
|
|
166
|
+
order_group_id: z.string().optional(),
|
|
167
|
+
exchange_index: z.number().min(0).default(0),
|
|
168
|
+
ticker: z.string(),
|
|
169
|
+
side: primitives$bookSideSchema,
|
|
170
|
+
count: primitives$fixedPointSchema,
|
|
171
|
+
subaccount: account$subaccountSchema,
|
|
172
|
+
price: primitives$fixedPointSchema,
|
|
173
|
+
post_only: z.boolean().default(false),
|
|
174
|
+
reduce_only: z.boolean().default(false),
|
|
175
|
+
cancel_order_on_pause: z.boolean(),
|
|
176
|
+
self_trade_prevention_type: orders$selfTradePreventionTypeSchema,
|
|
177
|
+
time_in_force: orders$timeInForceSchema,
|
|
178
|
+
expiration_time: z.number().optional()
|
|
179
|
+
});
|
|
127
180
|
//#endregion
|
|
128
181
|
//#region src/consts.ts
|
|
129
182
|
const KALSHI_WS_URL = {
|
|
130
183
|
"development": "wss://external-api-ws.demo.kalshi.co",
|
|
131
184
|
"production": "wss://external-api-ws.kalshi.com"
|
|
132
185
|
};
|
|
186
|
+
const KALSHI_API_URL = {
|
|
187
|
+
"development": "https://external-api.demo.kalshi.co",
|
|
188
|
+
"production": "https://external-api.kalshi.com"
|
|
189
|
+
};
|
|
133
190
|
//#endregion
|
|
134
191
|
//#region src/typed-emitter.ts
|
|
135
192
|
var TypedEmitter = class {
|
|
@@ -501,6 +558,8 @@ var WsKalshiError = class extends Error {
|
|
|
501
558
|
this.code = code;
|
|
502
559
|
}
|
|
503
560
|
};
|
|
561
|
+
var WsClosedError = class extends Error {};
|
|
562
|
+
var WsClosedByUserError = class extends Error {};
|
|
504
563
|
//#endregion
|
|
505
564
|
//#region src/ws/ws-client.ts
|
|
506
565
|
var WsClient = class extends TypedEmitter {
|
|
@@ -545,9 +604,39 @@ var WsClient = class extends TypedEmitter {
|
|
|
545
604
|
this.ws.on("reconnecting", this.onReconnecting);
|
|
546
605
|
this.ws.on("close", this.onClose);
|
|
547
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* @return {Promise<void>}
|
|
609
|
+
*/
|
|
610
|
+
connect() {
|
|
611
|
+
return this.ws.open();
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* @return {Promise<void>}
|
|
615
|
+
*/
|
|
616
|
+
async subscribe(options) {
|
|
617
|
+
const { channel, timeoutMs, ...rest } = options;
|
|
618
|
+
const messageId = ++this.lastMessageId;
|
|
619
|
+
const payload = {
|
|
620
|
+
id: messageId,
|
|
621
|
+
cmd: "subscribe",
|
|
622
|
+
params: {
|
|
623
|
+
channels: [channel],
|
|
624
|
+
...rest
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
const promise = this.subscribeAwaiters.add(messageId, timeoutMs ?? 2e3);
|
|
628
|
+
await this.ws.send(JSON.stringify(payload));
|
|
629
|
+
return promise;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* @return {Promise<void>}
|
|
633
|
+
*/
|
|
634
|
+
close() {
|
|
635
|
+
this.subscribeAwaiters.clear(new WsClosedByUserError());
|
|
636
|
+
return this.ws.close();
|
|
637
|
+
}
|
|
548
638
|
onReady = async (afterReconnect) => {
|
|
549
|
-
this.
|
|
550
|
-
this.emit("ready");
|
|
639
|
+
this.emit("ready", afterReconnect);
|
|
551
640
|
};
|
|
552
641
|
/**
|
|
553
642
|
* @param {WebSocket.RawData} data
|
|
@@ -581,21 +670,19 @@ var WsClient = class extends TypedEmitter {
|
|
|
581
670
|
* @param {number} attempt
|
|
582
671
|
*/
|
|
583
672
|
onReconnecting = (attempt) => {
|
|
584
|
-
this.log("debug", "reconnecting", { attempt });
|
|
585
673
|
this.emit("reconnect", attempt);
|
|
586
674
|
};
|
|
587
675
|
/**
|
|
588
676
|
* @param {Error} err
|
|
589
677
|
*/
|
|
590
678
|
onError = (err) => {
|
|
591
|
-
this.
|
|
679
|
+
this.emit("ws_error", err);
|
|
592
680
|
};
|
|
593
681
|
/**
|
|
594
682
|
*/
|
|
595
683
|
onClose = () => {
|
|
596
|
-
this.log("debug", "WebSocket connection closed");
|
|
597
684
|
this.emit("close");
|
|
598
|
-
this.subscribeAwaiters.clear();
|
|
685
|
+
this.subscribeAwaiters.clear(new WsClosedError());
|
|
599
686
|
};
|
|
600
687
|
/**
|
|
601
688
|
* @param {WsAnyMessage} msg
|
|
@@ -649,4 +736,155 @@ const WS_KALSHI_SERVER_ERRORS = [
|
|
|
649
736
|
WS_KALSHI_ERRORS.COMMAND_TIMEOUT
|
|
650
737
|
];
|
|
651
738
|
//#endregion
|
|
652
|
-
|
|
739
|
+
//#region src/api/metadata.ts
|
|
740
|
+
const METADATA = { NO_AUTH: Symbol("no-auth") };
|
|
741
|
+
//#endregion
|
|
742
|
+
//#region src/api/router/index.ts
|
|
743
|
+
const apiRouter = createRouter({
|
|
744
|
+
exchange: createRouter({
|
|
745
|
+
getStatus: {
|
|
746
|
+
method: "get",
|
|
747
|
+
path: "/status",
|
|
748
|
+
responses: { 200: z.object({
|
|
749
|
+
exchange_active: z.boolean(),
|
|
750
|
+
trading_active: z.boolean(),
|
|
751
|
+
exchange_estimated_resume_time: z.iso.datetime().nullable().optional()
|
|
752
|
+
}) }
|
|
753
|
+
},
|
|
754
|
+
getUserDataTimestamp: {
|
|
755
|
+
method: "get",
|
|
756
|
+
path: "/user_data_timestamp",
|
|
757
|
+
responses: { 200: z.object({ as_of_time: z.iso.datetime() }) }
|
|
758
|
+
}
|
|
759
|
+
}, {
|
|
760
|
+
path: "exchange",
|
|
761
|
+
metadata: { [METADATA.NO_AUTH]: true }
|
|
762
|
+
}),
|
|
763
|
+
account: createRouter({
|
|
764
|
+
getLimits: {
|
|
765
|
+
method: "get",
|
|
766
|
+
path: "/limits",
|
|
767
|
+
responses: { 200: z.object({
|
|
768
|
+
usage_tier: account$accountTierSchema,
|
|
769
|
+
read: primitives$rateLimitBucketMetaSchema,
|
|
770
|
+
write: primitives$rateLimitBucketMetaSchema,
|
|
771
|
+
grants: z.array(account$accountGrantSchema)
|
|
772
|
+
}) }
|
|
773
|
+
},
|
|
774
|
+
listNonDefaultEndpointCosts: {
|
|
775
|
+
method: "get",
|
|
776
|
+
path: "/endpoint_costs",
|
|
777
|
+
responses: { 200: z.object({
|
|
778
|
+
default_cost: z.number().min(0),
|
|
779
|
+
endpoint_costs: z.array(z.object({
|
|
780
|
+
method: z.string(),
|
|
781
|
+
path: z.string(),
|
|
782
|
+
cost: z.number().min(0)
|
|
783
|
+
}))
|
|
784
|
+
}) },
|
|
785
|
+
metadata: { [METADATA.NO_AUTH]: true }
|
|
786
|
+
}
|
|
787
|
+
}, { path: "/account" }),
|
|
788
|
+
orders: createRouter({
|
|
789
|
+
getOrder: {
|
|
790
|
+
method: "get",
|
|
791
|
+
path: "/orders/:order_id",
|
|
792
|
+
params: z.object({ order_id: z.uuid() }),
|
|
793
|
+
responses: { 200: z.object({ order: orders$orderDetailedSchema }) }
|
|
794
|
+
},
|
|
795
|
+
createOrder: {
|
|
796
|
+
method: "post",
|
|
797
|
+
path: "/events/orders",
|
|
798
|
+
body: orders$createOrderDtoSchema,
|
|
799
|
+
responses: { 201: z.object({
|
|
800
|
+
order_id: z.uuid(),
|
|
801
|
+
client_order_id: orders$clientOrderIdSchema,
|
|
802
|
+
fill_count: primitives$fixedPointSchema,
|
|
803
|
+
remaining_count: primitives$fixedPointSchema,
|
|
804
|
+
average_fill_price: primitives$fixedPointSchema.nullable().optional(),
|
|
805
|
+
average_fee_paid: primitives$fixedPointSchema.nullable().optional(),
|
|
806
|
+
ts_ms: z.number().min(0)
|
|
807
|
+
}) }
|
|
808
|
+
},
|
|
809
|
+
cancelOrderV1: {
|
|
810
|
+
method: "delete",
|
|
811
|
+
path: "/orders/:order_id",
|
|
812
|
+
params: z.object({ order_id: z.uuid() }),
|
|
813
|
+
query: z.object({
|
|
814
|
+
subaccount: z.number().min(0).max(63).default(0),
|
|
815
|
+
exchange_index: z.number().min(0).default(0)
|
|
816
|
+
}).prefault({}),
|
|
817
|
+
responses: { 200: z.object({
|
|
818
|
+
order: orders$orderDetailedSchema,
|
|
819
|
+
reduced_by_fp: primitives$fixedPointSchema
|
|
820
|
+
}) }
|
|
821
|
+
},
|
|
822
|
+
cancelOrderV2: {
|
|
823
|
+
method: "delete",
|
|
824
|
+
path: "/events/orders/:order_id",
|
|
825
|
+
params: z.object({ order_id: z.uuid() }),
|
|
826
|
+
query: z.object({
|
|
827
|
+
subaccount: z.number().min(0).max(63).default(0),
|
|
828
|
+
exchange_index: z.number().min(0).default(0)
|
|
829
|
+
}).prefault({}),
|
|
830
|
+
responses: { 200: z.object({
|
|
831
|
+
order_id: z.uuid(),
|
|
832
|
+
client_order_id: orders$clientOrderIdSchema,
|
|
833
|
+
reduced_by: primitives$fixedPointSchema,
|
|
834
|
+
ts_ms: z.number().min(0)
|
|
835
|
+
}) }
|
|
836
|
+
},
|
|
837
|
+
getOrderQueuePosition: {
|
|
838
|
+
method: "get",
|
|
839
|
+
path: "/orders/:order_id/queue_position",
|
|
840
|
+
params: z.object({ order_id: z.uuid() }),
|
|
841
|
+
responses: { 200: z.object({ queue_position_fp: primitives$fixedPointSchema }) }
|
|
842
|
+
}
|
|
843
|
+
}, { path: "/portfolio" })
|
|
844
|
+
}, { path: "/trade-api/v2" });
|
|
845
|
+
//#endregion
|
|
846
|
+
//#region src/api/client.ts
|
|
847
|
+
var ApiClient = class extends ApiClient$1 {
|
|
848
|
+
/**
|
|
849
|
+
* @param {ApiClientConfig} config
|
|
850
|
+
*/
|
|
851
|
+
constructor(config) {
|
|
852
|
+
super(apiRouter, {
|
|
853
|
+
...config,
|
|
854
|
+
baseURL: KALSHI_API_URL[config.environment ?? "development"],
|
|
855
|
+
qsArrayFormat: "brackets",
|
|
856
|
+
contentType: "application/json"
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* @template {Route} TRoute
|
|
861
|
+
* @param {TRoute} route
|
|
862
|
+
* @param {ApiRequestParams<TRoute>} params
|
|
863
|
+
* @param {ApiCallOptions} options
|
|
864
|
+
* @return {Promise<ApiResponse<TRoute>>}
|
|
865
|
+
*/
|
|
866
|
+
/**
|
|
867
|
+
* @param {"force"} force
|
|
868
|
+
* @return {Promise<void>}
|
|
869
|
+
* @private
|
|
870
|
+
*/
|
|
871
|
+
/**
|
|
872
|
+
* @param {ApiRawRequest} req
|
|
873
|
+
* @return {ApiRawRequest}
|
|
874
|
+
* @protected
|
|
875
|
+
*/
|
|
876
|
+
onBeforeRequest(req) {
|
|
877
|
+
if (req.route.metadata?.[METADATA.NO_AUTH] && req.route.metadata[METADATA.NO_AUTH] === true) return req;
|
|
878
|
+
const ts = Date.now();
|
|
879
|
+
req.headers["kalshi-access-key"] = this.config.credentialsProvider.getAccessKey();
|
|
880
|
+
req.headers["kalshi-access-timestamp"] = ts.toString();
|
|
881
|
+
req.headers["kalshi-access-signature"] = this.config.credentialsProvider.getSignature({
|
|
882
|
+
httpMethod: req.route.method,
|
|
883
|
+
path: req.path,
|
|
884
|
+
timestamp: ts
|
|
885
|
+
});
|
|
886
|
+
return req;
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
//#endregion
|
|
890
|
+
export { ApiClient, InMemoryCredentialsProvider, RequestSigner, WS_KALSHI_ERRORS, WS_KALSHI_SERVER_ERRORS, WsClient, WsClosedByUserError, WsClosedError, WsKalshiError, account$accountGrantSchema, account$accountTierSchema, account$subaccountSchema, http$errorMessageSchema, orders$clientOrderIdSchema, orders$createOrderDtoSchema, orders$orderDetailedSchema, orders$orderStatusSchema, orders$orderTypeSchema, orders$orderWsSchema, orders$selfTradePreventionTypeSchema, orders$timeInForceSchema, primitives$bookSideSchema, primitives$fixedPointSchema, primitives$orderActionSchema, primitives$orderSideSchema, primitives$rateLimitBucketMetaSchema, wsAnyMessageSchema, wsErrorMessageSchema, wsOkMessageSchema, wsSubscribedMessageSchema, wsUserOrderMessageSchema };
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.0
|
|
7
|
+
"version": "0.2.0",
|
|
8
8
|
"engines": {
|
|
9
9
|
"node": ">=22"
|
|
10
10
|
},
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
"dist"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
+
"@jsnw/api-client": "^0.7.1",
|
|
28
|
+
"@ts-rest/core": "3.53.0-rc.1",
|
|
27
29
|
"uuid": "^14.0.0",
|
|
28
30
|
"ws": "^8.21.0",
|
|
29
31
|
"zod": "^4.4.3"
|
|
@@ -32,12 +34,11 @@
|
|
|
32
34
|
"bufferutil": "^4.1.0"
|
|
33
35
|
},
|
|
34
36
|
"devDependencies": {
|
|
35
|
-
"@types/node": "^24.
|
|
37
|
+
"@types/node": "^24.13.1",
|
|
36
38
|
"@types/ws": "^8.18.1",
|
|
37
39
|
"nodemon": "^3.1.14",
|
|
38
|
-
"rimraf": "^6.1.3",
|
|
39
40
|
"ts-node": "^10.9.2",
|
|
40
|
-
"tsdown": "^0.22.
|
|
41
|
+
"tsdown": "^0.22.2",
|
|
41
42
|
"typescript": "^5.9.3"
|
|
42
43
|
},
|
|
43
44
|
"scripts": {
|