-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_backtest_comparison.py
More file actions
182 lines (151 loc) Β· 7.36 KB
/
Copy pathtest_backtest_comparison.py
File metadata and controls
182 lines (151 loc) Β· 7.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
from connection import AlpacaConnection
from strategies.backtest_value_averaging import BacktestValueAveragingStrategy
from strategies.backtest_dca import BacktestDCAStrategy
import logging
from config import LOG_LEVEL, LOG_FILE
from datetime import datetime, timedelta
import pandas as pd
import matplotlib.pyplot as plt
import os
# Configure logging
logging.basicConfig(
level=getattr(logging, LOG_LEVEL),
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(LOG_FILE),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
def plot_comparison(va_results, dca_results, symbol):
"""Plot comparison of VA and DCA strategies"""
try:
# Create figure with two subplots
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))
# Plot portfolio values
ax1.plot(va_results['results']['date'], va_results['results']['portfolio_value'],
label='Value Averaging', color='blue')
ax1.plot(dca_results['results']['date'], dca_results['results']['portfolio_value'],
label='Dollar Cost Averaging', color='green')
ax1.set_title(f'Portfolio Value Comparison - {symbol}')
ax1.set_xlabel('Date')
ax1.set_ylabel('Portfolio Value ($)')
ax1.grid(True)
ax1.legend()
# Plot trades
if not va_results['trades'].empty:
ax2.scatter(va_results['trades']['date'], va_results['trades']['price'],
color='blue', label='VA Trades', alpha=0.6)
if not dca_results['trades'].empty:
ax2.scatter(dca_results['trades']['date'], dca_results['trades']['price'],
color='green', label='DCA Trades', alpha=0.6)
ax2.plot(va_results['results']['date'], va_results['results']['portfolio_value'],
color='blue', alpha=0.3, label='VA Portfolio Value')
ax2.plot(dca_results['results']['date'], dca_results['results']['portfolio_value'],
color='green', alpha=0.3, label='DCA Portfolio Value')
ax2.set_title(f'Trade Points Comparison - {symbol}')
ax2.set_xlabel('Date')
ax2.set_ylabel('Price ($)')
ax2.grid(True)
ax2.legend()
plt.tight_layout()
# Create results directory if it doesn't exist
os.makedirs('results', exist_ok=True)
# Save plot
plt.savefig(f'results/strategy_comparison_{symbol}.png')
logger.info(f"π Saved strategy comparison plot to 'results/strategy_comparison_{symbol}.png'")
except Exception as e:
logger.error(f"β Error plotting comparison: {str(e)}")
def run_strategy_comparison(symbol, alpaca, start_date, end_date):
"""Run strategy comparison for a single symbol"""
try:
# Initialize strategies
logger.info(f"π Initializing strategies for {symbol}...")
# Adjust weekly investment based on symbol
weekly_investment = 1000 if symbol == 'SPY' else 500 # $1000 for SPY, $500 for TSLA
va_strategy = BacktestValueAveragingStrategy(
api=alpaca.api,
symbol=symbol,
weekly_target=weekly_investment, # Increased weekly target
initial_capital=10000 # Start with $10,000
)
dca_strategy = BacktestDCAStrategy(
api=alpaca.api,
symbol=symbol,
weekly_investment=weekly_investment, # Increased weekly investment
initial_capital=10000 # Start with $10,000
)
# Run backtests
logger.info(f"π Running backtests for {symbol} from {start_date.date()} to {end_date.date()}...")
va_results = va_strategy.run_backtest(start_date, end_date)
dca_results = dca_strategy.run_backtest(start_date, end_date)
if va_results is None or dca_results is None:
logger.error(f"β One or both backtests failed for {symbol}")
return False
# Create results directory if it doesn't exist
os.makedirs('results', exist_ok=True)
# Plot comparison
plot_comparison(va_results, dca_results, symbol)
# Save detailed results to CSV
va_results['results'].to_csv(f'results/va_portfolio_values_{symbol}.csv')
va_results['trades'].to_csv(f'results/va_trades_{symbol}.csv')
dca_results['results'].to_csv(f'results/dca_portfolio_values_{symbol}.csv')
dca_results['trades'].to_csv(f'results/dca_trades_{symbol}.csv')
logger.info(f"πΎ Saved detailed results to CSV files for {symbol}")
# Print comparison metrics
va_metrics = va_results['metrics']
dca_metrics = dca_results['metrics']
logger.info(f"\nπ Strategy Comparison for {symbol}:")
logger.info("\nValue Averaging:")
logger.info(f"Final Portfolio Value: ${va_metrics['final_value']:,.2f}")
logger.info(f"Total Return: {va_metrics['total_return']:.2%}")
logger.info(f"Annual Return: {va_metrics['annual_return']:.2%}")
logger.info(f"Sharpe Ratio: {va_metrics['sharpe_ratio']:.2f}")
logger.info(f"Number of Trades: {va_metrics['num_trades']}")
logger.info(f"Total Investment: ${va_metrics.get('total_investment', 0):,.2f}")
logger.info("\nDollar Cost Averaging:")
logger.info(f"Final Portfolio Value: ${dca_metrics['final_value']:,.2f}")
logger.info(f"Total Return: {dca_metrics['total_return']:.2%}")
logger.info(f"Annual Return: {dca_metrics['annual_return']:.2%}")
logger.info(f"Sharpe Ratio: {dca_metrics['sharpe_ratio']:.2f}")
logger.info(f"Number of Trades: {dca_metrics['num_trades']}")
logger.info(f"Total Investment: ${dca_metrics.get('total_investment', 0):,.2f}")
return True
except Exception as e:
logger.error(f"β οΈ Unexpected error for {symbol}: {str(e)}")
return False
def test_strategies():
"""Test and compare VA and DCA strategies for multiple symbols"""
# Initialize connection
alpaca = AlpacaConnection()
try:
# Connect to Alpaca
logger.info("π Testing Alpaca connection...")
if not alpaca.connect():
logger.error("β Failed to connect to Alpaca")
return False
# Set backtest parameters - use historical dates
end_date = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
start_date = end_date - timedelta(days=180) # Test for 6 months
# Adjust dates to ensure we're using historical data
if start_date > end_date:
logger.error("β Start date cannot be in the future")
return False
# List of symbols to test
symbols = ['SPY', 'TSLA']
# Run comparison for each symbol
for symbol in symbols:
logger.info(f"\n{'='*50}")
logger.info(f"Running comparison for {symbol}")
logger.info(f"{'='*50}\n")
run_strategy_comparison(symbol, alpaca, start_date, end_date)
return True
except Exception as e:
logger.error(f"β οΈ Unexpected error: {str(e)}")
return False
finally:
# Clean up
if alpaca.is_connected():
alpaca.disconnect()
if __name__ == "__main__":
test_strategies()