@tradejs/cli 2.0.0 → 2.0.2
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/cli.js +384 -122
- package/dist/lib/aiTrainCharts.js +49 -2
- package/dist/lib/aiTrainMetrics.js +49 -2
- package/dist/lib/aiTrainResearch.js +58 -4
- package/dist/lib/derivativesContextBackfill.js +262 -107
- package/dist/lib/marketContextPrepare.js +256 -107
- package/dist/scripts/aiPocketSearch.js +49 -2
- package/dist/scripts/aiTrain.js +76 -4
- package/dist/scripts/backtest.js +256 -107
- package/dist/scripts/derivativesIngest.js +11 -4
- package/dist/scripts/derivativesIngestCoinalyzeAll.js +38 -4
- package/dist/scripts/replay.js +256 -107
- package/dist/scripts/replayRunner.js +256 -107
- package/dist/scripts/runtimeParity.js +256 -107
- package/dist/scripts/signals.js +256 -107
- package/dist/scripts/signalsDaemon.js +256 -107
- package/package.json +9 -9
|
@@ -41,11 +41,11 @@ var import_timescale = require("@tradejs/infra/timescale");
|
|
|
41
41
|
var import_userSettings = require("@tradejs/infra/userSettings");
|
|
42
42
|
var import_connectors = require("@tradejs/connectors");
|
|
43
43
|
import_args.default.example(
|
|
44
|
-
"yarn ts-node ./src/scripts/derivativesIngest --provider coinalyze --symbols BTCUSDT,ETHUSDT --intervals 15m
|
|
44
|
+
"yarn ts-node ./src/scripts/derivativesIngest --provider coinalyze --symbols BTCUSDT,ETHUSDT --intervals 15m --days 120",
|
|
45
45
|
"Ingest market features (derivatives/spread) into Timescale by provider"
|
|
46
46
|
);
|
|
47
47
|
import_args.default.option(["s", "symbols"], "Comma-separated symbols", "BTCUSDT,ETHUSDT");
|
|
48
|
-
import_args.default.option(["t", "intervals"], "Comma-separated intervals: 15m,1h", "15m
|
|
48
|
+
import_args.default.option(["t", "intervals"], "Comma-separated intervals: 15m,1h", "15m");
|
|
49
49
|
import_args.default.option(["d", "days"], "Lookback in days", 120);
|
|
50
50
|
import_args.default.option(
|
|
51
51
|
["p", "provider"],
|
|
@@ -82,9 +82,16 @@ var main = async () => {
|
|
|
82
82
|
let totalSpreadRows = 0;
|
|
83
83
|
for (const symbol of symbols) {
|
|
84
84
|
for (const interval of intervals) {
|
|
85
|
+
const lastClosedStartMs = (0, import_indicators.getLastClosedDerivativesBarStartMs)(
|
|
86
|
+
now,
|
|
87
|
+
interval
|
|
88
|
+
);
|
|
85
89
|
let cursor = fromMs;
|
|
86
|
-
while (cursor <
|
|
87
|
-
const toMs = Math.min(
|
|
90
|
+
while (cursor < lastClosedStartMs) {
|
|
91
|
+
const toMs = Math.min(
|
|
92
|
+
lastClosedStartMs,
|
|
93
|
+
cursor + batchDays * 24 * 60 * 60 * 1e3
|
|
94
|
+
);
|
|
88
95
|
process.stdout.write(
|
|
89
96
|
`\r${import_chalk.default.cyan(providerName)} ${import_chalk.default.yellow(symbol)} ${interval} ${new Date(cursor).toISOString()} .. ${new Date(toMs).toISOString()} `
|
|
90
97
|
);
|
|
@@ -49,7 +49,7 @@ var coinalyzeIntervalMap = {
|
|
|
49
49
|
"1h": "1hour"
|
|
50
50
|
};
|
|
51
51
|
import_args.default.example(
|
|
52
|
-
"yarn ts-node ./src/scripts/derivativesIngestCoinalyzeAll --days 120 --intervals 15m
|
|
52
|
+
"yarn ts-node ./src/scripts/derivativesIngestCoinalyzeAll --days 120 --intervals 15m",
|
|
53
53
|
"Fetch derivatives for all getTickers symbols matched to Coinalyze markets"
|
|
54
54
|
);
|
|
55
55
|
import_args.default.option(["U", "user"], "User settings profile name from Redis", "root");
|
|
@@ -57,7 +57,7 @@ import_args.default.option(["t", "tickers"], "Comma-separated include symbols");
|
|
|
57
57
|
import_args.default.option(["e", "exclude"], "Comma-separated exclude symbols");
|
|
58
58
|
import_args.default.option(["l", "tickersLimit"], "Tickers limit");
|
|
59
59
|
import_args.default.option(["c", "chunk"], "Chunk selector, e.g. 1/4");
|
|
60
|
-
import_args.default.option(["i", "intervals"], "Intervals: 15m,1h", "15m
|
|
60
|
+
import_args.default.option(["i", "intervals"], "Intervals: 15m,1h", "15m");
|
|
61
61
|
import_args.default.option(["d", "days"], "Lookback in days", 120);
|
|
62
62
|
import_args.default.option(["b", "batchDays"], "Request chunk size in days", 120);
|
|
63
63
|
import_args.default.option(
|
|
@@ -326,12 +326,16 @@ var main = async () => {
|
|
|
326
326
|
let totalRows = 0;
|
|
327
327
|
let failedWindows = 0;
|
|
328
328
|
for (const interval of intervals) {
|
|
329
|
+
const lastClosedStartMs = (0, import_indicators.getLastClosedDerivativesBarStartMs)(now, interval);
|
|
329
330
|
for (let batchIdx = 0; batchIdx < symbolBatches.length; batchIdx += 1) {
|
|
330
331
|
const batch = symbolBatches[batchIdx];
|
|
331
332
|
const marketSymbols = batch.map((item) => item.marketSymbol);
|
|
332
333
|
let cursor = fromMs;
|
|
333
|
-
while (cursor <
|
|
334
|
-
const toMs = Math.min(
|
|
334
|
+
while (cursor < lastClosedStartMs) {
|
|
335
|
+
const toMs = Math.min(
|
|
336
|
+
lastClosedStartMs,
|
|
337
|
+
cursor + batchDays * 24 * 60 * 60 * 1e3
|
|
338
|
+
);
|
|
335
339
|
try {
|
|
336
340
|
const oiMap = await fetchMetricBatch({
|
|
337
341
|
endpoint: oiPath,
|
|
@@ -374,6 +378,36 @@ var main = async () => {
|
|
|
374
378
|
await (0, import_timescale.upsertDerivatives)(rows);
|
|
375
379
|
totalRows += rows.length;
|
|
376
380
|
}
|
|
381
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
382
|
+
interval,
|
|
383
|
+
fromMs: cursor,
|
|
384
|
+
toMs,
|
|
385
|
+
nowMs: now
|
|
386
|
+
});
|
|
387
|
+
if (confirmedLiquidationWindow) {
|
|
388
|
+
await (0, import_timescale.applyDerivativesMetricCoverage)(
|
|
389
|
+
batch.map((item) => {
|
|
390
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
391
|
+
const eventRowsCount = (liqMap.get(marketSymbol) ?? []).filter(
|
|
392
|
+
(point) => {
|
|
393
|
+
const timestamp = (0, import_indicators.toCoinalyzeTimestampMs)(
|
|
394
|
+
point.t ?? point.ts ?? point.time ?? point.timestamp
|
|
395
|
+
);
|
|
396
|
+
return timestamp != null && timestamp >= confirmedLiquidationWindow.fromMs && timestamp <= confirmedLiquidationWindow.toMs;
|
|
397
|
+
}
|
|
398
|
+
).length;
|
|
399
|
+
return {
|
|
400
|
+
source: "coinalyze",
|
|
401
|
+
metric: "liquidation",
|
|
402
|
+
symbol: item.symbol,
|
|
403
|
+
interval,
|
|
404
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
405
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
406
|
+
eventRowsCount
|
|
407
|
+
};
|
|
408
|
+
})
|
|
409
|
+
);
|
|
410
|
+
}
|
|
377
411
|
} catch (error) {
|
|
378
412
|
failedWindows += 1;
|
|
379
413
|
console.error(
|
package/dist/scripts/replay.js
CHANGED
|
@@ -3106,7 +3106,7 @@ var import_userSettings = require("@tradejs/infra/userSettings");
|
|
|
3106
3106
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
3107
3107
|
var DAY_MS2 = 24 * HOUR_MS;
|
|
3108
3108
|
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
3109
|
-
var
|
|
3109
|
+
var SOURCE_INTERVALS = ["15m"];
|
|
3110
3110
|
var coinalyzeIntervalMap = {
|
|
3111
3111
|
"15m": "15min",
|
|
3112
3112
|
"1h": "1hour"
|
|
@@ -3167,10 +3167,7 @@ var isDerivativesContextBackfillEnabled = (env) => {
|
|
|
3167
3167
|
var shouldBackfillDerivativesContextForBacktest = (params) => !params.cacheOnly && (params.aiEnabled || params.mlEnabled) && isBacktestDerivativesContextEnabled();
|
|
3168
3168
|
var shouldBackfillDerivativesContextForSignals = (params) => !params.cacheOnly && isSignalsDerivativesContextEnabled();
|
|
3169
3169
|
var resolveDerivativesContextIntervals = () => {
|
|
3170
|
-
|
|
3171
|
-
process.env.DERIVATIVES_CONTEXT_INTERVALS
|
|
3172
|
-
);
|
|
3173
|
-
return intervals.length ? intervals : DEFAULT_INTERVALS;
|
|
3170
|
+
return [...SOURCE_INTERVALS];
|
|
3174
3171
|
};
|
|
3175
3172
|
var resolveDerivativesContextLookbackMs = () => {
|
|
3176
3173
|
const hours = Number(process.env.DERIVATIVES_CONTEXT_LOOKBACK_HOURS);
|
|
@@ -3205,9 +3202,10 @@ var resolveDerivativesContextBackfillWindow = (params) => {
|
|
|
3205
3202
|
};
|
|
3206
3203
|
var resolveDerivativesContextIntervalBackfillWindow = (params) => {
|
|
3207
3204
|
const intervalMs = derivativesIntervalMs(params.interval);
|
|
3205
|
+
const alignedToMs = params.closedOnly ? (0, import_indicators.getLastClosedDerivativesBarStartMs)(params.toMs, params.interval) : Math.floor(params.toMs / intervalMs) * intervalMs;
|
|
3208
3206
|
return {
|
|
3209
3207
|
fromMs: Math.floor(params.fromMs / intervalMs) * intervalMs,
|
|
3210
|
-
toMs:
|
|
3208
|
+
toMs: alignedToMs,
|
|
3211
3209
|
intervalMs
|
|
3212
3210
|
};
|
|
3213
3211
|
};
|
|
@@ -3225,6 +3223,39 @@ var resolveDerivativesContextMissingFetchFromMs = (params) => {
|
|
|
3225
3223
|
}
|
|
3226
3224
|
return null;
|
|
3227
3225
|
};
|
|
3226
|
+
var resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
|
|
3227
|
+
var resolveDerivativesContextRequiredFetchFromMs = (params) => {
|
|
3228
|
+
const dataCoverageFromMs = params.dataCoverageKeyExists ? null : params.mode === "signals" ? params.fromMs : resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
3229
|
+
ranges: params.dataCoverageRanges,
|
|
3230
|
+
fromMs: params.fromMs,
|
|
3231
|
+
toMs: params.toMs,
|
|
3232
|
+
intervalMs: params.intervalMs
|
|
3233
|
+
});
|
|
3234
|
+
const edgesFromMs = dataCoverageFromMs == null ? null : resolveDerivativesContextFetchFromMs({
|
|
3235
|
+
edges: params.edges,
|
|
3236
|
+
fromMs: params.fromMs,
|
|
3237
|
+
toMs: params.toMs,
|
|
3238
|
+
intervalMs: params.intervalMs,
|
|
3239
|
+
refreshClosedTail: params.mode === "signals"
|
|
3240
|
+
});
|
|
3241
|
+
const dataFetchFromMs = dataCoverageFromMs != null && edgesFromMs != null ? Math.max(dataCoverageFromMs, edgesFromMs) : null;
|
|
3242
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
3243
|
+
interval: params.interval,
|
|
3244
|
+
fromMs: params.fromMs,
|
|
3245
|
+
toMs: params.toMs,
|
|
3246
|
+
nowMs: params.nowMs
|
|
3247
|
+
});
|
|
3248
|
+
const liquidationFetchFromMs = confirmedLiquidationWindow ? resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
3249
|
+
ranges: params.liquidationCoverageRanges,
|
|
3250
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
3251
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
3252
|
+
intervalMs: params.intervalMs
|
|
3253
|
+
}) : null;
|
|
3254
|
+
const fetchStarts = [dataFetchFromMs, liquidationFetchFromMs].filter(
|
|
3255
|
+
(value) => value != null
|
|
3256
|
+
);
|
|
3257
|
+
return fetchStarts.length ? Math.min(...fetchStarts) : null;
|
|
3258
|
+
};
|
|
3228
3259
|
var countBackfillWindows = (params) => {
|
|
3229
3260
|
let count = 0;
|
|
3230
3261
|
let cursor = params.fromMs;
|
|
@@ -3288,6 +3319,14 @@ var groupDerivativesContextMissingFetchRanges = (ranges) => {
|
|
|
3288
3319
|
}
|
|
3289
3320
|
return [...groups.entries()].sort(([a], [b]) => a - b).map(([fromMs, items]) => ({ fromMs, items }));
|
|
3290
3321
|
};
|
|
3322
|
+
var getMissingClosedDerivativesSymbols = (params) => {
|
|
3323
|
+
const availableSymbols = new Set(
|
|
3324
|
+
params.rows.filter((row) => row.ts.getTime() === params.expectedTimestamp).map((row) => row.symbol.trim().toUpperCase())
|
|
3325
|
+
);
|
|
3326
|
+
return params.symbols.filter(
|
|
3327
|
+
(symbol) => !availableSymbols.has(symbol.trim().toUpperCase())
|
|
3328
|
+
);
|
|
3329
|
+
};
|
|
3291
3330
|
var coverageKey = (params) => [
|
|
3292
3331
|
params.symbol.trim().toUpperCase(),
|
|
3293
3332
|
params.interval,
|
|
@@ -3552,7 +3591,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3552
3591
|
mode,
|
|
3553
3592
|
startMs,
|
|
3554
3593
|
endMs,
|
|
3555
|
-
preloadStartMs: params.preloadStartMs
|
|
3594
|
+
preloadStartMs: params.preloadStartMs,
|
|
3595
|
+
nowMs: Date.now()
|
|
3556
3596
|
});
|
|
3557
3597
|
if (safeEndMs <= fromMs) {
|
|
3558
3598
|
return skippedBackfillResult2();
|
|
@@ -3567,7 +3607,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3567
3607
|
...resolveDerivativesContextIntervalBackfillWindow({
|
|
3568
3608
|
fromMs,
|
|
3569
3609
|
toMs: safeEndMs,
|
|
3570
|
-
interval
|
|
3610
|
+
interval,
|
|
3611
|
+
closedOnly: mode === "signals"
|
|
3571
3612
|
})
|
|
3572
3613
|
})).filter((item) => item.toMs > item.fromMs);
|
|
3573
3614
|
if (!intervalWindows.length) {
|
|
@@ -3585,15 +3626,33 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3585
3626
|
);
|
|
3586
3627
|
const coverageKeysByInterval = /* @__PURE__ */ new Map();
|
|
3587
3628
|
const coverageRangesByInterval = /* @__PURE__ */ new Map();
|
|
3629
|
+
const liquidationCoverageRangesByInterval = /* @__PURE__ */ new Map();
|
|
3630
|
+
const coverageNowMs = Date.now();
|
|
3588
3631
|
await Promise.all(
|
|
3589
3632
|
intervalWindows.map(async (window2) => {
|
|
3590
|
-
const
|
|
3591
|
-
source: "coinalyze",
|
|
3592
|
-
symbols,
|
|
3633
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
3593
3634
|
interval: window2.interval,
|
|
3594
3635
|
fromMs: window2.fromMs,
|
|
3595
|
-
toMs: window2.toMs
|
|
3636
|
+
toMs: window2.toMs,
|
|
3637
|
+
nowMs: coverageNowMs
|
|
3596
3638
|
});
|
|
3639
|
+
const [coverageRows, liquidationCoverageRows] = await Promise.all([
|
|
3640
|
+
(0, import_timescale2.getDerivativesBackfillCoverage)({
|
|
3641
|
+
source: "coinalyze",
|
|
3642
|
+
symbols,
|
|
3643
|
+
interval: window2.interval,
|
|
3644
|
+
fromMs: window2.fromMs,
|
|
3645
|
+
toMs: window2.toMs
|
|
3646
|
+
}),
|
|
3647
|
+
confirmedLiquidationWindow ? (0, import_timescale2.getDerivativesMetricCoverage)({
|
|
3648
|
+
source: "coinalyze",
|
|
3649
|
+
metric: "liquidation",
|
|
3650
|
+
symbols,
|
|
3651
|
+
interval: window2.interval,
|
|
3652
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
3653
|
+
toMs: confirmedLiquidationWindow.toMs
|
|
3654
|
+
}) : Promise.resolve([])
|
|
3655
|
+
]);
|
|
3597
3656
|
coverageKeysByInterval.set(
|
|
3598
3657
|
window2.interval,
|
|
3599
3658
|
new Set(
|
|
@@ -3615,6 +3674,17 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3615
3674
|
rangesBySymbol.set(symbol, ranges);
|
|
3616
3675
|
}
|
|
3617
3676
|
coverageRangesByInterval.set(window2.interval, rangesBySymbol);
|
|
3677
|
+
const liquidationRangesBySymbol = /* @__PURE__ */ new Map();
|
|
3678
|
+
for (const row of liquidationCoverageRows) {
|
|
3679
|
+
const symbol = row.symbol.toUpperCase();
|
|
3680
|
+
const ranges = liquidationRangesBySymbol.get(symbol) ?? [];
|
|
3681
|
+
ranges.push({ fromMs: row.fromMs, toMs: row.toMs });
|
|
3682
|
+
liquidationRangesBySymbol.set(symbol, ranges);
|
|
3683
|
+
}
|
|
3684
|
+
liquidationCoverageRangesByInterval.set(
|
|
3685
|
+
window2.interval,
|
|
3686
|
+
liquidationRangesBySymbol
|
|
3687
|
+
);
|
|
3618
3688
|
})
|
|
3619
3689
|
);
|
|
3620
3690
|
const cachedWindows = intervalWindows.reduce(
|
|
@@ -3626,7 +3696,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3626
3696
|
}),
|
|
3627
3697
|
0
|
|
3628
3698
|
);
|
|
3629
|
-
const allBackfillWindowsCached = intervalWindows.every((window2) => {
|
|
3699
|
+
const allBackfillWindowsCached = mode !== "signals" && intervalWindows.every((window2) => {
|
|
3630
3700
|
const edgesBySymbol = edgesByInterval.get(window2.interval);
|
|
3631
3701
|
const coverageKeys = coverageKeysByInterval.get(window2.interval);
|
|
3632
3702
|
const backfillWindows = buildBackfillWindows({
|
|
@@ -3639,7 +3709,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3639
3709
|
(symbol) => backfillWindows.every((backfillWindow) => {
|
|
3640
3710
|
const normalizedSymbol = symbol.toUpperCase();
|
|
3641
3711
|
const coverageRanges = coverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [];
|
|
3642
|
-
|
|
3712
|
+
const dataCovered = hasDerivativesWindowCoverage({
|
|
3643
3713
|
edges: edgesBySymbol?.get(normalizedSymbol),
|
|
3644
3714
|
fromMs: backfillWindow.fromMs,
|
|
3645
3715
|
toMs: backfillWindow.toMs
|
|
@@ -3656,6 +3726,19 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3656
3726
|
toMs: backfillWindow.toMs
|
|
3657
3727
|
})
|
|
3658
3728
|
);
|
|
3729
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
3730
|
+
interval: window2.interval,
|
|
3731
|
+
fromMs: backfillWindow.fromMs,
|
|
3732
|
+
toMs: backfillWindow.toMs,
|
|
3733
|
+
nowMs: coverageNowMs
|
|
3734
|
+
});
|
|
3735
|
+
const liquidationCovered = confirmedLiquidationWindow == null || resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
3736
|
+
ranges: liquidationCoverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [],
|
|
3737
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
3738
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
3739
|
+
intervalMs: window2.intervalMs
|
|
3740
|
+
}) == null;
|
|
3741
|
+
return dataCovered && liquidationCovered;
|
|
3659
3742
|
})
|
|
3660
3743
|
);
|
|
3661
3744
|
});
|
|
@@ -3740,6 +3823,11 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3740
3823
|
coverageKeysByInterval.set(interval, coverageKeys);
|
|
3741
3824
|
const coverageRangesBySymbol = coverageRangesByInterval.get(interval) ?? /* @__PURE__ */ new Map();
|
|
3742
3825
|
coverageRangesByInterval.set(interval, coverageRangesBySymbol);
|
|
3826
|
+
const liquidationCoverageRangesBySymbol = liquidationCoverageRangesByInterval.get(interval) ?? /* @__PURE__ */ new Map();
|
|
3827
|
+
liquidationCoverageRangesByInterval.set(
|
|
3828
|
+
interval,
|
|
3829
|
+
liquidationCoverageRangesBySymbol
|
|
3830
|
+
);
|
|
3743
3831
|
for (let batchIdx = 0; batchIdx < symbolBatches.length; batchIdx += 1) {
|
|
3744
3832
|
const batch = symbolBatches[batchIdx];
|
|
3745
3833
|
let cursor = window2.fromMs;
|
|
@@ -3752,30 +3840,26 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3752
3840
|
fromMs: cursor,
|
|
3753
3841
|
toMs
|
|
3754
3842
|
});
|
|
3755
|
-
if (coverageKeys.has(key)) {
|
|
3756
|
-
return null;
|
|
3757
|
-
}
|
|
3758
3843
|
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3759
|
-
const
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
}
|
|
3778
|
-
return { item, fromMs: Math.max(coverageFromMs, edgesFromMs) };
|
|
3844
|
+
const requiredFromMs = resolveDerivativesContextRequiredFetchFromMs(
|
|
3845
|
+
{
|
|
3846
|
+
mode,
|
|
3847
|
+
interval,
|
|
3848
|
+
intervalMs,
|
|
3849
|
+
fromMs: cursor,
|
|
3850
|
+
toMs,
|
|
3851
|
+
nowMs: coverageNowMs,
|
|
3852
|
+
dataCoverageKeyExists: coverageKeys.has(key),
|
|
3853
|
+
dataCoverageRanges: coverageRangesBySymbol.get(normalizedSymbol),
|
|
3854
|
+
liquidationCoverageRanges: liquidationCoverageRangesBySymbol.get(normalizedSymbol),
|
|
3855
|
+
edges: edgesBySymbol.get(normalizedSymbol)
|
|
3856
|
+
}
|
|
3857
|
+
);
|
|
3858
|
+
if (requiredFromMs == null) return null;
|
|
3859
|
+
return {
|
|
3860
|
+
item,
|
|
3861
|
+
fromMs: requiredFromMs
|
|
3862
|
+
};
|
|
3779
3863
|
}).filter(
|
|
3780
3864
|
(item) => item != null
|
|
3781
3865
|
);
|
|
@@ -3789,85 +3873,150 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3789
3873
|
const marketSymbols = missingBatch.map(
|
|
3790
3874
|
(item) => item.marketSymbol
|
|
3791
3875
|
);
|
|
3792
|
-
const
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
metric: "liq",
|
|
3813
|
-
marketSymbols,
|
|
3814
|
-
apiKey,
|
|
3815
|
-
interval,
|
|
3816
|
-
fromMs: group.fromMs,
|
|
3817
|
-
toMs
|
|
3818
|
-
});
|
|
3819
|
-
const rows = missingBatch.flatMap((item) => {
|
|
3820
|
-
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
3821
|
-
const points = (0, import_indicators.mergeCoinalyzeMetrics)({
|
|
3822
|
-
symbol: item.symbol,
|
|
3823
|
-
oiRaw: oiMap.get(marketSymbol) ?? [],
|
|
3824
|
-
fundingRaw: fundingMap.get(marketSymbol) ?? [],
|
|
3825
|
-
liqRaw: liqMap.get(marketSymbol) ?? []
|
|
3876
|
+
const maxClosedBarAttempts = mode === "signals" ? asInt2(
|
|
3877
|
+
process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_MAX_ATTEMPTS,
|
|
3878
|
+
3
|
|
3879
|
+
) : 1;
|
|
3880
|
+
const closedBarRetryDelayMs = asInt2(
|
|
3881
|
+
process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_RETRY_DELAY_MS,
|
|
3882
|
+
2e3
|
|
3883
|
+
);
|
|
3884
|
+
let rows = [];
|
|
3885
|
+
let missingClosedSymbols = [];
|
|
3886
|
+
let liquidationRowsByMarket = /* @__PURE__ */ new Map();
|
|
3887
|
+
for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
|
|
3888
|
+
const oiMap = await fetchMetricBatch({
|
|
3889
|
+
endpoint: oiPath,
|
|
3890
|
+
metric: "oi",
|
|
3891
|
+
marketSymbols,
|
|
3892
|
+
apiKey,
|
|
3893
|
+
interval,
|
|
3894
|
+
fromMs: group.fromMs,
|
|
3895
|
+
toMs
|
|
3826
3896
|
});
|
|
3827
|
-
|
|
3828
|
-
|
|
3897
|
+
const fundingMap = await fetchMetricBatch({
|
|
3898
|
+
endpoint: fundingPath,
|
|
3899
|
+
metric: "funding",
|
|
3900
|
+
marketSymbols,
|
|
3901
|
+
apiKey,
|
|
3902
|
+
interval,
|
|
3903
|
+
fromMs: group.fromMs,
|
|
3904
|
+
toMs
|
|
3905
|
+
});
|
|
3906
|
+
liquidationRowsByMarket = await fetchMetricBatch({
|
|
3907
|
+
endpoint: liqPath,
|
|
3908
|
+
metric: "liq",
|
|
3909
|
+
marketSymbols,
|
|
3910
|
+
apiKey,
|
|
3911
|
+
interval,
|
|
3912
|
+
fromMs: group.fromMs,
|
|
3913
|
+
toMs
|
|
3914
|
+
});
|
|
3915
|
+
rows = missingBatch.flatMap((item) => {
|
|
3916
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
3917
|
+
const points = (0, import_indicators.mergeCoinalyzeMetrics)({
|
|
3918
|
+
symbol: item.symbol,
|
|
3919
|
+
oiRaw: oiMap.get(marketSymbol) ?? [],
|
|
3920
|
+
fundingRaw: fundingMap.get(marketSymbol) ?? [],
|
|
3921
|
+
liqRaw: liquidationRowsByMarket.get(marketSymbol) ?? []
|
|
3922
|
+
});
|
|
3923
|
+
return (0, import_indicators.coinalyzePointsToRows)(points, interval, "coinalyze");
|
|
3924
|
+
});
|
|
3925
|
+
missingClosedSymbols = mode === "signals" ? getMissingClosedDerivativesSymbols({
|
|
3926
|
+
symbols: missingBatch.map((item) => item.symbol),
|
|
3927
|
+
rows,
|
|
3928
|
+
expectedTimestamp: toMs
|
|
3929
|
+
}) : [];
|
|
3930
|
+
if (!missingClosedSymbols.length) break;
|
|
3931
|
+
if (attempt < maxClosedBarAttempts) {
|
|
3932
|
+
await (0, import_async.delay)(closedBarRetryDelayMs);
|
|
3933
|
+
}
|
|
3934
|
+
}
|
|
3935
|
+
if (missingClosedSymbols.length) {
|
|
3936
|
+
throw new Error(
|
|
3937
|
+
`Coinalyze closed ${interval} bar ${new Date(toMs).toISOString()} unavailable for ${missingClosedSymbols.join(",")}`
|
|
3938
|
+
);
|
|
3939
|
+
}
|
|
3829
3940
|
if (rows.length) {
|
|
3830
3941
|
await (0, import_timescale2.upsertDerivatives)(rows);
|
|
3831
3942
|
totalRows += rows.length;
|
|
3832
3943
|
}
|
|
3833
|
-
const
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
(rowsCountBySymbol.get(symbol) ?? 0) + 1
|
|
3839
|
-
);
|
|
3840
|
-
}
|
|
3841
|
-
const coverageRows = missingBatch.map((item) => {
|
|
3842
|
-
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3843
|
-
const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
|
|
3844
|
-
return {
|
|
3845
|
-
source: "coinalyze",
|
|
3846
|
-
symbol: item.symbol,
|
|
3847
|
-
interval,
|
|
3848
|
-
fromMs: cursor,
|
|
3849
|
-
toMs,
|
|
3850
|
-
rowsCount
|
|
3851
|
-
};
|
|
3944
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
3945
|
+
interval,
|
|
3946
|
+
fromMs: group.fromMs,
|
|
3947
|
+
toMs,
|
|
3948
|
+
nowMs: coverageNowMs
|
|
3852
3949
|
});
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3950
|
+
if (confirmedLiquidationWindow) {
|
|
3951
|
+
const metricCoverageRows = missingBatch.map((item) => {
|
|
3952
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
3953
|
+
const eventRowsCount = (liquidationRowsByMarket.get(marketSymbol) ?? []).filter((point) => {
|
|
3954
|
+
const timestamp = (0, import_indicators.toCoinalyzeTimestampMs)(
|
|
3955
|
+
point.t ?? point.ts ?? point.time ?? point.timestamp
|
|
3956
|
+
);
|
|
3957
|
+
return timestamp != null && timestamp >= confirmedLiquidationWindow.fromMs && timestamp <= confirmedLiquidationWindow.toMs;
|
|
3958
|
+
}).length;
|
|
3959
|
+
return {
|
|
3960
|
+
source: "coinalyze",
|
|
3961
|
+
metric: "liquidation",
|
|
3962
|
+
symbol: item.symbol,
|
|
3963
|
+
interval,
|
|
3964
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
3965
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
3966
|
+
eventRowsCount
|
|
3967
|
+
};
|
|
3968
|
+
});
|
|
3969
|
+
await (0, import_timescale2.applyDerivativesMetricCoverage)(metricCoverageRows);
|
|
3970
|
+
for (const coverageRow of metricCoverageRows) {
|
|
3971
|
+
const symbol = coverageRow.symbol.toUpperCase();
|
|
3972
|
+
const ranges = liquidationCoverageRangesBySymbol.get(symbol) ?? [];
|
|
3973
|
+
ranges.push({
|
|
3974
|
+
fromMs: coverageRow.fromMs,
|
|
3975
|
+
toMs: coverageRow.toMs
|
|
3976
|
+
});
|
|
3977
|
+
liquidationCoverageRangesBySymbol.set(symbol, ranges);
|
|
3978
|
+
}
|
|
3979
|
+
}
|
|
3980
|
+
if (mode === "backtest") {
|
|
3981
|
+
const rowsCountBySymbol = /* @__PURE__ */ new Map();
|
|
3982
|
+
for (const row of rows) {
|
|
3983
|
+
const symbol = row.symbol.toUpperCase();
|
|
3984
|
+
rowsCountBySymbol.set(
|
|
3862
3985
|
symbol,
|
|
3986
|
+
(rowsCountBySymbol.get(symbol) ?? 0) + 1
|
|
3987
|
+
);
|
|
3988
|
+
}
|
|
3989
|
+
const coverageRows = missingBatch.map((item) => {
|
|
3990
|
+
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3991
|
+
const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
|
|
3992
|
+
return {
|
|
3993
|
+
source: "coinalyze",
|
|
3994
|
+
symbol: item.symbol,
|
|
3863
3995
|
interval,
|
|
3864
3996
|
fromMs: cursor,
|
|
3865
|
-
toMs
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3997
|
+
toMs,
|
|
3998
|
+
rowsCount
|
|
3999
|
+
};
|
|
4000
|
+
});
|
|
4001
|
+
await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
|
|
4002
|
+
for (const coverageRow of coverageRows) {
|
|
4003
|
+
const symbol = coverageRow.symbol.toUpperCase();
|
|
4004
|
+
edgesBySymbol.set(
|
|
4005
|
+
symbol,
|
|
4006
|
+
extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
|
|
4007
|
+
);
|
|
4008
|
+
coverageKeys.add(
|
|
4009
|
+
coverageKey({
|
|
4010
|
+
symbol,
|
|
4011
|
+
interval,
|
|
4012
|
+
fromMs: cursor,
|
|
4013
|
+
toMs
|
|
4014
|
+
})
|
|
4015
|
+
);
|
|
4016
|
+
const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
|
|
4017
|
+
coverageRanges.push({ fromMs: cursor, toMs });
|
|
4018
|
+
coverageRangesBySymbol.set(symbol, coverageRanges);
|
|
4019
|
+
}
|
|
3871
4020
|
}
|
|
3872
4021
|
}
|
|
3873
4022
|
}
|