@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.
@@ -33,6 +33,7 @@ __export(derivativesContextBackfill_exports, {
33
33
  backfillDerivativesContextForBacktest: () => backfillDerivativesContextForBacktest,
34
34
  backfillDerivativesContextForSignals: () => backfillDerivativesContextForSignals,
35
35
  formatCoinalyzeRequestError: () => formatCoinalyzeRequestError,
36
+ getMissingClosedDerivativesSymbols: () => getMissingClosedDerivativesSymbols,
36
37
  groupDerivativesContextMissingFetchRanges: () => groupDerivativesContextMissingFetchRanges,
37
38
  hasDerivativesContextCoverageRange: () => hasDerivativesContextCoverageRange,
38
39
  isBacktestDerivativesContextEnabled: () => isBacktestDerivativesContextEnabled,
@@ -40,6 +41,7 @@ __export(derivativesContextBackfill_exports, {
40
41
  isSignalsDerivativesContextEnabled: () => isSignalsDerivativesContextEnabled,
41
42
  resolveDerivativesContextBackfillSymbols: () => resolveDerivativesContextBackfillSymbols,
42
43
  resolveDerivativesContextBackfillWindow: () => resolveDerivativesContextBackfillWindow,
44
+ resolveDerivativesContextFetchFromMs: () => resolveDerivativesContextFetchFromMs,
43
45
  resolveDerivativesContextIntervalBackfillWindow: () => resolveDerivativesContextIntervalBackfillWindow,
44
46
  resolveDerivativesContextIntervals: () => resolveDerivativesContextIntervals,
45
47
  resolveDerivativesContextLookbackMs: () => resolveDerivativesContextLookbackMs,
@@ -59,7 +61,7 @@ var import_userSettings = require("@tradejs/infra/userSettings");
59
61
  var HOUR_MS = 60 * 60 * 1e3;
60
62
  var DAY_MS = 24 * HOUR_MS;
61
63
  var DEFAULT_LOOKBACK_HOURS = 48;
62
- var DEFAULT_INTERVALS = ["15m", "1h"];
64
+ var SOURCE_INTERVALS = ["15m"];
63
65
  var coinalyzeIntervalMap = {
64
66
  "15m": "15min",
65
67
  "1h": "1hour"
@@ -120,10 +122,7 @@ var isDerivativesContextBackfillEnabled = (env) => {
120
122
  var shouldBackfillDerivativesContextForBacktest = (params) => !params.cacheOnly && (params.aiEnabled || params.mlEnabled) && isBacktestDerivativesContextEnabled();
121
123
  var shouldBackfillDerivativesContextForSignals = (params) => !params.cacheOnly && isSignalsDerivativesContextEnabled();
122
124
  var resolveDerivativesContextIntervals = () => {
123
- const intervals = (0, import_indicators.normalizeDerivativesIntervals)(
124
- process.env.DERIVATIVES_CONTEXT_INTERVALS
125
- );
126
- return intervals.length ? intervals : DEFAULT_INTERVALS;
125
+ return [...SOURCE_INTERVALS];
127
126
  };
128
127
  var resolveDerivativesContextLookbackMs = () => {
129
128
  const hours = Number(process.env.DERIVATIVES_CONTEXT_LOOKBACK_HOURS);
@@ -158,9 +157,10 @@ var resolveDerivativesContextBackfillWindow = (params) => {
158
157
  };
159
158
  var resolveDerivativesContextIntervalBackfillWindow = (params) => {
160
159
  const intervalMs = derivativesIntervalMs(params.interval);
160
+ const alignedToMs = params.closedOnly ? (0, import_indicators.getLastClosedDerivativesBarStartMs)(params.toMs, params.interval) : Math.floor(params.toMs / intervalMs) * intervalMs;
161
161
  return {
162
162
  fromMs: Math.floor(params.fromMs / intervalMs) * intervalMs,
163
- toMs: Math.floor(params.toMs / intervalMs) * intervalMs,
163
+ toMs: alignedToMs,
164
164
  intervalMs
165
165
  };
166
166
  };
@@ -178,6 +178,7 @@ var resolveDerivativesContextMissingFetchFromMs = (params) => {
178
178
  }
179
179
  return null;
180
180
  };
181
+ var resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
181
182
  var countBackfillWindows = (params) => {
182
183
  let count = 0;
183
184
  let cursor = params.fromMs;
@@ -244,6 +245,14 @@ var groupDerivativesContextMissingFetchRanges = (ranges) => {
244
245
  }
245
246
  return [...groups.entries()].sort(([a], [b]) => a - b).map(([fromMs, items]) => ({ fromMs, items }));
246
247
  };
248
+ var getMissingClosedDerivativesSymbols = (params) => {
249
+ const availableSymbols = new Set(
250
+ params.rows.filter((row) => row.ts.getTime() === params.expectedTimestamp).map((row) => row.symbol.trim().toUpperCase())
251
+ );
252
+ return params.symbols.filter(
253
+ (symbol) => !availableSymbols.has(symbol.trim().toUpperCase())
254
+ );
255
+ };
247
256
  var coverageKey = (params) => [
248
257
  params.symbol.trim().toUpperCase(),
249
258
  params.interval,
@@ -523,7 +532,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
523
532
  ...resolveDerivativesContextIntervalBackfillWindow({
524
533
  fromMs,
525
534
  toMs: safeEndMs,
526
- interval
535
+ interval,
536
+ closedOnly: mode === "signals"
527
537
  })
528
538
  })).filter((item) => item.toMs > item.fromMs);
529
539
  if (!intervalWindows.length) {
@@ -582,7 +592,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
582
592
  }),
583
593
  0
584
594
  );
585
- const allBackfillWindowsCached = intervalWindows.every((window) => {
595
+ const allBackfillWindowsCached = mode !== "signals" && intervalWindows.every((window) => {
586
596
  const edgesBySymbol = edgesByInterval.get(window.interval);
587
597
  const coverageKeys = coverageKeysByInterval.get(window.interval);
588
598
  const backfillWindows = buildBackfillWindows({
@@ -712,7 +722,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
712
722
  return null;
713
723
  }
714
724
  const normalizedSymbol = item.symbol.toUpperCase();
715
- const coverageFromMs = resolveDerivativesContextMissingCoverageFetchFromMs({
725
+ const coverageFromMs = mode === "signals" ? cursor : resolveDerivativesContextMissingCoverageFetchFromMs({
716
726
  ranges: coverageRangesBySymbol.get(normalizedSymbol),
717
727
  fromMs: cursor,
718
728
  toMs,
@@ -722,16 +732,20 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
722
732
  return null;
723
733
  }
724
734
  const edges = edgesBySymbol.get(normalizedSymbol);
725
- const edgesFromMs = resolveDerivativesContextMissingFetchFromMs({
735
+ const edgesFromMs = resolveDerivativesContextFetchFromMs({
726
736
  edges,
727
737
  fromMs: cursor,
728
738
  toMs,
729
- intervalMs
739
+ intervalMs,
740
+ refreshClosedTail: mode === "signals"
730
741
  });
731
742
  if (edgesFromMs == null) {
732
743
  return null;
733
744
  }
734
- return { item, fromMs: Math.max(coverageFromMs, edgesFromMs) };
745
+ return {
746
+ item,
747
+ fromMs: Math.max(coverageFromMs, edgesFromMs)
748
+ };
735
749
  }).filter(
736
750
  (item) => item != null
737
751
  );
@@ -745,85 +759,113 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
745
759
  const marketSymbols = missingBatch.map(
746
760
  (item) => item.marketSymbol
747
761
  );
748
- const oiMap = await fetchMetricBatch({
749
- endpoint: oiPath,
750
- metric: "oi",
751
- marketSymbols,
752
- apiKey,
753
- interval,
754
- fromMs: group.fromMs,
755
- toMs
756
- });
757
- const fundingMap = await fetchMetricBatch({
758
- endpoint: fundingPath,
759
- metric: "funding",
760
- marketSymbols,
761
- apiKey,
762
- interval,
763
- fromMs: group.fromMs,
764
- toMs
765
- });
766
- const liqMap = await fetchMetricBatch({
767
- endpoint: liqPath,
768
- metric: "liq",
769
- marketSymbols,
770
- apiKey,
771
- interval,
772
- fromMs: group.fromMs,
773
- toMs
774
- });
775
- const rows = missingBatch.flatMap((item) => {
776
- const marketSymbol = item.marketSymbol.toUpperCase();
777
- const points = (0, import_indicators.mergeCoinalyzeMetrics)({
778
- symbol: item.symbol,
779
- oiRaw: oiMap.get(marketSymbol) ?? [],
780
- fundingRaw: fundingMap.get(marketSymbol) ?? [],
781
- liqRaw: liqMap.get(marketSymbol) ?? []
762
+ const maxClosedBarAttempts = mode === "signals" ? asInt(
763
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_MAX_ATTEMPTS,
764
+ 3
765
+ ) : 1;
766
+ const closedBarRetryDelayMs = asInt(
767
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_RETRY_DELAY_MS,
768
+ 2e3
769
+ );
770
+ let rows = [];
771
+ let missingClosedSymbols = [];
772
+ for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
773
+ const oiMap = await fetchMetricBatch({
774
+ endpoint: oiPath,
775
+ metric: "oi",
776
+ marketSymbols,
777
+ apiKey,
778
+ interval,
779
+ fromMs: group.fromMs,
780
+ toMs
781
+ });
782
+ const fundingMap = await fetchMetricBatch({
783
+ endpoint: fundingPath,
784
+ metric: "funding",
785
+ marketSymbols,
786
+ apiKey,
787
+ interval,
788
+ fromMs: group.fromMs,
789
+ toMs
790
+ });
791
+ const liqMap = await fetchMetricBatch({
792
+ endpoint: liqPath,
793
+ metric: "liq",
794
+ marketSymbols,
795
+ apiKey,
796
+ interval,
797
+ fromMs: group.fromMs,
798
+ toMs
782
799
  });
783
- return (0, import_indicators.coinalyzePointsToRows)(points, interval, "coinalyze");
784
- });
800
+ rows = missingBatch.flatMap((item) => {
801
+ const marketSymbol = item.marketSymbol.toUpperCase();
802
+ const points = (0, import_indicators.mergeCoinalyzeMetrics)({
803
+ symbol: item.symbol,
804
+ oiRaw: oiMap.get(marketSymbol) ?? [],
805
+ fundingRaw: fundingMap.get(marketSymbol) ?? [],
806
+ liqRaw: liqMap.get(marketSymbol) ?? []
807
+ });
808
+ return (0, import_indicators.coinalyzePointsToRows)(points, interval, "coinalyze");
809
+ });
810
+ missingClosedSymbols = mode === "signals" ? getMissingClosedDerivativesSymbols({
811
+ symbols: missingBatch.map((item) => item.symbol),
812
+ rows,
813
+ expectedTimestamp: toMs
814
+ }) : [];
815
+ if (!missingClosedSymbols.length) break;
816
+ if (attempt < maxClosedBarAttempts) {
817
+ await (0, import_async.delay)(closedBarRetryDelayMs);
818
+ }
819
+ }
820
+ if (missingClosedSymbols.length) {
821
+ throw new Error(
822
+ `Coinalyze closed ${interval} bar ${new Date(toMs).toISOString()} unavailable for ${missingClosedSymbols.join(",")}`
823
+ );
824
+ }
785
825
  if (rows.length) {
786
826
  await (0, import_timescale.upsertDerivatives)(rows);
787
827
  totalRows += rows.length;
788
828
  }
789
- const rowsCountBySymbol = /* @__PURE__ */ new Map();
790
- for (const row of rows) {
791
- const symbol = row.symbol.toUpperCase();
792
- rowsCountBySymbol.set(
793
- symbol,
794
- (rowsCountBySymbol.get(symbol) ?? 0) + 1
795
- );
796
- }
797
- const coverageRows = missingBatch.map((item) => {
798
- const normalizedSymbol = item.symbol.toUpperCase();
799
- const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
800
- return {
801
- source: "coinalyze",
802
- symbol: item.symbol,
803
- interval,
804
- fromMs: cursor,
805
- toMs,
806
- rowsCount
807
- };
808
- });
809
- await (0, import_timescale.upsertDerivativesBackfillCoverage)(coverageRows);
810
- for (const coverageRow of coverageRows) {
811
- const symbol = coverageRow.symbol.toUpperCase();
812
- edgesBySymbol.set(
813
- symbol,
814
- extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
815
- );
816
- coverageKeys.add(
817
- coverageKey({
829
+ if (mode === "backtest") {
830
+ const rowsCountBySymbol = /* @__PURE__ */ new Map();
831
+ for (const row of rows) {
832
+ const symbol = row.symbol.toUpperCase();
833
+ rowsCountBySymbol.set(
818
834
  symbol,
835
+ (rowsCountBySymbol.get(symbol) ?? 0) + 1
836
+ );
837
+ }
838
+ const coverageRows = missingBatch.map((item) => {
839
+ const normalizedSymbol = item.symbol.toUpperCase();
840
+ const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
841
+ return {
842
+ source: "coinalyze",
843
+ symbol: item.symbol,
819
844
  interval,
820
845
  fromMs: cursor,
821
- toMs
822
- })
823
- );
824
- const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
825
- coverageRanges.push({ fromMs: cursor, toMs });
826
- coverageRangesBySymbol.set(symbol, coverageRanges);
846
+ toMs,
847
+ rowsCount
848
+ };
849
+ });
850
+ await (0, import_timescale.upsertDerivativesBackfillCoverage)(coverageRows);
851
+ for (const coverageRow of coverageRows) {
852
+ const symbol = coverageRow.symbol.toUpperCase();
853
+ edgesBySymbol.set(
854
+ symbol,
855
+ extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
856
+ );
857
+ coverageKeys.add(
858
+ coverageKey({
859
+ symbol,
860
+ interval,
861
+ fromMs: cursor,
862
+ toMs
863
+ })
864
+ );
865
+ const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
866
+ coverageRanges.push({ fromMs: cursor, toMs });
867
+ coverageRangesBySymbol.set(symbol, coverageRanges);
868
+ }
827
869
  }
828
870
  }
829
871
  }
@@ -883,6 +925,7 @@ var backfillDerivativesContextForSignals = async (params) => backfillDerivatives
883
925
  backfillDerivativesContextForBacktest,
884
926
  backfillDerivativesContextForSignals,
885
927
  formatCoinalyzeRequestError,
928
+ getMissingClosedDerivativesSymbols,
886
929
  groupDerivativesContextMissingFetchRanges,
887
930
  hasDerivativesContextCoverageRange,
888
931
  isBacktestDerivativesContextEnabled,
@@ -890,6 +933,7 @@ var backfillDerivativesContextForSignals = async (params) => backfillDerivatives
890
933
  isSignalsDerivativesContextEnabled,
891
934
  resolveDerivativesContextBackfillSymbols,
892
935
  resolveDerivativesContextBackfillWindow,
936
+ resolveDerivativesContextFetchFromMs,
893
937
  resolveDerivativesContextIntervalBackfillWindow,
894
938
  resolveDerivativesContextIntervals,
895
939
  resolveDerivativesContextLookbackMs,
@@ -2434,7 +2434,7 @@ var import_userSettings = require("@tradejs/infra/userSettings");
2434
2434
  var HOUR_MS = 60 * 60 * 1e3;
2435
2435
  var DAY_MS2 = 24 * HOUR_MS;
2436
2436
  var DEFAULT_LOOKBACK_HOURS = 48;
2437
- var DEFAULT_INTERVALS = ["15m", "1h"];
2437
+ var SOURCE_INTERVALS = ["15m"];
2438
2438
  var coinalyzeIntervalMap = {
2439
2439
  "15m": "15min",
2440
2440
  "1h": "1hour"
@@ -2495,10 +2495,7 @@ var isDerivativesContextBackfillEnabled = (env) => {
2495
2495
  var shouldBackfillDerivativesContextForBacktest = (params) => !params.cacheOnly && (params.aiEnabled || params.mlEnabled) && isBacktestDerivativesContextEnabled();
2496
2496
  var shouldBackfillDerivativesContextForSignals = (params) => !params.cacheOnly && isSignalsDerivativesContextEnabled();
2497
2497
  var resolveDerivativesContextIntervals = () => {
2498
- const intervals = (0, import_indicators.normalizeDerivativesIntervals)(
2499
- process.env.DERIVATIVES_CONTEXT_INTERVALS
2500
- );
2501
- return intervals.length ? intervals : DEFAULT_INTERVALS;
2498
+ return [...SOURCE_INTERVALS];
2502
2499
  };
2503
2500
  var resolveDerivativesContextLookbackMs = () => {
2504
2501
  const hours = Number(process.env.DERIVATIVES_CONTEXT_LOOKBACK_HOURS);
@@ -2533,9 +2530,10 @@ var resolveDerivativesContextBackfillWindow = (params) => {
2533
2530
  };
2534
2531
  var resolveDerivativesContextIntervalBackfillWindow = (params) => {
2535
2532
  const intervalMs = derivativesIntervalMs(params.interval);
2533
+ const alignedToMs = params.closedOnly ? (0, import_indicators.getLastClosedDerivativesBarStartMs)(params.toMs, params.interval) : Math.floor(params.toMs / intervalMs) * intervalMs;
2536
2534
  return {
2537
2535
  fromMs: Math.floor(params.fromMs / intervalMs) * intervalMs,
2538
- toMs: Math.floor(params.toMs / intervalMs) * intervalMs,
2536
+ toMs: alignedToMs,
2539
2537
  intervalMs
2540
2538
  };
2541
2539
  };
@@ -2553,6 +2551,7 @@ var resolveDerivativesContextMissingFetchFromMs = (params) => {
2553
2551
  }
2554
2552
  return null;
2555
2553
  };
2554
+ var resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
2556
2555
  var countBackfillWindows = (params) => {
2557
2556
  let count = 0;
2558
2557
  let cursor = params.fromMs;
@@ -2616,6 +2615,14 @@ var groupDerivativesContextMissingFetchRanges = (ranges) => {
2616
2615
  }
2617
2616
  return [...groups.entries()].sort(([a], [b]) => a - b).map(([fromMs, items]) => ({ fromMs, items }));
2618
2617
  };
2618
+ var getMissingClosedDerivativesSymbols = (params) => {
2619
+ const availableSymbols = new Set(
2620
+ params.rows.filter((row) => row.ts.getTime() === params.expectedTimestamp).map((row) => row.symbol.trim().toUpperCase())
2621
+ );
2622
+ return params.symbols.filter(
2623
+ (symbol) => !availableSymbols.has(symbol.trim().toUpperCase())
2624
+ );
2625
+ };
2619
2626
  var coverageKey = (params) => [
2620
2627
  params.symbol.trim().toUpperCase(),
2621
2628
  params.interval,
@@ -2895,7 +2902,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
2895
2902
  ...resolveDerivativesContextIntervalBackfillWindow({
2896
2903
  fromMs,
2897
2904
  toMs: safeEndMs,
2898
- interval
2905
+ interval,
2906
+ closedOnly: mode === "signals"
2899
2907
  })
2900
2908
  })).filter((item) => item.toMs > item.fromMs);
2901
2909
  if (!intervalWindows.length) {
@@ -2954,7 +2962,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
2954
2962
  }),
2955
2963
  0
2956
2964
  );
2957
- const allBackfillWindowsCached = intervalWindows.every((window2) => {
2965
+ const allBackfillWindowsCached = mode !== "signals" && intervalWindows.every((window2) => {
2958
2966
  const edgesBySymbol = edgesByInterval.get(window2.interval);
2959
2967
  const coverageKeys = coverageKeysByInterval.get(window2.interval);
2960
2968
  const backfillWindows = buildBackfillWindows({
@@ -3084,7 +3092,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3084
3092
  return null;
3085
3093
  }
3086
3094
  const normalizedSymbol = item.symbol.toUpperCase();
3087
- const coverageFromMs = resolveDerivativesContextMissingCoverageFetchFromMs({
3095
+ const coverageFromMs = mode === "signals" ? cursor : resolveDerivativesContextMissingCoverageFetchFromMs({
3088
3096
  ranges: coverageRangesBySymbol.get(normalizedSymbol),
3089
3097
  fromMs: cursor,
3090
3098
  toMs,
@@ -3094,16 +3102,20 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3094
3102
  return null;
3095
3103
  }
3096
3104
  const edges = edgesBySymbol.get(normalizedSymbol);
3097
- const edgesFromMs = resolveDerivativesContextMissingFetchFromMs({
3105
+ const edgesFromMs = resolveDerivativesContextFetchFromMs({
3098
3106
  edges,
3099
3107
  fromMs: cursor,
3100
3108
  toMs,
3101
- intervalMs
3109
+ intervalMs,
3110
+ refreshClosedTail: mode === "signals"
3102
3111
  });
3103
3112
  if (edgesFromMs == null) {
3104
3113
  return null;
3105
3114
  }
3106
- return { item, fromMs: Math.max(coverageFromMs, edgesFromMs) };
3115
+ return {
3116
+ item,
3117
+ fromMs: Math.max(coverageFromMs, edgesFromMs)
3118
+ };
3107
3119
  }).filter(
3108
3120
  (item) => item != null
3109
3121
  );
@@ -3117,85 +3129,113 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
3117
3129
  const marketSymbols = missingBatch.map(
3118
3130
  (item) => item.marketSymbol
3119
3131
  );
3120
- const oiMap = await fetchMetricBatch({
3121
- endpoint: oiPath,
3122
- metric: "oi",
3123
- marketSymbols,
3124
- apiKey,
3125
- interval,
3126
- fromMs: group.fromMs,
3127
- toMs
3128
- });
3129
- const fundingMap = await fetchMetricBatch({
3130
- endpoint: fundingPath,
3131
- metric: "funding",
3132
- marketSymbols,
3133
- apiKey,
3134
- interval,
3135
- fromMs: group.fromMs,
3136
- toMs
3137
- });
3138
- const liqMap = await fetchMetricBatch({
3139
- endpoint: liqPath,
3140
- metric: "liq",
3141
- marketSymbols,
3142
- apiKey,
3143
- interval,
3144
- fromMs: group.fromMs,
3145
- toMs
3146
- });
3147
- const rows = missingBatch.flatMap((item) => {
3148
- const marketSymbol = item.marketSymbol.toUpperCase();
3149
- const points = (0, import_indicators.mergeCoinalyzeMetrics)({
3150
- symbol: item.symbol,
3151
- oiRaw: oiMap.get(marketSymbol) ?? [],
3152
- fundingRaw: fundingMap.get(marketSymbol) ?? [],
3153
- liqRaw: liqMap.get(marketSymbol) ?? []
3132
+ const maxClosedBarAttempts = mode === "signals" ? asInt2(
3133
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_MAX_ATTEMPTS,
3134
+ 3
3135
+ ) : 1;
3136
+ const closedBarRetryDelayMs = asInt2(
3137
+ process.env.DERIVATIVES_CONTEXT_CLOSED_BAR_RETRY_DELAY_MS,
3138
+ 2e3
3139
+ );
3140
+ let rows = [];
3141
+ let missingClosedSymbols = [];
3142
+ for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
3143
+ const oiMap = await fetchMetricBatch({
3144
+ endpoint: oiPath,
3145
+ metric: "oi",
3146
+ marketSymbols,
3147
+ apiKey,
3148
+ interval,
3149
+ fromMs: group.fromMs,
3150
+ toMs
3151
+ });
3152
+ const fundingMap = await fetchMetricBatch({
3153
+ endpoint: fundingPath,
3154
+ metric: "funding",
3155
+ marketSymbols,
3156
+ apiKey,
3157
+ interval,
3158
+ fromMs: group.fromMs,
3159
+ toMs
3154
3160
  });
3155
- return (0, import_indicators.coinalyzePointsToRows)(points, interval, "coinalyze");
3156
- });
3161
+ const liqMap = await fetchMetricBatch({
3162
+ endpoint: liqPath,
3163
+ metric: "liq",
3164
+ marketSymbols,
3165
+ apiKey,
3166
+ interval,
3167
+ fromMs: group.fromMs,
3168
+ toMs
3169
+ });
3170
+ rows = missingBatch.flatMap((item) => {
3171
+ const marketSymbol = item.marketSymbol.toUpperCase();
3172
+ const points = (0, import_indicators.mergeCoinalyzeMetrics)({
3173
+ symbol: item.symbol,
3174
+ oiRaw: oiMap.get(marketSymbol) ?? [],
3175
+ fundingRaw: fundingMap.get(marketSymbol) ?? [],
3176
+ liqRaw: liqMap.get(marketSymbol) ?? []
3177
+ });
3178
+ return (0, import_indicators.coinalyzePointsToRows)(points, interval, "coinalyze");
3179
+ });
3180
+ missingClosedSymbols = mode === "signals" ? getMissingClosedDerivativesSymbols({
3181
+ symbols: missingBatch.map((item) => item.symbol),
3182
+ rows,
3183
+ expectedTimestamp: toMs
3184
+ }) : [];
3185
+ if (!missingClosedSymbols.length) break;
3186
+ if (attempt < maxClosedBarAttempts) {
3187
+ await (0, import_async.delay)(closedBarRetryDelayMs);
3188
+ }
3189
+ }
3190
+ if (missingClosedSymbols.length) {
3191
+ throw new Error(
3192
+ `Coinalyze closed ${interval} bar ${new Date(toMs).toISOString()} unavailable for ${missingClosedSymbols.join(",")}`
3193
+ );
3194
+ }
3157
3195
  if (rows.length) {
3158
3196
  await (0, import_timescale2.upsertDerivatives)(rows);
3159
3197
  totalRows += rows.length;
3160
3198
  }
3161
- const rowsCountBySymbol = /* @__PURE__ */ new Map();
3162
- for (const row of rows) {
3163
- const symbol = row.symbol.toUpperCase();
3164
- rowsCountBySymbol.set(
3165
- symbol,
3166
- (rowsCountBySymbol.get(symbol) ?? 0) + 1
3167
- );
3168
- }
3169
- const coverageRows = missingBatch.map((item) => {
3170
- const normalizedSymbol = item.symbol.toUpperCase();
3171
- const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
3172
- return {
3173
- source: "coinalyze",
3174
- symbol: item.symbol,
3175
- interval,
3176
- fromMs: cursor,
3177
- toMs,
3178
- rowsCount
3179
- };
3180
- });
3181
- await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
3182
- for (const coverageRow of coverageRows) {
3183
- const symbol = coverageRow.symbol.toUpperCase();
3184
- edgesBySymbol.set(
3185
- symbol,
3186
- extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
3187
- );
3188
- coverageKeys.add(
3189
- coverageKey({
3199
+ if (mode === "backtest") {
3200
+ const rowsCountBySymbol = /* @__PURE__ */ new Map();
3201
+ for (const row of rows) {
3202
+ const symbol = row.symbol.toUpperCase();
3203
+ rowsCountBySymbol.set(
3190
3204
  symbol,
3205
+ (rowsCountBySymbol.get(symbol) ?? 0) + 1
3206
+ );
3207
+ }
3208
+ const coverageRows = missingBatch.map((item) => {
3209
+ const normalizedSymbol = item.symbol.toUpperCase();
3210
+ const rowsCount = rowsCountBySymbol.get(normalizedSymbol) ?? 0;
3211
+ return {
3212
+ source: "coinalyze",
3213
+ symbol: item.symbol,
3191
3214
  interval,
3192
3215
  fromMs: cursor,
3193
- toMs
3194
- })
3195
- );
3196
- const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
3197
- coverageRanges.push({ fromMs: cursor, toMs });
3198
- coverageRangesBySymbol.set(symbol, coverageRanges);
3216
+ toMs,
3217
+ rowsCount
3218
+ };
3219
+ });
3220
+ await (0, import_timescale2.upsertDerivativesBackfillCoverage)(coverageRows);
3221
+ for (const coverageRow of coverageRows) {
3222
+ const symbol = coverageRow.symbol.toUpperCase();
3223
+ edgesBySymbol.set(
3224
+ symbol,
3225
+ extendEdges(edgesBySymbol.get(symbol), cursor, toMs)
3226
+ );
3227
+ coverageKeys.add(
3228
+ coverageKey({
3229
+ symbol,
3230
+ interval,
3231
+ fromMs: cursor,
3232
+ toMs
3233
+ })
3234
+ );
3235
+ const coverageRanges = coverageRangesBySymbol.get(symbol) ?? [];
3236
+ coverageRanges.push({ fromMs: cursor, toMs });
3237
+ coverageRangesBySymbol.set(symbol, coverageRanges);
3238
+ }
3199
3239
  }
3200
3240
  }
3201
3241
  }
@@ -2510,7 +2510,6 @@ var RESEARCH_CONTEXT_ENV_KEYS = [
2510
2510
  "INTERVAL",
2511
2511
  "DERIVATIVES_CONTEXT_ENABLED",
2512
2512
  "DERIVATIVES_CONTEXT_TARGET_ENABLED",
2513
- "DERIVATIVES_CONTEXT_INTERVALS",
2514
2513
  "DERIVATIVES_CONTEXT_LOOKBACK_HOURS",
2515
2514
  "DERIVATIVES_CONTEXT_EXTRA_REFERENCE_SYMBOLS",
2516
2515
  "DERIVATIVES_CONTEXT_EXCHANGE_PRIORITY",