@tradejs/infra 1.0.6 → 1.0.8

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.
@@ -22,22 +22,33 @@ var getPool = () => {
22
22
  };
23
23
  var derivativesSchemaReady = false;
24
24
  var spreadSchemaReady = false;
25
- var toRows = (symbol, interval, data) => data.map((i) => ({
26
- symbol,
27
- interval,
28
- ts: new Date(i.timestamp),
29
- // ms -> Date
30
- open: i.open,
31
- high: i.high,
32
- low: i.low,
33
- close: i.close,
34
- volume: i.volume ?? null,
35
- turnover: i.turnover ?? null
36
- }));
25
+ var normalizeCandleProvider = (provider) => String(provider || "").trim().toLowerCase();
26
+ var normalizeCandleSymbol = (symbol) => String(symbol || "").trim().toUpperCase();
27
+ var toRows = (provider, symbol, interval, data) => {
28
+ const normalizedProvider = normalizeCandleProvider(provider);
29
+ if (!normalizedProvider) {
30
+ throw new Error("Candle provider is required");
31
+ }
32
+ const normalizedSymbol = normalizeCandleSymbol(symbol);
33
+ return data.map((i) => ({
34
+ provider: normalizedProvider,
35
+ symbol: normalizedSymbol,
36
+ interval,
37
+ ts: new Date(i.timestamp),
38
+ // ms -> Date
39
+ open: i.open,
40
+ high: i.high,
41
+ low: i.low,
42
+ close: i.close,
43
+ volume: i.volume ?? null,
44
+ turnover: i.turnover ?? null
45
+ }));
46
+ };
37
47
  async function upsertCandles(rows) {
38
48
  if (!rows.length) return;
39
49
  const pool = getPool();
40
50
  const cols = [
51
+ "provider",
41
52
  "symbol",
42
53
  "interval",
43
54
  "ts",
@@ -59,7 +70,8 @@ async function upsertCandles(rows) {
59
70
  (_, i) => `(${cols.map((__, j) => `$${i * cols.length + j + 1}`).join(",")})`
60
71
  ).join(",");
61
72
  const flat = rows.flatMap((r) => [
62
- r.symbol,
73
+ normalizeCandleProvider(r.provider),
74
+ normalizeCandleSymbol(r.symbol),
63
75
  r.interval,
64
76
  r.ts,
65
77
  r.open,
@@ -72,7 +84,7 @@ async function upsertCandles(rows) {
72
84
  const sql = `
73
85
  INSERT INTO candles (${cols.join(",")})
74
86
  VALUES ${valuesSql}
75
- ON CONFLICT (symbol, interval, ts) DO UPDATE SET
87
+ ON CONFLICT (provider, symbol, interval, ts) DO UPDATE SET
76
88
  open = EXCLUDED.open,
77
89
  high = EXCLUDED.high,
78
90
  low = EXCLUDED.low,
@@ -223,6 +235,82 @@ async function getDerivativesRangeForSymbols(symbols, interval, startMs, endMs)
223
235
  const res = await pool.query(sql, [symbols, interval, startMs, endMs]);
224
236
  return res.rows;
225
237
  }
238
+ async function getDerivativesDataEdgesForSymbols(symbols, interval) {
239
+ const normalizedSymbols = [
240
+ ...new Set(
241
+ symbols.map(
242
+ (symbol) => String(symbol || "").trim().toUpperCase()
243
+ ).filter(Boolean)
244
+ )
245
+ ];
246
+ const edges = /* @__PURE__ */ new Map();
247
+ if (!normalizedSymbols.length) return edges;
248
+ await ensureDerivativesSchema();
249
+ const pool = getPool();
250
+ const sql = `
251
+ SELECT
252
+ symbol,
253
+ extract(epoch from MIN(ts))*1000 AS min,
254
+ extract(epoch from MAX(ts))*1000 AS max
255
+ FROM derivatives_market
256
+ WHERE symbol = ANY($1)
257
+ AND interval = $2
258
+ GROUP BY symbol
259
+ `;
260
+ const res = await pool.query(sql, [normalizedSymbols, interval]);
261
+ for (const row of res.rows) {
262
+ const min = Number(row.min);
263
+ const max = Number(row.max);
264
+ edges.set(String(row.symbol).toUpperCase(), {
265
+ min: Number.isFinite(min) ? min : void 0,
266
+ max: Number.isFinite(max) ? max : void 0
267
+ });
268
+ }
269
+ return edges;
270
+ }
271
+ async function getDerivativesWindow(params) {
272
+ const { symbol, intervals, endMs, lookbackMs } = params;
273
+ const normalizedSymbol = String(symbol || "").trim().toUpperCase();
274
+ const normalizedIntervals = [...new Set(intervals)].filter(Boolean);
275
+ if (!normalizedSymbol || !normalizedIntervals.length) {
276
+ return {};
277
+ }
278
+ await ensureDerivativesSchema();
279
+ const startMs = endMs - Math.max(0, lookbackMs);
280
+ const pool = getPool();
281
+ const sql = `
282
+ SELECT symbol, interval, ts, open_interest, funding_rate, liq_long, liq_short, liq_total, source
283
+ FROM derivatives_market
284
+ WHERE symbol = $1
285
+ AND interval = ANY($2)
286
+ AND ts >= to_timestamp($3/1000.0)
287
+ AND ts <= to_timestamp($4/1000.0)
288
+ ORDER BY interval ASC, ts ASC
289
+ `;
290
+ const res = await pool.query(sql, [
291
+ normalizedSymbol,
292
+ normalizedIntervals,
293
+ startMs,
294
+ endMs
295
+ ]);
296
+ const rowsByInterval = {};
297
+ for (const row of res.rows) {
298
+ const interval = row.interval;
299
+ rowsByInterval[interval] ??= [];
300
+ rowsByInterval[interval]?.push({
301
+ symbol: row.symbol,
302
+ interval,
303
+ ts: row.ts,
304
+ openInterest: row.open_interest,
305
+ fundingRate: row.funding_rate,
306
+ liqLong: row.liq_long,
307
+ liqShort: row.liq_short,
308
+ liqTotal: row.liq_total,
309
+ source: row.source
310
+ });
311
+ }
312
+ return rowsByInterval;
313
+ }
226
314
  async function getDerivativesSummary(hours = 24, limit = 500) {
227
315
  await ensureDerivativesSchema();
228
316
  const pool = getPool();
@@ -362,39 +450,49 @@ async function getSpreadSummary(hours = 24, limit = 500) {
362
450
  hours: cappedHours
363
451
  };
364
452
  }
365
- async function getCandlesRange(symbol, interval, startMs, endMs) {
453
+ async function getCandlesRange(provider, symbol, interval, startMs, endMs) {
366
454
  const pool = getPool();
455
+ const normalizedProvider = normalizeCandleProvider(provider);
456
+ const normalizedSymbol = normalizeCandleSymbol(symbol);
367
457
  const sql = `
368
458
  SELECT symbol, interval, ts,
369
459
  open, high, low, close, volume, turnover
370
460
  FROM candles
371
- WHERE symbol = $1 AND interval = $2
372
- AND ts >= to_timestamp($3/1000.0)
373
- AND ts <= to_timestamp($4/1000.0)
461
+ WHERE provider = $1 AND symbol = $2 AND interval = $3
462
+ AND ts >= to_timestamp($4/1000.0)
463
+ AND ts <= to_timestamp($5/1000.0)
374
464
  ORDER BY ts ASC
375
465
  `;
376
- const res = await pool.query(sql, [symbol, interval, startMs, endMs]);
466
+ const res = await pool.query(sql, [
467
+ normalizedProvider,
468
+ normalizedSymbol,
469
+ interval,
470
+ startMs,
471
+ endMs
472
+ ]);
377
473
  return res.rows;
378
474
  }
379
- async function getDataEdges(symbol, interval) {
475
+ async function getDataEdges(provider, symbol, interval) {
380
476
  const pool = getPool();
477
+ const normalizedProvider = normalizeCandleProvider(provider);
478
+ const normalizedSymbol = normalizeCandleSymbol(symbol);
381
479
  const sqlMin = `
382
480
  SELECT extract(epoch from ts)*1000 AS ms
383
481
  FROM candles
384
- WHERE symbol=$1 AND interval=$2
482
+ WHERE provider=$1 AND symbol=$2 AND interval=$3
385
483
  ORDER BY ts ASC
386
484
  LIMIT 1
387
485
  `;
388
486
  const sqlMax = `
389
487
  SELECT extract(epoch from ts)*1000 AS ms
390
488
  FROM candles
391
- WHERE symbol=$1 AND interval=$2
489
+ WHERE provider=$1 AND symbol=$2 AND interval=$3
392
490
  ORDER BY ts DESC
393
491
  LIMIT 1
394
492
  `;
395
493
  const [minQ, maxQ] = await Promise.all([
396
- pool.query(sqlMin, [symbol, interval]),
397
- pool.query(sqlMax, [symbol, interval])
494
+ pool.query(sqlMin, [normalizedProvider, normalizedSymbol, interval]),
495
+ pool.query(sqlMax, [normalizedProvider, normalizedSymbol, interval])
398
496
  ]);
399
497
  const minRaw = minQ.rows[0]?.ms;
400
498
  const maxRaw = maxQ.rows[0]?.ms;
@@ -416,16 +514,20 @@ async function waitForDbReady(attempts = 20, delayMs = 1e3) {
416
514
  }
417
515
  throw lastError;
418
516
  }
419
- async function deleteCandles(symbol, interval) {
517
+ async function deleteCandles(provider, symbol, interval) {
420
518
  const pool = getPool();
519
+ const normalizedProvider = normalizeCandleProvider(provider);
520
+ const normalizedSymbol = normalizeCandleSymbol(symbol);
421
521
  const sql = `
422
522
  DELETE FROM candles
423
- WHERE symbol = $1 AND interval = $2
523
+ WHERE provider = $1 AND symbol = $2 AND interval = $3
424
524
  `;
425
- await pool.query(sql, [symbol, interval]);
525
+ await pool.query(sql, [normalizedProvider, normalizedSymbol, interval]);
426
526
  }
427
- async function findContinuityGap(symbol, interval) {
527
+ async function findContinuityGap(provider, symbol, interval) {
428
528
  const pool = getPool();
529
+ const normalizedProvider = normalizeCandleProvider(provider);
530
+ const normalizedSymbol = normalizeCandleSymbol(symbol);
429
531
  const expectedSeconds = interval * 60;
430
532
  const sql = `
431
533
  WITH ordered AS (
@@ -433,7 +535,7 @@ async function findContinuityGap(symbol, interval) {
433
535
  ts,
434
536
  LAG(ts) OVER (ORDER BY ts) AS prev_ts
435
537
  FROM candles
436
- WHERE symbol = $1 AND interval = $2
538
+ WHERE provider = $1 AND symbol = $2 AND interval = $3
437
539
  )
438
540
  SELECT
439
541
  ts,
@@ -441,11 +543,16 @@ async function findContinuityGap(symbol, interval) {
441
543
  EXTRACT(EPOCH FROM (ts - prev_ts))::int AS diff_seconds
442
544
  FROM ordered
443
545
  WHERE prev_ts IS NOT NULL
444
- AND EXTRACT(EPOCH FROM (ts - prev_ts))::int <> $3
546
+ AND EXTRACT(EPOCH FROM (ts - prev_ts))::int <> $4
445
547
  ORDER BY ts ASC
446
548
  LIMIT 1
447
549
  `;
448
- const res = await pool.query(sql, [symbol, interval, expectedSeconds]);
550
+ const res = await pool.query(sql, [
551
+ normalizedProvider,
552
+ normalizedSymbol,
553
+ interval,
554
+ expectedSeconds
555
+ ]);
449
556
  const row = res.rows[0];
450
557
  if (!row) return null;
451
558
  return {
@@ -459,8 +566,10 @@ export {
459
566
  findContinuityGap,
460
567
  getCandlesRange,
461
568
  getDataEdges,
569
+ getDerivativesDataEdgesForSymbols,
462
570
  getDerivativesRangeForSymbols,
463
571
  getDerivativesSummary,
572
+ getDerivativesWindow,
464
573
  getSpreadRangeForSymbols,
465
574
  getSpreadSummary,
466
575
  toRows,
@@ -1,12 +1,13 @@
1
1
  interface UserRecord extends Record<string, unknown> {
2
2
  userName?: string;
3
3
  passwordHash?: string;
4
- token?: string;
5
4
  BYBIT_API_KEY?: string;
6
5
  BYBIT_API_SECRET?: string;
7
6
  COINALYZE_API_KEY?: string;
8
- OPENAI_API_KEY?: string;
9
- OPENAI_API_ENDPOINT?: string;
7
+ AI_API_KEY?: string;
8
+ AI_API_ENDPOINT?: string;
9
+ AI_MODEL?: string;
10
+ AI_RESPONSE_LANGUAGE?: string;
10
11
  TG_BOT_TOKEN?: string;
11
12
  TG_CHAT_ID?: string;
12
13
  updatedAt?: string;
@@ -15,10 +16,11 @@ interface UserSettings {
15
16
  userName: string;
16
17
  BYBIT_API_KEY: string;
17
18
  BYBIT_API_SECRET: string;
18
- token: string;
19
19
  COINALYZE_API_KEY: string;
20
- OPENAI_API_KEY: string;
21
- OPENAI_API_ENDPOINT: string;
20
+ AI_API_KEY: string;
21
+ AI_API_ENDPOINT: string;
22
+ AI_MODEL: string;
23
+ AI_RESPONSE_LANGUAGE: string;
22
24
  TG_BOT_TOKEN: string;
23
25
  TG_CHAT_ID: string;
24
26
  }
@@ -1,12 +1,13 @@
1
1
  interface UserRecord extends Record<string, unknown> {
2
2
  userName?: string;
3
3
  passwordHash?: string;
4
- token?: string;
5
4
  BYBIT_API_KEY?: string;
6
5
  BYBIT_API_SECRET?: string;
7
6
  COINALYZE_API_KEY?: string;
8
- OPENAI_API_KEY?: string;
9
- OPENAI_API_ENDPOINT?: string;
7
+ AI_API_KEY?: string;
8
+ AI_API_ENDPOINT?: string;
9
+ AI_MODEL?: string;
10
+ AI_RESPONSE_LANGUAGE?: string;
10
11
  TG_BOT_TOKEN?: string;
11
12
  TG_CHAT_ID?: string;
12
13
  updatedAt?: string;
@@ -15,10 +16,11 @@ interface UserSettings {
15
16
  userName: string;
16
17
  BYBIT_API_KEY: string;
17
18
  BYBIT_API_SECRET: string;
18
- token: string;
19
19
  COINALYZE_API_KEY: string;
20
- OPENAI_API_KEY: string;
21
- OPENAI_API_ENDPOINT: string;
20
+ AI_API_KEY: string;
21
+ AI_API_ENDPOINT: string;
22
+ AI_MODEL: string;
23
+ AI_RESPONSE_LANGUAGE: string;
22
24
  TG_BOT_TOKEN: string;
23
25
  TG_CHAT_ID: string;
24
26
  }