@tradejs/cli 3.1.27-beta.245 → 3.1.27-beta.248
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 +211 -19
- package/dist/lib/runtimeParityDetails.js +57 -2
- package/dist/scripts/replay.js +189 -16
- package/dist/scripts/replayRunner.js +189 -16
- package/dist/scripts/replayRuntimeEvidence.js +13 -1
- package/package.json +7 -7
package/dist/cli.js
CHANGED
|
@@ -24893,9 +24893,21 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
24893
24893
|
const replayLineage = asArray2(comparisonLineage.replay).filter(
|
|
24894
24894
|
(entry) => !useFilter || strategySet.has(String(asRecord4(entry).strategy ?? ""))
|
|
24895
24895
|
);
|
|
24896
|
+
const hasExcludedBacktestEntryDetails = Array.isArray(
|
|
24897
|
+
comparisonLineage.excludedBacktestEntryDetails
|
|
24898
|
+
);
|
|
24899
|
+
const excludedBacktestEntryDetails = asArray2(
|
|
24900
|
+
comparisonLineage.excludedBacktestEntryDetails
|
|
24901
|
+
).filter(
|
|
24902
|
+
(entry) => !useFilter || strategySet.has(String(asRecord4(entry).strategy ?? ""))
|
|
24903
|
+
);
|
|
24896
24904
|
return {
|
|
24897
24905
|
mode: comparison.mode ?? null,
|
|
24898
|
-
lineage: comparisonLineage ? {
|
|
24906
|
+
lineage: comparisonLineage ? {
|
|
24907
|
+
...comparisonLineage,
|
|
24908
|
+
replay: replayLineage,
|
|
24909
|
+
...hasExcludedBacktestEntryDetails ? { excludedBacktestEntryDetails } : {}
|
|
24910
|
+
} : null,
|
|
24899
24911
|
rows: asArray2(comparison.rows).filter(
|
|
24900
24912
|
(row) => !useFilter || strategySet.has(String(row.strategyName ?? ""))
|
|
24901
24913
|
),
|
|
@@ -35380,11 +35392,90 @@ var init_historicalSignalsReplayPreparation = __esm({
|
|
|
35380
35392
|
}
|
|
35381
35393
|
});
|
|
35382
35394
|
|
|
35395
|
+
// src/lib/replay/historicalSignalsReplaySkipEvidence.ts
|
|
35396
|
+
var import_data5, replayScopeKey, appendReplaySignalEvaluationRun, createHistoricalReplaySkipEvidence;
|
|
35397
|
+
var init_historicalSignalsReplaySkipEvidence = __esm({
|
|
35398
|
+
"src/lib/replay/historicalSignalsReplaySkipEvidence.ts"() {
|
|
35399
|
+
"use strict";
|
|
35400
|
+
import_data5 = require("@tradejs/core/data");
|
|
35401
|
+
replayScopeKey = (strategy, symbol) => `${strategy}::${symbol}`;
|
|
35402
|
+
appendReplaySignalEvaluationRun = ({
|
|
35403
|
+
runs = [],
|
|
35404
|
+
reason,
|
|
35405
|
+
timestamp,
|
|
35406
|
+
interval: interval4
|
|
35407
|
+
}) => {
|
|
35408
|
+
const stepMs = (0, import_data5.intervalToMs)(interval4);
|
|
35409
|
+
const last = runs.at(-1);
|
|
35410
|
+
if (last?.reason === reason && last.stepMs === stepMs && timestamp === last.lastTimestamp + stepMs) {
|
|
35411
|
+
return [...runs.slice(0, -1), { ...last, lastTimestamp: timestamp }];
|
|
35412
|
+
}
|
|
35413
|
+
return [
|
|
35414
|
+
...runs,
|
|
35415
|
+
{
|
|
35416
|
+
status: "skip",
|
|
35417
|
+
reason,
|
|
35418
|
+
firstTimestamp: timestamp,
|
|
35419
|
+
lastTimestamp: timestamp,
|
|
35420
|
+
stepMs
|
|
35421
|
+
}
|
|
35422
|
+
];
|
|
35423
|
+
};
|
|
35424
|
+
createHistoricalReplaySkipEvidence = (runtimeLineages) => {
|
|
35425
|
+
const lineageByStrategySymbol = new Map(
|
|
35426
|
+
runtimeLineages.map((record2) => [
|
|
35427
|
+
replayScopeKey(record2.strategy, record2.symbol),
|
|
35428
|
+
record2
|
|
35429
|
+
])
|
|
35430
|
+
);
|
|
35431
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
35432
|
+
const record = ({
|
|
35433
|
+
strategyName,
|
|
35434
|
+
symbol,
|
|
35435
|
+
strategyConfig,
|
|
35436
|
+
runtimeLineage,
|
|
35437
|
+
timestamp,
|
|
35438
|
+
result
|
|
35439
|
+
}) => {
|
|
35440
|
+
const scopeKey = replayScopeKey(strategyName, symbol);
|
|
35441
|
+
const lineageRecord = lineageByStrategySymbol.get(scopeKey);
|
|
35442
|
+
if (!lineageRecord) return;
|
|
35443
|
+
const existing = scopes.get(scopeKey);
|
|
35444
|
+
const skipReason = typeof result === "string" ? result.trim() || "NO_SIGNAL" : result ? null : "NO_SIGNAL";
|
|
35445
|
+
scopes.set(scopeKey, {
|
|
35446
|
+
strategy: strategyName,
|
|
35447
|
+
symbol,
|
|
35448
|
+
...lineageRecord.deploymentId ? { deploymentId: lineageRecord.deploymentId } : {},
|
|
35449
|
+
...lineageRecord.accountId ? { accountId: lineageRecord.accountId } : {},
|
|
35450
|
+
strategyRevision: runtimeLineage.strategyRevision,
|
|
35451
|
+
lineage: runtimeLineage,
|
|
35452
|
+
firstTimestamp: Math.min(
|
|
35453
|
+
existing?.firstTimestamp ?? timestamp,
|
|
35454
|
+
timestamp
|
|
35455
|
+
),
|
|
35456
|
+
lastTimestamp: Math.max(existing?.lastTimestamp ?? timestamp, timestamp),
|
|
35457
|
+
evaluationRuns: skipReason ? appendReplaySignalEvaluationRun({
|
|
35458
|
+
runs: existing?.evaluationRuns,
|
|
35459
|
+
reason: skipReason,
|
|
35460
|
+
timestamp,
|
|
35461
|
+
interval: strategyConfig.INTERVAL ?? "15"
|
|
35462
|
+
}) : existing?.evaluationRuns
|
|
35463
|
+
});
|
|
35464
|
+
};
|
|
35465
|
+
const values = () => [...scopes.values()].sort(
|
|
35466
|
+
(left, right) => left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol)
|
|
35467
|
+
);
|
|
35468
|
+
return { record, values };
|
|
35469
|
+
};
|
|
35470
|
+
}
|
|
35471
|
+
});
|
|
35472
|
+
|
|
35383
35473
|
// src/lib/replay/historicalSignalsReplayExecution.ts
|
|
35384
35474
|
var advanceCycleMarket, advanceAbortedCycle, executeHistoricalReplay;
|
|
35385
35475
|
var init_historicalSignalsReplayExecution = __esm({
|
|
35386
35476
|
"src/lib/replay/historicalSignalsReplayExecution.ts"() {
|
|
35387
35477
|
"use strict";
|
|
35478
|
+
init_historicalSignalsReplaySkipEvidence();
|
|
35388
35479
|
advanceCycleMarket = async (plan, connector, timestamp) => {
|
|
35389
35480
|
const cycleSymbols = plan.cycleSymbolsByTimestamp.get(timestamp) ?? [];
|
|
35390
35481
|
for (const symbolRuntime of cycleSymbols) {
|
|
@@ -35409,6 +35500,9 @@ var init_historicalSignalsReplayExecution = __esm({
|
|
|
35409
35500
|
executeHistoricalReplay = async (context, adapters) => {
|
|
35410
35501
|
const signals2 = [];
|
|
35411
35502
|
let abortedCycles = 0;
|
|
35503
|
+
const skipEvidence = createHistoricalReplaySkipEvidence(
|
|
35504
|
+
context.plan.runtimeLineages
|
|
35505
|
+
);
|
|
35412
35506
|
try {
|
|
35413
35507
|
for (const timestamp of context.plan.orderedTimestamps) {
|
|
35414
35508
|
const cycleStartedAt = adapters.clock.now();
|
|
@@ -35451,6 +35545,14 @@ var init_historicalSignalsReplayExecution = __esm({
|
|
|
35451
35545
|
btcCandle,
|
|
35452
35546
|
ethCandle?.timestamp === timestamp ? ethCandle : void 0
|
|
35453
35547
|
);
|
|
35548
|
+
skipEvidence.record({
|
|
35549
|
+
strategyName: strategyRuntime.strategyName,
|
|
35550
|
+
symbol: symbolRuntime.symbol,
|
|
35551
|
+
strategyConfig: strategyRuntime.strategyConfig,
|
|
35552
|
+
runtimeLineage: strategyRuntime.runtimeLineage,
|
|
35553
|
+
timestamp,
|
|
35554
|
+
result
|
|
35555
|
+
});
|
|
35454
35556
|
if (result && typeof result !== "string") {
|
|
35455
35557
|
result.runtimeLineage = strategyRuntime.runtimeLineage;
|
|
35456
35558
|
await adapters.enrichSignal(result);
|
|
@@ -35478,7 +35580,11 @@ var init_historicalSignalsReplayExecution = __esm({
|
|
|
35478
35580
|
adapters.releaseReplayCache(keyPrefix);
|
|
35479
35581
|
}
|
|
35480
35582
|
}
|
|
35481
|
-
return {
|
|
35583
|
+
return {
|
|
35584
|
+
signals: signals2,
|
|
35585
|
+
abortedCycles,
|
|
35586
|
+
replayLineageScopes: skipEvidence.values()
|
|
35587
|
+
};
|
|
35482
35588
|
};
|
|
35483
35589
|
}
|
|
35484
35590
|
});
|
|
@@ -35513,7 +35619,8 @@ var init_historicalSignalsReplayResults = __esm({
|
|
|
35513
35619
|
positionLog: context.artifacts.positionLog,
|
|
35514
35620
|
cycleCount: context.cycleCount,
|
|
35515
35621
|
abortedCycles: context.abortedCycles,
|
|
35516
|
-
runtimeLineages: context.runtimeLineages
|
|
35622
|
+
runtimeLineages: context.runtimeLineages,
|
|
35623
|
+
replayLineageScopes: context.replayLineageScopes
|
|
35517
35624
|
});
|
|
35518
35625
|
}
|
|
35519
35626
|
});
|
|
@@ -35755,7 +35862,8 @@ var init_historicalSignalsReplay = __esm({
|
|
|
35755
35862
|
signals: execution.signals,
|
|
35756
35863
|
cycleCount: plan.orderedTimestamps.length,
|
|
35757
35864
|
abortedCycles: execution.abortedCycles,
|
|
35758
|
-
runtimeLineages: plan.runtimeLineages
|
|
35865
|
+
runtimeLineages: plan.runtimeLineages,
|
|
35866
|
+
replayLineageScopes: execution.replayLineageScopes
|
|
35759
35867
|
});
|
|
35760
35868
|
};
|
|
35761
35869
|
}
|
|
@@ -36203,7 +36311,7 @@ var init_runtimeTradeSync = __esm({
|
|
|
36203
36311
|
});
|
|
36204
36312
|
|
|
36205
36313
|
// src/lib/runtimeParityDetails.ts
|
|
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;
|
|
36314
|
+
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, findNearestReplayEvaluationOutcome, hasRuntimeLineageCoverage, classifySignalDiagnostic, classifyEvaluationDiagnostic, summarizeMismatchDiagnostics, buildPnlDelta, buildPriceDeltaPct2, toFiniteNumberOrNull3, toAiDiagnostic, toSignalDiagnostic, toEvaluationDiagnostic, buildSlippageCost, buildMatchedReplayDetail, buildNearestCandidates, buildReplayMismatchDrilldown, buildReplayRuntimeComparisonDetails, buildReplayExchangeComparisonDetails;
|
|
36207
36315
|
var init_runtimeParityDetails = __esm({
|
|
36208
36316
|
"src/lib/runtimeParityDetails.ts"() {
|
|
36209
36317
|
"use strict";
|
|
@@ -36413,6 +36521,46 @@ var init_runtimeParityDetails = __esm({
|
|
|
36413
36521
|
}
|
|
36414
36522
|
return nearest;
|
|
36415
36523
|
};
|
|
36524
|
+
findNearestReplayEvaluationOutcome = ({
|
|
36525
|
+
entry,
|
|
36526
|
+
lineageScopes,
|
|
36527
|
+
toleranceMs,
|
|
36528
|
+
timestampOffsetMs
|
|
36529
|
+
}) => {
|
|
36530
|
+
const strategy = getEntryStrategy(entry);
|
|
36531
|
+
if (!strategy) return null;
|
|
36532
|
+
let nearest = null;
|
|
36533
|
+
for (const scope of lineageScopes) {
|
|
36534
|
+
if (scope.strategy !== strategy || scope.symbol !== entry.symbol) {
|
|
36535
|
+
continue;
|
|
36536
|
+
}
|
|
36537
|
+
for (const run of scope.evaluationRuns ?? []) {
|
|
36538
|
+
if (run.stepMs <= 0) continue;
|
|
36539
|
+
const targetTimestamp = entry.timestamp - timestampOffsetMs;
|
|
36540
|
+
if (targetTimestamp < run.firstTimestamp - toleranceMs || targetTimestamp > run.lastTimestamp + toleranceMs) {
|
|
36541
|
+
continue;
|
|
36542
|
+
}
|
|
36543
|
+
const step = Math.round(
|
|
36544
|
+
(targetTimestamp - run.firstTimestamp) / run.stepMs
|
|
36545
|
+
);
|
|
36546
|
+
const candidateTimestamp = run.firstTimestamp + step * run.stepMs;
|
|
36547
|
+
const timestampDiffMs = Math.abs(
|
|
36548
|
+
candidateTimestamp + timestampOffsetMs - entry.timestamp
|
|
36549
|
+
);
|
|
36550
|
+
if (candidateTimestamp < run.firstTimestamp || candidateTimestamp > run.lastTimestamp || timestampDiffMs > toleranceMs || nearest && timestampDiffMs >= nearest.timestampDiffMs) {
|
|
36551
|
+
continue;
|
|
36552
|
+
}
|
|
36553
|
+
nearest = {
|
|
36554
|
+
status: run.status,
|
|
36555
|
+
reason: run.reason,
|
|
36556
|
+
timestamp: candidateTimestamp,
|
|
36557
|
+
timestampDiffMs,
|
|
36558
|
+
source: "replay_scope_compact"
|
|
36559
|
+
};
|
|
36560
|
+
}
|
|
36561
|
+
}
|
|
36562
|
+
return nearest;
|
|
36563
|
+
};
|
|
36416
36564
|
hasRuntimeLineageCoverage = ({
|
|
36417
36565
|
entry,
|
|
36418
36566
|
lineageScopes
|
|
@@ -36667,6 +36815,7 @@ var init_runtimeParityDetails = __esm({
|
|
|
36667
36815
|
runtimeSignalEvaluations = [],
|
|
36668
36816
|
replaySignals = [],
|
|
36669
36817
|
replaySignalEvaluations = [],
|
|
36818
|
+
replayLineageScopes = [],
|
|
36670
36819
|
runtimeLineageScopes = [],
|
|
36671
36820
|
toleranceMs,
|
|
36672
36821
|
backtestTimestampOffsetMs,
|
|
@@ -36693,7 +36842,16 @@ var init_runtimeParityDetails = __esm({
|
|
|
36693
36842
|
toleranceMs,
|
|
36694
36843
|
timestampOffsetMs: backtestTimestampOffsetMs
|
|
36695
36844
|
});
|
|
36696
|
-
const
|
|
36845
|
+
const nearestReplayEvaluationOutcome = findNearestReplayEvaluationOutcome({
|
|
36846
|
+
entry,
|
|
36847
|
+
lineageScopes: replayLineageScopes,
|
|
36848
|
+
toleranceMs,
|
|
36849
|
+
timestampOffsetMs: backtestTimestampOffsetMs
|
|
36850
|
+
});
|
|
36851
|
+
const classification = nearestReplaySignal ? classifySignalDiagnostic(nearestReplaySignal.signal) : nearestReplayEvaluation ? classifyEvaluationDiagnostic(nearestReplayEvaluation.evaluation) : nearestReplayEvaluationOutcome ? {
|
|
36852
|
+
classification: "core_skipped",
|
|
36853
|
+
reason: nearestReplayEvaluationOutcome.reason
|
|
36854
|
+
} : nearestCandidate?.nearest ? {
|
|
36697
36855
|
classification: "timing_or_price_drift",
|
|
36698
36856
|
reason: nearestCandidate.reason
|
|
36699
36857
|
} : {
|
|
@@ -36717,7 +36875,8 @@ var init_runtimeParityDetails = __esm({
|
|
|
36717
36875
|
timestampDiffMs: nearestReplayEvaluation.timestampDiffMs
|
|
36718
36876
|
}),
|
|
36719
36877
|
...includeArtifacts ? { replayEvaluationArtifact: nearestReplayEvaluation.evaluation } : {}
|
|
36720
|
-
} : {}
|
|
36878
|
+
} : {},
|
|
36879
|
+
...nearestReplayEvaluationOutcome ? { replayEvaluationOutcome: nearestReplayEvaluationOutcome } : {}
|
|
36721
36880
|
};
|
|
36722
36881
|
});
|
|
36723
36882
|
const backtestOnlyDiagnostics = backtestOnly.map((entry, index) => {
|
|
@@ -36827,6 +36986,7 @@ var init_runtimeParityDetails = __esm({
|
|
|
36827
36986
|
runtimeSignalEvaluations,
|
|
36828
36987
|
replaySignals,
|
|
36829
36988
|
replaySignalEvaluations,
|
|
36989
|
+
replayLineageScopes,
|
|
36830
36990
|
runtimeLineageScopes
|
|
36831
36991
|
}) => {
|
|
36832
36992
|
const runtimeDetails = runtimeEntries.map(toRuntimeParityDetail);
|
|
@@ -36886,6 +37046,7 @@ var init_runtimeParityDetails = __esm({
|
|
|
36886
37046
|
runtimeSignalEvaluations,
|
|
36887
37047
|
replaySignals,
|
|
36888
37048
|
replaySignalEvaluations,
|
|
37049
|
+
replayLineageScopes,
|
|
36889
37050
|
runtimeLineageScopes,
|
|
36890
37051
|
toleranceMs,
|
|
36891
37052
|
backtestTimestampOffsetMs,
|
|
@@ -36908,6 +37069,7 @@ var init_runtimeParityDetails = __esm({
|
|
|
36908
37069
|
runtimeSignalEvaluations,
|
|
36909
37070
|
replaySignals,
|
|
36910
37071
|
replaySignalEvaluations,
|
|
37072
|
+
replayLineageScopes,
|
|
36911
37073
|
runtimeLineageScopes
|
|
36912
37074
|
}) => {
|
|
36913
37075
|
const toExchangeDetail = (entry) => toExchangeParityDetail({
|
|
@@ -36995,6 +37157,7 @@ var init_runtimeParityDetails = __esm({
|
|
|
36995
37157
|
runtimeSignalEvaluations,
|
|
36996
37158
|
replaySignals,
|
|
36997
37159
|
replaySignalEvaluations,
|
|
37160
|
+
replayLineageScopes,
|
|
36998
37161
|
runtimeLineageScopes,
|
|
36999
37162
|
toleranceMs,
|
|
37000
37163
|
backtestTimestampOffsetMs,
|
|
@@ -37127,14 +37290,35 @@ var init_runtimeComparisonCalculations = __esm({
|
|
|
37127
37290
|
lineageScopeKey(record)
|
|
37128
37291
|
])
|
|
37129
37292
|
);
|
|
37130
|
-
const comparableBacktestEntries =
|
|
37293
|
+
const comparableBacktestEntries = [];
|
|
37294
|
+
const excludedBacktestEntryDetails = [];
|
|
37295
|
+
for (const entry of backtestEntries) {
|
|
37131
37296
|
const replayScope = replayScopeByStrategySymbol.get(
|
|
37132
37297
|
`${entry.strategy}::${entry.symbol}`
|
|
37133
37298
|
);
|
|
37134
37299
|
const window = replayScope ? deploymentWindows.get(replayScope) : null;
|
|
37135
37300
|
const signalTimestamp = entry.signalTimestamp ?? entry.timestamp;
|
|
37136
|
-
|
|
37137
|
-
|
|
37301
|
+
if (window != null && signalTimestamp >= window.firstTimestamp && signalTimestamp <= window.lastTimestamp) {
|
|
37302
|
+
comparableBacktestEntries.push(entry);
|
|
37303
|
+
continue;
|
|
37304
|
+
}
|
|
37305
|
+
const reason = !replayScope ? "replay_scope_missing" : !window ? "runtime_scope_missing" : signalTimestamp < window.firstTimestamp ? "before_runtime_window" : "after_runtime_window";
|
|
37306
|
+
excludedBacktestEntryDetails.push({
|
|
37307
|
+
id: entry.id,
|
|
37308
|
+
strategy: entry.strategy,
|
|
37309
|
+
symbol: entry.symbol,
|
|
37310
|
+
direction: entry.direction,
|
|
37311
|
+
...entry.qty != null ? { qty: entry.qty } : {},
|
|
37312
|
+
timestamp: entry.timestamp,
|
|
37313
|
+
...entry.signalTimestamp != null ? { signalTimestamp: entry.signalTimestamp } : {},
|
|
37314
|
+
price: entry.price,
|
|
37315
|
+
...entry.orderId ? { orderId: entry.orderId } : {},
|
|
37316
|
+
...entry.signalId ? { signalId: entry.signalId } : {},
|
|
37317
|
+
...entry.expectedPnl != null ? { expectedPnl: entry.expectedPnl } : {},
|
|
37318
|
+
reason,
|
|
37319
|
+
runtimeWindow: window ?? null
|
|
37320
|
+
});
|
|
37321
|
+
}
|
|
37138
37322
|
const comparableScopeKeys = new Set(deploymentWindows.keys());
|
|
37139
37323
|
return {
|
|
37140
37324
|
runtimeTrades: comparableRuntimeTrades,
|
|
@@ -37152,6 +37336,7 @@ var init_runtimeComparisonCalculations = __esm({
|
|
|
37152
37336
|
excludedRuntimeLineageScopes: runtimeLineageScopes.length - comparableRuntimeLineageScopes.length,
|
|
37153
37337
|
excludedExchangeEntries: 0,
|
|
37154
37338
|
excludedBacktestEntries: backtestEntries.length - comparableBacktestEntries.length,
|
|
37339
|
+
excludedBacktestEntryDetails,
|
|
37155
37340
|
reason: comparableScopeKeys.size > 0 ? null : expectedByScope.size === 0 ? "replay_produced_no_lineage_scopes" : "no_runtime_artifacts_with_matching_lineage",
|
|
37156
37341
|
replay: [...expectedByScope.entries()].map(([scope, lineage]) => {
|
|
37157
37342
|
const [deploymentId, accountId, strategy, symbol] = scope.split("::");
|
|
@@ -37763,6 +37948,7 @@ var init_runtimeComparison = __esm({
|
|
|
37763
37948
|
backtestEntries,
|
|
37764
37949
|
replaySignals,
|
|
37765
37950
|
replaySignalEvaluations,
|
|
37951
|
+
replayLineageScopes,
|
|
37766
37952
|
runtimeSignals,
|
|
37767
37953
|
runtimeSignalEvaluations,
|
|
37768
37954
|
runtimeLineageScopes,
|
|
@@ -37818,7 +38004,8 @@ var init_runtimeComparison = __esm({
|
|
|
37818
38004
|
runtimeSignalEvaluations,
|
|
37819
38005
|
replaySignals,
|
|
37820
38006
|
replaySignalEvaluations,
|
|
37821
|
-
runtimeLineageScopes
|
|
38007
|
+
runtimeLineageScopes,
|
|
38008
|
+
replayLineageScopes
|
|
37822
38009
|
});
|
|
37823
38010
|
const emptyRowsByStrategy = new Map(
|
|
37824
38011
|
buildExchangeComparisonRows({
|
|
@@ -37875,7 +38062,8 @@ var init_runtimeComparison = __esm({
|
|
|
37875
38062
|
runtimeSignalEvaluations,
|
|
37876
38063
|
replaySignals,
|
|
37877
38064
|
replaySignalEvaluations,
|
|
37878
|
-
runtimeLineageScopes
|
|
38065
|
+
runtimeLineageScopes,
|
|
38066
|
+
replayLineageScopes
|
|
37879
38067
|
});
|
|
37880
38068
|
const rows = buildExchangeComparisonRows({
|
|
37881
38069
|
liveStrategySummaries,
|
|
@@ -37913,6 +38101,7 @@ var init_runtimeComparison = __esm({
|
|
|
37913
38101
|
backtestEntries,
|
|
37914
38102
|
replaySignals,
|
|
37915
38103
|
replayLineages,
|
|
38104
|
+
replayLineageScopes,
|
|
37916
38105
|
runtimeEvidencePath
|
|
37917
38106
|
}) => {
|
|
37918
38107
|
const { connector, connectorName, window } = getRuntimeCompareContext();
|
|
@@ -38024,6 +38213,7 @@ var init_runtimeComparison = __esm({
|
|
|
38024
38213
|
backtestEntries: comparableBacktestEntries,
|
|
38025
38214
|
replaySignals,
|
|
38026
38215
|
replaySignalEvaluations,
|
|
38216
|
+
replayLineageScopes,
|
|
38027
38217
|
runtimeSignals: comparable.runtimeSignals,
|
|
38028
38218
|
runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
|
|
38029
38219
|
runtimeLineageScopes: comparable.runtimeLineageScopes,
|
|
@@ -38051,7 +38241,8 @@ var init_runtimeComparison = __esm({
|
|
|
38051
38241
|
runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
|
|
38052
38242
|
replaySignals,
|
|
38053
38243
|
replaySignalEvaluations,
|
|
38054
|
-
runtimeLineageScopes: comparable.runtimeLineageScopes
|
|
38244
|
+
runtimeLineageScopes: comparable.runtimeLineageScopes,
|
|
38245
|
+
replayLineageScopes
|
|
38055
38246
|
});
|
|
38056
38247
|
const parityRows = summarizeTradeParityByStrategy({
|
|
38057
38248
|
runtimeEntries: runtimeDedupe.entries,
|
|
@@ -38094,13 +38285,13 @@ var init_runtimeComparison = __esm({
|
|
|
38094
38285
|
});
|
|
38095
38286
|
|
|
38096
38287
|
// src/lib/replay/outputReport.ts
|
|
38097
|
-
var import_promises33, import_node_path30,
|
|
38288
|
+
var import_promises33, import_node_path30, import_data6, formatMsk, formatNumber5, formatMoney2, formatPct, tableCell, createMarkdownTable2, entryStrategy, entryKey, buildDrilldownMap, buildPerTradeAnalysis, renderMatchedRows, renderRuntimeOnlyRows, renderOrderFailedRows, renderBacktestOnlyRows, renderStrategyRows, renderLineageRows, writeReplayOutputReport;
|
|
38098
38289
|
var init_outputReport = __esm({
|
|
38099
38290
|
"src/lib/replay/outputReport.ts"() {
|
|
38100
38291
|
"use strict";
|
|
38101
38292
|
import_promises33 = __toESM(require("fs/promises"));
|
|
38102
38293
|
import_node_path30 = __toESM(require("path"));
|
|
38103
|
-
|
|
38294
|
+
import_data6 = require("@tradejs/core/data");
|
|
38104
38295
|
init_support();
|
|
38105
38296
|
formatMsk = (timestamp) => typeof timestamp === "number" && Number.isFinite(timestamp) ? new Intl.DateTimeFormat("ru-RU", {
|
|
38106
38297
|
timeZone: "Europe/Moscow",
|
|
@@ -38508,7 +38699,7 @@ var init_outputReport = __esm({
|
|
|
38508
38699
|
];
|
|
38509
38700
|
await Promise.all([
|
|
38510
38701
|
import_promises33.default.writeFile(markdownPath, lines.join("\n"), "utf8"),
|
|
38511
|
-
import_promises33.default.writeFile(jsonPath, `${(0,
|
|
38702
|
+
import_promises33.default.writeFile(jsonPath, `${(0, import_data6.toJson)(report, true)}
|
|
38512
38703
|
`, "utf8")
|
|
38513
38704
|
]);
|
|
38514
38705
|
return {
|
|
@@ -38520,13 +38711,13 @@ var init_outputReport = __esm({
|
|
|
38520
38711
|
});
|
|
38521
38712
|
|
|
38522
38713
|
// src/scripts/replayRunner.ts
|
|
38523
|
-
var import_chalk53, import_constants19,
|
|
38714
|
+
var import_chalk53, import_constants19, import_data7, import_time14, import_redis21, prepareReplayBinanceMarketContext, finishReplay, replayBacktest;
|
|
38524
38715
|
var init_replayRunner = __esm({
|
|
38525
38716
|
"src/scripts/replayRunner.ts"() {
|
|
38526
38717
|
"use strict";
|
|
38527
38718
|
import_chalk53 = __toESM(require("chalk"));
|
|
38528
38719
|
import_constants19 = require("@tradejs/core/constants");
|
|
38529
|
-
|
|
38720
|
+
import_data7 = require("@tradejs/core/data");
|
|
38530
38721
|
import_time14 = require("@tradejs/core/time");
|
|
38531
38722
|
import_redis21 = require("@tradejs/infra/redis");
|
|
38532
38723
|
init_runFormatting();
|
|
@@ -38576,6 +38767,7 @@ var init_replayRunner = __esm({
|
|
|
38576
38767
|
backtestEntries: replayStrategySnapshot.backtestEntries,
|
|
38577
38768
|
replaySignals: replayResult.signals,
|
|
38578
38769
|
replayLineages: replayResult.runtimeLineages,
|
|
38770
|
+
replayLineageScopes: replayResult.replayLineageScopes,
|
|
38579
38771
|
runtimeEvidencePath: replayRuntimeEvidencePath
|
|
38580
38772
|
});
|
|
38581
38773
|
const finishedAt = /* @__PURE__ */ new Date();
|
|
@@ -38742,7 +38934,7 @@ var init_replayRunner = __esm({
|
|
|
38742
38934
|
deploymentId: deployment.id,
|
|
38743
38935
|
assetClasses: deployment.assetClasses,
|
|
38744
38936
|
deployment,
|
|
38745
|
-
closedIntervalMs: (0,
|
|
38937
|
+
closedIntervalMs: (0, import_data7.intervalToMs)(replayInterval)
|
|
38746
38938
|
});
|
|
38747
38939
|
if (!preparedRun || isReplayUpdateOnlyRun) {
|
|
38748
38940
|
return;
|
|
@@ -242,6 +242,46 @@ var findNearestRuntimeEvaluationOutcome = ({
|
|
|
242
242
|
}
|
|
243
243
|
return nearest;
|
|
244
244
|
};
|
|
245
|
+
var findNearestReplayEvaluationOutcome = ({
|
|
246
|
+
entry,
|
|
247
|
+
lineageScopes,
|
|
248
|
+
toleranceMs,
|
|
249
|
+
timestampOffsetMs
|
|
250
|
+
}) => {
|
|
251
|
+
const strategy = getEntryStrategy(entry);
|
|
252
|
+
if (!strategy) return null;
|
|
253
|
+
let nearest = null;
|
|
254
|
+
for (const scope of lineageScopes) {
|
|
255
|
+
if (scope.strategy !== strategy || scope.symbol !== entry.symbol) {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
for (const run of scope.evaluationRuns ?? []) {
|
|
259
|
+
if (run.stepMs <= 0) continue;
|
|
260
|
+
const targetTimestamp = entry.timestamp - timestampOffsetMs;
|
|
261
|
+
if (targetTimestamp < run.firstTimestamp - toleranceMs || targetTimestamp > run.lastTimestamp + toleranceMs) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
const step = Math.round(
|
|
265
|
+
(targetTimestamp - run.firstTimestamp) / run.stepMs
|
|
266
|
+
);
|
|
267
|
+
const candidateTimestamp = run.firstTimestamp + step * run.stepMs;
|
|
268
|
+
const timestampDiffMs = Math.abs(
|
|
269
|
+
candidateTimestamp + timestampOffsetMs - entry.timestamp
|
|
270
|
+
);
|
|
271
|
+
if (candidateTimestamp < run.firstTimestamp || candidateTimestamp > run.lastTimestamp || timestampDiffMs > toleranceMs || nearest && timestampDiffMs >= nearest.timestampDiffMs) {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
nearest = {
|
|
275
|
+
status: run.status,
|
|
276
|
+
reason: run.reason,
|
|
277
|
+
timestamp: candidateTimestamp,
|
|
278
|
+
timestampDiffMs,
|
|
279
|
+
source: "replay_scope_compact"
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return nearest;
|
|
284
|
+
};
|
|
245
285
|
var hasRuntimeLineageCoverage = ({
|
|
246
286
|
entry,
|
|
247
287
|
lineageScopes
|
|
@@ -496,6 +536,7 @@ var buildReplayMismatchDrilldown = ({
|
|
|
496
536
|
runtimeSignalEvaluations = [],
|
|
497
537
|
replaySignals = [],
|
|
498
538
|
replaySignalEvaluations = [],
|
|
539
|
+
replayLineageScopes = [],
|
|
499
540
|
runtimeLineageScopes = [],
|
|
500
541
|
toleranceMs,
|
|
501
542
|
backtestTimestampOffsetMs,
|
|
@@ -522,7 +563,16 @@ var buildReplayMismatchDrilldown = ({
|
|
|
522
563
|
toleranceMs,
|
|
523
564
|
timestampOffsetMs: backtestTimestampOffsetMs
|
|
524
565
|
});
|
|
525
|
-
const
|
|
566
|
+
const nearestReplayEvaluationOutcome = findNearestReplayEvaluationOutcome({
|
|
567
|
+
entry,
|
|
568
|
+
lineageScopes: replayLineageScopes,
|
|
569
|
+
toleranceMs,
|
|
570
|
+
timestampOffsetMs: backtestTimestampOffsetMs
|
|
571
|
+
});
|
|
572
|
+
const classification = nearestReplaySignal ? classifySignalDiagnostic(nearestReplaySignal.signal) : nearestReplayEvaluation ? classifyEvaluationDiagnostic(nearestReplayEvaluation.evaluation) : nearestReplayEvaluationOutcome ? {
|
|
573
|
+
classification: "core_skipped",
|
|
574
|
+
reason: nearestReplayEvaluationOutcome.reason
|
|
575
|
+
} : nearestCandidate?.nearest ? {
|
|
526
576
|
classification: "timing_or_price_drift",
|
|
527
577
|
reason: nearestCandidate.reason
|
|
528
578
|
} : {
|
|
@@ -546,7 +596,8 @@ var buildReplayMismatchDrilldown = ({
|
|
|
546
596
|
timestampDiffMs: nearestReplayEvaluation.timestampDiffMs
|
|
547
597
|
}),
|
|
548
598
|
...includeArtifacts ? { replayEvaluationArtifact: nearestReplayEvaluation.evaluation } : {}
|
|
549
|
-
} : {}
|
|
599
|
+
} : {},
|
|
600
|
+
...nearestReplayEvaluationOutcome ? { replayEvaluationOutcome: nearestReplayEvaluationOutcome } : {}
|
|
550
601
|
};
|
|
551
602
|
});
|
|
552
603
|
const backtestOnlyDiagnostics = backtestOnly.map((entry, index) => {
|
|
@@ -656,6 +707,7 @@ var buildReplayRuntimeComparisonDetails = ({
|
|
|
656
707
|
runtimeSignalEvaluations,
|
|
657
708
|
replaySignals,
|
|
658
709
|
replaySignalEvaluations,
|
|
710
|
+
replayLineageScopes,
|
|
659
711
|
runtimeLineageScopes
|
|
660
712
|
}) => {
|
|
661
713
|
const runtimeDetails = runtimeEntries.map(toRuntimeParityDetail);
|
|
@@ -715,6 +767,7 @@ var buildReplayRuntimeComparisonDetails = ({
|
|
|
715
767
|
runtimeSignalEvaluations,
|
|
716
768
|
replaySignals,
|
|
717
769
|
replaySignalEvaluations,
|
|
770
|
+
replayLineageScopes,
|
|
718
771
|
runtimeLineageScopes,
|
|
719
772
|
toleranceMs,
|
|
720
773
|
backtestTimestampOffsetMs,
|
|
@@ -737,6 +790,7 @@ var buildReplayExchangeComparisonDetails = ({
|
|
|
737
790
|
runtimeSignalEvaluations,
|
|
738
791
|
replaySignals,
|
|
739
792
|
replaySignalEvaluations,
|
|
793
|
+
replayLineageScopes,
|
|
740
794
|
runtimeLineageScopes
|
|
741
795
|
}) => {
|
|
742
796
|
const toExchangeDetail = (entry) => toExchangeParityDetail({
|
|
@@ -824,6 +878,7 @@ var buildReplayExchangeComparisonDetails = ({
|
|
|
824
878
|
runtimeSignalEvaluations,
|
|
825
879
|
replaySignals,
|
|
826
880
|
replaySignalEvaluations,
|
|
881
|
+
replayLineageScopes,
|
|
827
882
|
runtimeLineageScopes,
|
|
828
883
|
toleranceMs,
|
|
829
884
|
backtestTimestampOffsetMs,
|