@lynx-crypto/kraken-api 1.1.0 → 1.1.1

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.
Files changed (2) hide show
  1. package/README.md +119 -120
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -69,15 +69,15 @@ Bulk workflow:
69
69
 
70
70
  Using Yarn:
71
71
 
72
- '''sh
72
+ ```sh
73
73
  yarn add @lynx-crypto/kraken-api
74
- '''
74
+ ```
75
75
 
76
76
  Using npm:
77
77
 
78
- '''sh
78
+ ```sh
79
79
  npm install @lynx-crypto/kraken-api
80
- '''
80
+ ```
81
81
 
82
82
  ---
83
83
 
@@ -96,21 +96,21 @@ npm install @lynx-crypto/kraken-api
96
96
 
97
97
  ## Environment Variables (for private usage)
98
98
 
99
- '''bash
99
+ ```bash
100
100
  KRAKEN_API_KEY="your_api_key"
101
101
  KRAKEN_API_SECRET="your_api_secret"
102
- '''
102
+ ```
103
103
 
104
104
  ## Environment Variables (optional, for bulk downloads)
105
105
 
106
- '''bash
106
+ ```bash
107
107
 
108
108
  # If set, bulk downloads can be performed via the Google Drive API.
109
109
 
110
110
  # If not set, ZIPs can be downloaded manually and placed into the expected folders.
111
111
 
112
112
  LYNX_CRYPTO_KRAKEN_API_GOOGLE_DRIVE_API_KEY="your_google_drive_api_key"
113
- '''
113
+ ```
114
114
 
115
115
  ---
116
116
 
@@ -154,52 +154,52 @@ All public request/response and stream payloads are exported as TypeScript types
154
154
 
155
155
  ### Public REST example (no authentication)
156
156
 
157
- '''ts
157
+ ```ts
158
158
  import { KrakenSpotRestClient } from '@lynx-crypto/kraken-api';
159
159
 
160
160
  async function main() {
161
- const kraken = new KrakenSpotRestClient({
162
- userAgent: 'example-app/1.0.0',
163
- });
161
+ const kraken = new KrakenSpotRestClient({
162
+ userAgent: 'example-app/1.0.0',
163
+ });
164
164
 
165
- const time = await kraken.marketData.getServerTime();
166
- console.log('Kraken time:', time.rfc1123);
165
+ const time = await kraken.marketData.getServerTime();
166
+ console.log('Kraken time:', time.rfc1123);
167
167
  }
168
168
 
169
169
  main().catch((err) => {
170
- console.error(err);
171
- process.exitCode = 1;
170
+ console.error(err);
171
+ process.exitCode = 1;
172
172
  });
173
- '''
173
+ ```
174
174
 
175
175
  ### Private REST example (authenticated)
176
176
 
177
- '''ts
177
+ ```ts
178
178
  import 'dotenv/config';
179
179
  import { KrakenSpotRestClient } from '@lynx-crypto/kraken-api';
180
180
 
181
181
  function requireEnv(name: string): string {
182
- const v = process.env[name];
183
- if (!v) throw new Error(`Missing env var: ${name}`);
184
- return v;
182
+ const v = process.env[name];
183
+ if (!v) throw new Error(`Missing env var: ${name}`);
184
+ return v;
185
185
  }
186
186
 
187
187
  async function main() {
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);
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);
196
196
  }
197
197
 
198
198
  main().catch((err) => {
199
- console.error(err);
200
- process.exitCode = 1;
199
+ console.error(err);
200
+ process.exitCode = 1;
201
201
  });
202
- '''
202
+ ```
203
203
 
204
204
  ---
205
205
 
@@ -207,95 +207,95 @@ process.exitCode = 1;
207
207
 
208
208
  ### Public WebSocket (market data)
209
209
 
