@tradejs/cli 3.1.0 → 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 +1226 -928
- package/dist/lib/coreResearch.js +52 -20
- package/dist/lib/researchRoots.js +59 -0
- package/dist/lib/runtimeLineage.js +19 -4
- package/dist/lib/runtimeModeConfig.js +1 -1
- package/dist/lib/runtimeSignalsStorage.js +2 -1
- package/dist/scripts/agentRun.js +37 -11
- package/dist/scripts/coreResearch.js +91 -30
- package/dist/scripts/replay.js +45 -12
- package/dist/scripts/replayRunner.js +45 -12
- package/dist/scripts/researchAuto.js +32 -11
- package/dist/scripts/runtimeConfig.js +290 -0
- package/dist/scripts/runtimeEvidence.js +1 -1
- package/dist/scripts/runtimeParity.js +1 -1
- package/dist/scripts/signals.js +138 -209
- package/dist/scripts/signalsDaemon.js +138 -209
- package/package.json +12 -8
|
@@ -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
|
});
|
|
@@ -5135,14 +5135,29 @@ var resolveRuntimeGateFingerprint = async ({
|
|
|
5135
5135
|
gateFingerprintCache.set(cacheKey, result);
|
|
5136
5136
|
return result;
|
|
5137
5137
|
};
|
|
5138
|
-
|
|
5138
|
+
async function buildRuntimeLineage({
|
|
5139
5139
|
projectRoot,
|
|
5140
5140
|
strategyName,
|
|
5141
5141
|
compositionId,
|
|
5142
|
+
releaseVersion,
|
|
5143
|
+
strategyPackageVersion,
|
|
5144
|
+
runtimePackageVersion,
|
|
5142
5145
|
config,
|
|
5143
5146
|
runContext,
|
|
5144
5147
|
env = process.env
|
|
5145
|
-
})
|
|
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
|
+
}
|
|
5146
5161
|
const git = resolveGitLineage(projectRoot);
|
|
5147
5162
|
const hyperliquidPerpUniverseFingerprint = typeof import_strategies3.getHyperliquidPerpUniverseSnapshot === "function" ? (0, import_strategies3.getHyperliquidPerpUniverseSnapshot)().fingerprint : await resolveSnapshotFingerprint(
|
|
5148
5163
|
projectRoot,
|
|
@@ -5177,8 +5192,8 @@ var buildRuntimeLineage = async ({
|
|
|
5177
5192
|
contextFingerprint: fingerprintRuntimeValue(context),
|
|
5178
5193
|
maxLossValue: resolveRuntimeMaxLossValue(config)
|
|
5179
5194
|
};
|
|
5180
|
-
}
|
|
5181
|
-
var runtimeLineageKey = (lineage) => [
|
|
5195
|
+
}
|
|
5196
|
+
var runtimeLineageKey = (lineage) => lineage.schemaVersion === 2 ? ["v2", lineage.releaseVersion].join(":") : [
|
|
5182
5197
|
lineage.schemaVersion,
|
|
5183
5198
|
lineage.compositionId ?? "unbound-composition",
|
|
5184
5199
|
lineage.gitSha ?? "unknown",
|
|
@@ -5430,6 +5445,7 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5430
5445
|
userName: replayUserName,
|
|
5431
5446
|
connectorName,
|
|
5432
5447
|
runtimeConfigId: "config",
|
|
5448
|
+
runtimeLineage,
|
|
5433
5449
|
config: buildReplayStrategyConfig({
|
|
5434
5450
|
strategyConfig,
|
|
5435
5451
|
interval
|
|
@@ -7210,6 +7226,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7210
7226
|
strategy,
|
|
7211
7227
|
symbol,
|
|
7212
7228
|
runtimeConfigId,
|
|
7229
|
+
runtimeReleaseVersion,
|
|
7213
7230
|
timestamp,
|
|
7214
7231
|
lineage
|
|
7215
7232
|
}) => {
|
|
@@ -7222,6 +7239,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7222
7239
|
strategy,
|
|
7223
7240
|
symbol,
|
|
7224
7241
|
...runtimeConfigId ? { runtimeConfigId } : {},
|
|
7242
|
+
...runtimeReleaseVersion ? { runtimeReleaseVersion } : {},
|
|
7225
7243
|
lineage,
|
|
7226
7244
|
firstTimestamp: existing ? Math.min(existing.firstTimestamp, timestamp) : timestamp,
|
|
7227
7245
|
lastTimestamp: existing ? Math.max(existing.lastTimestamp, timestamp) : timestamp
|
|
@@ -7232,6 +7250,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7232
7250
|
strategy: signal.strategy,
|
|
7233
7251
|
symbol: signal.symbol,
|
|
7234
7252
|
runtimeConfigId: signal.runtimeConfigId,
|
|
7253
|
+
runtimeReleaseVersion: signal.runtimeReleaseVersion,
|
|
7235
7254
|
timestamp: signal.timestamp,
|
|
7236
7255
|
lineage: signal.runtimeLineage
|
|
7237
7256
|
});
|
|
@@ -7241,6 +7260,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7241
7260
|
strategy: evaluation.strategy,
|
|
7242
7261
|
symbol: evaluation.symbol,
|
|
7243
7262
|
runtimeConfigId: evaluation.runtimeConfigId,
|
|
7263
|
+
runtimeReleaseVersion: evaluation.runtimeReleaseVersion,
|
|
7244
7264
|
timestamp: evaluation.timestamp,
|
|
7245
7265
|
lineage: evaluation.runtimeLineage
|
|
7246
7266
|
});
|
|
@@ -8551,13 +8571,26 @@ var renderLineageRows = (runtimeComparison) => {
|
|
|
8551
8571
|
contexts: /* @__PURE__ */ new Set()
|
|
8552
8572
|
};
|
|
8553
8573
|
existing.scopes += 1;
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
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
|
+
}
|
|
8561
8594
|
grouped.set(record.strategy, existing);
|
|
8562
8595
|
}
|
|
8563
8596
|
const formatSet = (values) => {
|
|
@@ -4350,7 +4350,7 @@ var buildRuntimeModeStrategyConfig = ({
|
|
|
4350
4350
|
...strategyConfig,
|
|
4351
4351
|
ENV: env,
|
|
4352
4352
|
MAKE_ORDERS: makeOrders,
|
|
4353
|
-
INTERVAL: interval,
|
|
4353
|
+
INTERVAL: strategyConfig.INTERVAL ?? interval,
|
|
4354
4354
|
...typeof recordRuntimeTrades === "boolean" ? { RECORD_RUNTIME_TRADES: recordRuntimeTrades } : {},
|
|
4355
4355
|
...aiReplayAnalyses?.length ? { AI_REPLAY_ANALYSES: aiReplayAnalyses } : {}
|
|
4356
4356
|
});
|
|
@@ -5138,14 +5138,29 @@ var resolveRuntimeGateFingerprint = async ({
|
|
|
5138
5138
|
gateFingerprintCache.set(cacheKey, result);
|
|
5139
5139
|
return result;
|
|
5140
5140
|
};
|
|
5141
|
-
|
|
5141
|
+
async function buildRuntimeLineage({
|
|
5142
5142
|
projectRoot,
|
|
5143
5143
|
strategyName,
|
|
5144
5144
|
compositionId,
|
|
5145
|
+
releaseVersion,
|
|
5146
|
+
strategyPackageVersion,
|
|
5147
|
+
runtimePackageVersion,
|
|
5145
5148
|
config,
|
|
5146
5149
|
runContext,
|
|
5147
5150
|
env = process.env
|
|
5148
|
-
})
|
|
5151
|
+
}) {
|
|
5152
|
+
if (releaseVersion != null) {
|
|
5153
|
+
if (!Number.isSafeInteger(releaseVersion) || releaseVersion <= 0) {
|
|
5154
|
+
throw new Error(`Invalid runtime releaseVersion: ${releaseVersion}`);
|
|
5155
|
+
}
|
|
5156
|
+
return {
|
|
5157
|
+
schemaVersion: 2,
|
|
5158
|
+
releaseVersion,
|
|
5159
|
+
strategyPackageVersion,
|
|
5160
|
+
runtimePackageVersion,
|
|
5161
|
+
maxLossValue: resolveRuntimeMaxLossValue(config)
|
|
5162
|
+
};
|
|
5163
|
+
}
|
|
5149
5164
|
const git = resolveGitLineage(projectRoot);
|
|
5150
5165
|
const hyperliquidPerpUniverseFingerprint = typeof import_strategies3.getHyperliquidPerpUniverseSnapshot === "function" ? (0, import_strategies3.getHyperliquidPerpUniverseSnapshot)().fingerprint : await resolveSnapshotFingerprint(
|
|
5151
5166
|
projectRoot,
|
|
@@ -5180,8 +5195,8 @@ var buildRuntimeLineage = async ({
|
|
|
5180
5195
|
contextFingerprint: fingerprintRuntimeValue(context),
|
|
5181
5196
|
maxLossValue: resolveRuntimeMaxLossValue(config)
|
|
5182
5197
|
};
|
|
5183
|
-
}
|
|
5184
|
-
var runtimeLineageKey = (lineage) => [
|
|
5198
|
+
}
|
|
5199
|
+
var runtimeLineageKey = (lineage) => lineage.schemaVersion === 2 ? ["v2", lineage.releaseVersion].join(":") : [
|
|
5185
5200
|
lineage.schemaVersion,
|
|
5186
5201
|
lineage.compositionId ?? "unbound-composition",
|
|
5187
5202
|
lineage.gitSha ?? "unknown",
|
|
@@ -5433,6 +5448,7 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5433
5448
|
userName: replayUserName,
|
|
5434
5449
|
connectorName,
|
|
5435
5450
|
runtimeConfigId: "config",
|
|
5451
|
+
runtimeLineage,
|
|
5436
5452
|
config: buildReplayStrategyConfig({
|
|
5437
5453
|
strategyConfig,
|
|
5438
5454
|
interval
|
|
@@ -7213,6 +7229,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7213
7229
|
strategy,
|
|
7214
7230
|
symbol,
|
|
7215
7231
|
runtimeConfigId,
|
|
7232
|
+
runtimeReleaseVersion,
|
|
7216
7233
|
timestamp,
|
|
7217
7234
|
lineage
|
|
7218
7235
|
}) => {
|
|
@@ -7225,6 +7242,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7225
7242
|
strategy,
|
|
7226
7243
|
symbol,
|
|
7227
7244
|
...runtimeConfigId ? { runtimeConfigId } : {},
|
|
7245
|
+
...runtimeReleaseVersion ? { runtimeReleaseVersion } : {},
|
|
7228
7246
|
lineage,
|
|
7229
7247
|
firstTimestamp: existing ? Math.min(existing.firstTimestamp, timestamp) : timestamp,
|
|
7230
7248
|
lastTimestamp: existing ? Math.max(existing.lastTimestamp, timestamp) : timestamp
|
|
@@ -7235,6 +7253,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7235
7253
|
strategy: signal.strategy,
|
|
7236
7254
|
symbol: signal.symbol,
|
|
7237
7255
|
runtimeConfigId: signal.runtimeConfigId,
|
|
7256
|
+
runtimeReleaseVersion: signal.runtimeReleaseVersion,
|
|
7238
7257
|
timestamp: signal.timestamp,
|
|
7239
7258
|
lineage: signal.runtimeLineage
|
|
7240
7259
|
});
|
|
@@ -7244,6 +7263,7 @@ var buildRuntimeEvidenceLineageScopes = ({
|
|
|
7244
7263
|
strategy: evaluation.strategy,
|
|
7245
7264
|
symbol: evaluation.symbol,
|
|
7246
7265
|
runtimeConfigId: evaluation.runtimeConfigId,
|
|
7266
|
+
runtimeReleaseVersion: evaluation.runtimeReleaseVersion,
|
|
7247
7267
|
timestamp: evaluation.timestamp,
|
|
7248
7268
|
lineage: evaluation.runtimeLineage
|
|
7249
7269
|
});
|
|
@@ -8554,13 +8574,26 @@ var renderLineageRows = (runtimeComparison) => {
|
|
|
8554
8574
|
contexts: /* @__PURE__ */ new Set()
|
|
8555
8575
|
};
|
|
8556
8576
|
existing.scopes += 1;
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8577
|
+
if (record.lineage.schemaVersion === 2) {
|
|
8578
|
+
existing.gitShas.add("release-versioned");
|
|
8579
|
+
existing.dirty.add("n/a");
|
|
8580
|
+
existing.gates.add("release-versioned");
|
|
8581
|
+
existing.configs.add(`v${record.lineage.releaseVersion}`);
|
|
8582
|
+
existing.contexts.add(
|
|
8583
|
+
[
|
|
8584
|
+
record.lineage.strategyPackageVersion ?? "strategy:unknown",
|
|
8585
|
+
record.lineage.runtimePackageVersion ?? "runtime:unknown"
|
|
8586
|
+
].join("/")
|
|
8587
|
+
);
|
|
8588
|
+
} else {
|
|
8589
|
+
existing.gitShas.add(record.lineage.gitSha ?? "unknown");
|
|
8590
|
+
existing.dirty.add(
|
|
8591
|
+
record.lineage.gitDirty == null ? "unknown" : String(record.lineage.gitDirty)
|
|
8592
|
+
);
|
|
8593
|
+
existing.gates.add(record.lineage.gateFingerprint);
|
|
8594
|
+
existing.configs.add(record.lineage.configFingerprint);
|
|
8595
|
+
existing.contexts.add(record.lineage.contextFingerprint);
|
|
8596
|
+
}
|
|
8564
8597
|
grouped.set(record.strategy, existing);
|
|
8565
8598
|
}
|
|
8566
8599
|
const formatSet = (values) => {
|
|
@@ -57,7 +57,7 @@ var import_chalk2 = __toESM(require("chalk"));
|
|
|
57
57
|
var import_node_child_process = require("child_process");
|
|
58
58
|
var import_promises = __toESM(require("fs/promises"));
|
|
59
59
|
var import_node_os = __toESM(require("os"));
|
|
60
|
-
var
|
|
60
|
+
var import_node_path2 = __toESM(require("path"));
|
|
61
61
|
var import_constants = require("@tradejs/core/constants");
|
|
62
62
|
var import_ai = require("@tradejs/infra/ai");
|
|
63
63
|
var import_logger = require("@tradejs/infra/logger");
|
|
@@ -84,6 +84,26 @@ var BACKTEST_CLI_RUNTIME_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
84
84
|
"BACKTEST_ENTRY_DELAY_BARS"
|
|
85
85
|
]);
|
|
86
86
|
|
|
87
|
+
// src/lib/researchRoots.ts
|
|
88
|
+
var import_node_path = __toESM(require("path"));
|
|
89
|
+
var SOURCE_REPOSITORY_ROOT_ENV = "TRADEJS_SOURCE_REPOSITORY_ROOT";
|
|
90
|
+
var firstNonEmpty = (...values) => values.map((value) => String(value || "").trim()).find(Boolean);
|
|
91
|
+
var resolveResearchRoots = (options = {}) => {
|
|
92
|
+
const cwd = import_node_path.default.resolve(options.cwd || process.cwd());
|
|
93
|
+
const env = options.env || process.env;
|
|
94
|
+
const projectRoot2 = import_node_path.default.resolve(
|
|
95
|
+
firstNonEmpty(options.projectRoot, env.PROJECT_CWD, cwd) || cwd
|
|
96
|
+
);
|
|
97
|
+
const sourceRepositoryRoot2 = import_node_path.default.resolve(
|
|
98
|
+
firstNonEmpty(
|
|
99
|
+
options.sourceRepositoryRoot,
|
|
100
|
+
env[SOURCE_REPOSITORY_ROOT_ENV],
|
|
101
|
+
cwd
|
|
102
|
+
) || cwd
|
|
103
|
+
);
|
|
104
|
+
return { projectRoot: projectRoot2, sourceRepositoryRoot: sourceRepositoryRoot2 };
|
|
105
|
+
};
|
|
106
|
+
|
|
87
107
|
// src/lib/telegramReports.ts
|
|
88
108
|
var import_cli = require("@tradejs/node/cli");
|
|
89
109
|
var TELEGRAM_REPORT_CHUNK_LIMIT = 3900;
|
|
@@ -175,11 +195,11 @@ import_args.default.option(["O", "outDir"], "AI export output directory", "data/
|
|
|
175
195
|
import_args.default.option(["A", "skipAgent"], "Skip direct research agent invocation", false);
|
|
176
196
|
import_args.default.option(["j", "json"], "Print structured JSON summary", false);
|
|
177
197
|
var flags = import_args.default.parse(process.argv);
|
|
178
|
-
var projectRoot
|
|
198
|
+
var { projectRoot, sourceRepositoryRoot } = resolveResearchRoots();
|
|
179
199
|
var dotenvPath = String(
|
|
180
|
-
process.env.DOTENV_CONFIG_PATH ||
|
|
181
|
-
).trim() ||
|
|
182
|
-
var getResearchAutoLockPath = (userName) =>
|
|
200
|
+
process.env.DOTENV_CONFIG_PATH || import_node_path2.default.join(projectRoot, ".env")
|
|
201
|
+
).trim() || import_node_path2.default.join(projectRoot, ".env");
|
|
202
|
+
var getResearchAutoLockPath = (userName) => import_node_path2.default.join(
|
|
183
203
|
projectRoot,
|
|
184
204
|
"data",
|
|
185
205
|
"cache",
|
|
@@ -223,7 +243,7 @@ var acquireResearchAutoLock = async ({
|
|
|
223
243
|
startedAt,
|
|
224
244
|
argv: [...process.argv]
|
|
225
245
|
};
|
|
226
|
-
await import_promises.default.mkdir(
|
|
246
|
+
await import_promises.default.mkdir(import_node_path2.default.dirname(lockPath), { recursive: true });
|
|
227
247
|
const writeLock = async () => {
|
|
228
248
|
await import_promises.default.writeFile(lockPath, JSON.stringify(nextLock, null, 2), {
|
|
229
249
|
flag: "wx"
|
|
@@ -360,7 +380,7 @@ var listMergedFiles = async (outDir, strategyName) => {
|
|
|
360
380
|
try {
|
|
361
381
|
const entries = await import_promises.default.readdir(outDir);
|
|
362
382
|
const prefix = `ai-dataset-${(0, import_ai.toFileToken)(strategyName)}-merged-`;
|
|
363
|
-
return entries.filter((name) => name.startsWith(prefix) && name.endsWith(".jsonl")).sort().map((name) =>
|
|
383
|
+
return entries.filter((name) => name.startsWith(prefix) && name.endsWith(".jsonl")).sort().map((name) => import_node_path2.default.join(outDir, name));
|
|
364
384
|
} catch {
|
|
365
385
|
return [];
|
|
366
386
|
}
|
|
@@ -480,6 +500,7 @@ var runCliCommand = async (params) => {
|
|
|
480
500
|
const env = {
|
|
481
501
|
...process.env,
|
|
482
502
|
PROJECT_CWD: projectRoot,
|
|
503
|
+
[SOURCE_REPOSITORY_ROOT_ENV]: sourceRepositoryRoot,
|
|
483
504
|
DOTENV_CONFIG_PATH: dotenvPath,
|
|
484
505
|
...params.nodeHeapMb ? {
|
|
485
506
|
NODE_OPTIONS: buildNodeOptions({
|
|
@@ -489,8 +510,8 @@ var runCliCommand = async (params) => {
|
|
|
489
510
|
};
|
|
490
511
|
return new Promise((resolve, reject) => {
|
|
491
512
|
const child = (0, import_node_child_process.spawn)(
|
|
492
|
-
|
|
493
|
-
[
|
|
513
|
+
process.execPath,
|
|
514
|
+
[import_node_path2.default.resolve(process.argv[1]), params.command, ...params.args],
|
|
494
515
|
{
|
|
495
516
|
cwd: projectRoot,
|
|
496
517
|
env,
|
|
@@ -672,8 +693,8 @@ var main = async () => {
|
|
|
672
693
|
const jsonOutput = Boolean(flags.json);
|
|
673
694
|
const skipAgent = Boolean(flags.skipAgent);
|
|
674
695
|
const outDirArg = String(flags.outDir || "data/ai/export").trim() || "data/ai/export";
|
|
675
|
-
const outDir =
|
|
676
|
-
const cleanDirArg =
|
|
696
|
+
const outDir = import_node_path2.default.resolve(projectRoot, outDirArg);
|
|
697
|
+
const cleanDirArg = import_node_path2.default.relative(import_node_path2.default.join(projectRoot, "data"), outDir).replace(/\\/g, "/");
|
|
677
698
|
const target = await resolveTarget();
|
|
678
699
|
const runId = `${Date.now()}-${(0, import_ai.toFileToken)(target.strategy)}`;
|
|
679
700
|
const run = {
|