From e1bafe1ecca8baeb41b41c721325f2e270431578 Mon Sep 17 00:00:00 2001 From: Eddie Hebert Date: Wed, 26 Oct 2016 17:08:59 -0400 Subject: [PATCH] BUG: Use proxy for settlement on future adjustments. Instead of using the difference between the session close of the front contract before the roll and and the open of back contract on the beginning of the roll, use the close of both at the end of the session before the roll. The closes of the session prior to roll is in lieu of settlement data. --- tests/test_continuous_futures.py | 55 +++++++++++++++-------------- zipline/data/history_loader.py | 59 +++++++++++++++----------------- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/tests/test_continuous_futures.py b/tests/test_continuous_futures.py index cc3bd451..282ac624 100644 --- a/tests/test_continuous_futures.py +++ b/tests/test_continuous_futures.py @@ -617,18 +617,18 @@ def record_current_contract(algo, data): Timestamp('2016-03-06', tz='UTC'), 30, '1d', 'close') # Unadjusted value is: 115011.44 - # Adjustment is based on hop from 115231.44 to 122240.001 - # a ratio of ~1.06 + # Adjustment is based on hop from 115231.44 to 125231.44 + # a ratio of ~0.920 assert_almost_equal( window.loc['2016-01-26', cf_mul], - 118833.237, + 124992.348, err_msg="At beginning of window, should be FOG16's first value, " "adjusted.") # Difference of 7008.561 assert_almost_equal( window.loc['2016-01-26', cf_add], - 119028.562, + 125011.44, err_msg="At beginning of window, should be FOG16's first value, " "adjusted.") @@ -661,50 +661,52 @@ def record_current_contract(algo, data): # Unadjusted value: 115221.44 # Adjustments based on hops: - # 2016-02-25 00:00:00+00:00 115231.440 - # 2016-02-26 00:00:00+00:00 122240.001 - # ratio: ~1.061 - # difference: 7008.561 + # 2016-02-25 00:00:00+00:00 + # front 115231.440 + # back 125231.440 + # ratio: ~0.920 + # difference: 10000.0 # and - # 2016-03-23 00:00:00+00:00 125421.440 - # 2016-03-24 00:00:00+00:00 132430.001 - # ratio: ~1.056 - # difference: 7008.56 + # 2016-03-23 00:00:00+00:00 + # front 125421.440 + # back 135421.440 + # ratio: ~1.080 + # difference: 10000.00 assert_almost_equal( window.loc['2016-02-24', cf_mul], - 129090.459, + 135236.905, err_msg="At beginning of window, should be FOG16's 22nd value, " "with two adjustments.") assert_almost_equal( window.loc['2016-02-24', cf_add], - 129268.561, + 135251.44, err_msg="At beginning of window, should be FOG16's 22nd value, " "with two adjustments") # Unadjusted: 125241.44 assert_almost_equal( window.loc['2016-02-26', cf_mul], - 132271.58, + 135259.442, err_msg="On session with roll, should be FOH16's 24th value, " "with one adjustment.") assert_almost_equal( window.loc['2016-02-26', cf_add], - 132280.0, + 135271.44, err_msg="On session with roll, should be FOH16's 24th value, " "with one adjustment.") # Unadjusted: 125251.44 assert_almost_equal( window.loc['2016-02-29', cf_mul], - 132282.141, + 135270.241, err_msg="On session after roll, should be FOH16's 25th value, " "with one adjustment.") assert_almost_equal( window.loc['2016-02-29', cf_add], - 132290.00, + 135281.44, err_msg="On session after roll, should be FOH16's 25th value, " "unadjusted.") @@ -780,29 +782,30 @@ def record_current_contract(algo, data): # Unadjusted: 115231.412 # Adjustment based on roll: - # 2016-02-25 23:00:00+00:00 115231.440 - # 2016-02-25 23:01:00+00:00 122240.001 - # Ratio: ~1.061 - # Difference: 7008.561 + # 2016-02-25 23:00:00+00:00 + # front: 115231.440 + # back: 125231.440 + # Ratio: ~0.920 + # Difference: 10000.00 self.assertEqual(window.loc['2016-02-25 22:32', cf_mul], - 122239.971, + 125231.41, "Should be FOG16 at beginning of window. A minute " "which is in the 02-25 session, before the roll.") self.assertEqual(window.loc['2016-02-25 22:32', cf_add], - 122239.973, + 125231.412, "Should be FOG16 at beginning of window. A minute " "which is in the 02-25 session, before the roll.") # Unadjusted: 115231.44 # Should use same ratios as above. self.assertEqual(window.loc['2016-02-25 23:00', cf_mul], - 122240.001, + 125231.44, "Should be FOG16 on on minute before roll minute, " "adjusted.") self.assertEqual(window.loc['2016-02-25 23:00', cf_add], - 122240.001, + 125231.44, "Should be FOG16 on on minute before roll minute, " "adjusted.") diff --git a/zipline/data/history_loader.py b/zipline/data/history_loader.py index 4a7ab1e8..fb4b062f 100644 --- a/zipline/data/history_loader.py +++ b/zipline/data/history_loader.py @@ -184,15 +184,15 @@ class ContinuousFutureAdjustmentReader(object): def _make_adjustment(self, adjustment_type, - left_close, - right_open, + front_close, + back_close, end_loc): - adj_base = left_close - right_open + adj_base = back_close - front_close if adjustment_type == 'mul': - adj_value = 1.0 - adj_base / left_close + adj_value = 1.0 + adj_base / front_close adj_class = Float64Multiply elif adjustment_type == 'add': - adj_value = -adj_base + adj_value = adj_base adj_class = Float64Add return adj_class(0, end_loc, @@ -215,37 +215,34 @@ class ContinuousFutureAdjustmentReader(object): adjs = {} - for left, right in sliding_window(2, rolls): - left_sid, right_dt = left - right_sid = right[0] - left_dt = tc.previous_session_label(right_dt) + for front, back in sliding_window(2, rolls): + front_sid, roll_dt = front + back_sid = back[0] + dt = tc.previous_session_label(roll_dt) if self._frequency == 'minute': - _, left_dt = tc.open_and_close_for_session(left_dt) - right_dt, _ = tc.open_and_close_for_session(right_dt) - partitions.append((left_sid, - right_sid, - left_dt, - right_dt)) - + dt = tc.open_and_close_for_session(dt)[1] + roll_dt = tc.open_and_close_for_session(roll_dt)[0] + partitions.append((front_sid, + back_sid, + dt, + roll_dt)) for partition in partitions: - left_sid, right_sid, left_dt, right_dt = partition - last_left_dt = self._bar_reader.get_last_traded_dt( - self._asset_finder.retrieve_asset(left_sid), - left_dt) - last_right_dt = self._bar_reader.get_last_traded_dt( - self._asset_finder.retrieve_asset(right_sid), - right_dt) - if isnull(last_left_dt) or isnull(last_right_dt): + front_sid, back_sid, dt, roll_dt = partition + last_front_dt = self._bar_reader.get_last_traded_dt( + self._asset_finder.retrieve_asset(front_sid), dt) + last_back_dt = self._bar_reader.get_last_traded_dt( + self._asset_finder.retrieve_asset(back_sid), dt) + if isnull(last_front_dt) or isnull(last_back_dt): continue - left_close = self._bar_reader.get_value( - left_sid, last_left_dt, 'close') - right_open = self._bar_reader.get_value( - right_sid, last_right_dt, 'open') - adj_loc = dts.searchsorted(right_dt) + front_close = self._bar_reader.get_value( + front_sid, last_front_dt, 'close') + back_close = self._bar_reader.get_value( + back_sid, last_back_dt, 'close') + adj_loc = dts.searchsorted(roll_dt) end_loc = adj_loc - 1 adj = self._make_adjustment(cf.adjustment, - left_close, - right_open, + front_close, + back_close, end_loc) try: adjs[adj_loc].append(adj)