@tradejs/cli 2.0.1 → 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.
@@ -2728,6 +2728,38 @@ var resolveDerivativesContextMissingFetchFromMs = (params) => {
2728
2728
  return null;
2729
2729
  };
2730
2730
  var resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
2731
+ var resolveDerivativesContextRequiredFetchFromMs = (params) => {
2732
+ const dataCoverageFromMs = params.dataCoverageKeyExists ? null : params.mode === "signals" ? params.fromMs : resolveDerivativesContextMissingCoverageFetchFromMs({
2733
+ ranges: params.dataCoverageRanges,
2734
+ fromMs: params.fromMs,
2735
+ toMs: params.toMs,
2736
+ intervalMs: params.intervalMs
2737
+ });
2738
+ const edgesFromMs = dataCoverageFromMs == null ? null : resolveDerivativesContextFetchFromMs({
2739
+ edges: params.edges,
2740
+ fromMs: params.fromMs,
2741
+ toMs: params.toMs,
2742
+ intervalMs: params.intervalMs,
2743
+ refreshClosedTail: params.mode === "signals"
2744
+ });
2745
+ const dataFetchFromMs = dataCoverageFromMs != null && edgesFromMs != null ? Math.max(dataCoverageFromMs, edgesFromMs) : null;
2746
+ const confirmedLiquidationWindow = (0, import_indicators2.resolveCoinalyzeConfirmedIntradayCoverage)({
2747
+ interval: params.interval,
2748
+ fromMs: params.fromMs,
2749
+ toMs: params.toMs,
2750
+ nowMs: params.nowMs
2751
+ });
2752
+ const liquidationFetchFromMs = confirmedLiquidationWindow ? resolveDerivativesContextMissingCoverageFetchFromMs({
2753
+ ranges: params.liquidationCoverageRanges,
2754
+ fromMs: confirmedLiquidationWindow.fromMs,
2755
+ toMs: confirmedLiquidationWindow.toMs,
2756
+ intervalMs: params.intervalMs
2757
+ }) : null;
2758
+ const fetchStarts = [dataFetchFromMs, liquidationFetchFromMs].filter(
2759
+ (value) => value != null
2760
+ );
2761
+ return fetchStarts.length ? Math.min(...fetchStarts) : null;
2762
+ };
2731
2763
  var countBackfillWindows = (params) => {
2732
2764
  let count = 0;
2733
2765
  let cursor = params.fromMs;
@@ -3063,7 +3095,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3063
3095
  mode,
3064
3096
  startMs,
3065
3097
  endMs,
3066
- preloadStartMs: params.preloadStartMs
3098
+ preloadStartMs: params.preloadStartMs,
3099
+ nowMs: Date.now()
3067
3100
  });
3068
3101
  if (safeEndMs <= fromMs) {
3069
3102
  return skippedBackfillResult2();
@@ -3097,15 +3130,33 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3097
3130
  );
3098
3131
  const coverageKeysByInterval = /* @__PURE__ */ new Map();
3099
3132
  const coverageRangesByInterval = /* @__PURE__ */ new Map();
