@tradejs/cli 2.0.16 → 2.0.18

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.
@@ -4352,27 +4352,27 @@ var createCoinMarketCapFetchStats = () => ({
4352
4352
  totalCredits: 0,
4353
4353
  byPath: /* @__PURE__ */ new Map()
4354
4354
  });
4355
- var getCoinMarketCapPathLabel = (path3) => {
4356
- if (path3.includes("global-metrics")) return "global";
4357
- if (path3.includes("cryptocurrency/quotes")) return "reference";
4358
- if (path3.includes("exchange/quotes")) return "exchangeLiquidity";
4359
- if (path3.includes("fear-and-greed")) return "fearGreed";
4360
- if (path3.includes("cmc100")) return "cmc100";
4361
- if (path3.includes("cmc20")) return "cmc20";
4362
- return path3;
4363
- };
4364
- var recordCoinMarketCapFetchStats = (stats, path3, creditCount) => {
4355
+ var getCoinMarketCapPathLabel = (path4) => {
4356
+ if (path4.includes("global-metrics")) return "global";
4357
+ if (path4.includes("cryptocurrency/quotes")) return "reference";
4358
+ if (path4.includes("exchange/quotes")) return "exchangeLiquidity";
4359
+ if (path4.includes("fear-and-greed")) return "fearGreed";
4360
+ if (path4.includes("cmc100")) return "cmc100";
4361
+ if (path4.includes("cmc20")) return "cmc20";
4362
+ return path4;
4363
+ };
4364
+ var recordCoinMarketCapFetchStats = (stats, path4, creditCount) => {
4365
4365
  if (!stats) return;
4366
- const existing = stats.byPath.get(path3) ?? { requests: 0, credits: 0 };
4366
+ const existing = stats.byPath.get(path4) ?? { requests: 0, credits: 0 };
4367
4367
  existing.requests += 1;
4368
4368
  existing.credits += creditCount ?? 0;
4369
4369
  stats.requests += 1;
4370
4370
  stats.totalCredits += creditCount ?? 0;
4371
- stats.byPath.set(path3, existing);
4371
+ stats.byPath.set(path4, existing);
4372
4372
  };
4373
4373
  var formatCoinMarketCapFetchStats = (stats) => {
4374
4374
  const byPath = [...stats.byPath.entries()].map(
4375
- ([path3, item]) => `${getCoinMarketCapPathLabel(path3)}=${item.requests}req/${item.credits}cr`
4375
+ ([path4, item]) => `${getCoinMarketCapPathLabel(path4)}=${item.requests}req/${item.credits}cr`
4376
4376
  ).join(" ");
4377
4377
  return `apiRequests=${stats.requests} apiCredits=${stats.totalCredits}${byPath ? ` ${byPath}` : ""}`;
4378
4378
  };
@@ -5186,6 +5186,7 @@ var backfillCoinMarketCapContextForReplay = backfillCoinMarketCapContext;
5186
5186
  var backfillCoinMarketCapContextForSignals = (params) => backfillCoinMarketCapContext({ ...params, refreshStaleFearGreed: true });
5187
5187
 
5188
5188
  // src/lib/hyperliquidWhaleBackfill.ts
5189
+ var import_progress3 = __toESM(require("progress"));
5189
5190
  var import_timescale4 = require("@tradejs/infra/timescale");
5190
5191
  var import_strategies2 = require("@tradejs/node/strategies");
5191
5192
 
@@ -5560,11 +5561,36 @@ var backfillHyperliquidWhaleContext = async (params) => {
5560
5561
  toMs,
5561
5562
  ...identity
5562
5563
  });
