@tradejs/cli 3.1.26-beta.244 → 3.1.27-beta.245
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 +235 -36
- package/dist/lib/runtimeDebugEvidence.js +1 -0
- package/dist/lib/runtimeParityDetails.js +71 -4
- package/dist/lib/runtimeScorecard.js +103 -20
- package/dist/lib/runtimeSignalsLoader.js +1 -0
- package/dist/lib/runtimeSignalsStorage.js +33 -0
- package/dist/scripts/replay.js +85 -11
- package/dist/scripts/replayRunner.js +85 -11
- package/dist/scripts/replayRuntimeEvidence.js +1 -0
- package/dist/scripts/runtimeEvidence.js +1 -0
- package/dist/scripts/runtimeParity.js +1 -0
- package/dist/scripts/runtimeScorecard.js +109 -20
- package/dist/scripts/signals.js +37 -0
- package/dist/scripts/signalsDaemon.js +37 -0
- package/dist/scripts/signalsSummary.js +1 -0
- package/package.json +7 -7
package/dist/cli.js
CHANGED
|
@@ -24004,12 +24004,43 @@ var init_results = __esm({
|
|
|
24004
24004
|
});
|
|
24005
24005
|
|
|
24006
24006
|
// src/lib/runtimeSignalsStorage.ts
|
|
24007
|
-
var import_constants14, import_time6, SECONDS_PER_DAY, RUNTIME_SIGNAL_RETENTION_DAYS_ENV, DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS, RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS, parsePositiveNumber, getRuntimeSignalRetentionTtlSeconds, toRuntimeSignalBucketRef, shouldStoreRuntimeSignalDiagnostics, toStoredRuntimeSignal, isRuntimeSignalBucketRef, normalizeRuntimeSignalSkipReason, buildStatsReasonField, buildRuntimeSignalStatsIncrements, shouldStoreDetailedRuntimeSignalEvaluation, toCount, parseRuntimeSignalStatsBucket;
|
|
24007
|
+
var import_constants14, import_data4, import_time6, appendRuntimeSignalEvaluationRun, SECONDS_PER_DAY, RUNTIME_SIGNAL_RETENTION_DAYS_ENV, DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS, RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS, parsePositiveNumber, getRuntimeSignalRetentionTtlSeconds, toRuntimeSignalBucketRef, shouldStoreRuntimeSignalDiagnostics, toStoredRuntimeSignal, isRuntimeSignalBucketRef, normalizeRuntimeSignalSkipReason, buildStatsReasonField, buildRuntimeSignalStatsIncrements, shouldStoreDetailedRuntimeSignalEvaluation, toCount, parseRuntimeSignalStatsBucket;
|
|
24008
24008
|
var init_runtimeSignalsStorage = __esm({
|
|
24009
24009
|
"src/lib/runtimeSignalsStorage.ts"() {
|
|
24010
24010
|
"use strict";
|
|
24011
24011
|
import_constants14 = require("@tradejs/core/constants");
|
|
24012
|
+
import_data4 = require("@tradejs/core/data");
|
|
24012
24013
|
import_time6 = require("@tradejs/core/time");
|
|
24014
|
+
appendRuntimeSignalEvaluationRun = (runs = [], evaluation) => {
|
|
24015
|
+
if (evaluation.status !== "skip") {
|
|
24016
|
+
return [...runs];
|
|
24017
|
+
}
|
|
24018
|
+
const stepMs = (0, import_data4.intervalToMs)(evaluation.interval);
|
|
24019
|
+
const reason = evaluation.reason?.trim() || "NO_SIGNAL";
|
|
24020
|
+
const existing = runs.find(
|
|
24021
|
+
(run) => run.status === "skip" && run.reason === reason && run.stepMs === stepMs && evaluation.timestamp >= run.firstTimestamp && evaluation.timestamp <= run.lastTimestamp && (evaluation.timestamp - run.firstTimestamp) % stepMs === 0
|
|
24022
|
+
);
|
|
24023
|
+
if (existing) {
|
|
24024
|
+
return [...runs];
|
|
24025
|
+
}
|
|
24026
|
+
const last = runs.at(-1);
|
|
24027
|
+
if (last?.status === "skip" && last.reason === reason && last.stepMs === stepMs && evaluation.timestamp === last.lastTimestamp + stepMs) {
|
|
24028
|
+
return [
|
|
24029
|
+
...runs.slice(0, -1),
|
|
24030
|
+
{ ...last, lastTimestamp: evaluation.timestamp }
|
|
24031
|
+
];
|
|
24032
|
+
}
|
|
24033
|
+
return [
|
|
24034
|
+
...runs,
|
|
24035
|
+
{
|
|
24036
|
+
status: "skip",
|
|
24037
|
+
reason,
|
|
24038
|
+
firstTimestamp: evaluation.timestamp,
|
|
24039
|
+
lastTimestamp: evaluation.timestamp,
|
|
24040
|
+
stepMs
|
|
24041
|
+
}
|
|
24042
|
+
];
|
|
24043
|
+
};
|
|
24013
24044
|
SECONDS_PER_DAY = 86400;
|
|
24014
24045
|
RUNTIME_SIGNAL_RETENTION_DAYS_ENV = "RUNTIME_SIGNAL_RETENTION_DAYS";
|
|
24015
24046
|
DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS = import_constants14.TTL_3D;
|
|
@@ -26960,7 +26991,7 @@ var init_runtimeEvidenceSync2 = __esm({
|
|
|
26960
26991
|
});
|
|
26961
26992
|
|
|
26962
26993
|
// src/lib/runtimeScorecard.ts
|
|
26963
|
-
var asRecord6, asArray3, finiteNumber5, finiteString2, packageVersionMap, round, unwrapRows, runtimePayload, runtimeWindow, extractRuntimeRows, buildEmbeddedLineageScope, runtimeDeploymentBinding, belongsToRuntimeDeployment, belongsToStrategy, filterArtifactByStrategy, countBy2, buildDistributions, buildDistributionDelta, sum2, tradeTimestamp, dedupeTrades, maxDrawdown, buildRollingPerformance, getReplayComparison, replayCountsForStrategy, getProspectiveSummary, buildRuntimeScorecard, formatRuntimeScorecardMarkdown;
|
|
26994
|
+
var asRecord6, asArray3, finiteNumber5, finiteString2, packageVersionMap, round, unwrapRows, runtimePayload, runtimeWindow, extractRuntimeRows, buildEmbeddedLineageScope, runtimeDeploymentBinding, belongsToRuntimeDeployment, belongsToStrategy, filterArtifactByStrategy, countBy2, resolveGateDecision, buildDistributions, buildDistributionDelta, sum2, tradeTimestamp, dedupeTrades, maxDrawdown, buildRollingPerformance, getReplayComparison, replayCountsForStrategy, getProspectiveSummary, buildRuntimeScorecard, formatRuntimeScorecardMarkdown;
|
|
26964
26995
|
var init_runtimeScorecard = __esm({
|
|
26965
26996
|
"src/lib/runtimeScorecard.ts"() {
|
|
26966
26997
|
"use strict";
|
|
@@ -27180,6 +27211,20 @@ var init_runtimeScorecard = __esm({
|
|
|
27180
27211
|
Object.entries(counts).sort(([left], [right]) => left.localeCompare(right))
|
|
27181
27212
|
);
|
|
27182
27213
|
};
|
|
27214
|
+
resolveGateDecision = (evaluation) => {
|
|
27215
|
+
const analysis = asRecord6(evaluation.aiAnalysis);
|
|
27216
|
+
const explicit = finiteString2(analysis?.gateDecision);
|
|
27217
|
+
if (explicit === "approved" || explicit === "rejected") {
|
|
27218
|
+
return { decision: explicit, source: "gate_decision" };
|
|
27219
|
+
}
|
|
27220
|
+
if (typeof analysis?.approved === "boolean") {
|
|
27221
|
+
return {
|
|
27222
|
+
decision: analysis.approved ? "approved" : "rejected",
|
|
27223
|
+
source: "legacy_approved_fallback"
|
|
27224
|
+
};
|
|
27225
|
+
}
|
|
27226
|
+
return null;
|
|
27227
|
+
};
|
|
27183
27228
|
buildDistributions = ({
|
|
27184
27229
|
evaluations,
|
|
27185
27230
|
signals: signals2
|
|
@@ -27360,18 +27405,15 @@ var init_runtimeScorecard = __esm({
|
|
|
27360
27405
|
const signalEvaluations = rows.evaluations.filter(
|
|
27361
27406
|
(evaluation) => evaluation.status === "signal"
|
|
27362
27407
|
);
|
|
27363
|
-
const gateDecisions = signalEvaluations.map(
|
|
27364
|
-
|
|
27365
|
-
decision: finiteString2(asRecord6(evaluation.aiAnalysis)?.gateDecision)
|
|
27366
|
-
})).filter(
|
|
27367
|
-
({ decision }) => decision === "approved" || decision === "rejected"
|
|
27408
|
+
const gateDecisions = signalEvaluations.map(resolveGateDecision).filter(
|
|
27409
|
+
(decision) => Boolean(decision)
|
|
27368
27410
|
);
|
|
27369
27411
|
const llmEligibleEvaluations = llmComparatorPolicy === "disabled" ? [] : llmComparatorPolicy === "ai_approved_only" ? signalEvaluations.filter(
|
|
27370
|
-
(evaluation) =>
|
|
27412
|
+
(evaluation) => resolveGateDecision(evaluation)?.decision === "approved"
|
|
27371
27413
|
) : signalEvaluations;
|
|
27372
27414
|
const gateComparisons = llmEligibleEvaluations.map((evaluation) => {
|
|
27373
27415
|
const analysis = asRecord6(evaluation.aiAnalysis);
|
|
27374
|
-
const gateDecision =
|
|
27416
|
+
const gateDecision = resolveGateDecision(evaluation)?.decision ?? null;
|
|
27375
27417
|
const llmDecision = finiteString2(analysis?.llmDecision);
|
|
27376
27418
|
if (gateDecision !== "approved" && gateDecision !== "rejected" || llmDecision !== "approved" && llmDecision !== "rejected") {
|
|
27377
27419
|
return null;
|
|
@@ -27406,6 +27448,27 @@ var init_runtimeScorecard = __esm({
|
|
|
27406
27448
|
};
|
|
27407
27449
|
const actualSlippageBps = averageSampleMetric("signalToFillAdverseBps");
|
|
27408
27450
|
const residualVsModelBps = averageSampleMetric("residualVsCurrentModelBps");
|
|
27451
|
+
const signalToArrivalAdverseBps = averageSampleMetric(
|
|
27452
|
+
"signalToArrivalAdverseBps"
|
|
27453
|
+
);
|
|
27454
|
+
const arrivalToFillAdverseBps = averageSampleMetric(
|
|
27455
|
+
"arrivalToFillAdverseBps"
|
|
27456
|
+
);
|
|
27457
|
+
const averageSignalCloseToSubmitMs = averageSampleMetric(
|
|
27458
|
+
"signalCloseToSubmitMs"
|
|
27459
|
+
);
|
|
27460
|
+
const averageSubmitToFillMs = averageSampleMetric("submitToFillMs");
|
|
27461
|
+
const fullTelemetryTrades = calibrationSamples.filter(
|
|
27462
|
+
(sample) => finiteString2(sample.telemetryQuality) === "full"
|
|
27463
|
+
).length;
|
|
27464
|
+
const arrivalQuoteTrades = calibrationSamples.filter(
|
|
27465
|
+
(sample) => finiteNumber5(sample.arrivalMid) != null
|
|
27466
|
+
).length;
|
|
27467
|
+
const arrivalQuoteCoverage = calibrationSamples.length ? round(arrivalQuoteTrades / calibrationSamples.length) : null;
|
|
27468
|
+
const hasTelemetryQuality = calibrationSamples.some(
|
|
27469
|
+
(sample) => finiteString2(sample.telemetryQuality) != null
|
|
27470
|
+
);
|
|
27471
|
+
const maximumSignalCloseToSubmitMs = thresholds.maximumSignalCloseToSubmitMs ?? 3e4;
|
|
27409
27472
|
const prospective = getProspectiveSummary(prospectiveEvidenceArtifact);
|
|
27410
27473
|
const historyTrades = dedupeTrades([
|
|
27411
27474
|
...scopedHistoryArtifacts,
|
|
@@ -27462,7 +27525,28 @@ var init_runtimeScorecard = __esm({
|
|
|
27462
27525
|
reactions.push({
|
|
27463
27526
|
code: "SLIPPAGE_DRIFT",
|
|
27464
27527
|
severity: "warning",
|
|
27465
|
-
message: `
|
|
27528
|
+
message: `Signal-close-to-fill residual ${round(residualVsModelBps, 2)} bps exceeds ${thresholds.maximumSlippageResidualBps} bps.`
|
|
27529
|
+
});
|
|
27530
|
+
}
|
|
27531
|
+
if (averageSignalCloseToSubmitMs != null && averageSignalCloseToSubmitMs > maximumSignalCloseToSubmitMs) {
|
|
27532
|
+
reactions.push({
|
|
27533
|
+
code: "PRE_SUBMIT_LATENCY",
|
|
27534
|
+
severity: "warning",
|
|
27535
|
+
message: `Average signal-close-to-submit latency ${round(averageSignalCloseToSubmitMs, 3)} ms exceeds ${maximumSignalCloseToSubmitMs} ms.`
|
|
27536
|
+
});
|
|
27537
|
+
}
|
|
27538
|
+
if (hasTelemetryQuality && calibrationSamples.length > 0 && fullTelemetryTrades < calibrationSamples.length) {
|
|
27539
|
+
reactions.push({
|
|
27540
|
+
code: "EXECUTION_TELEMETRY_INCOMPLETE",
|
|
27541
|
+
severity: "info",
|
|
27542
|
+
message: `Full arrival and fill telemetry is available for ${fullTelemetryTrades}/${calibrationSamples.length} trades.`
|
|
27543
|
+
});
|
|
27544
|
+
}
|
|
27545
|
+
if (riskDecisions.some((decision) => decision.status === "rejected")) {
|
|
27546
|
+
reactions.push({
|
|
27547
|
+
code: "RISK_PLAN_EXCEEDS_DECLARED_LIMIT",
|
|
27548
|
+
severity: "warning",
|
|
27549
|
+
message: "At least one observed order plan exceeds its declared MAX_LOSS_VALUE; telemetry is not yet enforced."
|
|
27466
27550
|
});
|
|
27467
27551
|
}
|
|
27468
27552
|
if (sevenDay.closedTrades >= thresholds.minimumClosedTrades && sevenDay.expectancy != null && sevenDay.expectancy < thresholds.minimumExpectancy) {
|
|
@@ -27491,7 +27575,10 @@ var init_runtimeScorecard = __esm({
|
|
|
27491
27575
|
deployment: deploymentBinding,
|
|
27492
27576
|
lineage: runtimeLineage,
|
|
27493
27577
|
promotionStatus,
|
|
27494
|
-
thresholds
|
|
27578
|
+
thresholds: {
|
|
27579
|
+
...thresholds,
|
|
27580
|
+
maximumSignalCloseToSubmitMs
|
|
27581
|
+
},
|
|
27495
27582
|
funnel: {
|
|
27496
27583
|
evaluations: rows.evaluations.length,
|
|
27497
27584
|
coreCandidates: signalEvaluations.length,
|
|
@@ -27503,25 +27590,38 @@ var init_runtimeScorecard = __esm({
|
|
|
27503
27590
|
rejected: gateDecisions.filter(
|
|
27504
27591
|
({ decision }) => decision === "rejected"
|
|
27505
27592
|
).length,
|
|
27506
|
-
coverage: signalEvaluations.length ? round(gateDecisions.length / signalEvaluations.length) : null
|
|
27593
|
+
coverage: signalEvaluations.length ? round(gateDecisions.length / signalEvaluations.length) : null,
|
|
27594
|
+
legacyApprovedFallback: gateDecisions.filter(
|
|
27595
|
+
({ source }) => source === "legacy_approved_fallback"
|
|
27596
|
+
).length
|
|
27507
27597
|
},
|
|
27508
27598
|
allocator: {
|
|
27509
27599
|
available: allocatorDecisions.length > 0,
|
|
27510
27600
|
approved: allocatorDecisions.filter(
|
|
27511
|
-
(decision) => decision.
|
|
27601
|
+
(decision) => decision.status === "approved"
|
|
27512
27602
|
).length,
|
|
27513
27603
|
rejected: allocatorDecisions.filter(
|
|
27514
|
-
(decision) => decision.
|
|
27604
|
+
(decision) => decision.status === "rejected"
|
|
27605
|
+
).length,
|
|
27606
|
+
notApplicable: allocatorDecisions.filter(
|
|
27607
|
+
(decision) => decision.status === "not_applicable"
|
|
27608
|
+
).length,
|
|
27609
|
+
unavailable: allocatorDecisions.filter(
|
|
27610
|
+
(decision) => decision.status === "unavailable"
|
|
27515
27611
|
).length
|
|
27516
27612
|
},
|
|
27517
27613
|
risk: {
|
|
27518
27614
|
available: riskDecisions.length > 0,
|
|
27519
27615
|
approved: riskDecisions.filter(
|
|
27520
|
-
(decision) => decision.
|
|
27616
|
+
(decision) => decision.status === "approved"
|
|
27521
27617
|
).length,
|
|
27522
27618
|
rejected: riskDecisions.filter(
|
|
27523
|
-
(decision) => decision.
|
|
27524
|
-
).length
|
|
27619
|
+
(decision) => decision.status === "rejected"
|
|
27620
|
+
).length,
|
|
27621
|
+
unavailable: riskDecisions.filter(
|
|
27622
|
+
(decision) => decision.status === "unavailable"
|
|
27623
|
+
).length,
|
|
27624
|
+
enforced: riskDecisions.some((decision) => decision.enforced === true)
|
|
27525
27625
|
},
|
|
27526
27626
|
orderAttempts: orderAttempts.length,
|
|
27527
27627
|
orderFailures: orderAttempts.filter(
|
|
@@ -27583,8 +27683,16 @@ var init_runtimeScorecard = __esm({
|
|
|
27583
27683
|
},
|
|
27584
27684
|
execution: {
|
|
27585
27685
|
available: actualSlippageBps != null || residualVsModelBps != null,
|
|
27686
|
+
metricScope: arrivalToFillAdverseBps == null ? "signal_close_to_fill" : "signal_and_exchange_components",
|
|
27687
|
+
samples: calibrationSamples.length,
|
|
27688
|
+
fullTelemetryTrades,
|
|
27689
|
+
arrivalQuoteCoverage,
|
|
27586
27690
|
actualSignalToFillSlippageBps: actualSlippageBps,
|
|
27587
|
-
residualVsCurrentModelBps: residualVsModelBps
|
|
27691
|
+
residualVsCurrentModelBps: residualVsModelBps,
|
|
27692
|
+
signalToArrivalAdverseBps,
|
|
27693
|
+
arrivalToFillAdverseBps,
|
|
27694
|
+
averageSignalCloseToSubmitMs,
|
|
27695
|
+
averageSubmitToFillMs
|
|
27588
27696
|
},
|
|
27589
27697
|
prospective,
|
|
27590
27698
|
rolling,
|
|
@@ -27638,10 +27746,10 @@ Window: ${new Date(scorecard.window.startTime).toISOString()} \u2014 ${new Date(
|
|
|
27638
27746
|
|
|
27639
27747
|
- Evaluations: ${scorecard.funnel.evaluations}
|
|
27640
27748
|
- Core candidates: ${scorecard.funnel.coreCandidates}
|
|
27641
|
-
- Gate approvals/rejects: ${scorecard.funnel.gate.approved}/${scorecard.funnel.gate.rejected}
|
|
27749
|
+
- Gate approvals/rejects: ${scorecard.funnel.gate.approved}/${scorecard.funnel.gate.rejected} (legacy fallback: ${scorecard.funnel.gate.legacyApprovedFallback})
|
|
27642
27750
|
- AI / LLM disagreement: ${scorecard.gateComparison.disagreements}/${scorecard.gateComparison.compared}
|
|
27643
|
-
-
|
|
27644
|
-
- Risk
|
|
27751
|
+
- Runtime admission approved/rejected/not-applicable: ${scorecard.funnel.allocator.available ? `${scorecard.funnel.allocator.approved}/${scorecard.funnel.allocator.rejected}/${scorecard.funnel.allocator.notApplicable}` : "unavailable"}
|
|
27752
|
+
- Risk assessment within/exceeds/unavailable: ${scorecard.funnel.risk.available ? `${scorecard.funnel.risk.approved}/${scorecard.funnel.risk.rejected}/${scorecard.funnel.risk.unavailable}` : "unavailable"} (enforced: ${scorecard.funnel.risk.enforced})
|
|
27645
27753
|
- Order attempts/failures: ${scorecard.funnel.orderAttempts}/${scorecard.funnel.orderFailures}
|
|
27646
27754
|
- Fills: ${scorecard.funnel.fills}
|
|
27647
27755
|
- Closed trades: ${scorecard.funnel.closedTrades}
|
|
@@ -27650,8 +27758,14 @@ Window: ${new Date(scorecard.window.startTime).toISOString()} \u2014 ${new Date(
|
|
|
27650
27758
|
|
|
27651
27759
|
- Parity: ${scorecard.parity.ratio == null ? "n/a" : `${round(scorecard.parity.ratio * 100, 2)}%`}
|
|
27652
27760
|
- Runtime/replay mismatches: ${scorecard.parity.backtestOnly + scorecard.parity.runtimeOnly}
|
|
27653
|
-
-
|
|
27761
|
+
- Execution metric scope: ${scorecard.execution.metricScope}
|
|
27762
|
+
- Telemetry samples/full/arrival coverage: ${scorecard.execution.samples}/${scorecard.execution.fullTelemetryTrades}/${scorecard.execution.arrivalQuoteCoverage == null ? "n/a" : `${round(scorecard.execution.arrivalQuoteCoverage * 100, 2)}%`}
|
|
27763
|
+
- Signal-close-to-fill adverse move: ${scorecard.execution.actualSignalToFillSlippageBps ?? "n/a"} bps
|
|
27764
|
+
- Signal-to-arrival adverse move: ${scorecard.execution.signalToArrivalAdverseBps ?? "n/a"} bps
|
|
27765
|
+
- Arrival-to-fill exchange slippage: ${scorecard.execution.arrivalToFillAdverseBps ?? "n/a"} bps
|
|
27654
27766
|
- Residual vs current model: ${scorecard.execution.residualVsCurrentModelBps ?? "n/a"} bps
|
|
27767
|
+
- Average signal-close-to-submit: ${scorecard.execution.averageSignalCloseToSubmitMs ?? "n/a"} ms
|
|
27768
|
+
- Average submit-to-fill: ${scorecard.execution.averageSubmitToFillMs ?? "n/a"} ms
|
|
27655
27769
|
|
|
27656
27770
|
## Rolling performance
|
|
27657
27771
|
|
|
@@ -29179,6 +29293,11 @@ var init_runtimeScorecard2 = __esm({
|
|
|
29179
29293
|
"Maximum acceptable execution residual in bps",
|
|
29180
29294
|
3
|
|
29181
29295
|
);
|
|
29296
|
+
import_args30.default.option(
|
|
29297
|
+
["L", "maximumSignalCloseToSubmitMs"],
|
|
29298
|
+
"Maximum acceptable average signal-close-to-submit latency in milliseconds",
|
|
29299
|
+
3e4
|
|
29300
|
+
);
|
|
29182
29301
|
import_args30.default.option(
|
|
29183
29302
|
["T", "minimumClosedTrades"],
|
|
29184
29303
|
"Minimum 7d closed trades for expectancy reactions",
|
|
@@ -29271,6 +29390,7 @@ var init_runtimeScorecard2 = __esm({
|
|
|
29271
29390
|
thresholds: {
|
|
29272
29391
|
minimumParityRatio: Number(flags29.minimumParityRatio),
|
|
29273
29392
|
maximumSlippageResidualBps: Number(flags29.maximumSlippageResidualBps),
|
|
29393
|
+
maximumSignalCloseToSubmitMs: Number(flags29.maximumSignalCloseToSubmitMs),
|
|
29274
29394
|
minimumClosedTrades: Number(flags29.minimumClosedTrades),
|
|
29275
29395
|
minimumExpectancy: Number(flags29.minimumExpectancy)
|
|
29276
29396
|
},
|
|
@@ -32667,6 +32787,10 @@ var init_evaluations = __esm({
|
|
|
32667
32787
|
lastTimestamp: Math.max(
|
|
32668
32788
|
existing?.lastTimestamp ?? evaluation.timestamp,
|
|
32669
32789
|
evaluation.timestamp
|
|
32790
|
+
),
|
|
32791
|
+
evaluationRuns: appendRuntimeSignalEvaluationRun(
|
|
32792
|
+
existing?.evaluationRuns,
|
|
32793
|
+
evaluation
|
|
32670
32794
|
)
|
|
32671
32795
|
};
|
|
32672
32796
|
runtimeLineageScopeCache.set(cacheKey, scope);
|
|
@@ -33398,6 +33522,8 @@ var init_tickerEvaluator = __esm({
|
|
|
33398
33522
|
orderStatus: signal.orderStatus,
|
|
33399
33523
|
orderSkipReason: signal.orderSkipReason,
|
|
33400
33524
|
...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {},
|
|
33525
|
+
...signal.allocatorDecision ? { allocatorDecision: signal.allocatorDecision } : {},
|
|
33526
|
+
...signal.riskDecision ? { riskDecision: signal.riskDecision } : {},
|
|
33401
33527
|
...signal.ml ? { ml: signal.ml } : {}
|
|
33402
33528
|
});
|
|
33403
33529
|
import_logger9.logger.info("Signal found %s by strategy %s", symbol, strategyName);
|
|
@@ -36077,7 +36203,7 @@ var init_runtimeTradeSync = __esm({
|
|
|
36077
36203
|
});
|
|
36078
36204
|
|
|
36079
36205
|
// src/lib/runtimeParityDetails.ts
|
|
36080
|
-
var import_trade3, DEFAULT_REPLAY_PARITY_DETAILS_LIMIT, DEFAULT_REPLAY_PARITY_ARTIFACT_LIMIT, buildStrategyNameByOrderLinkKey, resolveReplayStrategyNameFromExchangeEntry, resolveReplayParityDetailsLimit, resolveReplayParityArtifactLimit, capReplayDetails, buildCostDetail, toBacktestParityDetail, toRuntimeParityDetail, toExchangeParityDetail, buildTimestampDelta, getComparisonTimestamp, getEntryStrategy, findNearestSignal, findNearestEvaluation, classifySignalDiagnostic, classifyEvaluationDiagnostic, summarizeMismatchDiagnostics, buildPnlDelta, buildPriceDeltaPct2, toFiniteNumberOrNull3, toAiDiagnostic, toSignalDiagnostic, toEvaluationDiagnostic, buildSlippageCost, buildMatchedReplayDetail, buildNearestCandidates, buildReplayMismatchDrilldown, buildReplayRuntimeComparisonDetails, buildReplayExchangeComparisonDetails;
|
|
36206
|
+
var import_trade3, DEFAULT_REPLAY_PARITY_DETAILS_LIMIT, DEFAULT_REPLAY_PARITY_ARTIFACT_LIMIT, buildStrategyNameByOrderLinkKey, resolveReplayStrategyNameFromExchangeEntry, resolveReplayParityDetailsLimit, resolveReplayParityArtifactLimit, capReplayDetails, buildCostDetail, toBacktestParityDetail, toRuntimeParityDetail, toExchangeParityDetail, buildTimestampDelta, getComparisonTimestamp, getEntryStrategy, findNearestSignal, findNearestEvaluation, findNearestRuntimeEvaluationOutcome, hasRuntimeLineageCoverage, classifySignalDiagnostic, classifyEvaluationDiagnostic, summarizeMismatchDiagnostics, buildPnlDelta, buildPriceDeltaPct2, toFiniteNumberOrNull3, toAiDiagnostic, toSignalDiagnostic, toEvaluationDiagnostic, buildSlippageCost, buildMatchedReplayDetail, buildNearestCandidates, buildReplayMismatchDrilldown, buildReplayRuntimeComparisonDetails, buildReplayExchangeComparisonDetails;
|
|
36081
36207
|
var init_runtimeParityDetails = __esm({
|
|
36082
36208
|
"src/lib/runtimeParityDetails.ts"() {
|
|
36083
36209
|
"use strict";
|
|
@@ -36253,6 +36379,50 @@ var init_runtimeParityDetails = __esm({
|
|
|
36253
36379
|
timestampDiffMs: bestDiff
|
|
36254
36380
|
} : null;
|
|
36255
36381
|
};
|
|
36382
|
+
findNearestRuntimeEvaluationOutcome = ({
|
|
36383
|
+
entry,
|
|
36384
|
+
lineageScopes,
|
|
36385
|
+
toleranceMs
|
|
36386
|
+
}) => {
|
|
36387
|
+
const strategy = getEntryStrategy(entry);
|
|
36388
|
+
const timestamp = entry.signalTimestamp ?? entry.timestamp;
|
|
36389
|
+
if (!strategy) return null;
|
|
36390
|
+
let nearest = null;
|
|
36391
|
+
for (const scope of lineageScopes) {
|
|
36392
|
+
if (scope.strategy !== strategy || scope.symbol !== entry.symbol) {
|
|
36393
|
+
continue;
|
|
36394
|
+
}
|
|
36395
|
+
for (const run of scope.evaluationRuns ?? []) {
|
|
36396
|
+
if (run.stepMs <= 0 || timestamp < run.firstTimestamp - toleranceMs || timestamp > run.lastTimestamp + toleranceMs) {
|
|
36397
|
+
continue;
|
|
36398
|
+
}
|
|
36399
|
+
const step = Math.round((timestamp - run.firstTimestamp) / run.stepMs);
|
|
36400
|
+
const candidateTimestamp = run.firstTimestamp + step * run.stepMs;
|
|
36401
|
+
const timestampDiffMs = Math.abs(candidateTimestamp - timestamp);
|
|
36402
|
+
if (candidateTimestamp < run.firstTimestamp || candidateTimestamp > run.lastTimestamp || timestampDiffMs > toleranceMs || nearest && timestampDiffMs >= nearest.timestampDiffMs) {
|
|
36403
|
+
continue;
|
|
36404
|
+
}
|
|
36405
|
+
nearest = {
|
|
36406
|
+
status: run.status,
|
|
36407
|
+
reason: run.reason,
|
|
36408
|
+
timestamp: candidateTimestamp,
|
|
36409
|
+
timestampDiffMs,
|
|
36410
|
+
source: "lineage_scope_compact"
|
|
36411
|
+
};
|
|
36412
|
+
}
|
|
36413
|
+
}
|
|
36414
|
+
return nearest;
|
|
36415
|
+
};
|
|
36416
|
+
hasRuntimeLineageCoverage = ({
|
|
36417
|
+
entry,
|
|
36418
|
+
lineageScopes
|
|
36419
|
+
}) => {
|
|
36420
|
+
const strategy = getEntryStrategy(entry);
|
|
36421
|
+
const timestamp = entry.signalTimestamp ?? entry.timestamp;
|
|
36422
|
+
return lineageScopes.some(
|
|
36423
|
+
(scope) => scope.strategy === strategy && scope.symbol === entry.symbol && timestamp >= scope.firstTimestamp && timestamp <= scope.lastTimestamp
|
|
36424
|
+
);
|
|
36425
|
+
};
|
|
36256
36426
|
classifySignalDiagnostic = (signal) => {
|
|
36257
36427
|
if (signal.orderStatus === "failed") {
|
|
36258
36428
|
return {
|
|
@@ -36497,6 +36667,7 @@ var init_runtimeParityDetails = __esm({
|
|
|
36497
36667
|
runtimeSignalEvaluations = [],
|
|
36498
36668
|
replaySignals = [],
|
|
36499
36669
|
replaySignalEvaluations = [],
|
|
36670
|
+
runtimeLineageScopes = [],
|
|
36500
36671
|
toleranceMs,
|
|
36501
36672
|
backtestTimestampOffsetMs,
|
|
36502
36673
|
limit
|
|
@@ -36564,9 +36735,26 @@ var init_runtimeParityDetails = __esm({
|
|
|
36564
36735
|
toleranceMs,
|
|
36565
36736
|
timestampOffsetMs: 0
|
|
36566
36737
|
});
|
|
36567
|
-
const
|
|
36738
|
+
const nearestRuntimeEvaluationOutcome = findNearestRuntimeEvaluationOutcome(
|
|
36739
|
+
{
|
|
36740
|
+
entry,
|
|
36741
|
+
lineageScopes: runtimeLineageScopes,
|
|
36742
|
+
toleranceMs
|
|
36743
|
+
}
|
|
36744
|
+
);
|
|
36745
|
+
const runtimeLineageCoversEntry = hasRuntimeLineageCoverage({
|
|
36746
|
+
entry,
|
|
36747
|
+
lineageScopes: runtimeLineageScopes
|
|
36748
|
+
});
|
|
36749
|
+
const classification = nearestRuntimeSignal ? classifySignalDiagnostic(nearestRuntimeSignal.signal) : nearestRuntimeEvaluation ? classifyEvaluationDiagnostic(nearestRuntimeEvaluation.evaluation) : nearestRuntimeEvaluationOutcome ? {
|
|
36750
|
+
classification: "core_skipped",
|
|
36751
|
+
reason: nearestRuntimeEvaluationOutcome.reason
|
|
36752
|
+
} : nearestCandidate?.nearest ? {
|
|
36568
36753
|
classification: "timing_or_price_drift",
|
|
36569
36754
|
reason: nearestCandidate.reason
|
|
36755
|
+
} : runtimeLineageCoversEntry ? {
|
|
36756
|
+
classification: "runtime_evaluation_detail_unavailable",
|
|
36757
|
+
reason: "runtime_scope_covers_timestamp_but_skip_detail_was_not_stored"
|
|
36570
36758
|
} : {
|
|
36571
36759
|
classification: "no_runtime_evaluation",
|
|
36572
36760
|
reason: "no_runtime_signal_or_evaluation"
|
|
@@ -36590,7 +36778,8 @@ var init_runtimeParityDetails = __esm({
|
|
|
36590
36778
|
...includeArtifacts ? {
|
|
36591
36779
|
runtimeEvaluationArtifact: nearestRuntimeEvaluation.evaluation
|
|
36592
36780
|
} : {}
|
|
36593
|
-
} : {}
|
|
36781
|
+
} : {},
|
|
36782
|
+
...nearestRuntimeEvaluationOutcome ? { runtimeEvaluationOutcome: nearestRuntimeEvaluationOutcome } : {}
|
|
36594
36783
|
};
|
|
36595
36784
|
});
|
|
36596
36785
|
for (const diagnostic of runtimeOnlyDiagnostics) {
|
|
@@ -36637,7 +36826,8 @@ var init_runtimeParityDetails = __esm({
|
|
|
36637
36826
|
runtimeSignals,
|
|
36638
36827
|
runtimeSignalEvaluations,
|
|
36639
36828
|
replaySignals,
|
|
36640
|
-
replaySignalEvaluations
|
|
36829
|
+
replaySignalEvaluations,
|
|
36830
|
+
runtimeLineageScopes
|
|
36641
36831
|
}) => {
|
|
36642
36832
|
const runtimeDetails = runtimeEntries.map(toRuntimeParityDetail);
|
|
36643
36833
|
const backtestDetails = backtestEntries.map(
|
|
@@ -36696,6 +36886,7 @@ var init_runtimeParityDetails = __esm({
|
|
|
36696
36886
|
runtimeSignalEvaluations,
|
|
36697
36887
|
replaySignals,
|
|
36698
36888
|
replaySignalEvaluations,
|
|
36889
|
+
runtimeLineageScopes,
|
|
36699
36890
|
toleranceMs,
|
|
36700
36891
|
backtestTimestampOffsetMs,
|
|
36701
36892
|
limit
|
|
@@ -36716,7 +36907,8 @@ var init_runtimeParityDetails = __esm({
|
|
|
36716
36907
|
runtimeSignals,
|
|
36717
36908
|
runtimeSignalEvaluations,
|
|
36718
36909
|
replaySignals,
|
|
36719
|
-
replaySignalEvaluations
|
|
36910
|
+
replaySignalEvaluations,
|
|
36911
|
+
runtimeLineageScopes
|
|
36720
36912
|
}) => {
|
|
36721
36913
|
const toExchangeDetail = (entry) => toExchangeParityDetail({
|
|
36722
36914
|
entry,
|
|
@@ -36803,6 +36995,7 @@ var init_runtimeParityDetails = __esm({
|
|
|
36803
36995
|
runtimeSignalEvaluations,
|
|
36804
36996
|
replaySignals,
|
|
36805
36997
|
replaySignalEvaluations,
|
|
36998
|
+
runtimeLineageScopes,
|
|
36806
36999
|
toleranceMs,
|
|
36807
37000
|
backtestTimestampOffsetMs,
|
|
36808
37001
|
limit
|
|
@@ -36947,6 +37140,7 @@ var init_runtimeComparisonCalculations = __esm({
|
|
|
36947
37140
|
runtimeTrades: comparableRuntimeTrades,
|
|
36948
37141
|
runtimeSignals: comparableRuntimeSignals,
|
|
36949
37142
|
runtimeSignalEvaluations: comparableRuntimeEvaluations,
|
|
37143
|
+
runtimeLineageScopes: comparableRuntimeLineageScopes,
|
|
36950
37144
|
backtestEntries: comparableBacktestEntries,
|
|
36951
37145
|
lineage: {
|
|
36952
37146
|
enforced: true,
|
|
@@ -37571,6 +37765,7 @@ var init_runtimeComparison = __esm({
|
|
|
37571
37765
|
replaySignalEvaluations,
|
|
37572
37766
|
runtimeSignals,
|
|
37573
37767
|
runtimeSignalEvaluations,
|
|
37768
|
+
runtimeLineageScopes,
|
|
37574
37769
|
lineage
|
|
37575
37770
|
}) => {
|
|
37576
37771
|
const { connector, connectorName, window } = getRuntimeCompareContext();
|
|
@@ -37622,7 +37817,8 @@ var init_runtimeComparison = __esm({
|
|
|
37622
37817
|
runtimeSignals,
|
|
37623
37818
|
runtimeSignalEvaluations,
|
|
37624
37819
|
replaySignals,
|
|
37625
|
-
replaySignalEvaluations
|
|
37820
|
+
replaySignalEvaluations,
|
|
37821
|
+
runtimeLineageScopes
|
|
37626
37822
|
});
|
|
37627
37823
|
const emptyRowsByStrategy = new Map(
|
|
37628
37824
|
buildExchangeComparisonRows({
|
|
@@ -37678,7 +37874,8 @@ var init_runtimeComparison = __esm({
|
|
|
37678
37874
|
runtimeSignals,
|
|
37679
37875
|
runtimeSignalEvaluations,
|
|
37680
37876
|
replaySignals,
|
|
37681
|
-
replaySignalEvaluations
|
|
37877
|
+
replaySignalEvaluations,
|
|
37878
|
+
runtimeLineageScopes
|
|
37682
37879
|
});
|
|
37683
37880
|
const rows = buildExchangeComparisonRows({
|
|
37684
37881
|
liveStrategySummaries,
|
|
@@ -37829,6 +38026,7 @@ var init_runtimeComparison = __esm({
|
|
|
37829
38026
|
replaySignalEvaluations,
|
|
37830
38027
|
runtimeSignals: comparable.runtimeSignals,
|
|
37831
38028
|
runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
|
|
38029
|
+
runtimeLineageScopes: comparable.runtimeLineageScopes,
|
|
37832
38030
|
lineage: comparable.lineage
|
|
37833
38031
|
});
|
|
37834
38032
|
}
|
|
@@ -37852,7 +38050,8 @@ var init_runtimeComparison = __esm({
|
|
|
37852
38050
|
runtimeSignals: comparable.runtimeSignals,
|
|
37853
38051
|
runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
|
|
37854
38052
|
replaySignals,
|
|
37855
|
-
replaySignalEvaluations
|
|
38053
|
+
replaySignalEvaluations,
|
|
38054
|
+
runtimeLineageScopes: comparable.runtimeLineageScopes
|
|
37856
38055
|
});
|
|
37857
38056
|
const parityRows = summarizeTradeParityByStrategy({
|
|
37858
38057
|
runtimeEntries: runtimeDedupe.entries,
|
|
@@ -37895,13 +38094,13 @@ var init_runtimeComparison = __esm({
|
|
|
37895
38094
|
});
|
|
37896
38095
|
|
|
37897
38096
|
// src/lib/replay/outputReport.ts
|
|
37898
|
-
var import_promises33, import_node_path30,
|
|
38097
|
+
var import_promises33, import_node_path30, import_data5, formatMsk, formatNumber5, formatMoney2, formatPct, tableCell, createMarkdownTable2, entryStrategy, entryKey, buildDrilldownMap, buildPerTradeAnalysis, renderMatchedRows, renderRuntimeOnlyRows, renderOrderFailedRows, renderBacktestOnlyRows, renderStrategyRows, renderLineageRows, writeReplayOutputReport;
|
|
37899
38098
|
var init_outputReport = __esm({
|
|
37900
38099
|
"src/lib/replay/outputReport.ts"() {
|
|
37901
38100
|
"use strict";
|
|
37902
38101
|
import_promises33 = __toESM(require("fs/promises"));
|
|
37903
38102
|
import_node_path30 = __toESM(require("path"));
|
|
37904
|
-
|
|
38103
|
+
import_data5 = require("@tradejs/core/data");
|
|
37905
38104
|
init_support();
|
|
37906
38105
|
formatMsk = (timestamp) => typeof timestamp === "number" && Number.isFinite(timestamp) ? new Intl.DateTimeFormat("ru-RU", {
|
|
37907
38106
|
timeZone: "Europe/Moscow",
|
|
@@ -38309,7 +38508,7 @@ var init_outputReport = __esm({
|
|
|
38309
38508
|
];
|
|
38310
38509
|
await Promise.all([
|
|
38311
38510
|
import_promises33.default.writeFile(markdownPath, lines.join("\n"), "utf8"),
|
|
38312
|
-
import_promises33.default.writeFile(jsonPath, `${(0,
|
|
38511
|
+
import_promises33.default.writeFile(jsonPath, `${(0, import_data5.toJson)(report, true)}
|
|
38313
38512
|
`, "utf8")
|
|
38314
38513
|
]);
|
|
38315
38514
|
return {
|
|
@@ -38321,13 +38520,13 @@ var init_outputReport = __esm({
|
|
|
38321
38520
|
});
|
|
38322
38521
|
|
|
38323
38522
|
// src/scripts/replayRunner.ts
|
|
38324
|
-
var import_chalk53, import_constants19,
|
|
38523
|
+
var import_chalk53, import_constants19, import_data6, import_time14, import_redis21, prepareReplayBinanceMarketContext, finishReplay, replayBacktest;
|
|
38325
38524
|
var init_replayRunner = __esm({
|
|
38326
38525
|
"src/scripts/replayRunner.ts"() {
|
|
38327
38526
|
"use strict";
|
|
38328
38527
|
import_chalk53 = __toESM(require("chalk"));
|
|
38329
38528
|
import_constants19 = require("@tradejs/core/constants");
|
|
38330
|
-
|
|
38529
|
+
import_data6 = require("@tradejs/core/data");
|
|
38331
38530
|
import_time14 = require("@tradejs/core/time");
|
|
38332
38531
|
import_redis21 = require("@tradejs/infra/redis");
|
|
38333
38532
|
init_runFormatting();
|
|
@@ -38543,7 +38742,7 @@ var init_replayRunner = __esm({
|
|
|
38543
38742
|
deploymentId: deployment.id,
|
|
38544
38743
|
assetClasses: deployment.assetClasses,
|
|
38545
38744
|
deployment,
|
|
38546
|
-
closedIntervalMs: (0,
|
|
38745
|
+
closedIntervalMs: (0, import_data6.intervalToMs)(replayInterval)
|
|
38547
38746
|
});
|
|
38548
38747
|
if (!preparedRun || isReplayUpdateOnlyRun) {
|
|
38549
38748
|
return;
|
|
@@ -104,6 +104,7 @@ var import_redis2 = require("@tradejs/infra/redis");
|
|
|
104
104
|
|
|
105
105
|
// src/lib/runtimeSignalsStorage.ts
|
|
106
106
|
var import_constants = require("@tradejs/core/constants");
|
|
107
|
+
var import_data = require("@tradejs/core/data");
|
|
107
108
|
var import_time2 = require("@tradejs/core/time");
|
|
108
109
|
var isRuntimeSignalBucketRef = (value) => {
|
|
109
110
|
if (!value || typeof value !== "object") {
|