3133
+ const liquidationCoverageRangesByInterval = /* @__PURE__ */ new Map();
3134
+ const coverageNowMs = Date.now();
3100
3135
  await Promise.all(
3101
3136
  intervalWindows.map(async (window2) => {
3102
- const coverageRows = await (0, import_timescale2.getDerivativesBackfillCoverage)({
3103
- source: "coinalyze",
3104
- symbols,
3137
+ const confirmedLiquidationWindow = (0, import_indicators2.resolveCoinalyzeConfirmedIntradayCoverage)({
3105
3138
  interval: window2.interval,
3106
3139
  fromMs: window2.fromMs,
3107
- toMs: window2.toMs
3140
+ toMs: window2.toMs,
3141
+ nowMs: coverageNowMs
3108
3142
  });
3143
+ const [coverageRows, liquidationCoverageRows] = await Promise.all([
3144
+ (0, import_timescale2.getDerivativesBackfillCoverage)({
3145
+ source: "coinalyze",
3146
+ symbols,
3147
+ interval: window2.interval,
3148
+ fromMs: window2.fromMs,
3149
+ toMs: window2.toMs
3150
+ }),
3151
+ confirmedLiquidationWindow ? (0, import_timescale2.getDerivativesMetricCoverage)({
3152
+ source: "coinalyze",
3153
+ metric: "liquidation",
3154
+ symbols,
3155
+ interval: window2.interval,
3156
+ fromMs: confirmedLiquidationWindow.fromMs,
3157
+ toMs: confirmedLiquidationWindow.toMs
3158
+ }) : Promise.resolve([])
3159
+ ]);
3109
3160
  coverageKeysByInterval.set(
3110
3161
  window2.interval,
3111
3162
  new Set(
@@ -3127,6 +3178,17 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3127
3178
  rangesBySymbol.set(symbol, ranges);
3128
3179
  }
3129
3180
  coverageRangesByInterval.set(window2.interval, rangesBySymbol);
3181
+ const liquidationRangesBySymbol = /* @__PURE__ */ new Map();
3182
+ for (const row of liquidationCoverageRows) {
3183
+ const symbol = row.symbol.toUpperCase();
3184
+ const ranges = liquidationRangesBySymbol.get(symbol) ?? [];
3185
+ ranges.push({ fromMs: row.fromMs, toMs: row.toMs });
3186
+ liquidationRangesBySymbol.set(symbol, ranges);
3187
+ }
3188
+ liquidationCoverageRangesByInterval.set(
3189
+ window2.interval,
3190
+ liquidationRangesBySymbol
3191
+ );
3130
3192
  })
3131
3193
  );
3132
3194
  const cachedWindows = intervalWindows.reduce(
@@ -3151,7 +3213,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3151
3213
  (symbol) => backfillWindows.every((backfillWindow) => {
3152
3214
  const normalizedSymbol = symbol.toUpperCase();
3153
3215
  const coverageRanges = coverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [];
3154
- return hasDerivativesWindowCoverage({
3216
+ const dataCovered = hasDerivativesWindowCoverage({
3155
3217
  edges: edgesBySymbol?.get(normalizedSymbol),
3156
3218
  fromMs: backfillWindow.fromMs,
3157
3219
  toMs: backfillWindow.toMs
@@ -3168,6 +3230,19 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3168
3230
  toMs: backfillWindow.toMs
3169
3231
  })
3170
3232
  );
3233
+ const confirmedLiquidationWindow = (0, import_indicators2.resolveCoinalyzeConfirmedIntradayCoverage)({
3234
+ interval: window2.interval,
3235
+ fromMs: backfillWindow.fromMs,
3236
+ toMs: backfillWindow.toMs,
3237
+ nowMs: coverageNowMs
3238
+ });
3239
+ const liquidationCovered = confirmedLiquidationWindow == null || resolveDerivativesContextMissingCoverageFetchFromMs({
3240
+ ranges: liquidationCoverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [],
3241
+ fromMs: confirmedLiquidationWindow.fromMs,
3242
+ toMs: confirmedLiquidationWindow.toMs,
3243
+ intervalMs: window2.intervalMs
3244
+ }) == null;
3245
+ return dataCovered && liquidationCovered;
3171
3246
  })
3172
3247
  );
3173
3248
  });
@@ -3252,6 +3327,11 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3252
3327
  coverageKeysByInterval.set(interval2, coverageKeys);
3253
3328
  const coverageRangesBySymbol = coverageRangesByInterval.get(interval2) ?? /* @__PURE__ */ new Map();
3254
3329
  coverageRangesByInterval.set(interval2, coverageRangesBySymbol);
3330
+ const liquidationCoverageRangesBySymbol = liquidationCoverageRangesByInterval.get(interval2) ?? /* @__PURE__ */ new Map();
3331
+ liquidationCoverageRangesByInterval.set(
3332
+ interval2,
3333
+ liquidationCoverageRangesBySymbol
3334
+ );
3255
3335
  for (let batchIdx = 0; batchIdx < symbolBatches.length; batchIdx += 1) {
3256
3336
  const batch = symbolBatches[batchIdx];
3257
3337
  let cursor = window2.fromMs;
@@ -3264,33 +3344,25 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3264
3344
  fromMs: cursor,
3265
3345
  toMs
3266
3346
  });
3267
- if (coverageKeys.has(key)) {
3268
- return null;
3269
- }
3270
3347
  const normalizedSymbol = item.symbol.toUpperCase();
3271
- const coverageFromMs = mode === "signals" ? cursor : resolveDerivativesContextMissingCoverageFetchFromMs({
3272
- ranges: coverageRangesBySymbol.get(normalizedSymbol),
3273
- fromMs: cursor,
3274
- toMs,
3275
- intervalMs: intervalMs2
3276
- });
3277
- if (coverageFromMs == null) {
3278
- return null;
3279
- }
3280
- const edges = edgesBySymbol.get(normalizedSymbol);
3281
- const edgesFromMs = resolveDerivativesContextFetchFromMs({
3282
- edges,
3283
- fromMs: cursor,
3284
- toMs,
3285
- intervalMs: intervalMs2,
3286
- refreshClosedTail: mode === "signals"
3287
- });
3288
- if (edgesFromMs == null) {
3289
- return null;
3290
- }
3348
+ const requiredFromMs = resolveDerivativesContextRequiredFetchFromMs(
3349
+ {
3350
+ mode,
3351
+ interval: interval2,
3352
+ intervalMs: intervalMs2,
3353
+ fromMs: cursor,
3354
+ toMs,
3355
+ nowMs: coverageNowMs,
3356
+ dataCoverageKeyExists: coverageKeys.has(key),
3357
+ dataCoverageRanges: coverageRangesBySymbol.get(normalizedSymbol),
3358
+ liquidationCoverageRanges: liquidationCoverageRangesBySymbol.get(normalizedSymbol),
3359
+ edges: edgesBySymbol.get(normalizedSymbol)
3360
+ }
3361
+ );
3362
+ if (requiredFromMs == null) return null;
3291
3363
  return {
3292
3364
  item,
3293
- fromMs: Math.max(coverageFromMs, edgesFromMs)
3365
+ fromMs: requiredFromMs
3294
3366
  };
3295
3367
  }).filter(
3296
3368
  (item) => item != null
@@ -3315,6 +3387,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3315
3387
  );
