Files
foxhunt/scripts/analyze_checkpoints_simple.py
jgrusewski 650b3894c6 🚀 Wave 160 Phase 5: Complete ML Ensemble + Production Deployment (27 Agents)
## Executive Summary
Deployed 27 parallel agents: all 6 models operational, ensemble working, adaptive
strategy integrated, hyperparameter tuning automated, TFT fixed, critical blocker
resolved (DbnSequenceLoader 99.85% memory reduction 40.6GB→61MB).

## Critical Fixes
- Agent 85: DbnSequenceLoader memory fix (UNBLOCKED all ML training)
- Agent 79: TFT 5 critical bugs fixed
- Agent 86: Adaptive strategy integration (regime-aware ensemble)
- Agent 88: Liquid NN API fix (14 compilation errors)
- Agent 89: Paper trading deployment (LIVE, 3-model ensemble)

## Infrastructure
- Database: 2,127 writes/sec (212% of target)
- Memory: DQN 192MB, PPO 288MB, TFT 384MB (all within targets)
- Ensemble: Sharpe 10.68, latency 35μs, throughput >20K/sec
- Monitoring: 22 alerts, PagerDuty integration

## Files: 193 changed, +70,250 insertions, -414 deletions

🤖 Generated with Claude Code - Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-14 18:41:48 +02:00

