mirror of
https://github.com/wassname/catalyst.git
synced 2026-06-29 22:32:30 +08:00
Merge pull request #1600 from quantopian/use-prev-session-for-volume-roll
BUG: Fix bounds errors in roll finder.
This commit is contained in:
@@ -176,18 +176,20 @@ class ContinuousFuturesTestCase(WithCreateBarData,
|
||||
vol_stop_session = sid_to_vol_stop_session[i]
|
||||
m_open = tc.open_and_close_for_session(vol_stop_session)[0]
|
||||
loc = dts.searchsorted(m_open)
|
||||
# Add a little bit of noise to roll. So that checks for exacly
|
||||
# 0 do not work, since there may be stragglers after a roll.
|
||||
# Add a little bit of noise to roll. So that predicates that
|
||||
# check for exactly 0 do not work, since there may be
|
||||
# stragglers after a roll.
|
||||
df.volume.values[loc] = 1000
|
||||
df.volume.values[loc + 1:] = 0
|
||||
j = i - 1
|
||||
if j in sid_to_vol_stop_session:
|
||||
non_primary_end = sid_to_vol_stop_session[j] - sessions.freq
|
||||
non_primary_end = sid_to_vol_stop_session[j]
|
||||
m_close = tc.open_and_close_for_session(non_primary_end)[1]
|
||||
loc = dts.searchsorted(m_close)
|
||||
# Add some volume before a roll, since a contracted may be
|
||||
# entered earlier than when it is the primary.
|
||||
df.volume.values[:loc] = 2000
|
||||
if m_close > dts[0]:
|
||||
loc = dts.get_loc(m_close)
|
||||
# Add some volume before a roll, since a contract may be
|
||||
# entered earlier than when it is the primary.
|
||||
df.volume.values[:loc + 1] = 10
|
||||
yield i, df
|
||||
|
||||
def test_create_continuous_future(self):
|
||||
@@ -311,14 +313,14 @@ class ContinuousFuturesTestCase(WithCreateBarData,
|
||||
lambda: pd.Timestamp('2016-01-26', tz='UTC'))
|
||||
contract = bar_data.current(cf_primary, 'contract')
|
||||
|
||||
self.assertEqual(contract.symbol, 'FOG16')
|
||||
self.assertEqual(contract.symbol, 'FOF16')
|
||||
|
||||
bar_data = self.create_bardata(
|
||||
lambda: pd.Timestamp('2016-01-26', tz='UTC'))
|
||||
lambda: pd.Timestamp('2016-01-27', tz='UTC'))
|
||||
contract = bar_data.current(cf_primary, 'contract')
|
||||
|
||||
self.assertEqual(contract.symbol, 'FOG16',
|
||||
'Auto close at beginning of session. FOG16 remains '
|
||||
'Auto close at beginning of session. FOG16 is now '
|
||||
'the current contract.')
|
||||
|
||||
bar_data = self.create_bardata(
|
||||
@@ -599,12 +601,12 @@ def record_current_contract(algo, data):
|
||||
|
||||
# Volume cuts out for FOF16 on 2016-01-25
|
||||
self.assertEqual(window.loc['2016-01-26', cf],
|
||||
1,
|
||||
"Should be FOG16 at beginning of window.")
|
||||
0,
|
||||
"Should be FOF16 at beginning of window.")
|
||||
|
||||
self.assertEqual(window.loc['2016-01-27', cf],
|
||||
1,
|
||||
"Should have remained FOG16.")
|
||||
"Should have rolled to FOG16.")
|
||||
|
||||
self.assertEqual(window.loc['2016-02-25', cf],
|
||||
1,
|
||||
@@ -630,24 +632,24 @@ def record_current_contract(algo, data):
|
||||
|
||||
self.assertEqual(window.loc['2016-02-26', cf],
|
||||
2,
|
||||
"Should be FOH16 on session with roll.")
|
||||
"Should be FOH16 on roll session.")
|
||||
|
||||
self.assertEqual(window.loc['2016-02-29', cf],
|
||||
2,
|
||||
"Should be FOH16 on session after roll.")
|
||||
"Should remain FOH16.")
|
||||
|
||||
self.assertEqual(window.loc['2016-03-17', cf],
|
||||
2,
|
||||
"Should be FOH16 on session before volume cuts out.")
|
||||
|
||||
self.assertEqual(window.loc['2016-03-18', cf],
|
||||
3,
|
||||
"Should be FOJ16 on session where the volume of "
|
||||
"FOH16 cuts out.")
|
||||
2,
|
||||
"Should be FOH16 on session where the volume of "
|
||||
"FOH16 cuts out, the roll is upcoming.")
|
||||
|
||||
self.assertEqual(window.loc['2016-03-24', cf],
|
||||
3,
|
||||
"Should have remained FOJ16.")
|
||||
"Should have rolled to FOJ16.")
|
||||
|
||||
self.assertEqual(window.loc['2016-03-28', cf],
|
||||
3,
|
||||
|
||||
@@ -96,23 +96,21 @@ class RollFinder(with_metaclass(ABCMeta, object)):
|
||||
i -= 1
|
||||
else:
|
||||
i -= 2
|
||||
auto_close_date = Timestamp(oc.auto_close_dates[i], tz='UTC')
|
||||
while auto_close_date > start and i > -1:
|
||||
session_loc = sessions.searchsorted(auto_close_date)
|
||||
curr = sessions[-1]
|
||||
while curr > start and i > -1:
|
||||
session_loc = sessions.searchsorted(curr)
|
||||
front = oc.contract_sids[i]
|
||||
back = oc.contract_sids[i + 1]
|
||||
while session_loc > -1:
|
||||
while session_loc > 0:
|
||||
session = sessions[session_loc]
|
||||
if back != self._active_contract(oc, front, back, session):
|
||||
prev = sessions[session_loc - 1]
|
||||
if back != self._active_contract(oc, front, back, prev):
|
||||
rolls.insert(0, (oc.contract_sids[i + offset], session))
|
||||
break
|
||||
session_loc -= 1
|
||||
roll_session = sessions[session_loc + 1]
|
||||
if roll_session > start:
|
||||
rolls.insert(0, (oc.contract_sids[i + offset],
|
||||
roll_session))
|
||||
i -= 1
|
||||
auto_close_date = Timestamp(oc.auto_close_dates[i],
|
||||
tz='UTC')
|
||||
curr = Timestamp(oc.auto_close_dates[i],
|
||||
tz='UTC')
|
||||
return rolls
|
||||
|
||||
|
||||
@@ -131,8 +129,8 @@ class CalendarRollFinder(RollFinder):
|
||||
if sid == front:
|
||||
break
|
||||
auto_close_date = Timestamp(oc.auto_close_dates[i], tz='UTC')
|
||||
before_auto_close = dt < auto_close_date
|
||||
return front if before_auto_close else back
|
||||
auto_closed = dt >= auto_close_date
|
||||
return back if auto_closed else front
|
||||
|
||||
|
||||
class VolumeRollFinder(RollFinder):
|
||||
@@ -149,7 +147,15 @@ class VolumeRollFinder(RollFinder):
|
||||
self.session_reader = session_reader
|
||||
|
||||
def _active_contract(self, oc, front, back, dt):
|
||||
# FIXME: Possible vector for look ahead bias.
|
||||
front_vol = self.session_reader.get_value(front, dt, 'volume')
|
||||
back_vol = self.session_reader.get_value(back, dt, 'volume')
|
||||
return back if back_vol > front_vol else front
|
||||
prev = dt - self.trading_calendar.day
|
||||
front_vol = self.session_reader.get_value(front, prev, 'volume')
|
||||
back_vol = self.session_reader.get_value(back, prev, 'volume')
|
||||
if back_vol > front_vol:
|
||||
return back
|
||||
else:
|
||||
for i, sid in enumerate(oc.contract_sids):
|
||||
if sid == front:
|
||||
break
|
||||
auto_close_date = Timestamp(oc.auto_close_dates[i], tz='UTC')
|
||||
auto_closed = dt >= auto_close_date
|
||||
return back if auto_closed else front
|
||||
|
||||
Reference in New Issue
Block a user