@tradejs/cli 3.1.29-beta.289 → 3.1.29-beta.291
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 +2574 -1236
- package/dist/lib/aiPocketSearch.js +37 -3
- package/dist/lib/aiTrainDataset.js +1 -0
- package/dist/lib/aiTrainEvaluationDump.js +7 -2
- package/dist/lib/aiTrainResearch.js +11 -7
- package/dist/lib/coreResearch.js +12 -4
- package/dist/lib/researchMetricSnapshot.js +74 -0
- package/dist/lib/researchVisuals.js +910 -0
- package/dist/lib/runtimeFeedbackNotification.js +6 -2
- package/dist/lib/runtimeFeedbackReplay.js +44 -29
- package/dist/lib/runtimeParity.js +1 -0
- package/dist/lib/runtimeParityDetails.js +51 -21
- package/dist/lib/strategyRelease.js +8 -2
- package/dist/lib/strategyResearch.js +133 -33
- package/dist/lib/tickerProfiles.js +76 -0
- package/dist/scripts/aiPocketSearch.js +38 -3
- package/dist/scripts/aiTrain.js +29 -17
- package/dist/scripts/coreResearch.js +12 -4
- package/dist/scripts/replay.js +223 -33
- package/dist/scripts/replayRunner.js +223 -33
- package/dist/scripts/researchVisuals.js +955 -0
- package/dist/scripts/runtimeFeedbackNotify.js +11 -3
- package/dist/scripts/runtimeFeedbackReplay.js +44 -29
- package/dist/scripts/runtimeParity.js +1 -0
- package/dist/scripts/signalsSummary.js +5 -6
- package/dist/scripts/strategyRelease.js +59 -7
- package/dist/scripts/strategyResearch.js +136 -36
- package/dist/scripts/tickerProfiles.js +114 -0
- package/package.json +8 -7
|
@@ -25,6 +25,7 @@ __export(runtimeFeedbackNotification_exports, {
|
|
|
25
25
|
notifyRuntimeFeedbackBundle: () => notifyRuntimeFeedbackBundle
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(runtimeFeedbackNotification_exports);
|
|
28
|
+
var import_userSettings = require("@tradejs/infra/userSettings");
|
|
28
29
|
|
|
29
30
|
// src/lib/runtimeFeedbackArtifacts.ts
|
|
30
31
|
var runtimeFeedbackArtifacts_exports = {};
|
|
@@ -210,11 +211,14 @@ var notifyRuntimeFeedbackBundle = async ({
|
|
|
210
211
|
}) => {
|
|
211
212
|
const verified = await (0, runtimeFeedbackArtifacts_exports.verifyRuntimeFeedbackReplayBundle)(bundleDir);
|
|
212
213
|
const message = buildRuntimeFeedbackTelegramMessage(verified.replayEvidence);
|
|
213
|
-
await
|
|
214
|
+
const settings = await (0, import_userSettings.getUserSettings)(verified.manifest.userName);
|
|
215
|
+
const sent = settings.NOTIFY_RUNTIME_DEBUG !== false;
|
|
216
|
+
if (sent) await send(message, { userName: verified.manifest.userName });
|
|
214
217
|
return {
|
|
215
218
|
artifactId: verified.manifest.artifactId,
|
|
216
219
|
userName: verified.manifest.userName,
|
|
217
|
-
message
|
|
220
|
+
message,
|
|
221
|
+
sent
|
|
218
222
|
};
|
|
219
223
|
};
|
|
220
224
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -39,6 +39,7 @@ module.exports = __toCommonJS(runtimeFeedbackReplay_exports);
|
|
|
39
39
|
var import_node_child_process = require("child_process");
|
|
40
40
|
var import_promises = __toESM(require("fs/promises"));
|
|
41
41
|
var import_node_path = __toESM(require("path"));
|
|
42
|
+
var import_mcp = require("@tradejs/node/mcp");
|
|
42
43
|
|
|
43
44
|
// src/lib/runtimeEvidenceDeployment.ts
|
|
44
45
|
var runtimeEvidenceDeployment_exports = {};
|
|
@@ -186,44 +187,58 @@ var runLoggedCommand = async ({
|
|
|
186
187
|
env,
|
|
187
188
|
logHandle
|
|
188
189
|
}) => {
|
|
189
|
-
await logHandle.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
};
|
|
199
|
-
const child = (0, import_node_child_process.spawn)(executable, command, {
|
|
200
|
-
cwd,
|
|
201
|
-
env,
|
|
202
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
203
|
-
});
|
|
204
|
-
child.stdout.on("data", (chunk) => {
|
|
205
|
-
process.stdout.write(chunk);
|
|
206
|
-
appendLog(chunk);
|
|
207
|
-
});
|
|
208
|
-
child.stderr.on("data", (chunk) => {
|
|
209
|
-
process.stderr.write(chunk);
|
|
210
|
-
appendLog(chunk);
|
|
211
|
-
});
|
|
190
|
+
await logHandle.writeFile(
|
|
191
|
+
"\n" + (0, import_mcp.formatMcpArtifactLogLine)(`$ ${[executable, ...command].join(" ")}`)
|
|
192
|
+
);
|
|
193
|
+
const child = (0, import_node_child_process.spawn)(executable, command, {
|
|
194
|
+
cwd,
|
|
195
|
+
env,
|
|
196
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
197
|
+
});
|
|
198
|
+
const exit = new Promise((resolve, reject) => {
|
|
212
199
|
child.once("error", reject);
|
|
213
200
|
child.once("close", (code, signal) => {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
resolve();
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
201
|
+
if (code === 0) resolve();
|
|
202
|
+
else {
|
|
219
203
|
reject(
|
|
220
204
|
new Error(
|
|
221
205
|
`Runtime feedback command failed: exit=${String(code)} signal=${String(signal)}`
|
|
222
206
|
)
|
|
223
207
|
);
|
|
224
|
-
}
|
|
208
|
+
}
|
|
225
209
|
});
|
|
226
210
|
});
|
|
211
|
+
let pendingLogWrite = Promise.resolve();
|
|
212
|
+
const copyLog = async (input, output) => {
|
|
213
|
+
const writeLine = async (line) => {
|
|
214
|
+
const formatted = (0, import_mcp.formatMcpArtifactLogLine)(line);
|
|
215
|
+
pendingLogWrite = pendingLogWrite.then(
|
|
216
|
+
() => logHandle.writeFile(formatted)
|
|
217
|
+
);
|
|
218
|
+
await pendingLogWrite;
|
|
219
|
+
output.write(formatted);
|
|
220
|
+
};
|
|
221
|
+
let pendingLine = "";
|
|
222
|
+
try {
|
|
223
|
+
for await (const chunk of input.setEncoding("utf8")) {
|
|
224
|
+
const lines = (pendingLine + chunk).split("\n");
|
|
225
|
+
pendingLine = lines.pop() ?? "";
|
|
226
|
+
for (const line of lines) await writeLine(line);
|
|
227
|
+
}
|
|
228
|
+
if (pendingLine) await writeLine(pendingLine);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
child.kill();
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
const results = await Promise.allSettled([
|
|
235
|
+
copyLog(child.stdout, process.stdout),
|
|
236
|
+
copyLog(child.stderr, process.stderr),
|
|
237
|
+
exit
|
|
238
|
+
]);
|
|
239
|
+
for (const result of results) {
|
|
240
|
+
if (result.status === "rejected") throw result.reason;
|
|
241
|
+
}
|
|
227
242
|
};
|
|
228
243
|
var runRuntimeFeedbackReplay = async ({
|
|
229
244
|
runtimeEvidencePath,
|
|
@@ -159,6 +159,7 @@ var extractRuntimeParityEntries = (trades) => trades.filter(
|
|
|
159
159
|
direction: trade.direction,
|
|
160
160
|
qty: toFiniteNumberOrNull(trade.qty),
|
|
161
161
|
timestamp: trade.entryTimestamp,
|
|
162
|
+
...Number.isFinite(trade.signalTimestamp) ? { signalTimestamp: trade.signalTimestamp } : {},
|
|
162
163
|
price: toFiniteNumberOrNull(trade.entryPrice),
|
|
163
164
|
orderId: trade.orderId,
|
|
164
165
|
signalId: typeof trade.signalId === "string" ? trade.signalId : void 0,
|
|
@@ -45,6 +45,13 @@ var getBacktestParityComparisonTimestamp = (entry, timestampOffsetMs = 0) => {
|
|
|
45
45
|
return (entry.signalTimestamp ?? entry.timestamp) + offsetMs;
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
+
// src/lib/replay/historicalSignalsReplayDecisionTrace.ts
|
|
49
|
+
var replayDecisionTraceKey = ({
|
|
50
|
+
strategy,
|
|
51
|
+
symbol,
|
|
52
|
+
signalTimestamp
|
|
53
|
+
}) => JSON.stringify([strategy, symbol, signalTimestamp]);
|
|
54
|
+
|
|
48
55
|
// src/lib/runtimeParityDetails.ts
|
|
49
56
|
var DEFAULT_REPLAY_PARITY_DETAILS_LIMIT = 500;
|
|
50
57
|
var DEFAULT_REPLAY_PARITY_ARTIFACT_LIMIT = 100;
|
|
@@ -120,6 +127,7 @@ var toRuntimeParityDetail = (entry) => ({
|
|
|
120
127
|
direction: entry.direction,
|
|
121
128
|
qty: entry.qty ?? null,
|
|
122
129
|
timestamp: entry.timestamp,
|
|
130
|
+
...entry.signalTimestamp != null ? { signalTimestamp: entry.signalTimestamp } : {},
|
|
123
131
|
price: entry.price,
|
|
124
132
|
exitType: entry.exitType ?? null,
|
|
125
133
|
exitTimestamp: entry.exitTimestamp ?? null,
|
|
@@ -193,7 +201,8 @@ var findNearestEvaluation = ({
|
|
|
193
201
|
evaluations,
|
|
194
202
|
toleranceMs,
|
|
195
203
|
timestampOffsetMs,
|
|
196
|
-
entryTimestampOffsetMs = 0
|
|
204
|
+
entryTimestampOffsetMs = 0,
|
|
205
|
+
matchDirection = false
|
|
197
206
|
}) => {
|
|
198
207
|
const entryStrategy = getEntryStrategy(entry);
|
|
199
208
|
if (!entryStrategy) {
|
|
@@ -203,7 +212,7 @@ var findNearestEvaluation = ({
|
|
|
203
212
|
let bestDiff = Number.POSITIVE_INFINITY;
|
|
204
213
|
const entryTimestamp = entry.timestamp + entryTimestampOffsetMs;
|
|
205
214
|
for (const evaluation of evaluations) {
|
|
206
|
-
if (evaluation.strategy !== entryStrategy || evaluation.symbol !== entry.symbol) {
|
|
215
|
+
if (evaluation.strategy !== entryStrategy || evaluation.symbol !== entry.symbol || matchDirection && evaluation.direction != null && evaluation.direction !== entry.direction) {
|
|
207
216
|
continue;
|
|
208
217
|
}
|
|
209
218
|
const diff = Math.abs(
|
|
@@ -549,6 +558,7 @@ var buildReplayMismatchDrilldown = ({
|
|
|
549
558
|
replaySignals = [],
|
|
550
559
|
replaySignalEvaluations = [],
|
|
551
560
|
replayLineageScopes = [],
|
|
561
|
+
replayDecisionTraces = [],
|
|
552
562
|
runtimeLineageScopes = [],
|
|
553
563
|
toleranceMs,
|
|
554
564
|
backtestTimestampOffsetMs,
|
|
@@ -557,48 +567,66 @@ var buildReplayMismatchDrilldown = ({
|
|
|
557
567
|
const nearestByEntry = new Map(
|
|
558
568
|
nearestCandidates.map((candidate) => [candidate.entry, candidate])
|
|
559
569
|
);
|
|
570
|
+
const traceByCandle = new Map(
|
|
571
|
+
replayDecisionTraces.map((trace) => [replayDecisionTraceKey(trace), trace])
|
|
572
|
+
);
|
|
560
573
|
const artifactLimit = Math.min(limit, resolveReplayParityArtifactLimit());
|
|
561
574
|
let runtimeOnlyArtifactsIncluded = 0;
|
|
562
575
|
let backtestOnlyArtifactsIncluded = 0;
|
|
563
576
|
const runtimeOnlyDiagnostics = runtimeOnly.map((entry, index) => {
|
|
564
|
-
const
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
577
|
+
const isRuntimeTrade = entry.source === "runtime";
|
|
578
|
+
const decisionEntry = isRuntimeTrade ? entry.signalTimestamp == null ? null : { ...entry, timestamp: entry.signalTimestamp } : entry;
|
|
579
|
+
const decisionClock = {
|
|
580
|
+
toleranceMs: isRuntimeTrade ? 0 : toleranceMs,
|
|
581
|
+
timestampOffsetMs: isRuntimeTrade ? 0 : resolveTradeParityTimestampOffset(
|
|
582
|
+
getEntryStrategy(entry) ?? "",
|
|
583
|
+
backtestTimestampOffsetMs
|
|
584
|
+
)
|
|
585
|
+
};
|
|
568
586
|
const includeArtifacts = index < artifactLimit;
|
|
569
587
|
const nearestCandidate = nearestByEntry.get(entry);
|
|
570
|
-
const nearestReplaySignal = findNearestSignal({
|
|
571
|
-
entry,
|
|
588
|
+
const nearestReplaySignal = decisionEntry && findNearestSignal({
|
|
589
|
+
entry: decisionEntry,
|
|
572
590
|
signals: replaySignals,
|
|
573
|
-
|
|
574
|
-
timestampOffsetMs: entryOffsetMs
|
|
591
|
+
...decisionClock
|
|
575
592
|
});
|
|
576
|
-
const nearestReplayEvaluation = findNearestEvaluation({
|
|
577
|
-
entry,
|
|
593
|
+
const nearestReplayEvaluation = decisionEntry && findNearestEvaluation({
|
|
594
|
+
entry: decisionEntry,
|
|
578
595
|
evaluations: replaySignalEvaluations,
|
|
579
|
-
|
|
580
|
-
|
|
596
|
+
matchDirection: isRuntimeTrade,
|
|
597
|
+
...decisionClock
|
|
581
598
|
});
|
|
582
|
-
const nearestReplayEvaluationOutcome = findNearestReplayEvaluationOutcome({
|
|
583
|
-
entry,
|
|
599
|
+
const nearestReplayEvaluationOutcome = decisionEntry && findNearestReplayEvaluationOutcome({
|
|
600
|
+
entry: decisionEntry,
|
|
584
601
|
lineageScopes: replayLineageScopes,
|
|
585
|
-
|
|
586
|
-
timestampOffsetMs: entryOffsetMs
|
|
602
|
+
...decisionClock
|
|
587
603
|
});
|
|
604
|
+
const strategy = getEntryStrategy(entry);
|
|
605
|
+
const replayDecisionTrace = isRuntimeTrade && strategy && decisionEntry ? traceByCandle.get(
|
|
606
|
+
replayDecisionTraceKey({
|
|
607
|
+
strategy,
|
|
608
|
+
symbol: entry.symbol,
|
|
609
|
+
signalTimestamp: decisionEntry.timestamp
|
|
610
|
+
})
|
|
611
|
+
) : void 0;
|
|
612
|
+
const unavailableReason = !isRuntimeTrade ? "no_replay_signal_or_backtest_candidate" : !decisionEntry ? "replay_signal_timestamp_unavailable" : replayDecisionTrace?.decision.stage === "not_evaluated" ? replayDecisionTrace.decision.reason : "replay_evaluation_unavailable";
|
|
588
613
|
const classification = nearestReplaySignal ? classifySignalDiagnostic(nearestReplaySignal.signal) : nearestReplayEvaluation ? classifyEvaluationDiagnostic(nearestReplayEvaluation.evaluation) : nearestReplayEvaluationOutcome ? {
|
|
589
|
-
classification:
|
|
614
|
+
classification: nearestReplayEvaluationOutcome.reason.startsWith(
|
|
615
|
+
"BACKTEST_ENTRY_DELAY_"
|
|
616
|
+
) ? "entry_delayed" : "core_skipped",
|
|
590
617
|
reason: nearestReplayEvaluationOutcome.reason
|
|
591
|
-
} : nearestCandidate?.nearest ? {
|
|
618
|
+
} : !isRuntimeTrade && nearestCandidate?.nearest ? {
|
|
592
619
|
classification: "timing_or_price_drift",
|
|
593
620
|
reason: nearestCandidate.reason
|
|
594
621
|
} : {
|
|
595
622
|
classification: "no_replay_candidate",
|
|
596
|
-
reason:
|
|
623
|
+
reason: unavailableReason
|
|
597
624
|
};
|
|
598
625
|
return {
|
|
599
626
|
entry,
|
|
600
627
|
...classification,
|
|
601
628
|
...nearestCandidate ? { nearestCandidate } : {},
|
|
629
|
+
...replayDecisionTrace ? { replayDecisionTrace } : {},
|
|
602
630
|
...nearestReplaySignal ? {
|
|
603
631
|
replaySignal: toSignalDiagnostic({
|
|
604
632
|
signal: nearestReplaySignal.signal,
|
|
@@ -724,6 +752,7 @@ var buildReplayRuntimeComparisonDetails = ({
|
|
|
724
752
|
replaySignals,
|
|
725
753
|
replaySignalEvaluations,
|
|
726
754
|
replayLineageScopes,
|
|
755
|
+
replayDecisionTraces,
|
|
727
756
|
runtimeLineageScopes
|
|
728
757
|
}) => {
|
|
729
758
|
const runtimeDetails = runtimeEntries.map(toRuntimeParityDetail);
|
|
@@ -784,6 +813,7 @@ var buildReplayRuntimeComparisonDetails = ({
|
|
|
784
813
|
replaySignals,
|
|
785
814
|
replaySignalEvaluations,
|
|
786
815
|
replayLineageScopes,
|
|
816
|
+
replayDecisionTraces,
|
|
787
817
|
runtimeLineageScopes,
|
|
788
818
|
toleranceMs,
|
|
789
819
|
backtestTimestampOffsetMs,
|
|
@@ -1355,12 +1355,18 @@ async function collectReleaseEvidenceReferences(references) {
|
|
|
1355
1355
|
}
|
|
1356
1356
|
const nested = (value) => value != null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
1357
1357
|
const array = (value) => Array.isArray(value) ? value : [];
|
|
1358
|
-
const semanticallyValid = reference.kind === "core_research" ?
|
|
1358
|
+
const semanticallyValid = reference.kind === "core_research" ? [
|
|
1359
|
+
"tradejs-core-research-result/v1",
|
|
1360
|
+
"tradejs-core-research-result/v2"
|
|
1361
|
+
].includes(String(artifact.schema)) || artifact.schema === "tradejs-core-research-manifest/v1" && artifact.status === "completed" : reference.kind === "ai_gate" ? nested(artifact.run)?.mode === "local-deterministic" && nested(artifact.research)?.lineage != null && nested(artifact.outcome) != null : reference.kind === "runtime_parity" ? artifact.reportType === "replay-runtime-evidence" && nested(nested(artifact.replay)?.runtimeComparison) != null : reference.kind === "execution_calibration" ? artifact.reportType === "execution-calibration" && nested(artifact.summary) != null : reference.kind === "runtime_evidence" ? artifact.reportType === "runtime-evidence" : artifact.reportType === "runtime-scorecard";
|
|
1359
1362
|
assert2(
|
|
1360
1363
|
semanticallyValid,
|
|
1361
1364
|
`evidence ${reference.artifactId} does not match ${reference.kind}`
|
|
1362
1365
|
);
|
|
1363
|
-
if (reference.kind === "core_research" &&
|
|
1366
|
+
if (reference.kind === "core_research" && [
|
|
1367
|
+
"tradejs-core-research-result/v1",
|
|
1368
|
+
"tradejs-core-research-result/v2"
|
|
1369
|
+
].includes(String(artifact.schema))) {
|
|
1364
1370
|
await verifyCompletedCoreResearchBundle({
|
|
1365
1371
|
artifact,
|
|
1366
1372
|
resultPath: reference.path,
|