examples/sectorRotationStrategy.ipynb
Sector rotation involves shifting investments across different sectors in the stock market, based on economic cycles or market performance expectations. This strategy seeks to maximize returns by focusing on sectors that are expected to perform better in the current market environment while reducing exposure to underperforming sectors.
Author:
!pip install openbb -q
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from openbb import obb
sector_etfs = ['XLF', 'XLE', 'XLK', 'XLY', 'XLI', 'XLU', 'XLV']
start_date = '2015-01-01'
etf_dataframes = []
for etf in sector_etfs:
try:
data = obb.etf.historical(
symbol=etf,
start_date=start_date,
provider="yfinance"
).to_df()
data['Symbol'] = etf
etf_dataframes.append(data)
except Exception as e:
print(f"Failed to fetch data for {etf}: {str(e)}")
combined_etf_data = pd.concat(etf_dataframes)
combined_etf_data = combined_etf_data.reset_index()
combined_etf_data.head()
combined_etf_data['date'] = pd.to_datetime(combined_etf_data['date'])
combined_etf_data = combined_etf_data[['date', 'close', 'Symbol']]
pivoted_data = combined_etf_data.pivot_table(index='date', columns='Symbol', values='close')
pivoted_data.ffill()
pivoted_data.head()
def sector_rotation_strategy(etf_data, lookback_period=3, top_n=3):
"""
Implements a simple sector rotation strategy that invests in the top 'n' sector ETFs based on
past performance over a lookback period.
Parameters:
etf_data (DataFrame): ETF performance data
lookback_period (int): Number of months to look back for performance evaluation
top_n (int): Number of top sector ETFs to invest in
Returns:
DataFrame: Portfolio returns based on the sector rotation strategy
"""
monthly_returns = etf_data.resample('ME').last().pct_change()
portfolio_returns = pd.DataFrame(index=monthly_returns.index, columns=['Portfolio Return'])
for date in monthly_returns.index[lookback_period:]:
past_returns = monthly_returns.loc[date - pd.DateOffset(months=lookback_period):date].mean()
top_etfs = past_returns.nlargest(top_n).index
next_month_date = date + pd.DateOffset(months=1)
if next_month_date in monthly_returns.index:
next_month_return = monthly_returns.loc[next_month_date, top_etfs].mean()
portfolio_returns.loc[next_month_date, 'Portfolio Return'] = next_month_return
return portfolio_returns
portfolio_returns = sector_rotation_strategy(pivoted_data, lookback_period=3, top_n=3)
portfolio_returns.dropna(inplace=True)
portfolio_returns.head()
portfolio_returns['Cumulative Return'] = (1 + portfolio_returns['Portfolio Return']).cumprod()
pivoted_data['Market Average'] = pivoted_data.mean(axis=1)
market_returns = pivoted_data['Market Average'].resample('ME').last().pct_change()
market_cumulative_return = (1 + market_returns).cumprod()
plt.figure(figsize=(12, 7))
plt.plot(portfolio_returns.index, portfolio_returns['Cumulative Return'], label='Sector Rotation Strategy', color='green')
plt.plot(market_cumulative_return.index, market_cumulative_return, label='Market Average', color='blue')
plt.title('Sector Rotation Strategy vs Market Average', fontsize=16, fontweight='bold')
plt.xlabel('Date', fontsize=12)
plt.ylabel('Cumulative Return', fontsize=12)
plt.legend()
plt.grid(True)
plt.show()
final_strategy_return = portfolio_returns['Cumulative Return'].iloc[-1]
final_market_return = market_cumulative_return.iloc[-1]
print(f"Final cumulative return of sector rotation strategy: {final_strategy_return:.2f}")
print(f"Final cumulative return of market average: {final_market_return:.2f}")
strategy_daily_returns = portfolio_returns['Portfolio Return'].dropna()
sharpe_ratio = (strategy_daily_returns.mean() / strategy_daily_returns.std()) * np.sqrt(12)
print(f"Sharpe Ratio of the sector rotation strategy: {sharpe_ratio:.2f}")