@lynx-crypto/kraken-api 1.0.0 → 1.1.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/README.md +224 -117
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +333 -1
- package/dist/index.d.ts +333 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +23 -6
package/README.md
CHANGED
|
@@ -9,12 +9,15 @@
|
|
|
9
9
|
[](./LICENSE.md)
|
|
10
10
|
|
|
11
11
|
A modern, strongly-typed TypeScript client for the **Kraken Spot API**, providing both **REST** and **WebSocket v2** access in a single package.
|
|
12
|
+
|
|
12
13
|
- **REST API** (public + private endpoints)
|
|
13
14
|
- **WebSocket v2** (public market-data + authenticated user-data/trading)
|
|
15
|
+
- **Bulk historical CSV datasets** (OHLCVT + Trades) via Kraken’s official Google Drive downloads
|
|
14
16
|
|
|
15
17
|
See [Kraken Official Documentation](https://docs.kraken.com/api/docs/category/guides)
|
|
16
18
|
|
|
17
19
|
## Important
|
|
20
|
+
|
|
18
21
|
- This package is currently **SPOT only**. It does **not** implement Kraken Futures.
|
|
19
22
|
- Unofficial project. Not affiliated with Kraken.
|
|
20
23
|
|
|
@@ -23,6 +26,7 @@ See [Kraken Official Documentation](https://docs.kraken.com/api/docs/category/gu
|
|
|
23
26
|
## Features
|
|
24
27
|
|
|
25
28
|
### Spot REST API
|
|
29
|
+
|
|
26
30
|
- Public market data (time, assets, pairs, ticker, OHLC, order book, trades, spreads)
|
|
27
31
|
- Private account data (balances, orders, trades, ledgers, export reports)
|
|
28
32
|
- Trading endpoints (add/amend/edit/cancel orders, batch operations)
|
|
@@ -32,6 +36,7 @@ See [Kraken Official Documentation](https://docs.kraken.com/api/docs/category/gu
|
|
|
32
36
|
- Transparency endpoints (pre-trade / post-trade data)
|
|
33
37
|
|
|
34
38
|
### Spot WebSocket v2 API
|
|
39
|
+
|
|
35
40
|
- Public streams (ticker, trades, book, OHLC, instruments)
|
|
36
41
|
- Private user streams (balances, executions)
|
|
37
42
|
- Private trading RPC methods
|
|
@@ -39,21 +44,40 @@ See [Kraken Official Documentation](https://docs.kraken.com/api/docs/category/gu
|
|
|
39
44
|
- Optional auto-reconnect with backoff
|
|
40
45
|
- Works in Node.js (via `ws`) or browser environments
|
|
41
46
|
|
|
47
|
+
### Bulk historical CSV datasets (OHLCVT + Trades)
|
|
48
|
+
|
|
49
|
+
Support for Kraken’s downloadable historical datasets:
|
|
50
|
+
|
|
51
|
+
- OHLCVT (open/high/low/close/volume/trades)
|
|
52
|
+
- Trades (time and sales)
|
|
53
|
+
|
|
54
|
+
Data source (Kraken Support):
|
|
55
|
+
|
|
56
|
+
- https://support.kraken.com/sections/360009899492-csv-data
|
|
57
|
+
- https://support.kraken.com/articles/360047124832-downloadable-historical-ohlcvt-open-high-low-close-volume-trades-data
|
|
58
|
+
- https://support.kraken.com/articles/360047543791-downloadable-historical-market-data-time-and-sales-
|
|
59
|
+
|
|
60
|
+
Bulk workflow:
|
|
61
|
+
|
|
62
|
+
- Download ZIPs (seamless via Drive API, or manually)
|
|
63
|
+
- Extract ZIPs into a stable on-disk layout
|
|
64
|
+
- Query extracted CSVs (streaming)
|
|
65
|
+
|
|
42
66
|
---
|
|
43
67
|
|
|
44
68
|
## Installation
|
|
45
69
|
|
|
46
70
|
Using Yarn:
|
|
47
71
|
|
|
48
|
-
|
|
72
|
+
'''sh
|
|
49
73
|
yarn add @lynx-crypto/kraken-api
|
|
50
|
-
|
|
74
|
+
'''
|
|
51
75
|
|
|
52
76
|
Using npm:
|
|
53
77
|
|
|
54
|
-
|
|
78
|
+
'''sh
|
|
55
79
|
npm install @lynx-crypto/kraken-api
|
|
56
|
-
|
|
80
|
+
'''
|
|
57
81
|
|
|
58
82
|
---
|
|
59
83
|
|
|
@@ -65,24 +89,39 @@ npm install @lynx-crypto/kraken-api
|
|
|
65
89
|
- Kraken API key and secret
|
|
66
90
|
- Appropriate permissions enabled in Kraken
|
|
67
91
|
- “WebSocket interface” enabled for private WS usage
|
|
92
|
+
- For bulk downloads (optional):
|
|
93
|
+
- A Google Drive API key for seamless downloads (manual ZIP placement is supported)
|
|
68
94
|
|
|
69
95
|
---
|
|
70
96
|
|
|
71
97
|
## Environment Variables (for private usage)
|
|
72
98
|
|
|
73
|
-
|
|
99
|
+
'''bash
|
|
74
100
|
KRAKEN_API_KEY="your_api_key"
|
|
75
101
|
KRAKEN_API_SECRET="your_api_secret"
|
|
76
|
-
|
|
102
|
+
'''
|
|
103
|
+
|
|
104
|
+
## Environment Variables (optional, for bulk downloads)
|
|
105
|
+
|
|
106
|
+
'''bash
|
|
107
|
+
|
|
108
|
+
# If set, bulk downloads can be performed via the Google Drive API.
|
|
109
|
+
|
|
110
|
+
# If not set, ZIPs can be downloaded manually and placed into the expected folders.
|
|
111
|
+
|
|
112
|
+
LYNX_CRYPTO_KRAKEN_API_GOOGLE_DRIVE_API_KEY="your_google_drive_api_key"
|
|
113
|
+
'''
|
|
77
114
|
|
|
78
115
|
---
|
|
79
116
|
|
|
80
117
|
## Package Exports
|
|
81
118
|
|
|
82
119
|
### REST
|
|
120
|
+
|
|
83
121
|
- `KrakenSpotRestClient`
|
|
84
122
|
|
|
85
123
|
Sub-APIs available on the client:
|
|
124
|
+
|
|
86
125
|
- `marketData`
|
|
87
126
|
- `accountData`
|
|
88
127
|
- `trading`
|
|
@@ -92,68 +131,75 @@ Sub-APIs available on the client:
|
|
|
92
131
|
- `transparency`
|
|
93
132
|
|
|
94
133
|
### WebSocket
|
|
134
|
+
|
|
95
135
|
- `KrakenSpotWebsocketV2Client`
|
|
96
136
|
- `KrakenWebsocketBase` (advanced / custom integrations)
|
|
97
137
|
|
|
98
138
|
Typed channel namespaces:
|
|
139
|
+
|
|
99
140
|
- `admin`
|
|
100
141
|
- `marketData`
|
|
101
142
|
- `userData`
|
|
102
143
|
- `userTrading`
|
|
103
144
|
|
|
145
|
+
### Bulk
|
|
146
|
+
|
|
147
|
+
- `KrakenBulkClient`
|
|
148
|
+
|
|
104
149
|
All public request/response and stream payloads are exported as TypeScript types.
|
|
105
150
|
|
|
106
151
|
---
|
|
152
|
+
|
|
107
153
|
## REST Usage
|
|
108
154
|
|
|
109
155
|
### Public REST example (no authentication)
|
|
110
156
|
|
|
111
|
-
|
|
157
|
+
'''ts
|
|
112
158
|
import { KrakenSpotRestClient } from '@lynx-crypto/kraken-api';
|
|
113
159
|
|
|
114
160
|
async function main() {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
161
|
+
const kraken = new KrakenSpotRestClient({
|
|
162
|
+
userAgent: 'example-app/1.0.0',
|
|
163
|
+
});
|
|
118
164
|
|
|
119
|
-
|
|
120
|
-
|
|
165
|
+
const time = await kraken.marketData.getServerTime();
|
|
166
|
+
console.log('Kraken time:', time.rfc1123);
|
|
121
167
|
}
|
|
122
168
|
|
|
123
169
|
main().catch((err) => {
|
|
124
|
-
|
|
125
|
-
|
|
170
|
+
console.error(err);
|
|
171
|
+
process.exitCode = 1;
|
|
126
172
|
});
|
|
127
|
-
|
|
173
|
+
'''
|
|
128
174
|
|
|
129
175
|
### Private REST example (authenticated)
|
|
130
176
|
|
|
131
|
-
|
|
177
|
+
'''ts
|
|
132
178
|
import 'dotenv/config';
|
|
133
179
|
import { KrakenSpotRestClient } from '@lynx-crypto/kraken-api';
|
|
134
180
|
|
|
135
181
|
function requireEnv(name: string): string {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
182
|
+
const v = process.env[name];
|
|
183
|
+
if (!v) throw new Error(`Missing env var: ${name}`);
|
|
184
|
+
return v;
|
|
139
185
|
}
|
|
140
186
|
|
|
141
187
|
async function main() {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
188
|
+
const kraken = new KrakenSpotRestClient({
|
|
189
|
+
userAgent: 'example-app/1.0.0',
|
|
190
|
+
apiKey: requireEnv('KRAKEN_API_KEY'),
|
|
191
|
+
apiSecret: requireEnv('KRAKEN_API_SECRET'),
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const balances = await kraken.accountData.getAccountBalance();
|
|
195
|
+
console.log('Asset count:', Object.keys(balances).length);
|
|
150
196
|
}
|
|
151
197
|
|
|
152
198
|
main().catch((err) => {
|
|
153
|
-
|
|
154
|
-
|
|
199
|
+
console.error(err);
|
|
200
|
+
process.exitCode = 1;
|
|
155
201
|
});
|
|
156
|
-
|
|
202
|
+
'''
|
|
157
203
|
|
|
158
204
|
---
|
|
159
205
|
|
|
@@ -161,95 +207,145 @@ main().catch((err) => {
|
|
|
161
207
|
|
|
162
208
|
### Public WebSocket (market data)
|
|
163
209
|
|
|
164
|
-
|
|
210
|
+
'''ts
|
|
165
211
|
import { KrakenSpotWebsocketV2Client } from '@lynx-crypto/kraken-api';
|
|
166
212
|
|
|
167
213
|
async function main() {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
214
|
+
const wsClient = new KrakenSpotWebsocketV2Client({
|
|
215
|
+
autoReconnect: false,
|
|
216
|
+
});
|
|
171
217
|
|
|
172
|
-
|
|
218
|
+
await wsClient.publicConnection.connect();
|
|
173
219
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
220
|
+
const ack = await wsClient.marketData.subscribeTrade(
|
|
221
|
+
{ symbol: ['BTC/USD'], snapshot: true },
|
|
222
|
+
{ reqId: 1 },
|
|
223
|
+
);
|
|
178
224
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
225
|
+
if (!ack.success) {
|
|
226
|
+
throw new Error(`Subscribe failed: ${ack.error}`);
|
|
227
|
+
}
|
|
182
228
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
229
|
+
const unsubscribe = wsClient.publicConnection.addMessageHandler((msg) => {
|
|
230
|
+
console.log(JSON.stringify(msg));
|
|
231
|
+
});
|
|
186
232
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
233
|
+
setTimeout(() => {
|
|
234
|
+
unsubscribe();
|
|
235
|
+
wsClient.publicConnection.close(1000, 'example done');
|
|
236
|
+
}, 20_000);
|
|
191
237
|
}
|
|
192
238
|
|
|
193
239
|
main().catch((err) => {
|
|
194
|
-
|
|
195
|
-
|
|
240
|
+
console.error(err);
|
|
241
|
+
process.exitCode = 1;
|
|
196
242
|
});
|
|
197
|
-
|
|
243
|
+
'''
|
|
198
244
|
|
|
199
245
|
### Private WebSocket (balances / executions)
|
|
200
246
|
|
|
201
247
|
Authenticated WebSocket usage requires a token obtained via REST.
|
|
202
248
|
|
|
203
|
-
|
|
249
|
+
'''ts
|
|
204
250
|
import 'dotenv/config';
|
|
205
251
|
import {
|
|
206
|
-
|
|
207
|
-
|
|
252
|
+
KrakenSpotRestClient,
|
|
253
|
+
KrakenSpotWebsocketV2Client,
|
|
208
254
|
} from '@lynx-crypto/kraken-api';
|
|
209
255
|
|
|
210
256
|
function requireEnv(name: string): string {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
257
|
+
const v = process.env[name];
|
|
258
|
+
if (!v) throw new Error(`Missing env var: ${name}`);
|
|
259
|
+
return v;
|
|
214
260
|
}
|
|
215
261
|
|
|
216
262
|
async function main() {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
263
|
+
const rest = new KrakenSpotRestClient({
|
|
264
|
+
userAgent: 'example-app/1.0.0',
|
|
265
|
+
apiKey: requireEnv('KRAKEN_API_KEY'),
|
|
266
|
+
apiSecret: requireEnv('KRAKEN_API_SECRET'),
|
|
267
|
+
});
|
|
222
268
|
|
|
223
|
-
|
|
269
|
+
const { token } = await rest.trading.getWebSocketsToken();
|
|
224
270
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
271
|
+
const wsClient = new KrakenSpotWebsocketV2Client({
|
|
272
|
+
authToken: token,
|
|
273
|
+
autoReconnect: false,
|
|
274
|
+
});
|
|
229
275
|
|
|
230
|
-
|
|
276
|
+
await wsClient.privateConnection.connect();
|
|
231
277
|
|
|
232
|
-
|
|
278
|
+
const ack = await wsClient.userData.subscribeBalances({}, { reqId: 10 });
|
|
233
279
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
280
|
+
if (!ack.success) {
|
|
281
|
+
throw new Error(`Subscribe failed: ${ack.error}`);
|
|
282
|
+
}
|
|
237
283
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
284
|
+
const off = wsClient.privateConnection.addMessageHandler((msg) => {
|
|
285
|
+
console.log(JSON.stringify(msg));
|
|
286
|
+
});
|
|
241
287
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
288
|
+
setTimeout(() => {
|
|
289
|
+
off();
|
|
290
|
+
wsClient.privateConnection.close(1000, 'example done');
|
|
291
|
+
}, 30_000);
|
|
246
292
|
}
|
|
247
293
|
|
|
248
294
|
main().catch((err) => {
|
|
249
|
-
|
|
250
|
-
|
|
295
|
+
console.error(err);
|
|
296
|
+
process.exitCode = 1;
|
|
251
297
|
});
|
|
252
|
-
|
|
298
|
+
'''
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Bulk historical data (OHLCVT + Trades)
|
|
303
|
+
|
|
304
|
+
Bulk data is managed by `KrakenBulkClient`. It supports:
|
|
305
|
+
|
|
306
|
+
- Downloading complete and quarterly ZIPs
|
|
307
|
+
- Extracting ZIPs into a stable directory layout
|
|
308
|
+
- Listing available pairs (and OHLC intervals)
|
|
309
|
+
- Streaming query results from extracted CSVs
|
|
310
|
+
|
|
311
|
+
### Storage layout
|
|
312
|
+
|
|
313
|
+
A `storageDir` is provided when constructing the client (examples use `.bulk-data`). The library stores ZIPs and extracted CSVs under dataset-specific folders:
|
|
314
|
+
|
|
315
|
+
'''txt
|
|
316
|
+
<storageDir>/
|
|
317
|
+
ohlcvt/
|
|
318
|
+
zips/
|
|
319
|
+
complete/complete.zip
|
|
320
|
+
quarterly/<YYYYQn>.zip
|
|
321
|
+
extracted/
|
|
322
|
+
complete/
|
|
323
|
+
quarterly/<YYYYQn>/
|
|
324
|
+
trades/
|
|
325
|
+
zips/
|
|
326
|
+
complete/complete.zip
|
|
327
|
+
quarterly/<YYYYQn>.zip
|
|
328
|
+
extracted/
|
|
329
|
+
complete/
|
|
330
|
+
quarterly/<YYYYQn>/
|
|
331
|
+
'''
|
|
332
|
+
|
|
333
|
+
Recommended:
|
|
334
|
+
|
|
335
|
+
- Add the storage directory to `.gitignore` (e.g. `.bulk-data/`).
|
|
336
|
+
|
|
337
|
+
### Downloading ZIPs (two options)
|
|
338
|
+
|
|
339
|
+
1. Seamless downloads (Drive API)
|
|
340
|
+
|
|
341
|
+
- Set `LYNX_CRYPTO_KRAKEN_API_GOOGLE_DRIVE_API_KEY`.
|
|
342
|
+
- Run the bulk download examples (see below).
|
|
343
|
+
|
|
344
|
+
2. Manual ZIP placement (no API key)
|
|
345
|
+
|
|
346
|
+
- Download the ZIP(s) from Kraken’s support pages.
|
|
347
|
+
- Place the ZIP(s) into the expected `zips/complete/` or `zips/quarterly/` folders.
|
|
348
|
+
- Run extraction and query examples as usual (extraction/query do not require an API key).
|
|
253
349
|
|
|
254
350
|
---
|
|
255
351
|
|
|
@@ -266,27 +362,27 @@ This library supports Kraken-style rate limiting with optional automatic retries
|
|
|
266
362
|
|
|
267
363
|
Example:
|
|
268
364
|
|
|
269
|
-
|
|
365
|
+
'''ts
|
|
270
366
|
const kraken = new KrakenSpotRestClient({
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
367
|
+
apiKey: process.env.KRAKEN_API_KEY,
|
|
368
|
+
apiSecret: process.env.KRAKEN_API_SECRET,
|
|
369
|
+
rateLimit: {
|
|
370
|
+
mode: 'auto',
|
|
371
|
+
tier: 'starter',
|
|
372
|
+
retryOnRateLimit: true,
|
|
373
|
+
maxRetries: 5,
|
|
374
|
+
// restCostFn: (path) => (path.includes("Ledgers") ? 2 : 1),
|
|
375
|
+
},
|
|
280
376
|
});
|
|
281
|
-
|
|
377
|
+
'''
|
|
282
378
|
|
|
283
379
|
Disable built-in throttling:
|
|
284
380
|
|
|
285
|
-
|
|
381
|
+
'''ts
|
|
286
382
|
rateLimit: {
|
|
287
|
-
|
|
383
|
+
mode: 'off',
|
|
288
384
|
}
|
|
289
|
-
|
|
385
|
+
'''
|
|
290
386
|
|
|
291
387
|
### Redis rate limiting (multi-process / multi-container)
|
|
292
388
|
|
|
@@ -296,7 +392,7 @@ For cross-process coordination, you can use the Redis-backed token bucket limite
|
|
|
296
392
|
|
|
297
393
|
Example (you provide the Redis client + EVAL wrapper):
|
|
298
394
|
|
|
299
|
-
|
|
395
|
+
'''ts
|
|
300
396
|
import { KrakenSpotRestClient } from '@lynx-crypto/kraken-api';
|
|
301
397
|
import { RedisTokenBucketLimiter } from '@lynx-crypto/kraken-api/base/redisRateLimit';
|
|
302
398
|
|
|
@@ -304,26 +400,26 @@ import { RedisTokenBucketLimiter } from '@lynx-crypto/kraken-api/base/redisRateL
|
|
|
304
400
|
// - 0 means "proceed now"
|
|
305
401
|
// - >0 means "wait this many ms then retry"
|
|
306
402
|
const evalRedis = async (
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
403
|
+
key: string,
|
|
404
|
+
maxCounter: number,
|
|
405
|
+
decayPerSec: number,
|
|
406
|
+
cost: number,
|
|
407
|
+
ttlSeconds: number,
|
|
408
|
+
minWaitMs: number,
|
|
313
409
|
): Promise<number> => {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
410
|
+
// Example shape (pseudo-code):
|
|
411
|
+
// return await redis.eval(luaScript, { keys: [key], arguments: [maxCounter, decayPerSec, cost, ttlSeconds, minWaitMs] });
|
|
412
|
+
return 0;
|
|
317
413
|
};
|
|
318
414
|
|
|
319
415
|
const kraken = new KrakenSpotRestClient({
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
416
|
+
apiKey: process.env.KRAKEN_API_KEY,
|
|
417
|
+
apiSecret: process.env.KRAKEN_API_SECRET,
|
|
418
|
+
rateLimit: {
|
|
419
|
+
mode: 'auto',
|
|
420
|
+
tier: 'starter',
|
|
421
|
+
retryOnRateLimit: true,
|
|
422
|
+
maxRetries: 5,
|
|
327
423
|
|
|
328
424
|
// Cross-process limiter (Redis):
|
|
329
425
|
redis: {
|
|
@@ -336,9 +432,10 @@ const kraken = new KrakenSpotRestClient({
|
|
|
336
432
|
evalRedis,
|
|
337
433
|
}),
|
|
338
434
|
},
|
|
339
|
-
|
|
435
|
+
|
|
436
|
+
},
|
|
340
437
|
});
|
|
341
|
-
|
|
438
|
+
'''
|
|
342
439
|
|
|
343
440
|
Notes:
|
|
344
441
|
|
|
@@ -354,9 +451,19 @@ The repository includes a comprehensive [examples](./examples) directory:
|
|
|
354
451
|
- REST (public + safe private endpoints)
|
|
355
452
|
- WebSocket v2 public streams
|
|
356
453
|
- WebSocket v2 private streams (balances, executions)
|
|
357
|
-
-
|
|
454
|
+
- Bulk historical data (OHLCVT + Trades): download, extract, list pairs/intervals, query
|
|
455
|
+
|
|
456
|
+
Bulk examples live under:
|
|
457
|
+
|
|
458
|
+
- [./examples/bulk/ohlcvt](./examples/bulk/ohlcvt)
|
|
459
|
+
- [./examples/bulk/trades](./examples/bulk/trades)
|
|
460
|
+
|
|
461
|
+
A minimal bulk flow:
|
|
462
|
+
|
|
463
|
+
- Download (or manually place ZIPs) → Extract → Query
|
|
358
464
|
|
|
359
465
|
Examples are designed to be:
|
|
466
|
+
|
|
360
467
|
- Runnable
|
|
361
468
|
- Safe by default
|
|
362
469
|
- Self-contained
|