@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.
@@ -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 DEFAULT_INTERVALS = ["15m", "1h"];
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
- const intervals = (0, import_indicators2.normalizeDerivativesIntervals)(
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: Math.floor(params.toMs / intervalMs2) * intervalMs2,
2710
+ toMs: alignedToMs,
2713
2711
  intervalMs: intervalMs2
2714
2712
  };
2715
2713
  };
@@ -2727,6 +2725,39 @@ var resolveDerivativesContextMissingFetchFromMs = (params) => {
2727
2725
  }
2728
2726
  return null;
2729
2727
  };
2728
+ var resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
2729
+ var resolveDerivativesContextRequiredFetchFromMs = (params) => {
2730
+ const dataCoverageFromMs = params.dataCoverageKeyExists ? null : params.mode === "signals" ? params.fromMs : resolveDerivativesContextMissingCoverageFetchFromMs({
2731
+ ranges: params.dataCoverageRanges,
2732
+ fromMs: params.fromMs,
2733
+ toMs: params.toMs,
2734
+ intervalMs: params.intervalMs
2735
+ });
2736
+ const edgesFromMs = dataCoverageFromMs == null ? null : resolveDerivativesContextFetchFromMs({
2737
+ edges: params.edges,
2738
+ fromMs: params.fromMs,
2739
+ toMs: params.toMs,
2740
+ intervalMs: params.intervalMs,
2741
+ refreshClosedTail: params.mode === "signals"
2742
+ });
2743
+ const dataFetchFromMs = dataCoverageFromMs != null && edgesFromMs != null ? Math.max(dataCoverageFromMs, edgesFromMs) : null;
2744
+ const confirmedLiquidationWindow = (0, import_indicators2.resolveCoinalyzeConfirmedIntradayCoverage)({
2745
+ interval: params.interval,
2746
+ fromMs: params.fromMs,
2747
+ toMs: params.toMs,
2748
+ nowMs: params.nowMs
2749
+ });
2750
+ const liquidationFetchFromMs = confirmedLiquidationWindow ? resolveDerivativesContextMissingCoverageFetchFromMs({
2751
+ ranges: params.liquidationCoverageRanges,
2752
+ fromMs: confirmedLiquidationWindow.fromMs,
2753
+ toMs: confirmedLiquidationWindow.toMs,
2754
+ intervalMs: params.intervalMs
2755
+ }) : null;
2756
+ const fetchStarts = [dataFetchFromMs, liquidationFetchFromMs].filter(
2757
+ (value) => value != null
2758
+ );
2759
+ return fetchStarts.length ? Math.min(...fetchStarts) : null;
2760
+ };
2730
2761
  var countBackfillWindows = (params) => {
2731
2762
  let count = 0;
2732
2763
  let cursor = params.fromMs;
@@ -2790,6 +2821,14 @@ var groupDerivativesContextMissingFetchRanges = (ranges) => {
2790
2821
  }
2791
2822
  return [...groups.entries()].sort(([a], [b]) => a - b).map(([fromMs, items]) => ({ fromMs, items }));
2792
2823
  };
2824
+ var getMissingClosedDerivativesSymbols = (params) => {
2825
+ const availableSymbols = new Set(
2826
+ params.rows.filter((row) => row.ts.getTime() === params.expectedTimestamp).map((row) => row.symbol.trim().toUpperCase())
2827
+ );
2828
+ return params.symbols.filter(
2829
+ (symbol) => !availableSymbols.has(symbol.trim().toUpperCase())
2830
+ );
2831
+ };
2793
2832
  var coverageKey = (params) => [
2794
2833
  params.symbol.trim().toUpperCase(),
2795
2834
  params.interval,
@@ -3054,7 +3093,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3054
3093
  mode,
3055
3094
  startMs,
3056
3095
  endMs,
3057
- preloadStartMs: params.preloadStartMs
3096
+ preloadStartMs: params.preloadStartMs,
3097
+ nowMs: Date.now()
3058
3098
  });
3059
3099
  if (safeEndMs <= fromMs) {
3060
3100
  return skippedBackfillResult2();
@@ -3069,7 +3109,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3069
3109
  ...resolveDerivativesContextIntervalBackfillWindow({
3070
3110
  fromMs,
3071
3111
  toMs: safeEndMs,
3072
- interval: interval2
3112
+ interval: interval2,
3113
+ closedOnly: mode === "signals"
3073
3114
  })
3074
3115
  })).filter((item) => item.toMs > item.fromMs);
