""" Example usage of the Incremental Backtester. This script demonstrates how to use the IncBacktester for various scenarios: 1. Single strategy backtesting 2. Multiple strategy comparison 3. Parameter optimization with multiprocessing 4. Custom analysis and result saving 5. Comprehensive result logging and action tracking Run this script to see the backtester in action with real or synthetic data. """ import pandas as pd import numpy as np import logging from datetime import datetime, timedelta import os from cycles.IncStrategies import ( IncBacktester, BacktestConfig, IncRandomStrategy ) from cycles.utils.storage import Storage # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) def ensure_results_directory(): """Ensure the results directory exists.""" results_dir = "results" if not os.path.exists(results_dir): os.makedirs(results_dir) logger.info(f"Created results directory: {results_dir}") return results_dir def create_sample_data(days: int = 30) -> pd.DataFrame: """ Create sample OHLCV data for demonstration. Args: days: Number of days of data to generate Returns: pd.DataFrame: Sample OHLCV data """ # Create date range end_date = datetime.now() start_date = end_date - timedelta(days=days) timestamps = pd.date_range(start=start_date, end=end_date, freq='1min') # Generate realistic price data np.random.seed(42) n_points = len(timestamps) # Start with a base price base_price = 45000 # Generate price movements with trend and volatility trend = np.linspace(0, 0.1, n_points) # Slight upward trend volatility = np.random.normal(0, 0.002, n_points) # 0.2% volatility # Calculate prices log_returns = trend + volatility prices = base_price * np.exp(np.cumsum(log_returns)) # Generate OHLCV data data = [] for i, (timestamp, close_price) in enumerate(zip(timestamps, prices)): # Generate realistic OHLC intrabar_vol = close_price * 0.001 open_price = close_price + np.random.normal(0, intrabar_vol) high_price = max(open_price, close_price) + abs(np.random.normal(0, intrabar_vol)) low_price = min(open_price, close_price) - abs(np.random.normal(0, intrabar_vol)) volume = np.random.uniform(50, 500) data.append({ 'open': open_price, 'high': high_price, 'low': low_price, 'close': close_price, 'volume': volume }) df = pd.DataFrame(data, index=timestamps) return df def example_single_strategy(): """Example 1: Single strategy backtesting with comprehensive results.""" print("\n" + "="*60) print("EXAMPLE 1: Single Strategy Backtesting") print("="*60) # Create sample data data = create_sample_data(days=7) # 1 week of data # Save data storage = Storage() data_file = "sample_data_single.csv" storage.save_data(data, data_file) # Configure backtest config = BacktestConfig( data_file=data_file, start_date=data.index[0].strftime("%Y-%m-%d"), end_date=data.index[-1].strftime("%Y-%m-%d"), initial_usd=10000, stop_loss_pct=0.02, take_profit_pct=0.05 ) # Create strategy strategy = IncRandomStrategy(params={ "timeframe": "15min", "entry_probability": 0.15, "exit_probability": 0.2, "random_seed": 42 }) # Run backtest backtester = IncBacktester(config, storage) results = backtester.run_single_strategy(strategy) # Print results print(f"\nResults:") print(f" Strategy: {results['strategy_name']}") print(f" Profit: {results['profit_ratio']*100:.2f}%") print(f" Final Balance: ${results['final_usd']:,.2f}") print(f" Trades: {results['n_trades']}") print(f" Win Rate: {results['win_rate']*100:.1f}%") print(f" Max Drawdown: {results['max_drawdown']*100:.2f}%") # Save comprehensive results backtester.save_comprehensive_results([results], "example_single_strategy") # Cleanup if os.path.exists(f"data/{data_file}"): os.remove(f"data/{data_file}") return results def example_multiple_strategies(): """Example 2: Multiple strategy comparison with comprehensive results.""" print("\n" + "="*60) print("EXAMPLE 2: Multiple Strategy Comparison") print("="*60) # Create sample data data = create_sample_data(days=10) # 10 days of data # Save data storage = Storage() data_file = "sample_data_multiple.csv" storage.save_data(data, data_file) # Configure backtest config = BacktestConfig( data_file=data_file, start_date=data.index[0].strftime("%Y-%m-%d"), end_date=data.index[-1].strftime("%Y-%m-%d"), initial_usd=10000, stop_loss_pct=0.015 ) # Create multiple strategies with different parameters strategies = [ IncRandomStrategy(params={ "timeframe": "5min", "entry_probability": 0.1, "exit_probability": 0.15, "random_seed": 42 }), IncRandomStrategy(params={ "timeframe": "15min", "entry_probability": 0.12, "exit_probability": 0.18, "random_seed": 123 }), IncRandomStrategy(params={ "timeframe": "30min", "entry_probability": 0.08, "exit_probability": 0.12, "random_seed": 456 }), IncRandomStrategy(params={ "timeframe": "1h", "entry_probability": 0.06, "exit_probability": 0.1, "random_seed": 789 }) ] # Run backtest backtester = IncBacktester(config, storage) results = backtester.run_multiple_strategies(strategies) # Print comparison print(f"\nStrategy Comparison:") print(f"{'Strategy':<20} {'Timeframe':<10} {'Profit %':<10} {'Trades':<8} {'Win Rate %':<12}") print("-" * 70) for i, result in enumerate(results): if result.get("success", True): timeframe = result['strategy_params']['timeframe'] profit = result['profit_ratio'] * 100 trades = result['n_trades'] win_rate = result['win_rate'] * 100 print(f"Strategy {i+1:<13} {timeframe:<10} {profit:<10.2f} {trades:<8} {win_rate:<12.1f}") # Get summary statistics summary = backtester.get_summary_statistics(results) print(f"\nSummary Statistics:") print(f" Best Profit: {summary['profit_ratio']['max']*100:.2f}%") print(f" Worst Profit: {summary['profit_ratio']['min']*100:.2f}%") print(f" Average Profit: {summary['profit_ratio']['mean']*100:.2f}%") print(f" Profit Std Dev: {summary['profit_ratio']['std']*100:.2f}%") # Save comprehensive results backtester.save_comprehensive_results(results, "example_multiple_strategies", summary) # Cleanup if os.path.exists(f"data/{data_file}"): os.remove(f"data/{data_file}") return results, summary def example_parameter_optimization(): """Example 3: Parameter optimization with multiprocessing and comprehensive results.""" print("\n" + "="*60) print("EXAMPLE 3: Parameter Optimization") print("="*60) # Create sample data data = create_sample_data(days=5) # 5 days for faster optimization # Save data storage = Storage() data_file = "sample_data_optimization.csv" storage.save_data(data, data_file) # Configure backtest config = BacktestConfig( data_file=data_file, start_date=data.index[0].strftime("%Y-%m-%d"), end_date=data.index[-1].strftime("%Y-%m-%d"), initial_usd=10000 ) # Define parameter grids strategy_param_grid = { "timeframe": ["5min", "15min", "30min"], "entry_probability": [0.08, 0.12, 0.16], "exit_probability": [0.1, 0.15, 0.2], "random_seed": [42] # Keep seed constant for fair comparison } trader_param_grid = { "stop_loss_pct": [0.01, 0.015, 0.02], "take_profit_pct": [0.0, 0.03, 0.05] } # Run optimization (will use SystemUtils to determine optimal workers) backtester = IncBacktester(config, storage) print(f"Starting optimization with {len(strategy_param_grid['timeframe']) * len(strategy_param_grid['entry_probability']) * len(strategy_param_grid['exit_probability']) * len(trader_param_grid['stop_loss_pct']) * len(trader_param_grid['take_profit_pct'])} combinations...") results = backtester.optimize_parameters( strategy_class=IncRandomStrategy, param_grid=strategy_param_grid, trader_param_grid=trader_param_grid, max_workers=None # Use SystemUtils for optimal worker count ) # Get summary summary = backtester.get_summary_statistics(results) # Print optimization results print(f"\nOptimization Results:") print(f" Total Combinations: {summary['total_runs']}") print(f" Successful Runs: {summary['successful_runs']}") print(f" Failed Runs: {summary['failed_runs']}") if summary['successful_runs'] > 0: print(f" Best Profit: {summary['profit_ratio']['max']*100:.2f}%") print(f" Worst Profit: {summary['profit_ratio']['min']*100:.2f}%") print(f" Average Profit: {summary['profit_ratio']['mean']*100:.2f}%") # Show top 3 configurations valid_results = [r for r in results if r.get("success", True)] valid_results.sort(key=lambda x: x["profit_ratio"], reverse=True) print(f"\nTop 3 Configurations:") for i, result in enumerate(valid_results[:3]): print(f" {i+1}. Profit: {result['profit_ratio']*100:.2f}% | " f"Timeframe: {result['strategy_params']['timeframe']} | " f"Entry Prob: {result['strategy_params']['entry_probability']} | " f"Stop Loss: {result['trader_params']['stop_loss_pct']*100:.1f}%") # Save comprehensive results backtester.save_comprehensive_results(results, "example_parameter_optimization", summary) # Cleanup if os.path.exists(f"data/{data_file}"): os.remove(f"data/{data_file}") return results, summary def example_custom_analysis(): """Example 4: Custom analysis with detailed result examination.""" print("\n" + "="*60) print("EXAMPLE 4: Custom Analysis") print("="*60) # Create sample data with more volatility for interesting results data = create_sample_data(days=14) # 2 weeks # Save data storage = Storage() data_file = "sample_data_analysis.csv" storage.save_data(data, data_file) # Configure backtest config = BacktestConfig( data_file=data_file, start_date=data.index[0].strftime("%Y-%m-%d"), end_date=data.index[-1].strftime("%Y-%m-%d"), initial_usd=25000, # Larger starting capital stop_loss_pct=0.025, take_profit_pct=0.04 ) # Create strategy with specific parameters for analysis strategy = IncRandomStrategy(params={ "timeframe": "30min", "entry_probability": 0.1, "exit_probability": 0.15, "random_seed": 42 }) # Run backtest backtester = IncBacktester(config, storage) results = backtester.run_single_strategy(strategy) # Detailed analysis print(f"\nDetailed Analysis:") print(f" Strategy: {results['strategy_name']}") print(f" Timeframe: {results['strategy_params']['timeframe']}") print(f" Data Period: {config.start_date} to {config.end_date}") print(f" Data Points: {results['data_points']:,}") print(f" Processing Time: {results['backtest_duration_seconds']:.2f}s") print(f"\nPerformance Metrics:") print(f" Initial Capital: ${results['initial_usd']:,.2f}") print(f" Final Balance: ${results['final_usd']:,.2f}") print(f" Total Return: {results['profit_ratio']*100:.2f}%") print(f" Total Trades: {results['n_trades']}") if results['n_trades'] > 0: print(f" Win Rate: {results['win_rate']*100:.1f}%") print(f" Average Trade: ${results['avg_trade']:.2f}") print(f" Max Drawdown: {results['max_drawdown']*100:.2f}%") print(f" Total Fees: ${results['total_fees_usd']:.2f}") # Calculate additional metrics days_traded = (pd.to_datetime(config.end_date) - pd.to_datetime(config.start_date)).days annualized_return = (1 + results['profit_ratio']) ** (365 / days_traded) - 1 print(f" Annualized Return: {annualized_return*100:.2f}%") # Risk metrics if results['max_drawdown'] > 0: calmar_ratio = annualized_return / results['max_drawdown'] print(f" Calmar Ratio: {calmar_ratio:.2f}") # Save comprehensive results with custom analysis backtester.save_comprehensive_results([results], "example_custom_analysis") # Cleanup if os.path.exists(f"data/{data_file}"): os.remove(f"data/{data_file}") return results def main(): """Run all examples.""" print("Incremental Backtester Examples") print("="*60) print("This script demonstrates various features of the IncBacktester:") print("1. Single strategy backtesting") print("2. Multiple strategy comparison") print("3. Parameter optimization with multiprocessing") print("4. Custom analysis and metrics") print("5. Comprehensive result saving and action logging") # Ensure results directory exists ensure_results_directory() try: # Run all examples single_results = example_single_strategy() multiple_results, multiple_summary = example_multiple_strategies() optimization_results, optimization_summary = example_parameter_optimization() analysis_results = example_custom_analysis() print("\n" + "="*60) print("ALL EXAMPLES COMPLETED SUCCESSFULLY!") print("="*60) print("\nšŸ“Š Comprehensive results have been saved to the 'results' directory.") print("Each example generated multiple files:") print(" šŸ“‹ Summary JSON with session info and statistics") print(" šŸ“ˆ Detailed CSV with all backtest results") print(" šŸ“ Action log JSON with all operations performed") print(" šŸ“ Individual strategy JSON files with trades and details") print(" šŸ—‚ļø Master index JSON for easy navigation") print(f"\nšŸŽÆ Key Insights:") print(f" • Single strategy achieved {single_results['profit_ratio']*100:.2f}% return") print(f" • Multiple strategies: best {multiple_summary['profit_ratio']['max']*100:.2f}%, worst {multiple_summary['profit_ratio']['min']*100:.2f}%") print(f" • Optimization tested {optimization_summary['total_runs']} combinations") print(f" • Custom analysis provided detailed risk metrics") print(f"\nšŸ”§ System Performance:") print(f" • Used SystemUtils for optimal CPU core utilization") print(f" • All actions logged for reproducibility") print(f" • Results saved in multiple formats for analysis") print(f"\nāœ… The incremental backtester is ready for production use!") except Exception as e: logger.error(f"Example failed: {e}") print(f"\nError: {e}") import traceback traceback.print_exc() if __name__ == "__main__": main()