@tradejs/cli 1.0.12 → 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.
@@ -3109,7 +3109,7 @@ var import_userSettings = require("@tradejs/infra/userSettings");
3109
3109
  var HOUR_MS = 60 * 60 * 1e3;
3110
3110
  var DAY_MS2 = 24 * HOUR_MS;
3111
3111
  var DEFAULT_LOOKBACK_HOURS = 48;
3112
- var DEFAULT_INTERVALS = ["15m", "1h"];
3112
+ var SOURCE_INTERVALS = ["15m"];
3113
3113
  var coinalyzeIntervalMap = {
3114
3114
  "15m": "15min",
3115
3115
  "1h": "1hour"
@@ -3170,10 +3170,7 @@ var isDerivativesContextBackfillEnabled = (env) => {
3170
3170
  var shouldBackfillDerivativesContextForBacktest = (params) => !params.cacheOnly && (params.aiEnabled || params.mlEnabled) && isBacktestDerivativesContextEnabled();
3171
3171
  var shouldBackfillDerivativesContextForSignals = (params) => !params.cacheOnly && isSignalsDerivativesContextEnabled();
3172
3172
  var resolveDerivativesContextIntervals = () => {
3173
- const intervals = (0, import_indicators.normalizeDerivativesIntervals)(
3174
- process.env.DERIVATIVES_CONTEXT_INTERVALS
3175
- );
3176
- return intervals.length ? intervals : DEFAULT_INTERVALS;
3173
+ return [...SOURCE_INTERVALS];
3177
3174
  };
3178
3175
  var resolveDerivativesContextLookbackMs = () => {
3179
3176
  const hours = Number(process.env.DERIVATIVES_CONTEXT_LOOKBACK_HOURS);
@@ -3208,9 +3205,10 @@ var resolveDerivativesContextBackfillWindow = (params) => {
3208
3205
  };
3209
3206
  var resolveDerivativesContextIntervalBackfillWindow = (params) => {
3210
3207
  const intervalMs = derivativesIntervalMs(params.interval);
3208
+ const alignedToMs = params.closedOnly ? (0, import_indicators.getLastClosedDerivativesBarStartMs)(params.toMs, params.interval) : Math.floor(params.toMs / intervalMs) * intervalMs;
3211
3209
  return {
3212
3210
  fromMs: Math.floor(params.fromMs / intervalMs) * intervalMs,
3213
- toMs: Math.floor(params.toMs / intervalMs) * intervalMs,
3211
+ toMs: alignedToMs,
3214
3212
  intervalMs
3215
3213
  };
3216
3214
  };
@@ -3228,6 +3226,7 @@ var resolveDerivativesContextMissingFetchFromMs = (params) => {
3228
3226
  }
3229
3227
  return null;
3230
3228
  };
3229
+ var resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
3231
3230
  var countBackfillWindows = (params) => {
3232
3231
  let count = 0;
3233
3232
  let cursor = params.fromMs;
@@ -3291,6 +3290,14 @@ var groupDerivativesContextMissingFetchRanges = (ranges) => {
3291
3290
  }
3292
3291
  return [...groups.entries()].sort(([a], [b]) => a - b).map(([fromMs, items]) => ({ fromMs, items }));
3293
3292
  };
3293
+ var getMissingClosedDerivativesSymbols = (params) => {
3294
+ const availableSymbols = new Set(
3295
+ params.rows.filter((row) => row.ts.getTime() === params.expectedTimestamp).map((row) => row.symbol.trim().toUpperCase())
3296
+ );
3297
+ return params.symbols.filter(
3298
+ (symbol) => !availableSymbols.has(symbol.trim().toUpperCase())
3299
+ );
3300
+ };
3294
3301
  var coverageKey = (params) => [
3295
3302
  params.symbol.trim().toUpperCase(),
3296
3303
  params.interval,
@@ -3570,7 +3577,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3570
3577
  ...resolveDerivativesContextIntervalBackfillWindow({
3571
3578
  fromMs,
3572
3579
  toMs: safeEndMs,
3573
- interval
3580
+ interval,
3581
+ closedOnly: mode === "signals"
3574
3582
  })
3575
3583
  })).filter((item) => item.toMs > item.fromMs);