5564
+ const totalCoverageBuckets = Math.ceil(
5565
+ (toMs - fromMs) / HYPERLIQUID_WHALE_BUCKET_MS
5566
+ );
5567
+ const coverageBar = new import_progress3.default(
5568
+ "Hyperliquid coverage :current/:total [:bar][:percent] :eta(s) rows=:rows chunk=:chunk",
5569
+ {
5570
+ total: Math.max(1, totalCoverageBuckets),
5571
+ width: 24
5572
+ }
5573
+ );
5574
+ let displayedCoverageBuckets = 0;
5563
5575
  const coverageBuckets = await (0, import_timescale4.rebuildHyperliquidWhaleCoverageRows)({
5564
5576
  fromMs,
5565
5577
  toMs,
5566
5578
  expectedWhales: whales.addresses.length,
5567
- ...identity
5579
+ ...identity,
5580
+ onProgress: (progress) => {
5581
+ const next = Math.max(
5582
+ displayedCoverageBuckets,
5583
+ Math.min(progress.completedBuckets, coverageBar.total)
5584
+ );
5585
+ const delta = next - displayedCoverageBuckets;
5586
+ if (delta > 0) {
5587
+ coverageBar.tick(delta, {
5588
+ rows: progress.rows,
5589
+ chunk: `${progress.chunkIndex}/${progress.totalChunks}`
5590
+ });
5591
+ displayedCoverageBuckets = next;
5592
+ }
5593
+ }
5568
5594
  });
