Repository navigation
feat(strategies): add RunReport with serialization and warm-start - #1005
Conversation
|
@pimaster900 is attempting to deploy a commit to the Collins' projects Team on Vercel. A member of the Team first needs to authorize it. |
- Define RunReport type (scenario, risk metrics, event counts, final state) - Serialize/deserialize with stroops-as-strings for lossless round-trips - Version the format; unknown versions throw UnknownReportVersionError - Add buildWarmStartContext and mergeReports for resuming long runs - Export all new types and functions from package index - 25 tests covering round-trip fidelity, warm-start equivalence, and version errors
78a950c to
f512d41
Compare
12a4ef3 to
1f4f18d
Compare
collinsezedike
left a comment
There was a problem hiding this comment.
@pimaster900 thank you for this contribution. A run report that carries the canonical Scenario closes a real gap, since a run's inputs were previously not recoverable from its output at all, and the warm-start path gives that record a second use.
I pushed a commit to your branch with some tightening on top: mergeReports now also rejects a continuation whose starting capital disagrees with the base's final value and one whose final state predates its own window end, deserializeFixed requires a string so a JSON number cannot reach BigInt already rounded, and sub-second instants survive the round trip through a window boundary.
Merging now.
|
@pimaster900 if Meridian is useful to you, a star on the repository would help other developers find it. |
Summary
RunReport, a self-contained record of a backtest run carrying the scenario it was produced from, the risk metrics, the event counts and the final portfolio state.RunReport.scenariothe canonicalScenariorather than a four-field summary, so the report carries everything a run is reproduced from. The seed, the data sources, the starting capital and the strategy params were previously not recorded at all, so two runs differing in any of them produced indistinguishable reports.engineVersionstays its own field, sincestrategy.versionversions the strategy config and not the engine.parseScenarioon deserialize, so a corrupted report cannot hand a caller a scenario the engine would refuse at run time.FixedPointDecimalas its raw stroop count in a decimal string, so a report round-trips through JSON without value drift, and reject a malformed stroop value rather than lettingBigIntread it as a number. A JSON number is rejected as well, sinceRegExp.testcoerces andJSON.parsehas already rounded the value by the time the guard sees it.REPORT_FORMAT_VERSIONand fail loudly on an unknown version withUnknownReportVersionErrorinstead of misparsing it.buildWarmStartContextandmergeReportsso a long run resumes from a saved report rather than replaying from the beginning. The context carries a full continuation scenario, and a window that is not a whole number of steps is rejected rather than handed to a clock that would throw on it.mergeReportsreject a continuation that does not continue the base. It checks that the window start is the base's final timestamp, that the starting capital is the base's final value, that the window end is the requested end, that the final state is from the continuation's own window end rather than earlier, that the engine version matches, and that the seed, source, strategy, params, assets and step agree. Window boundaries are compared as instants rather than as strings.mergeReportsreject a valid pair.scenario.ts, next to the duration format they implement, so the report does not reach into a market-regime fixture builder for them.Test plan
pnpm --filter @meridian/strategies coveragepasses, 656 tests across 35 filesreport.tsat 100% across statements, branches, functions and linespnpm typecheck,pnpm typecheck:apiandpnpm lintpass across the workspacenpx prettier --checkpasses on the changed filesCloses #882