3316
3388
  let rows = [];
3317
3389
  let missingClosedSymbols = [];
3390
+ let liquidationRowsByMarket = /* @__PURE__ */ new Map();
3318
3391
  for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
3319
3392
  const oiMap = await fetchMetricBatch({
3320
3393
  endpoint: oiPath,
@@ -3334,7 +3407,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3334
3407
  fromMs: group.fromMs,
3335
3408
  toMs
3336
3409
  });
3337
- const liqMap = await fetchMetricBatch({
3410
+ liquidationRowsByMarket = await fetchMetricBatch({
3338
3411
  endpoint: liqPath,
3339
3412
  metric: "liq",
3340
3413
  marketSymbols,
@@ -3349,7 +3422,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3349
3422
  symbol: item.symbol,
3350
3423
  oiRaw: oiMap.get(marketSymbol) ?? [],
3351
3424
  fundingRaw: fundingMap.get(marketSymbol) ?? [],
3352
- liqRaw: liqMap.get(marketSymbol) ?? []
3425
+ liqRaw: liquidationRowsByMarket.get(marketSymbol) ?? []
3353
3426
  });
3354
3427
  return (0, import_indicators2.coinalyzePointsToRows)(points, interval2, "coinalyze");
3355
3428
  });
@@ -3372,6 +3445,42 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3372
3445
  await (0, import_timescale2.upsertDerivatives)(rows);
3373
3446
  totalRows += rows.length;
3374
3447
  }