3576
3584
  if (!intervalWindows.length) {
@@ -3629,7 +3637,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3629
3637
  }),
3630
3638
  0
3631
3639
  );
3632
- const allBackfillWindowsCached = intervalWindows.every((window2) => {
3640
+ const allBackfillWindowsCached = mode !== "signals" && intervalWindows.every((window2) => {
3633
3641
  const edgesBySymbol = edgesByInterval.get(window2.interval);
3634
3642
  const coverageKeys = coverageKeysByInterval.get(window2.interval);
3635
3643
  const backfillWindows = buildBackfillWindows({
@@ -3759,7 +3767,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3759
3767
  return null;
3760
3768
  }
3761
3769
  const normalizedSymbol = item.symbol.toUpperCase();
3762
- const coverageFromMs = resolveDerivativesContextMissingCoverageFetchFromMs({
3770
+ const coverageFromMs = mode === "signals" ? cursor : resolveDerivativesContextMissingCoverageFetchFromMs({
3763
3771
  ranges: coverageRangesBySymbol.get(normalizedSymbol),
3764
3772
  fromMs: cursor,
3765
3773
  toMs,
@@ -3769,16 +3777,20 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3769
3777
  return null;
3770
3778
  }
3771
3779
  const edges = edgesBySymbol.get(normalizedSymbol);
3772
- const edgesFromMs = resolveDerivativesContextMissingFetchFromMs({
3780
+ const edgesFromMs = resolveDerivativesContextFetchFromMs({
3773
3781
  edges,
3774
3782
  fromMs: cursor,
3775
3783
  toMs,
3776
- intervalMs
3784
+ intervalMs,
3785
+ refreshClosedTail: mode === "signals"
3777
3786
  });
3778
3787
  if (edgesFromMs == null) {
3779
3788
  return null;
3780
3789
  }
3781
- return { item, fromMs: Math.max(coverageFromMs, edgesFromMs) };
3790
+ return {
3791
+ item,
3792
+ fromMs: Math.max(coverageFromMs, edgesFromMs)
3793
+ };
3782
3794
  }).filter(
3783
3795
  (item) => item != null
3784
3796
  );
@@ -3792,85 +3804,113 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3792
3804
  const marketSymbols = missingBatch.map(
3793
3805
  (item) => item.marketSymbol
3794
3806
  );
3795
- const oiMap = await fetchMetricBatch({
3796
- endpoint: oiPath,
3797
- metric: "oi",
3798
- marketSymbols,
3799
- apiKey,
3800
- interval,
3801
- fromMs: group.fromMs,
3802
- toMs
3803
- });
3804
- const fundingMap = await fetchMetricBatch({
3805
- endpoint: fundingPath,
3806
- metric: "funding",
3807
- marketSymbols,
3808
- apiKey,
3809
- interval,
3810
- fromMs: group.fromMs,
3811
- toMs
3812
- });
3813
- const liqMap = await fetchMetricBatch({
3814
- endpoint: liqPath,
3815
- metric: "liq",
3816
- marketSymbols,
3817
- apiKey,
3818
- interval,
3819
- fromMs: group.fromMs,
3820
- toMs
3821
- });
3822
- const rows = missingBatch.flatMap((item) => {
3823
- const marketSymbol = item.marketSymbol.toUpperCase();
3824
- const points = (0, import_indicators.mergeCoinalyzeMetrics)({
3825
- symbol: item.symbol,
3826
- oiRaw: oiMap.get(marketSymbol) ?? [],
3827
- fundingRaw: fundingMap.get(marketSymbol) ?? [],
3828
- liqRaw: liqMap.get(marketSymbol) ?? []
3807
+ const maxClosedBarAttempts = mode === "signals" ? asInt2(
3808
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_MAX_ATTEMPTS,
3809
+ 3
3810
+ ) : 1;
3811
+ const closedBarRetryDelayMs = asInt2(
3812
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_RETRY_DELAY_MS,
3813
+ 2e3
3814
+ );
3815
+ let rows = [];
3816
+ let missingClosedSymbols = [];
3817
+ for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
3818
+ const oiMap = await fetchMetricBatch({
3819
+ endpoint: oiPath,
3820
+ metric: "oi",
3821
+ marketSymbols,
3822
+ apiKey,
3823
+ interval,
3824
+ fromMs: group.fromMs,
3825
+ toMs
3826
+ });
3827
+ const fundingMap = await fetchMetricBatch({
3828
+ endpoint: fundingPath,
3829
+ metric: "funding",
3830
+ marketSymbols,
3831
+ apiKey,
3832
+ interval,
3833
+ fromMs: group.fromMs,
3834
+ toMs
3829
3835
  });
3830
- return (0, import_indicators.coinalyzePointsToRows)(points, interval, "coinalyze");
3831
- });
3836
+ const liqMap = await fetchMetricBatch({
3837
+ endpoint: liqPath,
3838
+ metric: "liq",
3839
+ marketSymbols,
3840
+ apiKey,
3841
+ interval,
3842
+ fromMs: group.fromMs,
3843
+ toMs
3844
+ });
3845
+ rows = missingBatch.flatMap((item) => {
3846
+ const marketSymbol = item.marketSymbol.toUpperCase();
3847
+ const points = (0, import_indicators.mergeCoinalyzeMetrics)({
3848
+ symbol: item.symbol,
3849
+ oiRaw: oiMap.get(marketSymbol) ?? [],
3850
+ fundingRaw: fundingMap.get(marketSymbol) ?? [],
3851
+ liqRaw: liqMap.get(marketSymbol) ?? []
3852
+ });
3853
+ return (0, import_indicators.coinalyzePointsToRows)(points, interval, "coinalyze");
3854
+ });
3855
+ missingClosedSymbols = mode === "signals" ? getMissingClosedDerivativesSymbols({
3856
+ symbols: missingBatch.map((item) => item.symbol),
3857
+ rows,
3858
+ expectedTimestamp: toMs
3859
+ }) : [];
3860
+ if (!missingClosedSymbols.length) break;
3861
+ if (attempt < maxClosedBarAttempts) {
3862
+ await (0, import_async.delay)(closedBarRetryDelayMs);
3863
+ }
3864
+ }
3865
+ if (missingClosedSymbols.length) {
3866
+ throw new Error(
3867
+ `Coinalyze closed ${interval} bar ${new Date(toMs).toISOString()} unavailable for ${missingClosedSymbols.join(",")}`
3868
+ );
3869
+ }
3832
3870
  if (rows.length) {
3833
3871
  await (0, import_timescale2.upsertDerivatives)(rows);
3834
3872
  totalRows += rows.length;
3835
3873
  }
3836
- const rowsCountBySymbol = /* @__PURE__ */ new Map();
3837
- for (const row of rows) {
3838
- const symbol = row.symbol.toUpperCase();
3839
- rowsCountBySymbol.set(
3840
- symbol,
3841
- (rowsCountBySymbol.get(symbol) ?? 0) + 1
3842
- );
3843
- }
3844
- const coverageRows = missingBatch.map((item) => {
3845
- const normalizedSymbol = item.symbol.toUpperCase();
3846
- const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
3847
- return {
3848
- source: "coinalyze",
3849
- symbol: item.symbol,
3850
- interval,
3851
- fromMs: cursor,
3852
- toMs,
3853
- rowsCount
3854
- };
3855
- });
3856
- await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
3857
- for (const coverageRow of coverageRows) {
3858
- const symbol = coverageRow.symbol.toUpperCase();
3859
- edgesBySymbol.set(
3860
- symbol,
3861
- extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
3862
- );
3863
- coverageKeys.add(
3864
- coverageKey({
3874
+ if (mode === "backtest") {
3875
+ const rowsCountBySymbol = /* @__PURE__ */ new Map();
3876
+ for (const row of rows) {
3877
+ const symbol = row.symbol.toUpperCase();
3878
+ rowsCountBySymbol.set(
3865
3879
  symbol,
3880
+ (rowsCountBySymbol.get(symbol) ?? 0) + 1
3881
+ );
3882
+ }
3883
+ const coverageRows = missingBatch.map((item) => {
3884
+ const normalizedSymbol = item.symbol.toUpperCase();
3885
+ const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
3886
+ return {
3887
+ source: "coinalyze",
3888
+ symbol: item.symbol,
3866
3889
  interval,
3867
3890
  fromMs: cursor,
3868
- toMs
3869
- })
3870
- );
3871
- const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
3872
- coverageRanges.push({ fromMs: cursor, toMs });
3873
- coverageRangesBySymbol.set(symbol, coverageRanges);
3891
+ toMs,
3892
+ rowsCount
3893
+ };
3894
+ });
3895
+ await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
3896
+ for (const coverageRow of coverageRows) {
3897
+ const symbol = coverageRow.symbol.toUpperCase();
3898
+ edgesBySymbol.set(
3899
+ symbol,
3900
+ extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
3901
+ );
3902
+ coverageKeys.add(
3903
+ coverageKey({
3904
+ symbol,
3905
+ interval,
3906
+ fromMs: cursor,
3907
+ toMs
3908
+ })
3909
+ );
3910
+ const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
3911
+ coverageRanges.push({ fromMs: cursor, toMs });
3912
+ coverageRangesBySymbol.set(symbol, coverageRanges);
3913
+ }
3874
3914
  }
3875
3915
  }
3876
3916
  }
@@ -3114,7 +3114,7 @@ var import_userSettings = require("@tradejs/infra/userSettings");
3114
3114
  var HOUR_MS = 60 * 60 * 1e3;
3115
3115
  var DAY_MS2 = 24 * HOUR_MS;
3116
3116
  var DEFAULT_LOOKBACK_HOURS = 48;
3117
- var DEFAULT_INTERVALS = ["15m", "1h"];
3117
+ var SOURCE_INTERVALS = ["15m"];
3118
3118
  var coinalyzeIntervalMap = {
3119
3119
  "15m": "15min",
3120
3120
  "1h": "1hour"
@@ -3175,10 +3175,7 @@ var isDerivativesContextBackfillEnabled = (env) => {
3175
3175
  var shouldBackfillDerivativesContextForBacktest = (params) => !params.cacheOnly && (params.aiEnabled || params.mlEnabled) && isBacktestDerivativesContextEnabled();
3176
3176
  var shouldBackfillDerivativesContextForSignals = (params) => !params.cacheOnly && isSignalsDerivativesContextEnabled();
3177
3177
  var resolveDerivativesContextIntervals = () => {
3178
- const intervals = (0, import_indicators.normalizeDerivativesIntervals)(
3179
- process.env.DERIVATIVES_CONTEXT_INTERVALS
3180
- );
3181
- return intervals.length ? intervals : DEFAULT_INTERVALS;
3178
+ return [...SOURCE_INTERVALS];
3182
3179
  };
3183
3180
  var resolveDerivativesContextLookbackMs = () => {
3184
3181
  const hours = Number(process.env.DERIVATIVES_CONTEXT_LOOKBACK_HOURS);
@@ -3213,9 +3210,10 @@ var resolveDerivativesContextBackfillWindow = (params) => {
3213
3210
  };
3214
3211
  var resolveDerivativesContextIntervalBackfillWindow = (params) => {
3215
3212
  const intervalMs = derivativesIntervalMs(params.interval);
3213
+ const alignedToMs = params.closedOnly ? (0, import_indicators.getLastClosedDerivativesBarStartMs)(params.toMs, params.interval) : Math.floor(params.toMs / intervalMs) * intervalMs;
3216
3214
  return {
3217
3215
  fromMs: Math.floor(params.fromMs / intervalMs) * intervalMs,
3218
- toMs: Math.floor(params.toMs / intervalMs) * intervalMs,
3216
+ toMs: alignedToMs,
3219
3217
  intervalMs
3220
3218
  };
3221
3219
  };
@@ -3233,6 +3231,7 @@ var resolveDerivativesContextMissingFetchFromMs = (params) => {
3233
3231
  }
3234
3232
  return null;
3235
3233
  };
3234
+ var resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
3236
3235
  var countBackfillWindows = (params) => {
3237
3236
  let count = 0;
3238
3237
  let cursor = params.fromMs;
@@ -3296,6 +3295,14 @@ var groupDerivativesContextMissingFetchRanges = (ranges) => {
3296
3295
  }
3297
3296
  return [...groups.entries()].sort(([a], [b]) => a - b).map(([fromMs, items]) => ({ fromMs, items }));
3298
3297
  };
3298
+ var getMissingClosedDerivativesSymbols = (params) => {
3299
+ const availableSymbols = new Set(
3300
+ params.rows.filter((row) => row.ts.getTime() === params.expectedTimestamp).map((row) => row.symbol.trim().toUpperCase())
3301
+ );
3302
+ return params.symbols.filter(
3303
+ (symbol) => !availableSymbols.has(symbol.trim().toUpperCase())
3304
+ );
3305
+ };
3299
3306
  var coverageKey = (params) => [
3300
3307
  params.symbol.trim().toUpperCase(),
3301
3308
  params.interval,
@@ -3575,7 +3582,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3575
3582
  ...resolveDerivativesContextIntervalBackfillWindow({
3576
3583
  fromMs,
3577
3584
  toMs: safeEndMs,
3578
- interval: interval2
3585
+ interval: interval2,
3586
+ closedOnly: mode === "signals"
3579
3587
  })
3580
3588
  })).filter((item) => item.toMs > item.fromMs);
3581
3589
  if (!intervalWindows.length) {
@@ -3634,7 +3642,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3634
3642
  }),
3635
3643
  0
3636
3644
  );
3637
- const allBackfillWindowsCached = intervalWindows.every((window2) => {
3645
+ const allBackfillWindowsCached = mode !== "signals" && intervalWindows.every((window2) => {
3638
3646
  const edgesBySymbol = edgesByInterval.get(window2.interval);
3639
3647
  const coverageKeys = coverageKeysByInterval.get(window2.interval);
3640
3648
  const backfillWindows = buildBackfillWindows({
@@ -3764,7 +3772,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3764
3772
  return null;
3765
3773
  }
3766
3774
  const normalizedSymbol = item.symbol.toUpperCase();
3767
- const coverageFromMs = resolveDerivativesContextMissingCoverageFetchFromMs({
3775
+ const coverageFromMs = mode === "signals" ? cursor : resolveDerivativesContextMissingCoverageFetchFromMs({
3768
3776
  ranges: coverageRangesBySymbol.get(normalizedSymbol),
3769
3777
  fromMs: cursor,
3770
3778
  toMs,
@@ -3774,16 +3782,20 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3774
3782
  return null;
3775
3783
  }
3776
3784
  const edges = edgesBySymbol.get(normalizedSymbol);
3777
- const edgesFromMs = resolveDerivativesContextMissingFetchFromMs({
3785
+ const edgesFromMs = resolveDerivativesContextFetchFromMs({
3778
3786
  edges,
3779
3787
  fromMs: cursor,
3780
3788
  toMs,
3781
- intervalMs
3789
+ intervalMs,
3790
+ refreshClosedTail: mode === "signals"
3782
3791
  });
3783
3792
  if (edgesFromMs == null) {
3784
3793
  return null;
3785
3794
  }
3786
- return { item, fromMs: Math.max(coverageFromMs, edgesFromMs) };
3795
+ return {
3796
+ item,
3797
+ fromMs: Math.max(coverageFromMs, edgesFromMs)
3798
+ };
3787
3799
  }).filter(
3788
3800
  (item) => item != null
3789
3801
  );
@@ -3797,85 +3809,113 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3797
3809
  const marketSymbols = missingBatch.map(
3798
3810
  (item) => item.marketSymbol
3799
3811
  );
3800
- const oiMap = await fetchMetricBatch({
3801
- endpoint: oiPath,
3802
- metric: "oi",
3803
- marketSymbols,
3804
- apiKey,
3805
- interval: interval2,
3806
- fromMs: group.fromMs,
3807
- toMs
3808
- });
3809
- const fundingMap = await fetchMetricBatch({
3810
- endpoint: fundingPath,
3811
- metric: "funding",
3812
- marketSymbols,
3813
- apiKey,
3814
- interval: interval2,
3815
- fromMs: group.fromMs,
3816
- toMs
3817
- });
3818
- const liqMap = await fetchMetricBatch({
3819
- endpoint: liqPath,
3820
- metric: "liq",
3821
- marketSymbols,
3822
- apiKey,
3823
- interval: interval2,
3824
- fromMs: group.fromMs,
3825
- toMs
3826
- });
3827
- const rows = missingBatch.flatMap((item) => {
3828
- const marketSymbol = item.marketSymbol.toUpperCase();
3829
- const points = (0, import_indicators.mergeCoinalyzeMetrics)({
3830
- symbol: item.symbol,
3831
- oiRaw: oiMap.get(marketSymbol) ?? [],
3832
- fundingRaw: fundingMap.get(marketSymbol) ?? [],
3833
- liqRaw: liqMap.get(marketSymbol) ?? []
3812
+ const maxClosedBarAttempts = mode === "signals" ? asInt2(
3813
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_MAX_ATTEMPTS,
3814
+ 3
3815
+ ) : 1;
3816
+ const closedBarRetryDelayMs = asInt2(
3817
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_RETRY_DELAY_MS,
3818
+ 2e3
3819
+ );
3820
+ let rows = [];
3821
+ let missingClosedSymbols = [];
3822
+ for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
3823
+ const oiMap = await fetchMetricBatch({
3824
+ endpoint: oiPath,
3825
+ metric: "oi",
3826
+ marketSymbols,
3827
+ apiKey,
3828
+ interval: interval2,
3829
+ fromMs: group.fromMs,
3830
+ toMs
3834
3831
  });
3835
- return (0, import_indicators.coinalyzePointsToRows)(points, interval2, "coinalyze");
3836
- });
3832
+ const fundingMap = await fetchMetricBatch({
3833
+ endpoint: fundingPath,
3834
+ metric: "funding",
3835
+ marketSymbols,
3836
+ apiKey,
3837
+ interval: interval2,
3838
+ fromMs: group.fromMs,
3839
+ toMs
3840
+ });
3841
+ const liqMap = await fetchMetricBatch({
3842
+ endpoint: liqPath,
3843
+ metric: "liq",
3844
+ marketSymbols,
3845
+ apiKey,
3846
+ interval: interval2,
3847
+ fromMs: group.fromMs,
3848
+ toMs
3849
+ });
3850
+ rows = missingBatch.flatMap((item) => {
3851
+ const marketSymbol = item.marketSymbol.toUpperCase();
3852
+ const points = (0, import_indicators.mergeCoinalyzeMetrics)({
3853
+ symbol: item.symbol,
3854
+ oiRaw: oiMap.get(marketSymbol) ?? [],
3855
+ fundingRaw: fundingMap.get(marketSymbol) ?? [],
3856
+ liqRaw: liqMap.get(marketSymbol) ?? []
3857
+ });
3858
+ return (0, import_indicators.coinalyzePointsToRows)(points, interval2, "coinalyze");
3859
+ });
3860
+ missingClosedSymbols = mode === "signals" ? getMissingClosedDerivativesSymbols({
3861
+ symbols: missingBatch.map((item) => item.symbol),
3862
+ rows,
3863
+ expectedTimestamp: toMs
3864
+ }) : [];
3865
+ if (!missingClosedSymbols.length) break;
3866
+ if (attempt < maxClosedBarAttempts) {
3867
+ await (0, import_async.delay)(closedBarRetryDelayMs);
3868
+ }
3869
+ }
3870
+ if (missingClosedSymbols.length) {
3871
+ throw new Error(
3872
+ `Coinalyze closed ${interval2} bar ${new Date(toMs).toISOString()} unavailable for ${missingClosedSymbols.join(",")}`
3873
+ );
3874
+ }
3837
3875
  if (rows.length) {
3838
3876
  await (0, import_timescale2.upsertDerivatives)(rows);
3839
3877
  totalRows += rows.length;
3840
3878
  }
3841
- const rowsCountBySymbol = /* @__PURE__ */ new Map();
3842
- for (const row of rows) {
3843
- const symbol = row.symbol.toUpperCase();
3844
- rowsCountBySymbol.set(
3845
- symbol,
3846
- (rowsCountBySymbol.get(symbol) ?? 0) + 1
3847
- );
3848
- }
3849
- const coverageRows = missingBatch.map((item) => {
3850
- const normalizedSymbol = item.symbol.toUpperCase();
3851
- const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
3852
- return {
3853
- source: "coinalyze",
3854
- symbol: item.symbol,
3855
- interval: interval2,
3856
- fromMs: cursor,
3857
- toMs,
3858
- rowsCount
3859
- };
3860
- });
3861
- await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
3862
- for (const coverageRow of coverageRows) {
3863
- const symbol = coverageRow.symbol.toUpperCase();
3864
- edgesBySymbol.set(
3865
- symbol,
3866
- extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
3867
- );
3868
- coverageKeys.add(
3869
- coverageKey({
3879
+ if (mode === "backtest") {
3880
+ const rowsCountBySymbol = /* @__PURE__ */ new Map();
3881
+ for (const row of rows) {
3882
+ const symbol = row.symbol.toUpperCase();
3883
+ rowsCountBySymbol.set(
3870
3884
  symbol,
3885
+ (rowsCountBySymbol.get(symbol) ?? 0) + 1
3886
+ );
3887
+ }
3888
+ const coverageRows = missingBatch.map((item) => {
3889
+ const normalizedSymbol = item.symbol.toUpperCase();
3890
+ const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
3891
+ return {
3892
+ source: "coinalyze",
3893
+ symbol: item.symbol,
3871
3894
  interval: interval2,
3872
3895
  fromMs: cursor,
3873
- toMs
3874
- })
3875
- );
3876
- const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
3877
- coverageRanges.push({ fromMs: cursor, toMs });
3878
- coverageRangesBySymbol.set(symbol, coverageRanges);
3896
+ toMs,
3897
+ rowsCount
3898
+ };
3899
+ });
3900
+ await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
3901
+ for (const coverageRow of coverageRows) {
3902
+ const symbol = coverageRow.symbol.toUpperCase();
3903
+ edgesBySymbol.set(
3904
+ symbol,
3905
+ extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
3906
+ );
3907
+ coverageKeys.add(
3908
+ coverageKey({
3909
+ symbol,
3910
+ interval: interval2,
3911
+ fromMs: cursor,
3912
+ toMs
3913
+ })
3914
+ );
3915
+ const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
3916
+ coverageRanges.push({ fromMs: cursor, toMs });
3917
+ coverageRangesBySymbol.set(symbol, coverageRanges);
3918
+ }
3879
3919
  }
3880
3920
  }
3881
3921
  }