Please update data as well as code for this Lab to allow us to be unblocked . Some code is out of date example pd.merge doesn't work .
ValueError: You are trying to merge on datetime64[ns] and object columns for key 'Date'. If you wish to proceed you should use pd.concat
Hi Pierre,
The notebook is running without any errors on our end. Are you running this on your local system with a different dataset? If yes, you need to ensure that the index of both the dataframes you are merging should be in the same format (datetime index in this case).
Hello Akshay,
I was able to change the data to the same format and clear some of the issue. I still have one more
KeyError: "['eom_signal'] not in index"
==
tlt_weight = 0.5111
tlt_prices['tlt_signal'] = tlt_prices[['eom_signal','auction_signal']].max(axis=1)
# Set date as index
tlt_prices.set_index('Date',inplace=True)
# Get daily returns
tlt_daily_changes = tlt_prices['Adjusted Close'].pct_change()
==
KeyError Traceback (most recent call last)
Cell In[23], line 2
1 tlt_weight = 0.5111
----> 2 tlt_prices['tlt_signal'] = tlt_prices[['eom_signal','auction_signal']].max(axis=1)
3 # Set date as index
4 tlt_prices.set_index('Date',inplace=True)
File D:\Anaconda\envs\quantra_py\lib\site-packages\pandas\core\frame.py:3511, in DataFrame.__getitem__(self, key)
3509 if is_iterator(key):
3510 key = list(key)
-> 3511 indexer = self.columns._get_indexer_strict(key, "columns")[1]
3513 # take() does not accept boolean indexers
3514 if getattr(indexer, "dtype", None) == bool:
File D:\Anaconda\envs\quantra_py\lib\site-packages\pandas\core\indexes\base.py:5796, in Index._get_indexer_strict(self, key, axis_name)
5793 else:
5794 keyarr, indexer, new_indexer = self._reindex_non_unique(keyarr)
-> 5796 self._raise_if_missing(keyarr, indexer, axis_name)
5798 keyarr = self.take(indexer)
5799 if isinstance(key, Index):
5800 # GH 42790 - Preserve name from an Index
File D:\Anaconda\envs\quantra_py\lib\site-packages\pandas\core\indexes\base.py:5859, in Index._raise_if_missing(self, key, indexer, axis_name)
5856 raise KeyError(f"None of [{key}] are in the [{axis_name}]")
5858 not_found = list(ensure_index(key)[missing_mask.nonzero()[0]].unique())
-> 5859 raise KeyError(f"{not_found} not in index")
KeyError: "['eom_signal'] not in index"
Hi Pierre,
It looks like the 'eom_signal' column is not present in the tlt_prices dataframe. Can you please check the same once? If it is not present, you can create the same using the below code:
condition_1 = tlt_prices.Date.dt.month != tlt_prices.Date.dt.month.shift(-1)
condition_2 = tlt_prices.Date.dt.month != tlt_prices.Date.dt.month.shift(-2)
tlt_prices['eom_signal'] = np.where(
(condition_1) | (condition_2), 1, 0
)
The above code is the same as the one in the "End of the month signal" part of the notebook. If the error still persists it would be great if you could please share the notebook that you are running on your local system along with the data files, to help us debug the issue.
Hope this helps!
#!/usr/bin/env python
# coding: utf-8
# # Composite seasonal strategy - Volatility Weighted
# ## Strategy overview
#
# In previous sections, we have covered fixed income, equity and volatility markets and suggested eight basic trading strategies. Each of those strategies is profitable, but their performance is not spectacular. Suggested strategies are not very risky, because they are usually in the market for a short part of the year. But their performance is low also for the same reason.
# Our goal in the previous sections was not to maximize the performance or return-risk ratio. But we can work on that in this section. The easiest way to do so is to combine all strategies.
# # Notebook navigation
# 1. Price data import
# 2. Calendar data import
# 3. Trading signals generation
# - 3.1. Equity strategies signals
# - 3.2. Fixed income strategies signals
# - 3.3. Volatility strategies signals
# 4. Composite strategy performance
# 5. Maximum Drawdown plotting
# ## 1. Price data import
# We have already covered every technique used in this notebook in previous sections, so let's get through this swiftly.
#
# First thing we need to do is to import price data points using pandas read_csv along with parsing lambda function. Do it for all assets used in composite strategy (SPY, TLT, VIXY).
# In[1]:
import numpy as np
import yfinance as yf
get_ipython().run_line_magic('matplotlib', 'inline')
import pandas as pd
from datetime import datetime
# In[2]:
get_ipython().system('pip install --upgrade pandas==1.4.4')
# In[3]:
# Set the start and end date
start = '1997-01-01'
end = '2023-11-07'
# Set the ticker
symbol = 'SPY'
# Get the data from Yahoo! Finance
df = yf.download(symbol, start, end)
# Disply the data
df.tail()
df.to_csv('../data_modules/spy_daily_1997_2023_1127.csv')
spy_prices =pd.read_csv('../data_modules/spy_daily_1997_2023_1127.csv', parse_dates=['Date'])
spy_prices.tail()
# In[4]:
tlt_prices =pd.read_csv('../data_modules/tlt_daily_1997_2023.csv', parse_dates=['Date'])
tlt_prices.tail()
# In[5]:
vixy_prices =pd.read_csv('../data_modules/vixy_daily_1997_2023_1126.csv', parse_dates=['Date'])
vixy_prices.tail()
# As you can see, VIXY price history has the least amount of data points. Its history starts in January of 2011. Since history length of assets is not the same, let's trim SPY and TLT history to the same length as VIXY history length. Also, it will be the start of backtest. It can be done by tail() function. At the same time we want to reset dataframe's index to 0 by using reset_index() function.
# In[6]:
# Trim SPY and TLT history length to VIXY history lenght.
vixy_len = len(vixy_prices)
spy_prices = spy_prices.tail(vixy_len).reset_index()
tlt_prices = tlt_prices.tail(vixy_len).reset_index()
# Make sure that every asset's history lenght equal.
print(len(spy_prices) == len(tlt_prices) == len(vixy_prices))
# In[7]:
tlt_prices
# ## 2. Calendar data import
# Next, we need to import calendar data points. Do it the same way we used in the previous step. Again, let's import data for every sub-strategy that we will need. Those are - FED days, VIX expiration dates and treasury auction dates.
# In[8]:
path = '../data_modules/'
# In[9]:
fed_parser = lambda x: datetime.strptime(x, "%d-%m-%Y")
# Read csv
fed_days = pd.read_csv(path+'fed_days_1993_2023_1.csv', sep=';', parse_dates=['Date'], date_parser=fed_parser)
# Print the last 5 rows of the dataframe
fed_days.tail(5)
# In[10]:
# Read csv
expiration_dates = pd.read_csv(path+'vix_futures_expiration.csv', sep=';', parse_dates=['Date'])
# Print the last 5 rows of the dataframe
expiration_dates.tail(5)
# In[11]:
# Read csv
auction_dates = pd.read_csv(path+'treasury_auction_dates1.csv', sep=';', parse_dates=['Date'])
# Print the last 5 rows of the dataframe
auction_dates.tail(5)
# ## 3. Trading signals generation
# Now the interesting part begins. We need to generate a trading signal for every sub-strategy and mix seasonal sub-strategies into one by using logical OR function.
#
# Seasonal sub-strategy on equities will consist of four different signals and will use OR function (if at least one signal is active, we perform the action to hold SPY ETF). Seasonal strategies on fixed income and volatility will consist of 2 signals each. In the end, we will have just three seasonal sub-strategies, each for one asset class.
#
# Generation of trading signal for every sub-strategy is described in previous sections, so let's look at them just briefly.
# ## 3.1. Equity strategies signals
# First up, we have 4 sub-strategies on equities - Turn of the Month, PayDay, FED day and Option Expiration Week. That's why we generate 4 signal vectors.
# ### Turn of the month signal
#
# In the code below, we generate the turn of the month signal by simply checking when the month number moves to the next one.
# In[12]:
# Flag all the dates when the month is changing
spy_prices['turn_
Hello Askhay,
Thank you for your support. Please see the code snippet above. I have added the conditions and it clears all the error, however the Strategy Return plot is blank as well as the max drawdown plot. The Max drawdown is nan. I couldn't figure out why.
Hi Pierre,
The code looks incomplete. Can you please upload the code and the data files on Google Drive and share the link (Please make sure to keep the link access public)?