@tradejs/cli 3.1.8-beta.213 → 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.
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/lib/runtimeScorecard.ts
@@ -24,6 +34,39 @@ __export(runtimeScorecard_exports, {
24
34
  formatRuntimeScorecardMarkdown: () => formatRuntimeScorecardMarkdown
25
35
  });
26
36
  module.exports = __toCommonJS(runtimeScorecard_exports);
37
+
38
+ // src/lib/runtimeLineage.ts
39
+ var import_node_child_process = require("child_process");
40
+ var import_node_crypto2 = require("crypto");
41
+ var import_promises2 = __toESM(require("fs/promises"));
42
+ var import_node_path2 = __toESM(require("path"));
43
+ var import_types = require("@tradejs/types");
44
+ var import_strategies = require("@tradejs/node/strategies");
45
+ var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
46
+
47
+ // src/lib/strategyGateFingerprint.ts
48
+ var import_node_crypto = require("crypto");
49
+ var import_node_module = require("module");
50
+ var import_promises = __toESM(require("fs/promises"));
51
+ var import_node_path = __toESM(require("path"));
52
+
53
+ // src/lib/runtimeLineage.ts
54
+ var runtimeLineageKey = (lineage) => lineage.schemaVersion === 2 ? [
55
+ "v2",
56
+ lineage.version,
57
+ lineage.strategyPackageVersion ?? "strategy:unknown",
58
+ lineage.runtimePackageVersion ?? "runtime:unknown"
59
+ ].join(":") : [
60
+ lineage.schemaVersion,
61
+ lineage.compositionId ?? "unbound-composition",
62
+ lineage.gitSha ?? "unknown",
63
+ lineage.gitDirty == null ? "unknown" : lineage.gitDirty ? "dirty" : "clean",
64
+ lineage.gateFingerprint,
65
+ lineage.configFingerprint,
66
+ lineage.contextFingerprint
67
+ ].join(":");
68
+
69
+ // src/lib/runtimeScorecard.ts
27
70
  var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
28
71
  var asArray = (value) => Array.isArray(value) ? value : [];
29
72
  var finiteNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
@@ -44,15 +87,32 @@ var extractRuntimeRows = (artifact) => {
44
87
  evaluations: unwrapRows(runtime.evaluations, "evaluation"),
45
88
  signals: unwrapRows(runtime.signals, "signal"),
46
89
  trades: unwrapRows(runtime.trades, "trade"),
90
+ lineageScopes: unwrapRows(runtime.lineageScopes, "lineageScope"),
47
91
  statsBuckets: asArray(runtime.evaluationStatsBuckets).map(asRecord).filter((item) => item != null)
48
92
  };
49
93
  };
