@tradejs/infra 1.0.6 → 1.0.9
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/aiEndpoints.d.mts +10 -0
- package/dist/aiEndpoints.d.ts +10 -0
- package/dist/aiEndpoints.js +159 -0
- package/dist/aiEndpoints.mjs +12 -0
- package/dist/aiLanguages.d.mts +11 -0
- package/dist/aiLanguages.d.ts +11 -0
- package/dist/aiLanguages.js +71 -0
- package/dist/aiLanguages.mjs +12 -0
- package/dist/aiModels.d.mts +12 -0
- package/dist/aiModels.d.ts +12 -0
- package/dist/aiModels.js +272 -0
- package/dist/aiModels.mjs +17 -0
- package/dist/chunk-CCC7DX2T.mjs +44 -0
- package/dist/chunk-DTCLZIBM.mjs +163 -0
- package/dist/{chunk-EFARW5QE.mjs → chunk-MLVWC2I2.mjs} +173 -0
- package/dist/chunk-XQ3YBULV.mjs +132 -0
- package/dist/ml.js +119 -0
- package/dist/ml.mjs +119 -0
- package/dist/redis.d.mts +27 -1
- package/dist/redis.d.ts +27 -1
- package/dist/redis.js +181 -2
- package/dist/redis.mjs +15 -3
- package/dist/timescale.d.mts +18 -7
- package/dist/timescale.d.ts +18 -7
- package/dist/timescale.js +142 -31
- package/dist/timescale.mjs +140 -31
- package/dist/userSettings.d.mts +8 -6
- package/dist/userSettings.d.ts +8 -6
- package/dist/userSettings.js +342 -4
- package/dist/userSettings.mjs +27 -5
- package/package.json +18 -3
package/dist/timescale.js
CHANGED
|
@@ -24,8 +24,10 @@ __export(timescale_exports, {
|
|
|
24
24
|
findContinuityGap: () => findContinuityGap,
|
|
25
25
|
getCandlesRange: () => getCandlesRange,
|
|
26
26
|
getDataEdges: () => getDataEdges,
|
|
27
|
+
getDerivativesDataEdgesForSymbols: () => getDerivativesDataEdgesForSymbols,
|
|
27
28
|
getDerivativesRangeForSymbols: () => getDerivativesRangeForSymbols,
|
|
28
29
|
getDerivativesSummary: () => getDerivativesSummary,
|
|
30
|
+
getDerivativesWindow: () => getDerivativesWindow,
|
|
29
31
|
getSpreadRangeForSymbols: () => getSpreadRangeForSymbols,
|
|
30
32
|
getSpreadSummary: () => getSpreadSummary,
|
|
31
33
|
toRows: () => toRows,
|
|
@@ -58,22 +60,33 @@ var getPool = () => {
|
|
|
58
60
|
};
|
|
59
61
|
var derivativesSchemaReady = false;
|
|
60
62
|
var spreadSchemaReady = false;
|
|
61
|
-
var
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
var normalizeCandleProvider = (provider) => String(provider || "").trim().toLowerCase();
|
|
64
|
+
var normalizeCandleSymbol = (symbol) => String(symbol || "").trim().toUpperCase();
|
|
65
|
+
var toRows = (provider, symbol, interval, data) => {
|
|
66
|
+
const normalizedProvider = normalizeCandleProvider(provider);
|
|
67
|
+
if (!normalizedProvider) {
|
|
68
|
+
throw new Error("Candle provider is required");
|
|
69
|
+
}
|
|
70
|
+
const normalizedSymbol = normalizeCandleSymbol(symbol);
|
|
71
|
+
return data.map((i) => ({
|
|
72
|
+
provider: normalizedProvider,
|
|
73
|
+
symbol: normalizedSymbol,
|
|
74
|
+
interval,
|
|
75
|
+
ts: new Date(i.timestamp),
|
|
76
|
+
// ms -> Date
|
|
77
|
+
open: i.open,
|
|
78
|
+
high: i.high,
|
|
79
|
+
low: i.low,
|
|
80
|
+
close: i.close,
|
|
81
|
+
volume: i.volume ?? null,
|
|
82
|
+
turnover: i.turnover ?? null
|
|
83
|
+
}));
|
|
84
|
+
};
|
|
73
85
|
async function upsertCandles(rows) {
|
|
74
86
|
if (!rows.length) return;
|
|
75
87
|
const pool = getPool();
|
|
76
88
|
const cols = [
|
|
89
|
+
"provider",
|
|
77
90
|
"symbol",
|
|
78
91
|
"interval",
|
|
79
92
|
"ts",
|
|
@@ -95,7 +108,8 @@ async function upsertCandles(rows) {
|
|
|
95
108
|
(_, i) => `(${cols.map((__, j) => `$${i * cols.length + j + 1}`).join(",")})`
|
|
96
109
|
).join(",");
|
|
97
110
|
const flat = rows.flatMap((r) => [
|
|
98
|
-
r.
|
|
111
|
+
normalizeCandleProvider(r.provider),
|
|
112
|
+
normalizeCandleSymbol(r.symbol),
|
|
99
113
|
r.interval,
|
|
100
114
|
r.ts,
|
|
101
115
|
r.open,
|
|
@@ -108,7 +122,7 @@ async function upsertCandles(rows) {
|
|
|
108
122
|
const sql = `
|
|
109
123
|
INSERT INTO candles (${cols.join(",")})
|
|
110
124
|
VALUES ${valuesSql}
|
|
111
|
-
ON CONFLICT (symbol, interval, ts) DO UPDATE SET
|
|
125
|
+
ON CONFLICT (provider, symbol, interval, ts) DO UPDATE SET
|
|
112
126
|
open = EXCLUDED.open,
|
|
113
127
|
high = EXCLUDED.high,
|
|
114
128
|
low = EXCLUDED.low,
|
|
@@ -259,6 +273,82 @@ async function getDerivativesRangeForSymbols(symbols, interval, startMs, endMs)
|
|
|
259
273
|
const res = await pool.query(sql, [symbols, interval, startMs, endMs]);
|
|
260
274
|
return res.rows;
|
|
261
275
|
}
|
|
276
|
+
async function getDerivativesDataEdgesForSymbols(symbols, interval) {
|
|
277
|
+
const normalizedSymbols = [
|
|
278
|
+
...new Set(
|
|
279
|
+
symbols.map(
|
|
280
|
+
(symbol) => String(symbol || "").trim().toUpperCase()
|
|
281
|
+
).filter(Boolean)
|
|
282
|
+
)
|
|
283
|
+
];
|
|
284
|
+
const edges = /* @__PURE__ */ new Map();
|
|
285
|
+
if (!normalizedSymbols.length) return edges;
|
|
286
|
+
await ensureDerivativesSchema();
|
|
287
|
+
const pool = getPool();
|
|
288
|
+
const sql = `
|
|
289
|
+
SELECT
|
|
290
|
+
symbol,
|
|
291
|
+
extract(epoch from MIN(ts))*1000 AS min,
|
|
292
|
+
extract(epoch from MAX(ts))*1000 AS max
|
|
293
|
+
FROM derivatives_market
|
|
294
|
+
WHERE symbol = ANY($1)
|
|
295
|
+
AND interval = $2
|
|
296
|
+
GROUP BY symbol
|
|
297
|
+
`;
|
|
298
|
+
const res = await pool.query(sql, [normalizedSymbols, interval]);
|
|
299
|
+
for (const row of res.rows) {
|
|
300
|
+
const min = Number(row.min);
|
|
301
|
+
const max = Number(row.max);
|
|
302
|
+
edges.set(String(row.symbol).toUpperCase(), {
|
|
303
|
+
min: Number.isFinite(min) ? min : void 0,
|
|
304
|
+
max: Number.isFinite(max) ? max : void 0
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
return edges;
|
|
308
|
+
}
|
|
309
|
+
async function getDerivativesWindow(params) {
|
|
310
|
+
const { symbol, intervals, endMs, lookbackMs } = params;
|
|
311
|
+
const normalizedSymbol = String(symbol || "").trim().toUpperCase();
|
|
312
|
+
const normalizedIntervals = [...new Set(intervals)].filter(Boolean);
|
|
313
|
+
if (!normalizedSymbol || !normalizedIntervals.length) {
|
|
314
|
+
return {};
|
|
315
|
+
}
|
|
316
|
+
await ensureDerivativesSchema();
|
|
317
|
+
const startMs = endMs - Math.max(0, lookbackMs);
|
|
318
|
+
const pool = getPool();
|
|
319
|
+
const sql = `
|
|
320
|
+
SELECT symbol, interval, ts, open_interest, funding_rate, liq_long, liq_short, liq_total, source
|
|
321
|
+
FROM derivatives_market
|
|
322
|
+
WHERE symbol = $1
|
|
323
|
+
AND interval = ANY($2)
|
|
324
|
+
AND ts >= to_timestamp($3/1000.0)
|
|
325
|
+
AND ts <= to_timestamp($4/1000.0)
|
|
326
|
+
ORDER BY interval ASC, ts ASC
|
|
327
|
+
`;
|
|
328
|
+
const res = await pool.query(sql, [
|
|
329
|
+
normalizedSymbol,
|
|
330
|
+
normalizedIntervals,
|
|
331
|
+
startMs,
|
|
332
|
+
endMs
|
|
333
|
+
]);
|
|
334
|
+
const rowsByInterval = {};
|
|
335
|
+
for (const row of res.rows) {
|
|
336
|
+
const interval = row.interval;
|
|
337
|
+
rowsByInterval[interval] ??= [];
|
|
338
|
+
rowsByInterval[interval]?.push({
|
|
339
|
+
symbol: row.symbol,
|
|
340
|
+
interval,
|
|
341
|
+
ts: row.ts,
|
|
342
|
+
openInterest: row.open_interest,
|
|
343
|
+
fundingRate: row.funding_rate,
|
|
344
|
+
liqLong: row.liq_long,
|
|
345
|
+
liqShort: row.liq_short,
|
|
346
|
+
liqTotal: row.liq_total,
|
|
347
|
+
source: row.source
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
return rowsByInterval;
|
|
351
|
+
}
|
|
262
352
|
async function getDerivativesSummary(hours = 24, limit = 500) {
|
|
263
353
|
await ensureDerivativesSchema();
|
|
264
354
|
const pool = getPool();
|
|
@@ -398,39 +488,49 @@ async function getSpreadSummary(hours = 24, limit = 500) {
|
|
|
398
488
|
hours: cappedHours
|
|
399
489
|
};
|
|
400
490
|
}
|
|
401
|
-
async function getCandlesRange(symbol, interval, startMs, endMs) {
|
|
491
|
+
async function getCandlesRange(provider, symbol, interval, startMs, endMs) {
|
|
402
492
|
const pool = getPool();
|
|
493
|
+
const normalizedProvider = normalizeCandleProvider(provider);
|
|
494
|
+
const normalizedSymbol = normalizeCandleSymbol(symbol);
|
|
403
495
|
const sql = `
|
|
404
496
|
SELECT symbol, interval, ts,
|
|
405
497
|
open, high, low, close, volume, turnover
|
|
406
498
|
FROM candles
|
|
407
|
-
WHERE
|
|
408
|
-
AND ts >= to_timestamp($
|
|
409
|
-
AND ts <= to_timestamp($
|
|
499
|
+
WHERE provider = $1 AND symbol = $2 AND interval = $3
|
|
500
|
+
AND ts >= to_timestamp($4/1000.0)
|
|
501
|
+
AND ts <= to_timestamp($5/1000.0)
|
|
410
502
|
ORDER BY ts ASC
|
|
411
503
|
`;
|
|
412
|
-
const res = await pool.query(sql, [
|
|
504
|
+
const res = await pool.query(sql, [
|
|
505
|
+
normalizedProvider,
|
|
506
|
+
normalizedSymbol,
|
|
507
|
+
interval,
|
|
508
|
+
startMs,
|
|
509
|
+
endMs
|
|
510
|
+
]);
|
|
413
511
|
return res.rows;
|
|
414
512
|
}
|
|
415
|
-
async function getDataEdges(symbol, interval) {
|
|
513
|
+
async function getDataEdges(provider, symbol, interval) {
|
|
416
514
|
const pool = getPool();
|
|
515
|
+
const normalizedProvider = normalizeCandleProvider(provider);
|
|
516
|
+
const normalizedSymbol = normalizeCandleSymbol(symbol);
|
|
417
517
|
const sqlMin = `
|
|
418
518
|
SELECT extract(epoch from ts)*1000 AS ms
|
|
419
519
|
FROM candles
|
|
420
|
-
WHERE
|
|
520
|
+
WHERE provider=$1 AND symbol=$2 AND interval=$3
|
|
421
521
|
ORDER BY ts ASC
|
|
422
522
|
LIMIT 1
|
|
423
523
|
`;
|
|
424
524
|
const sqlMax = `
|
|
425
525
|
SELECT extract(epoch from ts)*1000 AS ms
|
|
426
526
|
FROM candles
|
|
427
|
-
WHERE
|
|
527
|
+
WHERE provider=$1 AND symbol=$2 AND interval=$3
|
|
428
528
|
ORDER BY ts DESC
|
|
429
529
|
LIMIT 1
|
|
430
530
|
`;
|
|
431
531
|
const [minQ, maxQ] = await Promise.all([
|
|
432
|
-
pool.query(sqlMin, [
|
|
433
|
-
pool.query(sqlMax, [
|
|
532
|
+
pool.query(sqlMin, [normalizedProvider, normalizedSymbol, interval]),
|
|
533
|
+
pool.query(sqlMax, [normalizedProvider, normalizedSymbol, interval])
|
|
434
534
|
]);
|
|
435
535
|
const minRaw = minQ.rows[0]?.ms;
|
|
436
536
|
const maxRaw = maxQ.rows[0]?.ms;
|
|
@@ -452,16 +552,20 @@ async function waitForDbReady(attempts = 20, delayMs = 1e3) {
|
|
|
452
552
|
}
|
|
453
553
|
throw lastError;
|
|
454
554
|
}
|
|
455
|
-
async function deleteCandles(symbol, interval) {
|
|
555
|
+
async function deleteCandles(provider, symbol, interval) {
|
|
456
556
|
const pool = getPool();
|
|
557
|
+
const normalizedProvider = normalizeCandleProvider(provider);
|
|
558
|
+
const normalizedSymbol = normalizeCandleSymbol(symbol);
|
|
457
559
|
const sql = `
|
|
458
560
|
DELETE FROM candles
|
|
459
|
-
WHERE
|
|
561
|
+
WHERE provider = $1 AND symbol = $2 AND interval = $3
|
|
460
562
|
`;
|
|
461
|
-
await pool.query(sql, [
|
|
563
|
+
await pool.query(sql, [normalizedProvider, normalizedSymbol, interval]);
|
|
462
564
|
}
|
|
463
|
-
async function findContinuityGap(symbol, interval) {
|
|
565
|
+
async function findContinuityGap(provider, symbol, interval) {
|
|
464
566
|
const pool = getPool();
|
|
567
|
+
const normalizedProvider = normalizeCandleProvider(provider);
|
|
568
|
+
const normalizedSymbol = normalizeCandleSymbol(symbol);
|
|
465
569
|
const expectedSeconds = interval * 60;
|
|
466
570
|
const sql = `
|
|
467
571
|
WITH ordered AS (
|
|
@@ -469,7 +573,7 @@ async function findContinuityGap(symbol, interval) {
|
|
|
469
573
|
ts,
|
|
470
574
|
LAG(ts) OVER (ORDER BY ts) AS prev_ts
|
|
471
575
|
FROM candles
|
|
472
|
-
WHERE
|
|
576
|
+
WHERE provider = $1 AND symbol = $2 AND interval = $3
|
|
473
577
|
)
|
|
474
578
|
SELECT
|
|
475
579
|
ts,
|
|
@@ -477,11 +581,16 @@ async function findContinuityGap(symbol, interval) {
|
|
|
477
581
|
EXTRACT(EPOCH FROM (ts - prev_ts))::int AS diff_seconds
|
|
478
582
|
FROM ordered
|
|
479
583
|
WHERE prev_ts IS NOT NULL
|
|
480
|
-
AND EXTRACT(EPOCH FROM (ts - prev_ts))::int <> $
|
|
584
|
+
AND EXTRACT(EPOCH FROM (ts - prev_ts))::int <> $4
|
|
481
585
|
ORDER BY ts ASC
|
|
482
586
|
LIMIT 1
|
|
483
587
|
`;
|
|
484
|
-
const res = await pool.query(sql, [
|
|
588
|
+
const res = await pool.query(sql, [
|
|
589
|
+
normalizedProvider,
|
|
590
|
+
normalizedSymbol,
|
|
591
|
+
interval,
|
|
592
|
+
expectedSeconds
|
|
593
|
+
]);
|
|
485
594
|
const row = res.rows[0];
|
|
486
595
|
if (!row) return null;
|
|
487
596
|
return {
|
|
@@ -496,8 +605,10 @@ async function findContinuityGap(symbol, interval) {
|
|
|
496
605
|
findContinuityGap,
|
|
497
606
|
getCandlesRange,
|
|
498
607
|
getDataEdges,
|
|
608
|
+
getDerivativesDataEdgesForSymbols,
|
|
499
609
|
getDerivativesRangeForSymbols,
|
|
500
610
|
getDerivativesSummary,
|
|
611
|
+
getDerivativesWindow,
|
|
501
612
|
getSpreadRangeForSymbols,
|
|
502
613
|
getSpreadSummary,
|
|
503
614
|
toRows,
|
package/dist/timescale.mjs
CHANGED
|
@@ -22,22 +22,33 @@ var getPool = () => {
|
|
|
22
22
|
};
|
|
23
23
|
var derivativesSchemaReady = false;
|
|
24
24
|
var spreadSchemaReady = false;
|
|
25
|
-
var
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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.
|
|
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
|
|
372
|
-
AND ts >= to_timestamp($
|
|
373
|
-
AND ts <= to_timestamp($
|
|
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, [
|
|
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
|
|
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
|
|
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, [
|
|
397
|
-
pool.query(sqlMax, [
|
|
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
|
|
523
|
+
WHERE provider = $1 AND symbol = $2 AND interval = $3
|
|
424
524
|
`;
|
|
425
|
-
await pool.query(sql, [
|
|
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
|
|
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 <> $
|
|
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, [
|
|
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,
|
package/dist/userSettings.d.mts
CHANGED
|
@@ -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
|
-
|
|
9
|
-
|
|
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
|
-
|
|
21
|
-
|
|
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
|
}
|
package/dist/userSettings.d.ts
CHANGED
|
@@ -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
|
-
|
|
9
|
-
|
|
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
|
-
|
|
21
|
-
|
|
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
|
}
|