Backtesting Trading Strategies with Python and pandas
Overview
Backtesting is a critical step in evaluating the performance of an investment or trading strategy. By simulating how the strategy would have performed in the past, investors can assess its profitability and identify potential weaknesses. In this tutorial, we’ll explore how to implement a backtesting framework using Python and the pandas
library.
We’ll focus on:
- Fetching historical data.
- Calculating buy/sell signals based on a simple strategy.
- Simulating trades.
- Analyzing performance metrics.
Prerequisites
Before starting, ensure you have the following installed:
- Python 3.x
- Necessary libraries:
pip install pandas yfinance matplotlib
Step-by-Step Guide
1. Define the Trading Strategy
We will implement a Simple Moving Average (SMA) Crossover Strategy:
- Buy Signal: When the short-term moving average crosses above the long-term moving average.
- Sell Signal: When the short-term moving average crosses below the long-term moving average.
2. Fetch Historical Data
Use the yfinance
library to get historical stock prices.
Example Code
import yfinance as yf
import pandas as pd
# Fetch historical data
def fetch_data(ticker, start_date, end_date):
data = yf.download(ticker, start=start_date, end=end_date)
return data[['Close']] # Focus on 'Close' prices
# Example usage
data = fetch_data("AAPL", "2020-01-01", "2023-01-01")
print(data.head())
3. Calculate Moving Averages
Calculate the short-term (e.g., 50-day) and long-term (e.g., 200-day) moving averages.
# Add moving averages to the data
def add_moving_averages(data, short_window, long_window):
data['SMA50'] = data['Close'].rolling(window=short_window).mean()
data['SMA200'] = data['Close'].rolling(window=long_window).mean()
return data
# Add SMA columns
data = add_moving_averages(data, 50, 200)
print(data.tail())
4. Generate Buy/Sell Signals
Implement logic to identify crossover points.
# Generate buy and sell signals
def generate_signals(data):
data['Signal'] = 0
data.loc[data['SMA50'] > data['SMA200'], 'Signal'] = 1 # Buy signal
data.loc[data['SMA50'] <= data['SMA200'], 'Signal'] = -1 # Sell signal
return data
# Apply signals
data = generate_signals(data)
print(data.tail())
5. Simulate Trades
Backtest the strategy by simulating trades based on the signals.
# Simulate trades and calculate returns
def backtest_strategy(data, initial_capital=10000):
capital = initial_capital
position = 0
data['Portfolio'] = capital
data['Returns'] = data['Close'].pct_change()
for i in range(1, len(data)):
if data['Signal'].iloc[i] == 1 and position == 0: # Buy
position = capital / data['Close'].iloc[i]
capital = 0
elif data['Signal'].iloc[i] == -1 and position > 0: # Sell
capital = position * data['Close'].iloc[i]
position = 0
# Update portfolio value
data['Portfolio'].iloc[i] = capital + (position * data['Close'].iloc[i])
return data
# Backtest
results = backtest_strategy(data)
print(results.tail())
6. Visualize Results
Plot the equity curve and the buy/sell signals.
import matplotlib.pyplot as plt
def plot_results(data):
plt.figure(figsize=(14, 7))
plt.plot(data['Close'], label='Stock Price', alpha=0.5)
plt.plot(data['SMA50'], label='SMA50', linestyle='--')
plt.plot(data['SMA200'], label='SMA200', linestyle='--')
# Mark buy/sell points
buy_signals = data[data['Signal'] == 1]
sell_signals = data[data['Signal'] == -1]
plt.scatter(buy_signals.index, buy_signals['Close'], label='Buy Signal', marker='^', color='green')
plt.scatter(sell_signals.index, sell_signals['Close'], label='Sell Signal', marker='v', color='red')
plt.title('Trading Strategy Backtest')
plt.legend()
plt.show()
# Plot the results
plot_results(results)
7. Evaluate Strategy Performance
Calculate key performance metrics:
- Total Returns: The overall profit or loss.
- Maximum Drawdown: The largest drop from peak to trough.
- Sharpe Ratio: Return-to-risk ratio.
# Evaluate performance
def evaluate_performance(data):
total_return = (data['Portfolio'].iloc[-1] - data['Portfolio'].iloc[0]) / data['Portfolio'].iloc[0]
max_drawdown = ((data['Portfolio'] / data['Portfolio'].cummax()) - 1).min()
sharpe_ratio = data['Returns'].mean() / data['Returns'].std() * (252 ** 0.5) # Annualized Sharpe Ratio
return {
"Total Return": total_return,
"Max Drawdown": max_drawdown,
"Sharpe Ratio": sharpe_ratio
}
# Performance metrics
performance = evaluate_performance(results)
print(performance)
Example Output
Portfolio Value Over Time:
- Graph showing stock price and portfolio value with buy/sell markers.
Performance Metrics:
Total Return: 0.35 (35%) Max Drawdown: -0.15 (-15%) Sharpe Ratio: 1.2
Next Steps
- Advanced Strategies: Implement strategies based on technical indicators like RSI or Bollinger Bands.
- Optimization: Automate parameter tuning (e.g., SMA windows) using libraries like
scipy.optimize
. - Real-Time Trading: Transition to real-time trading by integrating with brokers via APIs like Interactive Brokers or Alpaca.
References
With this framework, you can backtest various trading strategies and refine them for improved performance, helping you make data-driven investment decisions.
'Valuable Information' 카테고리의 다른 글
뉴욕 마라톤 참가비 참가비용과 신청 방법 총정리 (0) | 2024.11.26 |
---|---|
뉴욕 마라톤 참가비 참가비용과 신청 방법 총정리 (0) | 2024.11.26 |
How to Predict Market Gaps Using Overnight Futures Data (0) | 2024.11.26 |
아이오닉 9 현대자동차의 새로운 전기 SUV 아이오닉 9의 모든 것 (0) | 2024.11.26 |
이지아 독보적인 매력과 미스터리한 배우의 삶 (0) | 2024.11.26 |