3075
3116
  if (!intervalWindows.length) {
@@ -3087,15 +3128,33 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3087
3128
  );
3088
3129
  const coverageKeysByInterval = /* @__PURE__ */ new Map();
3089
3130
  const coverageRangesByInterval = /* @__PURE__ */ new Map();
3131
+ const liquidationCoverageRangesByInterval = /* @__PURE__ */ new Map();
3132
+ const coverageNowMs = Date.now();
3090
3133
  await Promise.all(
3091
3134
  intervalWindows.map(async (window2) => {
3092
- const coverageRows = await (0, import_timescale2.getDerivativesBackfillCoverage)({
3093
- source: "coinalyze",
3094
- symbols,
3135
+ const confirmedLiquidationWindow = (0, import_indicators2.resolveCoinalyzeConfirmedIntradayCoverage)({
3095
3136
  interval: window2.interval,
3096
3137
  fromMs: window2.fromMs,
3097
- toMs: window2.toMs
3138
+ toMs: window2.toMs,
3139
+ nowMs: coverageNowMs
3098
3140
  });
3141
+ const [coverageRows, liquidationCoverageRows] = await Promise.all([
3142
+ (0, import_timescale2.getDerivativesBackfillCoverage)({
3143
+ source: "coinalyze",
3144
+ symbols,
3145
+ interval: window2.interval,
3146
+ fromMs: window2.fromMs,
3147
+ toMs: window2.toMs
3148
+ }),
3149
+ confirmedLiquidationWindow ? (0, import_timescale2.getDerivativesMetricCoverage)({
3150
+ source: "coinalyze",
3151
+ metric: "liquidation",
3152
+ symbols,
3153
+ interval: window2.interval,
3154
+ fromMs: confirmedLiquidationWindow.fromMs,
3155
+ toMs: confirmedLiquidationWindow.toMs
3156
+ }) : Promise.resolve([])
3157
+ ]);
3099
3158
  coverageKeysByInterval.set(
3100
3159
  window2.interval,
3101
3160
  new Set(
@@ -3117,6 +3176,17 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3117
3176
  rangesBySymbol.set(symbol, ranges);
3118
3177
  }
3119
3178
  coverageRangesByInterval.set(window2.interval, rangesBySymbol);
3179
+ const liquidationRangesBySymbol = /* @__PURE__ */ new Map();
3180
+ for (const row of liquidationCoverageRows) {
3181
+ const symbol = row.symbol.toUpperCase();
3182
+ const ranges = liquidationRangesBySymbol.get(symbol) ?? [];
3183
+ ranges.push({ fromMs: row.fromMs, toMs: row.toMs });
3184
+ liquidationRangesBySymbol.set(symbol, ranges);
3185
+ }
3186
+ liquidationCoverageRangesByInterval.set(
3187
+ window2.interval,
3188
+ liquidationRangesBySymbol
3189
+ );
3120
3190
  })
3121
3191
  );
3122
3192
  const cachedWindows = intervalWindows.reduce(
@@ -3128,7 +3198,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3128
3198
  }),
3129
3199
  0
3130
3200
  );
3131
- const allBackfillWindowsCached = intervalWindows.every((window2) => {
3201
+ const allBackfillWindowsCached = mode !== "signals" && intervalWindows.every((window2) => {
3132
3202
  const edgesBySymbol = edgesByInterval.get(window2.interval);
3133
3203
  const coverageKeys = coverageKeysByInterval.get(window2.interval);
3134
3204
  const backfillWindows = buildBackfillWindows({
@@ -3141,7 +3211,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3141
3211
  (symbol) => backfillWindows.every((backfillWindow) => {
3142
3212
  const normalizedSymbol = symbol.toUpperCase();
3143
3213
  const coverageRanges = coverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [];
3144
- return hasDerivativesWindowCoverage({
3214
+ const dataCovered = hasDerivativesWindowCoverage({
3145
3215
  edges: edgesBySymbol?.get(normalizedSymbol),
3146
3216
  fromMs: backfillWindow.fromMs,
3147
3217
  toMs: backfillWindow.toMs
@@ -3158,6 +3228,19 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3158
3228
  toMs: backfillWindow.toMs
3159
3229
  })
3160
3230
  );
3231
+ const confirmedLiquidationWindow = (0, import_indicators2.resolveCoinalyzeConfirmedIntradayCoverage)({
3232
+ interval: window2.interval,
3233
+ fromMs: backfillWindow.fromMs,
3234
+ toMs: backfillWindow.toMs,
3235
+ nowMs: coverageNowMs
3236
+ });
3237
+ const liquidationCovered = confirmedLiquidationWindow == null || resolveDerivativesContextMissingCoverageFetchFromMs({
3238
+ ranges: liquidationCoverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [],
3239
+ fromMs: confirmedLiquidationWindow.fromMs,
3240
+ toMs: confirmedLiquidationWindow.toMs,
3241
+ intervalMs: window2.intervalMs
3242
+ }) == null;
3243
+ return dataCovered && liquidationCovered;
3161
3244
  })
3162
3245
  );
3163
3246
  });
@@ -3242,6 +3325,11 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3242
3325
  coverageKeysByInterval.set(interval2, coverageKeys);
3243
3326
  const coverageRangesBySymbol = coverageRangesByInterval.get(interval2) ?? /* @__PURE__ */ new Map();
3244
3327
  coverageRangesByInterval.set(interval2, coverageRangesBySymbol);
3328
+ const liquidationCoverageRangesBySymbol = liquidationCoverageRangesByInterval.get(interval2) ?? /* @__PURE__ */ new Map();
3329
+ liquidationCoverageRangesByInterval.set(
3330
+ interval2,
3331
+ liquidationCoverageRangesBySymbol
3332
+ );
3245
3333
  for (let batchIdx = 0; batchIdx < symbolBatches.length; batchIdx += 1) {
3246
3334
  const batch = symbolBatches[batchIdx];
3247
3335
  let cursor = window2.fromMs;
@@ -3254,30 +3342,26 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3254
3342
  fromMs: cursor,
3255
3343
  toMs
3256
3344
  });
3257
- if (coverageKeys.has(key)) {
3258
- return null;
3259
- }
3260
3345
  const normalizedSymbol = item.symbol.toUpperCase();
3261
- const coverageFromMs = resolveDerivativesContextMissingCoverageFetchFromMs({
3262
- ranges: coverageRangesBySymbol.get(normalizedSymbol),
3263
- fromMs: cursor,
3264
- toMs,
3265
- intervalMs: intervalMs2
3266
- });
3267
- if (coverageFromMs == null) {
3268
- return null;
3269
- }
3270
- const edges = edgesBySymbol.get(normalizedSymbol);
3271
- const edgesFromMs = resolveDerivativesContextMissingFetchFromMs({
3272
- edges,
3273
- fromMs: cursor,
3274
- toMs,
3275
- intervalMs: intervalMs2
3276
- });
3277
- if (edgesFromMs == null) {
3278
- return null;
3279
- }
3280
- return { item, fromMs: Math.max(coverageFromMs, edgesFromMs) };
3346
+ const requiredFromMs = resolveDerivativesContextRequiredFetchFromMs(
3347
+ {
3348
+ mode,
3349
+ interval: interval2,
3350
+ intervalMs: intervalMs2,
3351
+ fromMs: cursor,
3352
+ toMs,
3353
+ nowMs: coverageNowMs,
3354
+ dataCoverageKeyExists: coverageKeys.has(key),
3355
+ dataCoverageRanges: coverageRangesBySymbol.get(normalizedSymbol),
3356
+ liquidationCoverageRanges: liquidationCoverageRangesBySymbol.get(normalizedSymbol),
3357
+ edges: edgesBySymbol.get(normalizedSymbol)
3358
+ }
3359
+ );
3360
+ if (requiredFromMs == null) return null;
3361
+ return {
3362
+ item,
3363
+ fromMs: requiredFromMs
3364
+ };
3281
3365
  }).filter(
3282
3366
  (item) => item != null
3283
3367
  );
@@ -3291,85 +3375,150 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3291
3375
  const marketSymbols = missingBatch.map(
3292
3376
  (item) => item.marketSymbol
3293
3377
  );
3294
- const oiMap = await fetchMetricBatch({
3295
- endpoint: oiPath,
3296
- metric: "oi",
3297
- marketSymbols,
3298
- apiKey,
3299
- interval: interval2,
3300
- fromMs: group.fromMs,
3301
- toMs
3302
- });
3303
- const fundingMap = await fetchMetricBatch({
3304
- endpoint: fundingPath,
3305
- metric: "funding",
3306
- marketSymbols,
3307
- apiKey,
3308
- interval: interval2,
3309
- fromMs: group.fromMs,
3310
- toMs
3311
- });
3312
- const liqMap = await fetchMetricBatch({
3313
- endpoint: liqPath,
3314
- metric: "liq",
3315
- marketSymbols,
3316
- apiKey,
3317
- interval: interval2,
3318
- fromMs: group.fromMs,
3319
- toMs
3320
- });
3321
- const rows = missingBatch.flatMap((item) => {
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) ?? []
3378
+ const maxClosedBarAttempts = mode === "signals" ? asInt2(
3379
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_MAX_ATTEMPTS,
3380
+ 3
3381
+ ) : 1;
3382
+ const closedBarRetryDelayMs = asInt2(
3383
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_RETRY_DELAY_MS,
3384
+ 2e3
3385
+ );
3386
+ let rows = [];
3387
+ let missingClosedSymbols = [];
3388
+ let liquidationRowsByMarket = /* @__PURE__ */ new Map();
3389
+ for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
3390
+ const oiMap = await fetchMetricBatch({
3391
+ endpoint: oiPath,
3392
+ metric: "oi",
3393
+ marketSymbols,
3394
+ apiKey,
3395
+ interval: interval2,
3396
+ fromMs: group.fromMs,
3397
+ toMs
3328
3398
  });
3329
- return (0, import_indicators2.coinalyzePointsToRows)(points, interval2, "coinalyze");
3330
- });
3399
+ const fundingMap = await fetchMetricBatch({
3400
+ endpoint: fundingPath,
3401
+ metric: "funding",
3402
+ marketSymbols,
3403
+ apiKey,
3404
+ interval: interval2,
3405
+ fromMs: group.fromMs,
3406
+ toMs
3407
+ });
3408
+ liquidationRowsByMarket = await fetchMetricBatch({
3409
+ endpoint: liqPath,
3410
+ metric: "liq",
3411
+ marketSymbols,
3412
+ apiKey,
3413
+ interval: interval2,
3414
+ fromMs: group.fromMs,
3415
+ toMs
3416
+ });
3417
+ rows = missingBatch.flatMap((item) => {
3418
+ const marketSymbol = item.marketSymbol.toUpperCase();
3419
+ const points = (0, import_indicators2.mergeCoinalyzeMetrics)({
3420
+ symbol: item.symbol,
3421
+ oiRaw: oiMap.get(marketSymbol) ?? [],
3422
+ fundingRaw: fundingMap.get(marketSymbol) ?? [],
3423
+ liqRaw: liquidationRowsByMarket.get(marketSymbol) ?? []
3424
+ });
3425
+ return (0, import_indicators2.coinalyzePointsToRows)(points, interval2, "coinalyze");
3426
+ });
3427
+ missingClosedSymbols = mode === "signals" ? getMissingClosedDerivativesSymbols({
3428
+ symbols: missingBatch.map((item) => item.symbol),
3429
+ rows,
3430
+ expectedTimestamp: toMs
3431
+ }) : [];
3432
+ if (!missingClosedSymbols.length) break;
3433
+ if (attempt < maxClosedBarAttempts) {
3434
+ await (0, import_async.delay)(closedBarRetryDelayMs);
3435
+ }
3436
+ }
3437
+ if (missingClosedSymbols.length) {
3438
+ throw new Error(
3439
+ `Coinalyze closed ${interval2} bar ${new Date(toMs).toISOString()} unavailable for ${missingClosedSymbols.join(",")}`
3440
+ );
3441
+ }
3331
3442
  if (rows.length) {
3332
3443
  await (0, import_timescale2.upsertDerivatives)(rows);
3333
3444
  totalRows += rows.length;
3334
3445
  }