3448
+ const confirmedLiquidationWindow = (0, import_indicators2.resolveCoinalyzeConfirmedIntradayCoverage)({
3449
+ interval: interval2,
3450
+ fromMs: group.fromMs,
3451
+ toMs,
3452
+ nowMs: coverageNowMs
3453
+ });
3454
+ if (confirmedLiquidationWindow) {
3455
+ const metricCoverageRows = missingBatch.map((item) => {
3456
+ const marketSymbol = item.marketSymbol.toUpperCase();
3457
+ const eventRowsCount = (liquidationRowsByMarket.get(marketSymbol) ?? []).filter((point) => {
3458
+ const timestamp = (0, import_indicators2.toCoinalyzeTimestampMs)(
3459
+ point.t ?? point.ts ?? point.time ?? point.timestamp
3460
+ );
3461
+ return timestamp != null && timestamp >= confirmedLiquidationWindow.fromMs && timestamp <= confirmedLiquidationWindow.toMs;
3462
+ }).length;
3463
+ return {
3464
+ source: "coinalyze",
3465
+ metric: "liquidation",
3466
+ symbol: item.symbol,
3467
+ interval: interval2,
3468
+ fromMs: confirmedLiquidationWindow.fromMs,
3469
+ toMs: confirmedLiquidationWindow.toMs,
3470
+ eventRowsCount
3471
+ };
3472
+ });
3473
+ await (0, import_timescale2.applyDerivativesMetricCoverage)(metricCoverageRows);
3474
+ for (const coverageRow of metricCoverageRows) {
3475
+ const symbol = coverageRow.symbol.toUpperCase();
3476
+ const ranges = liquidationCoverageRangesBySymbol.get(symbol) ?? [];
3477
+ ranges.push({
3478
+ fromMs: coverageRow.fromMs,
3479
+ toMs: coverageRow.toMs
3480
+ });
3481
+ liquidationCoverageRangesBySymbol.set(symbol, ranges);
3482
+ }
3483
+ }
3375
3484
  if (mode === "backtest") {
3376
3485
  const rowsCountBySymbol = /* @__PURE__ */ new Map();
3377
3486
  for (const row of rows) {
@@ -2726,6 +2726,38 @@ var resolveDerivativesContextMissingFetchFromMs = (params) => {
2726
2726
  return null;
2727
2727
  };
2728
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
+ };
2729
2761
  var countBackfillWindows = (params) => {
2730
2762
  let count = 0;
2731
2763
  let cursor = params.fromMs;
@@ -3061,7 +3093,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3061
3093
  mode,
3062
3094
  startMs,
3063
3095
  endMs,
3064
- preloadStartMs: params.preloadStartMs
3096
+ preloadStartMs: params.preloadStartMs,
3097
+ nowMs: Date.now()
3065
3098
  });
3066
3099
  if (safeEndMs <= fromMs) {
3067
3100
  return skippedBackfillResult2();
@@ -3095,15 +3128,33 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3095
3128
  );
3096
3129
  const coverageKeysByInterval = /* @__PURE__ */ new Map();
3097
3130
  const coverageRangesByInterval = /* @__PURE__ */ new Map();
