feat: robustness stats + dynamic recommendation; retire settled report sections
Robustness (answers 'is the edge just outliers?'):
- _bucket_stats gains median_net_r, profit_factor, and net_avg_r_ex_top5
(expectancy with the top 5% of winners removed); shown as stat tiles.
- Portfolio sim gains per-calendar-year returns, shown in the sim table.
Dynamic recommendation ('What this backtest recommends' panel):
- _build_recommendation derives advice from the report's own numbers on
every run — exit policy (target vs best hold, with sim CAGRs), which
gate floors earn their keep (ablation Hold column), best momentum
cutoff, book-vs-SPY verdict, and an outlier-dependence warning when
the trimmed expectancy goes non-positive.
Retired (conclusions reached, tables removed from report + UI):
- Take-profit sweep (no interior optimum — fixed TP is the wrong tool
for momentum), trailing sweep (converged to the hold-to-horizon exit),
probability calibration (model is display-only by decision).
- _tp_primitives slimmed to _risk_and_stop_day; trailing machinery gone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+12
-32
@@ -236,41 +236,16 @@ export interface BacktestBucket {
|
||||
worst_r?: number | null;
|
||||
avg_hold_days?: number | null;
|
||||
net_r_per_day?: number | null;
|
||||
}
|
||||
|
||||
export interface BacktestCalibrationRow {
|
||||
bucket: string;
|
||||
n: number;
|
||||
predicted_avg: number;
|
||||
realized_hit_rate: number;
|
||||
// Robustness: distribution shape, and expectancy without the top winners.
|
||||
median_net_r?: number | null;
|
||||
profit_factor?: number | null;
|
||||
net_avg_r_ex_top5?: number | null;
|
||||
}
|
||||
|
||||
export interface BacktestSweepRow extends BacktestBucket {
|
||||
min_momentum_percentile: number;
|
||||
}
|
||||
|
||||
export interface BacktestTakeProfitRow {
|
||||
tp_pct: number;
|
||||
total: number;
|
||||
wins: number;
|
||||
hit_rate: number | null;
|
||||
avg_r: number | null;
|
||||
total_r: number | null;
|
||||
net_avg_r?: number | null;
|
||||
net_total_r?: number | null;
|
||||
}
|
||||
|
||||
export interface BacktestTrailingRow {
|
||||
trail_pct: number;
|
||||
total: number;
|
||||
wins: number;
|
||||
win_rate: number | null;
|
||||
avg_r: number | null;
|
||||
total_r: number | null;
|
||||
net_avg_r?: number | null;
|
||||
net_total_r?: number | null;
|
||||
}
|
||||
|
||||
export interface BacktestTimeExitRow {
|
||||
hold_days: number;
|
||||
total: number;
|
||||
@@ -304,10 +279,17 @@ export interface BacktestPortfolioPolicy {
|
||||
avg_hold_days: number | null;
|
||||
skipped_book_full: number;
|
||||
spy_return_pct: number | null;
|
||||
yearly_returns?: { year: number; return_pct: number | null }[];
|
||||
start_date: string;
|
||||
end_date: string;
|
||||
}
|
||||
|
||||
export interface BacktestRecommendation {
|
||||
headline: string | null;
|
||||
items: { topic: string; text: string }[];
|
||||
note?: string;
|
||||
}
|
||||
|
||||
export interface BacktestPortfolioSim {
|
||||
params: {
|
||||
starting_capital: number;
|
||||
@@ -359,11 +341,9 @@ export interface BacktestReport {
|
||||
sweep: BacktestSweepRow[];
|
||||
gate_ablation?: BacktestGateAblationRow[];
|
||||
gate_ablation_note?: string;
|
||||
take_profit_sweep?: BacktestTakeProfitRow[];
|
||||
trailing_sweep?: BacktestTrailingRow[];
|
||||
time_exit_sweep?: BacktestTimeExitRow[];
|
||||
portfolio_sim?: BacktestPortfolioSim;
|
||||
calibration: BacktestCalibrationRow[];
|
||||
recommendation?: BacktestRecommendation;
|
||||
signal_eval?: BacktestSignalEvalRow[];
|
||||
signal_eval_note?: string;
|
||||
note: string;
|
||||
|
||||
Reference in New Issue
Block a user