@tradejs/cli 2.0.19 → 2.0.21

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.
@@ -35,11 +35,12 @@ __export(aiTrain_exports, {
35
35
  module.exports = __toCommonJS(aiTrain_exports);
36
36
  var import_args = __toESM(require("args"));
37
37
  var import_chalk = __toESM(require("chalk"));
38
- var import_promises2 = __toESM(require("fs/promises"));
38
+ var import_promises3 = __toESM(require("fs/promises"));
39
39
  var import_path = __toESM(require("path"));
40
40
  var import_progress = __toESM(require("progress"));
41
41
  var import_constants = require("@tradejs/core/constants");
42
42
  var import_ai = require("@tradejs/infra/ai");
43
+ var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
43
44
  var import_redis = require("@tradejs/infra/redis");
44
45
  var import_ai2 = require("@tradejs/node/ai");
45
46
  var import_constants2 = require("@tradejs/node/constants");
@@ -333,7 +334,10 @@ var isDirectionMatchAtThreshold = (evaluation, threshold) => {
333
334
  return directionMatches === true && evaluation.quality != null && evaluation.quality >= threshold;
334
335
  };
335
336
  var summarizeAiTrainEvaluationsByDirection = (evaluations) => {
336
- const grouped = /* @__PURE__ */ new Map();
337
+ const grouped = /* @__PURE__ */ new Map([
338
+ ["LONG", []],
339
+ ["SHORT", []]
340
+ ]);
337
341
  for (const evaluation of evaluations) {
338
342
  const direction = typeof evaluation.direction === "string" && evaluation.direction.trim() ? evaluation.direction : "UNKNOWN";
339
343
  const bucket = grouped.get(direction) ?? [];
@@ -805,6 +809,14 @@ var buildAiChartSnapshot = (params) => {
805
809
  strategies: cards
806
810
  };
807
811
  };
812
+ var buildAiChartPersistenceReceipt = (params) => ({
813
+ persisted: true,
814
+ mode: params.snapshot.mode,
815
+ datasetId: params.datasetId,
816
+ generatedAt: params.snapshot.generatedAt,
817
+ cardIds: params.snapshot.strategies.map((card) => card.cardId),
818
+ ttlMs: params.ttlMs
819
+ });
808
820
 
809
821
  // src/lib/aiTrainEvaluationDump.ts
810
822
  var BASE_CONTEXT_FEATURE_SECTIONS = [
@@ -948,11 +960,56 @@ var resolveAiTrainRecentLimit = ({
948
960
 
949
961
  // src/lib/aiTrainResearch.ts
950
962
  var import_node_child_process = require("child_process");
963
+ var import_node_crypto2 = require("crypto");
964
+ var import_promises2 = __toESM(require("fs/promises"));
965
+ var import_node_path2 = __toESM(require("path"));
966
+ var import_strategies = require("@tradejs/node/strategies");
967
+ var import_types = require("@tradejs/types");
968
+
969
+ // src/lib/strategyGateFingerprint.ts
951
970
  var import_node_crypto = require("crypto");
952
971
  var import_promises = __toESM(require("fs/promises"));
953
972
  var import_node_path = __toESM(require("path"));
954
- var import_strategies = require("@tradejs/node/strategies");
955
- var import_types = require("@tradejs/types");
973
+ var gateFingerprintRelativePaths = (strategyName) => [
974
+ `packages/strategies/src/${strategyName}/adapters/ai.ts`,
975
+ `packages/strategies/src/${strategyName}/guardrails.ts`,
976
+ `packages/strategies/src/${strategyName}/pockets.ts`,
977
+ `packages/strategies/src/${strategyName}/config.ts`,
978
+ "packages/strategies/src/shared/localAiGate.ts",
979
+ "packages/node/src/ai.ts",
980
+ "packages/core/src/utils/strategyHelpers/signalBuilders.ts"
981
+ ];
982
+ var resolveStrategyGateFingerprint = async ({
983
+ projectRoot,
984
+ strategyName,
985
+ gitSha
986
+ }) => {
987
+ const candidates = await Promise.all(
988
+ gateFingerprintRelativePaths(strategyName).map(async (relativePath) => {
989
+ const content = await import_promises.default.readFile(import_node_path.default.join(projectRoot, relativePath)).catch(() => null);
990
+ return content == null ? null : { relativePath, content };
991
+ })
992
+ );
993
+ const sourceEntries = candidates.filter(
994
+ (entry) => entry != null
995
+ );
996
+ const hash = (0, import_node_crypto.createHash)("sha256");
997
+ hash.update(strategyName);
998
+ if (sourceEntries.length) {
999
+ for (const entry of sourceEntries) {
1000
+ hash.update(entry.relativePath);
1001
+ hash.update(entry.content);
1002
+ }
1003
+ } else {
1004
+ hash.update(gitSha ?? "unknown-git-sha");
1005
+ }
1006
+ return {
1007
+ gateFingerprint: hash.digest("hex").slice(0, 16),
1008
+ gateFingerprintFiles: sourceEntries.map((entry) => entry.relativePath)
1009
+ };
1010
+ };
1011
+
1012
+ // src/lib/aiTrainResearch.ts
956
1013
  var DAY_MS2 = 24 * 60 * 60 * 1e3;
957
1014
  var RESEARCH_CONTEXT_ENV_KEYS = [
958
1015
  "AI_MODE",
@@ -992,9 +1049,9 @@ var writeAiTrainResearchSnapshot = async ({
992
1049
  outputPath,
993
1050
  result
994
1051
  }) => {
995
- const resolvedPath = import_node_path.default.resolve(outputPath);
996
- await import_promises.default.mkdir(import_node_path.default.dirname(resolvedPath), { recursive: true });
997
- await import_promises.default.writeFile(
1052
+ const resolvedPath = import_node_path2.default.resolve(outputPath);
1053
+ await import_promises2.default.mkdir(import_node_path2.default.dirname(resolvedPath), { recursive: true });
1054
+ await import_promises2.default.writeFile(
998
1055
  resolvedPath,
999
1056
  `${JSON.stringify(result, null, 2)}
1000
1057
  `,
@@ -1013,7 +1070,7 @@ var normalizeForStableJson = (value) => {
1013
1070
  }
1014
1071
  return value;
1015
1072
  };
1016
- var fingerprintResearchValue = (value) => (0, import_node_crypto.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
1073
+ var fingerprintResearchValue = (value) => (0, import_node_crypto2.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
1017
1074
  var getTimestampRange = (evaluations) => {
1018
1075
  let minTimestamp = null;
1019
1076
  let maxTimestamp = null;
@@ -1078,17 +1135,11 @@ var summarizeAiTrainTerminalWindows = (evaluations, windowDays) => {
1078
1135
  selected: selected.length,
1079
1136
  approvedPerCalendarDay: outcome.approved / coverageDays,
1080
1137
  outcome,
1138
+ byDirection: summarizeAiTrainEvaluationsByDirection(selected),
1081
1139
  topRejectReasons: summarizeAiTrainRejectReasons(selected)
1082
1140
  };
1083
1141
  });
1084
1142
  };
1085
- var readOptionalFile = async (filePath) => {
1086
- try {
1087
- return await import_promises.default.readFile(filePath);
1088
- } catch {
1089
- return null;
1090
- }
1091
- };
1092
1143
  var getGitLineage = (projectRoot) => {
1093
1144
  try {
1094
1145
  const gitSha = (0, import_node_child_process.execFileSync)("git", ["rev-parse", "HEAD"], {
@@ -1110,53 +1161,20 @@ var getGitLineage = (projectRoot) => {
1110
1161
  return { gitSha: null, gitDirty: null };
1111
1162
  }
1112
1163
  };
1113
- var resolveGateFingerprint = async (projectRoot, strategyName, gitSha) => {
1114
- const relativeCandidates = [
1115
- `packages/strategies/src/${strategyName}/adapters/ai.ts`,
1116
- `packages/strategies/src/${strategyName}/guardrails.ts`,
1117
- `packages/strategies/src/${strategyName}/pockets.ts`,
1118
- `packages/strategies/src/${strategyName}/config.ts`,
1119
- "packages/strategies/src/shared/localAiGate.ts",
1120
- "packages/node/src/ai.ts"
1121
- ];
1122
- const optionalSourceEntries = await Promise.all(
1123
- relativeCandidates.map(async (relativePath) => {
1124
- const content = await readOptionalFile(
1125
- import_node_path.default.join(projectRoot, relativePath)
1126
- );
1127
- return content == null ? null : { relativePath, content };
1128
- })
1129
- );
1130
- const sourceEntries = [];
1131
- for (const entry of optionalSourceEntries) {
1132
- if (entry != null) {
1133
- sourceEntries.push(entry);
1134
- }
1135
- }
1136
- const hash = (0, import_node_crypto.createHash)("sha256");
1137
- hash.update(strategyName);
1138
- if (sourceEntries.length) {
1139
- for (const entry of sourceEntries) {
1140
- hash.update(entry.relativePath);
1141
- hash.update(entry.content);
1142
- }
1143
- } else {
1144
- hash.update(gitSha ?? "unknown-git-sha");
1145
- }
1146
- return {
1147
- gateFingerprint: hash.digest("hex").slice(0, 16),
1148
- gateFingerprintFiles: sourceEntries.map((entry) => entry.relativePath)
1149
- };
1150
- };
1151
1164
  var buildAiTrainLineage = async ({
1152
1165
  projectRoot,
1153
1166
  strategyName,
1154
1167
  configIds,
1155
1168
  runContext,
1169
+ sourceSha256s = [],
1156
1170
  env = process.env
1157
1171
  }) => {
1158
1172
  const { gitSha, gitDirty } = getGitLineage(projectRoot);
1159
- const gate = await resolveGateFingerprint(projectRoot, strategyName, gitSha);
1173
+ const gate = await resolveStrategyGateFingerprint({
1174
+ projectRoot,
1175
+ strategyName,
1176
+ gitSha
1177
+ });
1160
1178
  const normalizedConfigIds = [...new Set(configIds.filter(Boolean))].sort();
1161
1179
  const hyperliquidPerpUniverseFingerprint = typeof import_strategies.getHyperliquidPerpUniverseSnapshot === "function" ? (0, import_strategies.getHyperliquidPerpUniverseSnapshot)().fingerprint : null;
1162
1180
  const hyperliquidWhaleRegistryFingerprint = typeof import_strategies.getHyperliquidWhaleRegistrySnapshot === "function" ? (0, import_strategies.getHyperliquidWhaleRegistrySnapshot)().fingerprint : null;
@@ -1176,7 +1194,8 @@ var buildAiTrainLineage = async ({
1176
1194
  configIdsFingerprint: fingerprintResearchValue(normalizedConfigIds),
1177
1195
  configIds: normalizedConfigIds,
1178
1196
  contextFingerprint: fingerprintResearchValue(context),
1179
- context
1197
+ context,
1198
+ sourceSha256s: [...new Set(sourceSha256s.filter(Boolean))].sort()
1180
1199
  };
1181
1200
  };
1182
1201
 
@@ -1550,7 +1569,7 @@ var listMergedFiles = async (params) => {
1550
1569
  const { outDir, strategyName } = params;
1551
1570
  let entries = [];
1552
1571
  try {
1553
- entries = await import_promises2.default.readdir(outDir);
1572
+ entries = await import_promises3.default.readdir(outDir);
1554
1573
  } catch {
1555
1574
  return [];
1556
1575
  }
@@ -2006,6 +2025,7 @@ var main = async () => {
2006
2025
  projectRoot: String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd(),
2007
2026
  strategyName,
2008
2027
  configIds: finalEvaluations.map((evaluation) => evaluation.configId),
2028
+ sourceSha256s: await Promise.all(filePaths.map(import_strategyReleaseEvidence.strategyEvidenceFileSha256)),
2009
2029
  runContext: {
2010
2030
  mode: localOnly ? "local-deterministic" : "llm",
2011
2031
  model: localOnly ? "local-deterministic" : model,
@@ -2049,22 +2069,17 @@ var main = async () => {
2049
2069
  topRejectReasons,
2050
2070
  lineage
2051
2071
  },
2072
+ chart: null,
2052
2073
  errors: {
2053
2074
  failed,
2054
2075
  providerErrors: errorMessages
2055
2076
  }
2056
2077
  };
2057
- if (jsonOutputPath) {
2058
- await writeAiTrainResearchSnapshot({
2059
- outputPath: jsonOutputPath,
2060
- result
2061
- });
2062
- }
2063
2078
  if (dumpEvaluationsPath) {
2064
- await import_promises2.default.mkdir(import_path.default.dirname(import_path.default.resolve(dumpEvaluationsPath)), {
2079
+ await import_promises3.default.mkdir(import_path.default.dirname(import_path.default.resolve(dumpEvaluationsPath)), {
2065
2080
  recursive: true
2066
2081
  });
2067
- await import_promises2.default.writeFile(
2082
+ await import_promises3.default.writeFile(
2068
2083
  dumpEvaluationsPath,
2069
2084
  finalEvaluations.map(
2070
2085
  (evaluation) => JSON.stringify({
@@ -2092,7 +2107,7 @@ var main = async () => {
2092
2107
  );
2093
2108
  }
2094
2109
  if (saveChart) {
2095
- await persistAiChartSnapshot({
2110
+ const snapshot = await persistAiChartSnapshot({
2096
2111
  strategyName,
2097
2112
  evaluatedRows,
2098
2113
  minQuality,
@@ -2101,6 +2116,17 @@ var main = async () => {
2101
2116
  userName,
2102
2117
  datasetId
2103
2118
  });
2119
+ result.chart = buildAiChartPersistenceReceipt({
2120
+ snapshot,
2121
+ datasetId: datasetId ?? null,
2122
+ ttlMs: import_constants.TTL_1M
2123
+ });
2124
+ }
2125
+ if (jsonOutputPath) {
2126
+ await writeAiTrainResearchSnapshot({
2127
+ outputPath: jsonOutputPath,
2128
+ result
2129
+ });
2104
2130
  }
2105
2131
  if (jsonOutput) {
2106
2132
  if (printJsonOutput) {
@@ -4262,6 +4262,11 @@ import_args.default.option(
4262
4262
  "Skip per-test artifact persistence and keep only in-memory summary/AI-ML dataset output",
4263
4263
  false
4264
4264
  );
4265
+ import_args.default.option(
4266
+ "researchTrace",
4267
+ "Write compact setup/entry/exit/skip research trace JSONL",
4268
+ false
4269
+ );
4265
4270
  import_args.default.option(
4266
4271
  ["K", "continue"],
4267
4272
  "Continue latest compatible interrupted backtest run",
@@ -4357,6 +4362,7 @@ var buildBacktestTestKey = (test) => hashValue({
4357
4362
  connectorName: test.connectorName,
4358
4363
  interval: String(test.interval ?? ""),
4359
4364
  ml: Boolean(test.ml),
4365
+ researchTrace: Boolean(test.researchTrace),
4360
4366
  options: test.options,
4361
4367
  strategyConfig: test.strategyConfig,
4362
4368
  strategyName: test.strategyName,
@@ -5093,6 +5099,7 @@ var buildPreparedTestSuite = async ({
5093
5099
  },
5094
5100
  ml: mlEnabled,
5095
5101
  ai: aiEnabled,
5102
+ researchTrace: Boolean(flags.researchTrace),
5096
5103
  fast: isFastMode,
5097
5104
  timeoutMs: testItemTimeoutMs
5098
5105
  })).slice(
@@ -5276,6 +5283,7 @@ var toPersistedBacktestResultEntry = (result) => ({
5276
5283
  orderLogId: result.orderLogId,
5277
5284
  stat: result.stat,
5278
5285
  executionCostModel: result.executionCostModel,
5286
+ researchTraceSummary: result.researchTraceSummary,
5279
5287
  test: {
5280
5288
  userName: result.test.userName,
5281
5289
  name: result.test.name,
@@ -5746,7 +5754,8 @@ var backtest = async () => {
5746
5754
  backtestPriceMode,
5747
5755
  cacheOnly: Boolean(flags.cacheOnly),
5748
5756
  fast: Boolean(flags.fast),
5749
- ml: Boolean(flags.ml)
5757
+ ml: Boolean(flags.ml),
5758
+ researchTrace: Boolean(flags.researchTrace)
5750
5759
  },
5751
5760
  marketContextPreparedAt: (/* @__PURE__ */ new Date()).toISOString(),
5752
5761
  testSuite