Fixing a Pair Trading KeyError by Passing the Full Ticker List
Summary
The document describes a Python error in code that retrieves two stock price series, calculates their returns, and uses the difference between the returns to form a pair-trading signal. The reported missing key is the concatenated pair name, even though that pair appears in the input CSV. The accompanying diagnostic shows that the generated keys instead use the first two characters of the first ticker.
The accepted explanation identifies the cause as passing one ticker pair into a function designed to receive a list of pairs. Since the function iterates over its input, giving it a single pair causes it to treat the ticker string as an iterable and build keys from individual characters. Passing the complete list lets the function iterate over each pair and construct the intended keys. This resolves the specific lookup mismatch described, but the document does not validate the return calculation or the broader signal logic, which contain other apparent implementation issues.
Key ideas
- The missing dictionary key results from how the input is passed to the data retrieval function.
- The returns function expects a collection of ticker pairs and iterates over that collection.
- Passing one pair directly can make the code iterate over ticker characters instead.
- Passing the complete pair list allows keys to be formed from both ticker symbols.
- Fixing the key lookup does not establish that the remaining signal calculation is correct.
Tags
Full text
# KeyError in Python code used to determine a trade signal for Pair Trading
# KeyError in Python code used to determine a trade signal for Pair Trading
I'm basically running some code as follows. Basically I'm just retrieving pairs of stocks (laid out as Row 1-Stock 1,2, Row 2-Stock 1,2 and so on, where Stock 1 and 2 are different in each row) from a CSV File. I then take in data from Yahoo associated with these "Pairs" of Stocks. I calculate the returns of the stocks and basically check if the distance (difference in returns) between a pair of stocks breaches some threshold and if so I return 1. However, I am running into the error below and Im unable to figure out why, as I know that the key ADP_PAYX which is associated with the first "stock pair" in the CSV File does infact exist.
```
Distancefunc(self, tickers, begdate, enddate)
111 data = Returns(ticker,begdate,enddate)
112 key = ticker[0]+'_'+ticker[1]
--> 113 R1 = data[key]['Returns'][0]
114 R2 = data[key]['Returns'][1]
115 distance = sum[(R1-R2)^2]
KeyError: 'ADP_PAYX'
from datetime import datetime
import pytz
#import zipline as zp
import csv
import pandas as pd
import pandas.io.data as web
import numpy as np
from matplotlib.pyplot import *
from matplotlib.finance import quotes_historical_yahoo
def Dataretriever():
Pairs = []
f1=open('C:\Users\Pairs_0420.csv') #Enter the location of the file
csvdata= csv.reader(f1)
for row in csvdata: #reading tickers from the csv file
Pairs.append(row)
return Pairs
tickers = Dataretriever()
tickersasstrings = map(str, tickers)
def PricePort(tickers,begdate,enddate):
"""
Returns historical adjusted prices of a portfolio of stocks.
tickers=pairsd """
final=pd.read_csv('http://chart.yahoo.com/table.csv?s=^GSPC',usecols=[0,6],index_col=0)
final.columns=['^GSPC']
data = {}
for ticker in tickers:
#print ticker
key = ticker[0]+'_'+ticker[1]
data1 = quotes_historical_yahoo(ticker[0], begdate, enddate,asobject=True, adjusted=True)
data2 = quotes_historical_yahoo(ticker[1], begdate, enddate,asobject=True, adjusted=True)
#url1 = 'http://chart.yahoo.com/table.csv?s=ttt'.replace('ttt',ticker[0])
data[key] = {'Data': (data1,data2)}
return data
def Returns(tickers,begdate,enddate):
begdate=(2014,1,1)
enddate=(2014,6,1)
p = PricePort(tickers,begdate,enddate)
for ticker in tickers:
key = ticker[0]+'_'+ticker[1]
data1 = p[key]['Data'][0]
data2 = p[key]['Data'][1]
ret1 = (data1.close[1:] - data1.close[:-1])/data1.close[1:]
ret2 = (data2.close[1:] - data2.close[:-1])/data2.close[1:]
p[key]['Returns'] = (ret1,ret2)
return p
class ThresholdClass():
#constructor
def __init__(self, Pairs,begdatae,enddate):
self.Pairs = Pairs
self.begdate = begdate
self.enddate = enddate
def Distancefunc(self, tickers, begdate, enddate):
for ticker in tickers:
data = Returns(ticker,begdate,enddate)
key = ticker[0]+'_'+ticker[1]
R1 = data[key]['Returns'][0]
R2 = data[key]['Returns'][1]
distance = sum[(R1-R2)^2]
return distance
def MeanofPairs(self, tickers, begdate, enddate):
sum = self.Distancefunc(tickers, begdate, enddate)
mean = np.mean(sum)
return mean
def StandardDeviation(self, tickers, begdate, enddate):
sum = self.Distancefunc(tickers, begdate, enddate)
standard_dev = np.std(sum)
return standard_dev
def ThresholdandnewsChecker(self, tickers, begdate, enddate):
threshold = self.MeanofPairs(tickers, begdate, enddate) + 2*self.StandardDeviation(tickers, begdate, enddate)
if (self.Distancefunc(tickers, begdate, enddate) > threshold):
news = self.newsfunc(binaryfromnews)
return 1
begdate=(2013,1,1)
enddate=(2013,12,31)
Threshold_Class = ThresholdClass(tickers[:1],begdate,enddate)
Threshold_Class.ThresholdandnewsChecker(tickers[:1], begdate, enddate)
```
Edit: Adding a print p before `data1 = p[key]['Data'][0]` showed that the keys are `A_D` and `P_A` instead of the required 'ADP_PAYX'. So, this is what I am looking to resolve at this point. Thanks.
## Answer by Olaf (score 1, accepted)
https://quant.stackexchange.com/a/17486
In the method `Distancefunc` change this:
```
for ticker in tickers:
data = Returns(ticker,begdate,enddate)
...
```
to this:
```
data = Returns(tickers,begdate,enddate)
for ticker in tickers:
...
```
Note the change from `ticker` to `tickers` in the argument of `Returns`. The reason is that `Returns` is designed to loop over all tickers, but currently you are passing it a string instead of a list of tickers. That's why the key is set to `A_D` and the data dictionary: it's the first and second letter of the tickername ADP_PAYX.Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.