@tradejs/cli 3.1.29-beta.292 → 3.1.29-beta.296

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.
@@ -30,7 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/scripts/backtest.ts
31
31
  var backtest_exports = {};
32
32
  __export(backtest_exports, {
33
- BACKTEST_PRELOAD_DAYS: () => import_constants6.BACKTEST_PRELOAD_DAYS,
33
+ BACKTEST_PRELOAD_DAYS: () => import_constants7.BACKTEST_PRELOAD_DAYS,
34
34
  backtest: () => backtest,
35
35
  chunkTestSuiteBySymbol: () => chunkTestSuiteBySymbol,
36
36
  interval: () => interval,
@@ -62,8 +62,8 @@ var import_chalk10 = __toESM(require("chalk"));
62
62
  var import_backtest3 = require("@tradejs/core/backtest");
63
63
  var import_grid = require("@tradejs/core/grid");
64
64
  var import_data = require("@tradejs/core/data");
65
- var import_redis5 = require("@tradejs/infra/redis");
66
- var import_constants6 = require("@tradejs/core/constants");
65
+ var import_redis6 = require("@tradejs/infra/redis");
66
+ var import_constants7 = require("@tradejs/core/constants");
67
67
 
68
68
  // src/lib/backtest/jevOptions.ts
69
69
  var import_promises = __toESM(require("fs/promises"));
@@ -491,13 +491,12 @@ var getReferenceSymbols = () => {
491
491
  };
492
492
  var intervalToMarketFeatureInterval = (interval2) => {
493
493
  const normalized = String(interval2).trim().toLowerCase();
494
- if (normalized === "1" || normalized === "1m") return "1m";
494
+ if (normalized === "1" || normalized === "1m") return null;
495
495
  if (normalized === "5" || normalized === "5m") return "5m";
496
496
  if (normalized === "60" || normalized === "1h") return "1h";
497
497
  return "15m";
498
498
  };
499
499
  var marketIntervalToConnectorInterval = (interval2) => {
500
- if (interval2 === "1m") return "1";
501
500
  if (interval2 === "5m") return "5";
502
501
  if (interval2 === "1h") return "60";
503
502
  return "15";
@@ -662,6 +661,7 @@ var backfillBinanceMarketContext = async (params, enabled) => {
662
661
  return skippedBackfillResult();
663
662
  }
664
663
  const interval2 = intervalToMarketFeatureInterval(params.interval);
664
+ if (interval2 === null) return skippedBackfillResult();
665
665
  const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval2];
666
666
  const { breadthStartMs, tradeFlowStartMs, endMs } = resolveBinanceMarketContextBackfillWindow(params);
667
667
  if (endMs <= Math.min(breadthStartMs, tradeFlowStartMs)) {
@@ -2242,7 +2242,7 @@ var coinMarketCapFetch = async (params) => {
2242
2242
  };
2243
2243
  var fetchCoinMarketCapIndexRows = async (params) => {
2244
2244
  const rows = [];
2245
- const maxChunkDays = 9;
2245
+ const maxChunkDays = 4;
2246
2246
  const totalChunks = Math.max(
2247
2247
  1,
2248
2248
  Math.ceil(
@@ -4777,7 +4777,9 @@ var executeBacktestWorkerPool = async ({
4777
4777
  chunkTestSuite,
4778
4778
  getProgressSnapshot,
4779
4779
  initialCompletedTests = 0,
4780
- totalTests
4780
+ totalTests,
4781
+ onProgress,
4782
+ onIncomplete
4781
4783
  }) => {
4782
4784
  const chunks = chunkTestSuite(testSuite);
4783
4785
  const fastAiWorkerPgPoolMax = resolveFastAiWorkerPgPoolMax(
@@ -4793,7 +4795,9 @@ var executeBacktestWorkerPool = async ({
4793
4795
  );
4794
4796
  let completedTests = initialCompletedTests;
4795
4797
  let renderedTests = 0;
4798
+ let pendingResults = 0;
4796
4799
  let isFinishing = false;
4800
+ let isInterrupted = false;
4797
4801
  let signalHandlersRemoved = false;
4798
4802
  const workers = /* @__PURE__ */ new Set();
4799
4803
  const stopWorkers = () => {
@@ -4804,6 +4808,7 @@ var executeBacktestWorkerPool = async ({
4804
4808
  }
4805
4809
  };
4806
4810
  const handleInterrupt = (signal, exitCode) => {
4811
+ isInterrupted = true;
4807
4812
  stopWorkers();
4808
4813
  void Promise.resolve(onInterrupt?.(signal)).catch((error) => {
4809
4814
  console.error(
@@ -4824,15 +4829,16 @@ var executeBacktestWorkerPool = async ({
4824
4829
  process.removeListener("SIGTERM", handleSigterm);
4825
4830
  };
4826
4831
  const maybeFinish = async () => {
4827
- if (isFinishing) {
4828
- return;
4829
- }
4830
- if (completedTests !== totalExpectedTests || workers.size > 0) {
4832
+ if (isFinishing || isInterrupted || workers.size > 0 || pendingResults > 0) {
4831
4833
  return;
4832
4834
  }
4833
4835
  isFinishing = true;
4834
4836
  try {
4835
- await onFinish();
4837
+ if (completedTests === totalExpectedTests) {
4838
+ await onFinish();
4839
+ } else {
4840
+ await onIncomplete?.();
4841
+ }
4836
4842
  } finally {
4837
4843
  cleanupSignalHandlers();
4838
4844
  }
@@ -4891,14 +4897,22 @@ var executeBacktestWorkerPool = async ({
4891
4897
  return;
4892
4898
  }
4893
4899
  completedTests++;
4894
- await onMessage(msg);
4895
- if (completedTests % progressStep2 === 0 || completedTests === totalExpectedTests) {
4896
- tickProgress();
4900
+ onProgress?.(completedTests);
4901
+ pendingResults++;
4902
+ try {
4903
+ await onMessage(msg);
4904
+ if (completedTests % progressStep2 === 0 || completedTests === totalExpectedTests) {
4905
+ tickProgress();
4906
+ }
4907
+ } finally {
4908
+ pendingResults--;
4897
4909
  }
4910
+ await maybeFinish();
4898
4911
  });
4899
4912
  tester.on("error", (err) => {
4900
4913
  workers.delete(tester);
4901
4914
  onWorkerError(err?.message ?? String(err));
4915
+ void maybeFinish();
4902
4916
  });
4903
4917
  tester.on("exit", (code) => {
4904
4918
  workers.delete(tester);
@@ -5285,7 +5299,9 @@ var executeTestSuite = async ({
5285
5299
  onFinish,
5286
5300
  initialCompletedTests = 0,
5287
5301
  totalTests,
5288
- backtestRunId
5302
+ backtestRunId,
5303
+ onProgress,
5304
+ onIncomplete
5289
5305
  }) => {
5290
5306
  markTestsStarted();
5291
5307
  const { testerWorkerPath, testerNeedsTsRuntime } = resolveTesterWorker();
@@ -5309,6 +5325,8 @@ var executeTestSuite = async ({
5309
5325
  chunkTestSuite: (suite) => chunkTestSuiteBySymbol(suite, effectiveParallel),
5310
5326
  initialCompletedTests,
5311
5327
  totalTests,
5328
+ onProgress,
5329
+ onIncomplete,
5312
5330
  onInterrupt,
5313
5331
  onMessage: async (msg) => {
5314
5332
  if (msg.error) {
@@ -5362,6 +5380,106 @@ var printRunOutro = () => {
5362
5380
  console.log("");
5363
5381
  };
5364
5382
 
5383
+ // src/lib/backtest/observeRun.ts
5384
+ var import_constants6 = require("@tradejs/core/constants");
5385
+ var import_redis5 = require("@tradejs/infra/redis");
5386
+ var import_logger = require("@tradejs/infra/logger");
5387
+ var HEARTBEAT_MS = 2e3;
5388
+ var ACTIVE_TTL_SECONDS = 30;
5389
+ var LINKED_RUN_TTL_SECONDS = 30 * 24 * import_constants6.TTL_1H;
5390
+ var RESEARCH_STUDY = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}\/\d{4}-\d{2}-\d{2}-[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/;
5391
+ var MAX_VALUES_PER_PARAMETER = 12;
5392
+ var MAX_VALUE_LENGTH = 500;
5393
+ var summarizeBacktestParameters = (tests) => {
5394
+ const parameters = /* @__PURE__ */ new Map();
5395
+ for (const test of tests) {
5396
+ for (const [name, value] of Object.entries(test.strategyConfig)) {
5397
+ const serialized = JSON.stringify(value);
5398
+ if (serialized === void 0) continue;
5399
+ const parameter = parameters.get(name) ?? {
5400
+ values: /* @__PURE__ */ new Set(),
5401
+ truncated: false
5402
+ };
5403
+ parameters.set(name, parameter);
5404
+ if (parameter.values.has(serialized)) continue;
5405
+ if (parameter.values.size === MAX_VALUES_PER_PARAMETER || serialized.length > MAX_VALUE_LENGTH) {
5406
+ parameter.truncated = true;
5407
+ } else {
5408
+ parameter.values.add(serialized);
5409
+ }
5410
+ }
5411
+ }
5412
+ return [...parameters].map(([name, { values, truncated }]) => ({
5413
+ name,
5414
+ values: [...values],
5415
+ truncated
5416
+ }));
5417
+ };
5418
+ var observeBacktestRun = async (manifest, initialCompleted, parallel) => {
5419
+ if (process.env.TRADEJS_BACKTEST_WEB_JOB === "1") return;
5420
+ const researchStudy = process.env.TRADEJS_RESEARCH_STUDY?.trim();
5421
+ const linkedStudy = researchStudy && RESEARCH_STUDY.test(researchStudy) ? researchStudy : void 0;
5422
+ if (researchStudy && !linkedStudy) {
5423
+ import_logger.logger.warn(
5424
+ "invalid TRADEJS_RESEARCH_STUDY; expected Strategy/YYYY-MM-DD-slug"
5425
+ );
5426
+ }
5427
+ const { testSuite } = manifest;
5428
+ const firstTest = testSuite[0];
5429
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
5430
+ const run = {
5431
+ id: manifest.runId,
5432
+ ...linkedStudy && { researchStudy: linkedStudy },
5433
+ userName: manifest.userName,
5434
+ strategyName: firstTest.strategyName,
5435
+ configId: manifest.config,
5436
+ connector: manifest.connectorName,
5437
+ interval: manifest.interval,
5438
+ startTime: manifest.window.start,
5439
+ endTime: manifest.window.end,
5440
+ symbols: [...new Set(testSuite.map((test) => test.symbol))],
5441
+ settings: {
5442
+ ...manifest.flags,
5443
+ parallel,
5444
+ ...firstTest.executionCosts && {
5445
+ executionCosts: JSON.stringify(firstTest.executionCosts)
5446
+ }
5447
+ },
5448
+ parameters: summarizeBacktestParameters(testSuite),
5449
+ status: "running",
5450
+ completed: initialCompleted,
5451
+ total: testSuite.length,
5452
+ startedAt,
5453
+ updatedAt: startedAt
5454
+ };
5455
+ const save = async (expire) => {
5456
+ run.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
5457
+ try {
5458
+ await import_redis5.cliBacktestRunStorage.put(run, expire);
5459
+ } catch (error) {
5460
+ import_logger.logger.warn("failed to publish CLI backtest progress: %s", String(error));
5461
+ }
5462
+ };
5463
+ await save(ACTIVE_TTL_SECONDS);
5464
+ let pending;
5465
+ const timer = setInterval(() => {
5466
+ pending ??= save(ACTIVE_TTL_SECONDS).finally(() => {
5467
+ pending = void 0;
5468
+ });
5469
+ }, HEARTBEAT_MS).unref();
5470
+ return {
5471
+ progress: (completed) => {
5472
+ run.completed = completed;
5473
+ },
5474
+ finish: async (status) => {
5475
+ clearInterval(timer);
5476
+ await pending;
5477
+ run.status = status;
5478
+ await save(linkedStudy ? LINKED_RUN_TTL_SECONDS : import_constants6.TTL_1H);
5479
+ }
5480
+ };
5481
+ };
5482
+
5365
5483
  // src/scripts/backtest.ts
5366
5484
  if (process.argv.some(
5367
5485
  (arg) => arg === "--live" || String(arg).startsWith("--live=")
@@ -5497,8 +5615,8 @@ var loadBacktestConfig = async () => {
5497
5615
  if (!strategyName) {
5498
5616
  throw new Error("Strategy name not found");
5499
5617
  }
5500
- const backtestConfig = await (0, import_redis5.getData)(
5501
- import_redis5.redisKeys.backtestConfig(userName, flags.config),
5618
+ const backtestConfig = await (0, import_redis6.getData)(
5619
+ import_redis6.redisKeys.backtestConfig(userName, flags.config),
5502
5620
  null
5503
5621
  );
5504
5622
  if (!backtestConfig) {
@@ -5645,8 +5763,8 @@ var finishBacktest = async (testSuite) => {
5645
5763
  console.log(import_chalk10.default.gray(`full report: ${markdownReportPath}`));
5646
5764
  console.log("");
5647
5765
  if (!isFastMode || flags.persistResults) {
5648
- await (0, import_redis5.setData)(
5649
- import_redis5.redisKeys.backtestResults(userName, flags.config, timestamp),
5766
+ await (0, import_redis6.setData)(
5767
+ import_redis6.redisKeys.backtestResults(userName, flags.config, timestamp),
5650
5768
  {
5651
5769
  config: flags.config,
5652
5770
  mode: "config",
@@ -5666,11 +5784,10 @@ var finishBacktest = async (testSuite) => {
5666
5784
  errorTests: errorTests2
5667
5785
  },
5668
5786
  {
5669
- expire: import_constants6.TTL_1M
5787
+ expire: import_constants7.TTL_1M
5670
5788
  }
5671
5789
  );
5672
5790
  }
5673
- process.exit();
5674
5791
  };
5675
5792
  var restoreCompletedBacktestResults = (completed) => {
5676
5793
  for (const { result } of completed) {
@@ -5751,6 +5868,56 @@ var prepareContinuedBacktestMarketContext = async ({
5751
5868
  log: (message) => console.log(import_chalk10.default.gray(message))
5752
5869
  });
5753
5870
  };
5871
+ var runBacktestSuite = async (manifest, testSuite, initialCompletedTests = 0) => {
5872
+ const observation = await observeBacktestRun(
5873
+ manifest,
5874
+ initialCompletedTests,
5875
+ effectiveParallel
5876
+ );
5877
+ try {
5878
+ await executeTestSuite({
5879
+ testSuite,
5880
+ window: manifest.window,
5881
+ preloadStart: manifest.preloadStart,
5882
+ backtestRunId: manifest.runId,
5883
+ initialCompletedTests,
5884
+ totalTests: manifest.testSuite.length,
5885
+ onProgress: observation?.progress,
5886
+ onIncomplete: async () => {
5887
+ await observation?.finish("failed");
5888
+ await markBacktestRunStatus({ run: manifest, status: "interrupted" });
5889
+ process.exit(1);
5890
+ },
5891
+ onResult: async (result) => {
5892
+ await saveBacktestCheckpointResult({
5893
+ result,
5894
+ runId: manifest.runId,
5895
+ userName
5896
+ });
5897
+ trackTopResult(result);
5898
+ updateBestTickerResult(result);
5899
+ },
5900
+ onInterrupt: async () => {
5901
+ await observation?.finish("cancelled");
5902
+ await markBacktestRunStatus({ run: manifest, status: "interrupted" });
5903
+ },
5904
+ onFinish: async () => {
5905
+ try {
5906
+ await markBacktestRunStatus({ run: manifest, status: "completed" });
5907
+ await finishBacktest(manifest.testSuite);
5908
+ await observation?.finish("completed");
5909
+ process.exit();
5910
+ } catch (error) {
5911
+ await observation?.finish("failed");
5912
+ throw error;
5913
+ }
5914
+ }
5915
+ });
5916
+ } catch (error) {
5917
+ await observation?.finish("failed");
5918
+ throw error;
5919
+ }
5920
+ };
5754
5921
  var backtest = async () => {
5755
5922
  resetRunState();
5756
5923
  const config = await loadBacktestConfig();
@@ -5765,33 +5932,10 @@ var backtest = async () => {
5765
5932
  if (!remainingSuite.length) {
5766
5933
  await markBacktestRunStatus({ run: manifest2, status: "completed" });
5767
5934
  await finishBacktest(manifest2.testSuite);
5768
- return;
5935
+ process.exit();
5769
5936
  }
5770
5937
  await prepareContinuedBacktestMarketContext({ manifest: manifest2, remainingSuite });
5771
- await executeTestSuite({
5772
- testSuite: remainingSuite,
5773
- window: manifest2.window,
5774
- preloadStart: manifest2.preloadStart,
5775
- backtestRunId: manifest2.runId,
5776
- initialCompletedTests: completed.length,
5777
- totalTests: manifest2.testSuite.length,
5778
- onResult: async (result) => {
5779
- await saveBacktestCheckpointResult({
5780
- result,
5781
- runId: manifest2.runId,
5782
- userName
5783
- });
5784
- trackTopResult(result);
5785
- updateBestTickerResult(result);
5786
- },
5787
- onInterrupt: async () => {
5788
- await markBacktestRunStatus({ run: manifest2, status: "interrupted" });
5789
- },
5790
- onFinish: async () => {
5791
- await markBacktestRunStatus({ run: manifest2, status: "completed" });
5792
- await finishBacktest(manifest2.testSuite);
5793
- }
5794
- });
5938
+ await runBacktestSuite(manifest2, remainingSuite, completed.length);
5795
5939
  return;
5796
5940
  }
5797
5941
  const preparedRun = await prepareRunEnvironment2(config.strategyName);
@@ -5852,28 +5996,7 @@ var backtest = async () => {
5852
5996
  testSuite
5853
5997
  });
5854
5998
  console.log(import_chalk10.default.gray(`backtest run id: ${manifest.runId}`));
5855
- await executeTestSuite({
5856
- testSuite,
5857
- window: preparedRun.window,
5858
- preloadStart: preparedRun.preloadStart,
5859
- backtestRunId: manifest.runId,
5860
- onResult: async (result) => {
5861
- await saveBacktestCheckpointResult({
5862
- result,
5863
- runId: manifest.runId,
5864
- userName
5865
- });
5866
- trackTopResult(result);
5867
- updateBestTickerResult(result);
5868
- },
5869
- onInterrupt: async () => {
5870
- await markBacktestRunStatus({ run: manifest, status: "interrupted" });
5871
- },
5872
- onFinish: async () => {
5873
- await markBacktestRunStatus({ run: manifest, status: "completed" });
5874
- await finishBacktest(testSuite);
5875
- }
5876
- });
5999
+ await runBacktestSuite(manifest, testSuite);
5877
6000
  };
5878
6001
  var main = backtest;
5879
6002
  // Annotate the CommonJS export names for ESM import in node:
@@ -352,7 +352,7 @@ var buildMarketBreadthRows = ({
352
352
 
353
353
  // src/scripts/binanceMarketIngest.ts
354
354
  import_args.default.example(
355
- "yarn cli:node8g binance:market-ingest --all --symbols BTCUSDT,ETHUSDT --days 0.05 --interval 1m --write",
355
+ "yarn cli:node8g binance:market-ingest --all --symbols BTCUSDT,ETHUSDT --days 0.05 --interval 15m --write",
356
356
  "Ingest Binance public market breadth and historical aggTrades buckets"
357
357
  );
358
358
  import_args.default.option(
@@ -360,7 +360,7 @@ import_args.default.option(
360
360
  "Comma-separated target symbols",
361
361
  "BTCUSDT,ETHUSDT"
362
362
  );
363
- import_args.default.option(["i", "interval"], "Aggregation interval: 1m,5m,15m,1h", "1m");
363
+ import_args.default.option(["i", "interval"], "Aggregation interval: 5m,15m,1h", "15m");
364
364
  import_args.default.option(["d", "days"], "Lookback window in days", "1");
365
365
  import_args.default.option(["h", "hours"], "Lookback window in hours; overrides --days");
366
366
  import_args.default.option(["a", "aggTrades"], "Fetch and bucket Binance aggTrades");
@@ -394,7 +394,6 @@ var asInt = (value, fallback) => {
394
394
  };
395
395
  var sleep = (ms) => ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
396
396
  var intervalToConnectorInterval = (interval) => {
397
- if (interval === "1m") return "1";
398
397
  if (interval === "5m") return "5";
399
398
  if (interval === "15m") return "15";
400
399
  return "60";
@@ -450,6 +449,7 @@ var printEstimate = (estimate) => {
450
449
  var main = async () => {
451
450
  const symbols = normalizeBinanceSymbols(flags.symbols);
452
451
  const interval = normalizeMarketFeatureInterval(flags.interval);
452
+ if (interval === "1m") throw new Error("Use interval 5m, 15m, or 1h");
453
453
  const hours = flags.hours == null ? null : asFloat(flags.hours, 0);
454
454
  const days = hours != null && hours > 0 ? hours / 24 : asFloat(flags.days, 1);
455
455
  const breadthUniverses = (0, import_strategies.getBinanceBreadthUniverses)();
@@ -1515,13 +1515,12 @@ var getReferenceSymbols = () => {
1515
1515
  };
1516
1516
  var intervalToMarketFeatureInterval = (interval) => {
1517
1517
  const normalized = String(interval).trim().toLowerCase();
1518
- if (normalized === "1" || normalized === "1m") return "1m";
1518
+ if (normalized === "1" || normalized === "1m") return null;
1519
1519
  if (normalized === "5" || normalized === "5m") return "5m";
1520
1520
  if (normalized === "60" || normalized === "1h") return "1h";
1521
1521
  return "15m";
1522
1522
  };
1523
1523
  var marketIntervalToConnectorInterval = (interval) => {
1524
- if (interval === "1m") return "1";
1525
1524
  if (interval === "5m") return "5";
1526
1525
  if (interval === "1h") return "60";
1527
1526
  return "15";
@@ -1686,6 +1685,7 @@ var backfillBinanceMarketContext = async (params, enabled) => {
1686
1685
  return skippedBackfillResult();
1687
1686
  }
1688
1687
  const interval = intervalToMarketFeatureInterval(params.interval);
1688
+ if (interval === null) return skippedBackfillResult();
1689
1689
  const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
1690
1690
  const { breadthStartMs, tradeFlowStartMs, endMs } = resolveBinanceMarketContextBackfillWindow(params);
1691
1691
  if (endMs <= Math.min(breadthStartMs, tradeFlowStartMs)) {
@@ -3266,7 +3266,7 @@ var coinMarketCapFetch = async (params) => {
3266
3266
  };
3267
3267
  var fetchCoinMarketCapIndexRows = async (params) => {
3268
3268
  const rows = [];
3269
- const maxChunkDays = 9;
3269
+ const maxChunkDays = 4;
3270
3270
  const totalChunks = Math.max(
3271
3271
  1,
3272
3272
  Math.ceil(
@@ -1520,13 +1520,12 @@ var getReferenceSymbols = () => {
1520
1520
  };
1521
1521
  var intervalToMarketFeatureInterval = (interval) => {
1522
1522
  const normalized = String(interval).trim().toLowerCase();
1523
- if (normalized === "1" || normalized === "1m") return "1m";
1523
+ if (normalized === "1" || normalized === "1m") return null;
1524
1524
  if (normalized === "5" || normalized === "5m") return "5m";
1525
1525
  if (normalized === "60" || normalized === "1h") return "1h";
1526
1526
  return "15m";
1527
1527
  };
1528
1528
  var marketIntervalToConnectorInterval = (interval) => {
1529
- if (interval === "1m") return "1";
1530
1529
  if (interval === "5m") return "5";
1531
1530
  if (interval === "1h") return "60";
1532
1531
  return "15";
@@ -1691,6 +1690,7 @@ var backfillBinanceMarketContext = async (params, enabled) => {
1691
1690
  return skippedBackfillResult();
1692
1691
  }
1693
1692
  const interval = intervalToMarketFeatureInterval(params.interval);
1693
+ if (interval === null) return skippedBackfillResult();
1694
1694
  const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
1695
1695
  const { breadthStartMs, tradeFlowStartMs, endMs } = resolveBinanceMarketContextBackfillWindow(params);
1696
1696
  if (endMs <= Math.min(breadthStartMs, tradeFlowStartMs)) {
@@ -3271,7 +3271,7 @@ var coinMarketCapFetch = async (params) => {
3271
3271
  };
3272
3272
  var fetchCoinMarketCapIndexRows = async (params) => {
3273
3273
  const rows = [];
3274
- const maxChunkDays = 9;
3274
+ const maxChunkDays = 4;
3275
3275
  const totalChunks = Math.max(
3276
3276
  1,
3277
3277
  Math.ceil(
@@ -1028,13 +1028,12 @@ var getReferenceSymbols = () => {
1028
1028
  };
1029
1029
  var intervalToMarketFeatureInterval = (interval2) => {
1030
1030
  const normalized = String(interval2).trim().toLowerCase();
1031
- if (normalized === "1" || normalized === "1m") return "1m";
1031
+ if (normalized === "1" || normalized === "1m") return null;
1032
1032
  if (normalized === "5" || normalized === "5m") return "5m";
1033
1033
  if (normalized === "60" || normalized === "1h") return "1h";
1034
1034
  return "15m";
1035
1035
  };
1036
1036
  var marketIntervalToConnectorInterval = (interval2) => {
1037
- if (interval2 === "1m") return "1";
1038
1037
  if (interval2 === "5m") return "5";
1039
1038
  if (interval2 === "1h") return "60";
1040
1039
  return "15";
@@ -1199,6 +1198,7 @@ var backfillBinanceMarketContext = async (params, enabled) => {
1199
1198
  return skippedBackfillResult();
1200
1199
  }
1201
1200
  const interval2 = intervalToMarketFeatureInterval(params.interval);
1201
+ if (interval2 === null) return skippedBackfillResult();
1202
1202
  const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval2];
1203
1203
  const { breadthStartMs, tradeFlowStartMs, endMs } = resolveBinanceMarketContextBackfillWindow(params);
1204
1204
  if (endMs <= Math.min(breadthStartMs, tradeFlowStartMs)) {
@@ -2779,7 +2779,7 @@ var coinMarketCapFetch = async (params) => {
2779
2779
  };
2780
2780
  var fetchCoinMarketCapIndexRows = async (params) => {
2781
2781
  const rows = [];
2782
- const maxChunkDays = 9;
2782
+ const maxChunkDays = 4;
2783
2783
  const totalChunks = Math.max(
2784
2784
  1,
2785
2785
  Math.ceil(
@@ -488,13 +488,12 @@ var getReferenceSymbols = () => {
488
488
  };
489
489
  var intervalToMarketFeatureInterval = (interval) => {
490
490
  const normalized = String(interval).trim().toLowerCase();
491
- if (normalized === "1" || normalized === "1m") return "1m";
491
+ if (normalized === "1" || normalized === "1m") return null;
492
492
  if (normalized === "5" || normalized === "5m") return "5m";
493
493
  if (normalized === "60" || normalized === "1h") return "1h";
494
494
  return "15m";
495
495
  };
496
496
  var marketIntervalToConnectorInterval = (interval) => {
497
- if (interval === "1m") return "1";
498
497
  if (interval === "5m") return "5";
499
498
  if (interval === "1h") return "60";
500
499
  return "15";
@@ -659,6 +658,7 @@ var backfillBinanceMarketContext = async (params, enabled) => {
659
658
  return skippedBackfillResult();
660
659
  }
661
660
  const interval = intervalToMarketFeatureInterval(params.interval);
661
+ if (interval === null) return skippedBackfillResult();
662
662
  const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
663
663
  const { breadthStartMs, tradeFlowStartMs, endMs } = resolveBinanceMarketContextBackfillWindow(params);
664
664
  if (endMs <= Math.min(breadthStartMs, tradeFlowStartMs)) {
@@ -2239,7 +2239,7 @@ var coinMarketCapFetch = async (params) => {
2239
2239
  };
2240
2240
  var fetchCoinMarketCapIndexRows = async (params) => {
2241
2241
  const rows = [];
2242
- const maxChunkDays = 9;
2242
+ const maxChunkDays = 4;
2243
2243
  const totalChunks = Math.max(
2244
2244
  1,
2245
2245
  Math.ceil(
@@ -486,13 +486,12 @@ var getReferenceSymbols = () => {
486
486
  };
487
487
  var intervalToMarketFeatureInterval = (interval) => {
488
488
  const normalized = String(interval).trim().toLowerCase();
489
- if (normalized === "1" || normalized === "1m") return "1m";
489
+ if (normalized === "1" || normalized === "1m") return null;
490
490
  if (normalized === "5" || normalized === "5m") return "5m";
491
491
  if (normalized === "60" || normalized === "1h") return "1h";
492
492
  return "15m";
493
493
  };
494
494
  var marketIntervalToConnectorInterval = (interval) => {
495
- if (interval === "1m") return "1";
496
495
  if (interval === "5m") return "5";
497
496
  if (interval === "1h") return "60";
498
497
  return "15";
@@ -657,6 +656,7 @@ var backfillBinanceMarketContext = async (params, enabled) => {
657
656
  return skippedBackfillResult();
658
657
  }
659
658
  const interval = intervalToMarketFeatureInterval(params.interval);
659
+ if (interval === null) return skippedBackfillResult();
660
660
  const intervalMs = MARKET_FEATURE_INTERVAL_MS[interval];
661
661
  const { breadthStartMs, tradeFlowStartMs, endMs } = resolveBinanceMarketContextBackfillWindow(params);
662
662
  if (endMs <= Math.min(breadthStartMs, tradeFlowStartMs)) {
@@ -2237,7 +2237,7 @@ var coinMarketCapFetch = async (params) => {
2237
2237
  };
2238
2238
  var fetchCoinMarketCapIndexRows = async (params) => {
2239
2239
  const rows = [];
2240
- const maxChunkDays = 9;
2240
+ const maxChunkDays = 4;
2241
2241
  const totalChunks = Math.max(
2242
2242
  1,
2243
2243
  Math.ceil(