In finance, futures contracts are usually represented by their expiry year and month. So for example, 201212
would be 2012 - December.
Some contracts, for example Corn, are only traded some months [3,5,7,9,12]
, whereas sometimes, you might only want to trade the [12]
contract (despite it trading other months too, so you'd trade 201212
, 201312
etc).
I'm currently using the the int
format to represent these contracts in my system, and using that as a Pandas index.
The tricky thing is, given a contract, I often need to get the next contract (and to a lesser extent, the previous one).
I've written a generator expression that does something like this:
def contract_generator(self, recent=True, year=None, month=None, traded_only=False):
if year is None:
year = datetime.datetime.now().year - 1 if recent == True else self.first_contract
if traded_only is True:
months = self.trade_only
else:
months = self.months_traded
months = deque(months)
if month is not None:
months.rotate(months.index(month)-1)
while True:
for month in months:
yield {
'year': year,
'month': month,
'contract': str(year)+str("%02d" % (month,)),
'formatted_contract': self.contract_format(year, month),
'expiration_date': self.expiration_date(year, month)
}
year+=1
def next_contract(self, contract):
c = contract_to_tuple(contract)
j = self.contract_generator(year = c[0], month = c[1], traded_only=False)
return next(j)['contract']
def contract_to_tuple(contract):
contract = str(contract)
return (int(contract[0:4]),int(contract[4:6]))
(where months_traded
& trade_only
are the lists to which I referred to in paragraph 2).
Crucially, its buggy and the above doesn't work quite right. I can fix it, but to be honest, I really dislike this approach. There must be a better way.
Ideas:
201212 + 1
to get the next contract (but would this really be easy with pandas?)Is there an easy/elegant way to do this that already exists? Or do I really need to make it from scratch?
Edit:
My final result:
def nc(self, contract, months=None):
d = pd.to_datetime(str(contract), format='%Y%m')
months_traded = deque(self.months_traded)
months_traded.rotate(-1)
output_month = months_traded[self.months_traded.index(d.month)]
output_year = d.year + 1 * d.month==12
return str(output_year)+str("%02d" % (output_month,))
This should do it:
def next_contract(contract, last=False):
d = pd.to_datetime(str(contract), format='%Y%m')
d += pd.offsets.MonthBegin(12 * (last * -2 + 1))
return int(d.strftime('%Y%m'))
next_contract(201212)
201312
next_contract(201212, last=True)
201112
def next_contract(contract, last=False):
# convert contract to datetime with assumed format of yyyymm
d = pd.to_datetime(str(contract), format='%Y%m')
# use pandas offsets. I don't care that it's month begin
# because I'm ditching the day anyway.
# (last * -2 + 1) equals -1 when last is True and 1 when last is False
d += pd.offsets.MonthBegin(12 * (last * -2 + 1))
return int(d.strftime('%Y%m'))
For what it's worth, here is a stub of a class. Honestly, coding up all the handling for the other months should be left as an exercise for you.
class Corn(object):
def __init__(self, contract):
self.contract = contract
def __add__(self, i):
d = pd.to_datetime(str(self.contract), format='%Y%m')
d += pd.offsets.MonthBegin(12 * i)
self.contract = int(d.strftime('%Y%m'))
return self
def __sub__(self, i):
return self.__add__(-i)
def get_next(self):
return self + 1
def get_last(self):
return self - 1
def __repr__(self):
return str(self.contract)
corn = Corn(201212)
print(corn + 1)
print(corn.get_next())
201312
201412
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With