210
- '''ts
210
+ ```ts
211
211
  import { KrakenSpotWebsocketV2Client } from '@lynx-crypto/kraken-api';
212
212
 
213
213
  async function main() {
214
- const wsClient = new KrakenSpotWebsocketV2Client({
215
- autoReconnect: false,
216
- });
214
+ const wsClient = new KrakenSpotWebsocketV2Client({
215
+ autoReconnect: false,
216
+ });
217
217
 
218
- await wsClient.publicConnection.connect();
218
+ await wsClient.publicConnection.connect();
219
219
 
220
- const ack = await wsClient.marketData.subscribeTrade(
221
- { symbol: ['BTC/USD'], snapshot: true },
222
- { reqId: 1 },
223
- );
220
+ const ack = await wsClient.marketData.subscribeTrade(
221
+ { symbol: ['BTC/USD'], snapshot: true },
222
+ { reqId: 1 },
223
+ );
224
224
 
225
- if (!ack.success) {
226
- throw new Error(`Subscribe failed: ${ack.error}`);
227
- }
225
+ if (!ack.success) {
226
+ throw new Error(`Subscribe failed: ${ack.error}`);
227
+ }
228
228
 
229
- const unsubscribe = wsClient.publicConnection.addMessageHandler((msg) => {
230
- console.log(JSON.stringify(msg));
231
- });
229
+ const unsubscribe = wsClient.publicConnection.addMessageHandler((msg) => {
230
+ console.log(JSON.stringify(msg));
231
+ });
232
232
 
233
- setTimeout(() => {
234
- unsubscribe();
235
- wsClient.publicConnection.close(1000, 'example done');
236
- }, 20_000);
233
+ setTimeout(() => {
234
+ unsubscribe();
235
+ wsClient.publicConnection.close(1000, 'example done');
236
+ }, 20_000);
237
237
  }
238
238
 
239
239
  main().catch((err) => {
240
- console.error(err);
241
- process.exitCode = 1;
240
+ console.error(err);
241
+ process.exitCode = 1;
242
242
  });
243
- '''
243
+ ```
244
244
 
245
245
  ### Private WebSocket (balances / executions)
246
246
 
247
247
  Authenticated WebSocket usage requires a token obtained via REST.
248
248
 
249
- '''ts
249
+ ```ts
250
250
  import 'dotenv/config';
251
251
  import {
252
- KrakenSpotRestClient,
253
- KrakenSpotWebsocketV2Client,
252
+ KrakenSpotRestClient,
253
+ KrakenSpotWebsocketV2Client,
254
254
  } from '@lynx-crypto/kraken-api';
255
255
 
256
256
  function requireEnv(name: string): string {
257
- const v = process.env[name];
258
- if (!v) throw new Error(`Missing env var: ${name}`);
259
- return v;
257
+ const v = process.env[name];
258
+ if (!v) throw new Error(`Missing env var: ${name}`);
259
+ return v;
260
260
  }
261
261
 
262
262
  async function main() {
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
- });
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
+ });
268
268
 
269
- const { token } = await rest.trading.getWebSocketsToken();
269
+ const { token } = await rest.trading.getWebSocketsToken();
270
270
 
271
- const wsClient = new KrakenSpotWebsocketV2Client({
272
- authToken: token,
273
- autoReconnect: false,
274
- });
271
+ const wsClient = new KrakenSpotWebsocketV2Client({
272
+ authToken: token,
273
+ autoReconnect: false,
274
+ });
275
275
 
276
- await wsClient.privateConnection.connect();
276
+ await wsClient.privateConnection.connect();
277
277
 
278
- const ack = await wsClient.userData.subscribeBalances({}, { reqId: 10 });
278
+ const ack = await wsClient.userData.subscribeBalances({}, { reqId: 10 });
279
279
 
280
- if (!ack.success) {
281
- throw new Error(`Subscribe failed: ${ack.error}`);
282
- }
280
+ if (!ack.success) {
281
+ throw new Error(`Subscribe failed: ${ack.error}`);
282
+ }
283
283
 
284
- const off = wsClient.privateConnection.addMessageHandler((msg) => {
285
- console.log(JSON.stringify(msg));
286
- });
284
+ const off = wsClient.privateConnection.addMessageHandler((msg) => {
285
+ console.log(JSON.stringify(msg));
286
+ });
287
287
 
