@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
package/dist/scripts/replay.js
CHANGED
|
@@ -37,7 +37,7 @@ module.exports = __toCommonJS(replay_exports);
|
|
|
37
37
|
// src/scripts/replayRunner.ts
|
|
38
38
|
var import_chalk13 = __toESM(require("chalk"));
|
|
39
39
|
var import_constants6 = require("@tradejs/core/constants");
|
|
40
|
-
var
|
|
40
|
+
var import_data4 = require("@tradejs/core/data");
|
|
41
41
|
var import_time7 = require("@tradejs/core/time");
|
|
42
42
|
var import_redis6 = require("@tradejs/infra/redis");
|
|
43
43
|
|
|
@@ -5611,6 +5611,78 @@ var prepareHistoricalReplay = async (context, adapters) => {
|
|
|
5611
5611
|
};
|
|
5612
5612
|
};
|
|
5613
5613
|
|
|
5614
|
+
// src/lib/replay/historicalSignalsReplaySkipEvidence.ts
|
|
5615
|
+
var import_data = require("@tradejs/core/data");
|
|
5616
|
+
var replayScopeKey = (strategy, symbol) => `${strategy}::${symbol}`;
|
|
5617
|
+
var appendReplaySignalEvaluationRun = ({
|
|
5618
|
+
runs = [],
|
|
5619
|
+
reason,
|
|
5620
|
+
timestamp,
|
|
5621
|
+
interval
|
|
5622
|
+
}) => {
|
|
5623
|
+
const stepMs = (0, import_data.intervalToMs)(interval);
|
|
5624
|
+
const last = runs.at(-1);
|
|
5625
|
+
if (last?.reason === reason && last.stepMs === stepMs && timestamp === last.lastTimestamp + stepMs) {
|
|
5626
|
+
return [...runs.slice(0, -1), { ...last, lastTimestamp: timestamp }];
|
|
5627
|
+
}
|
|
5628
|
+
return [
|
|
5629
|
+
...runs,
|
|
5630
|
+
{
|
|
5631
|
+
status: "skip",
|
|
5632
|
+
reason,
|
|
5633
|
+
firstTimestamp: timestamp,
|
|
5634
|
+
lastTimestamp: timestamp,
|
|
5635
|
+
stepMs
|
|
5636
|
+
}
|
|
5637
|
+
];
|
|
5638
|
+
};
|
|
5639
|
+
var createHistoricalReplaySkipEvidence = (runtimeLineages) => {
|
|
5640
|
+
const lineageByStrategySymbol = new Map(
|
|
5641
|
+
runtimeLineages.map((record2) => [
|
|
5642
|
+
replayScopeKey(record2.strategy, record2.symbol),
|
|
5643
|
+
record2
|
|
5644
|
+
])
|
|
5645
|
+
);
|
|
5646
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
5647
|
+
const record = ({
|
|
5648
|
+
strategyName,
|
|
5649
|
+
symbol,
|
|
5650
|
+
strategyConfig,
|
|
5651
|
+
runtimeLineage,
|
|
5652
|
+
timestamp,
|
|
5653
|
+
result
|
|
5654
|
+
}) => {
|
|
5655
|
+
const scopeKey = replayScopeKey(strategyName, symbol);
|
|
5656
|
+
const lineageRecord = lineageByStrategySymbol.get(scopeKey);
|
|
5657
|
+
if (!lineageRecord) return;
|
|
5658
|
+
const existing = scopes.get(scopeKey);
|
|
5659
|
+
const skipReason = typeof result === "string" ? result.trim() || "NO_SIGNAL" : result ? null : "NO_SIGNAL";
|
|
5660
|
+
scopes.set(scopeKey, {
|
|
5661
|
+
strategy: strategyName,
|
|
5662
|
+
symbol,
|
|
5663
|
+
...lineageRecord.deploymentId ? { deploymentId: lineageRecord.deploymentId } : {},
|
|
5664
|
+
...lineageRecord.accountId ? { accountId: lineageRecord.accountId } : {},
|
|
5665
|
+
strategyRevision: runtimeLineage.strategyRevision,
|
|
5666
|
+
lineage: runtimeLineage,
|
|
5667
|
+
firstTimestamp: Math.min(
|
|
5668
|
+
existing?.firstTimestamp ?? timestamp,
|
|
5669
|
+
timestamp
|
|
5670
|
+
),
|
|
5671
|
+
lastTimestamp: Math.max(existing?.lastTimestamp ?? timestamp, timestamp),
|
|
5672
|
+
evaluationRuns: skipReason ? appendReplaySignalEvaluationRun({
|
|
5673
|
+
runs: existing?.evaluationRuns,
|
|
5674
|
+
reason: skipReason,
|
|
5675
|
+
timestamp,
|
|
5676
|
+
interval: strategyConfig.INTERVAL ?? "15"
|
|
5677
|
+
}) : existing?.evaluationRuns
|
|
5678
|
+
});
|
|
5679
|
+
};
|
|
5680
|
+
const values = () => [...scopes.values()].sort(
|
|
5681
|
+
(left, right) => left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol)
|
|
5682
|
+
);
|
|
5683
|
+
return { record, values };
|
|
5684
|
+
};
|
|
5685
|
+
|
|
5614
5686
|
// src/lib/replay/historicalSignalsReplayExecution.ts
|
|
5615
5687
|
var advanceCycleMarket = async (plan, connector, timestamp) => {
|
|
5616
5688
|
const cycleSymbols = plan.cycleSymbolsByTimestamp.get(timestamp) ?? [];
|
|
@@ -5636,6 +5708,9 @@ var advanceAbortedCycle = (cycleSymbols, timestamp) => {
|
|
|
5636
5708
|
var executeHistoricalReplay = async (context, adapters) => {
|
|
5637
5709
|
const signals = [];
|
|
5638
5710
|
let abortedCycles = 0;
|
|
5711
|
+
const skipEvidence = createHistoricalReplaySkipEvidence(
|
|
5712
|
+
context.plan.runtimeLineages
|
|
5713
|
+
);
|
|
5639
5714
|
try {
|
|
5640
5715
|
for (const timestamp of context.plan.orderedTimestamps) {
|
|
5641
5716
|
const cycleStartedAt = adapters.clock.now();
|
|
@@ -5678,6 +5753,14 @@ var executeHistoricalReplay = async (context, adapters) => {
|
|
|
5678
5753
|
btcCandle,
|
|
5679
5754
|
ethCandle?.timestamp === timestamp ? ethCandle : void 0
|
|
5680
5755
|
);
|
|
5756
|
+
skipEvidence.record({
|
|
5757
|
+
strategyName: strategyRuntime.strategyName,
|
|
5758
|
+
symbol: symbolRuntime.symbol,
|
|
5759
|
+
strategyConfig: strategyRuntime.strategyConfig,
|
|
5760
|
+
runtimeLineage: strategyRuntime.runtimeLineage,
|
|
5761
|
+
timestamp,
|
|
5762
|
+
result
|
|
5763
|
+
});
|
|
5681
5764
|
if (result && typeof result !== "string") {
|
|
5682
5765
|
result.runtimeLineage = strategyRuntime.runtimeLineage;
|
|
5683
5766
|
await adapters.enrichSignal(result);
|
|
@@ -5705,7 +5788,11 @@ var executeHistoricalReplay = async (context, adapters) => {
|
|
|
5705
5788
|
adapters.releaseReplayCache(keyPrefix);
|
|
5706
5789
|
}
|
|
5707
5790
|
}
|
|
5708
|
-
return {
|
|
5791
|
+
return {
|
|
5792
|
+
signals,
|
|
5793
|
+
abortedCycles,
|
|
5794
|
+
replayLineageScopes: skipEvidence.values()
|
|
5795
|
+
};
|
|
5709
5796
|
};
|
|
5710
5797
|
|
|
5711
5798
|
// src/lib/replay/historicalSignalsReplayResults.ts
|
|
@@ -5734,7 +5821,8 @@ var collectHistoricalReplayResult = (context) => ({
|
|
|
5734
5821
|
positionLog: context.artifacts.positionLog,
|
|
5735
5822
|
cycleCount: context.cycleCount,
|
|
5736
5823
|
abortedCycles: context.abortedCycles,
|
|
5737
|
-
runtimeLineages: context.runtimeLineages
|
|
5824
|
+
runtimeLineages: context.runtimeLineages,
|
|
5825
|
+
replayLineageScopes: context.replayLineageScopes
|
|
5738
5826
|
});
|
|
5739
5827
|
|
|
5740
5828
|
// src/lib/replay/historicalSignalsReplay.ts
|
|
@@ -5953,7 +6041,8 @@ var runHistoricalSignalsReplay = async ({
|
|
|
5953
6041
|
signals: execution.signals,
|
|
5954
6042
|
cycleCount: plan.orderedTimestamps.length,
|
|
5955
6043
|
abortedCycles: execution.abortedCycles,
|
|
5956
|
-
runtimeLineages: plan.runtimeLineages
|
|
6044
|
+
runtimeLineages: plan.runtimeLineages,
|
|
6045
|
+
replayLineageScopes: execution.replayLineageScopes
|
|
5957
6046
|
});
|
|
5958
6047
|
};
|
|
5959
6048
|
|
|
@@ -6440,6 +6529,7 @@ var import_redis4 = require("@tradejs/infra/redis");
|
|
|
6440
6529
|
|
|
6441
6530
|
// src/lib/runtimeSignalsStorage.ts
|
|
6442
6531
|
var import_constants4 = require("@tradejs/core/constants");
|
|
6532
|
+
var import_data2 = require("@tradejs/core/data");
|
|
6443
6533
|
var import_time4 = require("@tradejs/core/time");
|
|
6444
6534
|
var isRuntimeSignalBucketRef = (value) => {
|
|
6445
6535
|
if (!value || typeof value !== "object") {
|
|
@@ -6988,6 +7078,90 @@ var findNearestEvaluation = ({
|
|
|
6988
7078
|
timestampDiffMs: bestDiff
|
|
6989
7079
|
} : null;
|
|
6990
7080
|
};
|
|
7081
|
+
var findNearestRuntimeEvaluationOutcome = ({
|
|
7082
|
+
entry,
|
|
7083
|
+
lineageScopes,
|
|
7084
|
+
toleranceMs
|
|
7085
|
+
}) => {
|
|
7086
|
+
const strategy = getEntryStrategy(entry);
|
|
7087
|
+
const timestamp = entry.signalTimestamp ?? entry.timestamp;
|
|
7088
|
+
if (!strategy) return null;
|
|
7089
|
+
let nearest = null;
|
|
7090
|
+
for (const scope of lineageScopes) {
|
|
7091
|
+
if (scope.strategy !== strategy || scope.symbol !== entry.symbol) {
|
|
7092
|
+
continue;
|
|
7093
|
+
}
|
|
7094
|
+
for (const run of scope.evaluationRuns ?? []) {
|
|
7095
|
+
if (run.stepMs <= 0 || timestamp < run.firstTimestamp - toleranceMs || timestamp > run.lastTimestamp + toleranceMs) {
|
|
7096
|
+
continue;
|
|
7097
|
+
}
|
|
7098
|
+
const step = Math.round((timestamp - run.firstTimestamp) / run.stepMs);
|
|
7099
|
+
const candidateTimestamp = run.firstTimestamp + step * run.stepMs;
|
|
7100
|
+
const timestampDiffMs = Math.abs(candidateTimestamp - timestamp);
|
|
7101
|
+
if (candidateTimestamp < run.firstTimestamp || candidateTimestamp > run.lastTimestamp || timestampDiffMs > toleranceMs || nearest && timestampDiffMs >= nearest.timestampDiffMs) {
|
|
7102
|
+
continue;
|
|
7103
|
+
}
|
|
7104
|
+
nearest = {
|
|
7105
|
+
status: run.status,
|
|
7106
|
+
reason: run.reason,
|
|
7107
|
+
timestamp: candidateTimestamp,
|
|
7108
|
+
timestampDiffMs,
|
|
7109
|
+
source: "lineage_scope_compact"
|
|
7110
|
+
};
|
|
7111
|
+
}
|
|
7112
|
+
}
|
|
7113
|
+
return nearest;
|
|
7114
|
+
};
|
|
7115
|
+
var findNearestReplayEvaluationOutcome = ({
|
|
7116
|
+
entry,
|
|
7117
|
+
lineageScopes,
|
|
7118
|
+
toleranceMs,
|
|
7119
|
+
timestampOffsetMs
|
|
7120
|
+
}) => {
|
|
7121
|
+
const strategy = getEntryStrategy(entry);
|
|
7122
|
+
if (!strategy) return null;
|
|
7123
|
+
let nearest = null;
|
|
7124
|
+
for (const scope of lineageScopes) {
|
|
7125
|
+
if (scope.strategy !== strategy || scope.symbol !== entry.symbol) {
|
|
7126
|
+
continue;
|
|
7127
|
+
}
|
|
7128
|
+
for (const run of scope.evaluationRuns ?? []) {
|
|
7129
|
+
if (run.stepMs <= 0) continue;
|
|
7130
|
+
const targetTimestamp = entry.timestamp - timestampOffsetMs;
|
|
7131
|
+
if (targetTimestamp < run.firstTimestamp - toleranceMs || targetTimestamp > run.lastTimestamp + toleranceMs) {
|
|
7132
|
+
continue;
|
|
7133
|
+
}
|
|
7134
|
+
const step = Math.round(
|
|
7135
|
+
(targetTimestamp - run.firstTimestamp) / run.stepMs
|
|
7136
|
+
);
|
|
7137
|
+
const candidateTimestamp = run.firstTimestamp + step * run.stepMs;
|
|
7138
|
+
const timestampDiffMs = Math.abs(
|
|
7139
|
+
candidateTimestamp + timestampOffsetMs - entry.timestamp
|
|
7140
|
+
);
|
|
7141
|
+
if (candidateTimestamp < run.firstTimestamp || candidateTimestamp > run.lastTimestamp || timestampDiffMs > toleranceMs || nearest && timestampDiffMs >= nearest.timestampDiffMs) {
|
|
7142
|
+
continue;
|
|
7143
|
+
}
|
|
7144
|
+
nearest = {
|
|
7145
|
+
status: run.status,
|
|
7146
|
+
reason: run.reason,
|
|
7147
|
+
timestamp: candidateTimestamp,
|
|
7148
|
+
timestampDiffMs,
|
|
7149
|
+
source: "replay_scope_compact"
|
|
7150
|
+
};
|
|
7151
|
+
}
|
|
7152
|
+
}
|
|
7153
|
+
return nearest;
|
|
7154
|
+
};
|
|
7155
|
+
var hasRuntimeLineageCoverage = ({
|
|
7156
|
+
entry,
|
|
7157
|
+
lineageScopes
|
|
7158
|
+
}) => {
|
|
7159
|
+
const strategy = getEntryStrategy(entry);
|
|
7160
|
+
const timestamp = entry.signalTimestamp ?? entry.timestamp;
|
|
7161
|
+
return lineageScopes.some(
|
|
7162
|
+
(scope) => scope.strategy === strategy && scope.symbol === entry.symbol && timestamp >= scope.firstTimestamp && timestamp <= scope.lastTimestamp
|
|
7163
|
+
);
|
|
7164
|
+
};
|
|
6991
7165
|
var classifySignalDiagnostic = (signal) => {
|
|
6992
7166
|
if (signal.orderStatus === "failed") {
|
|
6993
7167
|
return {
|
|
@@ -7232,6 +7406,8 @@ var buildReplayMismatchDrilldown = ({
|
|
|
7232
7406
|
runtimeSignalEvaluations = [],
|
|
7233
7407
|
replaySignals = [],
|
|
7234
7408
|
replaySignalEvaluations = [],
|
|
7409
|
+
replayLineageScopes = [],
|
|
7410
|
+
runtimeLineageScopes = [],
|
|
7235
7411
|
toleranceMs,
|
|
7236
7412
|
backtestTimestampOffsetMs,
|
|
7237
7413
|
limit
|
|
@@ -7257,7 +7433,16 @@ var buildReplayMismatchDrilldown = ({
|
|
|
7257
7433
|
toleranceMs,
|
|
7258
7434
|
timestampOffsetMs: backtestTimestampOffsetMs
|
|
7259
7435
|
});
|
|
7260
|
-
const
|
|
7436
|
+
const nearestReplayEvaluationOutcome = findNearestReplayEvaluationOutcome({
|
|
7437
|
+
entry,
|
|
7438
|
+
lineageScopes: replayLineageScopes,
|
|
7439
|
+
toleranceMs,
|
|
7440
|
+
timestampOffsetMs: backtestTimestampOffsetMs
|
|
7441
|
+
});
|
|
7442
|
+
const classification = nearestReplaySignal ? classifySignalDiagnostic(nearestReplaySignal.signal) : nearestReplayEvaluation ? classifyEvaluationDiagnostic(nearestReplayEvaluation.evaluation) : nearestReplayEvaluationOutcome ? {
|
|
7443
|
+
classification: "core_skipped",
|
|
7444
|
+
reason: nearestReplayEvaluationOutcome.reason
|
|
7445
|
+
} : nearestCandidate?.nearest ? {
|
|
7261
7446
|
classification: "timing_or_price_drift",
|
|
7262
7447
|
reason: nearestCandidate.reason
|
|
7263
7448
|
} : {
|
|
@@ -7281,7 +7466,8 @@ var buildReplayMismatchDrilldown = ({
|
|
|
7281
7466
|
timestampDiffMs: nearestReplayEvaluation.timestampDiffMs
|
|
7282
7467
|
}),
|
|
7283
7468
|
...includeArtifacts ? { replayEvaluationArtifact: nearestReplayEvaluation.evaluation } : {}
|
|
7284
|
-
} : {}
|
|
7469
|
+
} : {},
|
|
7470
|
+
...nearestReplayEvaluationOutcome ? { replayEvaluationOutcome: nearestReplayEvaluationOutcome } : {}
|
|
7285
7471
|
};
|
|
7286
7472
|
});
|
|
7287
7473
|
const backtestOnlyDiagnostics = backtestOnly.map((entry, index) => {
|
|
@@ -7299,9 +7485,26 @@ var buildReplayMismatchDrilldown = ({
|
|
|
7299
7485
|
toleranceMs,
|
|
7300
7486
|
timestampOffsetMs: 0
|
|
7301
7487
|
});
|
|
7302
|
-
const
|
|
7488
|
+
const nearestRuntimeEvaluationOutcome = findNearestRuntimeEvaluationOutcome(
|
|
7489
|
+
{
|
|
7490
|
+
entry,
|
|
7491
|
+
lineageScopes: runtimeLineageScopes,
|
|
7492
|
+
toleranceMs
|
|
7493
|
+
}
|
|
7494
|
+
);
|
|
7495
|
+
const runtimeLineageCoversEntry = hasRuntimeLineageCoverage({
|
|
7496
|
+
entry,
|
|
7497
|
+
lineageScopes: runtimeLineageScopes
|
|
7498
|
+
});
|
|
7499
|
+
const classification = nearestRuntimeSignal ? classifySignalDiagnostic(nearestRuntimeSignal.signal) : nearestRuntimeEvaluation ? classifyEvaluationDiagnostic(nearestRuntimeEvaluation.evaluation) : nearestRuntimeEvaluationOutcome ? {
|
|
7500
|
+
classification: "core_skipped",
|
|
7501
|
+
reason: nearestRuntimeEvaluationOutcome.reason
|
|
7502
|
+
} : nearestCandidate?.nearest ? {
|
|
7303
7503
|
classification: "timing_or_price_drift",
|
|
7304
7504
|
reason: nearestCandidate.reason
|
|
7505
|
+
} : runtimeLineageCoversEntry ? {
|
|
7506
|
+
classification: "runtime_evaluation_detail_unavailable",
|
|
7507
|
+
reason: "runtime_scope_covers_timestamp_but_skip_detail_was_not_stored"
|
|
7305
7508
|
} : {
|
|
7306
7509
|
classification: "no_runtime_evaluation",
|
|
7307
7510
|
reason: "no_runtime_signal_or_evaluation"
|
|
@@ -7325,7 +7528,8 @@ var buildReplayMismatchDrilldown = ({
|
|
|
7325
7528
|
...includeArtifacts ? {
|
|
7326
7529
|
runtimeEvaluationArtifact: nearestRuntimeEvaluation.evaluation
|
|
7327
7530
|
} : {}
|
|
7328
|
-
} : {}
|
|
7531
|
+
} : {},
|
|
7532
|
+
...nearestRuntimeEvaluationOutcome ? { runtimeEvaluationOutcome: nearestRuntimeEvaluationOutcome } : {}
|
|
7329
7533
|
};
|
|
7330
7534
|
});
|
|
7331
7535
|
for (const diagnostic of runtimeOnlyDiagnostics) {
|
|
@@ -7372,7 +7576,9 @@ var buildReplayRuntimeComparisonDetails = ({
|
|
|
7372
7576
|
runtimeSignals,
|
|
7373
7577
|
runtimeSignalEvaluations,
|
|
7374
7578
|
replaySignals,
|
|
7375
|
-
replaySignalEvaluations
|
|
7579
|
+
replaySignalEvaluations,
|
|
7580
|
+
replayLineageScopes,
|
|
7581
|
+
runtimeLineageScopes
|
|
7376
7582
|
}) => {
|
|
7377
7583
|
const runtimeDetails = runtimeEntries.map(toRuntimeParityDetail);
|
|
7378
7584
|
const backtestDetails = backtestEntries.map(
|
|
@@ -7431,6 +7637,8 @@ var buildReplayRuntimeComparisonDetails = ({
|
|
|
7431
7637
|
runtimeSignalEvaluations,
|
|
7432
7638
|
replaySignals,
|
|
7433
7639
|
replaySignalEvaluations,
|
|
7640
|
+
replayLineageScopes,
|
|
7641
|
+
runtimeLineageScopes,
|
|
7434
7642
|
toleranceMs,
|
|
7435
7643
|
backtestTimestampOffsetMs,
|
|
7436
7644
|
limit
|
|
@@ -7451,7 +7659,9 @@ var buildReplayExchangeComparisonDetails = ({
|
|
|
7451
7659
|
runtimeSignals,
|
|
7452
7660
|
runtimeSignalEvaluations,
|
|
7453
7661
|
replaySignals,
|
|
7454
|
-
replaySignalEvaluations
|
|
7662
|
+
replaySignalEvaluations,
|
|
7663
|
+
replayLineageScopes,
|
|
7664
|
+
runtimeLineageScopes
|
|
7455
7665
|
}) => {
|
|
7456
7666
|
const toExchangeDetail = (entry) => toExchangeParityDetail({
|
|
7457
7667
|
entry,
|
|
@@ -7538,6 +7748,8 @@ var buildReplayExchangeComparisonDetails = ({
|
|
|
7538
7748
|
runtimeSignalEvaluations,
|
|
7539
7749
|
replaySignals,
|
|
7540
7750
|
replaySignalEvaluations,
|
|
7751
|
+
replayLineageScopes,
|
|
7752
|
+
runtimeLineageScopes,
|
|
7541
7753
|
toleranceMs,
|
|
7542
7754
|
backtestTimestampOffsetMs,
|
|
7543
7755
|
limit
|
|
@@ -7660,19 +7872,41 @@ var filterReplayComparisonByLineage = ({
|
|
|
7660
7872
|
lineageScopeKey(record)
|
|
7661
7873
|
])
|
|
7662
7874
|
);
|
|
7663
|
-
const comparableBacktestEntries =
|
|
7875
|
+
const comparableBacktestEntries = [];
|
|
7876
|
+
const excludedBacktestEntryDetails = [];
|
|
7877
|
+
for (const entry of backtestEntries) {
|
|
7664
7878
|
const replayScope = replayScopeByStrategySymbol.get(
|
|
7665
7879
|
`${entry.strategy}::${entry.symbol}`
|
|
7666
7880
|
);
|
|
7667
7881
|
const window = replayScope ? deploymentWindows.get(replayScope) : null;
|
|
7668
7882
|
const signalTimestamp = entry.signalTimestamp ?? entry.timestamp;
|
|
7669
|
-
|
|
7670
|
-
|
|
7883
|
+
if (window != null && signalTimestamp >= window.firstTimestamp && signalTimestamp <= window.lastTimestamp) {
|
|
7884
|
+
comparableBacktestEntries.push(entry);
|
|
7885
|
+
continue;
|
|
7886
|
+
}
|
|
7887
|
+
const reason = !replayScope ? "replay_scope_missing" : !window ? "runtime_scope_missing" : signalTimestamp < window.firstTimestamp ? "before_runtime_window" : "after_runtime_window";
|
|
7888
|
+
excludedBacktestEntryDetails.push({
|
|
7889
|
+
id: entry.id,
|
|
7890
|
+
strategy: entry.strategy,
|
|
7891
|
+
symbol: entry.symbol,
|
|
7892
|
+
direction: entry.direction,
|
|
7893
|
+
...entry.qty != null ? { qty: entry.qty } : {},
|
|
7894
|
+
timestamp: entry.timestamp,
|
|
7895
|
+
...entry.signalTimestamp != null ? { signalTimestamp: entry.signalTimestamp } : {},
|
|
7896
|
+
price: entry.price,
|
|
7897
|
+
...entry.orderId ? { orderId: entry.orderId } : {},
|
|
7898
|
+
...entry.signalId ? { signalId: entry.signalId } : {},
|
|
7899
|
+
...entry.expectedPnl != null ? { expectedPnl: entry.expectedPnl } : {},
|
|
7900
|
+
reason,
|
|
7901
|
+
runtimeWindow: window ?? null
|
|
7902
|
+
});
|
|
7903
|
+
}
|
|
7671
7904
|
const comparableScopeKeys = new Set(deploymentWindows.keys());
|
|
7672
7905
|
return {
|
|
7673
7906
|
runtimeTrades: comparableRuntimeTrades,
|
|
7674
7907
|
runtimeSignals: comparableRuntimeSignals,
|
|
7675
7908
|
runtimeSignalEvaluations: comparableRuntimeEvaluations,
|
|
7909
|
+
runtimeLineageScopes: comparableRuntimeLineageScopes,
|
|
7676
7910
|
backtestEntries: comparableBacktestEntries,
|
|
7677
7911
|
lineage: {
|
|
7678
7912
|
enforced: true,
|
|
@@ -7684,6 +7918,7 @@ var filterReplayComparisonByLineage = ({
|
|
|
7684
7918
|
excludedRuntimeLineageScopes: runtimeLineageScopes.length - comparableRuntimeLineageScopes.length,
|
|
7685
7919
|
excludedExchangeEntries: 0,
|
|
7686
7920
|
excludedBacktestEntries: backtestEntries.length - comparableBacktestEntries.length,
|
|
7921
|
+
excludedBacktestEntryDetails,
|
|
7687
7922
|
reason: comparableScopeKeys.size > 0 ? null : expectedByScope.size === 0 ? "replay_produced_no_lineage_scopes" : "no_runtime_artifacts_with_matching_lineage",
|
|
7688
7923
|
replay: [...expectedByScope.entries()].map(([scope, lineage]) => {
|
|
7689
7924
|
const [deploymentId, accountId, strategy, symbol] = scope.split("::");
|
|
@@ -8267,8 +8502,10 @@ var saveAndPrintReplayExchangeComparison = async ({
|
|
|
8267
8502
|
backtestEntries,
|
|
8268
8503
|
replaySignals,
|
|
8269
8504
|
replaySignalEvaluations,
|
|
8505
|
+
replayLineageScopes,
|
|
8270
8506
|
runtimeSignals,
|
|
8271
8507
|
runtimeSignalEvaluations,
|
|
8508
|
+
runtimeLineageScopes,
|
|
8272
8509
|
lineage
|
|
8273
8510
|
}) => {
|
|
8274
8511
|
const { connector, connectorName, window } = getRuntimeCompareContext();
|
|
@@ -8320,7 +8557,9 @@ var saveAndPrintReplayExchangeComparison = async ({
|
|
|
8320
8557
|
runtimeSignals,
|
|
8321
8558
|
runtimeSignalEvaluations,
|
|
8322
8559
|
replaySignals,
|
|
8323
|
-
replaySignalEvaluations
|
|
8560
|
+
replaySignalEvaluations,
|
|
8561
|
+
runtimeLineageScopes,
|
|
8562
|
+
replayLineageScopes
|
|
8324
8563
|
});
|
|
8325
8564
|
const emptyRowsByStrategy = new Map(
|
|
8326
8565
|
buildExchangeComparisonRows({
|
|
@@ -8376,7 +8615,9 @@ var saveAndPrintReplayExchangeComparison = async ({
|
|
|
8376
8615
|
runtimeSignals,
|
|
8377
8616
|
runtimeSignalEvaluations,
|
|
8378
8617
|
replaySignals,
|
|
8379
|
-
replaySignalEvaluations
|
|
8618
|
+
replaySignalEvaluations,
|
|
8619
|
+
runtimeLineageScopes,
|
|
8620
|
+
replayLineageScopes
|
|
8380
8621
|
});
|
|
8381
8622
|
const rows = buildExchangeComparisonRows({
|
|
8382
8623
|
liveStrategySummaries,
|
|
@@ -8414,6 +8655,7 @@ var saveAndPrintReplayRuntimeComparison = async ({
|
|
|
8414
8655
|
backtestEntries,
|
|
8415
8656
|
replaySignals,
|
|
8416
8657
|
replayLineages,
|
|
8658
|
+
replayLineageScopes,
|
|
8417
8659
|
runtimeEvidencePath
|
|
8418
8660
|
}) => {
|
|
8419
8661
|
const { connector, connectorName, window } = getRuntimeCompareContext();
|
|
@@ -8525,8 +8767,10 @@ var saveAndPrintReplayRuntimeComparison = async ({
|
|
|
8525
8767
|
backtestEntries: comparableBacktestEntries,
|
|
8526
8768
|
replaySignals,
|
|
8527
8769
|
replaySignalEvaluations,
|
|
8770
|
+
replayLineageScopes,
|
|
8528
8771
|
runtimeSignals: comparable.runtimeSignals,
|
|
8529
8772
|
runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
|
|
8773
|
+
runtimeLineageScopes: comparable.runtimeLineageScopes,
|
|
8530
8774
|
lineage: comparable.lineage
|
|
8531
8775
|
});
|
|
8532
8776
|
}
|
|
@@ -8550,7 +8794,9 @@ var saveAndPrintReplayRuntimeComparison = async ({
|
|
|
8550
8794
|
runtimeSignals: comparable.runtimeSignals,
|
|
8551
8795
|
runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
|
|
8552
8796
|
replaySignals,
|
|
8553
|
-
replaySignalEvaluations
|
|
8797
|
+
replaySignalEvaluations,
|
|
8798
|
+
runtimeLineageScopes: comparable.runtimeLineageScopes,
|
|
8799
|
+
replayLineageScopes
|
|
8554
8800
|
});
|
|
8555
8801
|
const parityRows = summarizeTradeParityByStrategy({
|
|
8556
8802
|
runtimeEntries: runtimeDedupe.entries,
|
|
@@ -8593,7 +8839,7 @@ var saveAndPrintReplayRuntimeComparison = async ({
|
|
|
8593
8839
|
// src/lib/replay/outputReport.ts
|
|
8594
8840
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
8595
8841
|
var import_node_path2 = __toESM(require("path"));
|
|
8596
|
-
var
|
|
8842
|
+
var import_data3 = require("@tradejs/core/data");
|
|
8597
8843
|
var formatMsk = (timestamp) => typeof timestamp === "number" && Number.isFinite(timestamp) ? new Intl.DateTimeFormat("ru-RU", {
|
|
8598
8844
|
timeZone: "Europe/Moscow",
|
|
8599
8845
|
dateStyle: "short",
|
|
@@ -9000,7 +9246,7 @@ var writeReplayOutputReport = async ({
|
|
|
9000
9246
|
];
|
|
9001
9247
|
await Promise.all([
|
|
9002
9248
|
import_promises2.default.writeFile(markdownPath, lines.join("\n"), "utf8"),
|
|
9003
|
-
import_promises2.default.writeFile(jsonPath, `${(0,
|
|
9249
|
+
import_promises2.default.writeFile(jsonPath, `${(0, import_data3.toJson)(report, true)}
|
|
9004
9250
|
`, "utf8")
|
|
9005
9251
|
]);
|
|
9006
9252
|
return {
|
|
@@ -9042,6 +9288,7 @@ var finishReplay = async ({
|
|
|
9042
9288
|
backtestEntries: replayStrategySnapshot.backtestEntries,
|
|
9043
9289
|
replaySignals: replayResult.signals,
|
|
9044
9290
|
replayLineages: replayResult.runtimeLineages,
|
|
9291
|
+
replayLineageScopes: replayResult.replayLineageScopes,
|
|
9045
9292
|
runtimeEvidencePath: replayRuntimeEvidencePath
|
|
9046
9293
|
});
|
|
9047
9294
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
@@ -9208,7 +9455,7 @@ var replayBacktest = async () => {
|
|
|
9208
9455
|
deploymentId: deployment.id,
|
|
9209
9456
|
assetClasses: deployment.assetClasses,
|
|
9210
9457
|
deployment,
|
|
9211
|
-
closedIntervalMs: (0,
|
|
9458
|
+
closedIntervalMs: (0, import_data4.intervalToMs)(replayInterval)
|
|
9212
9459
|
});
|
|
9213
9460
|
if (!preparedRun || isReplayUpdateOnlyRun) {
|
|
9214
9461
|
return;
|