mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-08 14:54:17 +08:00
Merge pull request #1502 from quantopian/remove-future-chain
MAINT: Remove `future_chain` API method.
This commit is contained in:
@@ -87,8 +87,6 @@ Assets
|
||||
|
||||
.. autofunction:: zipline.api.future_symbol
|
||||
|
||||
.. autofunction:: zipline.api.future_chain
|
||||
|
||||
.. autofunction:: zipline.api.set_symbol_lookup_date
|
||||
|
||||
.. autofunction:: zipline.api.sid
|
||||
|
||||
@@ -58,7 +58,6 @@ from zipline.errors import (
|
||||
TradingControlViolation,
|
||||
AccountControlViolation,
|
||||
SymbolNotFound,
|
||||
RootSymbolNotFound,
|
||||
UnsupportedDatetimeFormat,
|
||||
CannotOrderDelistedAsset,
|
||||
SetCancelPolicyPostInit,
|
||||
@@ -726,108 +725,6 @@ def log_nyse_close(context, data):
|
||||
with self.assertRaises(TypeError):
|
||||
algo.future_symbol({'foo': 'bar'})
|
||||
|
||||
def test_future_chain_offset(self):
|
||||
# November 2006 December 2006
|
||||
# Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3 4 1 2
|
||||
# 5 6 7 8 9 10 11 3 4 5 6 7 8 9
|
||||
# 12 13 14 15 16 17 18 10 11 12 13 14 15 16
|
||||
# 19 20 21 22 23 24 25 17 18 19 20 21 22 23
|
||||
# 26 27 28 29 30 24 25 26 27 28 29 30
|
||||
# 31
|
||||
|
||||
algo = TradingAlgorithm(env=self.env)
|
||||
algo.datetime = pd.Timestamp('2006-12-01', tz='UTC')
|
||||
|
||||
self.assertEqual(
|
||||
algo.future_chain('CL', offset=1).as_of_date,
|
||||
pd.Timestamp("2006-12-04", tz='UTC')
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
algo.future_chain("CL", offset=5).as_of_date,
|
||||
pd.Timestamp("2006-12-08", tz='UTC')
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
algo.future_chain("CL", offset=-10).as_of_date,
|
||||
pd.Timestamp("2006-11-16", tz='UTC')
|
||||
)
|
||||
|
||||
# September 2016
|
||||
# Su Mo Tu We Th Fr Sa
|
||||
# 1 2 3
|
||||
# 4 5 6 7 8 9 10
|
||||
# 11 12 13 14 15 16 17
|
||||
# 18 19 20 21 22 23 24
|
||||
# 25 26 27 28 29 30
|
||||
self.assertEqual(
|
||||
algo.future_chain(
|
||||
"CL",
|
||||
as_of_date=pd.Timestamp("2016-08-31", tz='UTC'),
|
||||
offset=10
|
||||
).as_of_date,
|
||||
pd.Timestamp("2016-09-15", tz='UTC')
|
||||
)
|
||||
|
||||
def test_future_chain(self):
|
||||
algo = TradingAlgorithm(env=self.env)
|
||||
algo.datetime = pd.Timestamp('2006-12-01', tz='UTC')
|
||||
|
||||
# Check that the fields of the FutureChain object are set correctly
|
||||
cl = algo.future_chain('CL')
|
||||
self.assertEqual(cl.root_symbol, 'CL')
|
||||
self.assertEqual(cl.as_of_date, algo.datetime)
|
||||
|
||||
# Check the fields are set correctly if an as_of_date is supplied
|
||||
as_of_date = pd.Timestamp('1952-08-11', tz='UTC')
|
||||
|
||||
cl = algo.future_chain('CL', as_of_date=as_of_date)
|
||||
self.assertEqual(cl.root_symbol, 'CL')
|
||||
self.assertEqual(cl.as_of_date, as_of_date)
|
||||
|
||||
cl = algo.future_chain('CL', as_of_date='1952-08-11')
|
||||
self.assertEqual(cl.root_symbol, 'CL')
|
||||
self.assertEqual(cl.as_of_date, as_of_date)
|
||||
|
||||
# Check that weird capitalization is corrected
|
||||
cl = algo.future_chain('cL')
|
||||
self.assertEqual(cl.root_symbol, 'CL')
|
||||
|
||||
cl = algo.future_chain('cl')
|
||||
self.assertEqual(cl.root_symbol, 'CL')
|
||||
|
||||
# Check that invalid root symbols raise RootSymbolNotFound
|
||||
with self.assertRaises(RootSymbolNotFound):
|
||||
algo.future_chain('CLZ')
|
||||
|
||||
with self.assertRaises(RootSymbolNotFound):
|
||||
algo.future_chain('')
|
||||
|
||||
# Check that invalid dates raise UnsupportedDatetimeFormat
|
||||
with self.assertRaises(UnsupportedDatetimeFormat):
|
||||
algo.future_chain('CL', 'my_finger_slipped')
|
||||
|
||||
with self.assertRaises(UnsupportedDatetimeFormat):
|
||||
algo.future_chain('CL', '2015-09-')
|
||||
|
||||
# Supplying a non-string argument to future_chain()
|
||||
# should result in a TypeError.
|
||||
with self.assertRaises(TypeError):
|
||||
algo.future_chain(1)
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
algo.future_chain((1,))
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
algo.future_chain({1})
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
algo.future_chain([1])
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
algo.future_chain({'foo': 'bar'})
|
||||
|
||||
def test_set_symbol_lookup_date(self):
|
||||
"""
|
||||
Test the set_symbol_lookup_date API method.
|
||||
|
||||
@@ -48,11 +48,6 @@ from zipline.assets.synthetic import (
|
||||
from six import itervalues, integer_types
|
||||
from toolz import valmap
|
||||
|
||||
from zipline.assets.futures import (
|
||||
cme_code_to_month,
|
||||
FutureChain,
|
||||
month_to_cme_code
|
||||
)
|
||||
from zipline.assets.asset_writer import (
|
||||
check_version_info,
|
||||
write_version_info,
|
||||
@@ -67,7 +62,6 @@ from zipline.errors import (
|
||||
EquitiesNotFound,
|
||||
FutureContractsNotFound,
|
||||
MultipleSymbolsFound,
|
||||
RootSymbolNotFound,
|
||||
AssetDBVersionError,
|
||||
SidsNotFound,
|
||||
SymbolNotFound,
|
||||
@@ -883,94 +877,6 @@ class AssetFinderTestCase(WithTradingCalendars, ZiplineTestCase):
|
||||
self.assertTrue(issubclass(warning.category,
|
||||
DeprecationWarning))
|
||||
|
||||
def test_lookup_future_chain(self):
|
||||
metadata = pd.DataFrame.from_records([
|
||||
# Notice day is today, so should be valid.
|
||||
{
|
||||
'symbol': 'ADN15',
|
||||
'root_symbol': 'AD',
|
||||
'notice_date': pd.Timestamp('2015-06-14', tz='UTC'),
|
||||
'expiration_date': pd.Timestamp('2015-08-14', tz='UTC'),
|
||||
'start_date': pd.Timestamp('2015-01-01', tz='UTC'),
|
||||
'exchange': "TEST",
|
||||
},
|
||||
{
|
||||
'symbol': 'ADV15',
|
||||
'root_symbol': 'AD',
|
||||
'notice_date': pd.Timestamp('2015-05-14', tz='UTC'),
|
||||
'expiration_date': pd.Timestamp('2015-09-14', tz='UTC'),
|
||||
'start_date': pd.Timestamp('2015-01-01', tz='UTC'),
|
||||
'exchange': "TEST",
|
||||
},
|
||||
# Starts trading today, so should be valid.
|
||||
{
|
||||
'symbol': 'ADF16',
|
||||
'root_symbol': 'AD',
|
||||
'notice_date': pd.Timestamp('2015-11-16', tz='UTC'),
|
||||
'expiration_date': pd.Timestamp('2015-12-16', tz='UTC'),
|
||||
'start_date': pd.Timestamp('2015-05-14', tz='UTC'),
|
||||
'exchange': "TEST",
|
||||
},
|
||||
# Starts trading in August, so not valid.
|
||||
{
|
||||
'symbol': 'ADX16',
|
||||
'root_symbol': 'AD',
|
||||
'notice_date': pd.Timestamp('2015-11-16', tz='UTC'),
|
||||
'expiration_date': pd.Timestamp('2015-12-16', tz='UTC'),
|
||||
'start_date': pd.Timestamp('2015-08-01', tz='UTC'),
|
||||
'exchange': "TEST",
|
||||
},
|
||||
# Notice date comes after expiration
|
||||
{
|
||||
'symbol': 'ADZ16',
|
||||
'root_symbol': 'AD',
|
||||
'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'),
|
||||
'exchange': "TEST",
|
||||
},
|
||||
# This contract has no start date and also this contract should be
|
||||
# last in all chains
|
||||
{
|
||||
'symbol': 'ADZ20',
|
||||
'root_symbol': 'AD',
|
||||
'notice_date': pd.Timestamp('2020-11-25', tz='UTC'),
|
||||
'expiration_date': pd.Timestamp('2020-11-16', tz='UTC'),
|
||||
'exchange': "TEST",
|
||||
},
|
||||
])
|
||||
self.write_assets(futures=metadata)
|
||||
finder = self.asset_finder
|
||||
dt = pd.Timestamp('2015-05-14', 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)
|
||||
self.assertEqual(len(ad_contracts), 6)
|
||||
self.assertEqual(ad_contracts[0].sid, 1)
|
||||
self.assertEqual(ad_contracts[1].sid, 0)
|
||||
self.assertEqual(ad_contracts[5].sid, 5)
|
||||
|
||||
# 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 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)
|
||||
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
|
||||
dt = pd.Timestamp('2014-01-01', tz='UTC')
|
||||
@@ -1218,179 +1124,6 @@ class AssetFinderTestCase(WithTradingCalendars, ZiplineTestCase):
|
||||
)
|
||||
|
||||
|
||||
class TestFutureChain(WithAssetFinder, ZiplineTestCase):
|
||||
@classmethod
|
||||
def make_futures_info(cls):
|
||||
return pd.DataFrame.from_records([
|
||||
{
|
||||
'symbol': 'CLG06',
|
||||
'root_symbol': 'CL',
|
||||
'start_date': pd.Timestamp('2005-12-01', tz='UTC'),
|
||||
'notice_date': pd.Timestamp('2005-12-20', tz='UTC'),
|
||||
'expiration_date': pd.Timestamp('2006-01-20', tz='UTC'),
|
||||
'exchange': "TEST",
|
||||
},
|
||||
{
|
||||
'root_symbol': 'CL',
|
||||
'symbol': 'CLK06',
|
||||
'start_date': pd.Timestamp('2005-12-01', tz='UTC'),
|
||||
'notice_date': pd.Timestamp('2006-03-20', tz='UTC'),
|
||||
'expiration_date': pd.Timestamp('2006-04-20', tz='UTC'),
|
||||
'exchange': "TEST",
|
||||
},
|
||||
{
|
||||
'symbol': 'CLQ06',
|
||||
'root_symbol': 'CL',
|
||||
'start_date': pd.Timestamp('2005-12-01', tz='UTC'),
|
||||
'notice_date': pd.Timestamp('2006-06-20', tz='UTC'),
|
||||
'expiration_date': pd.Timestamp('2006-07-20', tz='UTC'),
|
||||
'exchange': "TEST",
|
||||
},
|
||||
{
|
||||
'symbol': 'CLX06',
|
||||
'root_symbol': 'CL',
|
||||
'start_date': pd.Timestamp('2006-02-01', tz='UTC'),
|
||||
'notice_date': pd.Timestamp('2006-09-20', tz='UTC'),
|
||||
'expiration_date': pd.Timestamp('2006-10-20', tz='UTC'),
|
||||
'exchange': "TEST",
|
||||
}
|
||||
])
|
||||
|
||||
def _get_future_chain(self, date_str, symbol):
|
||||
dt = pd.Timestamp(date_str, tz='UTC')
|
||||
|
||||
return FutureChain(
|
||||
symbol,
|
||||
dt,
|
||||
self.asset_finder.lookup_future_chain(symbol, dt)
|
||||
)
|
||||
|
||||
def test_len(self):
|
||||
""" Test the __len__ method of FutureChain.
|
||||
"""
|
||||
# Sids 0, 1, & 2 have started, 3 has not yet started, but all are in
|
||||
# the chain
|
||||
cl = self._get_future_chain('2005-12-01', 'CL')
|
||||
self.assertEqual(len(cl), 4)
|
||||
|
||||
# Sid 0 is still valid on its notice date.
|
||||
cl = self._get_future_chain('2005-12-20', 'CL')
|
||||
self.assertEqual(len(cl), 4)
|
||||
|
||||
# Sid 0 is now invalid, leaving Sids 1 & 2 valid (and 3 not started).
|
||||
cl = self._get_future_chain('2005-12-21', 'CL')
|
||||
self.assertEqual(len(cl), 3)
|
||||
|
||||
# Sid 3 has started, so 1, 2, & 3 are now valid.
|
||||
cl = self._get_future_chain('2006-02-01', 'CL')
|
||||
self.assertEqual(len(cl), 3)
|
||||
|
||||
# All contracts are no longer valid.
|
||||
cl = self._get_future_chain('2006-09-21', 'CL')
|
||||
self.assertEqual(len(cl), 0)
|
||||
|
||||
def test_getitem(self):
|
||||
""" Test the __getitem__ method of FutureChain.
|
||||
"""
|
||||
cl = self._get_future_chain('2005-12-01', 'CL')
|
||||
self.assertEqual(cl[0], 0)
|
||||
self.assertEqual(cl[1], 1)
|
||||
self.assertEqual(cl[2], 2)
|
||||
|
||||
cl = self._get_future_chain('2005-12-20', 'CL')
|
||||
self.assertEqual(cl[0], 0)
|
||||
|
||||
cl = self._get_future_chain('2005-12-21', 'CL')
|
||||
self.assertEqual(cl[0], 1)
|
||||
|
||||
cl = self._get_future_chain('2006-02-01', 'CL')
|
||||
self.assertEqual(cl[-1], 3)
|
||||
|
||||
def test_iter(self):
|
||||
""" Test the __iter__ method of FutureChain.
|
||||
"""
|
||||
cl = self._get_future_chain('2005-12-01', 'CL')
|
||||
for i, contract in enumerate(cl):
|
||||
self.assertEqual(contract, i)
|
||||
|
||||
# First contract is now invalid, so sids will be offset by one
|
||||
cl = self._get_future_chain('2005-12-21', 'CL')
|
||||
for i, contract in enumerate(cl):
|
||||
self.assertEqual(contract, i + 1)
|
||||
|
||||
def test_root_symbols(self):
|
||||
""" Test that different variations on root symbols are handled
|
||||
as expected.
|
||||
"""
|
||||
# Make sure this successfully gets the chain for CL.
|
||||
cl = self._get_future_chain('2005-12-01', 'CL')
|
||||
self.assertEqual(cl.root_symbol, 'CL')
|
||||
|
||||
# These root symbols don't exist, so RootSymbolNotFound should
|
||||
# be raised immediately.
|
||||
with self.assertRaises(RootSymbolNotFound):
|
||||
self._get_future_chain('2005-12-01', 'CLZ')
|
||||
|
||||
with self.assertRaises(RootSymbolNotFound):
|
||||
self._get_future_chain('2005-12-01', '')
|
||||
|
||||
def test_repr(self):
|
||||
""" Test the __repr__ method of FutureChain.
|
||||
"""
|
||||
cl = self._get_future_chain('2005-12-01', 'CL')
|
||||
|
||||
self.assertEqual(
|
||||
repr(cl),
|
||||
"FutureChain('CL', '2005-12-01')"
|
||||
)
|
||||
|
||||
def test_contracts_returns_a_copy(self):
|
||||
cl = self._get_future_chain('2005-12-01', 'CL')
|
||||
self.assertEqual(len(cl), 4)
|
||||
|
||||
contracts = cl.contracts
|
||||
contracts.pop(0)
|
||||
|
||||
self.assertEqual(len(contracts), 3)
|
||||
self.assertEqual(len(cl), 4)
|
||||
|
||||
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))
|
||||
|
||||
|
||||
class TestAssetDBVersioning(ZiplineTestCase):
|
||||
|
||||
def init_instance_fixtures(self):
|
||||
|
||||
@@ -82,7 +82,6 @@ from zipline.finance.slippage import (
|
||||
)
|
||||
from zipline.finance.cancel_policy import NeverCancel, CancelPolicy
|
||||
from zipline.assets import Asset, Future
|
||||
from zipline.assets.futures import FutureChain
|
||||
from zipline.gens.tradesimulation import AlgorithmSimulator
|
||||
from zipline.pipeline import Pipeline
|
||||
from zipline.pipeline.engine import (
|
||||
@@ -1246,68 +1245,6 @@ class TradingAlgorithm(object):
|
||||
"""
|
||||
return self.asset_finder.lookup_future_symbol(symbol)
|
||||
|
||||
@api_method
|
||||
@preprocess(root_symbol=ensure_upper_case)
|
||||
def future_chain(self, root_symbol, as_of_date=None, offset=0):
|
||||
"""
|
||||
Look up a future chain.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
root_symbol : str
|
||||
The root symbol of a future chain.
|
||||
as_of_date : datetime.datetime or pandas.Timestamp or str, optional
|
||||
Date at which the chain determination is rooted. If this date is
|
||||
not passed in, the current simulation session (not minute) is used.
|
||||
offset: int
|
||||
Number of sessions to shift `as_of_date`. Positive values shift
|
||||
forward in time. Negative values shift backward in time.
|
||||
|
||||
Returns
|
||||
-------
|
||||
chain : FutureChain
|
||||
The future chain matching the specified parameters.
|
||||
|
||||
Raises
|
||||
------
|
||||
RootSymbolNotFound
|
||||
If a future chain could not be found for the given root symbol.
|
||||
"""
|
||||
if as_of_date:
|
||||
try:
|
||||
as_of_date = pd.Timestamp(as_of_date, tz='UTC')
|
||||
except ValueError:
|
||||
raise UnsupportedDatetimeFormat(
|
||||
input=as_of_date,
|
||||
method='future_chain'
|
||||
)
|
||||
else:
|
||||
as_of_date = self.trading_calendar.minute_to_session_label(
|
||||
self.get_datetime()
|
||||
)
|
||||
|
||||
if offset != 0:
|
||||
# move as_of_date by offset sessions
|
||||
session_window = self.trading_calendar.sessions_window(
|
||||
as_of_date, offset
|
||||
)
|
||||
|
||||
if offset > 0:
|
||||
as_of_date = session_window[-1]
|
||||
else:
|
||||
as_of_date = session_window[0]
|
||||
|
||||
chain_of_contracts = self.asset_finder.lookup_future_chain(
|
||||
root_symbol,
|
||||
as_of_date
|
||||
)
|
||||
|
||||
return FutureChain(
|
||||
root_symbol=root_symbol,
|
||||
as_of_date=as_of_date,
|
||||
contracts=chain_of_contracts
|
||||
)
|
||||
|
||||
def _calculate_order_value_amount(self, asset, value):
|
||||
"""
|
||||
Calculates how many shares/contracts to order based on the type of
|
||||
|
||||
@@ -40,7 +40,6 @@ from zipline.errors import (
|
||||
FutureContractsNotFound,
|
||||
MapAssetIdentifierIndexError,
|
||||
MultipleSymbolsFound,
|
||||
RootSymbolNotFound,
|
||||
SidsNotFound,
|
||||
SymbolNotFound,
|
||||
)
|
||||
@@ -741,62 +740,6 @@ class AssetFinder(object):
|
||||
raise SymbolNotFound(symbol=symbol)
|
||||
return self.retrieve_asset(data['sid'])
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list
|
||||
A list of Future objects, the chain for the given
|
||||
parameters.
|
||||
|
||||
Raises
|
||||
------
|
||||
RootSymbolNotFound
|
||||
Raised when a future chain could not be found for the given
|
||||
root symbol.
|
||||
"""
|
||||
fc_cols = self.futures_contracts.c
|
||||
|
||||
if as_of_date is pd.NaT:
|
||||
# If the as_of_date is NaT, get all contracts for this
|
||||
# root symbol.
|
||||
sids = list(map(
|
||||
itemgetter('sid'),
|
||||
sa.select((fc_cols.sid,)).where(
|
||||
(fc_cols.root_symbol == root_symbol),
|
||||
).order_by(
|
||||
fc_cols.notice_date.asc(),
|
||||
).execute().fetchall()))
|
||||
else:
|
||||
sids = self._get_future_sids_for_root_symbol(
|
||||
root_symbol,
|
||||
as_of_date.value
|
||||
)
|
||||
|
||||
if not sids:
|
||||
# Check if root symbol exists.
|
||||
count = sa.select((sa.func.count(fc_cols.sid),)).where(
|
||||
fc_cols.root_symbol == root_symbol,
|
||||
).scalar()
|
||||
if count == 0:
|
||||
raise RootSymbolNotFound(root_symbol=root_symbol)
|
||||
|
||||
contracts = self.retrieve_futures_contracts(sids)
|
||||
return [contracts[sid] for sid in sids]
|
||||
|
||||
@weak_lru_cache(100)
|
||||
def _get_future_sids_for_root_symbol(self, root_symbol, as_of_date_ns):
|
||||
fc_cols = self.futures_contracts.c
|
||||
|
||||
@@ -13,164 +13,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from pandas import Timestamp
|
||||
|
||||
from zipline.utils.input_validation import expect_types
|
||||
|
||||
|
||||
class FutureChain(object):
|
||||
"""
|
||||
Allows users to look up future contracts.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
root_symbol : str
|
||||
The root symbol of a future chain.
|
||||
as_of_date : pandas.Timestamp
|
||||
Date at which the chain determination is rooted. I.e. the
|
||||
existing contract whose notice date is first after this date is
|
||||
the primary contract, etc.
|
||||
chain: list
|
||||
List of assets that represent the chain of contracts for the given
|
||||
root symbol at the given as_of_date.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
root_symbol : str
|
||||
The root symbol of the future chain.
|
||||
as_of_date: Timestamp
|
||||
The current as-of date of this future chain.
|
||||
"""
|
||||
@expect_types(root_symbol=str, as_of_date=Timestamp)
|
||||
def __init__(self, root_symbol, as_of_date, contracts):
|
||||
self._root_symbol = root_symbol
|
||||
self._as_of_date = as_of_date
|
||||
self._contracts = contracts
|
||||
|
||||
def __repr__(self):
|
||||
return "FutureChain('%s', '%s')" % (
|
||||
self.root_symbol, self.as_of_date.strftime('%Y-%m-%d'))
|
||||
|
||||
@property
|
||||
def root_symbol(self):
|
||||
"""
|
||||
The root symbol for this future chain.
|
||||
|
||||
Returns
|
||||
-------
|
||||
root_symbol: str
|
||||
The root symbol for this chain.
|
||||
"""
|
||||
return self._root_symbol
|
||||
|
||||
@property
|
||||
def as_of_date(self):
|
||||
"""
|
||||
The as-of date of this future chain.
|
||||
|
||||
Returns
|
||||
-------
|
||||
as_of_date: pd.Timestamp
|
||||
The as_of date for this chain.
|
||||
"""
|
||||
return self._as_of_date
|
||||
|
||||
@property
|
||||
def contracts(self):
|
||||
"""
|
||||
Returns
|
||||
-------
|
||||
contracts: list
|
||||
The contracts wrapped by this chain.
|
||||
"""
|
||||
return list(self._contracts)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._contracts[key]
|
||||
|
||||
def __len__(self):
|
||||
return len(self._contracts)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._contracts)
|
||||
|
||||
|
||||
# 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]
|
||||
|
||||
Reference in New Issue
Block a user