288
- setTimeout(() => {
289
- off();
290
- wsClient.privateConnection.close(1000, 'example done');
291
- }, 30_000);
288
+ setTimeout(() => {
289
+ off();
290
+ wsClient.privateConnection.close(1000, 'example done');
291
+ }, 30_000);
292
292
  }
293
293
 
294
294
  main().catch((err) => {
295
- console.error(err);
296
- process.exitCode = 1;
295
+ console.error(err);
296
+ process.exitCode = 1;
297
297
  });
298
- '''
298
+ ```
299
299
 
300
300
  ---
301
301
 
@@ -312,7 +312,7 @@ Bulk data is managed by `KrakenBulkClient`. It supports:
312
312
 
313
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
314
 
315
- '''txt
315
+ ```txt
316
316
  <storageDir>/
317
317
  ohlcvt/
318
318
  zips/
@@ -328,7 +328,7 @@ quarterly/<YYYYQn>.zip
328
328
  extracted/
329
329
  complete/
330
330
  quarterly/<YYYYQn>/
331
- '''
331
+ ```
332
332
 
333
333
  Recommended:
334
334
 
@@ -362,27 +362,27 @@ This library supports Kraken-style rate limiting with optional automatic retries
362
362
 
363
363
  Example:
364
364
 
365
- '''ts
365
+ ```ts
366
366
  const kraken = new KrakenSpotRestClient({
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
- },
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
+ },
376
376
  });
377
- '''
377
+ ```
378
378
 
379
379
  Disable built-in throttling:
380
380
 
381
- '''ts
381
+ ```ts
382
382
  rateLimit: {
383
383
  mode: 'off',
384
384
  }
385
- '''
385
+ ```
386
386
 
387
387
  ### Redis rate limiting (multi-process / multi-container)
388
388
 
@@ -392,7 +392,7 @@ For cross-process coordination, you can use the Redis-backed token bucket limite
392
392
 
393
393
  Example (you provide the Redis client + EVAL wrapper):
394
394
 
395
- '''ts
395
+ ```ts
396
396
  import { KrakenSpotRestClient } from '@lynx-crypto/kraken-api';
397
397
  import { RedisTokenBucketLimiter } from '@lynx-crypto/kraken-api/base/redisRateLimit';
398
398
 
@@ -400,26 +400,26 @@ import { RedisTokenBucketLimiter } from '@lynx-crypto/kraken-api/base/redisRateL
400
400
  // - 0 means "proceed now"
401
401
  // - >0 means "wait this many ms then retry"
402
402
  const evalRedis = async (
403
- key: string,
404
- maxCounter: number,
405
- decayPerSec: number,
406
- cost: number,
407
- ttlSeconds: number,
408
- minWaitMs: number,
403
+ key: string,
404
+ maxCounter: number,
405
+ decayPerSec: number,
406
+ cost: number,
407
+ ttlSeconds: number,
408
+ minWaitMs: number,
409
409
  ): Promise<number> => {
410
- // Example shape (pseudo-code):
411
- // return await redis.eval(luaScript, { keys: [key], arguments: [maxCounter, decayPerSec, cost, ttlSeconds, minWaitMs] });
412
- return 0;
410
+ // Example shape (pseudo-code):
411
+ // return await redis.eval(luaScript, { keys: [key], arguments: [maxCounter, decayPerSec, cost, ttlSeconds, minWaitMs] });
412
+ return 0;
413
413
  };
414
414
 
415
415
  const kraken = new KrakenSpotRestClient({
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,
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,
423
423
 
424
424
  // Cross-process limiter (Redis):
425
425
  redis: {
@@ -432,10 +432,9 @@ maxRetries: 5,
432
432
  evalRedis,
433
433
  }),
434
434
  },
435
-
436
- },
435
+ },
437
436
  });
438
- '''
437
+ ```
439
438
 
440
439
  Notes:
441
440
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lynx-crypto/kraken-api",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "TypeScript Kraken SPOT REST client + WebSocket v2 client (Spot market only).",
5
5
  "license": "MIT",
6
6
  "author": "Brett Blashko",