@tradejs/cli 2.0.19 → 2.0.20
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.
- package/dist/cli.js +8787 -3214
- package/dist/lib/aiExport.js +14 -1
- package/dist/lib/aiPocketSearch.js +499 -67
- package/dist/lib/aiPocketSearchCli.js +113 -0
- package/dist/lib/aiTrainCharts.js +14 -1
- package/dist/lib/aiTrainMetrics.js +4 -1
- package/dist/lib/aiTrainResearch.js +88 -54
- package/dist/lib/coreResearch.js +2738 -0
- package/dist/lib/executionCalibration.js +6 -3
- package/dist/lib/runtimeLineage.js +81 -48
- package/dist/lib/runtimeScorecard.js +153 -10
- package/dist/lib/strategyGateFingerprint.js +80 -0
- package/dist/lib/strategyRelease.js +1365 -0
- package/dist/scripts/aiExport.js +16 -3
- package/dist/scripts/aiPocketSearch.js +1069 -163
- package/dist/scripts/aiTrain.js +91 -65
- package/dist/scripts/backtest.js +10 -1
- package/dist/scripts/coreResearch.js +2830 -0
- package/dist/scripts/executionCalibration.js +6 -3
- package/dist/scripts/replay.js +106 -73
- package/dist/scripts/replayRunner.js +106 -73
- package/dist/scripts/replayRuntimeEvidence.js +27 -14
- package/dist/scripts/runtimeEvidence.js +16 -8
- package/dist/scripts/runtimeScorecard.js +883 -29
- package/dist/scripts/signals.js +133 -89
- package/dist/scripts/signalsDaemon.js +133 -89
- package/dist/scripts/strategyRelease.js +1469 -0
- package/package.json +11 -9
package/dist/scripts/aiTrain.js
CHANGED
|
@@ -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
|
|
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
|
|
955
|
-
|
|
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 =
|
|
996
|
-
await
|
|
997
|
-
await
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
2079
|
+
await import_promises3.default.mkdir(import_path.default.dirname(import_path.default.resolve(dumpEvaluationsPath)), {
|
|
2065
2080
|
recursive: true
|
|
2066
2081
|
});
|
|
2067
|
-
await
|
|
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) {
|
package/dist/scripts/backtest.js
CHANGED
|
@@ -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
|