mirror of
https://github.com/chrisnov-it/quantumbotx.git
synced 2026-07-28 03:07:53 +00:00
160 lines
6.8 KiB
Python
160 lines
6.8 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
# test_final_backtest.py - Final test of complete backtesting workflow
|
||
|
|
|
||
|
|
import sys
|
||
|
|
import os
|
||
|
|
import pandas as pd
|
||
|
|
|
||
|
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||
|
|
|
||
|
|
def test_complete_backtest_workflow():
|
||
|
|
"""Test the complete backtesting workflow like the web interface"""
|
||
|
|
|
||
|
|
print("🔍 Final INDEX_BREAKOUT_PRO Backtest Workflow Test")
|
||
|
|
print("=" * 70)
|
||
|
|
|
||
|
|
try:
|
||
|
|
from core.backtesting.enhanced_engine import run_enhanced_backtest
|
||
|
|
from core.strategies.strategy_map import STRATEGY_MAP
|
||
|
|
|
||
|
|
# Load US500 data
|
||
|
|
csv_file = 'lab/backtest_data/US500_H1_data.csv'
|
||
|
|
if not os.path.exists(csv_file):
|
||
|
|
print(f"❌ CSV file not found: {csv_file}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
print(f"📊 Loading US500 data...")
|
||
|
|
df = pd.read_csv(csv_file, parse_dates=['time'])
|
||
|
|
print(f"✅ Loaded {len(df)} rows")
|
||
|
|
|
||
|
|
# Use recent 2000 rows for faster testing
|
||
|
|
test_df = df.tail(2000).copy()
|
||
|
|
print(f"Testing with recent {len(test_df)} rows")
|
||
|
|
print(f"Date range: {test_df['time'].min()} to {test_df['time'].max()}")
|
||
|
|
|
||
|
|
# Simulate web interface parameters (what user would send)
|
||
|
|
web_params = {
|
||
|
|
'breakout_period': 20,
|
||
|
|
'volume_surge_multiplier': 1.5,
|
||
|
|
'confirmation_candles': 2,
|
||
|
|
'atr_multiplier_sl': 2.0,
|
||
|
|
'atr_multiplier_tp': 4.0,
|
||
|
|
'min_breakout_size': 0.2
|
||
|
|
}
|
||
|
|
|
||
|
|
# Map to enhanced engine parameters (like API does)
|
||
|
|
enhanced_params = web_params.copy()
|
||
|
|
enhanced_params['risk_percent'] = 1.0 # Conservative for index
|
||
|
|
enhanced_params['sl_atr_multiplier'] = web_params.get('atr_multiplier_sl', 2.0)
|
||
|
|
enhanced_params['tp_atr_multiplier'] = web_params.get('atr_multiplier_tp', 4.0)
|
||
|
|
|
||
|
|
print(f"\\n⚙️ Parameters:")
|
||
|
|
print(f" Web interface: {web_params}")
|
||
|
|
print(f" Enhanced engine: {enhanced_params}")
|
||
|
|
|
||
|
|
# Engine configuration (like API sets)
|
||
|
|
engine_config = {
|
||
|
|
'enable_spread_costs': True,
|
||
|
|
'enable_slippage': True,
|
||
|
|
'enable_realistic_execution': True
|
||
|
|
}
|
||
|
|
|
||
|
|
# Extract symbol name (like API does)
|
||
|
|
symbol_name = 'US500'
|
||
|
|
print(f"\\n🎯 Symbol: {symbol_name}")
|
||
|
|
|
||
|
|
# Run enhanced backtest (exactly like the API)
|
||
|
|
print(f"\\n🚀 Running enhanced backtest...")
|
||
|
|
|
||
|
|
strategy_id = 'INDEX_BREAKOUT_PRO'
|
||
|
|
results = run_enhanced_backtest(
|
||
|
|
strategy_id,
|
||
|
|
enhanced_params,
|
||
|
|
test_df,
|
||
|
|
symbol_name=symbol_name,
|
||
|
|
engine_config=engine_config
|
||
|
|
)
|
||
|
|
|
||
|
|
if 'error' in results:
|
||
|
|
print(f"❌ Backtest error: {results['error']}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
print(f"✅ Backtest completed successfully!")
|
||
|
|
print(f"\\n📈 Results Summary:")
|
||
|
|
print(f" Strategy: {results.get('strategy_name', 'Unknown')}")
|
||
|
|
print(f" Total Trades: {results.get('total_trades', 0)}")
|
||
|
|
print(f" Wins: {results.get('wins', 0)}")
|
||
|
|
print(f" Losses: {results.get('losses', 0)}")
|
||
|
|
print(f" Win Rate: {results.get('win_rate_percent', 0):.1f}%")
|
||
|
|
print(f" Total Profit USD: ${results.get('total_profit_usd', 0):.2f}")
|
||
|
|
print(f" Spread Costs: ${results.get('total_spread_costs', 0):.2f}")
|
||
|
|
print(f" Net Profit: ${results.get('net_profit_after_costs', 0):.2f}")
|
||
|
|
print(f" Max Drawdown: {results.get('max_drawdown_percent', 0):.1f}%")
|
||
|
|
print(f" Final Capital: ${results.get('final_capital', 0):.2f}")
|
||
|
|
|
||
|
|
# Check if we have trades
|
||
|
|
trades = results.get('trades', [])
|
||
|
|
if len(trades) > 0:
|
||
|
|
print(f"\\n📋 Sample Trades (last 5):")
|
||
|
|
for i, trade in enumerate(trades[-5:]):
|
||
|
|
entry_price = trade.get('entry', 0)
|
||
|
|
exit_price = trade.get('exit', 0)
|
||
|
|
profit = trade.get('profit', 0)
|
||
|
|
position_type = trade.get('position_type', 'Unknown')
|
||
|
|
print(f" {i+1}. {position_type}: Entry ${entry_price:.2f} → Exit ${exit_price:.2f} = ${profit:.2f}")
|
||
|
|
|
||
|
|
# Test parameter API format (like frontend expects)
|
||
|
|
print(f"\\n🔧 Testing parameter API format...")
|
||
|
|
strategy_class = STRATEGY_MAP.get(strategy_id)
|
||
|
|
if strategy_class and hasattr(strategy_class, 'get_definable_params'):
|
||
|
|
params = strategy_class.get_definable_params()
|
||
|
|
|
||
|
|
# Normalize like the API does
|
||
|
|
normalized_params = []
|
||
|
|
for param in params:
|
||
|
|
normalized_param = param.copy()
|
||
|
|
if 'display_name' in param and 'label' not in param:
|
||
|
|
normalized_param['label'] = param['display_name']
|
||
|
|
elif 'label' not in param and 'display_name' not in param:
|
||
|
|
normalized_param['label'] = param['name'].replace('_', ' ').title()
|
||
|
|
normalized_params.append(normalized_param)
|
||
|
|
|
||
|
|
print(f"✅ Parameter normalization successful")
|
||
|
|
print(f"Sample parameters for frontend:")
|
||
|
|
for param in normalized_params[:3]:
|
||
|
|
print(f" • {param['name']}: '{param.get('label', 'NO LABEL')}'")
|
||
|
|
|
||
|
|
# Success criteria
|
||
|
|
if results.get('total_trades', 0) > 0:
|
||
|
|
print(f"\\n✅ SUCCESS: Strategy generated {results.get('total_trades', 0)} trades!")
|
||
|
|
print(f"\\n🎉 Both issues are now FIXED:")
|
||
|
|
print(f" 1. ✅ Parameter names show correctly (not 'undefined')")
|
||
|
|
print(f" 2. ✅ Backtest generates trades (not empty results)")
|
||
|
|
return True
|
||
|
|
else:
|
||
|
|
print(f"\\n⚠️ Warning: No trades generated with these parameters")
|
||
|
|
print(f"Try adjusting parameters for more signals")
|
||
|
|
return False
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
print(f"❌ Test failed: {e}")
|
||
|
|
import traceback
|
||
|
|
traceback.print_exc()
|
||
|
|
return False
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
success = test_complete_backtest_workflow()
|
||
|
|
|
||
|
|
if success:
|
||
|
|
print(f"\\n🚀 FINAL RESULT: Both issues RESOLVED!")
|
||
|
|
print(f"\\n📋 Summary of fixes:")
|
||
|
|
print(f" 1. Parameter API normalization: display_name → label")
|
||
|
|
print(f" 2. Strategy signal generation: Much more practical and flexible")
|
||
|
|
print(f" 3. Volume calculation: Adaptive and robust")
|
||
|
|
print(f" 4. Multiple signal types: Range, momentum, breakout, trend")
|
||
|
|
print(f"\\n🎯 The web interface should now show:")
|
||
|
|
print(f" • Proper parameter names (Breakout Detection Period, etc.)")
|
||
|
|
print(f" • Non-zero backtest results with actual trades")
|
||
|
|
print(f" • Realistic profit/loss calculations")
|
||
|
|
else:
|
||
|
|
print(f"\\n❌ Some issues remain - check the output above")
|