diff --git a/tests/test_assets.py b/tests/test_assets.py index 10ed9f2d..9b50df1b 100644 --- a/tests/test_assets.py +++ b/tests/test_assets.py @@ -33,7 +33,11 @@ from nose_parameterized import parameterized from numpy import full from zipline.assets import Asset, Equity, Future, AssetFinder -from zipline.assets.futures import FutureChain +from zipline.assets.futures import ( + cme_code_to_month, + FutureChain, + month_to_cme_code, +) from zipline.errors import ( SymbolNotFound, MultipleSymbolsFound, @@ -1006,3 +1010,39 @@ class TestFutureChain(TestCase): # ValueError. with self.assertRaises(ValueError): cl.offset("blah") + + def test_cme_code_to_month(self): + codes = { + 'F': 1, # January + 'G': 2, # February + 'H': 3, # March + 'J': 4, # April + 'K': 5, # May + 'M': 6, # June + 'N': 7, # July + 'Q': 8, # August + 'U': 9, # September + 'V': 10, # October + 'X': 11, # November + 'Z': 12 # December + } + for key in codes: + self.assertEqual(codes[key], cme_code_to_month(key)) + + def test_month_to_cme_code(self): + codes = { + 1: 'F', # January + 2: 'G', # February + 3: 'H', # March + 4: 'J', # April + 5: 'K', # May + 6: 'M', # June + 7: 'N', # July + 8: 'Q', # August + 9: 'U', # September + 10: 'V', # October + 11: 'X', # November + 12: 'Z', # December + } + for key in codes: + self.assertEqual(codes[key], month_to_cme_code(key)) diff --git a/zipline/assets/futures.py b/zipline/assets/futures.py index 7d61dfda..9e71bd6a 100644 --- a/zipline/assets/futures.py +++ b/zipline/assets/futures.py @@ -180,3 +180,84 @@ class FutureChain(object): """ return self.as_of(self.as_of_date + Timedelta(time_delta)) + + +# http://www.cmegroup.com/product-codes-listing/month-codes.html +CME_CODE_TO_MONTH = dict(zip('FGHJKMNQUVXZ', range(1, 13))) +MONTH_TO_CME_CODE = dict(zip(range(1, 13), 'FGHJKMNQUVXZ')) + + +def cme_code_to_month(code): + """ + Convert a CME month code to a month index. + + The month codes are as follows: + + 'F' -> 1 (January) + 'G' -> 2 (February) + 'H' -> 3 (March) + 'J' -> 4 (April) + 'K' -> 5 (May) + 'M' -> 6 (June) + 'N' -> 7 (July) + 'Q' -> 8 (August) + 'U' -> 9 (September) + 'V' -> 10 (October) + 'X' -> 11 (November) + 'Z' -> 12 (December) + + Parameters + ---------- + code : str + The month code to look up. + + Returns + ------- + month : int + The month number (starting at 1 for January) corresponding to the + requested code. + + See Also + -------- + month_to_cme_code + Inverse of this function. + """ + return CME_CODE_TO_MONTH[code] + + +def month_to_cme_code(month): + """ + Convert a month to a CME code. + + The month codes are as follows: + + 1 (January) -> 'F' + 2 (February) -> 'G' + 3 (March) -> 'H' + 4 (April) -> 'J' + 5 (May) -> 'K' + 6 (June) -> 'M' + 7 (July) -> 'N' + 8 (August) -> 'Q' + 9 (September) -> 'U' + 10 (October) -> 'V' + 11 (November) -> 'X' + 12 (December) -> 'Z' + + Parameters + ---------- + month : int + The month number (starting at 1 for January) corresponding to the + requested code. + + Returns + ------- + code : str + The month code to look up. + + See Also + -------- + cme_code_to_month + Inverse of this function. + """ + return MONTH_TO_CME_CODE[month]