mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-05 01:06:33 +08:00
Merge pull request #782 from quantopian/future-chain-start-date
MAINT: Removes unneeded knowledge_date logic from future_chain
This commit is contained in:
+39
-38
@@ -627,7 +627,7 @@ class AssetFinderTestCase(TestCase):
|
||||
def test_lookup_future_chain(self):
|
||||
metadata = {
|
||||
# Notice day is today, so should be valid.
|
||||
2: {
|
||||
0: {
|
||||
'symbol': 'ADN15',
|
||||
'root_symbol': 'AD',
|
||||
'asset_type': 'future',
|
||||
@@ -644,7 +644,7 @@ class AssetFinderTestCase(TestCase):
|
||||
'start_date': pd.Timestamp('2015-01-01', tz='UTC')
|
||||
},
|
||||
# Starts trading today, so should be valid.
|
||||
0: {
|
||||
2: {
|
||||
'symbol': 'ADF16',
|
||||
'root_symbol': 'AD',
|
||||
'asset_type': 'future',
|
||||
@@ -666,45 +666,51 @@ class AssetFinderTestCase(TestCase):
|
||||
'symbol': 'ADZ16',
|
||||
'root_symbol': 'AD',
|
||||
'asset_type': 'future',
|
||||
'notice_date': pd.Timestamp('2015-11-25', tz='UTC'),
|
||||
'notice_date': pd.Timestamp('2016-11-25', tz='UTC'),
|
||||
'expiration_date': pd.Timestamp('2016-11-16', tz='UTC'),
|
||||
'start_date': pd.Timestamp('2015-08-01', tz='UTC')
|
||||
},
|
||||
# This contract has no start date and also this contract should be
|
||||
# last in all chains
|
||||
5: {
|
||||
'symbol': 'ADZ20',
|
||||
'root_symbol': 'AD',
|
||||
'asset_type': 'future',
|
||||
'notice_date': pd.Timestamp('2020-11-25', tz='UTC'),
|
||||
'expiration_date': pd.Timestamp('2020-11-16', tz='UTC')
|
||||
},
|
||||
}
|
||||
self.env.write_data(futures_data=metadata)
|
||||
finder = AssetFinder(self.env.engine)
|
||||
dt = pd.Timestamp('2015-05-14', tz='UTC')
|
||||
last_year = pd.Timestamp('2014-01-01', tz='UTC')
|
||||
first_day = pd.Timestamp('2015-01-01', tz='UTC')
|
||||
dt_2 = pd.Timestamp('2016-11-17', tz='UTC')
|
||||
dt_2 = pd.Timestamp('2015-10-14', tz='UTC')
|
||||
dt_3 = pd.Timestamp('2016-11-17', tz='UTC')
|
||||
|
||||
# Check that we get the expected number of contracts, in the
|
||||
# right order
|
||||
ad_contracts = finder.lookup_future_chain('AD', dt, dt)
|
||||
self.assertEqual(len(ad_contracts), 3)
|
||||
self.assertEqual(ad_contracts[0].sid, 2)
|
||||
ad_contracts = finder.lookup_future_chain('AD', dt)
|
||||
self.assertEqual(len(ad_contracts), 6)
|
||||
self.assertEqual(ad_contracts[0].sid, 0)
|
||||
self.assertEqual(ad_contracts[1].sid, 1)
|
||||
self.assertEqual(ad_contracts[5].sid, 5)
|
||||
|
||||
# Check that pd.NaT for knowledge_date uses the value of as_of_date
|
||||
ad_contracts = finder.lookup_future_chain('AD', dt, pd.NaT)
|
||||
self.assertEqual(len(ad_contracts), 3)
|
||||
# Check that, when some contracts have expired, the chain has advanced
|
||||
# properly to the next contracts
|
||||
ad_contracts = finder.lookup_future_chain('AD', dt_2)
|
||||
self.assertEqual(len(ad_contracts), 4)
|
||||
self.assertEqual(ad_contracts[0].sid, 2)
|
||||
self.assertEqual(ad_contracts[3].sid, 5)
|
||||
|
||||
# Check that we get nothing if our knowledge date is last year
|
||||
ad_contracts = finder.lookup_future_chain('AD', dt, last_year)
|
||||
self.assertEqual(len(ad_contracts), 0)
|
||||
|
||||
# Check that we get things that start on the knowledge date
|
||||
ad_contracts = finder.lookup_future_chain('AD', dt, first_day)
|
||||
self.assertEqual(len(ad_contracts), 2)
|
||||
# Check that when the expiration_date has passed but the
|
||||
# notice_date hasn't, contract is still considered invalid.
|
||||
ad_contracts = finder.lookup_future_chain('AD', dt_3)
|
||||
self.assertEqual(len(ad_contracts), 1)
|
||||
self.assertEqual(ad_contracts[0].sid, 5)
|
||||
|
||||
# Check that pd.NaT for as_of_date gives the whole chain
|
||||
ad_contracts = finder.lookup_future_chain('AD', pd.NaT, first_day)
|
||||
self.assertEqual(len(ad_contracts), 5)
|
||||
|
||||
# Check that when the expiration_date has past but the
|
||||
# notice_date hasn't, contract is still considered invalid.
|
||||
ad_contracts = finder.lookup_future_chain('AD', dt_2, dt_2)
|
||||
self.assertEqual(len(ad_contracts), 0)
|
||||
ad_contracts = finder.lookup_future_chain('AD', pd.NaT)
|
||||
self.assertEqual(len(ad_contracts), 6)
|
||||
self.assertEqual(ad_contracts[5].sid, 5)
|
||||
|
||||
def test_map_identifier_index_to_sids(self):
|
||||
# Build an empty finder and some Assets
|
||||
@@ -843,21 +849,18 @@ class TestFutureChain(TestCase):
|
||||
def test_len(self):
|
||||
""" Test the __len__ method of FutureChain.
|
||||
"""
|
||||
# None of the contracts have started yet.
|
||||
cl = FutureChain(self.asset_finder, lambda: '2005-11-30', 'CL')
|
||||
self.assertEqual(len(cl), 0)
|
||||
|
||||
# Sids 0, 1, & 2 have started, 3 has not yet started.
|
||||
# Sids 0, 1, & 2 have started, 3 has not yet started, but all are in
|
||||
# the chain
|
||||
cl = FutureChain(self.asset_finder, lambda: '2005-12-01', 'CL')
|
||||
self.assertEqual(len(cl), 3)
|
||||
self.assertEqual(len(cl), 4)
|
||||
|
||||
# Sid 0 is still valid its notice date.
|
||||
# Sid 0 is still valid on its notice date.
|
||||
cl = FutureChain(self.asset_finder, lambda: '2005-12-20', 'CL')
|
||||
self.assertEqual(len(cl), 3)
|
||||
self.assertEqual(len(cl), 4)
|
||||
|
||||
# Sid 0 is now invalid, leaving only Sids 1 & 2 valid.
|
||||
# Sid 0 is now invalid, leaving Sids 1 & 2 valid (and 3 not started).
|
||||
cl = FutureChain(self.asset_finder, lambda: '2005-12-21', 'CL')
|
||||
self.assertEqual(len(cl), 2)
|
||||
self.assertEqual(len(cl), 3)
|
||||
|
||||
# Sid 3 has started, so 1, 2, & 3 are now valid.
|
||||
cl = FutureChain(self.asset_finder, lambda: '2006-02-01', 'CL')
|
||||
@@ -874,8 +877,6 @@ class TestFutureChain(TestCase):
|
||||
self.assertEqual(cl[0], 0)
|
||||
self.assertEqual(cl[1], 1)
|
||||
self.assertEqual(cl[2], 2)
|
||||
with self.assertRaises(IndexError):
|
||||
cl[3]
|
||||
|
||||
cl = FutureChain(self.asset_finder, lambda: '2005-12-20', 'CL')
|
||||
self.assertEqual(cl[0], 0)
|
||||
|
||||
@@ -343,26 +343,20 @@ class AssetFinder(object):
|
||||
|
||||
return future
|
||||
|
||||
def lookup_future_chain(self, root_symbol, as_of_date, knowledge_date):
|
||||
def lookup_future_chain(self, root_symbol, as_of_date):
|
||||
""" Return the futures chain for a given root symbol.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
root_symbol : str
|
||||
Root symbol of the desired future.
|
||||
as_of_date : pd.Timestamp or pd.NaT
|
||||
|
||||
as_of_date : pd.Timestamp or pd.NaT
|
||||
Date at which the chain determination is rooted. I.e. the
|
||||
existing contract whose notice date/expiration date is first
|
||||
after this date is the primary contract, etc. If NaT is
|
||||
given, the chain is unbounded, and all contracts for this
|
||||
root symbol are returned.
|
||||
knowledge_date : pd.Timestamp or pd.NaT
|
||||
Date for determining which contracts exist for inclusion in
|
||||
this chain. Contracts exist only if they have a start_date
|
||||
on or before this date. If NaT is given and as_of_date is
|
||||
is not NaT, the value of as_of_date is used for
|
||||
knowledge_date.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -391,17 +385,11 @@ class AssetFinder(object):
|
||||
).execute().fetchall()))
|
||||
else:
|
||||
as_of_date = as_of_date.value
|
||||
if knowledge_date is pd.NaT:
|
||||
# If knowledge_date is NaT, default to using as_of_date
|
||||
knowledge_date = as_of_date
|
||||
else:
|
||||
knowledge_date = knowledge_date.value
|
||||
|
||||
sids = list(map(
|
||||
itemgetter('sid'),
|
||||
sa.select((fc_cols.sid,)).where(
|
||||
(fc_cols.root_symbol == root_symbol) &
|
||||
(fc_cols.start_date <= knowledge_date) &
|
||||
|
||||
# Filter to contracts that are still valid. If both
|
||||
# exist, use the one that comes first in time (i.e.
|
||||
|
||||
@@ -126,15 +126,13 @@ class FutureChain(object):
|
||||
list
|
||||
The up-to-date current chain, a list of Future objects.
|
||||
"""
|
||||
dt = self._get_datetime()
|
||||
|
||||
if (self._last_updated is None) or (self._last_updated != dt):
|
||||
if (self._last_updated is None)\
|
||||
or (self._last_updated != self.as_of_date):
|
||||
self._current_chain = self._asset_finder.lookup_future_chain(
|
||||
self.root_symbol,
|
||||
self.as_of_date,
|
||||
dt
|
||||
self.as_of_date
|
||||
)
|
||||
self._last_updated = dt
|
||||
self._last_updated = self.as_of_date
|
||||
|
||||
return self._current_chain
|
||||
|
||||
|
||||
Reference in New Issue
Block a user