@tradejs/cli 2.0.0 → 2.0.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.
- package/dist/cli.js +143 -93
- package/dist/lib/aiTrainResearch.js +0 -1
- package/dist/lib/derivativesContextBackfill.js +127 -83
- package/dist/lib/marketContextPrepare.js +123 -83
- package/dist/scripts/aiTrain.js +0 -1
- package/dist/scripts/backtest.js +123 -83
- package/dist/scripts/derivativesIngest.js +11 -4
- package/dist/scripts/derivativesIngestCoinalyzeAll.js +8 -4
- package/dist/scripts/replay.js +123 -83
- package/dist/scripts/replayRunner.js +123 -83
- package/dist/scripts/runtimeParity.js +123 -83
- package/dist/scripts/signals.js +123 -83
- package/dist/scripts/signalsDaemon.js +123 -83
- package/package.json +9 -9
package/dist/scripts/signals.js
CHANGED
|
@@ -2610,7 +2610,7 @@ var import_userSettings = require("@tradejs/infra/userSettings");
|
|
|
2610
2610
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
2611
2611
|
var DAY_MS2 = 24 * HOUR_MS;
|
|
2612
2612
|
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
2613
|
-
var
|
|
2613
|
+
var SOURCE_INTERVALS = ["15m"];
|
|
2614
2614
|
var coinalyzeIntervalMap = {
|
|
2615
2615
|
"15m": "15min",
|
|
2616
2616
|
"1h": "1hour"
|
|
@@ -2671,10 +2671,7 @@ var isDerivativesContextBackfillEnabled = (env) => {
|
|
|
2671
2671
|
var shouldBackfillDerivativesContextForBacktest = (params) => !params.cacheOnly && (params.aiEnabled || params.mlEnabled) && isBacktestDerivativesContextEnabled();
|
|
2672
2672
|
var shouldBackfillDerivativesContextForSignals = (params) => !params.cacheOnly && isSignalsDerivativesContextEnabled();
|
|
2673
2673
|
var resolveDerivativesContextIntervals = () => {
|
|
2674
|
-
|
|
2675
|
-
process.env.DERIVATIVES_CONTEXT_INTERVALS
|
|
2676
|
-
);
|
|
2677
|
-
return intervals.length ? intervals : DEFAULT_INTERVALS;
|
|
2674
|
+
return [...SOURCE_INTERVALS];
|
|
2678
2675
|
};
|
|
2679
2676
|
var resolveDerivativesContextLookbackMs = () => {
|
|
2680
2677
|
const hours = Number(process.env.DERIVATIVES_CONTEXT_LOOKBACK_HOURS);
|
|
@@ -2709,9 +2706,10 @@ var resolveDerivativesContextBackfillWindow = (params) => {
|
|
|
2709
2706
|
};
|
|
2710
2707
|
var resolveDerivativesContextIntervalBackfillWindow = (params) => {
|
|
2711
2708
|
const intervalMs2 = derivativesIntervalMs(params.interval);
|
|
2709
|
+
const alignedToMs = params.closedOnly ? (0, import_indicators2.getLastClosedDerivativesBarStartMs)(params.toMs, params.interval) : Math.floor(params.toMs / intervalMs2) * intervalMs2;
|
|
2712
2710
|
return {
|
|
2713
2711
|
fromMs: Math.floor(params.fromMs / intervalMs2) * intervalMs2,
|
|
2714
|
-
toMs:
|
|
2712
|
+
toMs: alignedToMs,
|
|
2715
2713
|
intervalMs: intervalMs2
|
|
2716
2714
|
};
|
|
2717
2715
|
};
|
|
@@ -2729,6 +2727,7 @@ var resolveDerivativesContextMissingFetchFromMs = (params) => {
|
|
|
2729
2727
|
}
|
|
2730
2728
|
return null;
|
|
2731
2729
|
};
|
|
2730
|
+
var resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
|
|
2732
2731
|
var countBackfillWindows = (params) => {
|
|
2733
2732
|
let count = 0;
|
|
2734
2733
|
let cursor = params.fromMs;
|
|
@@ -2792,6 +2791,14 @@ var groupDerivativesContextMissingFetchRanges = (ranges) => {
|
|
|
2792
2791
|
}
|
|
2793
2792
|
return [...groups.entries()].sort(([a], [b]) => a - b).map(([fromMs, items]) => ({ fromMs, items }));
|
|
2794
2793
|
};
|
|
2794
|
+
var getMissingClosedDerivativesSymbols = (params) => {
|
|
2795
|
+
const availableSymbols = new Set(
|
|
2796
|
+
params.rows.filter((row) => row.ts.getTime() === params.expectedTimestamp).map((row) => row.symbol.trim().toUpperCase())
|
|
2797
|
+
);
|
|
2798
|
+
return params.symbols.filter(
|
|
2799
|
+
(symbol) => !availableSymbols.has(symbol.trim().toUpperCase())
|
|
2800
|
+
);
|
|
2801
|
+
};
|
|
2795
2802
|
var coverageKey = (params) => [
|
|
2796
2803
|
params.symbol.trim().toUpperCase(),
|
|
2797
2804
|
params.interval,
|
|
@@ -3071,7 +3078,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3071
3078
|
...resolveDerivativesContextIntervalBackfillWindow({
|
|
3072
3079
|
fromMs,
|
|
3073
3080
|
toMs: safeEndMs,
|
|
3074
|
-
interval: interval2
|
|
3081
|
+
interval: interval2,
|
|
3082
|
+
closedOnly: mode === "signals"
|
|
3075
3083
|
})
|
|
3076
3084
|
})).filter((item) => item.toMs > item.fromMs);
|
|
3077
3085
|
if (!intervalWindows.length) {
|
|
@@ -3130,7 +3138,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3130
3138
|
}),
|
|
3131
3139
|
0
|
|
3132
3140
|
);
|
|
3133
|
-
const allBackfillWindowsCached = intervalWindows.every((window2) => {
|
|
3141
|
+
const allBackfillWindowsCached = mode !== "signals" && intervalWindows.every((window2) => {
|
|
3134
3142
|
const edgesBySymbol = edgesByInterval.get(window2.interval);
|
|
3135
3143
|
const coverageKeys = coverageKeysByInterval.get(window2.interval);
|
|
3136
3144
|
const backfillWindows = buildBackfillWindows({
|
|
@@ -3260,7 +3268,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3260
3268
|
return null;
|
|
3261
3269
|
}
|
|
3262
3270
|
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3263
|
-
const coverageFromMs = resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
3271
|
+
const coverageFromMs = mode === "signals" ? cursor : resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
3264
3272
|
ranges: coverageRangesBySymbol.get(normalizedSymbol),
|
|
3265
3273
|
fromMs: cursor,
|
|
3266
3274
|
toMs,
|
|
@@ -3270,16 +3278,20 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3270
3278
|
return null;
|
|
3271
3279
|
}
|
|
3272
3280
|
const edges = edgesBySymbol.get(normalizedSymbol);
|
|
3273
|
-
const edgesFromMs =
|
|
3281
|
+
const edgesFromMs = resolveDerivativesContextFetchFromMs({
|
|
3274
3282
|
edges,
|
|
3275
3283
|
fromMs: cursor,
|
|
3276
3284
|
toMs,
|
|
3277
|
-
intervalMs: intervalMs2
|
|
3285
|
+
intervalMs: intervalMs2,
|
|
3286
|
+
refreshClosedTail: mode === "signals"
|
|
3278
3287
|
});
|
|
3279
3288
|
if (edgesFromMs == null) {
|
|
3280
3289
|
return null;
|
|
3281
3290
|
}
|
|
3282
|
-
return {
|
|
3291
|
+
return {
|
|
3292
|
+
item,
|
|
3293
|
+
fromMs: Math.max(coverageFromMs, edgesFromMs)
|
|
3294
|
+
};
|
|
3283
3295
|
}).filter(
|
|
3284
3296
|
(item) => item != null
|
|
3285
3297
|
);
|
|
@@ -3293,85 +3305,113 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3293
3305
|
const marketSymbols = missingBatch.map(
|
|
3294
3306
|
(item) => item.marketSymbol
|
|
3295
3307
|
);
|
|
3296
|
-
const
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
3325
|
-
const points = (0, import_indicators2.mergeCoinalyzeMetrics)({
|
|
3326
|
-
symbol: item.symbol,
|
|
3327
|
-
oiRaw: oiMap.get(marketSymbol) ?? [],
|
|
3328
|
-
fundingRaw: fundingMap.get(marketSymbol) ?? [],
|
|
3329
|
-
liqRaw: liqMap.get(marketSymbol) ?? []
|
|
3308
|
+
const maxClosedBarAttempts = mode === "signals" ? asInt2(
|
|
3309
|
+
process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_MAX_ATTEMPTS,
|
|
3310
|
+
3
|
|
3311
|
+
) : 1;
|
|
3312
|
+
const closedBarRetryDelayMs = asInt2(
|
|
3313
|
+
process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_RETRY_DELAY_MS,
|
|
3314
|
+
2e3
|
|
3315
|
+
);
|
|
3316
|
+
let rows = [];
|
|
3317
|
+
let missingClosedSymbols = [];
|
|
3318
|
+
for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
|
|
3319
|
+
const oiMap = await fetchMetricBatch({
|
|
3320
|
+
endpoint: oiPath,
|
|
3321
|
+
metric: "oi",
|
|
3322
|
+
marketSymbols,
|
|
3323
|
+
apiKey,
|
|
3324
|
+
interval: interval2,
|
|
3325
|
+
fromMs: group.fromMs,
|
|
3326
|
+
toMs
|
|
3327
|
+
});
|
|
3328
|
+
const fundingMap = await fetchMetricBatch({
|
|
3329
|
+
endpoint: fundingPath,
|
|
3330
|
+
metric: "funding",
|
|
3331
|
+
marketSymbols,
|
|
3332
|
+
apiKey,
|
|
3333
|
+
interval: interval2,
|
|
3334
|
+
fromMs: group.fromMs,
|
|
3335
|
+
toMs
|
|
3330
3336
|
});
|
|
3331
|
-
|
|
3332
|
-
|
|
3337
|
+
const liqMap = await fetchMetricBatch({
|
|
3338
|
+
endpoint: liqPath,
|
|
3339
|
+
metric: "liq",
|
|
3340
|
+
marketSymbols,
|
|
3341
|
+
apiKey,
|
|
3342
|
+
interval: interval2,
|
|
3343
|
+
fromMs: group.fromMs,
|
|
3344
|
+
toMs
|
|
3345
|
+
});
|
|
3346
|
+
rows = missingBatch.flatMap((item) => {
|
|
3347
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
3348
|
+
const points = (0, import_indicators2.mergeCoinalyzeMetrics)({
|
|
3349
|
+
symbol: item.symbol,
|
|
3350
|
+
oiRaw: oiMap.get(marketSymbol) ?? [],
|
|
3351
|
+
fundingRaw: fundingMap.get(marketSymbol) ?? [],
|
|
3352
|
+
liqRaw: liqMap.get(marketSymbol) ?? []
|
|
3353
|
+
});
|
|
3354
|
+
return (0, import_indicators2.coinalyzePointsToRows)(points, interval2, "coinalyze");
|
|
3355
|
+
});
|
|
3356
|
+
missingClosedSymbols = mode === "signals" ? getMissingClosedDerivativesSymbols({
|
|
3357
|
+
symbols: missingBatch.map((item) => item.symbol),
|
|
3358
|
+
rows,
|
|
3359
|
+
expectedTimestamp: toMs
|
|
3360
|
+
}) : [];
|
|
3361
|
+
if (!missingClosedSymbols.length) break;
|
|
3362
|
+
if (attempt < maxClosedBarAttempts) {
|
|
3363
|
+
await (0, import_async.delay)(closedBarRetryDelayMs);
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
if (missingClosedSymbols.length) {
|
|
3367
|
+
throw new Error(
|
|
3368
|
+
`Coinalyze closed ${interval2} bar ${new Date(toMs).toISOString()} unavailable for ${missingClosedSymbols.join(",")}`
|
|
3369
|
+
);
|
|
3370
|
+
}
|
|
3333
3371
|
if (rows.length) {
|
|
3334
3372
|
await (0, import_timescale2.upsertDerivatives)(rows);
|
|
3335
3373
|
totalRows += rows.length;
|
|
3336
3374
|
}
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
const
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
(rowsCountBySymbol.get(symbol) ?? 0) + 1
|
|
3343
|
-
);
|
|
3344
|
-
}
|
|
3345
|
-
const coverageRows = missingBatch.map((item) => {
|
|
3346
|
-
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3347
|
-
const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
|
|
3348
|
-
return {
|
|
3349
|
-
source: "coinalyze",
|
|
3350
|
-
symbol: item.symbol,
|
|
3351
|
-
interval: interval2,
|
|
3352
|
-
fromMs: cursor,
|
|
3353
|
-
toMs,
|
|
3354
|
-
rowsCount
|
|
3355
|
-
};
|
|
3356
|
-
});
|
|
3357
|
-
await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
|
|
3358
|
-
for (const coverageRow of coverageRows) {
|
|
3359
|
-
const symbol = coverageRow.symbol.toUpperCase();
|
|
3360
|
-
edgesBySymbol.set(
|
|
3361
|
-
symbol,
|
|
3362
|
-
extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
|
|
3363
|
-
);
|
|
3364
|
-
coverageKeys.add(
|
|
3365
|
-
coverageKey({
|
|
3375
|
+
if (mode === "backtest") {
|
|
3376
|
+
const rowsCountBySymbol = /* @__PURE__ */ new Map();
|
|
3377
|
+
for (const row of rows) {
|
|
3378
|
+
const symbol = row.symbol.toUpperCase();
|
|
3379
|
+
rowsCountBySymbol.set(
|
|
3366
3380
|
symbol,
|
|
3381
|
+
(rowsCountBySymbol.get(symbol) ?? 0) + 1
|
|
3382
|
+
);
|
|
3383
|
+
}
|
|
3384
|
+
const coverageRows = missingBatch.map((item) => {
|
|
3385
|
+
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3386
|
+
const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
|
|
3387
|
+
return {
|
|
3388
|
+
source: "coinalyze",
|
|
3389
|
+
symbol: item.symbol,
|
|
3367
3390
|
interval: interval2,
|
|
3368
3391
|
fromMs: cursor,
|
|
3369
|
-
toMs
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3392
|
+
toMs,
|
|
3393
|
+
rowsCount
|
|
3394
|
+
};
|
|
3395
|
+
});
|
|
3396
|
+
await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
|
|
3397
|
+
for (const coverageRow of coverageRows) {
|
|
3398
|
+
const symbol = coverageRow.symbol.toUpperCase();
|
|
3399
|
+
edgesBySymbol.set(
|
|
3400
|
+
symbol,
|
|
3401
|
+
extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
|
|
3402
|
+
);
|
|
3403
|
+
coverageKeys.add(
|
|
3404
|
+
coverageKey({
|
|
3405
|
+
symbol,
|
|
3406
|
+
interval: interval2,
|
|
3407
|
+
fromMs: cursor,
|
|
3408
|
+
toMs
|
|
3409
|
+
})
|
|
3410
|
+
);
|
|
3411
|
+
const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
|
|
3412
|
+
coverageRanges.push({ fromMs: cursor, toMs });
|
|
3413
|
+
coverageRangesBySymbol.set(symbol, coverageRanges);
|
|
3414
|
+
}
|
|
3375
3415
|
}
|
|
3376
3416
|
}
|
|
3377
3417
|
}
|
|
@@ -2608,7 +2608,7 @@ var import_userSettings = require("@tradejs/infra/userSettings");
|
|
|
2608
2608
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
2609
2609
|
var DAY_MS2 = 24 * HOUR_MS;
|
|
2610
2610
|
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
2611
|
-
var
|
|
2611
|
+
var SOURCE_INTERVALS = ["15m"];
|
|
2612
2612
|
var coinalyzeIntervalMap = {
|
|
2613
2613
|
"15m": "15min",
|
|
2614
2614
|
"1h": "1hour"
|
|
@@ -2669,10 +2669,7 @@ var isDerivativesContextBackfillEnabled = (env) => {
|
|
|
2669
2669
|
var shouldBackfillDerivativesContextForBacktest = (params) => !params.cacheOnly && (params.aiEnabled || params.mlEnabled) && isBacktestDerivativesContextEnabled();
|
|
2670
2670
|
var shouldBackfillDerivativesContextForSignals = (params) => !params.cacheOnly && isSignalsDerivativesContextEnabled();
|
|
2671
2671
|
var resolveDerivativesContextIntervals = () => {
|
|
2672
|
-
|
|
2673
|
-
process.env.DERIVATIVES_CONTEXT_INTERVALS
|
|
2674
|
-
);
|
|
2675
|
-
return intervals.length ? intervals : DEFAULT_INTERVALS;
|
|
2672
|
+
return [...SOURCE_INTERVALS];
|
|
2676
2673
|
};
|
|
2677
2674
|
var resolveDerivativesContextLookbackMs = () => {
|
|
2678
2675
|
const hours = Number(process.env.DERIVATIVES_CONTEXT_LOOKBACK_HOURS);
|
|
@@ -2707,9 +2704,10 @@ var resolveDerivativesContextBackfillWindow = (params) => {
|
|
|
2707
2704
|
};
|
|
2708
2705
|
var resolveDerivativesContextIntervalBackfillWindow = (params) => {
|
|
2709
2706
|
const intervalMs2 = derivativesIntervalMs(params.interval);
|
|
2707
|
+
const alignedToMs = params.closedOnly ? (0, import_indicators2.getLastClosedDerivativesBarStartMs)(params.toMs, params.interval) : Math.floor(params.toMs / intervalMs2) * intervalMs2;
|
|
2710
2708
|
return {
|
|
2711
2709
|
fromMs: Math.floor(params.fromMs / intervalMs2) * intervalMs2,
|
|
2712
|
-
toMs:
|
|
2710
|
+
toMs: alignedToMs,
|
|
2713
2711
|
intervalMs: intervalMs2
|
|
2714
2712
|
};
|
|
2715
2713
|
};
|
|
@@ -2727,6 +2725,7 @@ var resolveDerivativesContextMissingFetchFromMs = (params) => {
|
|
|
2727
2725
|
}
|
|
2728
2726
|
return null;
|
|
2729
2727
|
};
|
|
2728
|
+
var resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
|
|
2730
2729
|
var countBackfillWindows = (params) => {
|
|
2731
2730
|
let count = 0;
|
|
2732
2731
|
let cursor = params.fromMs;
|
|
@@ -2790,6 +2789,14 @@ var groupDerivativesContextMissingFetchRanges = (ranges) => {
|
|
|
2790
2789
|
}
|
|
2791
2790
|
return [...groups.entries()].sort(([a], [b]) => a - b).map(([fromMs, items]) => ({ fromMs, items }));
|
|
2792
2791
|
};
|
|
2792
|
+
var getMissingClosedDerivativesSymbols = (params) => {
|
|
2793
|
+
const availableSymbols = new Set(
|
|
2794
|
+
params.rows.filter((row) => row.ts.getTime() === params.expectedTimestamp).map((row) => row.symbol.trim().toUpperCase())
|
|
2795
|
+
);
|
|
2796
|
+
return params.symbols.filter(
|
|
2797
|
+
(symbol) => !availableSymbols.has(symbol.trim().toUpperCase())
|
|
2798
|
+
);
|
|
2799
|
+
};
|
|
2793
2800
|
var coverageKey = (params) => [
|
|
2794
2801
|
params.symbol.trim().toUpperCase(),
|
|
2795
2802
|
params.interval,
|
|
@@ -3069,7 +3076,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3069
3076
|
...resolveDerivativesContextIntervalBackfillWindow({
|
|
3070
3077
|
fromMs,
|
|
3071
3078
|
toMs: safeEndMs,
|
|
3072
|
-
interval: interval2
|
|
3079
|
+
interval: interval2,
|
|
3080
|
+
closedOnly: mode === "signals"
|
|
3073
3081
|
})
|
|
3074
3082
|
})).filter((item) => item.toMs > item.fromMs);
|
|
3075
3083
|
if (!intervalWindows.length) {
|
|
@@ -3128,7 +3136,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3128
3136
|
}),
|
|
3129
3137
|
0
|
|
3130
3138
|
);
|
|
3131
|
-
const allBackfillWindowsCached = intervalWindows.every((window2) => {
|
|
3139
|
+
const allBackfillWindowsCached = mode !== "signals" && intervalWindows.every((window2) => {
|
|
3132
3140
|
const edgesBySymbol = edgesByInterval.get(window2.interval);
|
|
3133
3141
|
const coverageKeys = coverageKeysByInterval.get(window2.interval);
|
|
3134
3142
|
const backfillWindows = buildBackfillWindows({
|
|
@@ -3258,7 +3266,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3258
3266
|
return null;
|
|
3259
3267
|
}
|
|
3260
3268
|
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3261
|
-
const coverageFromMs = resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
3269
|
+
const coverageFromMs = mode === "signals" ? cursor : resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
3262
3270
|
ranges: coverageRangesBySymbol.get(normalizedSymbol),
|
|
3263
3271
|
fromMs: cursor,
|
|
3264
3272
|
toMs,
|
|
@@ -3268,16 +3276,20 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3268
3276
|
return null;
|
|
3269
3277
|
}
|
|
3270
3278
|
const edges = edgesBySymbol.get(normalizedSymbol);
|
|
3271
|
-
const edgesFromMs =
|
|
3279
|
+
const edgesFromMs = resolveDerivativesContextFetchFromMs({
|
|
3272
3280
|
edges,
|
|
3273
3281
|
fromMs: cursor,
|
|
3274
3282
|
toMs,
|
|
3275
|
-
intervalMs: intervalMs2
|
|
3283
|
+
intervalMs: intervalMs2,
|
|
3284
|
+
refreshClosedTail: mode === "signals"
|
|
3276
3285
|
});
|
|
3277
3286
|
if (edgesFromMs == null) {
|
|
3278
3287
|
return null;
|
|
3279
3288
|
}
|
|
3280
|
-
return {
|
|
3289
|
+
return {
|
|
3290
|
+
item,
|
|
3291
|
+
fromMs: Math.max(coverageFromMs, edgesFromMs)
|
|
3292
|
+
};
|
|
3281
3293
|
}).filter(
|
|
3282
3294
|
(item) => item != null
|
|
3283
3295
|
);
|
|
@@ -3291,85 +3303,113 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3291
3303
|
const marketSymbols = missingBatch.map(
|
|
3292
3304
|
(item) => item.marketSymbol
|
|
3293
3305
|
);
|
|
3294
|
-
const
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
3323
|
-
const points = (0, import_indicators2.mergeCoinalyzeMetrics)({
|
|
3324
|
-
symbol: item.symbol,
|
|
3325
|
-
oiRaw: oiMap.get(marketSymbol) ?? [],
|
|
3326
|
-
fundingRaw: fundingMap.get(marketSymbol) ?? [],
|
|
3327
|
-
liqRaw: liqMap.get(marketSymbol) ?? []
|
|
3306
|
+
const maxClosedBarAttempts = mode === "signals" ? asInt2(
|
|
3307
|
+
process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_MAX_ATTEMPTS,
|
|
3308
|
+
3
|
|
3309
|
+
) : 1;
|
|
3310
|
+
const closedBarRetryDelayMs = asInt2(
|
|
3311
|
+
process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_RETRY_DELAY_MS,
|
|
3312
|
+
2e3
|
|
3313
|
+
);
|
|
3314
|
+
let rows = [];
|
|
3315
|
+
let missingClosedSymbols = [];
|
|
3316
|
+
for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
|
|
3317
|
+
const oiMap = await fetchMetricBatch({
|
|
3318
|
+
endpoint: oiPath,
|
|
3319
|
+
metric: "oi",
|
|
3320
|
+
marketSymbols,
|
|
3321
|
+
apiKey,
|
|
3322
|
+
interval: interval2,
|
|
3323
|
+
fromMs: group.fromMs,
|
|
3324
|
+
toMs
|
|
3325
|
+
});
|
|
3326
|
+
const fundingMap = await fetchMetricBatch({
|
|
3327
|
+
endpoint: fundingPath,
|
|
3328
|
+
metric: "funding",
|
|
3329
|
+
marketSymbols,
|
|
3330
|
+
apiKey,
|
|
3331
|
+
interval: interval2,
|
|
3332
|
+
fromMs: group.fromMs,
|
|
3333
|
+
toMs
|
|
3328
3334
|
});
|
|
3329
|
-
|
|
3330
|
-
|
|
3335
|
+
const liqMap = await fetchMetricBatch({
|
|
3336
|
+
endpoint: liqPath,
|
|
3337
|
+
metric: "liq",
|
|
3338
|
+
marketSymbols,
|
|
3339
|
+
apiKey,
|
|
3340
|
+
interval: interval2,
|
|
3341
|
+
fromMs: group.fromMs,
|
|
3342
|
+
toMs
|
|
3343
|
+
});
|
|
3344
|
+
rows = missingBatch.flatMap((item) => {
|
|
3345
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
3346
|
+
const points = (0, import_indicators2.mergeCoinalyzeMetrics)({
|
|
3347
|
+
symbol: item.symbol,
|
|
3348
|
+
oiRaw: oiMap.get(marketSymbol) ?? [],
|
|
3349
|
+
fundingRaw: fundingMap.get(marketSymbol) ?? [],
|
|
3350
|
+
liqRaw: liqMap.get(marketSymbol) ?? []
|
|
3351
|
+
});
|
|
3352
|
+
return (0, import_indicators2.coinalyzePointsToRows)(points, interval2, "coinalyze");
|
|
3353
|
+
});
|
|
3354
|
+
missingClosedSymbols = mode === "signals" ? getMissingClosedDerivativesSymbols({
|
|
3355
|
+
symbols: missingBatch.map((item) => item.symbol),
|
|
3356
|
+
rows,
|
|
3357
|
+
expectedTimestamp: toMs
|
|
3358
|
+
}) : [];
|
|
3359
|
+
if (!missingClosedSymbols.length) break;
|
|
3360
|
+
if (attempt < maxClosedBarAttempts) {
|
|
3361
|
+
await (0, import_async.delay)(closedBarRetryDelayMs);
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
if (missingClosedSymbols.length) {
|
|
3365
|
+
throw new Error(
|
|
3366
|
+
`Coinalyze closed ${interval2} bar ${new Date(toMs).toISOString()} unavailable for ${missingClosedSymbols.join(",")}`
|
|
3367
|
+
);
|
|
3368
|
+
}
|
|
3331
3369
|
if (rows.length) {
|
|
3332
3370
|
await (0, import_timescale2.upsertDerivatives)(rows);
|
|
3333
3371
|
totalRows += rows.length;
|
|
3334
3372
|
}
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
const
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
(rowsCountBySymbol.get(symbol) ?? 0) + 1
|
|
3341
|
-
);
|
|
3342
|
-
}
|
|
3343
|
-
const coverageRows = missingBatch.map((item) => {
|
|
3344
|
-
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3345
|
-
const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
|
|
3346
|
-
return {
|
|
3347
|
-
source: "coinalyze",
|
|
3348
|
-
symbol: item.symbol,
|
|
3349
|
-
interval: interval2,
|
|
3350
|
-
fromMs: cursor,
|
|
3351
|
-
toMs,
|
|
3352
|
-
rowsCount
|
|
3353
|
-
};
|
|
3354
|
-
});
|
|
3355
|
-
await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
|
|
3356
|
-
for (const coverageRow of coverageRows) {
|
|
3357
|
-
const symbol = coverageRow.symbol.toUpperCase();
|
|
3358
|
-
edgesBySymbol.set(
|
|
3359
|
-
symbol,
|
|
3360
|
-
extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
|
|
3361
|
-
);
|
|
3362
|
-
coverageKeys.add(
|
|
3363
|
-
coverageKey({
|
|
3373
|
+
if (mode === "backtest") {
|
|
3374
|
+
const rowsCountBySymbol = /* @__PURE__ */ new Map();
|
|
3375
|
+
for (const row of rows) {
|
|
3376
|
+
const symbol = row.symbol.toUpperCase();
|
|
3377
|
+
rowsCountBySymbol.set(
|
|
3364
3378
|
symbol,
|
|
3379
|
+
(rowsCountBySymbol.get(symbol) ?? 0) + 1
|
|
3380
|
+
);
|
|
3381
|
+
}
|
|
3382
|
+
const coverageRows = missingBatch.map((item) => {
|
|
3383
|
+
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3384
|
+
const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
|
|
3385
|
+
return {
|
|
3386
|
+
source: "coinalyze",
|
|
3387
|
+
symbol: item.symbol,
|
|
3365
3388
|
interval: interval2,
|
|
3366
3389
|
fromMs: cursor,
|
|
3367
|
-
toMs
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3390
|
+
toMs,
|
|
3391
|
+
rowsCount
|
|
3392
|
+
};
|
|
3393
|
+
});
|
|
3394
|
+
await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
|
|
3395
|
+
for (const coverageRow of coverageRows) {
|
|
3396
|
+
const symbol = coverageRow.symbol.toUpperCase();
|
|
3397
|
+
edgesBySymbol.set(
|
|
3398
|
+
symbol,
|
|
3399
|
+
extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
|
|
3400
|
+
);
|
|
3401
|
+
coverageKeys.add(
|
|
3402
|
+
coverageKey({
|
|
3403
|
+
symbol,
|
|
3404
|
+
interval: interval2,
|
|
3405
|
+
fromMs: cursor,
|
|
3406
|
+
toMs
|
|
3407
|
+
})
|
|
3408
|
+
);
|
|
3409
|
+
const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
|
|
3410
|
+
coverageRanges.push({ fromMs: cursor, toMs });
|
|
3411
|
+
coverageRangesBySymbol.set(symbol, coverageRanges);
|
|
3412
|
+
}
|
|
3373
3413
|
}
|
|
3374
3414
|
}
|
|
3375
3415
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Official CLI for the TradeJS TypeScript framework: infra setup, backtests, signals, bots, and ML workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -29,14 +29,14 @@
|
|
|
29
29
|
"tradejs": "dist/cli.js"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@tradejs/base": "^2.0.
|
|
33
|
-
"@tradejs/connectors": "^2.0.
|
|
34
|
-
"@tradejs/core": "^2.0.
|
|
35
|
-
"@tradejs/indicators": "^2.0.
|
|
36
|
-
"@tradejs/infra": "^2.0.
|
|
37
|
-
"@tradejs/node": "^2.0.
|
|
38
|
-
"@tradejs/strategies": "^2.0.
|
|
39
|
-
"@tradejs/types": "^2.0.
|
|
32
|
+
"@tradejs/base": "^2.0.1",
|
|
33
|
+
"@tradejs/connectors": "^2.0.1",
|
|
34
|
+
"@tradejs/core": "^2.0.1",
|
|
35
|
+
"@tradejs/indicators": "^2.0.1",
|
|
36
|
+
"@tradejs/infra": "^2.0.1",
|
|
37
|
+
"@tradejs/node": "^2.0.1",
|
|
38
|
+
"@tradejs/strategies": "^2.0.1",
|
|
39
|
+
"@tradejs/types": "^2.0.1",
|
|
40
40
|
"args": "^5.0.3",
|
|
41
41
|
"bcryptjs": "^2.4.3",
|
|
42
42
|
"chalk": "4.1.2",
|