@tradejs/cli 3.1.8 → 3.1.9-beta.214

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.
@@ -233,18 +233,39 @@ var loadRuntimeSignalEvaluations = async (userName, {
233
233
  }
234
234
  return sortByTimestamp([...deduped.values()]);
235
235
  };
236
+ var loadRuntimeLineageScopes = async (userName, {
237
+ startTime,
238
+ endTime
239
+ }) => {
240
+ const records = (await Promise.all(
241
+ (0, import_time2.getRuntimeStorageDayKeys)(startTime, endTime).map(
242
+ (dayKey) => (0, import_redis2.getHashJsonValues)(
243
+ import_redis2.redisKeys.runtimeLineageScopeBucket(userName, dayKey)
244
+ )
245
+ )
246
+ )).flat().filter(
247
+ (record) => record != null && typeof record.strategy === "string" && typeof record.symbol === "string" && typeof record.firstTimestamp === "number" && typeof record.lastTimestamp === "number" && record.lineage != null
248
+ );
249
+ return records.sort(
250
+ (left, right) => left.firstTimestamp - right.firstTimestamp || left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol)
251
+ );
252
+ };
236
253
  var parseBucketKey = (prefix, key) => {
237
254
  if (!key.startsWith(prefix)) {
238
255
  return null;
239
256
  }
240
257
  const suffix = key.slice(prefix.length);
241
- const firstColon = suffix.indexOf(":");
242
- if (firstColon <= 0 || firstColon >= suffix.length - 1) {
258
+ const parts = suffix.split(":");
259
+ if (parts.length < 2 || parts.some((part) => !part)) {
243
260
  return null;
244
261
  }
262
+ const [dayKey, ...scopeParts] = parts;
263
+ const strategy = scopeParts.at(-1);
264
+ if (!dayKey || !strategy) return null;
245
265
  return {
246
- dayKey: suffix.slice(0, firstColon),
247
- strategy: suffix.slice(firstColon + 1)
266
+ dayKey,
267
+ ...scopeParts.length > 1 ? { deploymentId: scopeParts.slice(0, -1).join(":") } : {},
268
+ strategy
248
269
  };
249
270
  };
250
271
  var loadRuntimeSignalEvaluationStatsBuckets = async (userName) => {
@@ -288,7 +309,8 @@ var collectRuntimeDebugEvidence = async ({
288
309
  userName,
289
310
  startTime,
290
311
  endTime,
291
- strategies
312
+ strategies,
313
+ deploymentId
292
314
  }) => {
293
315
  const dayKeys = (0, import_time2.getRuntimeStorageDayKeys)(startTime, endTime);
294
316
  const dayKeySet = new Set(dayKeys);
@@ -298,6 +320,7 @@ var collectRuntimeDebugEvidence = async ({
298
320
  signals,
299
321
  evaluations,
300
322
  evaluationStatsBuckets,
323
+ lineageScopes,
301
324
  configs
302
325
  ] = await Promise.all([
303
326
  loadRuntimeTrades(userName, { startTime, endTime }),
@@ -305,6 +328,7 @@ var collectRuntimeDebugEvidence = async ({
305
328
  loadRuntimeSignals(userName, { startTime, endTime }),
306
329
  loadRuntimeSignalEvaluations(userName, { startTime, endTime }),
307
330
  loadRuntimeSignalEvaluationStatsBuckets(userName),
331
+ loadRuntimeLineageScopes(userName, { startTime, endTime }),
308
332
  (0, import_runtimeStrategyConfigs.loadRuntimeStrategyConfigs)(userName)
309
333
  ]);
310
334
  const tradesByOrderId = new Map(
@@ -317,15 +341,21 @@ var collectRuntimeDebugEvidence = async ({
317
341
  (left, right) => left.entryTimestamp - right.entryTimestamp
318
342
  );
319
343
  const filteredStats = evaluationStatsBuckets.filter(
320
- (entry) => dayKeySet.has(entry.dayKey) && (!strategies?.length || strategies.includes(entry.strategy))
344
+ (entry) => dayKeySet.has(entry.dayKey) && (!deploymentId || entry.deploymentId === deploymentId) && (!strategies?.length || strategies.includes(entry.strategy))
321
345
  );
346
+ const matchesDeployment = (value) => !deploymentId || value.deploymentId === deploymentId;
322
347
  return {
323
348
  dayKeys,
324
- trades: filterByStrategies(trades, strategies),
325
- signals: filterByStrategies(signals, strategies),
326
- evaluations: filterByStrategies(evaluations, strategies),
349
+ trades: filterByStrategies(trades, strategies).filter(matchesDeployment),
350
+ signals: filterByStrategies(signals, strategies).filter(matchesDeployment),
351
+ evaluations: filterByStrategies(evaluations, strategies).filter(
352
+ matchesDeployment
353
+ ),
327
354
  evaluationStatsBuckets: filteredStats,
328
- strategyConfigs: configs.filter(
355
+ lineageScopes: lineageScopes.filter(matchesDeployment).filter(
356
+ (scope) => !strategies?.length || strategies.includes(scope.strategy)
357
+ ),
358
+ strategyConfigs: deploymentId ? [] : configs.filter(
329
359
  (config) => !strategies?.length || strategies.includes(config.strategyName)
330
360
  )
331
361
  };
@@ -338,7 +368,8 @@ var buildRuntimeEvidenceReportPayload = ({
338
368
  evaluations,
339
369
  trades,
340
370
  strategyConfigs,
341
- evaluationStatsBuckets
371
+ evaluationStatsBuckets,
372
+ lineageScopes
342
373
  }) => ({
343
374
  reportType: "runtime-daily-evidence",
344
375
  generatedAt: Date.now(),
@@ -355,12 +386,14 @@ var buildRuntimeEvidenceReportPayload = ({
355
386
  signals: signals.length,
356
387
  evaluations: evaluations.length,
357
388
  evaluationStatsBuckets: evaluationStatsBuckets?.length ?? 0,
389
+ lineageScopes: lineageScopes?.length ?? 0,
358
390
  strategyConfigs: strategyConfigs?.length ?? 0
359
391
  },
360
392
  trades: trades.map((trade) => ({ trade })),
361
393
  signals: signals.map((signal) => ({ signal })),
362
394
  evaluations: evaluations.map((evaluation) => ({ evaluation })),
363
395
  evaluationStatsBuckets: evaluationStatsBuckets ?? [],
396
+ lineageScopes: lineageScopes ?? [],
364
397
  strategyConfigs: strategyConfigs ?? []
365
398
  });
366
399
 
@@ -641,7 +674,8 @@ var loadRuntimePayload = async ({
641
674
  return {
642
675
  source: "file",
643
676
  path: runtimeEvidencePath,
644
- payload: artifact.runtime ?? artifact
677
+ payload: artifact.runtime ?? artifact,
678
+ deployment: artifact.deployment ?? null
645
679
  };
646
680
  }
647
681
  const runtimeEvidence = await collectRuntimeDebugEvidence({
@@ -653,6 +687,7 @@ var loadRuntimePayload = async ({
653
687
  return {
654
688
  source: "local-redis",
655
689
  path: null,
690
+ deployment: null,
656
691
  payload: buildRuntimeEvidenceReportPayload({
657
692
  userName,
658
693
  startTime,
@@ -661,7 +696,8 @@ var loadRuntimePayload = async ({
661
696
  evaluations: runtimeEvidence.evaluations,
662
697
  trades: runtimeEvidence.trades,
663
698
  strategyConfigs: runtimeEvidence.strategyConfigs,
664
- evaluationStatsBuckets: runtimeEvidence.evaluationStatsBuckets
699
+ evaluationStatsBuckets: runtimeEvidence.evaluationStatsBuckets,
700
+ lineageScopes: runtimeEvidence.lineageScopes
665
701
  })
666
702
  };
667
703
  };
@@ -701,6 +737,7 @@ var replayRuntimeEvidence = async () => {
701
737
  type: runtime.source,
702
738
  path: runtime.path
703
739
  },
740
+ deployment: runtime.deployment,
704
741
  replay: {
705
742
  key: replay.key,
706
743
  availableKeys: replay.availableKeys,
@@ -231,18 +231,39 @@ var loadRuntimeSignalEvaluations = async (userName, {
231
231
  }
232
232
  return sortByTimestamp([...deduped.values()]);
233
233
  };
234
+ var loadRuntimeLineageScopes = async (userName, {
235
+ startTime,
236
+ endTime
237
+ }) => {
238
+ const records = (await Promise.all(
239
+ (0, import_time2.getRuntimeStorageDayKeys)(startTime, endTime).map(
240
+ (dayKey) => (0, import_redis2.getHashJsonValues)(
241
+ import_redis2.redisKeys.runtimeLineageScopeBucket(userName, dayKey)
242
+ )
243
+ )
244
+ )).flat().filter(
245
+ (record) => record != null && typeof record.strategy === "string" && typeof record.symbol === "string" && typeof record.firstTimestamp === "number" && typeof record.lastTimestamp === "number" && record.lineage != null
246
+ );
247
+ return records.sort(
248
+ (left, right) => left.firstTimestamp - right.firstTimestamp || left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol)
249
+ );
250
+ };
234
251
  var parseBucketKey = (prefix, key) => {
235
252
  if (!key.startsWith(prefix)) {
236
253
  return null;
237
254
  }
238
255
  const suffix = key.slice(prefix.length);
239
- const firstColon = suffix.indexOf(":");
240
- if (firstColon <= 0 || firstColon >= suffix.length - 1) {
256
+ const parts = suffix.split(":");
257
+ if (parts.length < 2 || parts.some((part) => !part)) {
241
258
  return null;
242
259
  }
260
+ const [dayKey, ...scopeParts] = parts;
261
+ const strategy = scopeParts.at(-1);
262
+ if (!dayKey || !strategy) return null;
243
263
  return {
244
- dayKey: suffix.slice(0, firstColon),
245
- strategy: suffix.slice(firstColon + 1)
264
+ dayKey,
265
+ ...scopeParts.length > 1 ? { deploymentId: scopeParts.slice(0, -1).join(":") } : {},
266
+ strategy
246
267
  };
247
268
  };
248
269
  var loadRuntimeSignalEvaluationStatsBuckets = async (userName) => {
@@ -286,7 +307,8 @@ var collectRuntimeDebugEvidence = async ({
286
307
  userName,
287
308
  startTime,
288
309
  endTime,
289
- strategies
310
+ strategies,
311
+ deploymentId
290
312
  }) => {
291
313
  const dayKeys = (0, import_time2.getRuntimeStorageDayKeys)(startTime, endTime);
292
314
  const dayKeySet = new Set(dayKeys);
@@ -296,6 +318,7 @@ var collectRuntimeDebugEvidence = async ({
296
318
  signals,
297
319
  evaluations,
298
320
  evaluationStatsBuckets,
321
+ lineageScopes,
299
322
  configs
300
323
  ] = await Promise.all([
301
324
  loadRuntimeTrades(userName, { startTime, endTime }),
@@ -303,6 +326,7 @@ var collectRuntimeDebugEvidence = async ({
303
326
  loadRuntimeSignals(userName, { startTime, endTime }),
304
327
  loadRuntimeSignalEvaluations(userName, { startTime, endTime }),
305
328
  loadRuntimeSignalEvaluationStatsBuckets(userName),
329
+ loadRuntimeLineageScopes(userName, { startTime, endTime }),
306
330
  (0, import_runtimeStrategyConfigs.loadRuntimeStrategyConfigs)(userName)
307
331
  ]);
308
332
  const tradesByOrderId = new Map(
@@ -315,15 +339,21 @@ var collectRuntimeDebugEvidence = async ({
315
339
  (left, right) => left.entryTimestamp - right.entryTimestamp
316
340
  );
317
341
  const filteredStats = evaluationStatsBuckets.filter(
318
- (entry) => dayKeySet.has(entry.dayKey) && (!strategies?.length || strategies.includes(entry.strategy))
342
+ (entry) => dayKeySet.has(entry.dayKey) && (!deploymentId || entry.deploymentId === deploymentId) && (!strategies?.length || strategies.includes(entry.strategy))
319
343
  );
344
+ const matchesDeployment = (value) => !deploymentId || value.deploymentId === deploymentId;
320
345
  return {
321
346
  dayKeys,
322
- trades: filterByStrategies(trades, strategies),
323
- signals: filterByStrategies(signals, strategies),
324
- evaluations: filterByStrategies(evaluations, strategies),
347
+ trades: filterByStrategies(trades, strategies).filter(matchesDeployment),
348
+ signals: filterByStrategies(signals, strategies).filter(matchesDeployment),
349
+ evaluations: filterByStrategies(evaluations, strategies).filter(
350
+ matchesDeployment
351
+ ),
325
352
  evaluationStatsBuckets: filteredStats,
326
- strategyConfigs: configs.filter(
353
+ lineageScopes: lineageScopes.filter(matchesDeployment).filter(
354
+ (scope) => !strategies?.length || strategies.includes(scope.strategy)
355
+ ),
356
+ strategyConfigs: deploymentId ? [] : configs.filter(
327
357
  (config) => !strategies?.length || strategies.includes(config.strategyName)
328
358
  )
329
359
  };
@@ -336,7 +366,8 @@ var buildRuntimeEvidenceReportPayload = ({
336
366
  evaluations,
337
367
  trades,
338
368
  strategyConfigs,
339
- evaluationStatsBuckets
369
+ evaluationStatsBuckets,
370
+ lineageScopes
340
371
  }) => ({
341
372
  reportType: "runtime-daily-evidence",
342
373
  generatedAt: Date.now(),
@@ -353,12 +384,14 @@ var buildRuntimeEvidenceReportPayload = ({
353
384
  signals: signals.length,
354
385
  evaluations: evaluations.length,
355
386
  evaluationStatsBuckets: evaluationStatsBuckets?.length ?? 0,
387
+ lineageScopes: lineageScopes?.length ?? 0,
356
388
  strategyConfigs: strategyConfigs?.length ?? 0
357
389
  },
358
390
  trades: trades.map((trade) => ({ trade })),
359
391
  signals: signals.map((signal) => ({ signal })),
360
392
  evaluations: evaluations.map((evaluation) => ({ evaluation })),
361
393
  evaluationStatsBuckets: evaluationStatsBuckets ?? [],
394
+ lineageScopes: lineageScopes ?? [],
362
395
  strategyConfigs: strategyConfigs ?? []
363
396
  });
364
397
 
@@ -573,7 +606,12 @@ var import_promises2 = __toESM(require("fs/promises"));
573
606
  var import_node_path2 = __toESM(require("path"));
574
607
 
575
608
  // src/lib/runtimeLineage.ts
576
- var runtimeLineageKey = (lineage) => lineage.schemaVersion === 2 ? ["v2", lineage.version].join(":") : [
609
+ var runtimeLineageKey = (lineage) => lineage.schemaVersion === 2 ? [
610
+ "v2",
611
+ lineage.version,
612
+ lineage.strategyPackageVersion ?? "strategy:unknown",
613
+ lineage.runtimePackageVersion ?? "runtime:unknown"
614
+ ].join(":") : [
577
615
  lineage.schemaVersion,
578
616
  lineage.compositionId ?? "unbound-composition",
579
617
  lineage.gitSha ?? "unknown",
@@ -583,6 +621,61 @@ var runtimeLineageKey = (lineage) => lineage.schemaVersion === 2 ? ["v2", lineag
583
621
  lineage.contextFingerprint
584
622
  ].join(":");
585
623
 
624
+ // src/lib/runtimeEvidenceDeployment.ts
625
+ var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
626
+ var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
627
+ var resolveRuntimeEvidenceDeploymentSnapshot = async ({
628
+ userName,
629
+ projectRoot: projectRoot2,
630
+ deploymentId
631
+ }) => {
632
+ const [deployment, strategies] = await Promise.all([
633
+ (0, import_runtimeStrategies.getRuntimeDeployment)({ userName, projectRoot: projectRoot2, deploymentId }),
634
+ (0, import_runtimeStrategies.loadResolvedRuntimeStrategies)({ userName, projectRoot: projectRoot2, deploymentId })
635
+ ]);
636
+ if (!deployment) {
637
+ throw new Error(`Runtime deployment not found: ${deploymentId}`);
638
+ }
639
+ return {
640
+ schemaVersion: 1,
641
+ id: deployment.id,
642
+ label: deployment.label,
643
+ connectorName: deployment.connectorName,
644
+ provider: deployment.provider,
645
+ accountId: deployment.accountId,
646
+ enabled: deployment.enabled,
647
+ strategies: strategies.map(
648
+ ({
649
+ strategyName,
650
+ version,
651
+ enabled,
652
+ controlState,
653
+ interval,
654
+ universe,
655
+ accountId,
656
+ strategyPackage,
657
+ strategyPackageVersion,
658
+ runtimePackageVersion,
659
+ sourceStrategyConfig
660
+ }) => ({
661
+ strategyName,
662
+ version,
663
+ enabled,
664
+ controlState,
665
+ interval,
666
+ universe,
667
+ ...accountId ? { accountId } : {},
668
+ strategyPackage,
669
+ strategyPackageVersion,
670
+ runtimePackageVersion,
671
+ strategyConfig: sourceStrategyConfig
672
+ })
673
+ ),
674
+ ...deployment.assetClasses ? { assetClasses: [...deployment.assetClasses] } : {},
675
+ ...deployment.tickers ? { tickers: [...deployment.tickers] } : {}
676
+ };
677
+ };
678
+
586
679
  // src/scripts/runtimeEvidence.ts
587
680
  import_args.default.option(["u", "user"], "Use user config", "root");
588
681
  import_args.default.option(
@@ -662,12 +755,34 @@ var resolveWindow = () => {
662
755
  var parseStrategyFilter = (value) => String(value ?? "").split(",").map((item) => item.trim()).filter(Boolean);
663
756
  var runtimeEvidence = async () => {
664
757
  const { startTime, endTime, source } = resolveWindow();
665
- const strategies = parseStrategyFilter(flags.strategy);
758
+ const deploymentId = String(flags.deployment);
759
+ const deployment = await resolveRuntimeEvidenceDeploymentSnapshot({
760
+ userName: String(flags.user),
761
+ projectRoot,
762
+ deploymentId
763
+ });
764
+ const activeStrategies = activeRuntimeEvidenceStrategies(deployment).map(
765
+ ({ strategyName }) => strategyName
766
+ );
767
+ const requestedStrategies = parseStrategyFilter(flags.strategy);
768
+ const strategies = requestedStrategies.length ? requestedStrategies : activeStrategies;
769
+ const declaredStrategies = new Set(
770
+ deployment.strategies.map(({ strategyName }) => strategyName)
771
+ );
772
+ const unknownStrategies = strategies.filter(
773
+ (strategyName) => !declaredStrategies.has(strategyName)
774
+ );
775
+ if (unknownStrategies.length) {
776
+ throw new Error(
777
+ `Strategies are not declared in ${deploymentId}: ${unknownStrategies.join(", ")}`
778
+ );
779
+ }
666
780
  const evidence = await collectRuntimeDebugEvidence({
667
781
  userName: flags.user,
668
782
  startTime,
669
783
  endTime,
670
- strategies: strategies.length ? strategies : void 0
784
+ strategies,
785
+ deploymentId
671
786
  });
672
787
  const runtime = buildRuntimeEvidenceReportPayload({
673
788
  userName: flags.user,
@@ -677,7 +792,8 @@ var runtimeEvidence = async () => {
677
792
  evaluations: evidence.evaluations,
678
793
  trades: evidence.trades,
679
794
  strategyConfigs: evidence.strategyConfigs,
680
- evaluationStatsBuckets: evidence.evaluationStatsBuckets
795
+ evaluationStatsBuckets: evidence.evaluationStatsBuckets,
796
+ lineageScopes: evidence.lineageScopes
681
797
  });
682
798
  const artifact = {
683
799
  reportType: "runtime-evidence",
@@ -691,6 +807,7 @@ var runtimeEvidence = async () => {
691
807
  source
692
808
  },
693
809
  strategies,
810
+ deployment,
694
811
  runtime
695
812
  };
696
813
  const outPath = import_node_path4.default.resolve(projectRoot, String(flags.out));
@@ -700,7 +817,7 @@ var runtimeEvidence = async () => {
700
817
  const publishDir = String(flags.publishDir ?? "").trim();
701
818
  const published = publishDir ? await publishRuntimeEvidenceBundle({
702
819
  publishRoot: import_node_path4.default.resolve(projectRoot, publishDir),
703
- deploymentId: String(flags.deployment),
820
+ deploymentId,
704
821
  userName: String(flags.user),
705
822
  startTime,
706
823
  endTime,
@@ -711,8 +828,9 @@ var runtimeEvidence = async () => {
711
828
  ...evidence.evaluations.map(
712
829
  (evaluation) => evaluation.runtimeLineage
713
830
  ),
714
- ...evidence.trades.map((trade) => trade.runtimeLineage)
715
- ].filter((lineage) => lineage != null).map(runtimeLineageKey)
831
+ ...evidence.trades.map((trade) => trade.runtimeLineage),
832
+ ...evidence.lineageScopes.map((scope) => scope.lineage)
833
+ ].filter((lineage) => lineage != null).map(runtimeLineageKey).filter((key, index, values) => values.indexOf(key) === index)
716
834
  }) : null;
717
835
  console.log(import_chalk.default.green(`Wrote ${outPath}`));
718
836
  if (published) {