50
94
  var buildRuntimeLineageSummary = (rows) => {
51
- const lineageRows = [...rows.evaluations, ...rows.signals, ...rows.trades];
95
+ const lineageRows = [
96
+ ...rows.evaluations,
97
+ ...rows.signals,
98
+ ...rows.trades,
99
+ ...rows.lineageScopes.map((scope) => ({
100
+ runtimeLineage: scope.lineage
101
+ }))
102
+ ];
52
103
  const lineages = lineageRows.map((row) => asRecord(row.runtimeLineage)).filter((lineage) => lineage != null);
53
104
  const identities = /* @__PURE__ */ new Map();
54
105
  for (const lineage of lineages) {
55
- const identity2 = {
106
+ const identity2 = lineage.schemaVersion === 2 ? {
107
+ schemaVersion: 2,
108
+ version: finiteNumber(lineage.version),
109
+ strategyPackageVersion: finiteString(
110
+ lineage.strategyPackageVersion
111
+ ),
112
+ runtimePackageVersion: finiteString(lineage.runtimePackageVersion),
113
+ maxLossValue: finiteNumber(lineage.maxLossValue)
114
+ } : {
115
+ schemaVersion: 1,
56
116
  compositionId: finiteString(lineage.compositionId),
57
117
  gitSha: finiteString(lineage.gitSha),
58
118
  gitDirty: typeof lineage.gitDirty === "boolean" ? lineage.gitDirty : null,
@@ -64,12 +124,23 @@ var buildRuntimeLineageSummary = (rows) => {
64
124
  identities.set(JSON.stringify(identity2), identity2);
65
125
  }
66
126
  const identity = identities.size === 1 ? [...identities.values()][0] : null;
67
- const complete = lineageRows.length > 0 && lineages.length === lineageRows.length && identity != null && identity.compositionId != null && identity.gitSha != null && identity.gitDirty === false && identity.gateFingerprint != null && identity.configFingerprint != null && identity.contextFingerprint != null && identity.maxLossValue != null;
127
+ const schemaVersion = finiteNumber(identity?.schemaVersion);
128
+ const identityComplete = lineages.length > 0 && identity != null && (schemaVersion === 2 && finiteNumber(identity.version) != null && finiteString(identity.strategyPackageVersion) != null && finiteString(identity.runtimePackageVersion) != null || schemaVersion === 1 && identity.compositionId != null && identity.gitSha != null && identity.gitDirty === false && identity.gateFingerprint != null && identity.configFingerprint != null && identity.contextFingerprint != null) && identity.maxLossValue != null;
129
+ const coverageComplete = lineageRows.length > 0 && lineages.length === lineageRows.length;
130
+ const complete = identityComplete && coverageComplete;
131
+ const lineageKey = identityComplete ? runtimeLineageKey(identity) : null;
68
132
  return {
69
133
  complete,
134
+ identityComplete,
135
+ coverageComplete,
70
136
  conflicts: identities.size > 1,
71
137
  rows: lineageRows.length,
72
138
  rowsWithLineage: lineages.length,
139
+ schemaVersion,
140
+ lineageKey,
141
+ version: finiteNumber(identity?.version),
142
+ strategyPackageVersion: finiteString(identity?.strategyPackageVersion),
143
+ runtimePackageVersion: finiteString(identity?.runtimePackageVersion),
73
144
  compositionId: finiteString(identity?.compositionId),
74
145
  gitSha: finiteString(identity?.gitSha),
75
146
  gitDirty: typeof identity?.gitDirty === "boolean" ? identity.gitDirty : null,
@@ -79,6 +150,20 @@ var buildRuntimeLineageSummary = (rows) => {
79
150
  maxLossValue: finiteNumber(identity?.maxLossValue)
80
151
  };
81
152
  };
153
+ var belongsToRuntimeLineage = (row, summary) => {
154
+ if (!summary.identityComplete || !summary.lineageKey) return false;
155
+ const lineage = asRecord(row.runtimeLineage);
156
+ if (!lineage) return false;
157
+ return runtimeLineageKey(lineage) === summary.lineageKey && finiteNumber(lineage.maxLossValue) === summary.maxLossValue;
158
+ };
159
+ var runtimeDeploymentBinding = (artifact) => {
160
+ const deployment = asRecord(asRecord(artifact)?.deployment);
161
+ return {
162
+ deploymentId: finiteString(deployment?.id),
163
+ accountId: finiteString(deployment?.accountId)
164
+ };
165
+ };
166
+ var belongsToRuntimeDeployment = (row, binding) => binding.deploymentId == null && binding.accountId == null ? true : finiteString(row.deploymentId) === binding.deploymentId && finiteString(row.accountId) === binding.accountId;
82
167
  var belongsToStrategy = (row, strategy) => strategy == null || finiteString(row.strategy) === strategy;
83
168
  var filterArtifactByStrategy = (artifact, strategy) => {
84
169
  if (!strategy) return artifact;
@@ -106,6 +191,9 @@ var filterArtifactByStrategy = (artifact, strategy) => {
106
191
  strategy
107
192
  )
108
193
  ),
194
+ lineageScopes: asArray(runtime.lineageScopes).filter(
195
+ (item) => belongsToStrategy(asRecord(item) ?? {}, strategy)
196
+ ),
109
197
  evaluationStatsBuckets: asArray(runtime.evaluationStatsBuckets).filter(
110
198
  (item) => belongsToStrategy(asRecord(item) ?? {}, strategy)
111
199
  )
@@ -285,6 +373,7 @@ var buildRuntimeScorecard = ({
285
373
  const scopedHistoryArtifacts = historyRuntimeArtifacts.map(
286
374
  (artifact) => filterArtifactByStrategy(artifact, strategy)
287
375
  );
376
+ const deploymentBinding = runtimeDeploymentBinding(runtimeArtifact);
288
377
  const rows = extractRuntimeRows(scopedRuntimeArtifact);
289
378
  const runtimeLineage = buildRuntimeLineageSummary(rows);
290
379
  const window = runtimeWindow(runtimeArtifact);
@@ -347,6 +436,12 @@ var buildRuntimeScorecard = ({
347
436
  ...scopedHistoryArtifacts,
348
437
  scopedRuntimeArtifact
349
438
  ]);
439
+ const comparableHistoryTrades = historyTrades.filter(
440
+ (trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && belongsToRuntimeLineage(trade, runtimeLineage)
441
+ );
442
+ const comparableCurrentClosedTrades = currentClosedTrades.filter(
443
+ (trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && belongsToRuntimeLineage(trade, runtimeLineage)
444
+ );
350
445
  const currentDistributions = buildDistributions(rows);
351
446
  const previousArtifact = scopedHistoryArtifacts.map((artifact) => ({ artifact, window: runtimeWindow(artifact) })).filter(({ window: candidateWindow }) => {
352
447
  const candidateEndTime = finiteNumber(candidateWindow.endTime);
@@ -357,7 +452,7 @@ var buildRuntimeScorecard = ({
357
452
  const previousDistributions = previousArtifact ? buildDistributions(extractRuntimeRows(previousArtifact.artifact)) : null;
358
453
  const rolling = [7, 30, 90].map(
359
454
  (days) => buildRollingPerformance({
360
- trades: [...historyTrades],
455
+ trades: [...comparableHistoryTrades],
361
456
  anchorTime: endTime,
362
457
  days
363
458
  })
@@ -371,6 +466,13 @@ var buildRuntimeScorecard = ({
371
466
  message: lineageReason
372
467
  });
373
468
  }
469
+ if (!runtimeLineage.complete) {
470
+ reactions.push({
471
+ code: "RUNTIME_LINEAGE_INCOMPLETE",
472
+ severity: "blocking",
473
+ message: "Runtime rows do not share one complete composition lineage."
474
+ });
475
+ }
374
476
  if (parityRatio != null && parityRatio < thresholds.minimumParityRatio) {
375
477
  reactions.push({
376
478
  code: "PARITY_REGRESSION",
@@ -408,6 +510,7 @@ var buildRuntimeScorecard = ({
408
510
  generatedAt,
409
511
  window: { startTime, endTime },
410
512
  strategy,
513
+ deployment: deploymentBinding,
411
514
  lineage: runtimeLineage,
412
515
  promotionStatus,
413
516
  thresholds,
@@ -452,17 +555,25 @@ var buildRuntimeScorecard = ({
452
555
  )
453
556
  ).length,
454
557
  fills: rows.trades.length,
455
- closedTrades: currentClosedTrades.length
558
+ closedTrades: currentClosedTrades.length,
559
+ comparableClosedTrades: comparableCurrentClosedTrades.length,
560
+ nonComparableClosedTrades: currentClosedTrades.length - comparableCurrentClosedTrades.length
456
561
  },
457
562
  realized: {
458
563
  pnl: sum(
459
- currentClosedTrades.map((trade) => finiteNumber(trade.closedPnl))
564
+ comparableCurrentClosedTrades.map(
565
+ (trade) => finiteNumber(trade.closedPnl)
566
+ )
460
567
  ),
461
568
  fees: sum(
462
- currentClosedTrades.map((trade) => finiteNumber(trade.totalFee))
569
+ comparableCurrentClosedTrades.map(
570
+ (trade) => finiteNumber(trade.totalFee)
571
+ )
463
572
  ),
464
573
  funding: sum(
465
- currentClosedTrades.map((trade) => finiteNumber(trade.fundingFee))
574
+ comparableCurrentClosedTrades.map(
575
+ (trade) => finiteNumber(trade.fundingFee)
576
+ )
466
577
  )
467
578
  },
468
579
  gateComparison: {
@@ -168,13 +168,17 @@ var parseBucketKey = (prefix, key) => {
168
168
  return null;
169
169
  }
170
170
  const suffix = key.slice(prefix.length);
171
- const firstColon = suffix.indexOf(":");
172
- if (firstColon <= 0 || firstColon >= suffix.length - 1) {
171
+ const parts = suffix.split(":");
172
+ if (parts.length < 2 || parts.some((part) => !part)) {
173
173
  return null;
174
174
  }
175
+ const [dayKey, ...scopeParts] = parts;
176
+ const strategy = scopeParts.at(-1);
177
+ if (!dayKey || !strategy) return null;
175
178
  return {
176
- dayKey: suffix.slice(0, firstColon),
177
- strategy: suffix.slice(firstColon + 1)
179
+ dayKey,
180
+ ...scopeParts.length > 1 ? { deploymentId: scopeParts.slice(0, -1).join(":") } : {},
181
+ strategy
178
182
  };
179
183
  };
180
184
  var loadRuntimeSignalEvaluationStatsBuckets = async (userName) => {
@@ -74,7 +74,7 @@ var import_constants5 = require("@tradejs/core/constants");
74
74
  var import_time3 = require("@tradejs/core/time");
75
75
  var import_backtestArtifacts = require("@tradejs/infra/backtestArtifacts");
76
76
  var import_redis4 = require("@tradejs/infra/redis");
77
- var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
77
+ var import_runtimeStrategies2 = require("@tradejs/node/runtimeStrategies");
78
78
  var import_types3 = require("@tradejs/types");
79
79
 
80
80
  // src/lib/runFormatting.ts
@@ -3577,6 +3577,54 @@ var import_connectors5 = require("@tradejs/node/connectors");
3577
3577
  var import_cli3 = require("@tradejs/node/cli");
3578
3578
  var import_constants2 = require("@tradejs/core/constants");
3579
3579
  var import_time2 = require("@tradejs/core/time");
3580
+ var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
3581
+
3582
+ // src/lib/runtimeStrategyBacktest.ts
3583
+ var import_chalk5 = __toESM(require("chalk"));
3584
+
3585
+ // src/lib/runtimeRedis.ts
3586
+ var import_redis = require("@tradejs/infra/redis");
3587
+ var import_time = require("@tradejs/core/time");
3588
+ var import_runtimeStrategyConfigs = require("@tradejs/infra/runtimeStrategyConfigs");
3589
+ var isRuntimeStrategyEnabled = (strategyConfig) => {
3590
+ const enabled = strategyConfig.ENABLE;
3591
+ return enabled !== false;
3592
+ };
3593
+
3594
+ // src/lib/runtimeStrategyBacktest.ts
3595
+ var BACKTEST_CLI_RUNTIME_CONFIG_KEYS = /* @__PURE__ */ new Set([
3596
+ "ENV",
3597
+ "INTERVAL",
3598
+ "MAKE_ORDERS",
3599
+ "CLOSE_OPPOSITE_POSITIONS",
3600
+ "BACKTEST_PRICE_MODE",
3601
+ "BACKTEST_ENTRY_DELAY_BARS"
3602
+ ]);
3603
+ var toStrategyConfigGrid = (strategyConfig) => Object.fromEntries(
3604
+ Object.entries(strategyConfig).filter(([key]) => !BACKTEST_CLI_RUNTIME_CONFIG_KEYS.has(key)).map(([key, value]) => [key, [value]])
3605
+ );
3606
+ var loadRuntimeStrategyBacktestConfigs = async (userName2) => {
3607
+ const configs = await (0, import_runtimeStrategyConfigs.loadRuntimeStrategyConfigs)(userName2, {
3608
+ onInvalidConfig: (key) => {
3609
+ console.log(import_chalk5.default.yellow(`Skip invalid runtime strategy config: ${key}`));
3610
+ }
3611
+ });
3612
+ return configs.filter(({ configId }) => configId === "config").filter(({ strategyName, strategyConfig }) => {
3613
+ const enabled = isRuntimeStrategyEnabled(strategyConfig);
3614
+ if (!enabled) {
3615
+ console.log(
3616
+ import_chalk5.default.yellow(
3617
+ `Skip inactive runtime strategy config by ENABLE=false: ${strategyName}`
3618
+ )
3619
+ );
3620
+ }
3621
+ return enabled;
3622
+ }).map(({ strategyName, strategyConfig }) => ({
3623
+ strategyName,
3624
+ strategyConfig,
3625
+ backtestConfig: toStrategyConfigGrid(strategyConfig)
3626
+ }));
3627
+ };
3580
3628
 
3581
3629
  // src/lib/timeWindow.ts
3582
3630
  var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
@@ -3680,53 +3728,6 @@ var resolveTimeWindow = ({
3680
3728
  );
3681
3729
  };
3682
3730
 
3683
- // src/lib/runtimeStrategyBacktest.ts
3684
- var import_chalk5 = __toESM(require("chalk"));
3685
-
3686
- // src/lib/runtimeRedis.ts
3687
- var import_redis = require("@tradejs/infra/redis");
3688
- var import_time = require("@tradejs/core/time");
3689
- var import_runtimeStrategyConfigs = require("@tradejs/infra/runtimeStrategyConfigs");
3690
- var isRuntimeStrategyEnabled = (strategyConfig) => {
3691
- const enabled = strategyConfig.ENABLE;
3692
- return enabled !== false;
3693
- };
3694
-
3695
- // src/lib/runtimeStrategyBacktest.ts
3696
- var BACKTEST_CLI_RUNTIME_CONFIG_KEYS = /* @__PURE__ */ new Set([
3697
- "ENV",
3698
- "INTERVAL",
3699
- "MAKE_ORDERS",
3700
- "CLOSE_OPPOSITE_POSITIONS",
3701
- "BACKTEST_PRICE_MODE",
3702
- "BACKTEST_ENTRY_DELAY_BARS"
3703
- ]);
3704
- var toStrategyConfigGrid = (strategyConfig) => Object.fromEntries(
3705
- Object.entries(strategyConfig).filter(([key]) => !BACKTEST_CLI_RUNTIME_CONFIG_KEYS.has(key)).map(([key, value]) => [key, [value]])
3706
- );
3707
- var loadRuntimeStrategyBacktestConfigs = async (userName2) => {
3708
- const configs = await (0, import_runtimeStrategyConfigs.loadRuntimeStrategyConfigs)(userName2, {
3709
- onInvalidConfig: (key) => {
3710
- console.log(import_chalk5.default.yellow(`Skip invalid runtime strategy config: ${key}`));
3711
- }
3712
- });
3713
- return configs.filter(({ configId }) => configId === "config").filter(({ strategyName, strategyConfig }) => {
3714
- const enabled = isRuntimeStrategyEnabled(strategyConfig);
3715
- if (!enabled) {
3716
- console.log(
3717
- import_chalk5.default.yellow(
3718
- `Skip inactive runtime strategy config by ENABLE=false: ${strategyName}`
3719
- )
3720
- );
3721
- }
3722
- return enabled;
3723
- }).map(({ strategyName, strategyConfig }) => ({
3724
- strategyName,
3725
- strategyConfig,
3726
- backtestConfig: toStrategyConfigGrid(strategyConfig)
3727
- }));
3728
- };
3729
-
3730
3731
  // src/lib/marketData/historyPrepare.ts
3731
3732
  var import_chalk6 = __toESM(require("chalk"));
3732
3733
  var import_connectors3 = require("@tradejs/connectors");
@@ -5025,7 +5026,7 @@ var validateBacktestRuntimeDeployment = ({
5025
5026
  };
5026
5027
  var prepareRunEnvironment2 = async () => {
5027
5028
  const deployment = validateBacktestRuntimeDeployment({
5028
- deployment: flags.deployment ? await (0, import_runtimeStrategies.getRuntimeDeployment)({
5029
+ deployment: flags.deployment ? await (0, import_runtimeStrategies2.getRuntimeDeployment)({
5029
5030
  userName,
5030
5031
  projectRoot,
5031
5032
  deploymentId: String(flags.deployment)