refactor: Improve multi-ticker backtest error handling and indicator settings processing

This commit is contained in:
Bobby (aider) 2025-02-14 00:09:14 -08:00
parent 840c96ede3
commit 1204b18a76

View File

@ -461,19 +461,28 @@ def run_multi_ticker_backtest(tickers: list, start_date: datetime, end_date: dat
"""Run backtest across multiple tickers and aggregate results"""
all_results = []
if not indicator_settings:
print("Error: No indicators selected")
raise ValueError("Please select at least one indicator")
# Convert indicator settings to the correct format
processed_settings = {}
for ind_name, ind_config in indicator_settings.items():
processed_settings[ind_name] = {
'type': ind_config['type'],
'params': {}
}
# Handle both optimization and non-optimization cases
if isinstance(ind_config['params'], dict):
# If params is a dictionary of parameter values (non-optimization mode)
processed_settings[ind_name] = {
'type': ind_config['type'],
'params': {k: float(v) if isinstance(v, (int, float)) else v
for k, v in ind_config['params'].items()}
}
else:
# If params is a dictionary of parameter ranges (optimization mode)
processed_settings[ind_name] = ind_config
for param_name, param_value in ind_config['params'].items():
# Handle both direct values and range dictionaries
if isinstance(param_value, dict):
# Use the minimum value from the range for non-optimization run
processed_settings[ind_name]['params'][param_name] = float(param_value['min'])
else:
processed_settings[ind_name]['params'][param_name] = float(param_value)
print(f"Processed indicator settings: {processed_settings}")
for ticker in tickers:
try:
@ -499,7 +508,10 @@ def run_multi_ticker_backtest(tickers: list, start_date: datetime, end_date: dat
# Run backtest
try:
# Set the indicator configs before creating the Backtest instance
DynamicStrategy.indicator_configs = processed_settings
print(f"Strategy configured with settings: {processed_settings}")
bt = Backtest(df, DynamicStrategy, cash=100000, commission=.002)
stats = bt.run()
@ -509,11 +521,11 @@ def run_multi_ticker_backtest(tickers: list, start_date: datetime, end_date: dat
# Store results with error handling for each metric
result = {
'Ticker': ticker,
'Return [%]': float(stats.get('Return [%]', stats.get('Return', 0))),
'Sharpe Ratio': float(stats.get('Sharpe Ratio', 0)),
'Max Drawdown [%]': float(stats.get('Max. Drawdown [%]', stats.get('Max Drawdown', 0))),
'Win Rate [%]': float(stats.get('Win Rate [%]', stats.get('Win Rate', 0))),
'Number of Trades': int(stats.get('# Trades', stats.get('Number of Trades', 0)))
'Return [%]': float(stats['Return [%]']), # Use direct key access
'Sharpe Ratio': float(stats['Sharpe Ratio']),
'Max Drawdown [%]': float(stats['Max. Drawdown [%]']),
'Win Rate [%]': float(stats['Win Rate [%]']),
'Number of Trades': int(stats['# Trades'])
}
# Verify results are valid
@ -537,12 +549,10 @@ def run_multi_ticker_backtest(tickers: list, start_date: datetime, end_date: dat
continue
if not all_results:
print("No valid results were generated. Check the following:")
print("1. Are the tickers valid?")
print("2. Is there data available for the selected date range?")
print("3. Are the indicator settings valid?")
print("4. Are there any errors in the strategy logic?")
print(f"Last used indicator settings: {processed_settings}")
print("\nNo valid results were generated. Debug information:")
print(f"Number of tickers processed: {len(tickers)}")
print(f"Indicator settings used: {processed_settings}")
print(f"Date range: {start_date} to {end_date}")
raise ValueError("No valid results were generated from any ticker")
return pd.DataFrame(all_results)