@tradejs/cli 3.0.1 → 3.1.1
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/README.md +2 -0
- package/dist/cli.js +3707 -2983
- package/dist/lib/aiPocketSearch.js +10 -0
- package/dist/lib/aiTrainResearch.js +24 -15
- package/dist/lib/coreResearch.js +52 -20
- package/dist/lib/researchAgent.js +16 -2
- package/dist/lib/researchRoots.js +59 -0
- package/dist/lib/runtimeLineage.js +43 -19
- package/dist/lib/runtimeModeConfig.js +1 -1
- package/dist/lib/runtimeSignalsStorage.js +2 -1
- package/dist/lib/strategyGateFingerprint.js +26 -15
- package/dist/lib/strategyRelease.js +266 -253
- package/dist/scripts/agentRun.js +83 -52
- package/dist/scripts/aiPocketSearch.js +2269 -1972
- package/dist/scripts/aiTrain.js +24 -15
- package/dist/scripts/coreResearch.js +91 -30
- package/dist/scripts/replay.js +69 -27
- package/dist/scripts/replayRunner.js +69 -27
- package/dist/scripts/researchAuto.js +34 -13
- package/dist/scripts/runtimeConfig.js +290 -0
- package/dist/scripts/runtimeEvidence.js +2 -1
- package/dist/scripts/runtimeParity.js +1 -1
- package/dist/scripts/runtimeScorecard.js +108 -103
- package/dist/scripts/signals.js +162 -224
- package/dist/scripts/signalsDaemon.js +162 -224
- package/dist/scripts/strategyRelease.js +222 -209
- package/dist/scripts/test-ml.js +8 -2
- package/package.json +13 -10
package/dist/scripts/aiTrain.js
CHANGED
|
@@ -1001,28 +1001,37 @@ var import_types = require("@tradejs/types");
|
|
|
1001
1001
|
|
|
1002
1002
|
// src/lib/strategyGateFingerprint.ts
|
|
1003
1003
|
var import_node_crypto = require("crypto");
|
|
1004
|
+
var import_node_module = require("module");
|
|
1004
1005
|
var import_promises = __toESM(require("fs/promises"));
|
|
1005
1006
|
var import_node_path = __toESM(require("path"));
|
|
1006
|
-
var
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
"
|
|
1012
|
-
"
|
|
1013
|
-
"packages/core/src/utils/strategyHelpers/signalBuilders.ts"
|
|
1007
|
+
var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
|
|
1008
|
+
var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
|
|
1009
|
+
var gateFingerprintSpecifiers = (strategyName) => [
|
|
1010
|
+
getStrategyPackageName(strategyName),
|
|
1011
|
+
"@tradejs/strategy-kit/ai-gate",
|
|
1012
|
+
"@tradejs/node/ai",
|
|
1013
|
+
"@tradejs/core/strategies"
|
|
1014
1014
|
];
|
|
1015
1015
|
var resolveStrategyGateFingerprint = async ({
|
|
1016
1016
|
projectRoot,
|
|
1017
1017
|
strategyName,
|
|
1018
1018
|
gitSha
|
|
1019
1019
|
}) => {
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1020
|
+
const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
|
|
1021
|
+
const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
|
|
1022
|
+
const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
|
|
1023
|
+
const candidates = requireFromProject ? await Promise.all(
|
|
1024
|
+
gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
|
|
1025
|
+
let resolvedPath;
|
|
1026
|
+
try {
|
|
1027
|
+
resolvedPath = requireFromProject.resolve(specifier);
|
|
1028
|
+
} catch {
|
|
1029
|
+
return null;
|
|
1030
|
+
}
|
|
1031
|
+
const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
|
|
1032
|
+
return content == null ? null : { specifier, content };
|
|
1024
1033
|
})
|
|
1025
|
-
);
|
|
1034
|
+
) : [];
|
|
1026
1035
|
const sourceEntries = candidates.filter(
|
|
1027
1036
|
(entry) => entry != null
|
|
1028
1037
|
);
|
|
@@ -1030,7 +1039,7 @@ var resolveStrategyGateFingerprint = async ({
|
|
|
1030
1039
|
hash.update(strategyName);
|
|
1031
1040
|
if (sourceEntries.length) {
|
|
1032
1041
|
for (const entry of sourceEntries) {
|
|
1033
|
-
hash.update(entry.
|
|
1042
|
+
hash.update(entry.specifier);
|
|
1034
1043
|
hash.update(entry.content);
|
|
1035
1044
|
}
|
|
1036
1045
|
} else {
|
|
@@ -1038,7 +1047,7 @@ var resolveStrategyGateFingerprint = async ({
|
|
|
1038
1047
|
}
|
|
1039
1048
|
return {
|
|
1040
1049
|
gateFingerprint: hash.digest("hex").slice(0, 16),
|
|
1041
|
-
gateFingerprintFiles: sourceEntries.map((entry) => entry.
|
|
1050
|
+
gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
|
|
1042
1051
|
};
|
|
1043
1052
|
};
|
|
1044
1053
|
|
|
@@ -34,7 +34,7 @@ __export(coreResearch_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(coreResearch_exports);
|
|
36
36
|
var import_promises5 = __toESM(require("fs/promises"));
|
|
37
|
-
var
|
|
37
|
+
var import_node_path7 = __toESM(require("path"));
|
|
38
38
|
var import_chalk = __toESM(require("chalk"));
|
|
39
39
|
|
|
40
40
|
// src/lib/coreResearch/io.ts
|
|
@@ -641,7 +641,7 @@ var writeCoreResearchStageIndex = async (rootDir) => {
|
|
|
641
641
|
|
|
642
642
|
// src/lib/coreResearch/orchestrator.ts
|
|
643
643
|
var import_promises4 = __toESM(require("fs/promises"));
|
|
644
|
-
var
|
|
644
|
+
var import_node_path6 = __toESM(require("path"));
|
|
645
645
|
var import_node_child_process = require("child_process");
|
|
646
646
|
var import_node_crypto5 = require("crypto");
|
|
647
647
|
var import_coreResearch = require("@tradejs/infra/coreResearch");
|
|
@@ -2107,6 +2107,26 @@ var summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
|
2107
2107
|
};
|
|
2108
2108
|
};
|
|
2109
2109
|
|
|
2110
|
+
// src/lib/researchRoots.ts
|
|
2111
|
+
var import_node_path5 = __toESM(require("path"));
|
|
2112
|
+
var SOURCE_REPOSITORY_ROOT_ENV = "TRADEJS_SOURCE_REPOSITORY_ROOT";
|
|
2113
|
+
var firstNonEmpty = (...values) => values.map((value) => String(value || "").trim()).find(Boolean);
|
|
2114
|
+
var resolveResearchRoots = (options = {}) => {
|
|
2115
|
+
const cwd = import_node_path5.default.resolve(options.cwd || process.cwd());
|
|
2116
|
+
const env = options.env || process.env;
|
|
2117
|
+
const projectRoot = import_node_path5.default.resolve(
|
|
2118
|
+
firstNonEmpty(options.projectRoot, env.PROJECT_CWD, cwd) || cwd
|
|
2119
|
+
);
|
|
2120
|
+
const sourceRepositoryRoot = import_node_path5.default.resolve(
|
|
2121
|
+
firstNonEmpty(
|
|
2122
|
+
options.sourceRepositoryRoot,
|
|
2123
|
+
env[SOURCE_REPOSITORY_ROOT_ENV],
|
|
2124
|
+
cwd
|
|
2125
|
+
) || cwd
|
|
2126
|
+
);
|
|
2127
|
+
return { projectRoot, sourceRepositoryRoot };
|
|
2128
|
+
};
|
|
2129
|
+
|
|
2110
2130
|
// src/lib/coreResearch/orchestrator.ts
|
|
2111
2131
|
var summarizeSupplementalFiles = async (params) => {
|
|
2112
2132
|
const loaded = await readCoreResearchVariant({
|
|
@@ -2299,7 +2319,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
|
|
|
2299
2319
|
const primarySourceHashes = Object.fromEntries(
|
|
2300
2320
|
analyses.flatMap(
|
|
2301
2321
|
(analysis) => analysis.files.map((file) => [
|
|
2302
|
-
|
|
2322
|
+
import_node_path6.default.relative(paths.researchDir, file.path),
|
|
2303
2323
|
file.sha256
|
|
2304
2324
|
])
|
|
2305
2325
|
)
|
|
@@ -2318,8 +2338,8 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
|
|
|
2318
2338
|
const supplementalSourceHashes = Object.fromEntries(
|
|
2319
2339
|
await Promise.all(
|
|
2320
2340
|
supplementalSourcePaths.map(async (filePath) => [
|
|
2321
|
-
|
|
2322
|
-
await sha256File(
|
|
2341
|
+
import_node_path6.default.relative(paths.researchDir, import_node_path6.default.resolve(filePath)),
|
|
2342
|
+
await sha256File(import_node_path6.default.resolve(filePath))
|
|
2323
2343
|
])
|
|
2324
2344
|
)
|
|
2325
2345
|
);
|
|
@@ -2396,7 +2416,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
|
|
|
2396
2416
|
"trades.jsonl": await sha256File(paths.tradesPath),
|
|
2397
2417
|
"report.html": await sha256File(paths.reportPath)
|
|
2398
2418
|
};
|
|
2399
|
-
const resolvedRunsPath =
|
|
2419
|
+
const resolvedRunsPath = import_node_path6.default.join(paths.researchDir, "resolved-runs.json");
|
|
2400
2420
|
try {
|
|
2401
2421
|
artifactHashes["resolved-runs.json"] = await sha256File(resolvedRunsPath);
|
|
2402
2422
|
} catch (error) {
|
|
@@ -2406,7 +2426,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
|
|
|
2406
2426
|
for (const name of await import_promises4.default.readdir(paths.runLogDir)) {
|
|
2407
2427
|
if (!name.endsWith(".log")) continue;
|
|
2408
2428
|
artifactHashes[`runs/${name}`] = await sha256File(
|
|
2409
|
-
|
|
2429
|
+
import_node_path6.default.join(paths.runLogDir, name)
|
|
2410
2430
|
);
|
|
2411
2431
|
}
|
|
2412
2432
|
} catch (error) {
|
|
@@ -2463,12 +2483,14 @@ var analyzeCoreResearch = async (spec, options = {}) => {
|
|
|
2463
2483
|
}
|
|
2464
2484
|
};
|
|
2465
2485
|
var createCoreResearchSpecTemplate = (params) => {
|
|
2466
|
-
const rootDir =
|
|
2467
|
-
|
|
2486
|
+
const rootDir = import_node_path6.default.relative(
|
|
2487
|
+
import_node_path6.default.resolve(params.projectRoot),
|
|
2488
|
+
import_node_path6.default.join(import_node_path6.default.resolve(params.projectRoot), "data", "research", "core")
|
|
2489
|
+
).replace(/\\/g, "/");
|
|
2468
2490
|
const lineage = (() => {
|
|
2469
2491
|
try {
|
|
2470
2492
|
const gitSha = (0, import_node_child_process.execFileSync)("git", ["rev-parse", "HEAD"], {
|
|
2471
|
-
cwd:
|
|
2493
|
+
cwd: params.sourceRepositoryRoot,
|
|
2472
2494
|
encoding: "utf8",
|
|
2473
2495
|
stdio: ["ignore", "pipe", "ignore"]
|
|
2474
2496
|
}).trim();
|
|
@@ -2476,13 +2498,23 @@ var createCoreResearchSpecTemplate = (params) => {
|
|
|
2476
2498
|
"git",
|
|
2477
2499
|
["diff", "--binary", "--no-ext-diff", "HEAD"],
|
|
2478
2500
|
{
|
|
2479
|
-
cwd:
|
|
2501
|
+
cwd: params.sourceRepositoryRoot,
|
|
2480
2502
|
encoding: "utf8",
|
|
2481
2503
|
stdio: ["ignore", "pipe", "ignore"]
|
|
2482
2504
|
}
|
|
2483
2505
|
);
|
|
2506
|
+
const sourceRepository = (0, import_node_child_process.execFileSync)(
|
|
2507
|
+
"git",
|
|
2508
|
+
["remote", "get-url", "origin"],
|
|
2509
|
+
{
|
|
2510
|
+
cwd: params.sourceRepositoryRoot,
|
|
2511
|
+
encoding: "utf8",
|
|
2512
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
2513
|
+
}
|
|
2514
|
+
).trim();
|
|
2484
2515
|
return {
|
|
2485
2516
|
gitSha,
|
|
2517
|
+
...sourceRepository ? { sourceRepository } : {},
|
|
2486
2518
|
...dirtyDiff ? {
|
|
2487
2519
|
dirtyDiffSha256: (0, import_node_crypto5.createHash)("sha256").update(dirtyDiff).digest("hex")
|
|
2488
2520
|
} : {}
|
|
@@ -2583,11 +2615,11 @@ var createCoreResearchSpecTemplate = (params) => {
|
|
|
2583
2615
|
};
|
|
2584
2616
|
var runCommand = async (params) => {
|
|
2585
2617
|
if (!params.command.length) throw new Error("Cannot run an empty command");
|
|
2586
|
-
await import_promises4.default.mkdir(
|
|
2618
|
+
await import_promises4.default.mkdir(import_node_path6.default.dirname(params.logPath), { recursive: true });
|
|
2587
2619
|
const chunks = [];
|
|
2588
2620
|
const child = (0, import_node_child_process.spawn)(params.command[0], params.command.slice(1), {
|
|
2589
2621
|
cwd: params.cwd,
|
|
2590
|
-
env: process.env,
|
|
2622
|
+
env: { ...process.env, ...params.env },
|
|
2591
2623
|
stdio: ["ignore", "pipe", "pipe"]
|
|
2592
2624
|
});
|
|
2593
2625
|
const capture = (chunk) => {
|
|
@@ -2655,7 +2687,7 @@ var validateCoreResearchRunCommand = (params) => {
|
|
|
2655
2687
|
};
|
|
2656
2688
|
var runCoreResearch = async (params) => {
|
|
2657
2689
|
const { spec } = params;
|
|
2658
|
-
const cwd =
|
|
2690
|
+
const cwd = import_node_path6.default.resolve(params.cwd ?? process.cwd());
|
|
2659
2691
|
const prepared = await prepareCoreResearch(spec);
|
|
2660
2692
|
const resolvedVariants = [];
|
|
2661
2693
|
for (const variant of spec.variants) {
|
|
@@ -2673,7 +2705,7 @@ var runCoreResearch = async (params) => {
|
|
|
2673
2705
|
artifactHashes: { variant: sha256Json(variant) }
|
|
2674
2706
|
});
|
|
2675
2707
|
let runId = "";
|
|
2676
|
-
const backtestLogPath =
|
|
2708
|
+
const backtestLogPath = import_node_path6.default.join(
|
|
2677
2709
|
prepared.paths.runLogDir,
|
|
2678
2710
|
`${variant.id}-backtest.log`
|
|
2679
2711
|
);
|
|
@@ -2682,6 +2714,14 @@ var runCoreResearch = async (params) => {
|
|
|
2682
2714
|
command: variant.command,
|
|
2683
2715
|
cwd,
|
|
2684
2716
|
logPath: backtestLogPath,
|
|
2717
|
+
env: {
|
|
2718
|
+
PROJECT_CWD: cwd,
|
|
2719
|
+
...params.sourceRepositoryRoot ? {
|
|
2720
|
+
[SOURCE_REPOSITORY_ROOT_ENV]: import_node_path6.default.resolve(
|
|
2721
|
+
params.sourceRepositoryRoot
|
|
2722
|
+
)
|
|
2723
|
+
} : {}
|
|
2724
|
+
},
|
|
2685
2725
|
onLine: (line) => {
|
|
2686
2726
|
const match = line.match(
|
|
2687
2727
|
/backtest run id:\s*([0-9]{12}-[a-f0-9]{8})/i
|
|
@@ -2692,12 +2732,12 @@ var runCoreResearch = async (params) => {
|
|
|
2692
2732
|
if (!runId) {
|
|
2693
2733
|
throw new Error(`Backtest for ${variant.id} did not report a run id`);
|
|
2694
2734
|
}
|
|
2695
|
-
const exportLogPath =
|
|
2735
|
+
const exportLogPath = import_node_path6.default.join(
|
|
2696
2736
|
prepared.paths.runLogDir,
|
|
2697
2737
|
`${variant.id}-export.log`
|
|
2698
2738
|
);
|
|
2699
2739
|
const exportParts = [];
|
|
2700
|
-
const cliPath =
|
|
2740
|
+
const cliPath = import_node_path6.default.resolve(process.argv[1]);
|
|
2701
2741
|
await runCommand({
|
|
2702
2742
|
command: [
|
|
2703
2743
|
process.execPath,
|
|
@@ -2714,9 +2754,17 @@ var runCoreResearch = async (params) => {
|
|
|
2714
2754
|
],
|
|
2715
2755
|
cwd,
|
|
2716
2756
|
logPath: exportLogPath,
|
|
2757
|
+
env: {
|
|
2758
|
+
PROJECT_CWD: cwd,
|
|
2759
|
+
...params.sourceRepositoryRoot ? {
|
|
2760
|
+
[SOURCE_REPOSITORY_ROOT_ENV]: import_node_path6.default.resolve(
|
|
2761
|
+
params.sourceRepositoryRoot
|
|
2762
|
+
)
|
|
2763
|
+
} : {}
|
|
2764
|
+
},
|
|
2717
2765
|
onLine: (line) => {
|
|
2718
2766
|
const match = line.match(/^part\d+:\s+(.+)$/);
|
|
2719
|
-
if (match) exportParts.push(
|
|
2767
|
+
if (match) exportParts.push(import_node_path6.default.resolve(cwd, match[1].trim()));
|
|
2720
2768
|
}
|
|
2721
2769
|
});
|
|
2722
2770
|
if (!exportParts.length) {
|
|
@@ -2727,7 +2775,7 @@ var runCoreResearch = async (params) => {
|
|
|
2727
2775
|
const traceFiles = await (0, import_coreResearch.listCoreResearchTraceFiles)({
|
|
2728
2776
|
strategyName: spec.strategy,
|
|
2729
2777
|
runId,
|
|
2730
|
-
outDir:
|
|
2778
|
+
outDir: import_node_path6.default.resolve(cwd, "data/research/core/trace")
|
|
2731
2779
|
});
|
|
2732
2780
|
resolvedVariants.push({
|
|
2733
2781
|
...variant,
|
|
@@ -2747,7 +2795,7 @@ var runCoreResearch = async (params) => {
|
|
|
2747
2795
|
...Object.fromEntries(
|
|
2748
2796
|
await Promise.all(
|
|
2749
2797
|
exportParts.map(async (filePath) => [
|
|
2750
|
-
|
|
2798
|
+
import_node_path6.default.basename(filePath),
|
|
2751
2799
|
await sha256File(filePath)
|
|
2752
2800
|
])
|
|
2753
2801
|
)
|
|
@@ -2766,7 +2814,7 @@ var runCoreResearch = async (params) => {
|
|
|
2766
2814
|
}
|
|
2767
2815
|
}
|
|
2768
2816
|
await writeJsonAtomic(
|
|
2769
|
-
|
|
2817
|
+
import_node_path6.default.join(prepared.paths.researchDir, "resolved-runs.json"),
|
|
2770
2818
|
{
|
|
2771
2819
|
schema: "tradejs-core-research-resolved-runs/v1",
|
|
2772
2820
|
researchId: spec.researchId,
|
|
@@ -2795,11 +2843,11 @@ var parseTimestamp = (value, name) => {
|
|
|
2795
2843
|
if (!Number.isFinite(numeric)) throw new Error(`${name} is invalid: ${text}`);
|
|
2796
2844
|
return numeric;
|
|
2797
2845
|
};
|
|
2798
|
-
var readSymbols = async (argv) => {
|
|
2846
|
+
var readSymbols = async (argv, projectRoot) => {
|
|
2799
2847
|
const symbolsFile = valueAfter(argv, "--symbolsFile");
|
|
2800
2848
|
if (symbolsFile) {
|
|
2801
2849
|
const parsed = JSON.parse(
|
|
2802
|
-
await import_promises5.default.readFile(
|
|
2850
|
+
await import_promises5.default.readFile(import_node_path7.default.resolve(projectRoot, symbolsFile), "utf8")
|
|
2803
2851
|
);
|
|
2804
2852
|
if (!Array.isArray(parsed) || parsed.some((symbol) => typeof symbol !== "string")) {
|
|
2805
2853
|
throw new Error("--symbolsFile must contain a JSON string array");
|
|
@@ -2820,6 +2868,8 @@ var printUsage = () => {
|
|
|
2820
2868
|
The run command executes only variants with an explicit command[] in the preregistered spec. Variants with files[] are analyzed without starting a backtest.`);
|
|
2821
2869
|
};
|
|
2822
2870
|
var main = async () => {
|
|
2871
|
+
const roots = resolveResearchRoots();
|
|
2872
|
+
process.chdir(roots.projectRoot);
|
|
2823
2873
|
const argv = process.argv.slice(2);
|
|
2824
2874
|
const command = argv[0];
|
|
2825
2875
|
if (!command || !["init", "prepare", "analyze", "run", "verify", "index"].includes(command)) {
|
|
@@ -2828,28 +2878,32 @@ var main = async () => {
|
|
|
2828
2878
|
return;
|
|
2829
2879
|
}
|
|
2830
2880
|
if (command === "index") {
|
|
2831
|
-
const rootDir =
|
|
2881
|
+
const rootDir = import_node_path7.default.resolve(
|
|
2882
|
+
roots.projectRoot,
|
|
2832
2883
|
required(valueAfter(argv, "--root"), "--root")
|
|
2833
2884
|
);
|
|
2834
2885
|
const index = await writeCoreResearchStageIndex(rootDir);
|
|
2835
2886
|
console.log(
|
|
2836
2887
|
import_chalk.default.green(
|
|
2837
|
-
`Core research index: ${
|
|
2888
|
+
`Core research index: ${import_node_path7.default.join(rootDir, "index.json")} (${index.families.length} families)`
|
|
2838
2889
|
)
|
|
2839
2890
|
);
|
|
2840
2891
|
return;
|
|
2841
2892
|
}
|
|
2842
2893
|
if (command === "init") {
|
|
2843
|
-
const outputPath =
|
|
2894
|
+
const outputPath = import_node_path7.default.resolve(
|
|
2895
|
+
roots.projectRoot,
|
|
2844
2896
|
required(valueAfter(argv, "--out"), "--out")
|
|
2845
2897
|
);
|
|
2846
2898
|
const spec = createCoreResearchSpecTemplate({
|
|
2847
2899
|
researchId: required(valueAfter(argv, "--researchId"), "--researchId"),
|
|
2848
2900
|
strategy: required(valueAfter(argv, "--strategy"), "--strategy"),
|
|
2849
|
-
symbols: await readSymbols(argv),
|
|
2901
|
+
symbols: await readSymbols(argv, roots.projectRoot),
|
|
2850
2902
|
start: parseTimestamp(valueAfter(argv, "--start"), "--start"),
|
|
2851
2903
|
end: parseTimestamp(valueAfter(argv, "--end"), "--end"),
|
|
2852
|
-
outputPath
|
|
2904
|
+
outputPath,
|
|
2905
|
+
projectRoot: roots.projectRoot,
|
|
2906
|
+
sourceRepositoryRoot: roots.sourceRepositoryRoot
|
|
2853
2907
|
});
|
|
2854
2908
|
const { outputPath: _outputPath, ...persisted } = spec;
|
|
2855
2909
|
await writeJsonAtomic(outputPath, persisted);
|
|
@@ -2861,7 +2915,10 @@ var main = async () => {
|
|
|
2861
2915
|
);
|
|
2862
2916
|
return;
|
|
2863
2917
|
}
|
|
2864
|
-
const specPath =
|
|
2918
|
+
const specPath = import_node_path7.default.resolve(
|
|
2919
|
+
roots.projectRoot,
|
|
2920
|
+
required(valueAfter(argv, "--spec"), "--spec")
|
|
2921
|
+
);
|
|
2865
2922
|
const loaded = await loadCoreResearchSpec(specPath);
|
|
2866
2923
|
if (command === "prepare") {
|
|
2867
2924
|
const result = await prepareCoreResearch(loaded.spec);
|
|
@@ -2880,7 +2937,11 @@ var main = async () => {
|
|
|
2880
2937
|
return;
|
|
2881
2938
|
}
|
|
2882
2939
|
if (command === "run") {
|
|
2883
|
-
const analyzed = await runCoreResearch({
|
|
2940
|
+
const analyzed = await runCoreResearch({
|
|
2941
|
+
spec: loaded.spec,
|
|
2942
|
+
cwd: roots.projectRoot,
|
|
2943
|
+
sourceRepositoryRoot: roots.sourceRepositoryRoot
|
|
2944
|
+
});
|
|
2884
2945
|
console.log(
|
|
2885
2946
|
import_chalk.default.green(`Core research report: ${analyzed.paths.reportPath}`)
|
|
2886
2947
|
);
|
package/dist/scripts/replay.js
CHANGED
|
@@ -4347,7 +4347,7 @@ var buildRuntimeModeStrategyConfig = ({
|
|
|
4347
4347
|
...strategyConfig,
|
|
4348
4348
|
ENV: env,
|
|
4349
4349
|
MAKE_ORDERS: makeOrders,
|
|
4350
|
-
INTERVAL: interval,
|
|
4350
|
+
INTERVAL: strategyConfig.INTERVAL ?? interval,
|
|
4351
4351
|
...typeof recordRuntimeTrades === "boolean" ? { RECORD_RUNTIME_TRADES: recordRuntimeTrades } : {},
|
|
4352
4352
|
...aiReplayAnalyses?.length ? { AI_REPLAY_ANALYSES: aiReplayAnalyses } : {}
|
|
4353
4353
|
});
|
|
@@ -4910,28 +4910,37 @@ var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvid
|
|
|
4910
4910
|
|
|
4911
4911
|
// src/lib/strategyGateFingerprint.ts
|
|
4912
4912
|
var import_node_crypto = require("crypto");
|
|
4913
|
+
var import_node_module = require("module");
|
|
4913
4914
|
var import_promises = __toESM(require("fs/promises"));
|
|
4914
4915
|
var import_node_path = __toESM(require("path"));
|
|
4915
|
-
var
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
"
|
|
4921
|
-
"
|
|
4922
|
-
"packages/core/src/utils/strategyHelpers/signalBuilders.ts"
|
|
4916
|
+
var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
|
|
4917
|
+
var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
|
|
4918
|
+
var gateFingerprintSpecifiers = (strategyName) => [
|
|
4919
|
+
getStrategyPackageName(strategyName),
|
|
4920
|
+
"@tradejs/strategy-kit/ai-gate",
|
|
4921
|
+
"@tradejs/node/ai",
|
|
4922
|
+
"@tradejs/core/strategies"
|
|
4923
4923
|
];
|
|
4924
4924
|
var resolveStrategyGateFingerprint = async ({
|
|
4925
4925
|
projectRoot,
|
|
4926
4926
|
strategyName,
|
|
4927
4927
|
gitSha
|
|
4928
4928
|
}) => {
|
|
4929
|
-
const
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4929
|
+
const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
|
|
4930
|
+
const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
|
|
4931
|
+
const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
|
|
4932
|
+
const candidates = requireFromProject ? await Promise.all(
|
|
4933
|
+
gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
|
|
4934
|
+
let resolvedPath;
|
|
4935
|
+
try {
|
|
4936
|
+
resolvedPath = requireFromProject.resolve(specifier);
|
|
4937
|
+
} catch {
|
|
4938
|
+
return null;
|
|
4939
|
+
}
|
|
4940
|
+
const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
|
|
4941
|
+
return content == null ? null : { specifier, content };
|
|
4933
4942
|
})
|
|
4934
|
-
);
|
|
4943
|
+
) : [];
|
|
4935
4944
|
const sourceEntries = candidates.filter(
|
|
4936
4945
|
(entry) => entry != null
|
|
4937
4946
|
);
|
|
@@ -4939,7 +4948,7 @@ var resolveStrategyGateFingerprint = async ({
|
|
|
4939
4948
|
hash.update(strategyName);
|
|
4940
4949
|
if (sourceEntries.length) {
|
|
4941
4950
|
for (const entry of sourceEntries) {
|
|
4942
|
-
hash.update(entry.
|
|
4951
|
+
hash.update(entry.specifier);
|
|
4943
4952
|
hash.update(entry.content);
|
|
4944
4953
|
}
|
|
4945
4954
|
} else {
|
|
@@ -4947,7 +4956,7 @@ var resolveStrategyGateFingerprint = async ({
|
|
|
4947
4956
|
}
|
|
4948
4957
|
return {
|
|
4949
4958
|
gateFingerprint: hash.digest("hex").slice(0, 16),
|
|
4950
|
-
gateFingerprintFiles: sourceEntries.map((entry) => entry.
|
|
4959
|
+
gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
|
|
4951
4960
|
};
|
|
4952
4961
|
};
|
|
4953
4962
|
|
|
@@ -5126,14 +5135,29 @@ var resolveRuntimeGateFingerprint = async ({
|
|
|
5126
5135
|
gateFingerprintCache.set(cacheKey, result);
|
|
5127
5136
|
return result;
|
|
5128
5137
|
};
|
|
5129
|
-
|
|
5138
|
+
async function buildRuntimeLineage({
|
|
5130
5139
|
projectRoot,
|
|
5131
5140
|
strategyName,
|
|
5132
5141
|
compositionId,
|
|
5142
|
+
releaseVersion,
|
|
5143
|
+
strategyPackageVersion,
|
|
5144
|
+
runtimePackageVersion,
|
|
5133
5145
|
config,
|
|
5134
5146
|
runContext,
|
|
5135
5147
|
env = process.env
|
|
5136
|
-
})
|
|
5148
|
+
}) {
|
|
5149
|
+
if (releaseVersion != null) {
|
|
5150
|
+
if (!Number.isSafeInteger(releaseVersion) || releaseVersion <= 0) {
|
|
5151
|
+
throw new Error(`Invalid runtime releaseVersion: ${releaseVersion}`);
|
|
5152
|
+
}
|
|
5153
|
+
return {
|
|
5154
|
+
schemaVersion: 2,
|
|
5155
|
+
releaseVersion,
|
|
5156
|
+
strategyPackageVersion,
|
|
5157
|
+
runtimePackageVersion,
|
|
5158
|
+
maxLossValue: resolveRuntimeMaxLossValue(config)
|
|
5159
|
+
};
|
|
5160
|
+
}
|
|
5137
5161
|
const git = resolveGitLineage(projectRoot);
|
|
5138
5162
|
const hyperliquidPerpUniverseFingerprint = typeof import_strategies3.getHyperliquidPerpUniverseSnapshot === "function" ? (0, import_strategies3.getHyperliquidPerpUniverseSnapshot)().fingerprint : await resolveSnapshotFingerprint(
|
|
5139
5163
|
projectRoot,
|
|
@@ -5168,8 +5192,8 @@ var buildRuntimeLineage = async ({
|
|
|
5168
5192
|
contextFingerprint: fingerprintRuntimeValue(context),
|
|
5169
5193
|
maxLossValue: resolveRuntimeMaxLossValue(config)
|
|
5170
5194
|
};
|
|
5171
|
-
}
|
|
5172
|
-
var runtimeLineageKey = (lineage) => [
|
|
5195
|
+
}
|
|
5196
|
+
var runtimeLineageKey = (lineage) => lineage.schemaVersion === 2 ? ["v2", lineage.releaseVersion].join(":") : [
|
|
5173
5197
|
lineage.schemaVersion,
|
|
5174
5198
|
lineage.compositionId ?? "unbound-composition",
|
|
5175
5199
|
lineage.gitSha ?? "unknown",
|
|
@@ -5421,6 +5445,7 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5421
5445
|
userName: replayUserName,
|
|
5422
5446
|
connectorName,
|
|
5423
5447
|
runtimeConfigId: "config",
|
|
5448
|
+
runtimeLineage,
|
|
5424
5449
|
config: buildReplayStrategyConfig({
|
|
5425
5450
|
strategyConfig,
|
|
5426
5451
|
interval
|
|
@@ -7201,6 +7226,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7201
7226
|
strategy,
|
|
7202
7227
|
symbol,
|
|
7203
7228
|
runtimeConfigId,
|
|
7229
|
+
runtimeReleaseVersion,
|
|
7204
7230
|
timestamp,
|
|
7205
7231
|
lineage
|
|
7206
7232
|
}) => {
|
|
@@ -7213,6 +7239,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7213
7239
|
strategy,
|
|
7214
7240
|
symbol,
|
|
7215
7241
|
...runtimeConfigId ? { runtimeConfigId } : {},
|
|
7242
|
+
...runtimeReleaseVersion ? { runtimeReleaseVersion } : {},
|
|
7216
7243
|
lineage,
|
|
7217
7244
|
firstTimestamp: existing ? Math.min(existing.firstTimestamp, timestamp) : timestamp,
|
|
7218
7245
|
lastTimestamp: existing ? Math.max(existing.lastTimestamp, timestamp) : timestamp
|
|
@@ -7223,6 +7250,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7223
7250
|
strategy: signal.strategy,
|
|
7224
7251
|
symbol: signal.symbol,
|
|
7225
7252
|
runtimeConfigId: signal.runtimeConfigId,
|
|
7253
|
+
runtimeReleaseVersion: signal.runtimeReleaseVersion,
|
|
7226
7254
|
timestamp: signal.timestamp,
|
|
7227
7255
|
lineage: signal.runtimeLineage
|
|
7228
7256
|
});
|
|
@@ -7232,6 +7260,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7232
7260
|
strategy: evaluation.strategy,
|
|
7233
7261
|
symbol: evaluation.symbol,
|
|
7234
7262
|
runtimeConfigId: evaluation.runtimeConfigId,
|
|
7263
|
+
runtimeReleaseVersion: evaluation.runtimeReleaseVersion,
|
|
7235
7264
|
timestamp: evaluation.timestamp,
|
|
7236
7265
|
lineage: evaluation.runtimeLineage
|
|
7237
7266
|
});
|
|
@@ -8542,13 +8571,26 @@ var renderLineageRows = (runtimeComparison) => {
|
|
|
8542
8571
|
contexts: /* @__PURE__ */ new Set()
|
|
8543
8572
|
};
|
|
8544
8573
|
existing.scopes += 1;
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8574
|
+
if (record.lineage.schemaVersion === 2) {
|
|
8575
|
+
existing.gitShas.add("release-versioned");
|
|
8576
|
+
existing.dirty.add("n/a");
|
|
8577
|
+
existing.gates.add("release-versioned");
|
|
8578
|
+
existing.configs.add(`v${record.lineage.releaseVersion}`);
|
|
8579
|
+
existing.contexts.add(
|
|
8580
|
+
[
|
|
8581
|
+
record.lineage.strategyPackageVersion ?? "strategy:unknown",
|
|
8582
|
+
record.lineage.runtimePackageVersion ?? "runtime:unknown"
|
|
8583
|
+
].join("/")
|
|
8584
|
+
);
|
|
8585
|
+
} else {
|
|
8586
|
+
existing.gitShas.add(record.lineage.gitSha ?? "unknown");
|
|
8587
|
+
existing.dirty.add(
|
|
8588
|
+
record.lineage.gitDirty == null ? "unknown" : String(record.lineage.gitDirty)
|
|
8589
|
+
);
|
|
8590
|
+
existing.gates.add(record.lineage.gateFingerprint);
|
|
8591
|
+
existing.configs.add(record.lineage.configFingerprint);
|
|
8592
|
+
existing.contexts.add(record.lineage.contextFingerprint);
|
|
8593
|
+
}
|
|
8552
8594
|
grouped.set(record.strategy, existing);
|
|
8553
8595
|
}
|
|
8554
8596
|
const formatSet = (values) => {
|