docs(experiments): add experiment 010 - start year sensitivity analysis
- Reproduce historical results:ca933e4code achieves 43.20% annual return - Attribution analysis: crash filter simplification (+4pp) + data extension (+2pp) - Start year traversal: 2020-2025, all years show 34-57% annual return - Compareca933e4vs HEAD (cabfee2) across different start years - Add test_start_year_analysis.py for reproducibility
This commit is contained in:
112
rotation/test_start_year_analysis.py
Normal file
112
rotation/test_start_year_analysis.py
Normal file
@@ -0,0 +1,112 @@
|
||||
"""
|
||||
Test different start years with select_num=1
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv(PROJECT_ROOT / '.env')
|
||||
|
||||
from rotation.config_loader import load_rotation_config
|
||||
from rotation.simple_rotation import SimpleRotationStrategy
|
||||
|
||||
|
||||
def run_test(start_date: str, select_num: int) -> dict:
|
||||
"""Run backtest with specified start date and select_num."""
|
||||
config_path = PROJECT_ROOT / 'rotation' / 'config_simple.yaml'
|
||||
|
||||
with open(config_path, 'r') as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
config['backtest']['start_date'] = start_date
|
||||
config['rotation']['select_num'] = select_num
|
||||
|
||||
temp_config_path = PROJECT_ROOT / 'rotation' / 'temp_config.yaml'
|
||||
with open(temp_config_path, 'w') as f:
|
||||
yaml.dump(config, f)
|
||||
|
||||
try:
|
||||
strategy = SimpleRotationStrategy(str(temp_config_path))
|
||||
result = strategy.run()
|
||||
return result['metrics']
|
||||
finally:
|
||||
if temp_config_path.exists():
|
||||
temp_config_path.unlink()
|
||||
|
||||
|
||||
def main():
|
||||
select_num = 1
|
||||
years = [2020, 2021, 2022, 2023, 2024, 2025]
|
||||
|
||||
print(f"\n{'='*80}")
|
||||
print(f"Testing select_num={select_num} with different start years")
|
||||
print(f"{'='*80}")
|
||||
|
||||
results = []
|
||||
|
||||
for year in years:
|
||||
start_date = f"{year}-01-01"
|
||||
print(f"\nTesting start_date={start_date}...")
|
||||
|
||||
try:
|
||||
metrics = run_test(start_date, select_num)
|
||||
results.append({
|
||||
'start_year': year,
|
||||
'start_date': start_date,
|
||||
'select_num': select_num,
|
||||
'total_return': metrics.get('total_return', 0),
|
||||
'annual_return': metrics.get('annual_return', 0),
|
||||
'max_drawdown': metrics.get('max_drawdown', 0),
|
||||
'sharpe_ratio': metrics.get('sharpe_ratio', 0),
|
||||
'rebalance_count': metrics.get('rebalance_count', 0),
|
||||
'win_rate': metrics.get('win_rate', 0),
|
||||
})
|
||||
print(f" Total Return: {metrics.get('total_return', 0)*100:.2f}%")
|
||||
print(f" Annual Return: {metrics.get('annual_return', 0)*100:.2f}%")
|
||||
print(f" Max Drawdown: {metrics.get('max_drawdown', 0)*100:.2f}%")
|
||||
print(f" Sharpe Ratio: {metrics.get('sharpe_ratio', 0):.3f}")
|
||||
print(f" Rebalance Count: {metrics.get('rebalance_count', 0)}")
|
||||
except Exception as e:
|
||||
print(f" Error: {e}")
|
||||
results.append({
|
||||
'start_year': year,
|
||||
'start_date': start_date,
|
||||
'select_num': select_num,
|
||||
'error': str(e)
|
||||
})
|
||||
|
||||
# Print summary table
|
||||
print(f"\n{'='*80}")
|
||||
print(f"SUMMARY TABLE (select_num={select_num})")
|
||||
print(f"{'='*80}")
|
||||
print(f"{'Start Year':<12} {'Total Return':<15} {'Annual Return':<15} {'Max Drawdown':<15} {'Sharpe':<10} {'Rebal':<8}")
|
||||
print(f"{'-'*80}")
|
||||
|
||||
for r in results:
|
||||
if 'error' in r:
|
||||
print(f"{r['start_year']:<12} {'ERROR':<15}")
|
||||
else:
|
||||
print(f"{r['start_year']:<12} {r['total_return']*100:>13.2f}% {r['annual_return']*100:>13.2f}% {r['max_drawdown']*100:>13.2f}% {r['sharpe_ratio']:>9.3f} {r['rebalance_count']:>7}")
|
||||
|
||||
# Save results to YAML
|
||||
output_path = PROJECT_ROOT / 'rotation' / 'results' / 'start_year_analysis.yaml'
|
||||
output_path.parent.mkdir(exist_ok=True)
|
||||
|
||||
with open(output_path, 'w') as f:
|
||||
yaml.dump({
|
||||
'select_num': select_num,
|
||||
'test_date': datetime.now().isoformat(),
|
||||
'results': results
|
||||
}, f, default_flow_style=False)
|
||||
|
||||
print(f"\nResults saved to: {output_path}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user