333 lines
15 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Simple Checkpoint Comparison Analysis (no matplotlib dependency)
Analyzes backtest results for all DQN and PPO checkpoints
"""
import json
import sys
from pathlib import Path
from collections import defaultdict
def load_results(results_file):
"""Load backtest results from JSON"""
with open(results_file, 'r') as f:
return json.load(f)
def filter_valid_results(results):
"""Filter out checkpoints with no trades or invalid metrics"""
return [r for r in results if r['total_trades'] > 0]
def create_comparison_analysis(results):
"""Analyze and compare DQN vs PPO checkpoints"""
# Separate DQN and PPO
dqn_results = [r for r in results if r['model_type'] == 'DQN']
ppo_results = [r for r in results if r['model_type'] == 'PPO']
print("\n" + "="*100)
print("📊 CHECKPOINT BACKTESTING ANALYSIS - COMPLETE RESULTS")
print("="*100)
print(f"\n✅ Total Checkpoints Tested: {len(results)}")
print(f" - DQN: {len(dqn_results)} checkpoints")
print(f" - PPO: {len(ppo_results)} checkpoints")
# Top 10 DQN
print("\n" + "="*100)
print("🔵 TOP 10 DQN CHECKPOINTS (Ranked by Sharpe Ratio)")
print("="*100)
dqn_sorted = sorted(dqn_results, key=lambda x: x['sharpe_ratio'], reverse=True)[:10]
print(f"{'Rank':<6} {'Epoch':<8} {'Sharpe':<10} {'Win Rate':<12} {'Trades':<8} {'PnL':<14} {'Drawdown':<12} {'Freq':<10}")
print("-"*100)
for rank, r in enumerate(dqn_sorted, 1):
print(f"{rank:<6} {r['epoch']:<8} {r['sharpe_ratio']:<10.3f} {r['win_rate']:<11.1f}% {r['total_trades']:<8} ${r['total_pnl']:<13.2f} {r['max_drawdown']*100:<11.2f}% {r['trade_frequency']:<10.1f}")
# Top 10 PPO
print("\n" + "="*100)
print("🟢 TOP 10 PPO CHECKPOINTS (Ranked by Sharpe Ratio)")
print("="*100)
ppo_sorted = sorted(ppo_results, key=lambda x: x['sharpe_ratio'], reverse=True)[:10]
print(f"{'Rank':<6} {'Epoch':<8} {'Sharpe':<10} {'Win Rate':<12} {'Trades':<8} {'PnL':<14} {'Drawdown':<12} {'Freq':<10}")
print("-"*100)
for rank, r in enumerate(ppo_sorted, 1):
print(f"{rank:<6} {r['epoch']:<8} {r['sharpe_ratio']:<10.3f} {r['win_rate']:<11.1f}% {r['total_trades']:<8} ${r['total_pnl']:<13.2f} {r['max_drawdown']*100:<11.2f}% {r['trade_frequency']:<10.1f}")
# Statistical summary
print("\n" + "="*100)
print("📈 STATISTICAL SUMMARY")
print("="*100)
dqn_sharpe = [r['sharpe_ratio'] for r in dqn_results]
dqn_win_rate = [r['win_rate'] for r in dqn_results]
dqn_trades = [r['total_trades'] for r in dqn_results]
dqn_pnl = [r['total_pnl'] for r in dqn_results]
ppo_sharpe = [r['sharpe_ratio'] for r in ppo_results]
ppo_win_rate = [r['win_rate'] for r in ppo_results]
ppo_trades = [r['total_trades'] for r in ppo_results]
ppo_pnl = [r['total_pnl'] for r in ppo_results]
print(f"\n{'Metric':<30} {'DQN':>20} {'PPO':>20} {'Winner':>20}")
print("-"*100)
# Calculate stats
metrics = [
('Checkpoints Tested', len(dqn_results), len(ppo_results)),
('Avg Sharpe Ratio', sum(dqn_sharpe)/len(dqn_sharpe), sum(ppo_sharpe)/len(ppo_sharpe)),
('Max Sharpe Ratio', max(dqn_sharpe), max(ppo_sharpe)),
('Min Sharpe Ratio', min(dqn_sharpe), min(ppo_sharpe)),
('Avg Win Rate (%)', sum(dqn_win_rate)/len(dqn_win_rate), sum(ppo_win_rate)/len(ppo_win_rate)),
('Avg Total Trades', sum(dqn_trades)/len(dqn_trades), sum(ppo_trades)/len(ppo_trades)),
('Max Total Trades', max(dqn_trades), max(ppo_trades)),
('Avg PnL ($)', sum(dqn_pnl)/len(dqn_pnl), sum(ppo_pnl)/len(ppo_pnl)),
('Best PnL ($)', max(dqn_pnl), max(ppo_pnl)),
('Worst PnL ($)', min(dqn_pnl), min(ppo_pnl)),
]
for name, dqn_val, ppo_val in metrics:
if name == 'Checkpoints Tested':
winner = 'DQN' if dqn_val > ppo_val else 'PPO' if ppo_val > dqn_val else 'Tie'
print(f"{name:<30} {int(dqn_val):>20} {int(ppo_val):>20} {winner:>20}")
else:
winner = 'DQN' if dqn_val > ppo_val else 'PPO' if ppo_val > dqn_val else 'Tie'
print(f"{name:<30} {dqn_val:>20.3f} {ppo_val:>20.3f} {winner:>20}")
# Best overall checkpoints
print("\n" + "="*100)
print("🏆 BEST CHECKPOINTS (Highest Sharpe Ratio)")
print("="*100)
best_dqn = max(dqn_results, key=lambda x: x['sharpe_ratio'])
best_ppo = max(ppo_results, key=lambda x: x['sharpe_ratio'])
print(f"\n🔵 Best DQN: Epoch {best_dqn['epoch']}")
print(f" Sharpe Ratio: {best_dqn['sharpe_ratio']:.3f}")
print(f" Win Rate: {best_dqn['win_rate']:.1f}%")
print(f" Total Trades: {best_dqn['total_trades']}")
print(f" Total PnL: ${best_dqn['total_pnl']:.2f}")
print(f" Max Drawdown: {best_dqn['max_drawdown']:.2%}")
print(f" Trade Frequency: {best_dqn['trade_frequency']:.1f} trades/1000 bars")
print(f"\n🟢 Best PPO: Epoch {best_ppo['epoch']}")
print(f" Sharpe Ratio: {best_ppo['sharpe_ratio']:.3f}")
print(f" Win Rate: {best_ppo['win_rate']:.1f}%")
print(f" Total Trades: {best_ppo['total_trades']}")
print(f" Total PnL: ${best_ppo['total_pnl']:.2f}")
print(f" Max Drawdown: {best_ppo['max_drawdown']:.2%}")
print(f" Trade Frequency: {best_ppo['trade_frequency']:.1f} trades/1000 bars")
# Training phase analysis
print("\n" + "="*100)
print("📊 TRAINING PHASE ANALYSIS")
print("="*100)
# DQN Early vs Late
dqn_early = [r for r in dqn_results if r['epoch'] <= 200]
dqn_late = [r for r in dqn_results if r['epoch'] > 200]
print(f"\n🔵 DQN Performance by Training Phase")
print(f"\nEarly Epochs (≤200): {len(dqn_early)} checkpoints")
if dqn_early:
print(f" Avg Sharpe: {sum(r['sharpe_ratio'] for r in dqn_early)/len(dqn_early):.3f}")
print(f" Avg Trades: {sum(r['total_trades'] for r in dqn_early)/len(dqn_early):.1f}")
print(f" Avg Win Rate: {sum(r['win_rate'] for r in dqn_early)/len(dqn_early):.1f}%")
print(f"\nLate Epochs (>200): {len(dqn_late)} checkpoints")
if dqn_late:
print(f" Avg Sharpe: {sum(r['sharpe_ratio'] for r in dqn_late)/len(dqn_late):.3f}")
print(f" Avg Trades: {sum(r['total_trades'] for r in dqn_late)/len(dqn_late):.1f}")
print(f" Avg Win Rate: {sum(r['win_rate'] for r in dqn_late)/len(dqn_late):.1f}%")
# PPO Early vs Late
ppo_early = [r for r in ppo_results if r['epoch'] <= 200]
ppo_late = [r for r in ppo_results if r['epoch'] > 200]
print(f"\n🟢 PPO Performance by Training Phase")
print(f"\nEarly Epochs (≤200): {len(ppo_early)} checkpoints")
if ppo_early:
print(f" Avg Sharpe: {sum(r['sharpe_ratio'] for r in ppo_early)/len(ppo_early):.3f}")
print(f" Avg Trades: {sum(r['total_trades'] for r in ppo_early)/len(ppo_early):.1f}")
print(f" Avg Win Rate: {sum(r['win_rate'] for r in ppo_early)/len(ppo_early):.1f}%")
print(f"\nLate Epochs (>200): {len(ppo_late)} checkpoints")
if ppo_late:
print(f" Avg Sharpe: {sum(r['sharpe_ratio'] for r in ppo_late)/len(ppo_late):.3f}")
print(f" Avg Trades: {sum(r['total_trades'] for r in ppo_late)/len(ppo_late):.1f}")
print(f" Avg Win Rate: {sum(r['win_rate'] for r in ppo_late)/len(ppo_late):.1f}%")
# Key findings
print("\n" + "="*100)
print("🔍 KEY FINDINGS")
print("="*100)
print("\n1. **Hypothesis Validation: Early Epochs (10-100) vs Late Epochs (400-500)**")
# Compare early vs very late
dqn_very_early = [r for r in dqn_results if 10 <= r['epoch'] <= 100]
dqn_very_late = [r for r in dqn_results if 400 <= r['epoch'] <= 500]
if dqn_very_early and dqn_very_late:
early_sharpe = sum(r['sharpe_ratio'] for r in dqn_very_early) / len(dqn_very_early)
late_sharpe = sum(r['sharpe_ratio'] for r in dqn_very_late) / len(dqn_very_late)
early_trades = sum(r['total_trades'] for r in dqn_very_early) / len(dqn_very_early)
late_trades = sum(r['total_trades'] for r in dqn_very_late) / len(dqn_very_late)
print(f"\n DQN Early (10-100):")
print(f" - Avg Sharpe: {early_sharpe:.3f}")
print(f" - Avg Trades: {early_trades:.1f}")
print(f"\n DQN Late (400-500):")
print(f" - Avg Sharpe: {late_sharpe:.3f}")
print(f" - Avg Trades: {late_trades:.1f}")
if late_sharpe > early_sharpe:
print(f"\n ✅ HYPOTHESIS CONFIRMED: Late epochs have {late_sharpe/early_sharpe:.2f}x better Sharpe ratio")
else:
print(f"\n ❌ HYPOTHESIS REJECTED: Early epochs have better Sharpe ratio")
print("\n2. **Optimal Training Duration**")
# Find best epoch ranges
dqn_by_range = defaultdict(list)
for r in dqn_results:
epoch_range = (r['epoch'] // 100) * 100
dqn_by_range[epoch_range].append(r)
print(f"\n DQN Best Performance by Epoch Range:")
for epoch_range in sorted(dqn_by_range.keys()):
checkpoints = dqn_by_range[epoch_range]
avg_sharpe = sum(r['sharpe_ratio'] for r in checkpoints) / len(checkpoints)
best = max(checkpoints, key=lambda x: x['sharpe_ratio'])
print(f" Epochs {epoch_range}-{epoch_range+99}: Avg Sharpe {avg_sharpe:.3f}, Best: Epoch {best['epoch']} (Sharpe {best['sharpe_ratio']:.3f})")
ppo_by_range = defaultdict(list)
for r in ppo_results:
epoch_range = (r['epoch'] // 100) * 100
ppo_by_range[epoch_range].append(r)
print(f"\n PPO Best Performance by Epoch Range:")
for epoch_range in sorted(ppo_by_range.keys()):
checkpoints = ppo_by_range[epoch_range]
avg_sharpe = sum(r['sharpe_ratio'] for r in checkpoints) / len(checkpoints)
best = max(checkpoints, key=lambda x: x['sharpe_ratio'])
print(f" Epochs {epoch_range}-{epoch_range+99}: Avg Sharpe {avg_sharpe:.3f}, Best: Epoch {best['epoch']} (Sharpe {best['sharpe_ratio']:.3f})")
print("\n3. **DQN vs PPO Comparison**")
overall_best = max(dqn_results + ppo_results, key=lambda x: x['sharpe_ratio'])
print(f"\n 🏆 Overall Winner: {overall_best['model_type']} Epoch {overall_best['epoch']}")
print(f" Sharpe Ratio: {overall_best['sharpe_ratio']:.3f}")
print(f" PnL: ${overall_best['total_pnl']:.2f}")
return dqn_results, ppo_results
def create_markdown_report(dqn_results, ppo_results, output_dir):
"""Create comprehensive markdown report"""
dqn_sorted = sorted(dqn_results, key=lambda x: x['sharpe_ratio'], reverse=True)[:10]
ppo_sorted = sorted(ppo_results, key=lambda x: x['sharpe_ratio'], reverse=True)[:10]
report = []
report.append("# Checkpoint Backtesting Results")
report.append(f"\n**Date**: 2025-10-14")
report.append(f"**Total Checkpoints Tested**: {len(dqn_results) + len(ppo_results)}")
report.append(f"**Data**: 6E.FUT (Euro FX Futures), 7,223 bars, 4 days")
report.append("\n---\n")
# Executive Summary
best_dqn = max(dqn_results, key=lambda x: x['sharpe_ratio'])
best_ppo = max(ppo_results, key=lambda x: x['sharpe_ratio'])
report.append("## Executive Summary")
report.append(f"\n### DQN Performance")
report.append(f"- **Best Checkpoint**: Epoch {best_dqn['epoch']}")
report.append(f"- **Best Sharpe Ratio**: {best_dqn['sharpe_ratio']:.3f}")
report.append(f"- **Best PnL**: ${best_dqn['total_pnl']:.2f}")
report.append(f"- **Win Rate**: {best_dqn['win_rate']:.1f}%")
report.append(f"\n### PPO Performance")
report.append(f"- **Best Checkpoint**: Epoch {best_ppo['epoch']}")
report.append(f"- **Best Sharpe Ratio**: {best_ppo['sharpe_ratio']:.3f}")
report.append(f"- **Best PnL**: ${best_ppo['total_pnl']:.2f}")
report.append(f"- **Win Rate**: {best_ppo['win_rate']:.1f}%")
# Top 10 DQN
report.append("\n---\n")
report.append("## Top 10 DQN Checkpoints")
report.append("\n| Rank | Epoch | Sharpe | Win Rate | Trades | PnL | Drawdown | Trade Freq |")
report.append("|------|-------|--------|----------|--------|-----|----------|------------|")
for rank, r in enumerate(dqn_sorted, 1):
report.append(f"| {rank} | {r['epoch']} | {r['sharpe_ratio']:.3f} | {r['win_rate']:.1f}% | {r['total_trades']} | ${r['total_pnl']:.2f} | {r['max_drawdown']:.2%} | {r['trade_frequency']:.1f} |")
# Top 10 PPO
report.append("\n---\n")
report.append("## Top 10 PPO Checkpoints")
report.append("\n| Rank | Epoch | Sharpe | Win Rate | Trades | PnL | Drawdown | Trade Freq |")
report.append("|------|-------|--------|----------|--------|-----|----------|------------|")
for rank, r in enumerate(ppo_sorted, 1):
report.append(f"| {rank} | {r['epoch']} | {r['sharpe_ratio']:.3f} | {r['win_rate']:.1f}% | {r['total_trades']} | ${r['total_pnl']:.2f} | {r['max_drawdown']:.2%} | {r['trade_frequency']:.1f} |")
# Production Recommendations
report.append("\n---\n")
report.append("## Production Deployment Recommendations")
report.append(f"\n### Primary Recommendation: **{best_dqn['model_type']} Epoch {best_dqn['epoch']}**")
report.append(f"- Sharpe Ratio: {best_dqn['sharpe_ratio']:.3f}")
report.append(f"- Win Rate: {best_dqn['win_rate']:.1f}%")
report.append(f"- Total PnL: ${best_dqn['total_pnl']:.2f}")
report.append(f"- Max Drawdown: {best_dqn['max_drawdown']:.2%}")
report.append(f"\n### Alternative: **{best_ppo['model_type']} Epoch {best_ppo['epoch']}**")
report.append(f"- Sharpe Ratio: {best_ppo['sharpe_ratio']:.3f}")
report.append(f"- Win Rate: {best_ppo['win_rate']:.1f}%")
report.append(f"- Total PnL: ${best_ppo['total_pnl']:.2f}")
report.append(f"- Max Drawdown: {best_ppo['max_drawdown']:.2%}")
# Save report
report_file = output_dir / 'CHECKPOINT_BACKTEST_REPORT.md'
with open(report_file, 'w') as f:
f.write('\n'.join(report))
print(f"\n📄 Markdown report saved to: {report_file}")
def main():
if len(sys.argv) < 2:
print("Usage: python analyze_checkpoints_simple.py <results_json_file>")
sys.exit(1)
results_file = Path(sys.argv[1])
if not results_file.exists():
print(f"Error: Results file not found: {results_file}")
sys.exit(1)
# Create output directory
output_dir = Path(__file__).parent.parent / 'results'
output_dir.mkdir(exist_ok=True)
# Load results
print(f"\n📖 Loading results from: {results_file}")
results = load_results(results_file)
# Filter valid results
valid_results = filter_valid_results(results)
print(f"✅ Found {len(valid_results)} checkpoints with valid trades")
# Create comprehensive analysis
dqn_results, ppo_results = create_comparison_analysis(valid_results)
# Create markdown report
create_markdown_report(dqn_results, ppo_results, output_dir)
print("\n✅ Analysis complete!")
if __name__ == '__main__':
main()