3335
- const rowsCountBySymbol = /* @__PURE__ */ new Map();
3336
- for (const row of rows) {
3337
- const symbol = row.symbol.toUpperCase();
3338
- rowsCountBySymbol.set(
3339
- symbol,
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
- };
3446
+ const confirmedLiquidationWindow = (0, import_indicators2.resolveCoinalyzeConfirmedIntradayCoverage)({
3447
+ interval: interval2,
3448
+ fromMs: group.fromMs,
3449
+ toMs,
3450
+ nowMs: coverageNowMs
3354
3451
  });
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({
3452
+ if (confirmedLiquidationWindow) {
3453
+ const metricCoverageRows = missingBatch.map((item) => {
3454
+ const marketSymbol = item.marketSymbol.toUpperCase();
3455
+ const eventRowsCount = (liquidationRowsByMarket.get(marketSymbol) ?? []).filter((point) => {
3456
+ const timestamp = (0, import_indicators2.toCoinalyzeTimestampMs)(
3457
+ point.t ?? point.ts ?? point.time ?? point.timestamp
3458
+ );
3459
+ return timestamp != null && timestamp >= confirmedLiquidationWindow.fromMs && timestamp <= confirmedLiquidationWindow.toMs;
3460
+ }).length;
3461
+ return {
3462
+ source: "coinalyze",
3463
+ metric: "liquidation",
3464
+ symbol: item.symbol,
3465
+ interval: interval2,
3466
+ fromMs: confirmedLiquidationWindow.fromMs,
3467
+ toMs: confirmedLiquidationWindow.toMs,
3468
+ eventRowsCount
3469
+ };
3470
+ });
3471
+ await (0, import_timescale2.applyDerivativesMetricCoverage)(metricCoverageRows);
3472
+ for (const coverageRow of metricCoverageRows) {
3473
+ const symbol = coverageRow.symbol.toUpperCase();
3474
+ const ranges = liquidationCoverageRangesBySymbol.get(symbol) ?? [];
3475
+ ranges.push({
3476
+ fromMs: coverageRow.fromMs,
3477
+ toMs: coverageRow.toMs
3478
+ });
3479
+ liquidationCoverageRangesBySymbol.set(symbol, ranges);
3480
+ }
3481
+ }
3482
+ if (mode === "backtest") {
3483
+ const rowsCountBySymbol = /* @__PURE__ */ new Map();
3484
+ for (const row of rows) {
3485
+ const symbol = row.symbol.toUpperCase();
3486
+ rowsCountBySymbol.set(
3364
3487
  symbol,
3488
+ (rowsCountBySymbol.get(symbol) ?? 0) + 1
3489
+ );
3490
+ }
3491
+ const coverageRows = missingBatch.map((item) => {
3492
+ const normalizedSymbol = item.symbol.toUpperCase();
3493
+ const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
3494
+ return {
3495
+ source: "coinalyze",
3496
+ symbol: item.symbol,
3365
3497
  interval: interval2,
3366
3498
  fromMs: cursor,
3367
- toMs
3368
- })
3369
- );
3370
- const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
3371
- coverageRanges.push({ fromMs: cursor, toMs });
3372
- coverageRangesBySymbol.set(symbol, coverageRanges);
3499
+ toMs,
3500
+ rowsCount
3501
+ };
3502
+ });
3503
+ await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
3504
+ for (const coverageRow of coverageRows) {
3505
+ const symbol = coverageRow.symbol.toUpperCase();
3506
+ edgesBySymbol.set(
3507
+ symbol,
3508
+ extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
3509
+ );
3510
+ coverageKeys.add(
3511
+ coverageKey({
3512
+ symbol,
3513
+ interval: interval2,
3514
+ fromMs: cursor,
3515
+ toMs
3516
+ })
3517
+ );
3518
+ const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
3519
+ coverageRanges.push({ fromMs: cursor, toMs });
3520
+ coverageRangesBySymbol.set(symbol, coverageRanges);
3521
+ }
3373
3522
  }
3374
3523
  }
3375
3524
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/cli",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
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.0",
33
- "@tradejs/connectors": "^2.0.0",
34
- "@tradejs/core": "^2.0.0",
35
- "@tradejs/indicators": "^2.0.0",
36
- "@tradejs/infra": "^2.0.0",
37
- "@tradejs/node": "^2.0.0",
38
- "@tradejs/strategies": "^2.0.0",
39
- "@tradejs/types": "^2.0.0",
32
+ "@tradejs/base": "^2.0.2",
33
+ "@tradejs/connectors": "^2.0.2",
34
+ "@tradejs/core": "^2.0.2",
35
+ "@tradejs/indicators": "^2.0.2",
36
+ "@tradejs/infra": "^2.0.2",
37
+ "@tradejs/node": "^2.0.2",
38
+ "@tradejs/strategies": "^2.0.2",
39
+ "@tradejs/types": "^2.0.2",
40
40
  "args": "^5.0.3",
41
41
  "bcryptjs": "^2.4.3",
42
42
  "chalk": "4.1.2",