@tradejs/cli 2.0.15 → 2.0.16
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 +2916 -978
- package/dist/lib/aiPocketSearch.js +493 -24
- package/dist/lib/aiTrainResearch.js +19 -2
- package/dist/lib/marketContextPrepare.js +85 -8
- package/dist/lib/researchAgent.js +3 -30
- package/dist/lib/runtimeDebugEvidence.js +76 -1
- package/dist/lib/runtimeEvidenceArtifacts.js +255 -0
- package/dist/lib/runtimeEvidenceSync.js +308 -0
- package/dist/lib/runtimeRedis.js +25 -0
- package/dist/lib/runtimeScorecard.js +442 -0
- package/dist/lib/runtimeTradeSync.js +9 -0
- package/dist/scripts/agentRun.js +16 -31
- package/dist/scripts/aiPocketSearch.js +717 -29
- package/dist/scripts/aiTrain.js +32 -2
- package/dist/scripts/backtest.js +83 -8
- package/dist/scripts/replay.js +92 -8
- package/dist/scripts/replayRunner.js +92 -8
- package/dist/scripts/replayRuntimeEvidence.js +68 -161
- package/dist/scripts/runtimeEvidence.js +316 -161
- package/dist/scripts/runtimeEvidenceSync.js +335 -0
- package/dist/scripts/runtimeParity.js +83 -8
- package/dist/scripts/runtimeScorecard.js +731 -0
- package/dist/scripts/signals.js +234 -142
- package/dist/scripts/signalsDaemon.js +234 -142
- package/dist/scripts/signalsSummary.js +9 -0
- package/dist/workers/testerWorker.js +2 -0
- package/package.json +11 -9
|
@@ -34,7 +34,8 @@ __export(aiTrainResearch_exports, {
|
|
|
34
34
|
fingerprintResearchValue: () => fingerprintResearchValue,
|
|
35
35
|
summarizeAiTrainCoverage: () => summarizeAiTrainCoverage,
|
|
36
36
|
summarizeAiTrainRejectReasons: () => summarizeAiTrainRejectReasons,
|
|
37
|
-
summarizeAiTrainTerminalWindows: () => summarizeAiTrainTerminalWindows
|
|
37
|
+
summarizeAiTrainTerminalWindows: () => summarizeAiTrainTerminalWindows,
|
|
38
|
+
writeAiTrainResearchSnapshot: () => writeAiTrainResearchSnapshot
|
|
38
39
|
});
|
|
39
40
|
module.exports = __toCommonJS(aiTrainResearch_exports);
|
|
40
41
|
var import_node_child_process = require("child_process");
|
|
@@ -350,6 +351,20 @@ var DERIVATIVES_CONTEXT_DATA_MODEL = {
|
|
|
350
351
|
hyperliquidWhaleMinCoveragePct: 0.8,
|
|
351
352
|
hyperliquidWhaleDataModelVersion: import_types.HYPERLIQUID_WHALE_DATA_MODEL_VERSION
|
|
352
353
|
};
|
|
354
|
+
var writeAiTrainResearchSnapshot = async ({
|
|
355
|
+
outputPath,
|
|
356
|
+
result
|
|
357
|
+
}) => {
|
|
358
|
+
const resolvedPath = import_node_path.default.resolve(outputPath);
|
|
359
|
+
await import_promises.default.mkdir(import_node_path.default.dirname(resolvedPath), { recursive: true });
|
|
360
|
+
await import_promises.default.writeFile(
|
|
361
|
+
resolvedPath,
|
|
362
|
+
`${JSON.stringify(result, null, 2)}
|
|
363
|
+
`,
|
|
364
|
+
"utf8"
|
|
365
|
+
);
|
|
366
|
+
return resolvedPath;
|
|
367
|
+
};
|
|
353
368
|
var normalizeForStableJson = (value) => {
|
|
354
369
|
if (Array.isArray(value)) {
|
|
355
370
|
return value.map(normalizeForStableJson);
|
|
@@ -464,6 +479,7 @@ var resolveGateFingerprint = async (projectRoot, strategyName, gitSha) => {
|
|
|
464
479
|
`packages/strategies/src/${strategyName}/guardrails.ts`,
|
|
465
480
|
`packages/strategies/src/${strategyName}/pockets.ts`,
|
|
466
481
|
`packages/strategies/src/${strategyName}/config.ts`,
|
|
482
|
+
"packages/strategies/src/shared/localAiGate.ts",
|
|
467
483
|
"packages/node/src/ai.ts"
|
|
468
484
|
];
|
|
469
485
|
const optionalSourceEntries = await Promise.all(
|
|
@@ -532,5 +548,6 @@ var buildAiTrainLineage = async ({
|
|
|
532
548
|
fingerprintResearchValue,
|
|
533
549
|
summarizeAiTrainCoverage,
|
|
534
550
|
summarizeAiTrainRejectReasons,
|
|
535
|
-
summarizeAiTrainTerminalWindows
|
|
551
|
+
summarizeAiTrainTerminalWindows,
|
|
552
|
+
writeAiTrainResearchSnapshot
|
|
536
553
|
});
|
|
@@ -1637,6 +1637,7 @@ var require_list_it = __commonJS({
|
|
|
1637
1637
|
var marketContextPrepare_exports = {};
|
|
1638
1638
|
__export(marketContextPrepare_exports, {
|
|
1639
1639
|
prepareMarketContextForRun: () => prepareMarketContextForRun,
|
|
1640
|
+
resolveMarketContextRunRequirements: () => resolveMarketContextRunRequirements,
|
|
1640
1641
|
shouldPrepareBinanceMarketContextForRun: () => shouldPrepareBinanceMarketContextForRun,
|
|
1641
1642
|
shouldPrepareCoinMarketCapContextForRun: () => shouldPrepareCoinMarketCapContextForRun,
|
|
1642
1643
|
shouldPrepareDerivativesContextForRun: () => shouldPrepareDerivativesContextForRun,
|
|
@@ -1644,6 +1645,8 @@ __export(marketContextPrepare_exports, {
|
|
|
1644
1645
|
});
|
|
1645
1646
|
module.exports = __toCommonJS(marketContextPrepare_exports);
|
|
1646
1647
|
var import_chalk4 = __toESM(require("chalk"));
|
|
1648
|
+
var import_timescale5 = require("@tradejs/infra/timescale");
|
|
1649
|
+
var import_registry = require("@tradejs/node/registry");
|
|
1647
1650
|
|
|
1648
1651
|
// src/lib/binanceMarketContextBackfill.ts
|
|
1649
1652
|
var import_progress = __toESM(require("progress"));
|
|
@@ -4904,6 +4907,9 @@ var backfillHyperliquidWhaleContext = async (params) => {
|
|
|
4904
4907
|
};
|
|
4905
4908
|
|
|
4906
4909
|
// src/lib/marketContextPrepare.ts
|
|
4910
|
+
var uniqueReasons = (reasons) => [
|
|
4911
|
+
...new Set(reasons)
|
|
4912
|
+
];
|
|
4907
4913
|
var shouldPrepareDerivativesContextForRun = (params) => {
|
|
4908
4914
|
if (params.universe === "tradfi") return false;
|
|
4909
4915
|
if (params.mode === "signals") {
|
|
@@ -4911,6 +4917,9 @@ var shouldPrepareDerivativesContextForRun = (params) => {
|
|
|
4911
4917
|
cacheOnly: params.cacheOnly
|
|
4912
4918
|
});
|
|
4913
4919
|
}
|
|
4920
|
+
if (params.mode === "backtest" && !params.aiEnabled && !params.mlEnabled) {
|
|
4921
|
+
return false;
|
|
4922
|
+
}
|
|
4914
4923
|
return shouldBackfillDerivativesContextForBacktest({
|
|
4915
4924
|
aiEnabled: Boolean(params.aiEnabled),
|
|
4916
4925
|
cacheOnly: params.cacheOnly,
|
|
@@ -4920,6 +4929,7 @@ var shouldPrepareDerivativesContextForRun = (params) => {
|
|
|
4920
4929
|
var shouldPrepareBinanceMarketContextForRun = (params) => {
|
|
4921
4930
|
if (params.universe === "tradfi") return false;
|
|
4922
4931
|
if (params.mode === "backtest") {
|
|
4932
|
+
if (!params.aiEnabled && !params.mlEnabled) return false;
|
|
4923
4933
|
return shouldBackfillBinanceMarketContextForBacktest({
|
|
4924
4934
|
aiEnabled: Boolean(params.aiEnabled),
|
|
4925
4935
|
cacheOnly: params.cacheOnly,
|
|
@@ -4938,6 +4948,7 @@ var shouldPrepareBinanceMarketContextForRun = (params) => {
|
|
|
4938
4948
|
var shouldPrepareCoinMarketCapContextForRun = (params) => {
|
|
4939
4949
|
if (params.universe === "tradfi") return false;
|
|
4940
4950
|
if (params.mode === "backtest") {
|
|
4951
|
+
if (!params.aiEnabled && !params.mlEnabled) return false;
|
|
4941
4952
|
return shouldBackfillCoinMarketCapContextForBacktest({
|
|
4942
4953
|
aiEnabled: Boolean(params.aiEnabled),
|
|
4943
4954
|
cacheOnly: params.cacheOnly,
|
|
@@ -4953,10 +4964,8 @@ var shouldPrepareCoinMarketCapContextForRun = (params) => {
|
|
|
4953
4964
|
cacheOnly: params.cacheOnly
|
|
4954
4965
|
});
|
|
4955
4966
|
};
|
|
4956
|
-
var shouldPrepareHyperliquidWhaleContextForRun = (params) => {
|
|
4957
|
-
const strategyRequiresContext =
|
|
4958
|
-
"HyperliquidConsensus"
|
|
4959
|
-
);
|
|
4967
|
+
var shouldPrepareHyperliquidWhaleContextForRun = (params, coreContextSources = []) => {
|
|
4968
|
+
const strategyRequiresContext = coreContextSources.includes("hyperliquidWhales");
|
|
4960
4969
|
if (params.universe === "tradfi" || params.mode === "signals" || params.cacheOnly || !params.aiEnabled && !params.mlEnabled && !strategyRequiresContext) {
|
|
4961
4970
|
return false;
|
|
4962
4971
|
}
|
|
@@ -4967,6 +4976,64 @@ var shouldPrepareHyperliquidWhaleContextForRun = (params) => {
|
|
|
4967
4976
|
if (strategyRequiresContext) return true;
|
|
4968
4977
|
return ["1", "true", "yes", "on"].includes(configured);
|
|
4969
4978
|
};
|
|
4979
|
+
var resolveCoreContextSources = async (params) => {
|
|
4980
|
+
const strategyNames = [...new Set(params.strategyNames ?? [])];
|
|
4981
|
+
if (!strategyNames.length) return [];
|
|
4982
|
+
await (0, import_registry.ensureStrategyPluginsLoaded)(params.projectRoot);
|
|
4983
|
+
return [
|
|
4984
|
+
...new Set(
|
|
4985
|
+
strategyNames.flatMap(
|
|
4986
|
+
(strategyName) => (0, import_registry.getStrategyManifest)(strategyName, params.projectRoot)?.contextRequirements?.core ?? []
|
|
4987
|
+
)
|
|
4988
|
+
)
|
|
4989
|
+
];
|
|
4990
|
+
};
|
|
4991
|
+
var resolveMarketContextRunRequirements = async (params) => {
|
|
4992
|
+
const coreContextSources = await resolveCoreContextSources(params);
|
|
4993
|
+
const paramsWithCoreDemand = (source) => coreContextSources.includes(source) ? { ...params, aiEnabled: true } : params;
|
|
4994
|
+
const isCrypto = params.universe !== "tradfi";
|
|
4995
|
+
const capturesPayload = Boolean(params.aiEnabled || params.mlEnabled);
|
|
4996
|
+
const runtimeReadsContext = params.mode !== "backtest";
|
|
4997
|
+
const reasonsFor = (source) => uniqueReasons([
|
|
4998
|
+
...coreContextSources.includes(source) ? ["core"] : [],
|
|
4999
|
+
...params.aiEnabled ? ["ai"] : [],
|
|
5000
|
+
...params.mlEnabled ? ["ml"] : [],
|
|
5001
|
+
...runtimeReadsContext ? ["runtime"] : []
|
|
5002
|
+
]);
|
|
5003
|
+
const readsStandardContext = isCrypto && (capturesPayload || runtimeReadsContext);
|
|
5004
|
+
const readsHyperliquid = isCrypto && (readsStandardContext || coreContextSources.includes("hyperliquidWhales"));
|
|
5005
|
+
return {
|
|
5006
|
+
binance: {
|
|
5007
|
+
read: readsStandardContext || coreContextSources.includes("binance"),
|
|
5008
|
+
backfill: shouldPrepareBinanceMarketContextForRun(
|
|
5009
|
+
paramsWithCoreDemand("binance")
|
|
5010
|
+
),
|
|
5011
|
+
requiredBy: reasonsFor("binance")
|
|
5012
|
+
},
|
|
5013
|
+
coinmarketcap: {
|
|
5014
|
+
read: readsStandardContext || coreContextSources.includes("coinmarketcap"),
|
|
5015
|
+
backfill: shouldPrepareCoinMarketCapContextForRun(
|
|
5016
|
+
paramsWithCoreDemand("coinmarketcap")
|
|
5017
|
+
),
|
|
5018
|
+
requiredBy: reasonsFor("coinmarketcap")
|
|
5019
|
+
},
|
|
5020
|
+
derivatives: {
|
|
5021
|
+
read: readsStandardContext || coreContextSources.includes("derivatives"),
|
|
5022
|
+
backfill: shouldPrepareDerivativesContextForRun(
|
|
5023
|
+
paramsWithCoreDemand("derivatives")
|
|
5024
|
+
),
|
|
5025
|
+
requiredBy: reasonsFor("derivatives")
|
|
5026
|
+
},
|
|
5027
|
+
hyperliquidWhales: {
|
|
5028
|
+
read: readsHyperliquid,
|
|
5029
|
+
backfill: shouldPrepareHyperliquidWhaleContextForRun(
|
|
5030
|
+
params,
|
|
5031
|
+
coreContextSources
|
|
5032
|
+
),
|
|
5033
|
+
requiredBy: reasonsFor("hyperliquidWhales")
|
|
5034
|
+
}
|
|
5035
|
+
};
|
|
5036
|
+
};
|
|
4970
5037
|
var resolveCoinMarketCapBackfillForMode = (mode) => mode === "backtest" ? backfillCoinMarketCapContextForBacktest : mode === "signals" ? backfillCoinMarketCapContextForSignals : backfillCoinMarketCapContextForReplay;
|
|
4971
5038
|
var buildCoinMarketCapBackfillParams = (params) => ({
|
|
4972
5039
|
userName: params.userName,
|
|
@@ -4995,7 +5062,15 @@ var prepareMarketContextForRun = async (params) => {
|
|
|
4995
5062
|
console.log(import_chalk4.default.gray(message));
|
|
4996
5063
|
});
|
|
4997
5064
|
const timeOperation2 = (label, operation) => timeOperation(label, operation, log);
|
|
4998
|
-
|
|
5065
|
+
const requirements = await resolveMarketContextRunRequirements(params);
|
|
5066
|
+
const readableSources = Object.entries(requirements).filter(([, requirement]) => requirement.read).map(([source]) => source);
|
|
5067
|
+
if (readableSources.length) {
|
|
5068
|
+
await timeOperation2(
|
|
5069
|
+
"market context schema ensure",
|
|
5070
|
+
() => (0, import_timescale5.ensureMarketContextSchemas)(readableSources)
|
|
5071
|
+
);
|
|
5072
|
+
}
|
|
5073
|
+
if (requirements.derivatives.backfill) {
|
|
4999
5074
|
await timeOperation2(
|
|
5000
5075
|
"derivatives context backfill",
|
|
5001
5076
|
() => (params.mode === "signals" ? backfillDerivativesContextForSignals : backfillDerivativesContextForBacktest)(
|
|
@@ -5003,7 +5078,7 @@ var prepareMarketContextForRun = async (params) => {
|
|
|
5003
5078
|
)
|
|
5004
5079
|
);
|
|
5005
5080
|
}
|
|
5006
|
-
if (
|
|
5081
|
+
if (requirements.hyperliquidWhales.backfill) {
|
|
5007
5082
|
await timeOperation2(
|
|
5008
5083
|
"hyperliquid whale context backfill",
|
|
5009
5084
|
() => backfillHyperliquidWhaleContext({
|
|
@@ -5015,13 +5090,13 @@ var prepareMarketContextForRun = async (params) => {
|
|
|
5015
5090
|
})
|
|
5016
5091
|
);
|
|
5017
5092
|
}
|
|
5018
|
-
if (
|
|
5093
|
+
if (requirements.binance.backfill) {
|
|
5019
5094
|
await timeOperation2("binance market context backfill", () => {
|
|
5020
5095
|
const backfill = params.mode === "backtest" ? backfillBinanceMarketContextForBacktest : params.mode === "signals" ? backfillBinanceMarketContextForSignals : backfillBinanceMarketContextForReplay;
|
|
5021
5096
|
return backfill(buildBinanceMarketBackfillParams(params));
|
|
5022
5097
|
});
|
|
5023
5098
|
}
|
|
5024
|
-
if (
|
|
5099
|
+
if (requirements.coinmarketcap.backfill) {
|
|
5025
5100
|
await timeOperation2(
|
|
5026
5101
|
"coinmarketcap historical context backfill",
|
|
5027
5102
|
() => resolveCoinMarketCapBackfillForMode(params.mode)(
|
|
@@ -5029,10 +5104,12 @@ var prepareMarketContextForRun = async (params) => {
|
|
|
5029
5104
|
)
|
|
5030
5105
|
);
|
|
5031
5106
|
}
|
|
5107
|
+
return requirements;
|
|
5032
5108
|
};
|
|
5033
5109
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5034
5110
|
0 && (module.exports = {
|
|
5035
5111
|
prepareMarketContextForRun,
|
|
5112
|
+
resolveMarketContextRunRequirements,
|
|
5036
5113
|
shouldPrepareBinanceMarketContextForRun,
|
|
5037
5114
|
shouldPrepareCoinMarketCapContextForRun,
|
|
5038
5115
|
shouldPrepareDerivativesContextForRun,
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// src/lib/researchAgent.ts
|
|
@@ -39,24 +29,14 @@ __export(researchAgent_exports, {
|
|
|
39
29
|
buildResearchAgentPrBody: () => buildResearchAgentPrBody,
|
|
40
30
|
buildResearchAgentPrTitle: () => buildResearchAgentPrTitle,
|
|
41
31
|
getResearchAgentAllowedPathPrefixes: () => getResearchAgentAllowedPathPrefixes,
|
|
42
|
-
getResearchAgentNotePath: () => getResearchAgentNotePath,
|
|
43
32
|
normalizeDiffOutput: () => normalizeDiffOutput,
|
|
44
33
|
parseChangedFilesFromDiff: () => parseChangedFilesFromDiff,
|
|
45
|
-
parseGithubRepositoryFromRemote: () => parseGithubRepositoryFromRemote
|
|
46
|
-
toUpperSnakeCase: () => toUpperSnakeCase
|
|
34
|
+
parseGithubRepositoryFromRemote: () => parseGithubRepositoryFromRemote
|
|
47
35
|
});
|
|
48
36
|
module.exports = __toCommonJS(researchAgent_exports);
|
|
49
|
-
var import_node_path = __toESM(require("path"));
|
|
50
37
|
var RESEARCH_AGENT_MODEL = "openai/gpt-5.4";
|
|
51
38
|
var RESEARCH_AGENT_REASONING_EFFORT = "medium";
|
|
52
39
|
var RESEARCH_AGENT_BRANCH_PREFIX = "codex/research";
|
|
53
|
-
var toUpperSnakeCase = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
54
|
-
var RESEARCH_NOTE_FILE_OVERRIDES = {
|
|
55
|
-
TrendLine: "AI_TRENDLINE_REPLAY_NOTES.md",
|
|
56
|
-
ReverseTrendLine: "AI_REVERSE_TRENDLINE_REPLAY_NOTES.md",
|
|
57
|
-
AdaptiveMomentumRibbon: "AI_ADAPTIVE_MOMENTUM_RIBBON_REPLAY_NOTES.md",
|
|
58
|
-
VolumeDivergence: "AI_VOLUME_DIVERGENCE_REPLAY_NOTES.md"
|
|
59
|
-
};
|
|
60
40
|
var buildResearchAgentBranchName = (strategy, runId) => {
|
|
61
41
|
const normalizedStrategy = strategy.trim().replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[^a-zA-Z0-9-]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
|
|
62
42
|
const normalizedRunId = runId.trim().replace(/[^a-zA-Z0-9-]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
|
|
@@ -64,13 +44,8 @@ var buildResearchAgentBranchName = (strategy, runId) => {
|
|
|
64
44
|
};
|
|
65
45
|
var buildResearchAgentCommitMessage = (strategy, runId) => `Research agent: ${strategy} follow-up for ${runId}`;
|
|
66
46
|
var buildResearchAgentPrTitle = (strategy, runId) => `Research agent: ${strategy} follow-up for ${runId}`;
|
|
67
|
-
var getResearchAgentNotePath = (strategy) => import_node_path.default.join(
|
|
68
|
-
"notes",
|
|
69
|
-
RESEARCH_NOTE_FILE_OVERRIDES[strategy] || `AI_${toUpperSnakeCase(strategy)}_REPLAY_NOTES.md`
|
|
70
|
-
);
|
|
71
47
|
var getResearchAgentAllowedPathPrefixes = (strategy) => [
|
|
72
|
-
`packages/strategies/src/${strategy}
|
|
73
|
-
getResearchAgentNotePath(strategy)
|
|
48
|
+
`packages/strategies/src/${strategy}/`
|
|
74
49
|
];
|
|
75
50
|
var parseGithubRepositoryFromRemote = (value) => {
|
|
76
51
|
const trimmed = value.trim();
|
|
@@ -187,9 +162,7 @@ ${diffText}`)) {
|
|
|
187
162
|
buildResearchAgentPrBody,
|
|
188
163
|
buildResearchAgentPrTitle,
|
|
189
164
|
getResearchAgentAllowedPathPrefixes,
|
|
190
|
-
getResearchAgentNotePath,
|
|
191
165
|
normalizeDiffOutput,
|
|
192
166
|
parseChangedFilesFromDiff,
|
|
193
|
-
parseGithubRepositoryFromRemote
|
|
194
|
-
toUpperSnakeCase
|
|
167
|
+
parseGithubRepositoryFromRemote
|
|
195
168
|
});
|
|
@@ -25,6 +25,7 @@ __export(runtimeDebugEvidence_exports, {
|
|
|
25
25
|
buildRuntimeDebugEvaluationId: () => buildRuntimeDebugEvaluationId,
|
|
26
26
|
buildRuntimeDebugReportAttachment: () => buildRuntimeDebugReportAttachment,
|
|
27
27
|
buildRuntimeDebugReportPayload: () => buildRuntimeDebugReportPayload,
|
|
28
|
+
buildRuntimeEvidenceReportPayload: () => buildRuntimeEvidenceReportPayload,
|
|
28
29
|
collectRuntimeDebugEvidence: () => collectRuntimeDebugEvidence
|
|
29
30
|
});
|
|
30
31
|
module.exports = __toCommonJS(runtimeDebugEvidence_exports);
|
|
@@ -122,6 +123,29 @@ var loadRuntimeTrades = async (userName, {
|
|
|
122
123
|
const trades = await Promise.all(keys.map((key) => (0, import_redis.getData)(key, null)));
|
|
123
124
|
return trades.filter(isRuntimeTradeRecord).filter(filterByWindow).sort((left, right) => left.entryTimestamp - right.entryTimestamp);
|
|
124
125
|
};
|
|
126
|
+
var loadRuntimeClosedTrades = async (userName, {
|
|
127
|
+
startTime,
|
|
128
|
+
endTime
|
|
129
|
+
}) => {
|
|
130
|
+
const dayKeys = (0, import_time.getRuntimeStorageDayKeys)(startTime, endTime);
|
|
131
|
+
const trades = (await Promise.all(
|
|
132
|
+
dayKeys.map(
|
|
133
|
+
(dayKey) => (0, import_redis.getHashJsonValues)(
|
|
134
|
+
import_redis.redisKeys.runtimeClosedTradeBucket(userName, dayKey)
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
)).flat();
|
|
138
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
139
|
+
for (const trade of trades) {
|
|
140
|
+
if (!isRuntimeTradeRecord(trade) || trade.status !== "closed" || !Number.isFinite(trade.exitTimestamp) || trade.exitTimestamp < startTime || trade.exitTimestamp >= endTime) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
deduped.set(trade.orderId, trade);
|
|
144
|
+
}
|
|
145
|
+
return [...deduped.values()].sort(
|
|
146
|
+
(left, right) => left.exitTimestamp - right.exitTimestamp
|
|
147
|
+
);
|
|
148
|
+
};
|
|
125
149
|
|
|
126
150
|
// src/lib/runtimeSignalsLoader.ts
|
|
127
151
|
var import_redis2 = require("@tradejs/infra/redis");
|
|
@@ -319,13 +343,30 @@ var collectRuntimeDebugEvidence = async ({
|
|
|
319
343
|
}) => {
|
|
320
344
|
const dayKeys = (0, import_time2.getRuntimeStorageDayKeys)(startTime, endTime);
|
|
321
345
|
const dayKeySet = new Set(dayKeys);
|
|
322
|
-
const [
|
|
346
|
+
const [
|
|
347
|
+
entryTrades,
|
|
348
|
+
closedTrades,
|
|
349
|
+
signals,
|
|
350
|
+
evaluations,
|
|
351
|
+
evaluationStatsBuckets,
|
|
352
|
+
configs
|
|
353
|
+
] = await Promise.all([
|
|
323
354
|
loadRuntimeTrades(userName, { startTime, endTime }),
|
|
355
|
+
loadRuntimeClosedTrades(userName, { startTime, endTime }),
|
|
324
356
|
loadRuntimeSignals(userName, { startTime, endTime }),
|
|
325
357
|
loadRuntimeSignalEvaluations(userName, { startTime, endTime }),
|
|
326
358
|
loadRuntimeSignalEvaluationStatsBuckets(userName),
|
|
327
359
|
loadRuntimeStrategyConfigs(userName)
|
|
328
360
|
]);
|
|
361
|
+
const tradesByOrderId = new Map(
|
|
362
|
+
entryTrades.map((trade) => [trade.orderId, trade])
|
|
363
|
+
);
|
|
364
|
+
for (const trade of closedTrades) {
|
|
365
|
+
tradesByOrderId.set(trade.orderId, trade);
|
|
366
|
+
}
|
|
367
|
+
const trades = [...tradesByOrderId.values()].sort(
|
|
368
|
+
(left, right) => left.entryTimestamp - right.entryTimestamp
|
|
369
|
+
);
|
|
329
370
|
const filteredStats = evaluationStatsBuckets.filter(
|
|
330
371
|
(entry) => dayKeySet.has(entry.dayKey) && (!strategies?.length || strategies.includes(entry.strategy))
|
|
331
372
|
);
|
|
@@ -502,6 +543,39 @@ var buildRuntimeDebugReportPayload = async ({
|
|
|
502
543
|
strategyConfigs: strategyConfigs ?? []
|
|
503
544
|
};
|
|
504
545
|
};
|
|
546
|
+
var buildRuntimeEvidenceReportPayload = ({
|
|
547
|
+
userName,
|
|
548
|
+
startTime,
|
|
549
|
+
endTime,
|
|
550
|
+
signals,
|
|
551
|
+
evaluations,
|
|
552
|
+
trades,
|
|
553
|
+
strategyConfigs,
|
|
554
|
+
evaluationStatsBuckets
|
|
555
|
+
}) => ({
|
|
556
|
+
reportType: "runtime-daily-evidence",
|
|
557
|
+
generatedAt: Date.now(),
|
|
558
|
+
userName,
|
|
559
|
+
window: {
|
|
560
|
+
startTime,
|
|
561
|
+
endTime,
|
|
562
|
+
startMsk: formatRuntimeDebugDateTime(startTime),
|
|
563
|
+
endMsk: formatRuntimeDebugDateTime(endTime),
|
|
564
|
+
dayKeys: (0, import_time2.getRuntimeStorageDayKeys)(startTime, endTime)
|
|
565
|
+
},
|
|
566
|
+
counts: {
|
|
567
|
+
trades: trades.length,
|
|
568
|
+
signals: signals.length,
|
|
569
|
+
evaluations: evaluations.length,
|
|
570
|
+
evaluationStatsBuckets: evaluationStatsBuckets?.length ?? 0,
|
|
571
|
+
strategyConfigs: strategyConfigs?.length ?? 0
|
|
572
|
+
},
|
|
573
|
+
trades: trades.map((trade) => ({ trade })),
|
|
574
|
+
signals: signals.map((signal) => ({ signal })),
|
|
575
|
+
evaluations: evaluations.map((evaluation) => ({ evaluation })),
|
|
576
|
+
evaluationStatsBuckets: evaluationStatsBuckets ?? [],
|
|
577
|
+
strategyConfigs: strategyConfigs ?? []
|
|
578
|
+
});
|
|
505
579
|
var buildRuntimeDebugReportAttachment = async (params) => {
|
|
506
580
|
const payload = await buildRuntimeDebugReportPayload(params);
|
|
507
581
|
const dayKey = formatRuntimeDebugIsoDayKey(params.endTime);
|
|
@@ -523,5 +597,6 @@ var buildRuntimeDebugReportAttachment = async (params) => {
|
|
|
523
597
|
buildRuntimeDebugEvaluationId,
|
|
524
598
|
buildRuntimeDebugReportAttachment,
|
|
525
599
|
buildRuntimeDebugReportPayload,
|
|
600
|
+
buildRuntimeEvidenceReportPayload,
|
|
526
601
|
collectRuntimeDebugEvidence
|
|
527
602
|
});
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/lib/runtimeEvidenceArtifacts.ts
|
|
31
|
+
var runtimeEvidenceArtifacts_exports = {};
|
|
32
|
+
__export(runtimeEvidenceArtifacts_exports, {
|
|
33
|
+
RUNTIME_EVIDENCE_COMPLETE_FILE: () => RUNTIME_EVIDENCE_COMPLETE_FILE,
|
|
34
|
+
RUNTIME_EVIDENCE_MANIFEST_FILE: () => RUNTIME_EVIDENCE_MANIFEST_FILE,
|
|
35
|
+
RUNTIME_EVIDENCE_PAYLOAD_FILE: () => RUNTIME_EVIDENCE_PAYLOAD_FILE,
|
|
36
|
+
discoverRuntimeEvidenceBundles: () => discoverRuntimeEvidenceBundles,
|
|
37
|
+
publishRuntimeEvidenceBundle: () => publishRuntimeEvidenceBundle,
|
|
38
|
+
verifyRuntimeEvidenceBundle: () => verifyRuntimeEvidenceBundle
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(runtimeEvidenceArtifacts_exports);
|
|
41
|
+
var import_node_crypto = require("crypto");
|
|
42
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
43
|
+
var import_node_path = __toESM(require("path"));
|
|
44
|
+
var RUNTIME_EVIDENCE_MANIFEST_FILE = "manifest.json";
|
|
45
|
+
var RUNTIME_EVIDENCE_PAYLOAD_FILE = "runtime-evidence.json";
|
|
46
|
+
var RUNTIME_EVIDENCE_COMPLETE_FILE = ".complete";
|
|
47
|
+
var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
48
|
+
var sha256 = (value) => (0, import_node_crypto.createHash)("sha256").update(value).digest("hex");
|
|
49
|
+
var isExistingDestinationError = (error) => {
|
|
50
|
+
const code = error.code;
|
|
51
|
+
return code === "EEXIST" || code === "ENOTEMPTY";
|
|
52
|
+
};
|
|
53
|
+
var safeSegment = (value, fallback) => {
|
|
54
|
+
const normalized = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
55
|
+
return normalized && normalized !== "." && normalized !== ".." ? normalized : fallback;
|
|
56
|
+
};
|
|
57
|
+
var compactTimestamp = (timestamp) => new Date(timestamp).toISOString().replace(/[-:]/g, "").replace(/\.000Z$/, "Z");
|
|
58
|
+
var dateParts = (timestamp) => {
|
|
59
|
+
const date = new Date(timestamp);
|
|
60
|
+
return [
|
|
61
|
+
String(date.getUTCFullYear()),
|
|
62
|
+
String(date.getUTCMonth() + 1).padStart(2, "0"),
|
|
63
|
+
String(date.getUTCDate()).padStart(2, "0")
|
|
64
|
+
];
|
|
65
|
+
};
|
|
66
|
+
var assertFiniteTimestamp = (value, label) => {
|
|
67
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
68
|
+
throw new Error(`Invalid runtime evidence ${label}`);
|
|
69
|
+
}
|
|
70
|
+
return value;
|
|
71
|
+
};
|
|
72
|
+
var parseManifest = (value) => {
|
|
73
|
+
const manifest = asRecord(value);
|
|
74
|
+
const window = asRecord(manifest?.window);
|
|
75
|
+
const payload = asRecord(manifest?.payload);
|
|
76
|
+
const counts = asRecord(manifest?.counts);
|
|
77
|
+
if (manifest?.schemaVersion !== 1 || manifest.reportType !== "runtime-evidence" || typeof manifest.artifactId !== "string" || typeof manifest.deploymentId !== "string" || typeof manifest.userName !== "string" || typeof manifest.createdAt !== "number" || payload?.file !== RUNTIME_EVIDENCE_PAYLOAD_FILE || typeof payload.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(payload.sha256) || typeof payload.bytes !== "number" || !Array.isArray(manifest.lineageKeys)) {
|
|
78
|
+
throw new Error("Invalid runtime evidence manifest");
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
schemaVersion: 1,
|
|
82
|
+
artifactId: manifest.artifactId,
|
|
83
|
+
reportType: "runtime-evidence",
|
|
84
|
+
deploymentId: manifest.deploymentId,
|
|
85
|
+
userName: manifest.userName,
|
|
86
|
+
createdAt: manifest.createdAt,
|
|
87
|
+
window: {
|
|
88
|
+
startTime: assertFiniteTimestamp(window?.startTime, "window.startTime"),
|
|
89
|
+
endTime: assertFiniteTimestamp(window?.endTime, "window.endTime")
|
|
90
|
+
},
|
|
91
|
+
payload: {
|
|
92
|
+
file: RUNTIME_EVIDENCE_PAYLOAD_FILE,
|
|
93
|
+
sha256: payload.sha256,
|
|
94
|
+
bytes: payload.bytes
|
|
95
|
+
},
|
|
96
|
+
counts: Object.fromEntries(
|
|
97
|
+
Object.entries(counts ?? {}).filter(
|
|
98
|
+
(entry) => typeof entry[1] === "number" && Number.isFinite(entry[1])
|
|
99
|
+
)
|
|
100
|
+
),
|
|
101
|
+
lineageKeys: manifest.lineageKeys.filter(
|
|
102
|
+
(value2) => typeof value2 === "string" && value2.length > 0
|
|
103
|
+
)
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
var publishRuntimeEvidenceBundle = async ({
|
|
107
|
+
publishRoot,
|
|
108
|
+
deploymentId,
|
|
109
|
+
userName,
|
|
110
|
+
startTime,
|
|
111
|
+
endTime,
|
|
112
|
+
artifact,
|
|
113
|
+
counts,
|
|
114
|
+
lineageKeys
|
|
115
|
+
}) => {
|
|
116
|
+
const payload = `${JSON.stringify(artifact, null, 2)}
|
|
117
|
+
`;
|
|
118
|
+
const payloadSha256 = sha256(payload);
|
|
119
|
+
const safeDeploymentId = safeSegment(deploymentId, "default");
|
|
120
|
+
const artifactId = [
|
|
121
|
+
compactTimestamp(startTime),
|
|
122
|
+
compactTimestamp(endTime),
|
|
123
|
+
payloadSha256.slice(0, 16)
|
|
124
|
+
].join("_");
|
|
125
|
+
const createdAt = Date.now();
|
|
126
|
+
const manifest = {
|
|
127
|
+
schemaVersion: 1,
|
|
128
|
+
artifactId,
|
|
129
|
+
reportType: "runtime-evidence",
|
|
130
|
+
deploymentId: safeDeploymentId,
|
|
131
|
+
userName,
|
|
132
|
+
createdAt,
|
|
133
|
+
window: { startTime, endTime },
|
|
134
|
+
payload: {
|
|
135
|
+
file: RUNTIME_EVIDENCE_PAYLOAD_FILE,
|
|
136
|
+
sha256: payloadSha256,
|
|
137
|
+
bytes: Buffer.byteLength(payload)
|
|
138
|
+
},
|
|
139
|
+
counts,
|
|
140
|
+
lineageKeys: [...new Set(lineageKeys)].sort()
|
|
141
|
+
};
|
|
142
|
+
const incomingRoot = import_node_path.default.join(publishRoot, "incoming");
|
|
143
|
+
const readyRoot = import_node_path.default.join(
|
|
144
|
+
publishRoot,
|
|
145
|
+
"ready",
|
|
146
|
+
safeDeploymentId,
|
|
147
|
+
...dateParts(endTime)
|
|
148
|
+
);
|
|
149
|
+
const bundleDir = import_node_path.default.join(readyRoot, artifactId);
|
|
150
|
+
const temporaryDir = import_node_path.default.join(
|
|
151
|
+
incomingRoot,
|
|
152
|
+
`${artifactId}.tmp-${(0, import_node_crypto.randomUUID)()}`
|
|
153
|
+
);
|
|
154
|
+
await import_promises.default.mkdir(temporaryDir, { recursive: true });
|
|
155
|
+
try {
|
|
156
|
+
await Promise.all([
|
|
157
|
+
import_promises.default.writeFile(
|
|
158
|
+
import_node_path.default.join(temporaryDir, RUNTIME_EVIDENCE_PAYLOAD_FILE),
|
|
159
|
+
payload,
|
|
160
|
+
"utf8"
|
|
161
|
+
),
|
|
162
|
+
import_promises.default.writeFile(
|
|
163
|
+
import_node_path.default.join(temporaryDir, RUNTIME_EVIDENCE_MANIFEST_FILE),
|
|
164
|
+
`${JSON.stringify(manifest, null, 2)}
|
|
165
|
+
`,
|
|
166
|
+
"utf8"
|
|
167
|
+
)
|
|
168
|
+
]);
|
|
169
|
+
await import_promises.default.writeFile(
|
|
170
|
+
import_node_path.default.join(temporaryDir, RUNTIME_EVIDENCE_COMPLETE_FILE),
|
|
171
|
+
`${artifactId}
|
|
172
|
+
`,
|
|
173
|
+
"utf8"
|
|
174
|
+
);
|
|
175
|
+
await import_promises.default.mkdir(readyRoot, { recursive: true });
|
|
176
|
+
try {
|
|
177
|
+
await import_promises.default.rename(temporaryDir, bundleDir);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
if (!isExistingDestinationError(error)) {
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
await import_promises.default.rm(temporaryDir, { recursive: true, force: true });
|
|
183
|
+
}
|
|
184
|
+
} catch (error) {
|
|
185
|
+
await import_promises.default.rm(temporaryDir, { recursive: true, force: true });
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
return verifyRuntimeEvidenceBundle(bundleDir);
|
|
189
|
+
};
|
|
190
|
+
var verifyRuntimeEvidenceBundle = async (bundleDir) => {
|
|
191
|
+
const manifestPath = import_node_path.default.join(bundleDir, RUNTIME_EVIDENCE_MANIFEST_FILE);
|
|
192
|
+
const payloadPath = import_node_path.default.join(bundleDir, RUNTIME_EVIDENCE_PAYLOAD_FILE);
|
|
193
|
+
const completePath = import_node_path.default.join(bundleDir, RUNTIME_EVIDENCE_COMPLETE_FILE);
|
|
194
|
+
const [manifestText, payload, completeText] = await Promise.all([
|
|
195
|
+
import_promises.default.readFile(manifestPath, "utf8"),
|
|
196
|
+
import_promises.default.readFile(payloadPath),
|
|
197
|
+
import_promises.default.readFile(completePath, "utf8")
|
|
198
|
+
]);
|
|
199
|
+
const manifest = parseManifest(JSON.parse(manifestText));
|
|
200
|
+
if (completeText.trim() !== manifest.artifactId) {
|
|
201
|
+
throw new Error(`Invalid completion marker in ${bundleDir}`);
|
|
202
|
+
}
|
|
203
|
+
if (payload.byteLength !== manifest.payload.bytes) {
|
|
204
|
+
throw new Error(`Runtime evidence size mismatch in ${bundleDir}`);
|
|
205
|
+
}
|
|
206
|
+
if (sha256(payload) !== manifest.payload.sha256) {
|
|
207
|
+
throw new Error(`Runtime evidence checksum mismatch in ${bundleDir}`);
|
|
208
|
+
}
|
|
209
|
+
const artifact = asRecord(JSON.parse(payload.toString("utf8")));
|
|
210
|
+
const artifactWindow = asRecord(artifact?.window);
|
|
211
|
+
if (artifact?.reportType !== "runtime-evidence" || artifactWindow?.startTime !== manifest.window.startTime || artifactWindow.endTime !== manifest.window.endTime) {
|
|
212
|
+
throw new Error(`Runtime evidence payload mismatch in ${bundleDir}`);
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
bundleDir,
|
|
216
|
+
manifestPath,
|
|
217
|
+
payloadPath,
|
|
218
|
+
manifest,
|
|
219
|
+
artifact
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
var discoverRuntimeEvidenceBundles = async (rootDir) => {
|
|
223
|
+
const bundles = [];
|
|
224
|
+
const visit = async (directory, depth) => {
|
|
225
|
+
if (depth > 8) return;
|
|
226
|
+
let entries;
|
|
227
|
+
try {
|
|
228
|
+
entries = await import_promises.default.readdir(directory, { withFileTypes: true });
|
|
229
|
+
} catch (error) {
|
|
230
|
+
if (error.code === "ENOENT") return;
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
const names = new Set(entries.map((entry) => entry.name));
|
|
234
|
+
if (names.has(RUNTIME_EVIDENCE_MANIFEST_FILE) && names.has(RUNTIME_EVIDENCE_PAYLOAD_FILE) && names.has(RUNTIME_EVIDENCE_COMPLETE_FILE)) {
|
|
235
|
+
bundles.push(directory);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
await Promise.all(
|
|
239
|
+
entries.filter(
|
|
240
|
+
(entry) => entry.isDirectory() && !entry.name.startsWith(".") && !entry.name.includes(".tmp-")
|
|
241
|
+
).map((entry) => visit(import_node_path.default.join(directory, entry.name), depth + 1))
|
|
242
|
+
);
|
|
243
|
+
};
|
|
244
|
+
await visit(rootDir, 0);
|
|
245
|
+
return bundles.sort();
|
|
246
|
+
};
|
|
247
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
248
|
+
0 && (module.exports = {
|
|
249
|
+
RUNTIME_EVIDENCE_COMPLETE_FILE,
|
|
250
|
+
RUNTIME_EVIDENCE_MANIFEST_FILE,
|
|
251
|
+
RUNTIME_EVIDENCE_PAYLOAD_FILE,
|
|
252
|
+
discoverRuntimeEvidenceBundles,
|
|
253
|
+
publishRuntimeEvidenceBundle,
|
|
254
|
+
verifyRuntimeEvidenceBundle
|
|
255
|
+
});
|