3131
+ const liquidationCoverageRangesByInterval = /* @__PURE__ */ new Map();
3132
+ const coverageNowMs = Date.now();
3098
3133
  await Promise.all(
3099
3134
  intervalWindows.map(async (window2) => {
3100
- const coverageRows = await (0, import_timescale2.getDerivativesBackfillCoverage)({
3101
- source: "coinalyze",
3102
- symbols,
3135
+ const confirmedLiquidationWindow = (0, import_indicators2.resolveCoinalyzeConfirmedIntradayCoverage)({
3103
3136
  interval: window2.interval,
3104
3137
  fromMs: window2.fromMs,
3105
- toMs: window2.toMs
3138
+ toMs: window2.toMs,
3139
+ nowMs: coverageNowMs
3106
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
+ ]);
3107
3158
  coverageKeysByInterval.set(
3108
3159
  window2.interval,
3109
3160
  new Set(
@@ -3125,6 +3176,17 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3125
3176
  rangesBySymbol.set(symbol, ranges);
3126
3177
  }
3127
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
+ );
3128
3190
  })
3129
3191
  );
3130
3192
  const cachedWindows = intervalWindows.reduce(
@@ -3149,7 +3211,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3149
3211
  (symbol) => backfillWindows.every((backfillWindow) => {
3150
3212
  const normalizedSymbol = symbol.toUpperCase();
3151
3213
  const coverageRanges = coverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [];
3152
- return hasDerivativesWindowCoverage({
3214
+ const dataCovered = hasDerivativesWindowCoverage({
3153
3215
  edges: edgesBySymbol?.get(normalizedSymbol),
3154
3216
  fromMs: backfillWindow.fromMs,
3155
3217
  toMs: backfillWindow.toMs
@@ -3166,6 +3228,19 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3166
3228
  toMs: backfillWindow.toMs
3167
3229
  })
3168
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;
3169
3244
  })
3170
3245
  );
3171
3246
  });
@@ -3250,6 +3325,11 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3250
3325
  coverageKeysByInterval.set(interval2, coverageKeys);
3251
3326
  const coverageRangesBySymbol = coverageRangesByInterval.get(interval2) ?? /* @__PURE__ */ new Map();
3252
3327
  coverageRangesByInterval.set(interval2, coverageRangesBySymbol);
3328
+ const liquidationCoverageRangesBySymbol = liquidationCoverageRangesByInterval.get(interval2) ?? /* @__PURE__ */ new Map();
3329
+ liquidationCoverageRangesByInterval.set(
3330
+ interval2,
3331
+ liquidationCoverageRangesBySymbol
3332
+ );
3253
3333
  for (let batchIdx = 0; batchIdx < symbolBatches.length; batchIdx += 1) {
3254
3334
  const batch = symbolBatches[batchIdx];
3255
3335
  let cursor = window2.fromMs;
@@ -3262,33 +3342,25 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3262
3342
  fromMs: cursor,
3263
3343
  toMs
3264
3344
  });
3265
- if (coverageKeys.has(key)) {
3266
- return null;
3267
- }
3268
3345
  const normalizedSymbol = item.symbol.toUpperCase();
3269
- const coverageFromMs = mode === "signals" ? cursor : resolveDerivativesContextMissingCoverageFetchFromMs({
3270
- ranges: coverageRangesBySymbol.get(normalizedSymbol),
3271
- fromMs: cursor,
3272
- toMs,
3273
- intervalMs: intervalMs2
3274
- });
3275
- if (coverageFromMs == null) {
3276
- return null;
3277
- }
3278
- const edges = edgesBySymbol.get(normalizedSymbol);
3279
- const edgesFromMs = resolveDerivativesContextFetchFromMs({
3280
- edges,
3281
- fromMs: cursor,
3282
- toMs,
3283
- intervalMs: intervalMs2,
3284
- refreshClosedTail: mode === "signals"
3285
- });
3286
- if (edgesFromMs == null) {
3287
- return null;
3288
- }
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;
3289
3361
  return {
3290
3362
  item,
3291
- fromMs: Math.max(coverageFromMs, edgesFromMs)
3363
+ fromMs: requiredFromMs
3292
3364
  };
3293
3365
  }).filter(
3294
3366
  (item) => item != null
@@ -3313,6 +3385,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3313
3385
  );
3314
3386
  let rows = [];
3315
3387
  let missingClosedSymbols = [];
3388
+ let liquidationRowsByMarket = /* @__PURE__ */ new Map();
3316
3389
  for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
3317
3390
  const oiMap = await fetchMetricBatch({
3318
3391
  endpoint: oiPath,
@@ -3332,7 +3405,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3332
3405
  fromMs: group.fromMs,
3333
3406
  toMs
3334
3407
  });
3335
- const liqMap = await fetchMetricBatch({
3408
+ liquidationRowsByMarket = await fetchMetricBatch({
3336
3409
  endpoint: liqPath,
3337
3410
  metric: "liq",
3338
3411
  marketSymbols,
@@ -3347,7 +3420,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3347
3420
  symbol: item.symbol,
3348
3421
  oiRaw: oiMap.get(marketSymbol) ?? [],
3349
3422
  fundingRaw: fundingMap.get(marketSymbol) ?? [],
3350
- liqRaw: liqMap.get(marketSymbol) ?? []
3423
+ liqRaw: liquidationRowsByMarket.get(marketSymbol) ?? []
3351
3424
  });
3352
3425
  return (0, import_indicators2.coinalyzePointsToRows)(points, interval2, "coinalyze");
3353
3426
  });
@@ -3370,6 +3443,42 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3370
3443
  await (0, import_timescale2.upsertDerivatives)(rows);
3371
3444
  totalRows += rows.length;
3372
3445
  }
3446
+ const confirmedLiquidationWindow = (0, import_indicators2.resolveCoinalyzeConfirmedIntradayCoverage)({
3447
+ interval: interval2,
3448
+ fromMs: group.fromMs,
3449
+ toMs,
3450
+ nowMs: coverageNowMs
3451
+ });
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
+ }
3373
3482
  if (mode === "backtest") {
3374
3483
  const rowsCountBySymbol = /* @__PURE__ */ new Map();
3375
3484
  for (const row of rows) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/cli",
3
- "version": "2.0.1",
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.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",
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",