Skip to content

Commit

Permalink
Merge pull request #1587 from quantopian/fix-bug-for-continuous-futur…
Browse files Browse the repository at this point in the history
…e-max-date

BUG: Fix continuous future end dates.
  • Loading branch information
ehebert authored Nov 9, 2016
2 parents fa6e4fe + e415c0f commit b309e3c
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 13 deletions.
56 changes: 45 additions & 11 deletions tests/test_continuous_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,42 +64,54 @@ def make_root_symbols_info(self):
@classmethod
def make_futures_info(self):
return DataFrame({
'symbol': ['FOF16', 'FOG16', 'FOH16', 'FOJ16', 'FOK16', 'FOF22'],
'root_symbol': ['FO'] * 6,
'asset_name': ['Foo'] * 6,
'symbol': ['FOF16', 'FOG16', 'FOH16', 'FOJ16', 'FOK16', 'FOF22',
'FOG22'],
'root_symbol': ['FO'] * 7,
'asset_name': ['Foo'] * 7,
'start_date': [Timestamp('2015-01-05', tz='UTC'),
Timestamp('2015-02-05', tz='UTC'),
Timestamp('2015-03-05', tz='UTC'),
Timestamp('2015-04-05', tz='UTC'),
Timestamp('2015-05-05', tz='UTC'),
Timestamp('2021-01-05', tz='UTC')],
Timestamp('2021-01-05', tz='UTC'),
Timestamp('2015-01-05', tz='UTC')],
'end_date': [Timestamp('2016-08-19', tz='UTC'),
Timestamp('2016-09-19', tz='UTC'),
Timestamp('2016-10-19', tz='UTC'),
Timestamp('2016-11-19', tz='UTC'),
Timestamp('2016-12-19', tz='UTC'),
Timestamp('2022-08-19', tz='UTC')],
Timestamp('2022-08-19', tz='UTC'),
# Set the last contract's end date (which is the last
# date for which there is data to a value that is
# within the range of the dates being tested. This
# models real life scenarios where the end date of the
# furthest out contract is not necessarily the
# greatest end date all contracts in the chain.
Timestamp('2015-02-05', tz='UTC')],
'notice_date': [Timestamp('2016-01-27', tz='UTC'),
Timestamp('2016-02-26', tz='UTC'),
Timestamp('2016-03-24', tz='UTC'),
Timestamp('2016-04-26', tz='UTC'),
Timestamp('2016-05-26', tz='UTC'),
Timestamp('2022-01-26', tz='UTC')],
Timestamp('2022-01-26', tz='UTC'),
Timestamp('2022-02-26', tz='UTC')],
'expiration_date': [Timestamp('2016-01-27', tz='UTC'),
Timestamp('2016-02-26', tz='UTC'),
Timestamp('2016-03-24', tz='UTC'),
Timestamp('2016-04-26', tz='UTC'),
Timestamp('2016-05-26', tz='UTC'),
Timestamp('2022-01-26', tz='UTC')],
Timestamp('2022-01-26', tz='UTC'),
Timestamp('2022-02-26', tz='UTC')],
'auto_close_date': [Timestamp('2016-01-27', tz='UTC'),
Timestamp('2016-02-26', tz='UTC'),
Timestamp('2016-03-24', tz='UTC'),
Timestamp('2016-04-26', tz='UTC'),
Timestamp('2016-05-26', tz='UTC'),
Timestamp('2022-01-26', tz='UTC')],
'tick_size': [0.001] * 6,
'multiplier': [1000.0] * 6,
'exchange': ['CME'] * 6,
Timestamp('2022-01-26', tz='UTC'),
Timestamp('2022-02-26', tz='UTC')],
'tick_size': [0.001] * 7,
'multiplier': [1000.0] * 7,
'exchange': ['CME'] * 7,
})

@classmethod
Expand Down Expand Up @@ -185,6 +197,10 @@ def test_create_continuous_future(self):
self.assertEqual(cf_primary.root_symbol, 'FO')
self.assertEqual(cf_primary.offset, 0)
self.assertEqual(cf_primary.roll_style, 'calendar')
self.assertEqual(cf_primary.start_date,
Timestamp('2015-01-05', tz='UTC'))
self.assertEqual(cf_primary.end_date,
Timestamp('2022-08-19', tz='UTC'))

retrieved_primary = self.asset_finder.retrieve_asset(
cf_primary.sid)
Expand All @@ -197,6 +213,10 @@ def test_create_continuous_future(self):
self.assertEqual(cf_secondary.root_symbol, 'FO')
self.assertEqual(cf_secondary.offset, 1)
self.assertEqual(cf_secondary.roll_style, 'calendar')
self.assertEqual(cf_primary.start_date,
Timestamp('2015-01-05', tz='UTC'))
self.assertEqual(cf_primary.end_date,
Timestamp('2022-08-19', tz='UTC'))

retrieved = self.asset_finder.retrieve_asset(
cf_secondary.sid)
Expand Down Expand Up @@ -270,6 +290,20 @@ def test_get_value_close_daily(self):
'Auto close at beginning of session so FOG16 is now '
'the current contract.')

# Check a value which occurs after the end date of the last known
# contract, to prevent a regression where the end date of the last
# contract was used instead of the max date of all contracts.
value = self.data_portal.get_spot_value(
cf_primary,
'close',
pd.Timestamp('2016-03-26', tz='UTC'),
'daily',
)

self.assertEqual(value, 135441.44,
'Value should be for FOJ16, even though last '
'contract ends before query date.')

def test_current_contract_volume_roll(self):
cf_primary = self.asset_finder.create_continuous_future(
'FO', 0, 'volume')
Expand Down
5 changes: 3 additions & 2 deletions zipline/assets/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -922,8 +922,9 @@ def get_ordered_contracts(self, root_symbol):

def create_continuous_future(self, root_symbol, offset, roll_style):
oc = self.get_ordered_contracts(root_symbol)
start_date = self.retrieve_asset(oc.contract_sids[0]).start_date
end_date = self.retrieve_asset(oc.contract_sids[-1]).end_date
contracts = self.retrieve_all(oc.contract_sids)
start_date = min(c.start_date for c in contracts)
end_date = max(c.end_date for c in contracts)
exchange = self._get_root_symbol_exchange(root_symbol)

sid = _encode_continuous_future_sid(root_symbol, offset,
Expand Down

0 comments on commit b309e3c

Please sign in to comment.