Audit date: 2026-05-08
Candidate audited: trend_basket-1h-lb720-tr1440-bt2880-rb168-top2-mm0.000-bm0.000-vw336-vc0.0300-lev0.75-exp0.50-vt0.2000
Source row: reports/strategy-expansion/rotation-risk-top.csv, row 1.
Verdict: passed.
The prior audit finding is fixed. trade_stats now uses the same executed-weight basis as the core equity curve, charges internal volatility-target turnover inside active trade segments, and charges the actual close-row turnover when a segment flattens. The generated rotation-risk-* reports are consistent with the repaired implementation.
| metric | reported | recomputed | status |
|---|---|---|---|
| total_return | 1.520238100611786 | 1.520238100611786 | match |
| annualized_return | 0.1564147619507854 | 0.1564147619507854 | match |
| max_drawdown | 0.0771828375342993 | 0.07718283753429936 | match |
| calmar | 2.0265484782323027 | 2.0265484782323027 | match |
| turnover_per_year | 6.024310117968542 | 6.024310117968542 | match |
| trades | 45 | 45 | match |
| win_rate | 0.5777777777777777 | 0.5777777777777777 | match |
| profit_factor | 7.384619055503101 | 7.384619055503101 | match |
Data window: 2019-12-25 00:00 UTC to 2026-05-03 15:00 UTC, 55,720 hourly rows, BTC/ETH universe.
First nonzero signal: 2020-04-30 00:00 UTC.
First executed exposure: 2020-04-30 01:00 UTC.
Passed.
scripts/refine_expansion_rotation_risk.py:131 computes trade statistics from executed = weights.shift(1).fillna(0.0), matching the equity curve execution basis at scripts/refine_expansion_rotation_risk.py:123.
For the audited candidate:
38.3183259661060712.91499134035575816.274426312324719.128908313425487trade_stats: 38.318325966105995The current reported profit_factor is 7.384619055503101. Recomputing the old entry/exit-only fee model gives 7.4386055102893875, confirming the regenerated report is not using the prior faulty basis.
No synthetic liquidation fee is added for positions still open at the final data row, because the core equity curve also does not force a final liquidation. This keeps trade_stats aligned with the equity curve.
Passed.
Batch recomputation of all 30 rows in rotation-risk-top.csv matched the current script output:
trades diff: 0win_rate diff: 0.0profit_factor diff: 8.881784197001252e-164.440892098500626e-16turnover_per_year diff: 8.881784197001252e-16Report files were written after the script modification:
2026-05-08 01:26:30 +0800rotation-risk-total.csv mtime: 2026-05-08 01:33:19 +0800rotation-risk-top.csv mtime: 2026-05-08 01:33:19 +0800rotation-risk-horizons.csv mtime: 2026-05-08 01:33:19 +0800rotation-risk-monthly.csv mtime: 2026-05-08 01:33:19 +0800rotation-risk-report.md mtime: 2026-05-08 01:33:19 +0800Passed.
Signal construction in scripts/search_expansion_rotation.py:173 uses current and historical closes for momentum, trend, BTC trend, BTC momentum, and BTC volatility. scripts/refine_expansion_rotation_risk.py:123 then applies weights.shift(1) before returns are multiplied in the equity curve.
The volatility-target scale at scripts/refine_expansion_rotation_risk.py:115 uses controlled.shift(1) and realized returns through the current row to size weights for that row; the equity curve executes those weights one row later. Therefore the current bar's return is not applied to a weight that was sized using that same return.
The first nonzero signal appears at 2020-04-30 00:00 UTC; the first executed exposure appears at 2020-04-30 01:00 UTC.
Passed.
horizon_rows slices the already compounded equity curve and computes each horizon as horizon.iloc[-1] / horizon.iloc[0] - 1, so recent horizons are not reset to initial equity. monthly_rows chains start_equity from the prior month end.
Relevant paths:
scripts/search_expansion_rotation.py:250scripts/search_expansion_rotation.py:269Passed.
The repaired trade_stats fee/turnover basis is aligned with the equity curve for executed weights, internal volatility-target turnover, and actual close-row turnover. The core equity curve remains free of same-row lookahead under the audited execution model.