#!/usr/bin/env python3 """ Generate Quick Summary Statistics for Backtest Results Creates a concise reference card for production deployment """ import json import statistics # Load results with open('results/comprehensive_backtest_results_20251014_143309.json', 'r') as f: results = json.load(f) def generate_production_reference(): """Generate production reference card""" # Filter to active, high-quality models active_models = [r for r in results if r['total_trades'] > 50] # Top 5 by multiple criteria top_sharpe = sorted(active_models, key=lambda x: x['sharpe_ratio'], reverse=True)[:5] top_pnl = sorted(active_models, key=lambda x: x['total_pnl'], reverse=True)[:5] top_calmar = sorted([r for r in active_models if r['calmar_ratio'] > 0], key=lambda x: x['calmar_ratio'], reverse=True)[:5] print("\n" + "="*80) print("PRODUCTION REFERENCE CARD - TOP 5 MODELS BY METRIC") print("="*80) print("\nšŸ† TOP 5 BY SHARPE RATIO (RISK-ADJUSTED)") print("-" * 80) for i, m in enumerate(top_sharpe, 1): print(f"{i}. {m['model_name']:25} | Sharpe: {m['sharpe_ratio']:6.2f} | " f"WR: {m['win_rate']:5.1f}% | PnL: ${m['total_pnl']:8.2f} | " f"Trades: {m['total_trades']:3d}") print("\nšŸ’° TOP 5 BY TOTAL PNL (ABSOLUTE RETURNS)") print("-" * 80) for i, m in enumerate(top_pnl, 1): print(f"{i}. {m['model_name']:25} | PnL: ${m['total_pnl']:8.2f} | " f"Sharpe: {m['sharpe_ratio']:6.2f} | WR: {m['win_rate']:5.1f}% | " f"Trades: {m['total_trades']:3d}") print("\nšŸ›”ļø TOP 5 BY CALMAR RATIO (RETURN/DRAWDOWN)") print("-" * 80) for i, m in enumerate(top_calmar, 1): print(f"{i}. {m['model_name']:25} | Calmar: {m['calmar_ratio']:8.2f} | " f"DD: {m['max_drawdown']*100:6.4f}% | PnL: ${m['total_pnl']:8.2f}") # Consistent performers (all-around strong) consistent = [r for r in active_models if r['win_rate'] > 50 and r['profit_factor'] and r['profit_factor'] > 2 and r['calmar_ratio'] > 5 and r['sharpe_ratio'] > 3] print("\n⭐ TIER 1 CONSISTENT PERFORMERS (WR>50%, PF>2, Calmar>5, Sharpe>3)") print("-" * 80) print(f"Total: {len(consistent)} models") # Sort by composite score for m in consistent: m['composite_score'] = (m['sharpe_ratio'] + m['win_rate']/10 + m['calmar_ratio']/100) / 3 consistent_sorted = sorted(consistent, key=lambda x: x['composite_score'], reverse=True)[:10] for i, m in enumerate(consistent_sorted, 1): print(f"{i:2d}. {m['model_name']:25} | " f"Sharpe: {m['sharpe_ratio']:5.2f} | WR: {m['win_rate']:5.1f}% | " f"PnL: ${m['total_pnl']:7.2f} | Calmar: {m['calmar_ratio']:7.1f}") # Production ensemble recommendation print("\n" + "="*80) print("RECOMMENDED PRODUCTION ENSEMBLE (8 MODELS)") print("="*80) # 5 Tier 1 + 3 Tier 2 tier1 = consistent_sorted[:5] tier2_candidates = [m for m in top_pnl if m not in tier1][:3] print("\nšŸ“Š Tier 1: Consistent Performers (70% allocation)") for i, m in enumerate(tier1, 1): allocation = 14.0 # 70% / 5 models print(f"{i}. {m['model_name']:25} | {allocation:4.1f}% capital | " f"Sharpe: {m['sharpe_ratio']:5.2f} | WR: {m['win_rate']:5.1f}%") print("\nšŸš€ Tier 2: High Return (30% allocation)") for i, m in enumerate(tier2_candidates, 1): allocation = 10.0 # 30% / 3 models print(f"{i}. {m['model_name']:25} | {allocation:4.1f}% capital | " f"PnL: ${m['total_pnl']:7.2f} | Sharpe: {m['sharpe_ratio']:5.2f}") # Expected ensemble performance print("\n" + "="*80) print("EXPECTED ENSEMBLE PERFORMANCE") print("="*80) tier1_sharpe = statistics.mean([m['sharpe_ratio'] for m in tier1]) tier1_wr = statistics.mean([m['win_rate'] for m in tier1]) tier1_pnl = statistics.mean([m['total_pnl'] for m in tier1]) tier2_sharpe = statistics.mean([m['sharpe_ratio'] for m in tier2_candidates]) tier2_wr = statistics.mean([m['win_rate'] for m in tier2_candidates]) tier2_pnl = statistics.mean([m['total_pnl'] for m in tier2_candidates]) ensemble_sharpe = 0.7 * tier1_sharpe + 0.3 * tier2_sharpe ensemble_wr = 0.7 * tier1_wr + 0.3 * tier2_wr ensemble_pnl = 0.7 * tier1_pnl + 0.3 * tier2_pnl print(f"\nTier 1 Average: Sharpe {tier1_sharpe:.2f}, WR {tier1_wr:.1f}%, PnL ${tier1_pnl:.2f}") print(f"Tier 2 Average: Sharpe {tier2_sharpe:.2f}, WR {tier2_wr:.1f}%, PnL ${tier2_pnl:.2f}") print(f"\nWeighted Ensemble: Sharpe {ensemble_sharpe:.2f}, WR {ensemble_wr:.1f}%, PnL ${ensemble_pnl:.2f}") # Monthly return projection monthly_return_pct = (ensemble_pnl / 90) * 30 # Scale to 30 days annual_return_pct = monthly_return_pct * 12 print(f"\nProjected Returns (90-day backtest scaled):") print(f" Monthly: {monthly_return_pct:.1f}% (on $10K = ${monthly_return_pct * 100:.2f}/month)") print(f" Annual: {annual_return_pct:.1f}% (not compounded)") # Risk metrics ensemble_dd = statistics.mean([m['max_drawdown'] for m in tier1 + tier2_candidates]) print(f"\nRisk Metrics:") print(f" Expected Max Drawdown: {ensemble_dd*100:.3f}%") print(f" Expected Calmar Ratio: {(monthly_return_pct/30)/(ensemble_dd*100):.1f}") print("\n" + "="*80) print("PRODUCTION RISK LIMITS") print("="*80) print(""" 1. Per-Model Max Drawdown: 1.0% (kill switch) 2. Per-Model Min Win Rate: 55% (rolling 100 trades) 3. Per-Model Min Sharpe: 2.0 (rolling 50 trades) 4. Ensemble Max Drawdown: 2.0% (flatten all) 5. Daily Loss Limit: -3% (halt trading for 24h) 6. Trade Frequency: 10-30 trades/day per model 7. Position Sizing: 2% risk per trade 8. Max Correlation: 0.7 between models """) print("="*80) print("DEPLOYMENT CHECKLIST") print("="*80) print(""" ☐ Week 1: Out-of-sample validation (Jan-Mar 2025 data) ☐ Week 2: Production risk framework implementation ☐ Week 3: Ensemble system build + unit tests ☐ Week 4: Paper trading (target: Sharpe >2.0, WR >55%) ☐ Week 5: Limited live ($10K, Tier 1 only) ☐ Week 6: Daily monitoring (require >3% weekly return) ☐ Week 7: Add Tier 2 ($5K additional) ☐ Week 8: Scale to $50K if 10%+ return, <3% DD ☐ Week 9: Full production ($100K, 8-model ensemble) ☐ Week 10: Automated monitoring dashboard ☐ Week 11: Monthly retraining cycle begin ☐ Week 12: Operations playbook documentation """) def generate_model_matrix(): """Generate model selection matrix""" print("\n" + "="*80) print("MODEL SELECTION MATRIX") print("="*80) models = [r for r in results if r['total_trades'] > 50] # Categorize by characteristics categories = { 'High Sharpe (>7)': [m for m in models if m['sharpe_ratio'] > 7], 'High PnL (>$80)': [m for m in models if m['total_pnl'] > 80], 'Low Drawdown (<0.01%)': [m for m in models if m['max_drawdown'] < 0.0001], 'High Win Rate (>58%)': [m for m in models if m['win_rate'] > 58], 'Low Frequency (<20/day)': [m for m in models if m['trade_frequency'] < 20], 'Balanced (50-60% WR, 100-500 trades)': [m for m in models if 50 < m['win_rate'] < 60 and 100 < m['total_trades'] < 500] } for category, category_models in categories.items(): print(f"\n{category}: {len(category_models)} models") for m in sorted(category_models, key=lambda x: x['sharpe_ratio'], reverse=True)[:3]: print(f" • {m['model_name']:25} | Sharpe: {m['sharpe_ratio']:5.2f} | " f"WR: {m['win_rate']:5.1f}% | PnL: ${m['total_pnl']:7.2f}") if __name__ == '__main__': generate_production_reference() generate_model_matrix() print("\n" + "="*80) print("SUMMARY GENERATION COMPLETE") print("="*80 + "\n")