examples/BacktestingMomentumTrading.ipynb
This notebook demonstrates how to perform backtesting of a momentum trading strategy using historical stock price data from OpenBB. A momentum trading strategy involves buying or selling assets based on recent price movements. In this notebook, we will:
The goal of the analysis is to test the effectiveness of a momentum-based trading strategy over time and to see how it performs in comparison to a simple buy-and-hold approach.
Author:
!pip install openbb -q
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from openbb import obb
symbols = ['AAPL', 'GOOG', 'MSFT', 'NVDA']
start_date = '2015-01-01'
initial_capital = 10000
short_window = 40
long_window = 100
dataframes = []
for symbol in symbols:
try:
data = obb.equity.price.historical(
symbol=symbol,
start_date=start_date,
provider="yfinance"
).to_df()
data['Symbol'] = symbol
dataframes.append(data)
except Exception as e:
print(f"Failed to fetch data for {symbol}: {str(e)}")
combined_data = pd.concat(dataframes)
combined_data = combined_data.reset_index()
combined_data.head()
def momentum_strategy(data, short_window, long_window):
data['Short MA'] = data['close'].rolling(window=short_window, min_periods=1).mean()
data['Long MA'] = data['close'].rolling(window=long_window, min_periods=1).mean()
data['Signal'] = 0
signal_values = np.where(
data['Short MA'][short_window:] > data['Long MA'][short_window:], 1, -1
)
data.loc[data.index[short_window:], 'Signal'] = signal_values
data['Position'] = data['Signal'].shift(1)
return data
def backtest(data, initial_capital):
data['Daily Return'] = data['close'].pct_change()
data['Strategy Return'] = data['Position'] * data['Daily Return']
data['Cumulative Market Return'] = (1 + data['Daily Return']).cumprod()
data['Cumulative Strategy Return'] = (1 + data['Strategy Return']).cumprod()
data['Portfolio Value'] = initial_capital * data['Cumulative Strategy Return']
return data
def visualize_backtest(data, symbol):
plt.figure(figsize=(12, 7))
plt.plot(data['date'], data['Cumulative Market Return'], label='Market Return (Buy & Hold)', color='blue')
plt.plot(data['date'], data['Cumulative Strategy Return'], label='Momentum Strategy Return', color='green')
plt.title(f'{symbol} Backtest: Momentum Strategy vs Buy & Hold', fontsize=16, fontweight='bold')
plt.xlabel('Date', fontsize=12)
plt.ylabel('Cumulative Return', fontsize=12)
plt.xticks(rotation=45)
plt.legend()
plt.show()
for symbol in symbols:
stock_data = combined_data[combined_data['Symbol'] == symbol].copy()
stock_data = momentum_strategy(stock_data, short_window, long_window)
stock_data = backtest(stock_data, initial_capital)
visualize_backtest(stock_data, symbol)
final_portfolio_value = stock_data['Portfolio Value'].iloc[-1]
print(f"Final portfolio value for {symbol}: ${final_portfolio_value:.2f}")
total_market_return = stock_data['Cumulative Market Return'].iloc[-1] - 1
total_strategy_return = stock_data['Cumulative Strategy Return'].iloc[-1] - 1
print(f"Total market return for {symbol}: {total_market_return * 100:.2f}%")
print(f"Total strategy return for {symbol}: {total_strategy_return * 100:.2f}%")
print("="*40)