@tradejs/cli 3.1.26 → 3.1.27-beta.247
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 +436 -45
- package/dist/lib/runtimeDebugEvidence.js +1 -0
- package/dist/lib/runtimeParityDetails.js +128 -6
- 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 +266 -19
- package/dist/scripts/replayRunner.js +266 -19
- package/dist/scripts/replayRuntimeEvidence.js +14 -1
- 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
|
@@ -40,7 +40,7 @@ __export(replayRunner_exports, {
|
|
|
40
40
|
module.exports = __toCommonJS(replayRunner_exports);
|
|
41
41
|
var import_chalk13 = __toESM(require("chalk"));
|
|
42
42
|
var import_constants6 = require("@tradejs/core/constants");
|
|
43
|
-
var
|
|
43
|
+
var import_data4 = require("@tradejs/core/data");
|
|
44
44
|
var import_time7 = require("@tradejs/core/time");
|
|
45
45
|
var import_redis6 = require("@tradejs/infra/redis");
|
|
46
46
|
|
|
@@ -5614,6 +5614,78 @@ var prepareHistoricalReplay = async (context, adapters) => {
|
|
|
5614
5614
|
};
|
|
5615
5615
|
};
|
|
5616
5616
|
|
|
5617
|
+
// src/lib/replay/historicalSignalsReplaySkipEvidence.ts
|
|
5618
|
+
var import_data = require("@tradejs/core/data");
|
|
5619
|
+
var replayScopeKey = (strategy, symbol) => `${strategy}::${symbol}`;
|
|
5620
|
+
var appendReplaySignalEvaluationRun = ({
|
|
5621
|
+
runs = [],
|
|
5622
|
+
reason,
|
|
5623
|
+
timestamp,
|
|
5624
|
+
interval
|
|
5625
|
+
}) => {
|
|
5626
|
+
const stepMs = (0, import_data.intervalToMs)(interval);
|
|
5627
|
+
const last = runs.at(-1);
|
|
5628
|
+
if (last?.reason === reason && last.stepMs === stepMs && timestamp === last.lastTimestamp + stepMs) {
|
|
5629
|
+
return [...runs.slice(0, -1), { ...last, lastTimestamp: timestamp }];
|
|
5630
|
+
}
|
|
5631
|
+
return [
|
|
5632
|
+
...runs,
|
|
5633
|
+
{
|
|
5634
|
+
status: "skip",
|
|
5635
|
+
reason,
|
|
5636
|
+
firstTimestamp: timestamp,
|
|
5637
|
+
lastTimestamp: timestamp,
|
|
5638
|
+
stepMs
|
|
5639
|
+
}
|
|
5640
|
+
];
|
|
5641
|
+
};
|
|
5642
|
+
var createHistoricalReplaySkipEvidence = (runtimeLineages) => {
|
|
5643
|
+
const lineageByStrategySymbol = new Map(
|
|
5644
|
+
runtimeLineages.map((record2) => [
|
|
5645
|
+
replayScopeKey(record2.strategy, record2.symbol),
|
|
5646
|
+
record2
|
|
5647
|
+
])
|
|
5648
|
+
);
|
|
5649
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
5650
|
+
const record = ({
|
|
5651
|
+
strategyName,
|
|
5652
|
+
symbol,
|
|
5653
|
+
strategyConfig,
|
|
5654
|
+
runtimeLineage,
|
|
5655
|
+
timestamp,
|
|
5656
|
+
result
|
|
5657
|
+
}) => {
|
|
5658
|
+
const scopeKey = replayScopeKey(strategyName, symbol);
|
|
5659
|
+
const lineageRecord = lineageByStrategySymbol.get(scopeKey);
|
|
5660
|
+
if (!lineageRecord) return;
|
|
5661
|
+
const existing = scopes.get(scopeKey);
|
|
5662
|
+
const skipReason = typeof result === "string" ? result.trim() || "NO_SIGNAL" : result ? null : "NO_SIGNAL";
|
|
5663
|
+
scopes.set(scopeKey, {
|
|
5664
|
+
strategy: strategyName,
|
|
5665
|
+
symbol,
|
|
5666
|
+
...lineageRecord.deploymentId ? { deploymentId: lineageRecord.deploymentId } : {},
|
|
5667
|
+
...lineageRecord.accountId ? { accountId: lineageRecord.accountId } : {},
|
|
5668
|
+
strategyRevision: runtimeLineage.strategyRevision,
|
|
5669
|
+
lineage: runtimeLineage,
|
|
5670
|
+
firstTimestamp: Math.min(
|
|
5671
|
+
existing?.firstTimestamp ?? timestamp,
|
|
5672
|
+
timestamp
|
|
5673
|
+
),
|
|
5674
|
+
lastTimestamp: Math.max(existing?.lastTimestamp ?? timestamp, timestamp),
|
|
5675
|
+
evaluationRuns: skipReason ? appendReplaySignalEvaluationRun({
|
|
5676
|
+
runs: existing?.evaluationRuns,
|
|
5677
|
+
reason: skipReason,
|
|
5678
|
+
timestamp,
|
|
5679
|
+
interval: strategyConfig.INTERVAL ?? "15"
|
|
5680
|
+
}) : existing?.evaluationRuns
|
|
5681
|
+
});
|
|
5682
|
+
};
|
|
5683
|
+
const values = () => [...scopes.values()].sort(
|
|
5684
|
+
(left, right) => left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol)
|
|
5685
|
+
);
|
|
5686
|
+
return { record, values };
|
|
5687
|
+
};
|
|
5688
|
+
|
|
5617
5689
|
// src/lib/replay/historicalSignalsReplayExecution.ts
|
|
5618
5690
|
var advanceCycleMarket = async (plan, connector, timestamp) => {
|
|
5619
5691
|
const cycleSymbols = plan.cycleSymbolsByTimestamp.get(timestamp) ?? [];
|
|
@@ -5639,6 +5711,9 @@ var advanceAbortedCycle = (cycleSymbols, timestamp) => {
|
|
|
5639
5711
|
var executeHistoricalReplay = async (context, adapters) => {
|
|
5640
5712
|
const signals = [];
|
|
5641
5713
|
let abortedCycles = 0;
|
|
5714
|
+
const skipEvidence = createHistoricalReplaySkipEvidence(
|
|
5715
|
+
context.plan.runtimeLineages
|
|
5716
|
+
);
|
|
5642
5717
|
try {
|
|
5643
5718
|
for (const timestamp of context.plan.orderedTimestamps) {
|
|
5644
5719
|
const cycleStartedAt = adapters.clock.now();
|
|
@@ -5681,6 +5756,14 @@ var executeHistoricalReplay = async (context, adapters) => {
|
|
|
5681
5756
|
btcCandle,
|
|
5682
5757
|
ethCandle?.timestamp === timestamp ? ethCandle : void 0
|
|
5683
5758
|
);
|
|
5759
|
+
skipEvidence.record({
|
|
5760
|
+
strategyName: strategyRuntime.strategyName,
|
|
5761
|
+
symbol: symbolRuntime.symbol,
|
|
5762
|
+
strategyConfig: strategyRuntime.strategyConfig,
|
|
5763
|
+
runtimeLineage: strategyRuntime.runtimeLineage,
|
|
5764
|
+
timestamp,
|
|
5765
|
+
result
|
|
5766
|
+
});
|
|
5684
5767
|
if (result && typeof result !== "string") {
|
|
5685
5768
|
result.runtimeLineage = strategyRuntime.runtimeLineage;
|
|
5686
5769
|
await adapters.enrichSignal(result);
|
|
@@ -5708,7 +5791,11 @@ var executeHistoricalReplay = async (context, adapters) => {
|
|
|
5708
5791
|
adapters.releaseReplayCache(keyPrefix);
|
|
5709
5792
|
}
|
|
5710
5793
|
}
|
|
5711
|
-
return {
|
|
5794
|
+
return {
|
|
5795
|
+
signals,
|
|
5796
|
+
abortedCycles,
|
|
5797
|
+
replayLineageScopes: skipEvidence.values()
|
|
5798
|
+
};
|
|
5712
5799
|
};
|
|
5713
5800
|
|
|
5714
5801
|
// src/lib/replay/historicalSignalsReplayResults.ts
|
|
@@ -5737,7 +5824,8 @@ var collectHistoricalReplayResult = (context) => ({
|
|
|
5737
5824
|
positionLog: context.artifacts.positionLog,
|
|
5738
5825
|
cycleCount: context.cycleCount,
|
|
5739
5826
|
abortedCycles: context.abortedCycles,
|
|
5740
|
-
runtimeLineages: context.runtimeLineages
|
|
5827
|
+
runtimeLineages: context.runtimeLineages,
|
|
5828
|
+
replayLineageScopes: context.replayLineageScopes
|
|
5741
5829
|
});
|
|
5742
5830
|
|
|
5743
5831
|
// src/lib/replay/historicalSignalsReplay.ts
|
|
@@ -5956,7 +6044,8 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5956
6044
|
signals: execution.signals,
|
|
5957
6045
|
cycleCount: plan.orderedTimestamps.length,
|
|
5958
6046
|
abortedCycles: execution.abortedCycles,
|
|
5959
|
-
runtimeLineages: plan.runtimeLineages
|
|
6047
|
+
runtimeLineages: plan.runtimeLineages,
|
|
6048
|
+
replayLineageScopes: execution.replayLineageScopes
|
|
5960
6049
|
});
|
|
5961
6050
|
};
|
|
5962
6051
|
|
|
@@ -6443,6 +6532,7 @@ var import_redis4 = require("@tradejs/infra/redis");
|
|
|
6443
6532
|
|
|
6444
6533
|
// src/lib/runtimeSignalsStorage.ts
|
|
6445
6534
|
var import_constants4 = require("@tradejs/core/constants");
|
|
6535
|
+
var import_data2 = require("@tradejs/core/data");
|
|
6446
6536
|
var import_time4 = require("@tradejs/core/time");
|
|
6447
6537
|
var isRuntimeSignalBucketRef = (value) => {
|
|
6448
6538
|
if (!value || typeof value !== "object") {
|
|
@@ -6991,6 +7081,90 @@ var findNearestEvaluation = ({
|
|
|
6991
7081
|
timestampDiffMs: bestDiff
|
|
6992
7082
|
} : null;
|
|
6993
7083
|
};
|
|
7084
|
+
var findNearestRuntimeEvaluationOutcome = ({
|
|
7085
|
+
entry,
|
|
7086
|
+
lineageScopes,
|
|
7087
|
+
toleranceMs
|
|
7088
|
+
}) => {
|
|
7089
|
+
const strategy = getEntryStrategy(entry);
|
|
7090
|
+
const timestamp = entry.signalTimestamp ?? entry.timestamp;
|
|
7091
|
+
if (!strategy) return null;
|
|
7092
|
+
let nearest = null;
|
|
7093
|
+
for (const scope of lineageScopes) {
|
|
7094
|
+
if (scope.strategy !== strategy || scope.symbol !== entry.symbol) {
|
|
7095
|
+
continue;
|
|
7096
|
+
}
|
|
7097
|
+
for (const run of scope.evaluationRuns ?? []) {
|
|
7098
|
+
if (run.stepMs <= 0 || timestamp < run.firstTimestamp - toleranceMs || timestamp > run.lastTimestamp + toleranceMs) {
|
|
7099
|
+
continue;
|
|
7100
|
+
}
|
|
7101
|
+
const step = Math.round((timestamp - run.firstTimestamp) / run.stepMs);
|
|
7102
|
+
const candidateTimestamp = run.firstTimestamp + step * run.stepMs;
|
|
7103
|
+
const timestampDiffMs = Math.abs(candidateTimestamp - timestamp);
|
|
7104
|
+
if (candidateTimestamp < run.firstTimestamp || candidateTimestamp > run.lastTimestamp || timestampDiffMs > toleranceMs || nearest && timestampDiffMs >= nearest.timestampDiffMs) {
|
|
7105
|
+
continue;
|
|
7106
|
+
}
|
|
7107
|
+
nearest = {
|
|
7108
|
+
status: run.status,
|
|
7109
|
+
reason: run.reason,
|
|
7110
|
+
timestamp: candidateTimestamp,
|
|
7111
|
+
timestampDiffMs,
|
|
7112
|
+
source: "lineage_scope_compact"
|
|
7113
|
+
};
|
|
7114
|
+
}
|
|
7115
|
+
}
|
|
7116
|
+
return nearest;
|
|
7117
|
+
};
|
|
7118
|
+
var findNearestReplayEvaluationOutcome = ({
|
|
7119
|
+
entry,
|
|
7120
|
+
lineageScopes,
|
|
7121
|
+
toleranceMs,
|
|
7122
|
+
timestampOffsetMs
|
|
7123
|
+
}) => {
|
|
7124
|
+
const strategy = getEntryStrategy(entry);
|
|
7125
|
+
if (!strategy) return null;
|
|
7126
|
+
let nearest = null;
|
|
7127
|
+
for (const scope of lineageScopes) {
|
|
7128
|
+
if (scope.strategy !== strategy || scope.symbol !== entry.symbol) {
|
|
7129
|
+
continue;
|
|
7130
|
+
}
|
|
7131
|
+
for (const run of scope.evaluationRuns ?? []) {
|
|
7132
|
+
if (run.stepMs <= 0) continue;
|
|
7133
|
+
const targetTimestamp = entry.timestamp - timestampOffsetMs;
|
|
7134
|
+
if (targetTimestamp < run.firstTimestamp - toleranceMs || targetTimestamp > run.lastTimestamp + toleranceMs) {
|
|
7135
|
+
continue;
|
|
7136
|
+
}
|
|
7137
|
+
const step = Math.round(
|
|
7138
|
+
(targetTimestamp - run.firstTimestamp) / run.stepMs
|
|
7139
|
+
);
|
|
7140
|
+
const candidateTimestamp = run.firstTimestamp + step * run.stepMs;
|
|
7141
|
+
const timestampDiffMs = Math.abs(
|
|
7142
|
+
candidateTimestamp + timestampOffsetMs - entry.timestamp
|
|
7143
|
+
);
|
|
7144
|
+
if (candidateTimestamp < run.firstTimestamp || candidateTimestamp > run.lastTimestamp || timestampDiffMs > toleranceMs || nearest && timestampDiffMs >= nearest.timestampDiffMs) {
|
|
7145
|
+
continue;
|
|
7146
|
+
}
|
|
7147
|
+
nearest = {
|
|
7148
|
+
status: run.status,
|
|
7149
|
+
reason: run.reason,
|
|
7150
|
+
timestamp: candidateTimestamp,
|
|
7151
|
+
timestampDiffMs,
|
|
7152
|
+
source: "replay_scope_compact"
|
|
7153
|
+
};
|
|
7154
|
+
}
|
|
7155
|
+
}
|
|
7156
|
+
return nearest;
|
|
7157
|
+
};
|
|
7158
|
+
var hasRuntimeLineageCoverage = ({
|
|
7159
|
+
entry,
|
|
7160
|
+
lineageScopes
|
|
7161
|
+
}) => {
|
|
7162
|
+
const strategy = getEntryStrategy(entry);
|
|
7163
|
+
const timestamp = entry.signalTimestamp ?? entry.timestamp;
|
|
7164
|
+
return lineageScopes.some(
|
|
7165
|
+
(scope) => scope.strategy === strategy && scope.symbol === entry.symbol && timestamp >= scope.firstTimestamp && timestamp <= scope.lastTimestamp
|
|
7166
|
+
);
|
|
7167
|
+
};
|
|
6994
7168
|
var classifySignalDiagnostic = (signal) => {
|
|
6995
7169
|
if (signal.orderStatus === "failed") {
|
|
6996
7170
|
return {
|
|
@@ -7235,6 +7409,8 @@ var buildReplayMismatchDrilldown = ({
|
|
|
7235
7409
|
runtimeSignalEvaluations = [],
|
|
7236
7410
|
replaySignals = [],
|
|
7237
7411
|
replaySignalEvaluations = [],
|
|
7412
|
+
replayLineageScopes = [],
|
|
7413
|
+
runtimeLineageScopes = [],
|
|
7238
7414
|
toleranceMs,
|
|
7239
7415
|
backtestTimestampOffsetMs,
|
|
7240
7416
|
limit
|
|
@@ -7260,7 +7436,16 @@ var buildReplayMismatchDrilldown = ({
|
|
|
7260
7436
|
toleranceMs,
|
|
7261
7437
|
timestampOffsetMs: backtestTimestampOffsetMs
|
|
7262
7438
|
});
|
|
7263
|
-
const
|
|
7439
|
+
const nearestReplayEvaluationOutcome = findNearestReplayEvaluationOutcome({
|
|
7440
|
+
entry,
|
|
7441
|
+
lineageScopes: replayLineageScopes,
|
|
7442
|
+
toleranceMs,
|
|
7443
|
+
timestampOffsetMs: backtestTimestampOffsetMs
|
|
7444
|
+
});
|
|
7445
|
+
const classification = nearestReplaySignal ? classifySignalDiagnostic(nearestReplaySignal.signal) : nearestReplayEvaluation ? classifyEvaluationDiagnostic(nearestReplayEvaluation.evaluation) : nearestReplayEvaluationOutcome ? {
|
|
7446
|
+
classification: "core_skipped",
|
|
7447
|
+
reason: nearestReplayEvaluationOutcome.reason
|
|
7448
|
+
} : nearestCandidate?.nearest ? {
|
|
7264
7449
|
classification: "timing_or_price_drift",
|
|
7265
7450
|
reason: nearestCandidate.reason
|
|
7266
7451
|
} : {
|
|
@@ -7284,7 +7469,8 @@ var buildReplayMismatchDrilldown = ({
|
|
|
7284
7469
|
timestampDiffMs: nearestReplayEvaluation.timestampDiffMs
|
|
7285
7470
|
}),
|
|
7286
7471
|
...includeArtifacts ? { replayEvaluationArtifact: nearestReplayEvaluation.evaluation } : {}
|
|
7287
|
-
} : {}
|
|
7472
|
+
} : {},
|
|
7473
|
+
...nearestReplayEvaluationOutcome ? { replayEvaluationOutcome: nearestReplayEvaluationOutcome } : {}
|
|
7288
7474
|
};
|
|
7289
7475
|
});
|
|
7290
7476
|
const backtestOnlyDiagnostics = backtestOnly.map((entry, index) => {
|
|
@@ -7302,9 +7488,26 @@ var buildReplayMismatchDrilldown = ({
|
|
|
7302
7488
|
toleranceMs,
|
|
7303
7489
|
timestampOffsetMs: 0
|
|
7304
7490
|
});
|
|
7305
|
-
const
|
|
7491
|
+
const nearestRuntimeEvaluationOutcome = findNearestRuntimeEvaluationOutcome(
|
|
7492
|
+
{
|
|
7493
|
+
entry,
|
|
7494
|
+
lineageScopes: runtimeLineageScopes,
|
|
7495
|
+
toleranceMs
|
|
7496
|
+
}
|
|
7497
|
+
);
|
|
7498
|
+
const runtimeLineageCoversEntry = hasRuntimeLineageCoverage({
|
|
7499
|
+
entry,
|
|
7500
|
+
lineageScopes: runtimeLineageScopes
|
|
7501
|
+
});
|
|
7502
|
+
const classification = nearestRuntimeSignal ? classifySignalDiagnostic(nearestRuntimeSignal.signal) : nearestRuntimeEvaluation ? classifyEvaluationDiagnostic(nearestRuntimeEvaluation.evaluation) : nearestRuntimeEvaluationOutcome ? {
|
|
7503
|
+
classification: "core_skipped",
|
|
7504
|
+
reason: nearestRuntimeEvaluationOutcome.reason
|
|
7505
|
+
} : nearestCandidate?.nearest ? {
|
|
7306
7506
|
classification: "timing_or_price_drift",
|
|
7307
7507
|
reason: nearestCandidate.reason
|
|
7508
|
+
} : runtimeLineageCoversEntry ? {
|
|
7509
|
+
classification: "runtime_evaluation_detail_unavailable",
|
|
7510
|
+
reason: "runtime_scope_covers_timestamp_but_skip_detail_was_not_stored"
|
|
7308
7511
|
} : {
|
|
7309
7512
|
classification: "no_runtime_evaluation",
|
|
7310
7513
|
reason: "no_runtime_signal_or_evaluation"
|
|
@@ -7328,7 +7531,8 @@ var buildReplayMismatchDrilldown = ({
|
|
|
7328
7531
|
...includeArtifacts ? {
|
|
7329
7532
|
runtimeEvaluationArtifact: nearestRuntimeEvaluation.evaluation
|
|
7330
7533
|
} : {}
|
|
7331
|
-
} : {}
|
|
7534
|
+
} : {},
|
|
7535
|
+
...nearestRuntimeEvaluationOutcome ? { runtimeEvaluationOutcome: nearestRuntimeEvaluationOutcome } : {}
|
|
7332
7536
|
};
|
|
7333
7537
|
});
|
|
7334
7538
|
for (const diagnostic of runtimeOnlyDiagnostics) {
|
|
@@ -7375,7 +7579,9 @@ var buildReplayRuntimeComparisonDetails = ({
|
|
|
7375
7579
|
runtimeSignals,
|
|
7376
7580
|
runtimeSignalEvaluations,
|
|
7377
7581
|
replaySignals,
|
|
7378
|
-
replaySignalEvaluations
|
|
7582
|
+
replaySignalEvaluations,
|
|
7583
|
+
replayLineageScopes,
|
|
7584
|
+
runtimeLineageScopes
|
|
7379
7585
|
}) => {
|
|
7380
7586
|
const runtimeDetails = runtimeEntries.map(toRuntimeParityDetail);
|
|
7381
7587
|
const backtestDetails = backtestEntries.map(
|
|
@@ -7434,6 +7640,8 @@ var buildReplayRuntimeComparisonDetails = ({
|
|
|
7434
7640
|
runtimeSignalEvaluations,
|
|
7435
7641
|
replaySignals,
|
|
7436
7642
|
replaySignalEvaluations,
|
|
7643
|
+
replayLineageScopes,
|
|
7644
|
+
runtimeLineageScopes,
|
|
7437
7645
|
toleranceMs,
|
|
7438
7646
|
backtestTimestampOffsetMs,
|
|
7439
7647
|
limit
|
|
@@ -7454,7 +7662,9 @@ var buildReplayExchangeComparisonDetails = ({
|
|
|
7454
7662
|
runtimeSignals,
|
|
7455
7663
|
runtimeSignalEvaluations,
|
|
7456
7664
|
replaySignals,
|
|
7457
|
-
replaySignalEvaluations
|
|
7665
|
+
replaySignalEvaluations,
|
|
7666
|
+
replayLineageScopes,
|
|
7667
|
+
runtimeLineageScopes
|
|
7458
7668
|
}) => {
|
|
7459
7669
|
const toExchangeDetail = (entry) => toExchangeParityDetail({
|
|
7460
7670
|
entry,
|
|
@@ -7541,6 +7751,8 @@ var buildReplayExchangeComparisonDetails = ({
|
|
|
7541
7751
|
runtimeSignalEvaluations,
|
|
7542
7752
|
replaySignals,
|
|
7543
7753
|
replaySignalEvaluations,
|
|
7754
|
+
replayLineageScopes,
|
|
7755
|
+
runtimeLineageScopes,
|
|
7544
7756
|
toleranceMs,
|
|
7545
7757
|
backtestTimestampOffsetMs,
|
|
7546
7758
|
limit
|
|
@@ -7663,19 +7875,41 @@ var filterReplayComparisonByLineage = ({
|
|
|
7663
7875
|
lineageScopeKey(record)
|
|
7664
7876
|
])
|
|
7665
7877
|
);
|
|
7666
|
-
const comparableBacktestEntries =
|
|
7878
|
+
const comparableBacktestEntries = [];
|
|
7879
|
+
const excludedBacktestEntryDetails = [];
|
|
7880
|
+
for (const entry of backtestEntries) {
|
|
7667
7881
|
const replayScope = replayScopeByStrategySymbol.get(
|
|
7668
7882
|
`${entry.strategy}::${entry.symbol}`
|
|
7669
7883
|
);
|
|
7670
7884
|
const window = replayScope ? deploymentWindows.get(replayScope) : null;
|
|
7671
7885
|
const signalTimestamp = entry.signalTimestamp ?? entry.timestamp;
|
|
7672
|
-
|
|
7673
|
-
|
|
7886
|
+
if (window != null && signalTimestamp >= window.firstTimestamp && signalTimestamp <= window.lastTimestamp) {
|
|
7887
|
+
comparableBacktestEntries.push(entry);
|
|
7888
|
+
continue;
|
|
7889
|
+
}
|
|
7890
|
+
const reason = !replayScope ? "replay_scope_missing" : !window ? "runtime_scope_missing" : signalTimestamp < window.firstTimestamp ? "before_runtime_window" : "after_runtime_window";
|
|
7891
|
+
excludedBacktestEntryDetails.push({
|
|
7892
|
+
id: entry.id,
|
|
7893
|
+
strategy: entry.strategy,
|
|
7894
|
+
symbol: entry.symbol,
|
|
7895
|
+
direction: entry.direction,
|
|
7896
|
+
...entry.qty != null ? { qty: entry.qty } : {},
|
|
7897
|
+
timestamp: entry.timestamp,
|
|
7898
|
+
...entry.signalTimestamp != null ? { signalTimestamp: entry.signalTimestamp } : {},
|
|
7899
|
+
price: entry.price,
|
|
7900
|
+
...entry.orderId ? { orderId: entry.orderId } : {},
|
|
7901
|
+
...entry.signalId ? { signalId: entry.signalId } : {},
|
|
7902
|
+
...entry.expectedPnl != null ? { expectedPnl: entry.expectedPnl } : {},
|
|
7903
|
+
reason,
|
|
7904
|
+
runtimeWindow: window ?? null
|
|
7905
|
+
});
|
|
7906
|
+
}
|
|
7674
7907
|
const comparableScopeKeys = new Set(deploymentWindows.keys());
|
|
7675
7908
|
return {
|
|
7676
7909
|
runtimeTrades: comparableRuntimeTrades,
|
|
7677
7910
|
runtimeSignals: comparableRuntimeSignals,
|
|
7678
7911
|
runtimeSignalEvaluations: comparableRuntimeEvaluations,
|
|
7912
|
+
runtimeLineageScopes: comparableRuntimeLineageScopes,
|
|
7679
7913
|
backtestEntries: comparableBacktestEntries,
|
|
7680
7914
|
lineage: {
|
|
7681
7915
|
enforced: true,
|
|
@@ -7687,6 +7921,7 @@ var filterReplayComparisonByLineage = ({
|
|
|
7687
7921
|
excludedRuntimeLineageScopes: runtimeLineageScopes.length - comparableRuntimeLineageScopes.length,
|
|
7688
7922
|
excludedExchangeEntries: 0,
|
|
7689
7923
|
excludedBacktestEntries: backtestEntries.length - comparableBacktestEntries.length,
|
|
7924
|
+
excludedBacktestEntryDetails,
|
|
7690
7925
|
reason: comparableScopeKeys.size > 0 ? null : expectedByScope.size === 0 ? "replay_produced_no_lineage_scopes" : "no_runtime_artifacts_with_matching_lineage",
|
|
7691
7926
|
replay: [...expectedByScope.entries()].map(([scope, lineage]) => {
|
|
7692
7927
|
const [deploymentId, accountId, strategy, symbol] = scope.split("::");
|
|
@@ -8270,8 +8505,10 @@ var saveAndPrintReplayExchangeComparison = async ({
|
|
|
8270
8505
|
backtestEntries,
|
|
8271
8506
|
replaySignals,
|
|
8272
8507
|
replaySignalEvaluations,
|
|
8508
|
+
replayLineageScopes,
|
|
8273
8509
|
runtimeSignals,
|
|
8274
8510
|
runtimeSignalEvaluations,
|
|
8511
|
+
runtimeLineageScopes,
|
|
8275
8512
|
lineage
|
|
8276
8513
|
}) => {
|
|
8277
8514
|
const { connector, connectorName, window } = getRuntimeCompareContext();
|
|
@@ -8323,7 +8560,9 @@ var saveAndPrintReplayExchangeComparison = async ({
|
|
|
8323
8560
|
runtimeSignals,
|
|
8324
8561
|
runtimeSignalEvaluations,
|
|
8325
8562
|
replaySignals,
|
|
8326
|
-
replaySignalEvaluations
|
|
8563
|
+
replaySignalEvaluations,
|
|
8564
|
+
runtimeLineageScopes,
|
|
8565
|
+
replayLineageScopes
|
|
8327
8566
|
});
|
|
8328
8567
|
const emptyRowsByStrategy = new Map(
|
|
8329
8568
|
buildExchangeComparisonRows({
|
|
@@ -8379,7 +8618,9 @@ var saveAndPrintReplayExchangeComparison = async ({
|
|
|
8379
8618
|
runtimeSignals,
|
|
8380
8619
|
runtimeSignalEvaluations,
|
|
8381
8620
|
replaySignals,
|
|
8382
|
-
replaySignalEvaluations
|
|
8621
|
+
replaySignalEvaluations,
|
|
8622
|
+
runtimeLineageScopes,
|
|
8623
|
+
replayLineageScopes
|
|
8383
8624
|
});
|
|
8384
8625
|
const rows = buildExchangeComparisonRows({
|
|
8385
8626
|
liveStrategySummaries,
|
|
@@ -8417,6 +8658,7 @@ var saveAndPrintReplayRuntimeComparison = async ({
|
|
|
8417
8658
|
backtestEntries,
|
|
8418
8659
|
replaySignals,
|
|
8419
8660
|
replayLineages,
|
|
8661
|
+
replayLineageScopes,
|
|
8420
8662
|
runtimeEvidencePath
|
|
8421
8663
|
}) => {
|
|
8422
8664
|
const { connector, connectorName, window } = getRuntimeCompareContext();
|
|
@@ -8528,8 +8770,10 @@ var saveAndPrintReplayRuntimeComparison = async ({
|
|
|
8528
8770
|
backtestEntries: comparableBacktestEntries,
|
|
8529
8771
|
replaySignals,
|
|
8530
8772
|
replaySignalEvaluations,
|
|
8773
|
+
replayLineageScopes,
|
|
8531
8774
|
runtimeSignals: comparable.runtimeSignals,
|
|
8532
8775
|
runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
|
|
8776
|
+
runtimeLineageScopes: comparable.runtimeLineageScopes,
|
|
8533
8777
|
lineage: comparable.lineage
|
|
8534
8778
|
});
|
|
8535
8779
|
}
|
|
@@ -8553,7 +8797,9 @@ var saveAndPrintReplayRuntimeComparison = async ({
|
|
|
8553
8797
|
runtimeSignals: comparable.runtimeSignals,
|
|
8554
8798
|
runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
|
|
8555
8799
|
replaySignals,
|
|
8556
|
-
replaySignalEvaluations
|
|
8800
|
+
replaySignalEvaluations,
|
|
8801
|
+
runtimeLineageScopes: comparable.runtimeLineageScopes,
|
|
8802
|
+
replayLineageScopes
|
|
8557
8803
|
});
|
|
8558
8804
|
const parityRows = summarizeTradeParityByStrategy({
|
|
8559
8805
|
runtimeEntries: runtimeDedupe.entries,
|
|
@@ -8596,7 +8842,7 @@ var saveAndPrintReplayRuntimeComparison = async ({
|
|
|
8596
8842
|
// src/lib/replay/outputReport.ts
|
|
8597
8843
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
8598
8844
|
var import_node_path2 = __toESM(require("path"));
|
|
8599
|
-
var
|
|
8845
|
+
var import_data3 = require("@tradejs/core/data");
|
|
8600
8846
|
var formatMsk = (timestamp) => typeof timestamp === "number" && Number.isFinite(timestamp) ? new Intl.DateTimeFormat("ru-RU", {
|
|
8601
8847
|
timeZone: "Europe/Moscow",
|
|
8602
8848
|
dateStyle: "short",
|
|
@@ -9003,7 +9249,7 @@ var writeReplayOutputReport = async ({
|
|
|
9003
9249
|
];
|
|
9004
9250
|
await Promise.all([
|
|
9005
9251
|
import_promises2.default.writeFile(markdownPath, lines.join("\n"), "utf8"),
|
|
9006
|
-
import_promises2.default.writeFile(jsonPath, `${(0,
|
|
9252
|
+
import_promises2.default.writeFile(jsonPath, `${(0, import_data3.toJson)(report, true)}
|
|
9007
9253
|
`, "utf8")
|
|
9008
9254
|
]);
|
|
9009
9255
|
return {
|
|
@@ -9045,6 +9291,7 @@ var finishReplay = async ({
|
|
|
9045
9291
|
backtestEntries: replayStrategySnapshot.backtestEntries,
|
|
9046
9292
|
replaySignals: replayResult.signals,
|
|
9047
9293
|
replayLineages: replayResult.runtimeLineages,
|
|
9294
|
+
replayLineageScopes: replayResult.replayLineageScopes,
|
|
9048
9295
|
runtimeEvidencePath: replayRuntimeEvidencePath
|
|
9049
9296
|
});
|
|
9050
9297
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
@@ -9211,7 +9458,7 @@ var replayBacktest = async () => {
|
|
|
9211
9458
|
deploymentId: deployment.id,
|
|
9212
9459
|
assetClasses: deployment.assetClasses,
|
|
9213
9460
|
deployment,
|
|
9214
|
-
closedIntervalMs: (0,
|
|
9461
|
+
closedIntervalMs: (0, import_data4.intervalToMs)(replayInterval)
|
|
9215
9462
|
});
|
|
9216
9463
|
if (!preparedRun || isReplayUpdateOnlyRun) {
|
|
9217
9464
|
return;
|
|
@@ -117,6 +117,7 @@ var import_redis2 = require("@tradejs/infra/redis");
|
|
|
117
117
|
|
|
118
118
|
// src/lib/runtimeSignalsStorage.ts
|
|
119
119
|
var import_constants = require("@tradejs/core/constants");
|
|
120
|
+
var import_data = require("@tradejs/core/data");
|
|
120
121
|
var import_time2 = require("@tradejs/core/time");
|
|
121
122
|
var isRuntimeSignalBucketRef = (value) => {
|
|
122
123
|
if (!value || typeof value !== "object") {
|
|
@@ -540,9 +541,21 @@ var summarizeReplayComparison = (runtimeComparison, strategies) => {
|
|
|
540
541
|
const replayLineage = asArray(comparisonLineage.replay).filter(
|
|
541
542
|
(entry) => !useFilter || strategySet.has(String(asRecord(entry).strategy ?? ""))
|
|
542
543
|
);
|
|
544
|
+
const hasExcludedBacktestEntryDetails = Array.isArray(
|
|
545
|
+
comparisonLineage.excludedBacktestEntryDetails
|
|
546
|
+
);
|
|
547
|
+
const excludedBacktestEntryDetails = asArray(
|
|
548
|
+
comparisonLineage.excludedBacktestEntryDetails
|
|
549
|
+
).filter(
|
|
550
|
+
(entry) => !useFilter || strategySet.has(String(asRecord(entry).strategy ?? ""))
|
|
551
|
+
);
|
|
543
552
|
return {
|
|
544
553
|
mode: comparison.mode ?? null,
|
|
545
|
-
lineage: comparisonLineage ? {
|
|
554
|
+
lineage: comparisonLineage ? {
|
|
555
|
+
...comparisonLineage,
|
|
556
|
+
replay: replayLineage,
|
|
557
|
+
...hasExcludedBacktestEntryDetails ? { excludedBacktestEntryDetails } : {}
|
|
558
|
+
} : null,
|
|
546
559
|
rows: asArray(comparison.rows).filter(
|
|
547
560
|
(row) => !useFilter || strategySet.has(String(row.strategyName ?? ""))
|
|
548
561
|
),
|
|
@@ -115,6 +115,7 @@ var import_redis2 = require("@tradejs/infra/redis");
|
|
|
115
115
|
|
|
116
116
|
// src/lib/runtimeSignalsStorage.ts
|
|
117
117
|
var import_constants = require("@tradejs/core/constants");
|
|
118
|
+
var import_data = require("@tradejs/core/data");
|
|
118
119
|
var import_time2 = require("@tradejs/core/time");
|
|
119
120
|
var isRuntimeSignalBucketRef = (value) => {
|
|
120
121
|
if (!value || typeof value !== "object") {
|
|
@@ -394,6 +394,7 @@ var import_redis2 = require("@tradejs/infra/redis");
|
|
|
394
394
|
|
|
395
395
|
// src/lib/runtimeSignalsStorage.ts
|
|
396
396
|
var import_constants = require("@tradejs/core/constants");
|
|
397
|
+
var import_data = require("@tradejs/core/data");
|
|
397
398
|
var import_time2 = require("@tradejs/core/time");
|
|
398
399
|
var isRuntimeSignalBucketRef = (value) => {
|
|
399
400
|
if (!value || typeof value !== "object") {
|