diff --git a/setup.py b/setup.py index acf1c5c4..826bfd7d 100644 --- a/setup.py +++ b/setup.py @@ -20,8 +20,8 @@ import numpy as np ext_modules = [ Extension( - 'zipline.assets._securities', - ['zipline/assets/_securities.pyx'], + 'zipline.assets._assets', + ['zipline/assets/_assets.pyx'], include_dirs=[np.get_include()], ), ] diff --git a/tests/test_assets.py b/tests/test_assets.py index 7c856d93..fea726ab 100644 --- a/tests/test_assets.py +++ b/tests/test_assets.py @@ -17,33 +17,73 @@ Tests for the zipline.assets package """ +import sys from unittest import TestCase -from zipline.assets._securities import Security +from zipline.assets._assets import Asset, Future -class SecurityTestCase(TestCase): +class AssetTestCase(TestCase): - def test_security_object(self): - self.assertEquals({5061: 'foo'}[Security(5061)], 'foo') - self.assertEquals(Security(5061), 5061) - self.assertEquals(5061, Security(5061)) + def test_asset_object(self): + self.assertEquals({5061: 'foo'}[Asset(5061)], 'foo') + self.assertEquals(Asset(5061), 5061) + self.assertEquals(5061, Asset(5061)) - self.assertEquals(Security(5061), Security(5061)) - self.assertEquals(int(Security(5061)), 5061) + self.assertEquals(Asset(5061), Asset(5061)) + self.assertEquals(int(Asset(5061)), 5061) - self.assertEquals(str(Security(5061)), 'Security(5061)') + self.assertEquals(str(Asset(5061)), 'Asset(5061)') - # TODO: we can't provide this property while subclassing - # int. Need to subclass object to fix all the following - # cases. - # assert Security(5061) != 5061.0 - # with self.assertRaises(TypeError): - # assert Security(5061) + Security(5061) +class TestAssetRichCmp(TestCase): - # with self.assertRaises(TypeError): - # print float(Security(5061)) + def test_lt(self): + self.assertTrue(Asset(3) < Asset(4)) + self.assertFalse(Asset(4) < Asset(4)) + self.assertFalse(Asset(5) < Asset(4)) - # with self.assertRaises(TypeError): - # print float(Security(5061)) + def test_le(self): + self.assertTrue(Asset(3) <= Asset(4)) + self.assertTrue(Asset(4) <= Asset(4)) + self.assertFalse(Asset(5) <= Asset(4)) + + def test_eq(self): + self.assertFalse(Asset(3) == Asset(4)) + self.assertTrue(Asset(4) == Asset(4)) + self.assertFalse(Asset(5) == Asset(4)) + + def test_ge(self): + self.assertFalse(Asset(3) >= Asset(4)) + self.assertTrue(Asset(4) >= Asset(4)) + self.assertTrue(Asset(5) >= Asset(4)) + + def test_gt(self): + self.assertFalse(Asset(3) > Asset(4)) + self.assertFalse(Asset(4) > Asset(4)) + self.assertTrue(Asset(5) > Asset(4)) + + def test_type_mismatch(self): + if sys.version_info.major < 3: + self.assertIsNotNone(Asset(3) < 'a') + self.assertIsNotNone('a' < Asset(3)) + else: + with self.assertRaises(TypeError): + Asset(3) < 'a' + with self.assertRaises(TypeError): + 'a' < Asset(3) + + +class testFuture(TestCase): + + def test_repr(self): + + future = Future(2468, + notice_date='2014-01-20', + expiration_date='2014-02-20') + rep = future.__repr__() + + self.assertTrue("Future" in rep) + self.assertTrue("2468" in rep) + self.assertTrue("notice_date='2014-01-20'" in rep) + self.assertTrue("expiration_date='2014-02-20'" in rep) diff --git a/tests/test_security_object.py b/tests/test_security_object.py deleted file mode 100644 index 528a8bc3..00000000 --- a/tests/test_security_object.py +++ /dev/null @@ -1,40 +0,0 @@ -import sys -from unittest import TestCase -from zipline.assets._securities import Security - - -class TestSecurityRichCmp(TestCase): - def test_lt(self): - self.assertTrue(Security(3) < Security(4)) - self.assertFalse(Security(4) < Security(4)) - self.assertFalse(Security(5) < Security(4)) - - def test_le(self): - self.assertTrue(Security(3) <= Security(4)) - self.assertTrue(Security(4) <= Security(4)) - self.assertFalse(Security(5) <= Security(4)) - - def test_eq(self): - self.assertFalse(Security(3) == Security(4)) - self.assertTrue(Security(4) == Security(4)) - self.assertFalse(Security(5) == Security(4)) - - def test_ge(self): - self.assertFalse(Security(3) >= Security(4)) - self.assertTrue(Security(4) >= Security(4)) - self.assertTrue(Security(5) >= Security(4)) - - def test_gt(self): - self.assertFalse(Security(3) > Security(4)) - self.assertFalse(Security(4) > Security(4)) - self.assertTrue(Security(5) > Security(4)) - - def test_type_mismatch(self): - if sys.version_info.major < 3: - self.assertIsNotNone(Security(3) < 'a') - self.assertIsNotNone('a' < Security(3)) - else: - with self.assertRaises(TypeError): - Security(3) < 'a' - with self.assertRaises(TypeError): - 'a' < Security(3) diff --git a/zipline/assets/_securities.pyx b/zipline/assets/_assets.pyx similarity index 62% rename from zipline/assets/_securities.pyx rename to zipline/assets/_assets.pyx index 30f94401..16b8ba06 100644 --- a/zipline/assets/_securities.pyx +++ b/zipline/assets/_assets.pyx @@ -14,22 +14,26 @@ # limitations under the License. """ -Cythonized Security object. +Cythonized Asset object. """ cimport cython import numpy as np cimport numpy as np +cdef enum AssetType: + EQUITY = 1 + FUTURE = 2 -cdef class Security: +cdef class Asset: cdef readonly int sid # Cached hash of self.sid cdef int sid_hash cdef readonly object symbol - cdef readonly object security_name + cdef readonly object asset_name + cdef readonly AssetType asset_type # TODO: Maybe declare as pandas Timestamp? cdef readonly object start_date @@ -41,16 +45,18 @@ cdef class Security: def __cinit__(self, int sid, # sid is required object symbol="", - object security_name="", + object asset_name="", object start_date=None, object end_date=None, object first_traded=None, - object exchange=""): + object exchange="", + *args, + **kwargs): self.sid = sid - self.sid_hash = hash(sid) + self.sid_hash = hash(sid) self.symbol = symbol - self.security_name = security_name + self.asset_name = asset_name self.exchange = exchange self.start_date = start_date self.end_date = end_date @@ -62,7 +68,7 @@ cdef class Security: def __hash__(self): return self.sid_hash - property security_start_date: + property asset_start_date: """ Alias for start_date to disambiguate from other `start_date`s in the system. @@ -70,7 +76,7 @@ cdef class Security: def __get__(self): return self.start_date - property security_end_date: + property asset_end_date: """ Alias for end_date to disambiguate from other `end_date`s in the system. @@ -92,14 +98,14 @@ cdef class Security: """ cdef int x_as_int, y_as_int - if isinstance(x, Security): + if isinstance(x, Asset): x_as_int = x.sid elif isinstance(x, int): x_as_int = x else: return NotImplemented - if isinstance(y, Security): + if isinstance(y, Asset): y_as_int = y.sid elif isinstance(y, int): y_as_int = y @@ -131,18 +137,18 @@ cdef class Security: def __str__(self): if self.symbol: - return 'Security(%d [%s])' % (self.sid, self.symbol) + return 'Asset(%d [%s])' % (self.sid, self.symbol) else: - return 'Security(%d)' % self.sid + return 'Asset(%d)' % self.sid def __repr__(self): - attrs = ('symbol', 'security_name', 'exchange', + attrs = ('symbol', 'asset_name', 'exchange', 'start_date', 'end_date', 'first_traded') tuples = ((attr, repr(getattr(self, attr, None))) for attr in attrs) strings = ('%s=%s' % (t[0], t[1]) for t in tuples) params = ', '.join(strings) - return 'Security(%d, %s)' % (self.sid, params) + return 'Asset(%d, %s)' % (self.sid, params) cpdef __reduce__(self): """ @@ -153,7 +159,7 @@ cdef class Security: """ return (self.__class__, (self.sid, self.symbol, - self.security_name, + self.asset_name, self.start_date, self.end_date, self.first_traded, @@ -166,7 +172,7 @@ cdef class Security: return { 'sid': self.sid, 'symbol': self.symbol, - 'security_name': self.security_name, + 'asset_name': self.asset_name, 'start_date': self.start_date, 'end_date': self.end_date, 'first_traded': self.first_traded, @@ -176,6 +182,60 @@ cdef class Security: @staticmethod def from_dict(dict_): """ - Build a Security instance from a dict. + Build an Asset instance from a dict. """ - return Security(**dict_) + return Asset(**dict_) + + +cdef class Equity(Asset): + + def __cinit__(self, + int sid, # sid is required + object symbol="", + object asset_name="", + object start_date=None, + object end_date=None, + object first_traded=None, + object exchange=""): + + self.asset_type = EQUITY + + def __repr__(self): + attrs = ('symbol', 'asset_name', 'exchange', + 'start_date', 'end_date', 'first_traded') + tuples = ((attr, repr(getattr(self, attr, None))) + for attr in attrs) + strings = ('%s=%s' % (t[0], t[1]) for t in tuples) + params = ', '.join(strings) + return 'Equity(%d, %s)' % (self.sid, params) + + +cdef class Future(Asset): + + cdef readonly object notice_date + cdef readonly object expiration_date + + def __cinit__(self, + int sid, # sid is required + object symbol="", + object asset_name="", + object start_date=None, + object end_date=None, + object notice_date=None, + object expiration_date=None, + object first_traded=None, + object exchange=""): + + self.asset_type = FUTURE + self.notice_date = notice_date + self.expiration_date = expiration_date + + def __repr__(self): + attrs = ('symbol', 'asset_name', 'exchange', + 'start_date', 'end_date', 'first_traded', 'notice_date', + 'expiration_date') + tuples = ((attr, repr(getattr(self, attr, None))) + for attr in attrs) + strings = ('%s=%s' % (t[0], t[1]) for t in tuples) + params = ', '.join(strings) + return 'Future(%d, %s)' % (self.sid, params)