5569
5595
  const result = {
5570
5596
  cached: false,
@@ -5926,6 +5952,10 @@ import_args.default.option(["f", "timeframe"], "Timeframe", 15);
5926
5952
  import_args.default.option(["d", "days"], "Run replay only for the last N days");
5927
5953
  import_args.default.option("startTime", "Explicit replay start timestamp (ms or seconds)");
5928
5954
  import_args.default.option("endTime", "Explicit replay end timestamp (ms or seconds)");
5955
+ import_args.default.option(
5956
+ "runtimeEvidence",
5957
+ "Immutable runtime evidence JSON used for offline runtime comparison"
5958
+ );
5929
5959
  import_args.default.option(["u", "updateOnly"], "Only update tickers history", false);
5930
5960
  import_args.default.option(["C", "cacheOnly"], "Do not update tickers history", false);
5931
5961
  import_args.default.option(
@@ -5951,6 +5981,7 @@ var replayFlags = import_args.default.parse(replayNormalizedArgv);
5951
5981
  var replayInterval = String(replayFlags.timeframe ?? 15);
5952
5982
  var replayUserName = String(replayFlags.user ?? "root");
5953
5983
  var replayProjectRoot = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
5984
+ var replayRuntimeEvidencePath = typeof replayFlags.runtimeEvidence === "string" && replayFlags.runtimeEvidence.trim() ? replayFlags.runtimeEvidence.trim() : null;
5954
5985
  var isReplayUpdateOnlyRun = Boolean(replayFlags.updateOnly);
5955
5986
 
5956
5987
  // src/lib/replay/support.ts
@@ -6062,7 +6093,7 @@ var compactReplaySignal = (signal) => {
6062
6093
 
6063
6094
  // src/lib/replay/historicalSignalsReplay.ts
6064
6095
  var import_chalk9 = __toESM(require("chalk"));
6065
- var import_progress3 = __toESM(require("progress"));
6096
+ var import_progress4 = __toESM(require("progress"));
6066
6097
  var import_backtest = require("@tradejs/core/backtest");
6067
6098
  var import_strategies4 = require("@tradejs/core/strategies");
6068
6099
  var import_time3 = require("@tradejs/core/time");
@@ -6946,7 +6977,7 @@ var runHistoricalSignalsReplay = async ({
6946
6977
  const sharedReplayKeyPrefixes = [];
6947
6978
  let preparedSymbols = 0;
6948
6979
  let skippedSymbols = 0;
6949
- const prepareBar = new import_progress3.default(
6980
+ const prepareBar = new import_progress4.default(
6950
6981
  "prepare :current/:total [:bar][:percent] skipped=:skipped :etas(s) :symbol",
6951
6982
  {
6952
6983
  total: preparedRun.tickers.length,
@@ -7068,7 +7099,7 @@ var runHistoricalSignalsReplay = async ({
7068
7099
  interval
7069
7100
  });
7070
7101
  let abortedCycles = 0;
7071
- const cycleBar = new import_progress3.default(
7102
+ const cycleBar = new import_progress4.default(
7072
7103
  "cycles :current/:total [:bar][:percent] sig=:signals abort=:aborted :etas(s) :ts",
7073
7104
  {
7074
7105
  total: orderedTimestamps.length,
@@ -8783,6 +8814,114 @@ var buildReplayExchangeComparisonDetails = ({
8783
8814
  };
8784
8815
  };
8785
8816
 
8817
+ // src/lib/replay/runtimeEvidenceSource.ts
8818
+ var import_promises2 = __toESM(require("fs/promises"));
8819
+ var import_node_path2 = __toESM(require("path"));
8820
+ var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
8821
+ var asFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
8822
+ var unwrapRows = (value, field) => (Array.isArray(value) ? value : []).map((item) => {
8823
+ const row = asRecord(item);
8824
+ return asRecord(row?.[field]) ?? row;
8825
+ }).filter((item) => item != null);
8826
+ var buildRuntimeEvidenceLineageScopes = ({
8827
+ signals,
8828
+ evaluations
8829
+ }) => {
8830
+ const scopes = /* @__PURE__ */ new Map();
8831
+ const add = ({
8832
+ strategy,
8833
+ symbol,
8834
+ runtimeConfigId,
8835
+ timestamp,
8836
+ lineage
8837
+ }) => {
8838
+ if (!lineage || !Number.isFinite(timestamp)) {
8839
+ return;
8840
+ }
8841
+ const key = `${strategy}::${symbol}::${runtimeLineageKey(lineage)}`;
8842
+ const existing = scopes.get(key);
8843
+ scopes.set(key, {
8844
+ strategy,
8845
+ symbol,
8846
+ ...runtimeConfigId ? { runtimeConfigId } : {},
8847
+ lineage,
8848
+ firstTimestamp: existing ? Math.min(existing.firstTimestamp, timestamp) : timestamp,
8849
+ lastTimestamp: existing ? Math.max(existing.lastTimestamp, timestamp) : timestamp
8850
+ });
8851
+ };
8852
+ for (const signal of signals) {
8853
+ add({
8854
+ strategy: signal.strategy,
8855
+ symbol: signal.symbol,
8856
+ runtimeConfigId: signal.runtimeConfigId,
8857
+ timestamp: signal.timestamp,
8858
+ lineage: signal.runtimeLineage
8859
+ });
8860
+ }
8861
+ for (const evaluation of evaluations) {
8862
+ add({
8863
+ strategy: evaluation.strategy,
8864
+ symbol: evaluation.symbol,
8865
+ runtimeConfigId: evaluation.runtimeConfigId,
8866
+ timestamp: evaluation.timestamp,
8867
+ lineage: evaluation.runtimeLineage
8868
+ });
8869
+ }
8870
+ return [...scopes.values()].sort(
8871
+ (left, right) => left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol) || left.firstTimestamp - right.firstTimestamp
8872
+ );
8873
+ };
8874
+ var loadReplayRuntimeEvidenceSource = async ({
8875
+ filePath,
8876
+ projectRoot,
8877
+ expectedUserName,
8878
+ expectedWindow
8879
+ }) => {
8880
+ const resolvedPath = import_node_path2.default.resolve(projectRoot, filePath);
8881
+ const root = asRecord(
8882
+ JSON.parse(await import_promises2.default.readFile(resolvedPath, "utf8"))
8883
+ );
8884
+ const runtime = asRecord(root?.runtime) ?? root;
8885
+ if (!root || !runtime) {
8886
+ throw new Error(`Invalid runtime evidence JSON: ${resolvedPath}`);
8887
+ }
8888
+ const rootWindow = asRecord(root.window);
8889
+ const runtimeWindow = asRecord(runtime.window);
8890
+ const startTime = asFiniteNumber(rootWindow?.startTime) ?? asFiniteNumber(runtimeWindow?.startTime);
8891
+ const endTime = asFiniteNumber(rootWindow?.endTime) ?? asFiniteNumber(runtimeWindow?.endTime);
8892
+ const userName = String(root.userName ?? runtime.userName ?? "").trim();
8893
+ if (!userName || userName !== expectedUserName) {
8894
+ throw new Error(
8895
+ `Runtime evidence user mismatch: expected=${expectedUserName}, actual=${userName || "missing"}`
8896
+ );
8897
+ }
8898
+ const endTimeMatches = endTime === expectedWindow.end || endTime === expectedWindow.end + 1;
8899
+ if (startTime !== expectedWindow.start || !endTimeMatches) {
8900
+ throw new Error(
8901
+ `Runtime evidence window mismatch: expected=${expectedWindow.start}..${expectedWindow.end}, actual=${startTime ?? "missing"}..${endTime ?? "missing"}`
8902
+ );
8903
+ }
8904
+ const trades = unwrapRows(runtime.trades, "trade");
8905
+ const signals = unwrapRows(runtime.signals, "signal");
8906
+ const evaluations = unwrapRows(
8907
+ runtime.evaluations,
8908
+ "evaluation"
8909
+ );
8910
+ return {
8911
+ path: resolvedPath,
8912
+ userName,
8913
+ startTime,
8914
+ endTime,
8915
+ trades,
8916
+ signals,
8917
+ evaluations,
8918
+ lineageScopes: buildRuntimeEvidenceLineageScopes({
8919
+ signals,
8920
+ evaluations
8921
+ })
8922
+ };
8923
+ };
8924
+
8786
8925
  // src/lib/replay/runtimeComparison.ts
8787
8926
  var getReplayEntryTimestampCompareOffsetMs = () => {
8788
8927
  const intervalMinutes = Number(replayInterval);
@@ -9552,7 +9691,8 @@ var saveAndPrintReplayRuntimeComparison = async ({
9552
9691
  liveStrategySummaries,
9553
9692
  backtestEntries,
9554
9693
  replaySignals,
9555
- replayLineages
9694
+ replayLineages,
9695
+ runtimeEvidencePath
9556
9696
  }) => {
9557
9697
  const { connector, connectorName, window: window2 } = getRuntimeCompareContext();
9558
9698
  if (!connector || !window2) {
@@ -9562,12 +9702,23 @@ var saveAndPrintReplayRuntimeComparison = async ({
9562
9702
  liveStrategySummaries.map((summary) => summary.strategyName)
9563
9703
  );
9564
9704
  const replaySignalEvaluations = buildReplaySignalEvaluations(replaySignals);
9705
+ const runtimeEvidence = runtimeEvidencePath ? await loadReplayRuntimeEvidenceSource({
9706
+ filePath: runtimeEvidencePath,
9707
+ projectRoot: replayProjectRoot,
9708
+ expectedUserName: replayUserName,
9709
+ expectedWindow: window2
9710
+ }) : null;
9565
9711
  const [
9566
9712
  rawRuntimeTrades,
9567
9713
  runtimeSignals,
9568
9714
  runtimeSignalEvaluations,
9569
9715
  runtimeLineageScopes
9570
- ] = await Promise.all([
9716
+ ] = runtimeEvidence ? [
9717
+ runtimeEvidence.trades,
9718
+ runtimeEvidence.signals,
9719
+ runtimeEvidence.evaluations,
9720
+ runtimeEvidence.lineageScopes
9721
+ ] : await Promise.all([
9571
9722
  loadRuntimeTrades(replayUserName, {
9572
9723
  startTime: window2.start,
9573
9724
  endTime: window2.end
@@ -9585,7 +9736,14 @@ var saveAndPrintReplayRuntimeComparison = async ({
9585
9736
  endTime: window2.end
9586
9737
  })
9587
9738
  ]);
9588
- const syncedRuntimeTrades = await syncRuntimeTrades({
9739
+ if (runtimeEvidence) {
9740
+ console.log(
9741
+ import_chalk11.default.gray(
9742
+ `runtime compare: using immutable evidence ${runtimeEvidence.path}`
9743
+ )
9744
+ );
9745
+ }
9746
+ const syncedRuntimeTrades = runtimeEvidence ? rawRuntimeTrades : await syncRuntimeTrades({
9589
9747
  userName: replayUserName,
9590
9748
  connector,
9591
9749
  trades: rawRuntimeTrades,
@@ -9636,7 +9794,7 @@ var saveAndPrintReplayRuntimeComparison = async ({
9636
9794
  const windowRuntimeTrades = comparable.runtimeTrades.filter(
9637
9795
  (trade) => trade.entryTimestamp >= window2.start && trade.entryTimestamp < window2.end && relevantStrategies.has(trade.strategy)
9638
9796
  );
9639
- if (!windowRuntimeTrades.length) {
9797
+ if (!windowRuntimeTrades.length && !runtimeEvidence) {
9640
9798
  console.log("");
9641
9799
  console.log(
9642
9800
  import_chalk11.default.yellow(
@@ -9768,8 +9926,8 @@ var saveAndPrintReplayRuntimeComparison = async ({
9768
9926
  };
9769
9927
 
9770
9928
  // src/lib/replay/outputReport.ts
9771
- var import_promises2 = __toESM(require("fs/promises"));
9772
- var import_node_path2 = __toESM(require("path"));
9929
+ var import_promises3 = __toESM(require("fs/promises"));
9930
+ var import_node_path3 = __toESM(require("path"));
9773
9931
  var import_data = require("@tradejs/core/data");
9774
9932
  var formatMsk = (timestamp) => typeof timestamp === "number" && Number.isFinite(timestamp) ? new Intl.DateTimeFormat("ru-RU", {
9775
9933
  timeZone: "Europe/Moscow",
@@ -10073,8 +10231,8 @@ var writeReplayOutputReport = async ({
10073
10231
  strategySnapshot,
10074
10232
  runtimeComparison
10075
10233
  }) => {
10076
- const outputDir = import_node_path2.default.resolve(projectRoot, "data/replay/output");
10077
- await import_promises2.default.mkdir(outputDir, { recursive: true });
10234
+ const outputDir = import_node_path3.default.resolve(projectRoot, "data/replay/output");
10235
+ await import_promises3.default.mkdir(outputDir, { recursive: true });
10078
10236
  const perTradeAnalysis = buildPerTradeAnalysis(runtimeComparison);
10079
10237
  const report = {
10080
10238
  reportType: "replay-output",
@@ -10109,8 +10267,8 @@ var writeReplayOutputReport = async ({
10109
10267
  runtimeComparison,
10110
10268
  perTradeAnalysis
10111
10269
  };
10112
- const markdownPath = import_node_path2.default.join(outputDir, `${timestamp}-replay-report.md`);
10113
- const jsonPath = import_node_path2.default.join(outputDir, `${timestamp}-replay-report.json`);
10270
+ const markdownPath = import_node_path3.default.join(outputDir, `${timestamp}-replay-report.md`);
10271
+ const jsonPath = import_node_path3.default.join(outputDir, `${timestamp}-replay-report.json`);
10114
10272
  const lines = [
10115
10273
  "# Replay Report",
10116
10274
  "",
@@ -10176,8 +10334,8 @@ var writeReplayOutputReport = async ({
10176
10334
  ""
10177
10335
  ];
10178
10336
  await Promise.all([
10179
- import_promises2.default.writeFile(markdownPath, lines.join("\n"), "utf8"),
10180
- import_promises2.default.writeFile(jsonPath, `${(0, import_data.toJson)(report, true)}
10337
+ import_promises3.default.writeFile(markdownPath, lines.join("\n"), "utf8"),
10338
+ import_promises3.default.writeFile(jsonPath, `${(0, import_data.toJson)(report, true)}
10181
10339
  `, "utf8")
10182
10340
  ]);
10183
10341
  return {
@@ -10218,7 +10376,8 @@ var finishReplay = async ({
10218
10376
  liveStrategySummaries: replayStrategySnapshot.summaries,
10219
10377
  backtestEntries: replayStrategySnapshot.backtestEntries,
10220
10378
  replaySignals: replayResult.signals,
10221
- replayLineages: replayResult.runtimeLineages
10379
+ replayLineages: replayResult.runtimeLineages,
10380
+ runtimeEvidencePath: replayRuntimeEvidencePath
10222
10381
  });
10223
10382
  const finishedAt = /* @__PURE__ */ new Date();
10224
10383
  const durationSeconds = Number(
@@ -417,6 +417,17 @@ var RUNTIME_EVIDENCE_PAYLOAD_FILE = "runtime-evidence.json";
417
417
  var RUNTIME_EVIDENCE_COMPLETE_FILE = ".complete";
418
418
  var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
419
419
  var sha256 = (value) => (0, import_node_crypto.createHash)("sha256").update(value).digest("hex");
420
+ var runtimeEvidenceIdentitySha256 = (artifact) => {
421
+ const identityArtifact = { ...artifact };
422
+ delete identityArtifact.generatedAt;
423
+ const runtime = asRecord(identityArtifact.runtime);
424
+ if (runtime) {
425
+ const identityRuntime = { ...runtime };
426
+ delete identityRuntime.generatedAt;
427
+ identityArtifact.runtime = identityRuntime;
428
+ }
429
+ return sha256(JSON.stringify(identityArtifact));
430
+ };
420
431
  var isExistingDestinationError = (error) => {
421
432
  const code = error.code;
422
433
  return code === "EEXIST" || code === "ENOTEMPTY";
@@ -487,11 +498,12 @@ var publishRuntimeEvidenceBundle = async ({
487
498
  const payload = `${JSON.stringify(artifact, null, 2)}
488
499
  `;
489
500
  const payloadSha256 = sha256(payload);
501
+ const identitySha256 = runtimeEvidenceIdentitySha256(artifact);
490
502
  const safeDeploymentId = safeSegment(deploymentId, "default");
491
503
  const artifactId = [
492
504
  compactTimestamp(startTime),
493
505
  compactTimestamp(endTime),
494
- payloadSha256.slice(0, 16)
506
+ identitySha256.slice(0, 16)
495
507
  ].join("_");
496
508
  const createdAt = Date.now();
497
509
  const manifest = {
@@ -5188,6 +5188,7 @@ var backfillCoinMarketCapContextForReplay = backfillCoinMarketCapContext;
5188
5188
  var backfillCoinMarketCapContextForSignals = (params) => backfillCoinMarketCapContext({ ...params, refreshStaleFearGreed: true });
5189
5189
 
5190
5190
  // src/lib/hyperliquidWhaleBackfill.ts
5191
+ var import_progress3 = __toESM(require("progress"));
5191
5192
  var import_timescale4 = require("@tradejs/infra/timescale");
5192
5193
  var import_strategies2 = require("@tradejs/node/strategies");
5193
5194
 
@@ -5562,11 +5563,36 @@ var backfillHyperliquidWhaleContext = async (params) => {
5562
5563
  toMs,
5563
5564
  ...identity
5564
5565
  });
5566
+ const totalCoverageBuckets = Math.ceil(
5567
+ (toMs - fromMs) / HYPERLIQUID_WHALE_BUCKET_MS
5568
+ );
5569
+ const coverageBar = new import_progress3.default(
5570
+ "Hyperliquid coverage :current/:total [:bar][:percent] :eta(s) rows=:rows chunk=:chunk",
5571
+ {
5572
+ total: Math.max(1, totalCoverageBuckets),
5573
+ width: 24
5574
+ }
5575
+ );
5576
+ let displayedCoverageBuckets = 0;
5565
5577
  const coverageBuckets = await (0, import_timescale4.rebuildHyperliquidWhaleCoverageRows)({
5566
5578
  fromMs,
5567
5579
  toMs,
5568
5580
  expectedWhales: whales.addresses.length,
5569
- ...identity
5581
+ ...identity,
5582
+ onProgress: (progress) => {
5583
+ const next = Math.max(
5584
+ displayedCoverageBuckets,
5585
+ Math.min(progress.completedBuckets, coverageBar.total)
5586
+ );
5587
+ const delta = next - displayedCoverageBuckets;
5588
+ if (delta > 0) {
5589
+ coverageBar.tick(delta, {
5590
+ rows: progress.rows,
5591
+ chunk: `${progress.chunkIndex}/${progress.totalChunks}`
5592
+ });
5593
+ displayedCoverageBuckets = next;
5594
+ }
5595
+ }
5570
5596
  });
5571
5597
  const result = {
5572
5598
  cached: false,
@@ -1645,7 +1645,7 @@ __export(signals_exports, {
1645
1645
  module.exports = __toCommonJS(signals_exports);
1646
1646
  var import_config = require("dotenv/config");
1647
1647
  var import_args = __toESM(require("args"));
1648
- var import_progress3 = __toESM(require("progress"));
1648
+ var import_progress4 = __toESM(require("progress"));
1649
1649
  var import_chalk7 = __toESM(require("chalk"));
1650
1650
  var import_connectors6 = require("@tradejs/node/connectors");
1651
1651
  var import_cli2 = require("@tradejs/node/cli");
@@ -4553,6 +4553,7 @@ var backfillCoinMarketCapContextForReplay = backfillCoinMarketCapContext;
4553
4553
  var backfillCoinMarketCapContextForSignals = (params) => backfillCoinMarketCapContext({ ...params, refreshStaleFearGreed: true });
4554
4554
 
4555
4555
  // src/lib/hyperliquidWhaleBackfill.ts
4556
+ var import_progress3 = __toESM(require("progress"));
4556
4557
  var import_timescale4 = require("@tradejs/infra/timescale");
4557
4558
  var import_strategies2 = require("@tradejs/node/strategies");
4558
4559
 
@@ -4927,11 +4928,36 @@ var backfillHyperliquidWhaleContext = async (params) => {
4927
4928
  toMs,
4928
4929
  ...identity
4929
4930
  });
4931
+ const totalCoverageBuckets = Math.ceil(
4932
+ (toMs - fromMs) / HYPERLIQUID_WHALE_BUCKET_MS
4933
+ );
4934
+ const coverageBar = new import_progress3.default(
4935
+ "Hyperliquid coverage :current/:total [:bar][:percent] :eta(s) rows=:rows chunk=:chunk",
4936
+ {
4937
+ total: Math.max(1, totalCoverageBuckets),
4938
+ width: 24
4939
+ }
4940
+ );
4941
+ let displayedCoverageBuckets = 0;
4930
4942
  const coverageBuckets = await (0, import_timescale4.rebuildHyperliquidWhaleCoverageRows)({
4931
4943
  fromMs,
4932
4944
  toMs,
4933
4945
  expectedWhales: whales.addresses.length,
4934
- ...identity
4946
+ ...identity,
4947
+ onProgress: (progress) => {
4948
+ const next = Math.max(
4949
+ displayedCoverageBuckets,
4950
+ Math.min(progress.completedBuckets, coverageBar.total)
4951
+ );
4952
+ const delta = next - displayedCoverageBuckets;
4953
+ if (delta > 0) {
4954
+ coverageBar.tick(delta, {
4955
+ rows: progress.rows,
4956
+ chunk: `${progress.chunkIndex}/${progress.totalChunks}`
4957
+ });
4958
+ displayedCoverageBuckets = next;
4959
+ }
4960
+ }
4935
4961
  });
4936
4962
  const result = {
4937
4963
  cached: false,
@@ -7029,7 +7055,7 @@ var signals = async (options = {}) => {
7029
7055
  return;
7030
7056
  }
7031
7057
  const strategyStats = createStrategySkipStats(runtimeStrategies);
7032
- const bar = new import_progress3.default(
7058
+ const bar = new import_progress4.default(
7033
7059
  ":current/:total [:bar][:percent] :found :eta(s) :symbol",
7034
7060
  {
7035
7061
  total: tickers.length,
@@ -1643,7 +1643,7 @@ module.exports = __toCommonJS(signalsDaemon_exports);
1643
1643
  // src/scripts/signals.ts
1644
1644
  var import_config = require("dotenv/config");
1645
1645
  var import_args = __toESM(require("args"));
1646
- var import_progress3 = __toESM(require("progress"));
1646
+ var import_progress4 = __toESM(require("progress"));
1647
1647
  var import_chalk7 = __toESM(require("chalk"));
1648
1648
  var import_connectors6 = require("@tradejs/node/connectors");
1649
1649
  var import_cli2 = require("@tradejs/node/cli");
@@ -4551,6 +4551,7 @@ var backfillCoinMarketCapContextForReplay = backfillCoinMarketCapContext;
4551
4551
  var backfillCoinMarketCapContextForSignals = (params) => backfillCoinMarketCapContext({ ...params, refreshStaleFearGreed: true });
4552
4552
 
4553
4553
  // src/lib/hyperliquidWhaleBackfill.ts
4554
+ var import_progress3 = __toESM(require("progress"));
4554
4555
  var import_timescale4 = require("@tradejs/infra/timescale");
4555
4556
  var import_strategies2 = require("@tradejs/node/strategies");
4556
4557
 
@@ -4925,11 +4926,36 @@ var backfillHyperliquidWhaleContext = async (params) => {
4925
4926
  toMs,
4926
4927
  ...identity
4927
4928
  });
4929
+ const totalCoverageBuckets = Math.ceil(
4930
+ (toMs - fromMs) / HYPERLIQUID_WHALE_BUCKET_MS
4931
+ );
4932
+ const coverageBar = new import_progress3.default(
4933
+ "Hyperliquid coverage :current/:total [:bar][:percent] :eta(s) rows=:rows chunk=:chunk",
4934
+ {
4935
+ total: Math.max(1, totalCoverageBuckets),
4936
+ width: 24
4937
+ }
4938
+ );
4939
+ let displayedCoverageBuckets = 0;
4928
4940
  const coverageBuckets = await (0, import_timescale4.rebuildHyperliquidWhaleCoverageRows)({
4929
4941
  fromMs,
4930
4942
  toMs,
4931
4943
  expectedWhales: whales.addresses.length,
4932
- ...identity
4944
+ ...identity,
4945
+ onProgress: (progress) => {
4946
+ const next = Math.max(
4947
+ displayedCoverageBuckets,
4948
+ Math.min(progress.completedBuckets, coverageBar.total)
4949
+ );
4950
+ const delta = next - displayedCoverageBuckets;
4951
+ if (delta > 0) {
4952
+ coverageBar.tick(delta, {
4953
+ rows: progress.rows,
4954
+ chunk: `${progress.chunkIndex}/${progress.totalChunks}`
4955
+ });
4956
+ displayedCoverageBuckets = next;
4957
+ }
4958
+ }
4933
4959
  });
4934
4960
  const result = {
4935
4961
  cached: false,
@@ -7027,7 +7053,7 @@ var signals = async (options = {}) => {
7027
7053
  return;
7028
7054
  }
7029
7055
  const strategyStats = createStrategySkipStats(runtimeStrategies);
7030
- const bar = new import_progress3.default(
7056
+ const bar = new import_progress4.default(
7031
7057
  ":current/:total [:bar][:percent] :found :eta(s) :symbol",
7032
7058
  {
7033
7059
  total: tickers.length,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/cli",
3
- "version": "2.0.16",
3
+ "version": "2.0.18",
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.16",
33
- "@tradejs/connectors": "^2.0.16",
34
- "@tradejs/core": "^2.0.16",
35
- "@tradejs/indicators": "^2.0.16",
36
- "@tradejs/infra": "^2.0.16",
37
- "@tradejs/node": "^2.0.16",
38
- "@tradejs/strategies": "^2.0.16",
39
- "@tradejs/types": "^2.0.16",
32
+ "@tradejs/base": "^2.0.18",
33
+ "@tradejs/connectors": "^2.0.18",
34
+ "@tradejs/core": "^2.0.18",
35
+ "@tradejs/indicators": "^2.0.18",
36
+ "@tradejs/infra": "^2.0.18",
37
+ "@tradejs/node": "^2.0.18",
38
+ "@tradejs/strategies": "^2.0.18",
39
+ "@tradejs/types": "^2.0.18",
40
40
  "args": "^5.0.3",
41
41
  "bcryptjs": "^2.4.3",
42
42
  "chalk": "4.1.2",