completely noob here, hope this question isn’t too silly. I’m trying to backtest some investment strategies in python through QuantStats, the problem is that my analysis, independently from the year I choose, starts from 4th February despite setting the sgtart date at 1/1/year. How can I fix this?
Below you can find my code
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
import yfinance as yf
import quantstats as qs
qs.extend_pandas()
import matplotlib.pyplot as plt
equity_etfs = ['VTI','IEF']
stock_frames = []
stock_daily_frames = []
for tick in equity_etfs:
data = yf.download(tick, start="2013-01-01", end="2023-12-31", group_by='ticker', interval='1d')
data = data[['Adj Close']]
data = data.rename(columns={'Adj Close': tick})
stock_daily_frames.append(data)
equity_daily_returns = pd.concat(stock_daily_frames, axis=1)
equity_daily_returns = equity_daily_returns.pct_change().dropna()
equity_daily_returns = equity_daily_returns.dropna()
def calculate_60_40_strategy(daily_returns, name='60/40 Strategy'):
daily_returns.index = pd.to_datetime(daily_returns.index)
daily_returns[name] = np.nan
weights = {'VTI': 0.6, 'IEF': 0.4}
for month_end in daily_returns.resample('M').last().index:
start_of_next_month = month_end + pd.DateOffset(days=1)
end_of_next_month = start_of_next_month + pd.DateOffset(months=1) - pd.DateOffset(days=1)
mask = (daily_returns.index >= start_of_next_month) & (daily_returns.index <= end_of_next_month)
daily_returns.loc[mask, name] = daily_returns.loc[mask, ['VTI', 'IEF']].dot(pd.Series(weights))
daily_returns[name].fillna(method='ffill', inplace=True)
return daily_returns
def calculate_60_40_strategy(daily_returns, fees=0, name='60/40 Strategy'):
daily_returns.index = pd.to_datetime(daily_returns.index)
daily_returns[name] = np.nan
weights = {'VTI': 0.6, 'IEF': 0.4}
first_month = True
for month_end in daily_returns.resample('M').last().index:
start_of_next_month = month_end + pd.DateOffset(days=1)
end_of_next_month = start_of_next_month + pd.DateOffset(months=1) - pd.DateOffset(days=1)
mask = (daily_returns.index >= start_of_next_month) & (daily_returns.index <= end_of_next_month)
if not first_month:
daily_returns.loc[mask, name] = (daily_returns.loc[mask, ['VTI', 'IEF']].dot(pd.Series(weights))) * (1 - fees)
else:
daily_returns.loc[mask, name] = daily_returns.loc[mask, ['VTI', 'IEF']].dot(pd.Series(weights))
first_month = False
daily_returns[name].fillna(method='ffill', inplace=True)
return daily_returns
fee_levels = [0, 0.01, 0.03, 0.05]
for fee in fee_levels:
strategy_name = f"60/40 fees={fee}"
calculate_60_40_strategy(equity_daily_returns, fees=fee, name=strategy_name)
cumulative_returns = (1 + equity_daily_returns.filter(like="60/40")).cumprod()
plt.figure(figsize=(12, 6))
for column in cumulative_returns.columns:
plt.plot(cumulative_returns.index, cumulative_returns[column], label=column)
plt.title("Cumulative Returns of 60/40 Strategy with Different Fees")
plt.xlabel("Date")
plt.ylabel("Cumulative Returns")
plt.legend()
plt.show()
qs.reports.html(equity_daily_returns['60/40 fees=0'], equity_daily_returns['VTI'], output="60_40_2013_2023 Strategy.html")
New contributor
Matteo Fratini is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.