From 8c2b8233cfcfa97339a0246321fa200843636f6e Mon Sep 17 00:00:00 2001 From: "Bobby (aider)" Date: Fri, 14 Feb 2025 00:04:40 -0800 Subject: [PATCH] refactor: Enhance multi-ticker backtest error handling and debugging --- src/pages/backtesting/backtesting_page.py | 73 ++++++++++++++++------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/src/pages/backtesting/backtesting_page.py b/src/pages/backtesting/backtesting_page.py index d6ec03f..be32a30 100644 --- a/src/pages/backtesting/backtesting_page.py +++ b/src/pages/backtesting/backtesting_page.py @@ -466,40 +466,67 @@ def run_multi_ticker_backtest(tickers: list, start_date: datetime, end_date: dat print(f"\nTesting strategy on {ticker}") df = get_stock_data(ticker, start_date, end_date, 'daily') - if df.empty: + if df is None or df.empty: print(f"No data available for {ticker}") continue - df = prepare_data_for_backtest(df) + print(f"Data shape for {ticker}: {df.shape}") + print(f"Date range: {df.index.min()} to {df.index.max()}") + print(f"Columns: {df.columns.tolist()}") + + try: + df = prepare_data_for_backtest(df) + except Exception as e: + print(f"Error preparing data for {ticker}: {str(e)}") + continue + + print(f"Prepared data shape: {df.shape}") + print(f"Final columns: {df.columns.tolist()}") # Run backtest - DynamicStrategy.indicator_configs = indicator_settings - bt = Backtest(df, DynamicStrategy, cash=100000, commission=.002) - stats = bt.run() - - # Print raw stats for debugging - print("Debug - Available stats keys:", stats.keys()) - - # Store results with error handling for each metric - result = { - 'Ticker': ticker, - 'Return [%]': stats.get('Return [%]', stats.get('Return', 0)), - 'Sharpe Ratio': stats.get('Sharpe Ratio', 0), - 'Max Drawdown [%]': stats.get('Max. Drawdown [%]', stats.get('Max Drawdown', 0)), - 'Win Rate [%]': stats.get('Win Rate [%]', stats.get('Win Rate', 0)), - 'Number of Trades': stats.get('# Trades', stats.get('Number of Trades', 0)) - } - all_results.append(result) - - print(f"{ticker} - Return: {result['Return [%]']:.2f}%, " - f"Sharpe: {result['Sharpe Ratio']:.2f}, " - f"Drawdown: {result['Max Drawdown [%]']:.2f}%") + try: + DynamicStrategy.indicator_configs = indicator_settings + bt = Backtest(df, DynamicStrategy, cash=100000, commission=.002) + stats = bt.run() + + print(f"Backtest completed for {ticker}") + print("Available stats keys:", stats.keys()) + + # 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))) + } + + # Verify results are valid + if any(pd.isna(val) for val in result.values()): + print(f"Warning: NaN values in results for {ticker}") + continue + + all_results.append(result) + + print(f"Success - {ticker} results:") + for key, value in result.items(): + print(f"{key}: {value}") + + except Exception as e: + print(f"Error during backtest for {ticker}: {str(e)}") + continue except Exception as e: print(f"Error processing {ticker}: {str(e)}") 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?") raise ValueError("No valid results were generated from any ticker") return pd.DataFrame(all_results)