mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-06 05:14:38 +08:00
MAINT: Removes the ability to reference a global TradingEnvironment
This commit removes the ability to reference a shared TradingEnvironment through the zipline.finance.trading module. In place, the classes that require a TradingEnvironment, or its child AssetFinder, contain their own references to those objects. This commit also adds serialization utilities that allow for the pickling/unpickling of objects without unintentionally their TradingEnvironments or AssetFinders.
This commit is contained in:
+23
-18
@@ -10,18 +10,19 @@ from zipline.history.history import HistorySpec
|
||||
from zipline.protocol import BarData
|
||||
from zipline.utils.test_utils import to_utc
|
||||
|
||||
_cases_env = TradingEnvironment()
|
||||
|
||||
|
||||
def mixed_frequency_expected_index(count, frequency):
|
||||
"""
|
||||
Helper for enumerating expected indices for test_mixed_frequency.
|
||||
"""
|
||||
env = TradingEnvironment.instance()
|
||||
minute = MIXED_FREQUENCY_MINUTES[count]
|
||||
|
||||
if frequency == '1d':
|
||||
return [env.previous_open_and_close(minute)[1], minute]
|
||||
return [_cases_env.previous_open_and_close(minute)[1], minute]
|
||||
elif frequency == '1m':
|
||||
return [env.previous_market_minute(minute), minute]
|
||||
return [_cases_env.previous_market_minute(minute), minute]
|
||||
|
||||
|
||||
def mixed_frequency_expected_data(count, frequency):
|
||||
@@ -41,32 +42,36 @@ def mixed_frequency_expected_data(count, frequency):
|
||||
return [count - 1, count]
|
||||
|
||||
|
||||
MIXED_FREQUENCY_MINUTES = TradingEnvironment.instance().market_minute_window(
|
||||
MIXED_FREQUENCY_MINUTES = _cases_env.market_minute_window(
|
||||
to_utc('2013-07-03 9:31AM'), 600,
|
||||
)
|
||||
ONE_MINUTE_PRICE_ONLY_SPECS = [
|
||||
HistorySpec(1, '1m', 'price', True, data_frequency='minute'),
|
||||
HistorySpec(1, '1m', 'price', True, _cases_env, data_frequency='minute'),
|
||||
]
|
||||
DAILY_OPEN_CLOSE_SPECS = [
|
||||
HistorySpec(3, '1d', 'open_price', False, data_frequency='minute'),
|
||||
HistorySpec(3, '1d', 'close_price', False, data_frequency='minute'),
|
||||
HistorySpec(3, '1d', 'open_price', False, _cases_env,
|
||||
data_frequency='minute'),
|
||||
HistorySpec(3, '1d', 'close_price', False, _cases_env,
|
||||
data_frequency='minute'),
|
||||
]
|
||||
ILLIQUID_PRICES_SPECS = [
|
||||
HistorySpec(3, '1m', 'price', False, data_frequency='minute'),
|
||||
HistorySpec(5, '1m', 'price', True, data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'price', False, _cases_env, data_frequency='minute'),
|
||||
HistorySpec(5, '1m', 'price', True, _cases_env, data_frequency='minute'),
|
||||
]
|
||||
MIXED_FREQUENCY_SPECS = [
|
||||
HistorySpec(1, '1m', 'price', False, data_frequency='minute'),
|
||||
HistorySpec(2, '1m', 'price', False, data_frequency='minute'),
|
||||
HistorySpec(2, '1d', 'price', False, data_frequency='minute'),
|
||||
HistorySpec(1, '1m', 'price', False, _cases_env, data_frequency='minute'),
|
||||
HistorySpec(2, '1m', 'price', False, _cases_env, data_frequency='minute'),
|
||||
HistorySpec(2, '1d', 'price', False, _cases_env, data_frequency='minute'),
|
||||
]
|
||||
MIXED_FIELDS_SPECS = [
|
||||
HistorySpec(3, '1m', 'price', True, data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'open_price', True, data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'close_price', True, data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'high', True, data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'low', True, data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'volume', True, data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'price', True, _cases_env, data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'open_price', True, _cases_env,
|
||||
data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'close_price', True, _cases_env,
|
||||
data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'high', True, _cases_env, data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'low', True, _cases_env, data_frequency='minute'),
|
||||
HistorySpec(3, '1m', 'volume', True, _cases_env, data_frequency='minute'),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -96,13 +96,16 @@ TEST_QUERY_ASSETS = EQUITY_INFO.index
|
||||
|
||||
class BcolzDailyBarTestCase(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
all_trading_days = TradingEnvironment.instance().trading_days
|
||||
self.trading_days = all_trading_days[
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
all_trading_days = TradingEnvironment().trading_days
|
||||
cls.trading_days = all_trading_days[
|
||||
all_trading_days.get_loc(TEST_CALENDAR_START):
|
||||
all_trading_days.get_loc(TEST_CALENDAR_STOP) + 1
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
|
||||
self.asset_info = EQUITY_INFO
|
||||
self.writer = SyntheticDailyBarWriter(
|
||||
self.asset_info,
|
||||
@@ -401,7 +404,7 @@ class USEquityPricingLoaderTestCase(TestCase):
|
||||
writer.write(SPLITS, MERGERS, DIVIDENDS)
|
||||
|
||||
cls.assets = TEST_QUERY_ASSETS
|
||||
all_days = TradingEnvironment.instance().trading_days
|
||||
all_days = TradingEnvironment().trading_days
|
||||
cls.calendar_days = all_days[
|
||||
all_days.slice_indexer(TEST_CALENDAR_START, TEST_CALENDAR_STOP)
|
||||
]
|
||||
|
||||
@@ -21,7 +21,7 @@ import pytz
|
||||
import zipline.finance.risk as risk
|
||||
from zipline.utils import factory
|
||||
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
from zipline.finance.trading import SimulationParameters, TradingEnvironment
|
||||
|
||||
from . import answer_key
|
||||
ANSWER_KEY = answer_key.ANSWER_KEY
|
||||
@@ -29,6 +29,10 @@ ANSWER_KEY = answer_key.ANSWER_KEY
|
||||
|
||||
class TestRisk(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
|
||||
def setUp(self):
|
||||
start_date = datetime.datetime(
|
||||
year=2006,
|
||||
@@ -42,7 +46,8 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
self.sim_params = SimulationParameters(
|
||||
period_start=start_date,
|
||||
period_end=end_date
|
||||
period_end=end_date,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
self.algo_returns_06 = factory.create_returns_from_list(
|
||||
@@ -51,7 +56,8 @@ class TestRisk(unittest.TestCase):
|
||||
)
|
||||
|
||||
self.cumulative_metrics_06 = risk.RiskMetricsCumulative(
|
||||
self.sim_params)
|
||||
self.sim_params, env=self.env
|
||||
)
|
||||
|
||||
for dt, returns in answer_key.RETURNS_DATA.iterrows():
|
||||
self.cumulative_metrics_06.update(dt,
|
||||
|
||||
@@ -21,7 +21,7 @@ import pytz
|
||||
import zipline.finance.risk as risk
|
||||
from zipline.utils import factory
|
||||
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
from zipline.finance.trading import SimulationParameters, TradingEnvironment
|
||||
|
||||
from . import answer_key
|
||||
from . answer_key import AnswerKey
|
||||
@@ -33,6 +33,10 @@ RETURNS = ANSWER_KEY.RETURNS
|
||||
|
||||
class TestRisk(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
|
||||
def setUp(self):
|
||||
|
||||
start_date = datetime.datetime(
|
||||
@@ -47,7 +51,8 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
self.sim_params = SimulationParameters(
|
||||
period_start=start_date,
|
||||
period_end=end_date
|
||||
period_end=end_date,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
self.algo_returns_06 = factory.create_returns_from_list(
|
||||
@@ -61,7 +66,8 @@ class TestRisk(unittest.TestCase):
|
||||
self.metrics_06 = risk.RiskReport(
|
||||
self.algo_returns_06,
|
||||
self.sim_params,
|
||||
benchmark_returns=self.benchmark_returns_06
|
||||
benchmark_returns=self.benchmark_returns_06,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
start_08 = datetime.datetime(
|
||||
@@ -80,7 +86,8 @@ class TestRisk(unittest.TestCase):
|
||||
)
|
||||
self.sim_params08 = SimulationParameters(
|
||||
period_start=start_08,
|
||||
period_end=end_08
|
||||
period_end=end_08,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
@@ -97,9 +104,13 @@ class TestRisk(unittest.TestCase):
|
||||
returns = factory.create_returns_from_list(
|
||||
[1.0, -0.5, 0.8, .17, 1.0, -0.1, -0.45], self.sim_params)
|
||||
# 200, 100, 180, 210.6, 421.2, 379.8, 208.494
|
||||
metrics = risk.RiskMetricsPeriod(returns.index[0],
|
||||
returns.index[-1],
|
||||
returns)
|
||||
metrics = risk.RiskMetricsPeriod(
|
||||
returns.index[0],
|
||||
returns.index[-1],
|
||||
returns,
|
||||
env=self.env,
|
||||
benchmark_returns=self.env.benchmark_returns,
|
||||
)
|
||||
self.assertEqual(metrics.max_drawdown, 0.505)
|
||||
|
||||
def test_benchmark_returns_06(self):
|
||||
@@ -123,7 +134,7 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
def test_trading_days_06(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params, env=self.env)
|
||||
self.assertEqual([x.num_trading_days for x in metrics.year_periods],
|
||||
[251])
|
||||
self.assertEqual([x.num_trading_days for x in metrics.month_periods],
|
||||
@@ -347,7 +358,7 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
def test_benchmark_returns_08(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08, env=self.env)
|
||||
|
||||
self.assertEqual([round(x.benchmark_period_returns, 3)
|
||||
for x in metrics.month_periods],
|
||||
@@ -393,7 +404,7 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
def test_trading_days_08(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08, env=self.env)
|
||||
self.assertEqual([x.num_trading_days for x in metrics.year_periods],
|
||||
[253])
|
||||
|
||||
@@ -402,7 +413,7 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
def test_benchmark_volatility_08(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08)
|
||||
metrics = risk.RiskReport(returns, self.sim_params08, env=self.env)
|
||||
|
||||
self.assertEqual([round(x.benchmark_volatility, 3)
|
||||
for x in metrics.month_periods],
|
||||
@@ -450,7 +461,7 @@ class TestRisk(unittest.TestCase):
|
||||
|
||||
def test_treasury_returns_06(self):
|
||||
returns = factory.create_returns_from_range(self.sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params, env=self.env)
|
||||
self.assertEqual([round(x.treasury_period_return, 4)
|
||||
for x in metrics.month_periods],
|
||||
[0.0037,
|
||||
@@ -513,22 +524,24 @@ class TestRisk(unittest.TestCase):
|
||||
end = start + datetime.timedelta(days=total_days)
|
||||
sim_params90s = SimulationParameters(
|
||||
period_start=start,
|
||||
period_end=end
|
||||
period_end=end,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
returns = factory.create_returns_from_range(sim_params90s)
|
||||
returns = returns[:-10] # truncate the returns series to end mid-month
|
||||
metrics = risk.RiskReport(returns, sim_params90s)
|
||||
metrics = risk.RiskReport(returns, sim_params90s, env=self.env)
|
||||
total_months = 60
|
||||
self.check_metrics(metrics, total_months, start)
|
||||
|
||||
def check_year_range(self, start_date, years):
|
||||
sim_params = SimulationParameters(
|
||||
period_start=start_date,
|
||||
period_end=start_date.replace(year=(start_date.year + years))
|
||||
period_end=start_date.replace(year=(start_date.year + years)),
|
||||
env=self.env,
|
||||
)
|
||||
returns = factory.create_returns_from_range(sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params)
|
||||
metrics = risk.RiskReport(returns, self.sim_params, env=self.env)
|
||||
total_months = years * 12
|
||||
self.check_metrics(metrics, total_months, start_date)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ from zipline.protocol import Account
|
||||
from zipline.protocol import Portfolio
|
||||
from zipline.protocol import Position as ProtocolPosition
|
||||
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
from zipline.finance.trading import SimulationParameters, TradingEnvironment
|
||||
|
||||
from zipline.utils import factory
|
||||
|
||||
@@ -41,17 +41,19 @@ def stringify_cases(cases, func=None):
|
||||
results.append(new_case)
|
||||
return results
|
||||
|
||||
|
||||
cases_env = TradingEnvironment()
|
||||
sim_params_daily = SimulationParameters(
|
||||
datetime.datetime(2013, 6, 19, tzinfo=pytz.UTC),
|
||||
datetime.datetime(2013, 6, 19, tzinfo=pytz.UTC),
|
||||
10000,
|
||||
emission_rate='daily')
|
||||
emission_rate='daily',
|
||||
env=cases_env)
|
||||
sim_params_minute = SimulationParameters(
|
||||
datetime.datetime(2013, 6, 19, tzinfo=pytz.UTC),
|
||||
datetime.datetime(2013, 6, 19, tzinfo=pytz.UTC),
|
||||
10000,
|
||||
emission_rate='minute')
|
||||
emission_rate='minute',
|
||||
env=cases_env)
|
||||
returns = factory.create_returns_from_list(
|
||||
[1.0], sim_params_daily)
|
||||
|
||||
@@ -65,14 +67,17 @@ def object_serialization_cases(skip_daily=False):
|
||||
(PerTrade, (), {}, 'dict'),
|
||||
(PerDollar, (), {}, 'dict'),
|
||||
(PerformancePeriod,
|
||||
(10000,), {'position_tracker': PositionTracker()}, 'to_dict'),
|
||||
(10000, cases_env.asset_finder),
|
||||
{'position_tracker': PositionTracker(cases_env.asset_finder)},
|
||||
'to_dict'),
|
||||
(Position, (8554,), {}, 'dict'),
|
||||
(PositionTracker, (), {}, 'dict'),
|
||||
(PerformanceTracker, (sim_params_minute,), {}, 'to_dict'),
|
||||
(RiskMetricsCumulative, (sim_params_minute,), {}, 'to_dict'),
|
||||
(PositionTracker, (cases_env.asset_finder,), {}, 'dict'),
|
||||
(PerformanceTracker, (sim_params_minute, cases_env), {}, 'to_dict'),
|
||||
(RiskMetricsCumulative, (sim_params_minute, cases_env), {}, 'to_dict'),
|
||||
(RiskMetricsPeriod,
|
||||
(returns.index[0], returns.index[0], returns), {}, 'to_dict'),
|
||||
(RiskReport, (returns, sim_params_minute), {}, 'to_dict'),
|
||||
(returns.index[0], returns.index[0], returns, cases_env),
|
||||
{}, 'to_dict'),
|
||||
(RiskReport, (returns, sim_params_minute, cases_env), {}, 'to_dict'),
|
||||
(FixedSlippage, (), {}, 'dict'),
|
||||
(Transaction,
|
||||
(8554, 10, datetime.datetime(2013, 6, 19), 100, "0000"), {},
|
||||
@@ -85,9 +90,12 @@ def object_serialization_cases(skip_daily=False):
|
||||
|
||||
if not skip_daily:
|
||||
cases.extend([
|
||||
(PerformanceTracker, (sim_params_daily,), {}, 'to_dict'),
|
||||
(RiskMetricsCumulative, (sim_params_daily,), {}, 'to_dict'),
|
||||
(RiskReport, (returns, sim_params_daily), {}, 'to_dict'),
|
||||
(PerformanceTracker,
|
||||
(sim_params_daily, cases_env), {}, 'to_dict'),
|
||||
(RiskMetricsCumulative,
|
||||
(sim_params_daily, cases_env), {}, 'to_dict'),
|
||||
(RiskReport,
|
||||
(returns, sim_params_daily, cases_env), {}, 'to_dict'),
|
||||
])
|
||||
|
||||
return stringify_cases(cases)
|
||||
|
||||
+293
-158
File diff suppressed because it is too large
Load Diff
+16
-16
@@ -135,18 +135,17 @@ class AlgorithmGeneratorTestCase(TestCase):
|
||||
Ensure the pipeline of generators are in sync, at least as far as
|
||||
their current dates.
|
||||
"""
|
||||
# Ensure we are pointing to the TradingEnvironment for this class
|
||||
trading.environment = AlgorithmGeneratorTestCase.env
|
||||
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=datetime(2011, 7, 30, tzinfo=pytz.utc),
|
||||
end=datetime(2012, 7, 30, tzinfo=pytz.utc)
|
||||
end=datetime(2012, 7, 30, tzinfo=pytz.utc),
|
||||
env=self.env,
|
||||
)
|
||||
algo = TestAlgo(self, sim_params=sim_params,
|
||||
env=AlgorithmGeneratorTestCase.env)
|
||||
algo = TestAlgo(self, sim_params=sim_params, env=self.env)
|
||||
trade_source = factory.create_daily_trade_source(
|
||||
[8229],
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env,
|
||||
)
|
||||
algo.set_sources([trade_source])
|
||||
|
||||
@@ -168,10 +167,10 @@ class AlgorithmGeneratorTestCase(TestCase):
|
||||
sim_params = SimulationParameters(
|
||||
period_start=datetime(2012, 7, 30, tzinfo=pytz.utc),
|
||||
period_end=datetime(2012, 7, 30, tzinfo=pytz.utc),
|
||||
data_frequency='minute'
|
||||
data_frequency='minute',
|
||||
env=self.env,
|
||||
)
|
||||
algo = TestAlgo(self, sim_params=sim_params,
|
||||
env=AlgorithmGeneratorTestCase.env)
|
||||
algo = TestAlgo(self, sim_params=sim_params, env=self.env)
|
||||
|
||||
midnight_custom_source = [Event({
|
||||
'custom_field': 42.0,
|
||||
@@ -214,13 +213,14 @@ class AlgorithmGeneratorTestCase(TestCase):
|
||||
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=datetime(2008, 1, 1, tzinfo=pytz.utc),
|
||||
end=datetime(2008, 1, 5, tzinfo=pytz.utc)
|
||||
end=datetime(2008, 1, 5, tzinfo=pytz.utc),
|
||||
env=self.env,
|
||||
)
|
||||
algo = TestAlgo(self, sim_params=sim_params,
|
||||
env=AlgorithmGeneratorTestCase.env)
|
||||
algo = TestAlgo(self, sim_params=sim_params, env=self.env)
|
||||
trade_source = factory.create_daily_trade_source(
|
||||
[8229],
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env,
|
||||
)
|
||||
algo.set_sources([trade_source])
|
||||
|
||||
@@ -238,8 +238,8 @@ class AlgorithmGeneratorTestCase(TestCase):
|
||||
See https://github.com/quantopian/zipline/issues/241
|
||||
"""
|
||||
sim_params = create_simulation_parameters(num_days=1,
|
||||
data_frequency='minute')
|
||||
algo = TestAlgo(self, sim_params=sim_params,
|
||||
env=AlgorithmGeneratorTestCase.env)
|
||||
data_frequency='minute',
|
||||
env=self.env)
|
||||
algo = TestAlgo(self, sim_params=sim_params, env=self.env)
|
||||
algo.run(source=[], overwrite_sim_params=False)
|
||||
self.assertEqual(algo.datetime, sim_params.last_close)
|
||||
|
||||
+38
-38
@@ -40,8 +40,7 @@ from zipline.errors import (
|
||||
SidAssignmentError,
|
||||
RootSymbolNotFound,
|
||||
)
|
||||
from zipline.finance import trading
|
||||
from zipline.finance.trading import with_environment
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
from zipline.utils.test_utils import (
|
||||
all_subindices,
|
||||
make_rotating_asset_info,
|
||||
@@ -87,9 +86,9 @@ def build_lookup_generic_cases():
|
||||
},
|
||||
],
|
||||
index='sid')
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
trading.environment.write_data(equities_df=frame)
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
env = TradingEnvironment()
|
||||
env.write_data(equities_df=frame)
|
||||
finder = env.asset_finder
|
||||
dupe_0, dupe_1, unique = assets = [
|
||||
finder.retrieve_asset(i)
|
||||
for i in range(3)
|
||||
@@ -281,7 +280,7 @@ class TestFuture(TestCase):
|
||||
class AssetFinderTestCase(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
self.env = TradingEnvironment()
|
||||
|
||||
def test_lookup_symbol_fuzzy(self):
|
||||
as_of = pd.Timestamp('2013-01-01', tz='UTC')
|
||||
@@ -299,8 +298,8 @@ class AssetFinderTestCase(TestCase):
|
||||
for i in range(3)
|
||||
]
|
||||
)
|
||||
trading.environment.write_data(equities_df=frame)
|
||||
finder = AssetFinder(trading.environment.engine, fuzzy_char='@')
|
||||
self.env.write_data(equities_df=frame)
|
||||
finder = AssetFinder(self.env.engine, fuzzy_char='@')
|
||||
asset_0, asset_1, asset_2 = (
|
||||
finder.retrieve_asset(i) for i in range(3)
|
||||
)
|
||||
@@ -344,8 +343,8 @@ class AssetFinderTestCase(TestCase):
|
||||
for i, date in enumerate(dates)
|
||||
]
|
||||
)
|
||||
trading.environment.write_data(equities_df=df)
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
self.env.write_data(equities_df=df)
|
||||
finder = AssetFinder(self.env.engine)
|
||||
for _ in range(2): # Run checks twice to test for caching bugs.
|
||||
with self.assertRaises(SymbolNotFound):
|
||||
finder.lookup_symbol_resolve_multiple('non_existing', dates[0])
|
||||
@@ -411,8 +410,8 @@ class AssetFinderTestCase(TestCase):
|
||||
},
|
||||
]
|
||||
)
|
||||
trading.environment.write_data(equities_df=data)
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
self.env.write_data(equities_df=data)
|
||||
finder = AssetFinder(self.env.engine)
|
||||
results, missing = finder.lookup_generic(
|
||||
['real', 1, 'fake', 'real_but_old', 'real_but_in_the_future'],
|
||||
pd.Timestamp('2013-02-01', tz='UTC'),
|
||||
@@ -436,8 +435,8 @@ class AssetFinderTestCase(TestCase):
|
||||
'end_date': '2015-01-01',
|
||||
'symbol': "PLAY",
|
||||
'foo_data': "FOO"}}
|
||||
trading.environment.write_data(equities_data=data)
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
self.env.write_data(equities_data=data)
|
||||
finder = AssetFinder(self.env.engine)
|
||||
# Test proper insertion
|
||||
equity = finder.retrieve_asset(0)
|
||||
self.assertIsInstance(equity, Equity)
|
||||
@@ -454,8 +453,8 @@ class AssetFinderTestCase(TestCase):
|
||||
# Test dict consumption
|
||||
dict_to_consume = {0: {'symbol': 'PLAY'},
|
||||
1: {'symbol': 'MSFT'}}
|
||||
trading.environment.write_data(equities_data=dict_to_consume)
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
self.env.write_data(equities_data=dict_to_consume)
|
||||
finder = AssetFinder(self.env.engine)
|
||||
|
||||
equity = finder.retrieve_asset(0)
|
||||
self.assertIsInstance(equity, Equity)
|
||||
@@ -467,9 +466,9 @@ class AssetFinderTestCase(TestCase):
|
||||
df['exchange'][0] = "NASDAQ"
|
||||
df['asset_name'][1] = "Microsoft"
|
||||
df['exchange'][1] = "NYSE"
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
trading.environment.write_data(equities_df=df)
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
self.env = TradingEnvironment()
|
||||
self.env.write_data(equities_df=df)
|
||||
finder = AssetFinder(self.env.engine)
|
||||
self.assertEqual('NASDAQ', finder.retrieve_asset(0).exchange)
|
||||
self.assertEqual('Microsoft', finder.retrieve_asset(1).asset_name)
|
||||
|
||||
@@ -483,9 +482,9 @@ class AssetFinderTestCase(TestCase):
|
||||
future_asset = Future(200, symbol="TESTFUT", end_date=fut_end)
|
||||
|
||||
# Consume the Assets
|
||||
trading.environment.write_data(equities_identifiers=[equity_asset],
|
||||
futures_identifiers=[future_asset])
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
self.env.write_data(equities_identifiers=[equity_asset],
|
||||
futures_identifiers=[future_asset])
|
||||
finder = AssetFinder(self.env.engine)
|
||||
|
||||
# Test equality with newly built Assets
|
||||
self.assertEqual(equity_asset, finder.retrieve_asset(1))
|
||||
@@ -501,11 +500,11 @@ class AssetFinderTestCase(TestCase):
|
||||
today = normalize_date(pd.Timestamp('2015-07-09', tz='UTC'))
|
||||
|
||||
# Write data with sid assignment
|
||||
trading.environment.write_data(equities_identifiers=metadata,
|
||||
allow_sid_assignment=True)
|
||||
self.env.write_data(equities_identifiers=metadata,
|
||||
allow_sid_assignment=True)
|
||||
|
||||
# Verify that Assets were built and different sids were assigned
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
finder = AssetFinder(self.env.engine)
|
||||
play = finder.lookup_symbol('PLAY', today)
|
||||
msft = finder.lookup_symbol('MSFT', today)
|
||||
self.assertEqual('PLAY', play.symbol)
|
||||
@@ -519,8 +518,8 @@ class AssetFinderTestCase(TestCase):
|
||||
|
||||
# Write data without sid assignment, asserting failure
|
||||
with self.assertRaises(SidAssignmentError):
|
||||
trading.environment.write_data(equities_identifiers=metadata,
|
||||
allow_sid_assignment=False)
|
||||
self.env.write_data(equities_identifiers=metadata,
|
||||
allow_sid_assignment=False)
|
||||
|
||||
def test_security_dates_warning(self):
|
||||
|
||||
@@ -577,8 +576,8 @@ class AssetFinderTestCase(TestCase):
|
||||
},
|
||||
|
||||
}
|
||||
trading.environment.write_data(futures_data=metadata)
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
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')
|
||||
@@ -609,7 +608,7 @@ class AssetFinderTestCase(TestCase):
|
||||
def test_map_identifier_index_to_sids(self):
|
||||
# Build an empty finder and some Assets
|
||||
dt = pd.Timestamp('2014-01-01', tz='UTC')
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
finder = AssetFinder(self.env.engine)
|
||||
asset1 = Equity(1, symbol="AAPL")
|
||||
asset2 = Equity(2, symbol="GOOG")
|
||||
asset200 = Future(200, symbol="CLK15")
|
||||
@@ -627,9 +626,9 @@ class AssetFinderTestCase(TestCase):
|
||||
post_map = finder.map_identifier_index_to_sids(pre_map, dt)
|
||||
self.assertListEqual([201, 2, 200, 1], post_map)
|
||||
|
||||
@with_environment()
|
||||
def test_compute_lifetimes(self, env=None):
|
||||
def test_compute_lifetimes(self):
|
||||
num_assets = 4
|
||||
env = TradingEnvironment()
|
||||
trading_day = env.trading_day
|
||||
first_start = pd.Timestamp('2015-04-01', tz='UTC')
|
||||
|
||||
@@ -641,8 +640,8 @@ class AssetFinderTestCase(TestCase):
|
||||
asset_lifetime=5
|
||||
)
|
||||
|
||||
trading.environment.write_data(equities_df=frame)
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
env.write_data(equities_df=frame)
|
||||
finder = env.asset_finder
|
||||
|
||||
all_dates = pd.date_range(
|
||||
start=first_start,
|
||||
@@ -676,7 +675,8 @@ class AssetFinderTestCase(TestCase):
|
||||
|
||||
class TestFutureChain(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
metadata = {
|
||||
0: {
|
||||
'symbol': 'CLG06',
|
||||
@@ -708,9 +708,9 @@ class TestFutureChain(TestCase):
|
||||
'expiration_date': pd.Timestamp('2006-10-20', tz='UTC')}
|
||||
}
|
||||
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
trading.environment.write_data(futures_data=metadata)
|
||||
self.asset_finder = AssetFinder(trading.environment.engine)
|
||||
env = TradingEnvironment()
|
||||
env.write_data(futures_data=metadata)
|
||||
cls.asset_finder = env.asset_finder
|
||||
|
||||
def test_len(self):
|
||||
""" Test the __len__ method of FutureChain.
|
||||
|
||||
@@ -30,10 +30,9 @@ import zipline.utils.factory as factory
|
||||
from zipline.transforms import batch_transform
|
||||
|
||||
from zipline.test_algorithms import (BatchTransformAlgorithm,
|
||||
BatchTransformAlgorithmMinute,
|
||||
ReturnPriceBatchTransform)
|
||||
BatchTransformAlgorithmMinute)
|
||||
|
||||
from zipline.finance import trading
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
from zipline.algorithm import TradingAlgorithm
|
||||
from zipline.utils.tradingcalendar import trading_days
|
||||
from copy import deepcopy
|
||||
@@ -107,16 +106,19 @@ class DifferentSidSource(DataSource):
|
||||
class TestChangeOfSids(TestCase):
|
||||
def setUp(self):
|
||||
self.sids = range(90)
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
trading.environment.write_data(equities_identifiers=self.sids)
|
||||
self.env = TradingEnvironment()
|
||||
self.env.write_data(equities_identifiers=self.sids)
|
||||
|
||||
self.sim_params = factory.create_simulation_parameters(
|
||||
start=datetime(1990, 1, 1, tzinfo=pytz.utc),
|
||||
end=datetime(1990, 1, 8, tzinfo=pytz.utc)
|
||||
end=datetime(1990, 1, 8, tzinfo=pytz.utc),
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
def test_all_sids_passed(self):
|
||||
algo = BatchTransformAlgorithmSetSid(
|
||||
sim_params=self.sim_params,
|
||||
env=self.env,
|
||||
)
|
||||
source = DifferentSidSource()
|
||||
algo.run(source)
|
||||
@@ -131,26 +133,32 @@ class TestChangeOfSids(TestCase):
|
||||
|
||||
|
||||
class TestBatchTransformMinutely(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
cls.env.write_data(equities_identifiers=[0])
|
||||
|
||||
def setUp(self):
|
||||
setup_logger(self)
|
||||
start = pd.datetime(1990, 1, 3, 0, 0, 0, 0, pytz.utc)
|
||||
end = pd.datetime(1990, 1, 8, 0, 0, 0, 0, pytz.utc)
|
||||
self.sim_params = factory.create_simulation_parameters(
|
||||
start=start,
|
||||
end=end,
|
||||
start=start, end=end, env=self.env,
|
||||
)
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
trading.environment.write_data(equities_identifiers=[0])
|
||||
self.sim_params.emission_rate = 'daily'
|
||||
self.sim_params.data_frequency = 'minute'
|
||||
self.source, self.df = \
|
||||
factory.create_test_df_source(bars='minute')
|
||||
factory.create_test_df_source(sim_params=self.sim_params,
|
||||
env=self.env,
|
||||
bars='minute')
|
||||
|
||||
def tearDown(self):
|
||||
teardown_logger(self)
|
||||
|
||||
def test_core(self):
|
||||
algo = BatchTransformAlgorithmMinute(sim_params=self.sim_params)
|
||||
algo = BatchTransformAlgorithmMinute(sim_params=self.sim_params,
|
||||
env=self.env)
|
||||
algo.run(self.source)
|
||||
wl = int(algo.window_length * 6.5 * 60)
|
||||
for bt in algo.history[wl:]:
|
||||
@@ -158,7 +166,9 @@ class TestBatchTransformMinutely(TestCase):
|
||||
|
||||
def test_window_length(self):
|
||||
algo = BatchTransformAlgorithmMinute(sim_params=self.sim_params,
|
||||
window_length=1, refresh_period=0)
|
||||
env=self.env,
|
||||
window_length=1,
|
||||
refresh_period=0)
|
||||
algo.run(self.source)
|
||||
wl = int(algo.window_length * 6.5 * 60)
|
||||
np.testing.assert_array_equal(algo.history[:(wl - 1)],
|
||||
@@ -171,24 +181,25 @@ class TestBatchTransform(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = trading.TradingEnvironment()
|
||||
cls.env = TradingEnvironment()
|
||||
cls.env.write_data(equities_identifiers=[0])
|
||||
|
||||
def setUp(self):
|
||||
setup_logger(self)
|
||||
self.sim_params = factory.create_simulation_parameters(
|
||||
start=datetime(1990, 1, 1, tzinfo=pytz.utc),
|
||||
end=datetime(1990, 1, 8, tzinfo=pytz.utc)
|
||||
end=datetime(1990, 1, 8, tzinfo=pytz.utc),
|
||||
env=self.env
|
||||
)
|
||||
trading.environment = TestBatchTransform.env
|
||||
self.source, self.df = \
|
||||
factory.create_test_df_source(self.sim_params)
|
||||
factory.create_test_df_source(self.sim_params, self.env)
|
||||
|
||||
def tearDown(self):
|
||||
teardown_logger(self)
|
||||
|
||||
def test_core_functionality(self):
|
||||
algo = BatchTransformAlgorithm(sim_params=self.sim_params)
|
||||
algo = BatchTransformAlgorithm(sim_params=self.sim_params,
|
||||
env=self.env)
|
||||
algo.run(self.source)
|
||||
wl = algo.window_length
|
||||
# The following assertion depend on window length of 3
|
||||
@@ -257,7 +268,8 @@ class TestBatchTransform(TestCase):
|
||||
|
||||
def test_passing_of_args(self):
|
||||
algo = BatchTransformAlgorithm(1, kwarg='str',
|
||||
sim_params=self.sim_params)
|
||||
sim_params=self.sim_params,
|
||||
env=self.env)
|
||||
algo.run(self.source)
|
||||
self.assertEqual(algo.args, (1,))
|
||||
self.assertEqual(algo.kwargs, {'kwarg': 'str'})
|
||||
@@ -278,22 +290,3 @@ class TestBatchTransform(TestCase):
|
||||
# 1990-01-08 - window now full
|
||||
expected_item
|
||||
])
|
||||
|
||||
|
||||
def run_batchtransform(window_length=10):
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=datetime(1990, 1, 1, tzinfo=pytz.utc),
|
||||
end=datetime(1995, 1, 8, tzinfo=pytz.utc)
|
||||
)
|
||||
source, df = factory.create_test_df_source(sim_params)
|
||||
|
||||
return_price_class = ReturnPriceBatchTransform(
|
||||
refresh_period=1,
|
||||
window_length=window_length,
|
||||
clean_nans=False
|
||||
)
|
||||
|
||||
for raw_event in source:
|
||||
raw_event['datetime'] = raw_event.dt
|
||||
event = {0: raw_event}
|
||||
return_price_class.handle_data(event)
|
||||
|
||||
+159
-161
@@ -19,8 +19,7 @@ import pytz
|
||||
|
||||
import numpy as np
|
||||
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
from zipline.finance import trading
|
||||
from zipline.finance.trading import SimulationParameters, TradingEnvironment
|
||||
from zipline.algorithm import TradingAlgorithm
|
||||
from zipline.protocol import (
|
||||
Event,
|
||||
@@ -43,10 +42,12 @@ class BuyAndHoldAlgorithm(TradingAlgorithm):
|
||||
|
||||
class TestEventsThroughRisk(unittest.TestCase):
|
||||
|
||||
def test_daily_buy_and_hold(self):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
cls.env.write_data(equities_identifiers=[1])
|
||||
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
trading.environment.write_data(equities_identifiers=[1])
|
||||
def test_daily_buy_and_hold(self):
|
||||
|
||||
start_date = datetime.datetime(
|
||||
year=2006,
|
||||
@@ -70,8 +71,7 @@ class TestEventsThroughRisk(unittest.TestCase):
|
||||
emission_rate='daily'
|
||||
)
|
||||
|
||||
algo = BuyAndHoldAlgorithm(
|
||||
sim_params=sim_params)
|
||||
algo = BuyAndHoldAlgorithm(sim_params=sim_params, env=self.env)
|
||||
|
||||
first_date = datetime.datetime(2006, 1, 3, tzinfo=pytz.utc)
|
||||
second_date = datetime.datetime(2006, 1, 4, tzinfo=pytz.utc)
|
||||
@@ -169,178 +169,176 @@ class TestEventsThroughRisk(unittest.TestCase):
|
||||
err_msg="Mismatch at %s" % (current_dt,))
|
||||
|
||||
def test_minute_buy_and_hold(self):
|
||||
with trading.TradingEnvironment():
|
||||
start_date = datetime.datetime(
|
||||
year=2006,
|
||||
month=1,
|
||||
day=3,
|
||||
hour=0,
|
||||
minute=0,
|
||||
tzinfo=pytz.utc)
|
||||
end_date = datetime.datetime(
|
||||
year=2006,
|
||||
month=1,
|
||||
day=5,
|
||||
hour=0,
|
||||
minute=0,
|
||||
tzinfo=pytz.utc)
|
||||
|
||||
sim_params = SimulationParameters(
|
||||
period_start=start_date,
|
||||
period_end=end_date,
|
||||
emission_rate='daily',
|
||||
data_frequency='minute')
|
||||
start_date = datetime.datetime(
|
||||
year=2006,
|
||||
month=1,
|
||||
day=3,
|
||||
hour=0,
|
||||
minute=0,
|
||||
tzinfo=pytz.utc)
|
||||
end_date = datetime.datetime(
|
||||
year=2006,
|
||||
month=1,
|
||||
day=5,
|
||||
hour=0,
|
||||
minute=0,
|
||||
tzinfo=pytz.utc)
|
||||
|
||||
algo = BuyAndHoldAlgorithm(
|
||||
identifiers=[1],
|
||||
sim_params=sim_params)
|
||||
sim_params = SimulationParameters(
|
||||
period_start=start_date,
|
||||
period_end=end_date,
|
||||
emission_rate='daily',
|
||||
data_frequency='minute',
|
||||
env=self.env)
|
||||
|
||||
first_date = datetime.datetime(2006, 1, 3, tzinfo=pytz.utc)
|
||||
first_open, first_close = \
|
||||
trading.environment.get_open_and_close(first_date)
|
||||
algo = BuyAndHoldAlgorithm(
|
||||
sim_params=sim_params,
|
||||
env=self.env)
|
||||
|
||||
second_date = datetime.datetime(2006, 1, 4, tzinfo=pytz.utc)
|
||||
second_open, second_close = \
|
||||
trading.environment.get_open_and_close(second_date)
|
||||
first_date = datetime.datetime(2006, 1, 3, tzinfo=pytz.utc)
|
||||
first_open, first_close = self.env.get_open_and_close(first_date)
|
||||
|
||||
third_date = datetime.datetime(2006, 1, 5, tzinfo=pytz.utc)
|
||||
third_open, third_close = \
|
||||
trading.environment.get_open_and_close(third_date)
|
||||
second_date = datetime.datetime(2006, 1, 4, tzinfo=pytz.utc)
|
||||
second_open, second_close = self.env.get_open_and_close(second_date)
|
||||
|
||||
benchmark_data = [
|
||||
Event({
|
||||
'returns': 0.1,
|
||||
'dt': first_close,
|
||||
'source_id': 'test-benchmark-source',
|
||||
'type': DATASOURCE_TYPE.BENCHMARK
|
||||
}),
|
||||
Event({
|
||||
'returns': 0.2,
|
||||
'dt': second_close,
|
||||
'source_id': 'test-benchmark-source',
|
||||
'type': DATASOURCE_TYPE.BENCHMARK
|
||||
}),
|
||||
Event({
|
||||
'returns': 0.4,
|
||||
'dt': third_close,
|
||||
'source_id': 'test-benchmark-source',
|
||||
'type': DATASOURCE_TYPE.BENCHMARK
|
||||
}),
|
||||
]
|
||||
third_date = datetime.datetime(2006, 1, 5, tzinfo=pytz.utc)
|
||||
third_open, third_close = self.env.get_open_and_close(third_date)
|
||||
|
||||
trade_bar_data = [
|
||||
Event({
|
||||
'open_price': 10,
|
||||
'close_price': 15,
|
||||
'price': 15,
|
||||
'volume': 1000,
|
||||
'sid': 1,
|
||||
'dt': first_open,
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
Event({
|
||||
'open_price': 10,
|
||||
'close_price': 15,
|
||||
'price': 15,
|
||||
'volume': 1000,
|
||||
'sid': 1,
|
||||
'dt': first_open + datetime.timedelta(minutes=10),
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
Event({
|
||||
'open_price': 15,
|
||||
'close_price': 20,
|
||||
'price': 20,
|
||||
'volume': 2000,
|
||||
'sid': 1,
|
||||
'dt': second_open,
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
Event({
|
||||
'open_price': 15,
|
||||
'close_price': 20,
|
||||
'price': 20,
|
||||
'volume': 2000,
|
||||
'sid': 1,
|
||||
'dt': second_open + datetime.timedelta(minutes=10),
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
Event({
|
||||
'open_price': 20,
|
||||
'close_price': 15,
|
||||
'price': 15,
|
||||
'volume': 1000,
|
||||
'sid': 1,
|
||||
'dt': third_open,
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
Event({
|
||||
'open_price': 20,
|
||||
'close_price': 15,
|
||||
'price': 15,
|
||||
'volume': 1000,
|
||||
'sid': 1,
|
||||
'dt': third_open + datetime.timedelta(minutes=10),
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
]
|
||||
benchmark_data = [
|
||||
Event({
|
||||
'returns': 0.1,
|
||||
'dt': first_close,
|
||||
'source_id': 'test-benchmark-source',
|
||||
'type': DATASOURCE_TYPE.BENCHMARK
|
||||
}),
|
||||
Event({
|
||||
'returns': 0.2,
|
||||
'dt': second_close,
|
||||
'source_id': 'test-benchmark-source',
|
||||
'type': DATASOURCE_TYPE.BENCHMARK
|
||||
}),
|
||||
Event({
|
||||
'returns': 0.4,
|
||||
'dt': third_close,
|
||||
'source_id': 'test-benchmark-source',
|
||||
'type': DATASOURCE_TYPE.BENCHMARK
|
||||
}),
|
||||
]
|
||||
|
||||
algo.benchmark_return_source = benchmark_data
|
||||
algo.set_sources(list([trade_bar_data]))
|
||||
gen = algo._create_generator(sim_params)
|
||||
trade_bar_data = [
|
||||
Event({
|
||||
'open_price': 10,
|
||||
'close_price': 15,
|
||||
'price': 15,
|
||||
'volume': 1000,
|
||||
'sid': 1,
|
||||
'dt': first_open,
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
Event({
|
||||
'open_price': 10,
|
||||
'close_price': 15,
|
||||
'price': 15,
|
||||
'volume': 1000,
|
||||
'sid': 1,
|
||||
'dt': first_open + datetime.timedelta(minutes=10),
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
Event({
|
||||
'open_price': 15,
|
||||
'close_price': 20,
|
||||
'price': 20,
|
||||
'volume': 2000,
|
||||
'sid': 1,
|
||||
'dt': second_open,
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
Event({
|
||||
'open_price': 15,
|
||||
'close_price': 20,
|
||||
'price': 20,
|
||||
'volume': 2000,
|
||||
'sid': 1,
|
||||
'dt': second_open + datetime.timedelta(minutes=10),
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
Event({
|
||||
'open_price': 20,
|
||||
'close_price': 15,
|
||||
'price': 15,
|
||||
'volume': 1000,
|
||||
'sid': 1,
|
||||
'dt': third_open,
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
Event({
|
||||
'open_price': 20,
|
||||
'close_price': 15,
|
||||
'price': 15,
|
||||
'volume': 1000,
|
||||
'sid': 1,
|
||||
'dt': third_open + datetime.timedelta(minutes=10),
|
||||
'source_id': 'test-trade-source',
|
||||
'type': DATASOURCE_TYPE.TRADE
|
||||
}),
|
||||
]
|
||||
|
||||
crm = algo.perf_tracker.cumulative_risk_metrics
|
||||
dt_loc = crm.cont_index.get_loc(algo.datetime)
|
||||
algo.benchmark_return_source = benchmark_data
|
||||
algo.set_sources(list([trade_bar_data]))
|
||||
gen = algo._create_generator(sim_params)
|
||||
|
||||
first_msg = next(gen)
|
||||
crm = algo.perf_tracker.cumulative_risk_metrics
|
||||
dt_loc = crm.cont_index.get_loc(algo.datetime)
|
||||
|
||||
self.assertIsNotNone(first_msg,
|
||||
"There should be a message emitted.")
|
||||
first_msg = next(gen)
|
||||
|
||||
# Protects against bug where the positions appeared to be
|
||||
# a day late, because benchmarks were triggering
|
||||
# calculations before the events for the day were
|
||||
# processed.
|
||||
self.assertEqual(1, len(algo.portfolio.positions), "There should "
|
||||
"be one position after the first day.")
|
||||
self.assertIsNotNone(first_msg,
|
||||
"There should be a message emitted.")
|
||||
|
||||
self.assertEquals(
|
||||
0,
|
||||
crm.algorithm_volatility[dt_loc],
|
||||
"On the first day algorithm volatility does not exist.")
|
||||
# Protects against bug where the positions appeared to be
|
||||
# a day late, because benchmarks were triggering
|
||||
# calculations before the events for the day were
|
||||
# processed.
|
||||
self.assertEqual(1, len(algo.portfolio.positions), "There should "
|
||||
"be one position after the first day.")
|
||||
|
||||
second_msg = next(gen)
|
||||
self.assertEquals(
|
||||
0,
|
||||
crm.algorithm_volatility[dt_loc],
|
||||
"On the first day algorithm volatility does not exist.")
|
||||
|
||||
self.assertIsNotNone(second_msg, "There should be a message "
|
||||
"emitted.")
|
||||
second_msg = next(gen)
|
||||
|
||||
self.assertEqual(1, len(algo.portfolio.positions),
|
||||
"Number of positions should stay the same.")
|
||||
self.assertIsNotNone(second_msg, "There should be a message "
|
||||
"emitted.")
|
||||
|
||||
# TODO: Hand derive. Current value is just a canary to
|
||||
# detect changes.
|
||||
np.testing.assert_almost_equal(
|
||||
0.050022510129558301,
|
||||
crm.algorithm_returns[-1],
|
||||
decimal=6)
|
||||
self.assertEqual(1, len(algo.portfolio.positions),
|
||||
"Number of positions should stay the same.")
|
||||
|
||||
third_msg = next(gen)
|
||||
# TODO: Hand derive. Current value is just a canary to
|
||||
# detect changes.
|
||||
np.testing.assert_almost_equal(
|
||||
0.050022510129558301,
|
||||
crm.algorithm_returns[-1],
|
||||
decimal=6)
|
||||
|
||||
self.assertEqual(1, len(algo.portfolio.positions),
|
||||
"Number of positions should stay the same.")
|
||||
third_msg = next(gen)
|
||||
|
||||
self.assertIsNotNone(third_msg, "There should be a message "
|
||||
"emitted.")
|
||||
self.assertEqual(1, len(algo.portfolio.positions),
|
||||
"Number of positions should stay the same.")
|
||||
|
||||
# TODO: Hand derive. Current value is just a canary to
|
||||
# detect changes.
|
||||
np.testing.assert_almost_equal(
|
||||
-0.047639464532418657,
|
||||
crm.algorithm_returns[-1],
|
||||
decimal=6)
|
||||
self.assertIsNotNone(third_msg, "There should be a message "
|
||||
"emitted.")
|
||||
|
||||
# TODO: Hand derive. Current value is just a canary to
|
||||
# detect changes.
|
||||
np.testing.assert_almost_equal(
|
||||
-0.047639464532418657,
|
||||
crm.algorithm_returns[-1],
|
||||
decimal=6)
|
||||
|
||||
@@ -31,8 +31,6 @@ from zipline.utils import parse_args, run_pipeline
|
||||
# Otherwise the next line sometimes complains about being run too late.
|
||||
_multiprocess_can_split_ = False
|
||||
|
||||
from zipline.finance import trading
|
||||
|
||||
matplotlib.use('Agg')
|
||||
|
||||
|
||||
@@ -47,8 +45,6 @@ class ExamplesTests(TestCase):
|
||||
@parameterized.expand(((os.path.basename(f).replace('.', '_'), f) for f in
|
||||
glob.glob(os.path.join(example_dir(), '*.py'))))
|
||||
def test_example(self, name, example):
|
||||
# Create a new trading environment for each test.
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
imp.load_source('__main__', os.path.basename(example), open(example))
|
||||
|
||||
# Test algorithm as if scripts/run_algo.py is being used.
|
||||
|
||||
@@ -24,6 +24,7 @@ from zipline.test_algorithms import (
|
||||
SetPortfolioAlgorithm,
|
||||
)
|
||||
from zipline.finance.slippage import FixedSlippage
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
|
||||
|
||||
from zipline.utils.test_utils import (
|
||||
@@ -39,6 +40,11 @@ EXTENDED_TIMEOUT = 90
|
||||
|
||||
class ExceptionTestCase(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
cls.env.write_data(equities_identifiers=[133])
|
||||
|
||||
def setUp(self):
|
||||
self.zipline_test_config = {
|
||||
'sid': 133,
|
||||
@@ -65,7 +71,8 @@ class ExceptionTestCase(TestCase):
|
||||
ExceptionAlgorithm(
|
||||
'handle_data',
|
||||
self.zipline_test_config['sid'],
|
||||
sim_params=factory.create_simulation_parameters()
|
||||
sim_params=factory.create_simulation_parameters(),
|
||||
env=self.env
|
||||
)
|
||||
|
||||
zipline = simfactory.create_test_zipline(
|
||||
@@ -75,8 +82,7 @@ class ExceptionTestCase(TestCase):
|
||||
with self.assertRaises(Exception) as ctx:
|
||||
output, _ = drain_zipline(self, zipline)
|
||||
|
||||
self.assertEqual(str(ctx.exception),
|
||||
'Algo exception in handle_data')
|
||||
self.assertEqual(str(ctx.exception), 'Algo exception in handle_data')
|
||||
|
||||
def test_zerodivision_exception_in_handle_data(self):
|
||||
|
||||
@@ -85,7 +91,8 @@ class ExceptionTestCase(TestCase):
|
||||
self.zipline_test_config['algorithm'] = \
|
||||
DivByZeroAlgorithm(
|
||||
self.zipline_test_config['sid'],
|
||||
sim_params=factory.create_simulation_parameters()
|
||||
sim_params=factory.create_simulation_parameters(),
|
||||
env=self.env
|
||||
)
|
||||
|
||||
zipline = simfactory.create_test_zipline(
|
||||
@@ -105,7 +112,8 @@ class ExceptionTestCase(TestCase):
|
||||
self.zipline_test_config['algorithm'] = \
|
||||
SetPortfolioAlgorithm(
|
||||
self.zipline_test_config['sid'],
|
||||
sim_params=factory.create_simulation_parameters()
|
||||
sim_params=factory.create_simulation_parameters(),
|
||||
env=self.env
|
||||
)
|
||||
|
||||
zipline = simfactory.create_test_zipline(
|
||||
|
||||
+16
-11
@@ -39,7 +39,6 @@ import zipline.utils.simfactory as simfactory
|
||||
from zipline.finance.blotter import Blotter
|
||||
from zipline.gens.composites import date_sorted_sources
|
||||
|
||||
from zipline.finance import trading
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
from zipline.finance.execution import MarketOrder, LimitOrder
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
@@ -59,9 +58,12 @@ _multiprocess_can_split_ = False
|
||||
|
||||
class FinanceTestCase(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
cls.env.write_data(equities_identifiers=[1, 133])
|
||||
|
||||
def setUp(self):
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
trading.environment.write_data(equities_identifiers=[1, 133])
|
||||
self.zipline_test_config = {
|
||||
'sid': 133,
|
||||
}
|
||||
@@ -76,7 +78,8 @@ class FinanceTestCase(TestCase):
|
||||
sim_params = factory.create_simulation_parameters()
|
||||
trade_source = factory.create_daily_trade_source(
|
||||
[133],
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env,
|
||||
)
|
||||
prev = None
|
||||
for trade in trade_source:
|
||||
@@ -94,7 +97,6 @@ class FinanceTestCase(TestCase):
|
||||
# No transactions can be filled on the first trade, so
|
||||
# we have one extra trade to ensure all orders are filled.
|
||||
self.zipline_test_config['trade_count'] = 101
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
full_zipline = simfactory.create_test_zipline(
|
||||
**self.zipline_test_config)
|
||||
assert_single_position(self, full_zipline)
|
||||
@@ -231,7 +233,8 @@ class FinanceTestCase(TestCase):
|
||||
price,
|
||||
volume,
|
||||
trade_interval,
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
if alternate:
|
||||
@@ -265,7 +268,7 @@ class FinanceTestCase(TestCase):
|
||||
self.assertEqual(order.sid, sid)
|
||||
self.assertEqual(order.amount, order_amount * alternator ** i)
|
||||
|
||||
tracker = PerformanceTracker(sim_params)
|
||||
tracker = PerformanceTracker(sim_params, env=self.env)
|
||||
|
||||
benchmark_returns = [
|
||||
Event({'dt': dt,
|
||||
@@ -273,7 +276,7 @@ class FinanceTestCase(TestCase):
|
||||
'type':
|
||||
zipline.protocol.DATASOURCE_TYPE.BENCHMARK,
|
||||
'source_id': 'benchmarks'})
|
||||
for dt, ret in trading.environment.benchmark_returns.iteritems()
|
||||
for dt, ret in self.env.benchmark_returns.iteritems()
|
||||
if dt.date() >= sim_params.period_start.date() and
|
||||
dt.date() <= sim_params.period_end.date()
|
||||
]
|
||||
@@ -412,6 +415,7 @@ class TradingEnvironmentTestCase(TestCase):
|
||||
period_start=datetime(2008, 1, 1, tzinfo=pytz.utc),
|
||||
period_end=datetime(2008, 12, 31, tzinfo=pytz.utc),
|
||||
capital_base=100000,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
self.assertTrue(env.last_close.month == 12)
|
||||
@@ -428,10 +432,11 @@ class TradingEnvironmentTestCase(TestCase):
|
||||
# 20 21 22 23 24 25 26
|
||||
# 27 28 29 30 31
|
||||
|
||||
env = SimulationParameters(
|
||||
params = SimulationParameters(
|
||||
period_start=datetime(2007, 12, 31, tzinfo=pytz.utc),
|
||||
period_end=datetime(2008, 1, 7, tzinfo=pytz.utc),
|
||||
capital_base=100000,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
expected_trading_days = (
|
||||
@@ -447,9 +452,9 @@ class TradingEnvironmentTestCase(TestCase):
|
||||
)
|
||||
|
||||
num_expected_trading_days = 5
|
||||
self.assertEquals(num_expected_trading_days, env.days_in_period)
|
||||
self.assertEquals(num_expected_trading_days, params.days_in_period)
|
||||
np.testing.assert_array_equal(expected_trading_days,
|
||||
env.trading_days.tolist())
|
||||
params.trading_days.tolist())
|
||||
|
||||
@timed(DEFAULT_TIMEOUT)
|
||||
def test_market_minute_window(self):
|
||||
|
||||
+40
-22
@@ -32,7 +32,6 @@ from zipline.finance import trading
|
||||
from zipline.finance.trading import (
|
||||
SimulationParameters,
|
||||
TradingEnvironment,
|
||||
with_environment,
|
||||
)
|
||||
from zipline.errors import IncompatibleHistoryFrequency
|
||||
|
||||
@@ -133,29 +132,30 @@ def convert_cases(cases):
|
||||
INDEX_TEST_CASES = convert_cases(INDEX_TEST_CASES_RAW)
|
||||
|
||||
|
||||
def get_index_at_dt(case_input):
|
||||
def get_index_at_dt(case_input, env):
|
||||
history_spec = history.HistorySpec(
|
||||
case_input['bar_count'],
|
||||
case_input['frequency'],
|
||||
None,
|
||||
False,
|
||||
env=env,
|
||||
data_frequency='minute',
|
||||
)
|
||||
return history.index_at_dt(history_spec, case_input['algo_dt'])
|
||||
return history.index_at_dt(history_spec, case_input['algo_dt'], env=env)
|
||||
|
||||
|
||||
class TestHistoryIndex(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.environment = TradingEnvironment.instance()
|
||||
cls.environment = TradingEnvironment()
|
||||
|
||||
@parameterized.expand(
|
||||
[(name, case['input'], case['expected'])
|
||||
for name, case in INDEX_TEST_CASES.items()]
|
||||
)
|
||||
def test_index_at_dt(self, name, case_input, expected):
|
||||
history_index = get_index_at_dt(case_input)
|
||||
history_index = get_index_at_dt(case_input, self.environment)
|
||||
|
||||
history_series = pd.Series(index=history_index)
|
||||
expected_series = pd.Series(index=expected)
|
||||
@@ -167,7 +167,7 @@ class TestHistoryContainer(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment.instance()
|
||||
cls.env = TradingEnvironment()
|
||||
|
||||
def bar_data_dt(self, bar_data, require_unique=True):
|
||||
"""
|
||||
@@ -205,6 +205,7 @@ class TestHistoryContainer(TestCase):
|
||||
|
||||
container = HistoryContainer(
|
||||
{spec.key_str: spec for spec in specs}, sids, dt, 'minute',
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
for update_count, update in enumerate(updates):
|
||||
@@ -232,14 +233,16 @@ class TestHistoryContainer(TestCase):
|
||||
frequency='1m',
|
||||
field='price',
|
||||
ffill=True,
|
||||
data_frequency='minute'
|
||||
data_frequency='minute',
|
||||
env=self.env,
|
||||
)
|
||||
no_fill_spec = history.HistorySpec(
|
||||
bar_count=3,
|
||||
frequency='1m',
|
||||
field='price',
|
||||
ffill=False,
|
||||
data_frequency='minute'
|
||||
data_frequency='minute',
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
specs = {spec.key_str: spec, no_fill_spec.key_str: no_fill_spec}
|
||||
@@ -248,7 +251,7 @@ class TestHistoryContainer(TestCase):
|
||||
'2013-06-28 9:31AM', tz='US/Eastern').tz_convert('UTC')
|
||||
|
||||
container = HistoryContainer(
|
||||
specs, initial_sids, initial_dt, 'minute'
|
||||
specs, initial_sids, initial_dt, 'minute', env=self.env,
|
||||
)
|
||||
|
||||
bar_data = BarData()
|
||||
@@ -282,7 +285,8 @@ class TestHistoryContainer(TestCase):
|
||||
frequency='1d',
|
||||
field='price',
|
||||
ffill=True,
|
||||
data_frequency='minute'
|
||||
data_frequency='minute',
|
||||
env=self.env,
|
||||
)
|
||||
specs = {spec.key_str: spec}
|
||||
initial_sids = [1, ]
|
||||
@@ -290,7 +294,7 @@ class TestHistoryContainer(TestCase):
|
||||
'2013-06-28 9:31AM', tz='US/Eastern').tz_convert('UTC')
|
||||
|
||||
container = HistoryContainer(
|
||||
specs, initial_sids, initial_dt, 'minute'
|
||||
specs, initial_sids, initial_dt, 'minute', env=self.env,
|
||||
)
|
||||
|
||||
bar_data = BarData()
|
||||
@@ -440,9 +444,10 @@ def handle_data(context, data):
|
||||
end = pd.Timestamp('2006-03-30', tz='UTC')
|
||||
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=start, end=end, data_frequency='daily')
|
||||
start=start, end=end, data_frequency='daily', env=self.env,
|
||||
)
|
||||
|
||||
_, df = factory.create_test_df_source(sim_params)
|
||||
_, df = factory.create_test_df_source(sim_params, self.env)
|
||||
df = df.astype(np.float64)
|
||||
source = DataFrameSource(df)
|
||||
|
||||
@@ -1039,14 +1044,15 @@ def handle_data(context, data):
|
||||
period_end=end,
|
||||
capital_base=float("1.0e5"),
|
||||
data_frequency='minute',
|
||||
emission_rate='daily'
|
||||
emission_rate='daily',
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
test_algo = TradingAlgorithm(
|
||||
script=algo_text,
|
||||
data_frequency='minute',
|
||||
sim_params=sim_params,
|
||||
env=TestHistoryAlgo.env,
|
||||
env=self.env,
|
||||
)
|
||||
test_algo.test_case = self
|
||||
|
||||
@@ -1089,14 +1095,15 @@ def handle_data(context, data):
|
||||
period_end=end,
|
||||
capital_base=float("1.0e5"),
|
||||
data_frequency='minute',
|
||||
emission_rate='daily'
|
||||
emission_rate='daily',
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
test_algo = TradingAlgorithm(
|
||||
script=algo_text,
|
||||
data_frequency='minute',
|
||||
sim_params=sim_params,
|
||||
env=TestHistoryAlgo.env,
|
||||
env=self.env,
|
||||
)
|
||||
test_algo.test_case = self
|
||||
|
||||
@@ -1107,6 +1114,11 @@ def handle_data(context, data):
|
||||
|
||||
|
||||
class TestHistoryContainerResize(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
|
||||
@parameterized.expand(
|
||||
(freq, field, data_frequency, construct_digest)
|
||||
for freq in ('1m', '1d')
|
||||
@@ -1127,6 +1139,7 @@ class TestHistoryContainerResize(TestCase):
|
||||
field=field,
|
||||
ffill=True,
|
||||
data_frequency=data_frequency,
|
||||
env=self.env,
|
||||
)
|
||||
specs = {spec.key_str: spec}
|
||||
initial_sids = [1]
|
||||
@@ -1138,7 +1151,7 @@ class TestHistoryContainerResize(TestCase):
|
||||
)
|
||||
|
||||
container = HistoryContainer(
|
||||
specs, initial_sids, initial_dt, data_frequency,
|
||||
specs, initial_sids, initial_dt, data_frequency, env=self.env,
|
||||
)
|
||||
|
||||
if construct_digest:
|
||||
@@ -1156,6 +1169,7 @@ class TestHistoryContainerResize(TestCase):
|
||||
field=field,
|
||||
ffill=True,
|
||||
data_frequency=data_frequency,
|
||||
env=self.env,
|
||||
),
|
||||
history.HistorySpec(
|
||||
bar_count=bar_count + 2,
|
||||
@@ -1163,6 +1177,7 @@ class TestHistoryContainerResize(TestCase):
|
||||
field=field,
|
||||
ffill=True,
|
||||
data_frequency=data_frequency,
|
||||
env=self.env,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1192,6 +1207,7 @@ class TestHistoryContainerResize(TestCase):
|
||||
field=first,
|
||||
ffill=True,
|
||||
data_frequency=data_frequency,
|
||||
env=self.env,
|
||||
)
|
||||
specs = {spec.key_str: spec}
|
||||
initial_sids = [1]
|
||||
@@ -1203,7 +1219,7 @@ class TestHistoryContainerResize(TestCase):
|
||||
)
|
||||
|
||||
container = HistoryContainer(
|
||||
specs, initial_sids, initial_dt, data_frequency,
|
||||
specs, initial_sids, initial_dt, data_frequency, env=self.env
|
||||
)
|
||||
|
||||
if bar_count > 1:
|
||||
@@ -1220,6 +1236,7 @@ class TestHistoryContainerResize(TestCase):
|
||||
field=second,
|
||||
ffill=True,
|
||||
data_frequency=data_frequency,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
container.ensure_spec(new_spec, initial_dt, bar_data)
|
||||
@@ -1252,6 +1269,7 @@ class TestHistoryContainerResize(TestCase):
|
||||
field=field,
|
||||
ffill=True,
|
||||
data_frequency=data_frequency,
|
||||
env=self.env,
|
||||
)
|
||||
specs = {spec.key_str: spec}
|
||||
initial_sids = [1]
|
||||
@@ -1263,7 +1281,7 @@ class TestHistoryContainerResize(TestCase):
|
||||
)
|
||||
|
||||
container = HistoryContainer(
|
||||
specs, initial_sids, initial_dt, data_frequency,
|
||||
specs, initial_sids, initial_dt, data_frequency, env=self.env,
|
||||
)
|
||||
|
||||
if bar_count > 1:
|
||||
@@ -1280,6 +1298,7 @@ class TestHistoryContainerResize(TestCase):
|
||||
field=field,
|
||||
ffill=True,
|
||||
data_frequency=data_frequency,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
container.ensure_spec(new_spec, initial_dt, bar_data)
|
||||
@@ -1292,8 +1311,7 @@ class TestHistoryContainerResize(TestCase):
|
||||
|
||||
self.assert_history(container, new_spec, initial_dt)
|
||||
|
||||
@with_environment()
|
||||
def assert_history(self, container, spec, dt, env=None):
|
||||
def assert_history(self, container, spec, dt):
|
||||
hst = container.get_history(spec, dt)
|
||||
|
||||
self.assertEqual(len(hst), spec.bar_count)
|
||||
|
||||
+170
-141
@@ -15,7 +15,6 @@
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import pickle
|
||||
import collections
|
||||
from datetime import (
|
||||
datetime,
|
||||
@@ -40,12 +39,14 @@ from zipline.finance.slippage import Transaction, create_transaction
|
||||
import zipline.utils.math_utils as zp_math
|
||||
|
||||
from zipline.gens.composites import date_sorted_sources
|
||||
from zipline.finance import trading
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
from zipline.finance.blotter import Order
|
||||
from zipline.finance.commission import PerShare, PerTrade, PerDollar
|
||||
from zipline.finance.trading import with_environment
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
from zipline.utils.factory import create_random_simulation_parameters
|
||||
from zipline.utils.serialization_utils import (
|
||||
load_with_persistent_ids, dump_with_persistent_ids
|
||||
)
|
||||
import zipline.protocol as zp
|
||||
from zipline.protocol import Event, DATASOURCE_TYPE
|
||||
from zipline.sources.data_frame_source import DataPanelSource
|
||||
@@ -128,8 +129,7 @@ def create_txn(trade_event, price, amount):
|
||||
return create_transaction(trade_event, mock_order, price, amount)
|
||||
|
||||
|
||||
@with_environment()
|
||||
def benchmark_events_in_range(sim_params, env=None):
|
||||
def benchmark_events_in_range(sim_params, env):
|
||||
return [
|
||||
Event({'dt': dt,
|
||||
'returns': ret,
|
||||
@@ -174,7 +174,7 @@ def calculate_results(host,
|
||||
txns = txns or []
|
||||
splits = splits or []
|
||||
|
||||
perf_tracker = perf.PerformanceTracker(host.sim_params)
|
||||
perf_tracker = perf.PerformanceTracker(host.sim_params, host.env)
|
||||
|
||||
if dividend_events is not None:
|
||||
dividend_frame = pd.DataFrame(
|
||||
@@ -246,9 +246,9 @@ def check_perf_tracker_serialization(perf_tracker):
|
||||
'total_days',
|
||||
]
|
||||
|
||||
p_string = pickle.dumps(perf_tracker)
|
||||
p_string = dump_with_persistent_ids(perf_tracker)
|
||||
|
||||
test = pickle.loads(p_string)
|
||||
test = load_with_persistent_ids(p_string, env=perf_tracker.env)
|
||||
|
||||
for k in scalar_keys:
|
||||
nt.assert_equal(getattr(test, k), getattr(perf_tracker, k), k)
|
||||
@@ -259,13 +259,15 @@ def check_perf_tracker_serialization(perf_tracker):
|
||||
|
||||
class TestSplitPerformance(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.env = TradingEnvironment()
|
||||
self.env.write_data(equities_identifiers=[1])
|
||||
self.sim_params, self.dt, self.end_dt = \
|
||||
create_random_simulation_parameters()
|
||||
trading.environment.write_data(equities_identifiers=[1])
|
||||
# start with $10,000
|
||||
self.sim_params.capital_base = 10e3
|
||||
|
||||
self.benchmark_events = benchmark_events_in_range(self.sim_params)
|
||||
self.benchmark_events = benchmark_events_in_range(self.sim_params,
|
||||
self.env)
|
||||
|
||||
def test_split_long_position(self):
|
||||
events = factory.create_trade_history(
|
||||
@@ -273,7 +275,8 @@ class TestSplitPerformance(unittest.TestCase):
|
||||
[20, 20],
|
||||
[100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
# set up a long position in sid 1
|
||||
@@ -359,17 +362,20 @@ class TestSplitPerformance(unittest.TestCase):
|
||||
class TestCommissionEvents(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.env = TradingEnvironment()
|
||||
self.env.write_data(
|
||||
equities_identifiers=[0, 1, 133]
|
||||
)
|
||||
self.sim_params, self.dt, self.end_dt = \
|
||||
create_random_simulation_parameters()
|
||||
|
||||
trading.environment.write_data(equities_identifiers=[0, 1, 133])
|
||||
|
||||
logger.info("sim_params: %s, dt: %s, end_dt: %s" %
|
||||
(self.sim_params, self.dt, self.end_dt))
|
||||
|
||||
self.sim_params.capital_base = 10e3
|
||||
|
||||
self.benchmark_events = benchmark_events_in_range(self.sim_params)
|
||||
self.benchmark_events = benchmark_events_in_range(self.sim_params,
|
||||
self.env)
|
||||
|
||||
def test_commission_event(self):
|
||||
events = factory.create_trade_history(
|
||||
@@ -377,7 +383,8 @@ class TestCommissionEvents(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
# Test commission models and validate result
|
||||
@@ -454,7 +461,8 @@ class TestCommissionEvents(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
# Buy and sell the same sid so that we have a zero position by the
|
||||
@@ -484,7 +492,8 @@ class TestCommissionEvents(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
# Add a cash adjustment at the time of event[3].
|
||||
@@ -500,21 +509,26 @@ class TestCommissionEvents(unittest.TestCase):
|
||||
|
||||
class TestDividendPerformance(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
cls.env.write_data(equities_identifiers=[1, 2])
|
||||
|
||||
def setUp(self):
|
||||
self.sim_params, self.dt, self.end_dt = \
|
||||
create_random_simulation_parameters()
|
||||
trading.environment.write_data(equities_identifiers=[1, 2])
|
||||
self.sim_params.capital_base = 10e3
|
||||
|
||||
self.benchmark_events = benchmark_events_in_range(self.sim_params)
|
||||
self.benchmark_events = benchmark_events_in_range(self.sim_params,
|
||||
self.env)
|
||||
|
||||
def test_market_hours_calculations(self):
|
||||
# DST in US/Eastern began on Sunday March 14, 2010
|
||||
before = datetime(2010, 3, 12, 14, 31, tzinfo=pytz.utc)
|
||||
after = factory.get_next_trading_dt(
|
||||
before,
|
||||
timedelta(days=1)
|
||||
timedelta(days=1),
|
||||
self.env,
|
||||
)
|
||||
self.assertEqual(after.hour, 13)
|
||||
|
||||
@@ -525,7 +539,8 @@ class TestDividendPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
dividend = factory.create_dividend(
|
||||
1,
|
||||
@@ -576,7 +591,8 @@ class TestDividendPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params)
|
||||
self.sim_params,
|
||||
env=self.env)
|
||||
)
|
||||
|
||||
dividend = factory.create_stock_dividend(
|
||||
@@ -626,7 +642,8 @@ class TestDividendPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
dividend = factory.create_dividend(
|
||||
@@ -667,7 +684,8 @@ class TestDividendPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
dividend = factory.create_dividend(
|
||||
@@ -708,7 +726,8 @@ class TestDividendPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
dividend = factory.create_dividend(
|
||||
@@ -749,13 +768,14 @@ class TestDividendPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
pay_date = self.sim_params.first_open
|
||||
# find pay date that is much later.
|
||||
for i in range(30):
|
||||
pay_date = factory.get_next_trading_dt(pay_date, oneday)
|
||||
pay_date = factory.get_next_trading_dt(pay_date, oneday, self.env)
|
||||
dividend = factory.create_dividend(
|
||||
1,
|
||||
10.00,
|
||||
@@ -795,7 +815,8 @@ class TestDividendPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
dividend = factory.create_dividend(
|
||||
@@ -836,7 +857,8 @@ class TestDividendPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
dividend = factory.create_dividend(
|
||||
@@ -865,15 +887,15 @@ class TestDividendPerformance(unittest.TestCase):
|
||||
[event['cumulative_perf']['capital_used'] for event in results]
|
||||
self.assertEqual(cumulative_cash_flows, [0, 0, 0, 0, 0])
|
||||
|
||||
@with_environment()
|
||||
def test_no_dividend_at_simulation_end(self, env=None):
|
||||
def test_no_dividend_at_simulation_end(self):
|
||||
# post some trades in the market
|
||||
events = factory.create_trade_history(
|
||||
1,
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
dividend = factory.create_dividend(
|
||||
1,
|
||||
@@ -886,12 +908,12 @@ class TestDividendPerformance(unittest.TestCase):
|
||||
events[-2].dt,
|
||||
# pay date, when the algorithm receives the dividend.
|
||||
# This pays out on the day after the last event
|
||||
env.next_trading_day(events[-1].dt)
|
||||
self.env.next_trading_day(events[-1].dt)
|
||||
)
|
||||
|
||||
# Set the last day to be the last event
|
||||
self.sim_params.period_end = events[-1].dt
|
||||
self.sim_params._update_internal()
|
||||
self.sim_params.update_internal_from_env(self.env)
|
||||
|
||||
# Simulate a transaction being filled prior to the ex_date.
|
||||
txns = [create_txn(events[0], 10.0, 100)]
|
||||
@@ -929,18 +951,29 @@ class TestDividendPerformanceHolidayStyle(TestDividendPerformance):
|
||||
self.end_dt = datetime(2004, 11, 25, tzinfo=pytz.utc)
|
||||
self.sim_params = SimulationParameters(
|
||||
self.dt,
|
||||
self.end_dt)
|
||||
self.benchmark_events = benchmark_events_in_range(self.sim_params)
|
||||
self.end_dt,
|
||||
env=self.env)
|
||||
|
||||
self.sim_params.capital_base = 10e3
|
||||
|
||||
self.benchmark_events = benchmark_events_in_range(self.sim_params,
|
||||
self.env)
|
||||
|
||||
|
||||
class TestPositionPerformance(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
cls.env.write_data(equities_identifiers=[1, 2])
|
||||
|
||||
def setUp(self):
|
||||
self.sim_params, self.dt, self.end_dt = \
|
||||
create_random_simulation_parameters()
|
||||
|
||||
trading.environment.write_data(equities_identifiers=[1, 2])
|
||||
self.benchmark_events = benchmark_events_in_range(self.sim_params)
|
||||
self.finder = self.env.asset_finder
|
||||
self.benchmark_events = benchmark_events_in_range(self.sim_params,
|
||||
self.env)
|
||||
|
||||
def test_long_short_positions(self):
|
||||
"""
|
||||
@@ -956,7 +989,8 @@ class TestPositionPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 9],
|
||||
[100, 100, 100, 100],
|
||||
onesec,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
trades_2 = factory.create_trade_history(
|
||||
@@ -964,13 +998,14 @@ class TestPositionPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 11],
|
||||
[100, 100, 100, 100],
|
||||
onesec,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
txn1 = create_txn(trades_1[1], 10.0, 100)
|
||||
txn2 = create_txn(trades_2[1], 10.0, -100)
|
||||
pt = perf.PositionTracker()
|
||||
pp = perf.PerformancePeriod(1000.0)
|
||||
pt = perf.PositionTracker(self.env.asset_finder)
|
||||
pp = perf.PerformancePeriod(1000.0, self.env.asset_finder)
|
||||
pp.position_tracker = pt
|
||||
pt.execute_transaction(txn1)
|
||||
pp.handle_execution(txn1)
|
||||
@@ -1046,12 +1081,13 @@ class TestPositionPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 11],
|
||||
[100, 100, 100, 100],
|
||||
onesec,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
txn = create_txn(trades[1], 10.0, 1000)
|
||||
pt = perf.PositionTracker()
|
||||
pp = perf.PerformancePeriod(1000.0)
|
||||
pt = perf.PositionTracker(self.env.asset_finder)
|
||||
pp = perf.PerformancePeriod(1000.0, self.env.asset_finder)
|
||||
pp.position_tracker = pt
|
||||
|
||||
pt.execute_transaction(txn)
|
||||
@@ -1125,12 +1161,13 @@ class TestPositionPerformance(unittest.TestCase):
|
||||
[10, 10, 10, 11],
|
||||
[100, 100, 100, 100],
|
||||
onesec,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
txn = create_txn(trades[1], 10.0, 100)
|
||||
pt = perf.PositionTracker()
|
||||
pp = perf.PerformancePeriod(1000.0)
|
||||
pt = perf.PositionTracker(self.env.asset_finder)
|
||||
pp = perf.PerformancePeriod(1000.0, self.env.asset_finder)
|
||||
pp.position_tracker = pt
|
||||
|
||||
pt.execute_transaction(txn)
|
||||
@@ -1228,14 +1265,15 @@ single short-sale transaction"""
|
||||
[10, 10, 10, 11, 10, 9],
|
||||
[100, 100, 100, 100, 100, 100],
|
||||
onesec,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
trades_1 = trades[:-2]
|
||||
|
||||
txn = create_txn(trades[1], 10.0, -100)
|
||||
pt = perf.PositionTracker()
|
||||
pp = perf.PerformancePeriod(1000.0)
|
||||
pt = perf.PositionTracker(self.env.asset_finder)
|
||||
pp = perf.PerformancePeriod(1000.0, self.env.asset_finder)
|
||||
pp.position_tracker = pt
|
||||
|
||||
pt.execute_transaction(txn)
|
||||
@@ -1352,8 +1390,8 @@ single short-sale transaction"""
|
||||
)
|
||||
|
||||
# now run a performance period encompassing the entire trade sample.
|
||||
ptTotal = perf.PositionTracker()
|
||||
ppTotal = perf.PerformancePeriod(1000.0)
|
||||
ptTotal = perf.PositionTracker(self.env.asset_finder)
|
||||
ppTotal = perf.PerformancePeriod(1000.0, self.env.asset_finder)
|
||||
ppTotal.position_tracker = pt
|
||||
|
||||
for trade in trades_1:
|
||||
@@ -1447,7 +1485,8 @@ trade after cover"""
|
||||
[10, 10, 10, 11, 9, 8, 7, 8, 9, 10],
|
||||
[100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
|
||||
onesec,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
short_txn = create_txn(
|
||||
@@ -1457,8 +1496,8 @@ trade after cover"""
|
||||
)
|
||||
|
||||
cover_txn = create_txn(trades[6], 7.0, 100)
|
||||
pt = perf.PositionTracker()
|
||||
pp = perf.PerformancePeriod(1000.0)
|
||||
pt = perf.PositionTracker(self.env.asset_finder)
|
||||
pp = perf.PerformancePeriod(1000.0, self.env.asset_finder)
|
||||
pp.position_tracker = pt
|
||||
|
||||
pt.execute_transaction(short_txn)
|
||||
@@ -1551,13 +1590,14 @@ shares in position"
|
||||
[10, 11, 11, 12],
|
||||
[100, 100, 100, 100],
|
||||
onesec,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
self.env
|
||||
)
|
||||
trades = factory.create_trade_history(*history_args)
|
||||
transactions = factory.create_txn_history(*history_args)
|
||||
|
||||
pt = perf.PositionTracker()
|
||||
pp = perf.PerformancePeriod(1000.0)
|
||||
pt = perf.PositionTracker(self.env.asset_finder)
|
||||
pp = perf.PerformancePeriod(1000.0, self.env.asset_finder)
|
||||
pp.position_tracker = pt
|
||||
|
||||
average_cost = 0
|
||||
@@ -1623,8 +1663,8 @@ shares in position"
|
||||
|
||||
self.assertEqual(pp.pnl, -800, "this period goes from +400 to -400")
|
||||
|
||||
pt3 = perf.PositionTracker()
|
||||
pp3 = perf.PerformancePeriod(1000.0)
|
||||
pt3 = perf.PositionTracker(self.env.asset_finder)
|
||||
pp3 = perf.PerformancePeriod(1000.0, self.env.asset_finder)
|
||||
pp3.position_tracker = pt3
|
||||
|
||||
average_cost = 0
|
||||
@@ -1666,15 +1706,16 @@ shares in position"
|
||||
[10, 9, 11, 8, 9, 12, 13, 14],
|
||||
[200, -100, -100, 100, -300, 100, 500, 400],
|
||||
onesec,
|
||||
self.sim_params
|
||||
self.sim_params,
|
||||
self.env
|
||||
)
|
||||
cost_bases = [10, 10, 0, 8, 9, 9, 13, 13.5]
|
||||
|
||||
trades = factory.create_trade_history(*history_args)
|
||||
transactions = factory.create_txn_history(*history_args)
|
||||
|
||||
pt = perf.PositionTracker()
|
||||
pp = perf.PerformancePeriod(1000.0)
|
||||
pt = perf.PositionTracker(self.env.asset_finder)
|
||||
pp = perf.PerformancePeriod(1000.0, self.env.asset_finder)
|
||||
pp.position_tracker = pt
|
||||
|
||||
for txn, cb in zip(transactions, cost_bases):
|
||||
@@ -1692,9 +1733,10 @@ shares in position"
|
||||
|
||||
class TestPerformanceTracker(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
trading.environment.write_data(equities_identifiers=[133, 134])
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
cls.env.write_data(equities_identifiers=[1, 2, 133, 134])
|
||||
|
||||
NumDaysToDelete = collections.namedtuple(
|
||||
'NumDaysToDelete', ('start', 'middle', 'end'))
|
||||
@@ -1733,8 +1775,6 @@ class TestPerformanceTracker(unittest.TestCase):
|
||||
# 12 13 14 15 16 17 18
|
||||
# 19 20 21 22 23 24 25
|
||||
# 26 27 28 29 30 31
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
trading.environment.write_data(equities_identifiers=[133, 134])
|
||||
start_dt = datetime(year=2008,
|
||||
month=10,
|
||||
day=9,
|
||||
@@ -1753,10 +1793,11 @@ class TestPerformanceTracker(unittest.TestCase):
|
||||
|
||||
sim_params = SimulationParameters(
|
||||
period_start=start_dt,
|
||||
period_end=end_dt
|
||||
period_end=end_dt,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
benchmark_events = benchmark_events_in_range(sim_params)
|
||||
benchmark_events = benchmark_events_in_range(sim_params, self.env)
|
||||
|
||||
trade_history = factory.create_trade_history(
|
||||
sid,
|
||||
@@ -1764,7 +1805,8 @@ class TestPerformanceTracker(unittest.TestCase):
|
||||
volume,
|
||||
trade_time_increment,
|
||||
sim_params,
|
||||
source_id="factory1"
|
||||
source_id="factory1",
|
||||
env=self.env
|
||||
)
|
||||
|
||||
sid2 = 134
|
||||
@@ -1776,7 +1818,8 @@ class TestPerformanceTracker(unittest.TestCase):
|
||||
volume,
|
||||
trade_time_increment,
|
||||
sim_params,
|
||||
source_id="factory2"
|
||||
source_id="factory2",
|
||||
env=self.env
|
||||
)
|
||||
# 'middle' start of 3 depends on number of days == 7
|
||||
middle = 3
|
||||
@@ -1796,10 +1839,6 @@ class TestPerformanceTracker(unittest.TestCase):
|
||||
del trade_history[-days_to_delete.end:]
|
||||
del trade_history2[-days_to_delete.end:]
|
||||
|
||||
sim_params.first_open = \
|
||||
sim_params.calculate_first_open()
|
||||
sim_params.last_close = \
|
||||
sim_params.calculate_last_close()
|
||||
sim_params.capital_base = 1000.0
|
||||
sim_params.frame_index = [
|
||||
'sid',
|
||||
@@ -1808,7 +1847,7 @@ class TestPerformanceTracker(unittest.TestCase):
|
||||
'price',
|
||||
'changed']
|
||||
perf_tracker = perf.PerformanceTracker(
|
||||
sim_params
|
||||
sim_params, self.env
|
||||
)
|
||||
|
||||
events = date_sorted_sources(trade_history, trade_history2)
|
||||
@@ -1887,23 +1926,21 @@ class TestPerformanceTracker(unittest.TestCase):
|
||||
else:
|
||||
yield event
|
||||
|
||||
@with_environment()
|
||||
def test_minute_tracker(self, env=None):
|
||||
def test_minute_tracker(self):
|
||||
""" Tests minute performance tracking."""
|
||||
start_dt = env.exchange_dt_in_utc(datetime(2013, 3, 1, 9, 31))
|
||||
end_dt = env.exchange_dt_in_utc(datetime(2013, 3, 1, 16, 0))
|
||||
|
||||
sim_params = SimulationParameters(
|
||||
period_start=start_dt,
|
||||
period_end=end_dt,
|
||||
emission_rate='minute'
|
||||
)
|
||||
tracker = perf.PerformanceTracker(sim_params)
|
||||
start_dt = self.env.exchange_dt_in_utc(datetime(2013, 3, 1, 9, 31))
|
||||
end_dt = self.env.exchange_dt_in_utc(datetime(2013, 3, 1, 16, 0))
|
||||
|
||||
foosid = 1
|
||||
barsid = 2
|
||||
|
||||
env.write_data(equities_identifiers=[foosid, barsid])
|
||||
sim_params = SimulationParameters(
|
||||
period_start=start_dt,
|
||||
period_end=end_dt,
|
||||
emission_rate='minute',
|
||||
env=self.env,
|
||||
)
|
||||
tracker = perf.PerformanceTracker(sim_params, env=self.env)
|
||||
|
||||
foo_event_1 = factory.create_trade(foosid, 10.0, 20, start_dt)
|
||||
order_event_1 = Order(sid=foo_event_1.sid,
|
||||
@@ -1996,10 +2033,8 @@ class TestPerformanceTracker(unittest.TestCase):
|
||||
|
||||
check_perf_tracker_serialization(tracker)
|
||||
|
||||
@with_environment()
|
||||
def test_close_position_event(self, env=None):
|
||||
env.write_data(equities_identifiers=[1, 2])
|
||||
pt = perf.PositionTracker()
|
||||
def test_close_position_event(self):
|
||||
pt = perf.PositionTracker(asset_finder=self.env.asset_finder)
|
||||
dt = pd.Timestamp("1984/03/06 3:00PM")
|
||||
pos1 = perf.Position(1, amount=np.float64(120.0),
|
||||
last_sale_date=dt, last_sale_price=3.4)
|
||||
@@ -2037,11 +2072,12 @@ class TestPerformanceTracker(unittest.TestCase):
|
||||
[10, 10, 10, 10, 10],
|
||||
[100, 100, 100, 100, 100],
|
||||
oneday,
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env
|
||||
)
|
||||
|
||||
# Create a tracker and a dividend
|
||||
perf_tracker = perf.PerformanceTracker(sim_params)
|
||||
perf_tracker = perf.PerformanceTracker(sim_params, env=self.env)
|
||||
dividend = factory.create_dividend(
|
||||
1,
|
||||
10.00,
|
||||
@@ -2081,11 +2117,12 @@ class TestPerformanceTracker(unittest.TestCase):
|
||||
|
||||
sim_params = SimulationParameters(
|
||||
period_start=start_dt,
|
||||
period_end=end_dt
|
||||
period_end=end_dt,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
perf_tracker = perf.PerformanceTracker(
|
||||
sim_params
|
||||
sim_params, env=self.env
|
||||
)
|
||||
check_perf_tracker_serialization(perf_tracker)
|
||||
|
||||
@@ -2099,16 +2136,26 @@ class TestPosition(unittest.TestCase):
|
||||
pos = perf.Position(10, amount=np.float64(120.0), last_sale_date=dt,
|
||||
last_sale_price=3.4)
|
||||
|
||||
p_string = pickle.dumps(pos)
|
||||
p_string = dump_with_persistent_ids(pos)
|
||||
|
||||
test = pickle.loads(p_string)
|
||||
test = load_with_persistent_ids(p_string, env=None)
|
||||
nt.assert_dict_equal(test.__dict__, pos.__dict__)
|
||||
|
||||
|
||||
class TestPositionTracker(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
|
||||
equities_metadata = {1: {'asset_type': 'equity'},
|
||||
2: {'asset_type': 'equity'}}
|
||||
futures_metadata = {3: {'asset_type': 'future',
|
||||
'contract_multiplier': 1000},
|
||||
4: {'asset_type': 'future',
|
||||
'contract_multiplier': 1000}}
|
||||
cls.env.write_data(equities_data=equities_metadata,
|
||||
futures_data=futures_metadata)
|
||||
|
||||
def test_empty_positions(self):
|
||||
"""
|
||||
@@ -2117,7 +2164,7 @@ class TestPositionTracker(unittest.TestCase):
|
||||
Originally this bug was due to np.dot([], []) returning
|
||||
np.bool_(False)
|
||||
"""
|
||||
pt = perf.PositionTracker()
|
||||
pt = perf.PositionTracker(self.env.asset_finder)
|
||||
|
||||
stats = [
|
||||
'calculate_positions_value',
|
||||
@@ -2137,41 +2184,28 @@ class TestPositionTracker(unittest.TestCase):
|
||||
self.assertEquals(val, 0)
|
||||
self.assertNotIsInstance(val, (bool, np.bool_))
|
||||
|
||||
def test_update_last_sale(self, env=None):
|
||||
equities_metadata = {1: {'asset_type': 'equity'}}
|
||||
futures_metadata = {2: {'asset_type': 'future',
|
||||
'contract_multiplier': 1000}}
|
||||
trading.environment.write_data(equities_data=equities_metadata,
|
||||
futures_data=futures_metadata)
|
||||
pt = perf.PositionTracker()
|
||||
def test_update_last_sale(self):
|
||||
pt = perf.PositionTracker(self.env.asset_finder)
|
||||
dt = pd.Timestamp("1984/03/06 3:00PM")
|
||||
pos1 = perf.Position(1, amount=np.float64(100.0),
|
||||
last_sale_date=dt, last_sale_price=10)
|
||||
pos2 = perf.Position(2, amount=np.float64(100.0),
|
||||
pos3 = perf.Position(3, amount=np.float64(100.0),
|
||||
last_sale_date=dt, last_sale_price=10)
|
||||
pt.update_positions({1: pos1, 2: pos2})
|
||||
pt.update_positions({1: pos1, 3: pos3})
|
||||
|
||||
event1 = Event({'sid': 1,
|
||||
'price': 11,
|
||||
'dt': dt})
|
||||
event2 = Event({'sid': 2,
|
||||
event3 = Event({'sid': 3,
|
||||
'price': 11,
|
||||
'dt': dt})
|
||||
|
||||
# Check cash-adjustment return value
|
||||
self.assertEqual(0, pt.update_last_sale(event1))
|
||||
self.assertEqual(100000, pt.update_last_sale(event2))
|
||||
self.assertEqual(100000, pt.update_last_sale(event3))
|
||||
|
||||
def test_position_values_and_exposures(self, env=None):
|
||||
equities_metadata = {1: {'asset_type': 'equity'},
|
||||
2: {'asset_type': 'equity'}}
|
||||
futures_metadata = {3: {'asset_type': 'future',
|
||||
'contract_multiplier': 1000},
|
||||
4: {'asset_type': 'future',
|
||||
'contract_multiplier': 1000}}
|
||||
trading.environment.write_data(equities_data=equities_metadata,
|
||||
futures_data=futures_metadata)
|
||||
pt = perf.PositionTracker()
|
||||
def test_position_values_and_exposures(self):
|
||||
pt = perf.PositionTracker(self.env.asset_finder)
|
||||
dt = pd.Timestamp("1984/03/06 3:00PM")
|
||||
pos1 = perf.Position(1, amount=np.float64(10.0),
|
||||
last_sale_date=dt, last_sale_price=10)
|
||||
@@ -2199,21 +2233,17 @@ class TestPositionTracker(unittest.TestCase):
|
||||
self.assertEqual(100 + 200 + 300000 + 400000, pt._gross_exposure())
|
||||
self.assertEqual(100 - 200 + 300000 - 400000, pt._net_exposure())
|
||||
|
||||
def test_serialization(self, env=None):
|
||||
metadata = {1: {'asset_type': 'equity'},
|
||||
2: {'asset_type': 'future',
|
||||
'contract_multiplier': 1000}}
|
||||
trading.environment.write_data(equities_data=metadata)
|
||||
pt = perf.PositionTracker()
|
||||
def test_serialization(self):
|
||||
pt = perf.PositionTracker(self.env.asset_finder)
|
||||
dt = pd.Timestamp("1984/03/06 3:00PM")
|
||||
pos1 = perf.Position(1, amount=np.float64(120.0),
|
||||
last_sale_date=dt, last_sale_price=3.4)
|
||||
pos2 = perf.Position(2, amount=np.float64(100.0),
|
||||
pos3 = perf.Position(3, amount=np.float64(100.0),
|
||||
last_sale_date=dt, last_sale_price=3.4)
|
||||
|
||||
pt.update_positions({1: pos1, 2: pos2})
|
||||
p_string = pickle.dumps(pt)
|
||||
test = pickle.loads(p_string)
|
||||
pt.update_positions({1: pos1, 3: pos3})
|
||||
p_string = dump_with_persistent_ids(pt)
|
||||
test = load_with_persistent_ids(p_string, env=self.env)
|
||||
nt.assert_dict_equal(test._position_amounts, pt._position_amounts)
|
||||
nt.assert_dict_equal(test._position_last_sale_prices,
|
||||
pt._position_last_sale_prices)
|
||||
@@ -2224,16 +2254,15 @@ class TestPositionTracker(unittest.TestCase):
|
||||
|
||||
|
||||
class TestPerformancePeriod(unittest.TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def test_serialization(self):
|
||||
pt = perf.PositionTracker()
|
||||
pp = perf.PerformancePeriod(100)
|
||||
env = TradingEnvironment()
|
||||
pt = perf.PositionTracker(env.asset_finder)
|
||||
pp = perf.PerformancePeriod(100, env.asset_finder)
|
||||
pp.position_tracker = pt
|
||||
|
||||
p_string = pickle.dumps(pp)
|
||||
test = pickle.loads(p_string)
|
||||
p_string = dump_with_persistent_ids(pp)
|
||||
test = load_with_persistent_ids(p_string, env=env)
|
||||
|
||||
correct = pp.__dict__.copy()
|
||||
del correct['_position_tracker']
|
||||
|
||||
@@ -13,14 +13,17 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import pickle
|
||||
from zipline.utils.serialization_utils import (
|
||||
load_with_persistent_ids, dump_with_persistent_ids
|
||||
)
|
||||
|
||||
from nose_parameterized import parameterized
|
||||
from unittest import TestCase
|
||||
|
||||
from .serialization_cases import (
|
||||
object_serialization_cases,
|
||||
assert_dict_equal
|
||||
assert_dict_equal,
|
||||
cases_env,
|
||||
)
|
||||
|
||||
|
||||
@@ -37,9 +40,9 @@ class PickleSerializationTestCase(TestCase):
|
||||
obj = cls(*initargs)
|
||||
for k, v in di_vars.items():
|
||||
setattr(obj, k, v)
|
||||
state = pickle.dumps(obj)
|
||||
state = dump_with_persistent_ids(obj)
|
||||
|
||||
obj2 = pickle.loads(state)
|
||||
obj2 = load_with_persistent_ids(state, env=cases_env)
|
||||
for k, v in di_vars.items():
|
||||
setattr(obj2, k, v)
|
||||
|
||||
|
||||
@@ -23,17 +23,21 @@ import pandas as pd
|
||||
import pandas.util.testing as tm
|
||||
|
||||
from zipline.utils.data import MutableIndexRollingPanel, RollingPanel
|
||||
from zipline.finance.trading import with_environment
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
|
||||
|
||||
class TestRollingPanel(unittest.TestCase):
|
||||
@with_environment()
|
||||
def test_alignment(self, env):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
|
||||
def test_alignment(self):
|
||||
items = ('a', 'b')
|
||||
sids = (1, 2)
|
||||
|
||||
dts = env.market_minute_window(
|
||||
env.open_and_closes.market_open[0], 4,
|
||||
dts = self.env.market_minute_window(
|
||||
self.env.open_and_closes.market_open[0], 4,
|
||||
).values
|
||||
rp = RollingPanel(2, items, sids, initial_dates=dts[1:-1])
|
||||
|
||||
@@ -90,8 +94,7 @@ class TestRollingPanel(unittest.TestCase):
|
||||
expected,
|
||||
)
|
||||
|
||||
@with_environment()
|
||||
def test_get_current_multiple_call_same_tick(self, env):
|
||||
def test_get_current_multiple_call_same_tick(self):
|
||||
"""
|
||||
In old get_current, each call the get_current would copy the data. Thus
|
||||
changing that object would have no side effects.
|
||||
@@ -104,8 +107,8 @@ class TestRollingPanel(unittest.TestCase):
|
||||
items = ('a', 'b')
|
||||
sids = (1, 2)
|
||||
|
||||
dts = env.market_minute_window(
|
||||
env.open_and_closes.market_open[0], 4,
|
||||
dts = self.env.market_minute_window(
|
||||
self.env.open_and_closes.market_open[0], 4,
|
||||
).values
|
||||
rp = RollingPanel(2, items, sids, initial_dates=dts[1:-1])
|
||||
|
||||
|
||||
+82
-64
@@ -6,8 +6,7 @@ from unittest import TestCase
|
||||
from zipline.algorithm import TradingAlgorithm
|
||||
from zipline.errors import TradingControlViolation
|
||||
from zipline.sources import SpecificEquityTrades
|
||||
from zipline.finance import trading
|
||||
from zipline.finance.trading import with_environment
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
from zipline.utils.test_utils import (
|
||||
setup_logger, teardown_logger, security_list_copy, add_security_data,)
|
||||
from zipline.utils import factory
|
||||
@@ -19,7 +18,7 @@ LEVERAGED_ETFS = load_from_directory('leveraged_etf_list')
|
||||
|
||||
class RestrictedAlgoWithCheck(TradingAlgorithm):
|
||||
def initialize(self, symbol):
|
||||
self.rl = SecurityListSet(self.get_datetime)
|
||||
self.rl = SecurityListSet(self.get_datetime, self.asset_finder)
|
||||
self.set_do_not_order_list(self.rl.leveraged_etf_list)
|
||||
self.order_count = 0
|
||||
self.sid = self.symbol(symbol)
|
||||
@@ -34,7 +33,7 @@ class RestrictedAlgoWithCheck(TradingAlgorithm):
|
||||
|
||||
class RestrictedAlgoWithoutCheck(TradingAlgorithm):
|
||||
def initialize(self, symbol):
|
||||
self.rl = SecurityListSet(self.get_datetime)
|
||||
self.rl = SecurityListSet(self.get_datetime, self.asset_finder)
|
||||
self.set_do_not_order_list(self.rl.leveraged_etf_list)
|
||||
self.order_count = 0
|
||||
self.sid = self.symbol(symbol)
|
||||
@@ -46,7 +45,7 @@ class RestrictedAlgoWithoutCheck(TradingAlgorithm):
|
||||
|
||||
class IterateRLAlgo(TradingAlgorithm):
|
||||
def initialize(self, symbol):
|
||||
self.rl = SecurityListSet(self.get_datetime)
|
||||
self.rl = SecurityListSet(self.get_datetime, self.asset_finder)
|
||||
self.set_do_not_order_list(self.rl.leveraged_etf_list)
|
||||
self.order_count = 0
|
||||
self.sid = self.symbol(symbol)
|
||||
@@ -60,6 +59,12 @@ class IterateRLAlgo(TradingAlgorithm):
|
||||
|
||||
class SecurityListTestCase(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
cls.env.write_data(equities_identifiers=['AAPL', 'GOOG', 'BZQ',
|
||||
'URTY', 'JFT'])
|
||||
|
||||
def setUp(self, env=None):
|
||||
|
||||
self.extra_knowledge_date = \
|
||||
@@ -69,43 +74,38 @@ class SecurityListTestCase(TestCase):
|
||||
|
||||
setup_logger(self)
|
||||
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
|
||||
def tearDown(self):
|
||||
teardown_logger(self)
|
||||
|
||||
def test_iterate_over_rl(self):
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=list(LEVERAGED_ETFS.keys())[0], num_days=4)
|
||||
trading.environment.write_data(equities_identifiers=['BZQ'])
|
||||
start=list(LEVERAGED_ETFS.keys())[0], num_days=4, env=self.env)
|
||||
trade_history = factory.create_trade_history(
|
||||
'BZQ',
|
||||
[10.0, 10.0, 11.0, 11.0],
|
||||
[100, 100, 100, 300],
|
||||
timedelta(days=1),
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env
|
||||
)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history)
|
||||
algo = IterateRLAlgo(symbol='BZQ', sim_params=sim_params)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history,
|
||||
env=self.env)
|
||||
algo = IterateRLAlgo(symbol='BZQ', sim_params=sim_params, env=self.env)
|
||||
algo.run(self.source)
|
||||
self.assertTrue(algo.found)
|
||||
|
||||
@with_environment()
|
||||
def test_security_list(self, env=None):
|
||||
def test_security_list(self):
|
||||
|
||||
# set the knowledge date to the first day of the
|
||||
# leveraged etf knowledge date.
|
||||
def get_datetime():
|
||||
return list(LEVERAGED_ETFS.keys())[0]
|
||||
|
||||
env.write_data(equities_identifiers=['AAPL', 'GOOG', 'BZQ',
|
||||
'URTY', 'JFT'])
|
||||
|
||||
rl = SecurityListSet(get_datetime)
|
||||
rl = SecurityListSet(get_datetime, self.env.asset_finder)
|
||||
# assert that a sample from the leveraged list are in restricted
|
||||
should_exist = [
|
||||
asset.sid for asset in
|
||||
[env.asset_finder.lookup_symbol(
|
||||
[self.env.asset_finder.lookup_symbol(
|
||||
symbol,
|
||||
as_of_date=self.extra_knowledge_date)
|
||||
for symbol in ["BZQ", "URTY", "JFT"]]
|
||||
@@ -116,7 +116,7 @@ class SecurityListTestCase(TestCase):
|
||||
# assert that a sample of allowed stocks are not in restricted
|
||||
shouldnt_exist = [
|
||||
asset.sid for asset in
|
||||
[env.asset_finder.lookup_symbol(
|
||||
[self.env.asset_finder.lookup_symbol(
|
||||
symbol,
|
||||
as_of_date=self.extra_knowledge_date)
|
||||
for symbol in ["AAPL", "GOOG"]]
|
||||
@@ -124,18 +124,15 @@ class SecurityListTestCase(TestCase):
|
||||
for sid in shouldnt_exist:
|
||||
self.assertNotIn(sid, rl.leveraged_etf_list)
|
||||
|
||||
@with_environment()
|
||||
def test_security_add(self, env=None):
|
||||
def test_security_add(self):
|
||||
def get_datetime():
|
||||
return datetime(2015, 1, 27, tzinfo=pytz.utc)
|
||||
with security_list_copy():
|
||||
add_security_data(['AAPL', 'GOOG'], [])
|
||||
env.write_data(equities_identifiers=['AAPL', 'GOOG',
|
||||
'BZQ', 'URTY'])
|
||||
rl = SecurityListSet(get_datetime)
|
||||
rl = SecurityListSet(get_datetime, self.env.asset_finder)
|
||||
should_exist = [
|
||||
asset.sid for asset in
|
||||
[env.asset_finder.lookup_symbol(
|
||||
[self.env.asset_finder.lookup_symbol(
|
||||
symbol,
|
||||
as_of_date=self.extra_knowledge_date
|
||||
) for symbol in ["AAPL", "GOOG", "BZQ", "URTY"]]
|
||||
@@ -147,57 +144,67 @@ class SecurityListTestCase(TestCase):
|
||||
with security_list_copy():
|
||||
def get_datetime():
|
||||
return datetime(2015, 1, 27, tzinfo=pytz.utc)
|
||||
trading.environment.write_data(equities_identifiers=['BZQ',
|
||||
'URTY'])
|
||||
rl = SecurityListSet(get_datetime)
|
||||
rl = SecurityListSet(get_datetime, self.env.asset_finder)
|
||||
self.assertNotIn("BZQ", rl.leveraged_etf_list)
|
||||
self.assertNotIn("URTY", rl.leveraged_etf_list)
|
||||
|
||||
def test_algo_without_rl_violation_via_check(self):
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=list(LEVERAGED_ETFS.keys())[0], num_days=4)
|
||||
trading.environment.write_data(equities_identifiers=['BZQ'])
|
||||
start=list(LEVERAGED_ETFS.keys())[0], num_days=4,
|
||||
env=self.env)
|
||||
trade_history = factory.create_trade_history(
|
||||
'BZQ',
|
||||
[10.0, 10.0, 11.0, 11.0],
|
||||
[100, 100, 100, 300],
|
||||
timedelta(days=1),
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env
|
||||
)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history,
|
||||
env=self.env)
|
||||
|
||||
algo = RestrictedAlgoWithCheck(symbol='BZQ', sim_params=sim_params)
|
||||
algo = RestrictedAlgoWithCheck(symbol='BZQ',
|
||||
sim_params=sim_params,
|
||||
env=self.env)
|
||||
algo.run(self.source)
|
||||
|
||||
def test_algo_without_rl_violation(self):
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=list(LEVERAGED_ETFS.keys())[0], num_days=4)
|
||||
trading.environment.write_data(equities_identifiers=['AAPL'])
|
||||
start=list(LEVERAGED_ETFS.keys())[0], num_days=4,
|
||||
env=self.env)
|
||||
trade_history = factory.create_trade_history(
|
||||
'AAPL',
|
||||
[10.0, 10.0, 11.0, 11.0],
|
||||
[100, 100, 100, 300],
|
||||
timedelta(days=1),
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env
|
||||
)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history)
|
||||
algo = RestrictedAlgoWithoutCheck(symbol='AAPL', sim_params=sim_params)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history,
|
||||
env=self.env)
|
||||
algo = RestrictedAlgoWithoutCheck(symbol='AAPL',
|
||||
sim_params=sim_params,
|
||||
env=self.env)
|
||||
algo.run(self.source)
|
||||
|
||||
def test_algo_with_rl_violation(self):
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=list(LEVERAGED_ETFS.keys())[0], num_days=4)
|
||||
trading.environment.write_data(equities_identifiers=['BZQ', 'JFT'])
|
||||
start=list(LEVERAGED_ETFS.keys())[0], num_days=4,
|
||||
env=self.env)
|
||||
trade_history = factory.create_trade_history(
|
||||
'BZQ',
|
||||
[10.0, 10.0, 11.0, 11.0],
|
||||
[100, 100, 100, 300],
|
||||
timedelta(days=1),
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env
|
||||
)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history,
|
||||
env=self.env)
|
||||
|
||||
algo = RestrictedAlgoWithoutCheck(symbol='BZQ', sim_params=sim_params)
|
||||
algo = RestrictedAlgoWithoutCheck(symbol='BZQ',
|
||||
sim_params=sim_params,
|
||||
env=self.env)
|
||||
with self.assertRaises(TradingControlViolation) as ctx:
|
||||
algo.run(self.source)
|
||||
|
||||
@@ -209,11 +216,15 @@ class SecurityListTestCase(TestCase):
|
||||
[10.0, 10.0, 11.0, 11.0],
|
||||
[100, 100, 100, 300],
|
||||
timedelta(days=1),
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env
|
||||
)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history,
|
||||
env=self.env)
|
||||
|
||||
algo = RestrictedAlgoWithoutCheck(symbol='JFT', sim_params=sim_params)
|
||||
algo = RestrictedAlgoWithoutCheck(symbol='JFT',
|
||||
sim_params=sim_params,
|
||||
env=self.env)
|
||||
with self.assertRaises(TradingControlViolation) as ctx:
|
||||
algo.run(self.source)
|
||||
|
||||
@@ -222,17 +233,21 @@ class SecurityListTestCase(TestCase):
|
||||
def test_algo_with_rl_violation_after_knowledge_date(self):
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=list(
|
||||
LEVERAGED_ETFS.keys())[0] + timedelta(days=7), num_days=5)
|
||||
trading.environment.write_data(equities_identifiers=['BZQ'])
|
||||
LEVERAGED_ETFS.keys())[0] + timedelta(days=7), num_days=5,
|
||||
env=self.env)
|
||||
trade_history = factory.create_trade_history(
|
||||
'BZQ',
|
||||
[10.0, 10.0, 11.0, 11.0],
|
||||
[100, 100, 100, 300],
|
||||
timedelta(days=1),
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env
|
||||
)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history)
|
||||
algo = RestrictedAlgoWithoutCheck(symbol='BZQ', sim_params=sim_params)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history,
|
||||
env=self.env)
|
||||
algo = RestrictedAlgoWithoutCheck(symbol='BZQ',
|
||||
sim_params=sim_params,
|
||||
env=self.env)
|
||||
with self.assertRaises(TradingControlViolation) as ctx:
|
||||
algo.run(self.source)
|
||||
|
||||
@@ -255,12 +270,13 @@ class SecurityListTestCase(TestCase):
|
||||
[10.0, 10.0, 11.0, 11.0],
|
||||
[100, 100, 100, 300],
|
||||
timedelta(days=1),
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env,
|
||||
)
|
||||
trading.environment.write_data(equities_identifiers=['BZQ'])
|
||||
self.source = SpecificEquityTrades(event_list=trade_history)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history,
|
||||
env=self.env)
|
||||
algo = RestrictedAlgoWithoutCheck(
|
||||
symbol='BZQ', sim_params=sim_params)
|
||||
symbol='BZQ', sim_params=sim_params, env=self.env)
|
||||
with self.assertRaises(TradingControlViolation) as ctx:
|
||||
algo.run(self.source)
|
||||
|
||||
@@ -273,18 +289,19 @@ class SecurityListTestCase(TestCase):
|
||||
add_security_data([], ['BZQ'])
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=self.extra_knowledge_date, num_days=3)
|
||||
trading.environment.write_data(equities_identifiers=['BZQ'])
|
||||
|
||||
trade_history = factory.create_trade_history(
|
||||
'BZQ',
|
||||
[10.0, 10.0, 11.0, 11.0],
|
||||
[100, 100, 100, 300],
|
||||
timedelta(days=1),
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env,
|
||||
)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history,
|
||||
env=self.env)
|
||||
algo = RestrictedAlgoWithoutCheck(
|
||||
symbol='BZQ', sim_params=sim_params
|
||||
symbol='BZQ', sim_params=sim_params, env=self.env
|
||||
)
|
||||
algo.run(self.source)
|
||||
|
||||
@@ -293,17 +310,18 @@ class SecurityListTestCase(TestCase):
|
||||
add_security_data(['AAPL'], [])
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=self.trading_day_before_first_kd, num_days=4)
|
||||
trading.environment.write_data(equities_identifiers=['AAPL'])
|
||||
trade_history = factory.create_trade_history(
|
||||
'AAPL',
|
||||
[10.0, 10.0, 11.0, 11.0],
|
||||
[100, 100, 100, 300],
|
||||
timedelta(days=1),
|
||||
sim_params
|
||||
sim_params,
|
||||
env=self.env
|
||||
)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history)
|
||||
self.source = SpecificEquityTrades(event_list=trade_history,
|
||||
env=self.env)
|
||||
algo = RestrictedAlgoWithoutCheck(
|
||||
symbol='AAPL', sim_params=sim_params)
|
||||
symbol='AAPL', sim_params=sim_params, env=self.env)
|
||||
with self.assertRaises(TradingControlViolation) as ctx:
|
||||
algo.run(self.source)
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ def gather_bad_dicts(state):
|
||||
class SerializationTestCase(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment.instance()
|
||||
cls.env = TradingEnvironment()
|
||||
|
||||
@parameterized.expand(object_serialization_cases())
|
||||
def test_object_serialization(self,
|
||||
|
||||
@@ -27,12 +27,12 @@ from zipline.sources import (DataFrameSource,
|
||||
RandomWalkSource)
|
||||
from zipline.utils import tradingcalendar as calendar_nyse
|
||||
from zipline.assets import AssetFinder
|
||||
from zipline.finance import trading
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
|
||||
|
||||
class TestDataFrameSource(TestCase):
|
||||
def test_df_source(self):
|
||||
source, df = factory.create_test_df_source()
|
||||
source, df = factory.create_test_df_source(env=None)
|
||||
assert isinstance(source.start, pd.lib.Timestamp)
|
||||
assert isinstance(source.end, pd.lib.Timestamp)
|
||||
|
||||
@@ -43,7 +43,7 @@ class TestDataFrameSource(TestCase):
|
||||
assert expected_price[0] == sid0.price
|
||||
|
||||
def test_df_sid_filtering(self):
|
||||
_, df = factory.create_test_df_source()
|
||||
_, df = factory.create_test_df_source(env=None)
|
||||
source = DataFrameSource(df)
|
||||
assert 1 not in [event.sid for event in source], \
|
||||
"DataFrameSource should only stream selected sid 0, not sid 1."
|
||||
@@ -65,10 +65,10 @@ class TestDataFrameSource(TestCase):
|
||||
self.assertTrue(isinstance(event['arbitrary'], float))
|
||||
|
||||
def test_yahoo_bars_to_panel_source(self):
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
finder = AssetFinder(trading.environment.engine)
|
||||
env = TradingEnvironment()
|
||||
finder = AssetFinder(env.engine)
|
||||
stocks = ['AAPL', 'GE']
|
||||
trading.environment.write_data(equities_identifiers=stocks)
|
||||
env.write_data(equities_identifiers=stocks)
|
||||
start = pd.datetime(1993, 1, 1, 0, 0, 0, 0, pytz.utc)
|
||||
end = pd.datetime(2002, 1, 1, 0, 0, 0, 0, pytz.utc)
|
||||
data = factory.load_bars_from_yahoo(stocks=stocks,
|
||||
|
||||
@@ -103,6 +103,7 @@ def with_algo(f):
|
||||
initialize=initialize_with(self, tfm_name, days),
|
||||
handle_data=handle_data_wrapper(f),
|
||||
sim_params=sim_params,
|
||||
env=self.env,
|
||||
)
|
||||
algo.run(source)
|
||||
|
||||
@@ -127,17 +128,19 @@ class TransformTestCase(TestCase):
|
||||
data_frequency='daily',
|
||||
emission_rate='daily',
|
||||
)
|
||||
cls.env = TradingEnvironment.instance()
|
||||
cls.env = TradingEnvironment()
|
||||
cls.env.write_data(equities_identifiers=[1, 2, 3])
|
||||
cls.sim_and_source = {
|
||||
'minute': (minute_sim_ps, factory.create_minutely_trade_source(
|
||||
cls.sids,
|
||||
sim_params=minute_sim_ps,
|
||||
env=cls.env,
|
||||
)),
|
||||
'daily': (daily_sim_ps, factory.create_trade_source(
|
||||
cls.sids,
|
||||
trade_time_increment=timedelta(days=1),
|
||||
sim_params=daily_sim_ps,
|
||||
env=cls.env,
|
||||
)),
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
import pytz
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import talib
|
||||
|
||||
from datetime import timedelta, datetime
|
||||
from unittest import TestCase, skip
|
||||
@@ -23,21 +24,26 @@ from unittest import TestCase, skip
|
||||
from zipline.utils.test_utils import setup_logger, teardown_logger
|
||||
|
||||
import zipline.utils.factory as factory
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
|
||||
from zipline.test_algorithms import TALIBAlgorithm
|
||||
|
||||
import talib
|
||||
import zipline.transforms.ta as ta
|
||||
|
||||
|
||||
class TestTALIB(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment()
|
||||
|
||||
def setUp(self):
|
||||
setup_logger(self)
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=datetime(1990, 1, 1, tzinfo=pytz.utc),
|
||||
end=datetime(1990, 3, 30, tzinfo=pytz.utc))
|
||||
self.source, self.panel = \
|
||||
factory.create_test_panel_ohlc_source(sim_params)
|
||||
factory.create_test_panel_ohlc_source(sim_params, self.env)
|
||||
|
||||
def tearDown(self):
|
||||
teardown_logger(self)
|
||||
@@ -60,7 +66,7 @@ class TestTALIB(TestCase):
|
||||
sim_params = factory.create_simulation_parameters(
|
||||
start=start, end=end)
|
||||
source, panel = \
|
||||
factory.create_test_panel_ohlc_source(sim_params)
|
||||
factory.create_test_panel_ohlc_source(sim_params, self.env)
|
||||
|
||||
algo = TALIBAlgorithm(talib=zipline_transform)
|
||||
algo.run(source)
|
||||
|
||||
+36
-21
@@ -19,10 +19,12 @@ import random
|
||||
from six.moves import range, map
|
||||
from nose_parameterized import parameterized
|
||||
from unittest import TestCase
|
||||
from functools import partial
|
||||
from collections import namedtuple
|
||||
|
||||
import numpy as np
|
||||
|
||||
from zipline.finance.trading import TradingEnvironment, with_environment
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
import zipline.utils.events
|
||||
from zipline.utils.events import (
|
||||
EventRule,
|
||||
@@ -161,7 +163,7 @@ class TestEventManager(TestCase):
|
||||
class CountingRule(Always):
|
||||
count = 0
|
||||
|
||||
def should_trigger(self, dt):
|
||||
def should_trigger(self, dt, env):
|
||||
CountingRule.count += 1
|
||||
return True
|
||||
|
||||
@@ -170,7 +172,10 @@ class TestEventManager(TestCase):
|
||||
Event(r(), lambda context, data: None)
|
||||
)
|
||||
|
||||
self.em.handle_data(None, None, datetime.datetime.now())
|
||||
mock_algo_class = namedtuple('FakeAlgo', ['trading_environment'])
|
||||
mock_algo = mock_algo_class(trading_environment="fake_env")
|
||||
self.em.handle_data(mock_algo, None, datetime.datetime.now(),
|
||||
mock_algo.trading_environment)
|
||||
|
||||
self.assertEqual(CountingRule.count, 5)
|
||||
|
||||
@@ -182,11 +187,10 @@ class TestEventRule(TestCase):
|
||||
|
||||
def test_not_implemented(self):
|
||||
with self.assertRaises(NotImplementedError):
|
||||
super(Always, Always()).should_trigger('a')
|
||||
super(Always, Always()).should_trigger('a', env=None)
|
||||
|
||||
|
||||
@with_environment()
|
||||
def minutes_for_days(env=None):
|
||||
def minutes_for_days():
|
||||
"""
|
||||
500 randomly selected days.
|
||||
This is used to make sure our test coverage is unbaised towards any rules.
|
||||
@@ -202,6 +206,7 @@ def minutes_for_days(env=None):
|
||||
Iterating over this yeilds a single day, iterating over the day yields
|
||||
the minutes for that day.
|
||||
"""
|
||||
env = TradingEnvironment()
|
||||
random.seed('deterministic')
|
||||
return ((env.market_minutes_for_day(random.choice(env.trading_days)),)
|
||||
for _ in range(500))
|
||||
@@ -210,7 +215,7 @@ def minutes_for_days(env=None):
|
||||
class RuleTestCase(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.env = TradingEnvironment.instance()
|
||||
cls.env = TradingEnvironment()
|
||||
cls.class_ = None # Mark that this is the base class.
|
||||
|
||||
def test_completeness(self):
|
||||
@@ -256,17 +261,18 @@ class TestStatelessRules(RuleTestCase):
|
||||
|
||||
@parameterized.expand(minutes_for_days())
|
||||
def test_Always(self, ms):
|
||||
should_trigger = Always().should_trigger
|
||||
self.assertTrue(all(map(should_trigger, ms)))
|
||||
should_trigger = partial(Always().should_trigger, env=self.env)
|
||||
self.assertTrue(all(map(partial(should_trigger, env=self.env), ms)))
|
||||
|
||||
@parameterized.expand(minutes_for_days())
|
||||
def test_Never(self, ms):
|
||||
should_trigger = Never().should_trigger
|
||||
should_trigger = partial(Never().should_trigger, env=self.env)
|
||||
self.assertFalse(any(map(should_trigger, ms)))
|
||||
|
||||
@parameterized.expand(minutes_for_days())
|
||||
def test_AfterOpen(self, ms):
|
||||
should_trigger = AfterOpen(minutes=5, hours=1).should_trigger
|
||||
should_trigger = partial(AfterOpen(minutes=5, hours=1).should_trigger,
|
||||
env=self.env)
|
||||
for m in islice(ms, 64):
|
||||
# Check the first 64 minutes of data.
|
||||
# We use 64 because the offset is from market open
|
||||
@@ -280,20 +286,23 @@ class TestStatelessRules(RuleTestCase):
|
||||
@parameterized.expand(minutes_for_days())
|
||||
def test_BeforeClose(self, ms):
|
||||
ms = list(ms)
|
||||
should_trigger = BeforeClose(hours=1, minutes=5).should_trigger
|
||||
should_trigger = partial(
|
||||
BeforeClose(hours=1, minutes=5).should_trigger, env=self.env
|
||||
)
|
||||
for m in ms[0:-66]:
|
||||
self.assertFalse(should_trigger(m))
|
||||
for m in ms[-66:]:
|
||||
self.assertTrue(should_trigger(m))
|
||||
|
||||
def test_NotHalfDay(self):
|
||||
should_trigger = NotHalfDay().should_trigger
|
||||
should_trigger = partial(NotHalfDay().should_trigger, env=self.env)
|
||||
self.assertTrue(should_trigger(FULL_DAY))
|
||||
self.assertFalse(should_trigger(HALF_DAY))
|
||||
|
||||
@parameterized.expand(param_range(MAX_WEEK_RANGE))
|
||||
def test_NthTradingDayOfWeek(self, n):
|
||||
should_trigger = NthTradingDayOfWeek(n).should_trigger
|
||||
should_trigger = partial(NthTradingDayOfWeek(n).should_trigger,
|
||||
env=self.env)
|
||||
prev_day = self.sept_week[0].date()
|
||||
n_tdays = 0
|
||||
for m in self.sept_week:
|
||||
@@ -308,7 +317,9 @@ class TestStatelessRules(RuleTestCase):
|
||||
|
||||
@parameterized.expand(param_range(MAX_WEEK_RANGE))
|
||||
def test_NDaysBeforeLastTradingDayOfWeek(self, n):
|
||||
should_trigger = NDaysBeforeLastTradingDayOfWeek(n).should_trigger
|
||||
should_trigger = partial(
|
||||
NDaysBeforeLastTradingDayOfWeek(n).should_trigger, env=self.env
|
||||
)
|
||||
for m in self.sept_week:
|
||||
if should_trigger(m):
|
||||
n_tdays = 0
|
||||
@@ -323,7 +334,8 @@ class TestStatelessRules(RuleTestCase):
|
||||
|
||||
@parameterized.expand(param_range(MAX_MONTH_RANGE))
|
||||
def test_NthTradingDayOfMonth(self, n):
|
||||
should_trigger = NthTradingDayOfMonth(n).should_trigger
|
||||
should_trigger = partial(NthTradingDayOfMonth(n).should_trigger,
|
||||
env=self.env)
|
||||
for n_tdays, d in enumerate(self.sept_days):
|
||||
for m in self.env.market_minutes_for_day(d):
|
||||
if should_trigger(m):
|
||||
@@ -333,7 +345,9 @@ class TestStatelessRules(RuleTestCase):
|
||||
|
||||
@parameterized.expand(param_range(MAX_MONTH_RANGE))
|
||||
def test_NDaysBeforeLastTradingDayOfMonth(self, n):
|
||||
should_trigger = NDaysBeforeLastTradingDayOfMonth(n).should_trigger
|
||||
should_trigger = partial(
|
||||
NDaysBeforeLastTradingDayOfMonth(n).should_trigger, env=self.env
|
||||
)
|
||||
for n_days_before, d in enumerate(reversed(self.sept_days)):
|
||||
for m in self.env.market_minutes_for_day(d):
|
||||
if should_trigger(m):
|
||||
@@ -347,10 +361,11 @@ class TestStatelessRules(RuleTestCase):
|
||||
rule2 = Never()
|
||||
|
||||
composed = rule1 & rule2
|
||||
should_trigger = partial(composed.should_trigger, env=self.env)
|
||||
self.assertIsInstance(composed, ComposedRule)
|
||||
self.assertIs(composed.first, rule1)
|
||||
self.assertIs(composed.second, rule2)
|
||||
self.assertFalse(any(map(composed.should_trigger, ms)))
|
||||
self.assertFalse(any(map(should_trigger, ms)))
|
||||
|
||||
|
||||
class TestStatefulRules(RuleTestCase):
|
||||
@@ -369,14 +384,14 @@ class TestStatefulRules(RuleTestCase):
|
||||
"""
|
||||
count = 0
|
||||
|
||||
def should_trigger(self, dt):
|
||||
st = self.rule.should_trigger(dt)
|
||||
def should_trigger(self, dt, env):
|
||||
st = self.rule.should_trigger(dt, env)
|
||||
if st:
|
||||
self.count += 1
|
||||
return st
|
||||
|
||||
rule = RuleCounter(OncePerDay())
|
||||
for m in ms:
|
||||
rule.should_trigger(m)
|
||||
rule.should_trigger(m, env=self.env)
|
||||
|
||||
self.assertEqual(rule.count, 1)
|
||||
|
||||
+59
-14
@@ -191,6 +191,18 @@ class TradingAlgorithm(object):
|
||||
|
||||
self.instant_fill = kwargs.pop('instant_fill', False)
|
||||
|
||||
# If an env has been provided, pop it
|
||||
self.trading_environment = kwargs.pop('env', None)
|
||||
|
||||
if self.trading_environment is None:
|
||||
self.trading_environment = TradingEnvironment()
|
||||
|
||||
# Update the TradingEnvironment with the provided asset metadata
|
||||
self.trading_environment.write_data(
|
||||
equities_data=kwargs.pop('asset_metadata', {}),
|
||||
equities_identifiers=kwargs.pop('identifiers', []),
|
||||
)
|
||||
|
||||
# set the capital base
|
||||
self.capital_base = kwargs.pop('capital_base', DEFAULT_CAPITAL_BASE)
|
||||
self.sim_params = kwargs.pop('sim_params', None)
|
||||
@@ -198,17 +210,15 @@ class TradingAlgorithm(object):
|
||||
self.sim_params = create_simulation_parameters(
|
||||
capital_base=self.capital_base,
|
||||
start=kwargs.pop('start', None),
|
||||
end=kwargs.pop('end', None)
|
||||
end=kwargs.pop('end', None),
|
||||
env=self.trading_environment,
|
||||
)
|
||||
self.perf_tracker = PerformanceTracker(self.sim_params)
|
||||
else:
|
||||
self.sim_params.update_internal_from_env(self.trading_environment)
|
||||
|
||||
# Update the TradingEnvironment with the provided asset metadata
|
||||
self.trading_environment = kwargs.pop('env',
|
||||
TradingEnvironment.instance())
|
||||
self.trading_environment.write_data(
|
||||
equities_data=kwargs.pop('asset_metadata', {}),
|
||||
equities_identifiers=kwargs.pop('identifiers', []),
|
||||
)
|
||||
# Build a perf_tracker
|
||||
self.perf_tracker = PerformanceTracker(sim_params=self.sim_params,
|
||||
env=self.trading_environment)
|
||||
|
||||
# Pull in the environment's new AssetFinder for quick reference
|
||||
self.asset_finder = self.trading_environment.asset_finder
|
||||
@@ -441,7 +451,9 @@ class TradingAlgorithm(object):
|
||||
if self.perf_tracker is None:
|
||||
# HACK: When running with the `run` method, we set perf_tracker to
|
||||
# None so that it will be overwritten here.
|
||||
self.perf_tracker = PerformanceTracker(sim_params)
|
||||
self.perf_tracker = PerformanceTracker(
|
||||
sim_params=sim_params, env=self.trading_environment
|
||||
)
|
||||
|
||||
self.portfolio_needs_update = True
|
||||
self.account_needs_update = True
|
||||
@@ -500,8 +512,21 @@ class TradingAlgorithm(object):
|
||||
# if DataFrame provided, map columns to sids and wrap
|
||||
# in DataFrameSource
|
||||
copy_frame = source.copy()
|
||||
|
||||
# Build new Assets for identifiers that can't be resolved as
|
||||
# sids/Assets
|
||||
identifiers_to_build = []
|
||||
for identifier in source.columns:
|
||||
if hasattr(identifier, '__int__'):
|
||||
asset = self.asset_finder.retrieve_asset(sid=identifier,
|
||||
default_none=True)
|
||||
if asset is None:
|
||||
identifiers_to_build.append(identifier)
|
||||
else:
|
||||
identifiers_to_build.append(identifier)
|
||||
|
||||
self.trading_environment.write_data(
|
||||
equities_identifiers=source.columns)
|
||||
equities_identifiers=identifiers_to_build)
|
||||
copy_frame.columns = \
|
||||
self.asset_finder.map_identifier_index_to_sids(
|
||||
source.columns, source.index[0]
|
||||
@@ -512,8 +537,21 @@ class TradingAlgorithm(object):
|
||||
# If Panel provided, map items to sids and wrap
|
||||
# in DataPanelSource
|
||||
copy_panel = source.copy()
|
||||
|
||||
# Build new Assets for identifiers that can't be resolved as
|
||||
# sids/Assets
|
||||
identifiers_to_build = []
|
||||
for identifier in source.items:
|
||||
if hasattr(identifier, '__int__'):
|
||||
asset = self.asset_finder.retrieve_asset(sid=identifier,
|
||||
default_none=True)
|
||||
if asset is None:
|
||||
identifiers_to_build.append(identifier)
|
||||
else:
|
||||
identifiers_to_build.append(identifier)
|
||||
|
||||
self.trading_environment.write_data(
|
||||
equities_identifiers=source.items)
|
||||
equities_identifiers=identifiers_to_build)
|
||||
copy_panel.items = self.asset_finder.map_identifier_index_to_sids(
|
||||
source.items, source.major_axis[0]
|
||||
)
|
||||
@@ -532,7 +570,9 @@ class TradingAlgorithm(object):
|
||||
self.sim_params.period_end = source.end
|
||||
# Changing period_start and period_close might require updating
|
||||
# of first_open and last_close.
|
||||
self.sim_params._update_internal()
|
||||
self.sim_params.update_internal_from_env(
|
||||
env=self.trading_environment
|
||||
)
|
||||
|
||||
# The sids field of the source is the reference for the universe at
|
||||
# the start of the run
|
||||
@@ -560,6 +600,7 @@ class TradingAlgorithm(object):
|
||||
self.current_universe(),
|
||||
self.sim_params.first_open,
|
||||
self.sim_params.data_frequency,
|
||||
self.trading_environment,
|
||||
)
|
||||
|
||||
# loop through simulated_trading, each iteration returns a
|
||||
@@ -1137,7 +1178,8 @@ class TradingAlgorithm(object):
|
||||
def add_history(self, bar_count, frequency, field, ffill=True):
|
||||
data_frequency = self.sim_params.data_frequency
|
||||
history_spec = HistorySpec(bar_count, frequency, field, ffill,
|
||||
data_frequency=data_frequency)
|
||||
data_frequency=data_frequency,
|
||||
env=self.trading_environment)
|
||||
self.history_specs[history_spec.key_str] = history_spec
|
||||
if self.initialized:
|
||||
if self.history_container:
|
||||
@@ -1150,6 +1192,7 @@ class TradingAlgorithm(object):
|
||||
self.current_universe(),
|
||||
self.sim_params.first_open,
|
||||
self.sim_params.data_frequency,
|
||||
env=self.trading_environment,
|
||||
)
|
||||
|
||||
def get_history_spec(self, bar_count, frequency, field, ffill):
|
||||
@@ -1162,6 +1205,7 @@ class TradingAlgorithm(object):
|
||||
field,
|
||||
ffill,
|
||||
data_frequency=data_freq,
|
||||
env=self.trading_environment,
|
||||
)
|
||||
self.history_specs[spec_key] = spec
|
||||
if not self.history_container:
|
||||
@@ -1171,6 +1215,7 @@ class TradingAlgorithm(object):
|
||||
self.datetime,
|
||||
self.sim_params.data_frequency,
|
||||
bar_data=self._most_recent_data,
|
||||
env=self.trading_environment,
|
||||
)
|
||||
self.history_container.ensure_spec(
|
||||
spec, self.datetime, self._most_recent_data,
|
||||
|
||||
@@ -46,6 +46,10 @@ log = Logger('assets.py')
|
||||
|
||||
class AssetFinder(object):
|
||||
|
||||
# Token used as a substitute for pickling objects that contain a
|
||||
# reference to an AssetFinder
|
||||
PERSISTENT_TOKEN = "<AssetFinder>"
|
||||
|
||||
def __init__(self, engine, allow_sid_assignment=True, fuzzy_char=None):
|
||||
|
||||
self.fuzzy_char = fuzzy_char
|
||||
@@ -160,7 +164,9 @@ class AssetFinder(object):
|
||||
else:
|
||||
asset = None
|
||||
|
||||
self._asset_cache[sid] = asset
|
||||
# Cache the asset if it has been retrieved
|
||||
if asset is not None:
|
||||
self._asset_cache[sid] = asset
|
||||
|
||||
if asset is not None:
|
||||
return asset
|
||||
|
||||
@@ -402,3 +402,15 @@ class UnsupportedDatetimeFormat(ZiplineError):
|
||||
"""
|
||||
msg = ("The input '{input}' passed to '{method}' is not "
|
||||
"coercible to a pandas.Timestamp object.")
|
||||
|
||||
|
||||
class PositionTrackerMissingAssetFinder(ZiplineError):
|
||||
"""
|
||||
Raised by a PositionTracker if it is asked to update an Asset but does not
|
||||
have an AssetFinder
|
||||
"""
|
||||
msg = (
|
||||
"PositionTracker attempted to update its Asset information but does "
|
||||
"not have an AssetFinder. This may be caused by a failure to properly "
|
||||
"de-serialize a TradingAlgorithm."
|
||||
)
|
||||
|
||||
@@ -75,7 +75,6 @@ import logbook
|
||||
|
||||
import numpy as np
|
||||
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
from zipline.assets import Future
|
||||
|
||||
try:
|
||||
@@ -92,8 +91,6 @@ from zipline.utils.serialization_utils import (
|
||||
VERSION_LABEL
|
||||
)
|
||||
|
||||
from .position_tracker import PositionTracker
|
||||
|
||||
log = logbook.Logger('Performance')
|
||||
TRADE_TYPE = zp.DATASOURCE_TYPE.TRADE
|
||||
|
||||
@@ -103,12 +100,15 @@ class PerformancePeriod(object):
|
||||
def __init__(
|
||||
self,
|
||||
starting_cash,
|
||||
asset_finder,
|
||||
period_open=None,
|
||||
period_close=None,
|
||||
keep_transactions=True,
|
||||
keep_orders=False,
|
||||
serialize_positions=True):
|
||||
|
||||
self.asset_finder = asset_finder
|
||||
|
||||
self.period_open = period_open
|
||||
self.period_close = period_close
|
||||
|
||||
@@ -225,8 +225,7 @@ class PerformancePeriod(object):
|
||||
try:
|
||||
multiplier = self._execution_cash_flow_multipliers[txn.sid]
|
||||
except KeyError:
|
||||
asset = TradingEnvironment.instance().asset_finder.\
|
||||
retrieve_asset(txn.sid)
|
||||
asset = self.asset_finder.retrieve_asset(txn.sid)
|
||||
# Futures experience no cash flow on transactions
|
||||
if isinstance(asset, Future):
|
||||
multiplier = 0
|
||||
@@ -424,13 +423,13 @@ class PerformancePeriod(object):
|
||||
state_dict['orders_by_modified'] = \
|
||||
dict(self.orders_by_modified)
|
||||
|
||||
STATE_VERSION = 2
|
||||
STATE_VERSION = 3
|
||||
state_dict[VERSION_LABEL] = STATE_VERSION
|
||||
return state_dict
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
OLDEST_SUPPORTED_STATE = 1
|
||||
OLDEST_SUPPORTED_STATE = 3
|
||||
version = state.pop(VERSION_LABEL)
|
||||
|
||||
if version < OLDEST_SUPPORTED_STATE:
|
||||
@@ -450,16 +449,4 @@ class PerformancePeriod(object):
|
||||
|
||||
self._execution_cash_flow_multipliers = {}
|
||||
|
||||
# pop positions to use for v1
|
||||
positions = state.pop('positions', None)
|
||||
self.__dict__.update(state)
|
||||
|
||||
if version == 1:
|
||||
# version 1 had PositionTracker logic inside of Period
|
||||
# we create the PositionTracker here.
|
||||
# Note: that in V2 it is assumed that the position_tracker
|
||||
# will be dependency injected and so is not reconstructed
|
||||
assert positions is not None, "positions should exist in v1"
|
||||
position_tracker = PositionTracker()
|
||||
position_tracker.update_positions(positions)
|
||||
self.position_tracker = position_tracker
|
||||
|
||||
@@ -21,7 +21,7 @@ import zipline.protocol as zp
|
||||
from zipline.assets import (
|
||||
Equity, Future
|
||||
)
|
||||
from zipline.finance.trading import with_environment
|
||||
from zipline.errors import PositionTrackerMissingAssetFinder
|
||||
from . position import positiondict
|
||||
|
||||
log = logbook.Logger('Performance')
|
||||
@@ -29,7 +29,9 @@ log = logbook.Logger('Performance')
|
||||
|
||||
class PositionTracker(object):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, asset_finder):
|
||||
self.asset_finder = asset_finder
|
||||
|
||||
# sid => position object
|
||||
self.positions = positiondict()
|
||||
# Arrays for quick calculations of positions value
|
||||
@@ -47,18 +49,18 @@ class PositionTracker(object):
|
||||
# for any Assets in this tracker's positions
|
||||
self._auto_close_position_sids = {}
|
||||
|
||||
@with_environment()
|
||||
def _retrieve_asset(self, sid, env=None):
|
||||
return env.asset_finder.retrieve_asset(sid)
|
||||
|
||||
def _update_asset(self, sid):
|
||||
try:
|
||||
self._position_value_multipliers[sid]
|
||||
self._position_exposure_multipliers[sid]
|
||||
self._position_payout_multipliers[sid]
|
||||
except KeyError:
|
||||
# Check if there is an AssetFinder
|
||||
if self.asset_finder is None:
|
||||
raise PositionTrackerMissingAssetFinder()
|
||||
|
||||
# Collect the value multipliers from applicable sids
|
||||
asset = self._retrieve_asset(sid)
|
||||
asset = self.asset_finder.retrieve_asset(sid)
|
||||
if isinstance(asset, Equity):
|
||||
self._position_value_multipliers[sid] = 1
|
||||
self._position_exposure_multipliers[sid] = 1
|
||||
@@ -400,20 +402,31 @@ class PositionTracker(object):
|
||||
def __getstate__(self):
|
||||
state_dict = {}
|
||||
|
||||
state_dict['asset_finder'] = self.asset_finder
|
||||
state_dict['positions'] = dict(self.positions)
|
||||
state_dict['unpaid_dividends'] = self._unpaid_dividends
|
||||
|
||||
STATE_VERSION = 1
|
||||
# Asset-finder dependent dicts must be serialized
|
||||
state_dict['position_value_multipliers'] = \
|
||||
serialize_ordered_dict(self._position_value_multipliers)
|
||||
state_dict['position_exposure_multipliers'] = \
|
||||
serialize_ordered_dict(self._position_exposure_multipliers)
|
||||
state_dict['position_payout_multipliers'] = \
|
||||
serialize_ordered_dict(self._position_payout_multipliers)
|
||||
state_dict['auto_close_position_sids'] = self._auto_close_position_sids
|
||||
|
||||
STATE_VERSION = 3
|
||||
state_dict[VERSION_LABEL] = STATE_VERSION
|
||||
return state_dict
|
||||
|
||||
def __setstate__(self, state):
|
||||
OLDEST_SUPPORTED_STATE = 1
|
||||
OLDEST_SUPPORTED_STATE = 3
|
||||
version = state.pop(VERSION_LABEL)
|
||||
|
||||
if version < OLDEST_SUPPORTED_STATE:
|
||||
raise BaseException("PositionTracker saved state is too old.")
|
||||
|
||||
self.asset_finder = state['asset_finder']
|
||||
self.positions = positiondict()
|
||||
# note that positions_store is temporary and gets regened from
|
||||
# .positions
|
||||
@@ -421,12 +434,35 @@ class PositionTracker(object):
|
||||
|
||||
self._unpaid_dividends = state['unpaid_dividends']
|
||||
|
||||
# AssetFinder-dependent dicts are de-serialized
|
||||
self._position_value_multipliers = \
|
||||
deserialize_ordered_dict(state['position_value_multipliers'])
|
||||
self._position_exposure_multipliers = \
|
||||
deserialize_ordered_dict(state['position_exposure_multipliers'])
|
||||
self._position_payout_multipliers = \
|
||||
deserialize_ordered_dict(state['position_payout_multipliers'])
|
||||
self._auto_close_position_sids = state['auto_close_position_sids']
|
||||
|
||||
# Arrays for quick calculations of positions value
|
||||
self._position_amounts = OrderedDict()
|
||||
self._position_last_sale_prices = OrderedDict()
|
||||
self._position_value_multipliers = OrderedDict()
|
||||
self._position_exposure_multipliers = OrderedDict()
|
||||
self._position_payout_multipliers = OrderedDict()
|
||||
self._auto_close_position_sids = {}
|
||||
|
||||
# Update positions is called without a finder
|
||||
self.update_positions(state['positions'])
|
||||
|
||||
|
||||
def serialize_ordered_dict(ordered_dict):
|
||||
"""
|
||||
Converts an OrderedDict in to a list of key/value pair tuples
|
||||
"""
|
||||
return [(key, value) for key, value in ordered_dict.items()]
|
||||
|
||||
|
||||
def deserialize_ordered_dict(serialized_ordered_dict):
|
||||
"""
|
||||
Converts a list of key/value pair tuples in to an OrderedDict
|
||||
"""
|
||||
result = OrderedDict()
|
||||
for key, value in serialized_ordered_dict:
|
||||
result[key] = value
|
||||
return result
|
||||
|
||||
@@ -68,7 +68,6 @@ import pandas as pd
|
||||
from pandas.tseries.tools import normalize_date
|
||||
|
||||
import zipline.finance.risk as risk
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
from . period import PerformancePeriod
|
||||
|
||||
from zipline.utils.serialization_utils import (
|
||||
@@ -83,15 +82,17 @@ class PerformanceTracker(object):
|
||||
"""
|
||||
Tracks the performance of the algorithm.
|
||||
"""
|
||||
def __init__(self, sim_params):
|
||||
def __init__(self, sim_params, env):
|
||||
|
||||
self.sim_params = sim_params
|
||||
env = TradingEnvironment.instance()
|
||||
self.env = env
|
||||
|
||||
self.period_start = self.sim_params.period_start
|
||||
self.period_end = self.sim_params.period_end
|
||||
self.last_close = self.sim_params.last_close
|
||||
first_open = self.sim_params.first_open.tz_convert(env.exchange_tz)
|
||||
first_open = self.sim_params.first_open.tz_convert(
|
||||
self.env.exchange_tz
|
||||
)
|
||||
self.day = pd.Timestamp(datetime(first_open.year, first_open.month,
|
||||
first_open.day), tz='UTC')
|
||||
self.market_open, self.market_close = env.get_open_and_close(self.day)
|
||||
@@ -108,7 +109,7 @@ class PerformanceTracker(object):
|
||||
self.dividend_frame = pd.DataFrame()
|
||||
self._dividend_count = 0
|
||||
|
||||
self.position_tracker = PositionTracker()
|
||||
self.position_tracker = PositionTracker(asset_finder=env.asset_finder)
|
||||
|
||||
self.perf_periods = []
|
||||
|
||||
@@ -116,7 +117,7 @@ class PerformanceTracker(object):
|
||||
self.all_benchmark_returns = pd.Series(
|
||||
index=self.trading_days)
|
||||
self.cumulative_risk_metrics = \
|
||||
risk.RiskMetricsCumulative(self.sim_params)
|
||||
risk.RiskMetricsCumulative(self.sim_params, self.env)
|
||||
|
||||
elif self.emission_rate == 'minute':
|
||||
self.all_benchmark_returns = pd.Series(index=pd.date_range(
|
||||
@@ -124,22 +125,23 @@ class PerformanceTracker(object):
|
||||
freq='Min'))
|
||||
|
||||
self.cumulative_risk_metrics = \
|
||||
risk.RiskMetricsCumulative(self.sim_params,
|
||||
risk.RiskMetricsCumulative(self.sim_params, self.env,
|
||||
create_first_day_stats=True)
|
||||
|
||||
self.minute_performance = PerformancePeriod(
|
||||
# initial cash is your capital base.
|
||||
self.capital_base,
|
||||
starting_cash=self.capital_base,
|
||||
# the cumulative period will be calculated over the
|
||||
# entire test.
|
||||
self.period_start,
|
||||
self.period_end,
|
||||
period_open=self.period_start,
|
||||
period_close=self.period_end,
|
||||
# don't save the transactions for the cumulative
|
||||
# period
|
||||
keep_transactions=False,
|
||||
keep_orders=False,
|
||||
# don't serialize positions for cumualtive period
|
||||
serialize_positions=False
|
||||
serialize_positions=False,
|
||||
asset_finder=self.env.asset_finder,
|
||||
)
|
||||
self.minute_performance.position_tracker = self.position_tracker
|
||||
self.perf_periods.append(self.minute_performance)
|
||||
@@ -148,16 +150,17 @@ class PerformanceTracker(object):
|
||||
# inception.
|
||||
self.cumulative_performance = PerformancePeriod(
|
||||
# initial cash is your capital base.
|
||||
self.capital_base,
|
||||
starting_cash=self.capital_base,
|
||||
# the cumulative period will be calculated over the entire test.
|
||||
self.period_start,
|
||||
self.period_end,
|
||||
period_open=self.period_start,
|
||||
period_close=self.period_end,
|
||||
# don't save the transactions for the cumulative
|
||||
# period
|
||||
keep_transactions=False,
|
||||
keep_orders=False,
|
||||
# don't serialize positions for cumualtive period
|
||||
serialize_positions=False,
|
||||
asset_finder=self.env.asset_finder,
|
||||
)
|
||||
self.cumulative_performance.position_tracker = self.position_tracker
|
||||
self.perf_periods.append(self.cumulative_performance)
|
||||
@@ -165,13 +168,14 @@ class PerformanceTracker(object):
|
||||
# this performance period will span just the current market day
|
||||
self.todays_performance = PerformancePeriod(
|
||||
# initial cash is your capital base.
|
||||
self.capital_base,
|
||||
starting_cash=self.capital_base,
|
||||
# the daily period will be calculated for the market day
|
||||
self.market_open,
|
||||
self.market_close,
|
||||
period_open=self.market_open,
|
||||
period_close=self.market_close,
|
||||
keep_transactions=True,
|
||||
keep_orders=True,
|
||||
serialize_positions=True,
|
||||
asset_finder=self.env.asset_finder,
|
||||
)
|
||||
self.todays_performance.position_tracker = self.position_tracker
|
||||
|
||||
@@ -490,8 +494,7 @@ class PerformanceTracker(object):
|
||||
|
||||
# Get the next trading day and, if it is past the bounds of this
|
||||
# simulation, return the daily perf packet
|
||||
next_trading_day = TradingEnvironment.instance().\
|
||||
next_trading_day(completed_date)
|
||||
next_trading_day = self.env.next_trading_day(completed_date)
|
||||
|
||||
# Check if any assets need to be auto-closed before generating today's
|
||||
# perf period
|
||||
@@ -509,10 +512,9 @@ class PerformanceTracker(object):
|
||||
return daily_update
|
||||
|
||||
# move the market day markers forward
|
||||
env = TradingEnvironment.instance()
|
||||
self.market_open, self.market_close = \
|
||||
env.next_open_and_close(self.day)
|
||||
self.day = env.next_trading_day(self.day)
|
||||
self.env.next_open_and_close(self.day)
|
||||
self.day = self.env.next_trading_day(self.day)
|
||||
|
||||
# Roll over positions to current day.
|
||||
self.todays_performance.rollover()
|
||||
@@ -552,7 +554,8 @@ class PerformanceTracker(object):
|
||||
ars,
|
||||
self.sim_params,
|
||||
benchmark_returns=bms,
|
||||
algorithm_leverages=acl)
|
||||
algorithm_leverages=acl,
|
||||
env=self.env)
|
||||
|
||||
risk_dict = self.risk_report.to_dict()
|
||||
return risk_dict
|
||||
@@ -569,14 +572,14 @@ class PerformanceTracker(object):
|
||||
# we already store perf periods as attributes
|
||||
del state_dict['perf_periods']
|
||||
|
||||
STATE_VERSION = 3
|
||||
STATE_VERSION = 4
|
||||
state_dict[VERSION_LABEL] = STATE_VERSION
|
||||
|
||||
return state_dict
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
OLDEST_SUPPORTED_STATE = 3
|
||||
OLDEST_SUPPORTED_STATE = 4
|
||||
version = state.pop(VERSION_LABEL)
|
||||
|
||||
if version < OLDEST_SUPPORTED_STATE:
|
||||
|
||||
@@ -18,7 +18,6 @@ import logbook
|
||||
import math
|
||||
import numpy as np
|
||||
|
||||
from zipline.finance import trading
|
||||
import zipline.utils.math_utils as zp_math
|
||||
|
||||
import pandas as pd
|
||||
@@ -91,10 +90,10 @@ class RiskMetricsCumulative(object):
|
||||
'information',
|
||||
)
|
||||
|
||||
def __init__(self, sim_params,
|
||||
def __init__(self, sim_params, env,
|
||||
create_first_day_stats=False,
|
||||
account=None):
|
||||
self.treasury_curves = trading.environment.treasury_curves
|
||||
self.treasury_curves = env.treasury_curves
|
||||
self.start_date = sim_params.period_start.replace(
|
||||
hour=0, minute=0, second=0, microsecond=0
|
||||
)
|
||||
@@ -102,15 +101,12 @@ class RiskMetricsCumulative(object):
|
||||
hour=0, minute=0, second=0, microsecond=0
|
||||
)
|
||||
|
||||
self.trading_days = trading.environment.days_in_range(
|
||||
self.start_date,
|
||||
self.end_date)
|
||||
self.trading_days = env.days_in_range(self.start_date, self.end_date)
|
||||
|
||||
# Hold on to the trading day before the start,
|
||||
# used for index of the zero return value when forcing returns
|
||||
# on the first day.
|
||||
self.day_before_start = self.start_date - \
|
||||
trading.environment.trading_days.freq
|
||||
self.day_before_start = self.start_date - env.trading_days.freq
|
||||
|
||||
last_day = normalize_date(sim_params.period_end)
|
||||
if last_day not in self.trading_days:
|
||||
@@ -120,6 +116,7 @@ class RiskMetricsCumulative(object):
|
||||
self.trading_days = self.trading_days.append(last_day)
|
||||
|
||||
self.sim_params = sim_params
|
||||
self.env = env
|
||||
|
||||
self.create_first_day_stats = create_first_day_stats
|
||||
|
||||
@@ -276,7 +273,8 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}"
|
||||
treasury_period_return = choose_treasury(
|
||||
self.treasury_curves,
|
||||
self.start_date,
|
||||
treasury_end
|
||||
treasury_end,
|
||||
self.env,
|
||||
)
|
||||
self.daily_treasury[treasury_end] = treasury_period_return
|
||||
self.treasury_period_return = self.daily_treasury[treasury_end]
|
||||
@@ -459,18 +457,17 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}"
|
||||
return beta
|
||||
|
||||
def __getstate__(self):
|
||||
state_dict = \
|
||||
{k: v for k, v in iteritems(self.__dict__) if
|
||||
(not k.startswith('_') and not k == 'treasury_curves')}
|
||||
state_dict = {k: v for k, v in iteritems(self.__dict__)
|
||||
if not k.startswith('_')}
|
||||
|
||||
STATE_VERSION = 2
|
||||
STATE_VERSION = 3
|
||||
state_dict[VERSION_LABEL] = STATE_VERSION
|
||||
|
||||
return state_dict
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
OLDEST_SUPPORTED_STATE = 2
|
||||
OLDEST_SUPPORTED_STATE = 3
|
||||
version = state.pop(VERSION_LABEL)
|
||||
|
||||
if version < OLDEST_SUPPORTED_STATE:
|
||||
@@ -478,7 +475,3 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}"
|
||||
saved state is too old.")
|
||||
|
||||
self.__dict__.update(state)
|
||||
|
||||
# This are big and we don't need to serialize them
|
||||
# pop them back in now
|
||||
self.treasury_curves = trading.environment.treasury_curves
|
||||
|
||||
@@ -22,8 +22,6 @@ import numpy.linalg as la
|
||||
|
||||
from six import iteritems
|
||||
|
||||
from zipline.finance import trading
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from . import risk
|
||||
@@ -47,11 +45,11 @@ choose_treasury = functools.partial(risk.choose_treasury,
|
||||
|
||||
|
||||
class RiskMetricsPeriod(object):
|
||||
def __init__(self, start_date, end_date, returns,
|
||||
benchmark_returns=None,
|
||||
algorithm_leverages=None):
|
||||
def __init__(self, start_date, end_date, returns, env,
|
||||
benchmark_returns=None, algorithm_leverages=None):
|
||||
|
||||
treasury_curves = trading.environment.treasury_curves
|
||||
self.env = env
|
||||
treasury_curves = env.treasury_curves
|
||||
if treasury_curves.index[-1] >= start_date:
|
||||
mask = ((treasury_curves.index >= start_date) &
|
||||
(treasury_curves.index <= end_date))
|
||||
@@ -66,12 +64,14 @@ class RiskMetricsPeriod(object):
|
||||
self.end_date = end_date
|
||||
|
||||
if benchmark_returns is None:
|
||||
br = trading.environment.benchmark_returns
|
||||
br = env.benchmark_returns
|
||||
benchmark_returns = br[(br.index >= returns.index[0]) &
|
||||
(br.index <= returns.index[-1])]
|
||||
|
||||
self.algorithm_returns = self.mask_returns_to_period(returns)
|
||||
self.benchmark_returns = self.mask_returns_to_period(benchmark_returns)
|
||||
self.algorithm_returns = self.mask_returns_to_period(returns,
|
||||
env)
|
||||
self.benchmark_returns = self.mask_returns_to_period(benchmark_returns,
|
||||
env)
|
||||
self.algorithm_leverages = algorithm_leverages
|
||||
|
||||
self.calculate_metrics()
|
||||
@@ -114,7 +114,8 @@ class RiskMetricsPeriod(object):
|
||||
self.treasury_period_return = choose_treasury(
|
||||
self.treasury_curves,
|
||||
self.start_date,
|
||||
self.end_date
|
||||
self.end_date,
|
||||
self.env,
|
||||
)
|
||||
self.sharpe = self.calculate_sharpe()
|
||||
# The consumer currently expects a 0.0 value for sharpe in period,
|
||||
@@ -193,14 +194,14 @@ class RiskMetricsPeriod(object):
|
||||
|
||||
return '\n'.join(statements)
|
||||
|
||||
def mask_returns_to_period(self, daily_returns):
|
||||
def mask_returns_to_period(self, daily_returns, env):
|
||||
if isinstance(daily_returns, list):
|
||||
returns = pd.Series([x.returns for x in daily_returns],
|
||||
index=[x.date for x in daily_returns])
|
||||
else: # otherwise we're receiving an index already
|
||||
returns = daily_returns
|
||||
|
||||
trade_days = trading.environment.trading_days
|
||||
trade_days = env.trading_days
|
||||
trade_day_mask = returns.index.normalize().isin(trade_days)
|
||||
|
||||
mask = ((returns.index >= self.start_date) &
|
||||
@@ -321,18 +322,17 @@ class RiskMetricsPeriod(object):
|
||||
return max(self.algorithm_leverages)
|
||||
|
||||
def __getstate__(self):
|
||||
state_dict = \
|
||||
{k: v for k, v in iteritems(self.__dict__) if
|
||||
(not k.startswith('_') and not k == 'treasury_curves')}
|
||||
state_dict = {k: v for k, v in iteritems(self.__dict__)
|
||||
if not k.startswith('_')}
|
||||
|
||||
STATE_VERSION = 2
|
||||
STATE_VERSION = 3
|
||||
state_dict[VERSION_LABEL] = STATE_VERSION
|
||||
|
||||
return state_dict
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
OLDEST_SUPPORTED_STATE = 2
|
||||
OLDEST_SUPPORTED_STATE = 3
|
||||
version = state.pop(VERSION_LABEL)
|
||||
|
||||
if version < OLDEST_SUPPORTED_STATE:
|
||||
@@ -340,5 +340,3 @@ class RiskMetricsPeriod(object):
|
||||
is too old.")
|
||||
|
||||
self.__dict__.update(state)
|
||||
|
||||
self.treasury_curves = trading.environment.treasury_curves
|
||||
|
||||
@@ -72,7 +72,7 @@ log = logbook.Logger('Risk Report')
|
||||
|
||||
|
||||
class RiskReport(object):
|
||||
def __init__(self, algorithm_returns, sim_params,
|
||||
def __init__(self, algorithm_returns, sim_params, env,
|
||||
benchmark_returns=None, algorithm_leverages=None):
|
||||
"""
|
||||
algorithm_returns needs to be a list of daily_return objects
|
||||
@@ -84,6 +84,7 @@ class RiskReport(object):
|
||||
|
||||
self.algorithm_returns = algorithm_returns
|
||||
self.sim_params = sim_params
|
||||
self.env = env
|
||||
self.benchmark_returns = benchmark_returns
|
||||
self.algorithm_leverages = algorithm_leverages
|
||||
|
||||
@@ -144,6 +145,7 @@ class RiskReport(object):
|
||||
end_date=cur_end,
|
||||
returns=self.algorithm_returns,
|
||||
benchmark_returns=self.benchmark_returns,
|
||||
env=self.env,
|
||||
algorithm_leverages=self.algorithm_leverages,
|
||||
)
|
||||
|
||||
@@ -160,14 +162,14 @@ class RiskReport(object):
|
||||
if '_dividend_count' in dir(self):
|
||||
state_dict['_dividend_count'] = self._dividend_count
|
||||
|
||||
STATE_VERSION = 1
|
||||
STATE_VERSION = 2
|
||||
state_dict[VERSION_LABEL] = STATE_VERSION
|
||||
|
||||
return state_dict
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
OLDEST_SUPPORTED_STATE = 1
|
||||
OLDEST_SUPPORTED_STATE = 2
|
||||
version = state.pop(VERSION_LABEL)
|
||||
|
||||
if version < OLDEST_SUPPORTED_STATE:
|
||||
|
||||
@@ -62,7 +62,6 @@ import logbook
|
||||
import math
|
||||
import numpy as np
|
||||
|
||||
from zipline.finance import trading
|
||||
import zipline.utils.math_utils as zp_math
|
||||
|
||||
log = logbook.Logger('Risk')
|
||||
@@ -203,8 +202,8 @@ def get_treasury_rate(treasury_curves, treasury_duration, day):
|
||||
return rate
|
||||
|
||||
|
||||
def search_day_distance(end_date, dt):
|
||||
tdd = trading.environment.trading_day_distance(dt, end_date)
|
||||
def search_day_distance(end_date, dt, env):
|
||||
tdd = env.trading_day_distance(dt, end_date)
|
||||
if tdd is None:
|
||||
return None
|
||||
assert tdd >= 0
|
||||
@@ -238,7 +237,7 @@ def select_treasury_duration(start_date, end_date):
|
||||
|
||||
|
||||
def choose_treasury(select_treasury, treasury_curves, start_date, end_date,
|
||||
compound=True):
|
||||
env, compound=True):
|
||||
"""
|
||||
Find the latest known interest rate for a given duration within a date
|
||||
range.
|
||||
@@ -270,7 +269,7 @@ def choose_treasury(select_treasury, treasury_curves, start_date, end_date,
|
||||
prev_day)
|
||||
if rate is not None:
|
||||
search_day = prev_day
|
||||
search_dist = search_day_distance(end_date, prev_day)
|
||||
search_dist = search_day_distance(end_date, prev_day, env)
|
||||
break
|
||||
|
||||
if search_day:
|
||||
|
||||
+25
-95
@@ -16,7 +16,6 @@
|
||||
import bisect
|
||||
import logbook
|
||||
import datetime
|
||||
from functools import wraps
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
@@ -51,40 +50,17 @@ log = logbook.Logger('Trading')
|
||||
# for serialization and storage, and the timezone is used to
|
||||
# ensure proper rollover through daylight savings and so on.
|
||||
#
|
||||
# This module maintains a global variable, environment, which is
|
||||
# subsequently referenced directly by zipline financial
|
||||
# components. To set the environment, you can set the property on
|
||||
# the module directly:
|
||||
# from zipline.finance import trading
|
||||
# trading.environment = TradingEnvironment()
|
||||
#
|
||||
# or if you want to switch the environment for a limited context
|
||||
# you can use a TradingEnvironment in a with clause:
|
||||
# lse = TradingEnvironment(bm_index="^FTSE", exchange_tz="Europe/London")
|
||||
# with lse:
|
||||
# the code here will have lse as the global trading.environment
|
||||
# algo.run(start, end)
|
||||
#
|
||||
# User code will not normally need to use TradingEnvironment
|
||||
# directly. If you are extending zipline's core financial
|
||||
# compponents and need to use the environment, you must import the module
|
||||
# NOT the variable. If you import the module, you will get a
|
||||
# reference to the environment at import time, which will prevent
|
||||
# your code from responding to user code that changes the global
|
||||
# state.
|
||||
|
||||
environment = None
|
||||
|
||||
# components and need to use the environment, you must import the module and
|
||||
# build a new TradingEnvironment object, then pass that TradingEnvironment as
|
||||
# the 'env' arg to your TradingAlgorithm.
|
||||
|
||||
class TradingEnvironment(object):
|
||||
|
||||
@classmethod
|
||||
def instance(cls):
|
||||
global environment
|
||||
if not environment:
|
||||
environment = TradingEnvironment()
|
||||
|
||||
return environment
|
||||
# Token used as a substitute for pickling objects that contain a
|
||||
# reference to a TradingEnvironment
|
||||
PERSISTENT_TOKEN = "<TradingEnvironment>"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -140,21 +116,6 @@ class TradingEnvironment(object):
|
||||
AssetDBWriterFromDictionary().init_db(engine)
|
||||
self.asset_finder = AssetFinder(engine)
|
||||
|
||||
def __enter__(self, *args, **kwargs):
|
||||
global environment
|
||||
self.prev_environment = environment
|
||||
environment = self
|
||||
# return value here is associated with "as such_and_such" on the
|
||||
# with clause.
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
global environment
|
||||
environment = self.prev_environment
|
||||
# signal that any exceptions need to be propagated up the
|
||||
# stack.
|
||||
return False
|
||||
|
||||
def write_data(self,
|
||||
engine=None,
|
||||
equities_data={},
|
||||
@@ -486,7 +447,8 @@ class SimulationParameters(object):
|
||||
def __init__(self, period_start, period_end,
|
||||
capital_base=10e3,
|
||||
emission_rate='daily',
|
||||
data_frequency='daily'):
|
||||
data_frequency='daily',
|
||||
env=None):
|
||||
|
||||
self.period_start = period_start
|
||||
self.period_end = period_end
|
||||
@@ -498,55 +460,53 @@ class SimulationParameters(object):
|
||||
# copied to algorithm's environment for runtime access
|
||||
self.arena = 'backtest'
|
||||
|
||||
self._update_internal()
|
||||
if env is not None:
|
||||
self.update_internal_from_env(env=env)
|
||||
|
||||
def _update_internal(self):
|
||||
# This is the global environment for trading simulation.
|
||||
environment = TradingEnvironment.instance()
|
||||
def update_internal_from_env(self, env):
|
||||
|
||||
assert self.period_start <= self.period_end, \
|
||||
"Period start falls after period end."
|
||||
|
||||
assert self.period_start <= environment.last_trading_day, \
|
||||
assert self.period_start <= env.last_trading_day, \
|
||||
"Period start falls after the last known trading day."
|
||||
assert self.period_end >= environment.first_trading_day, \
|
||||
assert self.period_end >= env.first_trading_day, \
|
||||
"Period end falls before the first known trading day."
|
||||
|
||||
self.first_open = self.calculate_first_open()
|
||||
self.last_close = self.calculate_last_close()
|
||||
start_index = \
|
||||
environment.get_index(self.first_open)
|
||||
end_index = environment.get_index(self.last_close)
|
||||
self.first_open = self._calculate_first_open(env)
|
||||
self.last_close = self._calculate_last_close(env)
|
||||
|
||||
start_index = env.get_index(self.first_open)
|
||||
end_index = env.get_index(self.last_close)
|
||||
|
||||
# take an inclusive slice of the environment's
|
||||
# trading_days.
|
||||
self.trading_days = \
|
||||
environment.trading_days[start_index:end_index + 1]
|
||||
self.trading_days = env.trading_days[start_index:end_index + 1]
|
||||
|
||||
def calculate_first_open(self):
|
||||
def _calculate_first_open(self, env):
|
||||
"""
|
||||
Finds the first trading day on or after self.period_start.
|
||||
"""
|
||||
first_open = self.period_start
|
||||
one_day = datetime.timedelta(days=1)
|
||||
|
||||
while not environment.is_trading_day(first_open):
|
||||
while not env.is_trading_day(first_open):
|
||||
first_open = first_open + one_day
|
||||
|
||||
mkt_open, _ = environment.get_open_and_close(first_open)
|
||||
mkt_open, _ = env.get_open_and_close(first_open)
|
||||
return mkt_open
|
||||
|
||||
def calculate_last_close(self):
|
||||
def _calculate_last_close(self, env):
|
||||
"""
|
||||
Finds the last trading day on or before self.period_end
|
||||
"""
|
||||
last_close = self.period_end
|
||||
one_day = datetime.timedelta(days=1)
|
||||
|
||||
while not environment.is_trading_day(last_close):
|
||||
while not env.is_trading_day(last_close):
|
||||
last_close = last_close - one_day
|
||||
|
||||
_, mkt_close = environment.get_open_and_close(last_close)
|
||||
_, mkt_close = env.get_open_and_close(last_close)
|
||||
return mkt_close
|
||||
|
||||
@property
|
||||
@@ -572,33 +532,3 @@ class SimulationParameters(object):
|
||||
emission_rate=self.emission_rate,
|
||||
first_open=self.first_open,
|
||||
last_close=self.last_close)
|
||||
|
||||
|
||||
def with_environment(asname='env'):
|
||||
"""
|
||||
Decorator to automagically pass TradingEnvironment to the function
|
||||
under the name asname. If the environment is passed explicitly as a keyword
|
||||
then the explicitly passed value will be used instead.
|
||||
|
||||
usage:
|
||||
with_environment()
|
||||
def f(env=None):
|
||||
pass
|
||||
|
||||
with_environment(asname='my_env')
|
||||
def g(my_env=None):
|
||||
pass
|
||||
"""
|
||||
def with_environment_decorator(f):
|
||||
@wraps(f)
|
||||
def wrapper(*args, **kwargs):
|
||||
# inject env into the namespace for the function.
|
||||
# This doesn't use setdefault so that grabbing the trading env
|
||||
# is lazy.
|
||||
if asname not in kwargs:
|
||||
kwargs[asname] = TradingEnvironment.instance()
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return with_environment_decorator
|
||||
|
||||
@@ -20,7 +20,7 @@ from pandas.tslib import normalize_date
|
||||
|
||||
from zipline.utils.api_support import ZiplineAPI
|
||||
|
||||
from zipline.finance import trading
|
||||
from zipline.finance.trading import NoFurtherDataError
|
||||
from zipline.protocol import (
|
||||
BarData,
|
||||
SIDData,
|
||||
@@ -50,6 +50,7 @@ class AlgorithmSimulator(object):
|
||||
# ==============
|
||||
self.algo = algo
|
||||
self.algo_start = normalize_date(self.sim_params.first_open)
|
||||
self.env = algo.trading_environment
|
||||
|
||||
# ==============
|
||||
# Snapshot Setup
|
||||
@@ -132,10 +133,9 @@ class AlgorithmSimulator(object):
|
||||
mkt_close < self.algo.perf_tracker.last_close
|
||||
try:
|
||||
mkt_open, mkt_close = \
|
||||
trading.environment \
|
||||
.next_open_and_close(mkt_close)
|
||||
self.env.next_open_and_close(mkt_close)
|
||||
|
||||
except trading.NoFurtherDataError:
|
||||
except NoFurtherDataError:
|
||||
# If at the end of backtest history,
|
||||
# skip advancing market close.
|
||||
pass
|
||||
@@ -144,7 +144,7 @@ class AlgorithmSimulator(object):
|
||||
self._call_before_trading_start(mkt_open)
|
||||
|
||||
elif data_frequency == 'daily':
|
||||
next_day = trading.environment.next_trading_day(date)
|
||||
next_day = self.env.next_trading_day(date)
|
||||
|
||||
if next_day is not None and \
|
||||
next_day < self.algo.perf_tracker.last_close:
|
||||
|
||||
+28
-43
@@ -19,8 +19,6 @@ import numpy as np
|
||||
import pandas as pd
|
||||
import re
|
||||
|
||||
from zipline.finance import trading
|
||||
from zipline.finance.trading import with_environment
|
||||
from zipline.errors import IncompatibleHistoryFrequency
|
||||
|
||||
|
||||
@@ -45,7 +43,7 @@ class Frequency(object):
|
||||
MAX_MINUTES = {'m': 1, 'd': 390}
|
||||
MAX_DAYS = {'d': 1}
|
||||
|
||||
def __init__(self, freq_str, data_frequency):
|
||||
def __init__(self, freq_str, data_frequency, env):
|
||||
|
||||
if freq_str not in self.SUPPORTED_FREQUENCIES:
|
||||
raise ValueError(
|
||||
@@ -61,6 +59,7 @@ class Frequency(object):
|
||||
self.num, self.unit_str = parse_freq_str(freq_str)
|
||||
|
||||
self.data_frequency = data_frequency
|
||||
self.env = env
|
||||
|
||||
def next_window_start(self, previous_window_close):
|
||||
"""
|
||||
@@ -68,35 +67,25 @@ class Frequency(object):
|
||||
finished on @previous_window_close.
|
||||
"""
|
||||
if self.unit_str == 'd':
|
||||
return self.next_day_window_start(previous_window_close,
|
||||
return self.next_day_window_start(previous_window_close, self.env,
|
||||
self.data_frequency)
|
||||
elif self.unit_str == 'm':
|
||||
return self.next_minute_window_start(previous_window_close)
|
||||
return self.env.next_market_minute(previous_window_close)
|
||||
|
||||
@staticmethod
|
||||
def next_day_window_start(previous_window_close, data_frequency='minute'):
|
||||
def next_day_window_start(previous_window_close, env,
|
||||
data_frequency='minute'):
|
||||
"""
|
||||
Get the next day window start after @previous_window_close. This is
|
||||
defined as the first market open strictly greater than
|
||||
@previous_window_close.
|
||||
"""
|
||||
env = trading.environment
|
||||
if data_frequency == 'daily':
|
||||
next_open = env.next_trading_day(previous_window_close)
|
||||
else:
|
||||
next_open = env.next_market_minute(previous_window_close)
|
||||
return next_open
|
||||
|
||||
@staticmethod
|
||||
def next_minute_window_start(previous_window_close):
|
||||
"""
|
||||
Get the next minute window start after @previous_window_close. This is
|
||||
defined as the first market minute strictly greater than
|
||||
@previous_window_close.
|
||||
"""
|
||||
env = trading.environment
|
||||
return env.next_market_minute(previous_window_close)
|
||||
|
||||
def window_open(self, window_close):
|
||||
"""
|
||||
For a period ending on `window_end`, calculate the date of the first
|
||||
@@ -123,8 +112,7 @@ class Frequency(object):
|
||||
minute @window_close. This is calculated by searching backward until
|
||||
@num_days market_closes are encountered.
|
||||
"""
|
||||
env = trading.environment
|
||||
open_ = env.open_close_window(
|
||||
open_ = self.env.open_close_window(
|
||||
window_close,
|
||||
1,
|
||||
offset=-(num_days - 1)
|
||||
@@ -147,8 +135,9 @@ class Frequency(object):
|
||||
# Short circuit this case.
|
||||
return window_close
|
||||
|
||||
env = trading.environment
|
||||
return env.market_minute_window(window_close, count=-num_minutes)[-1]
|
||||
return self.env.market_minute_window(
|
||||
window_close, count=-num_minutes
|
||||
)[-1]
|
||||
|
||||
def day_window_close(self, window_start, num_days):
|
||||
"""
|
||||
@@ -159,15 +148,13 @@ class Frequency(object):
|
||||
If the data_frequency is minute, this will be midnight utc of the last
|
||||
day of the window.
|
||||
"""
|
||||
env = trading.environment
|
||||
|
||||
if self.data_frequency != 'daily':
|
||||
return env.get_open_and_close(
|
||||
env.add_trading_days(num_days - 1, window_start),
|
||||
return self.env.get_open_and_close(
|
||||
self.env.add_trading_days(num_days - 1, window_start),
|
||||
)[1]
|
||||
|
||||
return pd.tslib.normalize_date(
|
||||
env.add_trading_days(num_days - 1, window_start),
|
||||
self.env.add_trading_days(num_days - 1, window_start),
|
||||
)
|
||||
|
||||
def minute_window_close(self, window_start, num_minutes):
|
||||
@@ -182,23 +169,23 @@ class Frequency(object):
|
||||
# Short circuit this case.
|
||||
return window_start
|
||||
|
||||
env = trading.environment
|
||||
return env.market_minute_window(window_start, count=num_minutes)[-1]
|
||||
return self.env.market_minute_window(
|
||||
window_start, count=num_minutes
|
||||
)[-1]
|
||||
|
||||
@with_environment()
|
||||
def prev_bar(self, dt, env=None):
|
||||
def prev_bar(self, dt):
|
||||
"""
|
||||
Returns the previous bar for dt.
|
||||
"""
|
||||
if self.unit_str == 'd':
|
||||
if self.data_frequency == 'minute':
|
||||
def func(dt):
|
||||
return env.get_open_and_close(
|
||||
env.previous_trading_day(dt))[1]
|
||||
return self.env.get_open_and_close(
|
||||
self.env.previous_trading_day(dt))[1]
|
||||
else:
|
||||
func = env.previous_trading_day
|
||||
func = self.env.previous_trading_day
|
||||
else:
|
||||
func = env.previous_market_minute
|
||||
func = self.env.previous_market_minute
|
||||
|
||||
# Cache the function dispatch.
|
||||
self.prev_bar = func
|
||||
@@ -262,13 +249,13 @@ class HistorySpec(object):
|
||||
return "{0}:{1}:{2}:{3}".format(
|
||||
bar_count, freq_str, field, ffill)
|
||||
|
||||
def __init__(self, bar_count, frequency, field, ffill,
|
||||
def __init__(self, bar_count, frequency, field, ffill, env,
|
||||
data_frequency='daily'):
|
||||
|
||||
# Number of bars to look back.
|
||||
self.bar_count = bar_count
|
||||
if isinstance(frequency, str):
|
||||
frequency = Frequency(frequency, data_frequency)
|
||||
frequency = Frequency(frequency, data_frequency, env)
|
||||
if frequency.unit_str == 'm' and data_frequency == 'daily':
|
||||
raise IncompatibleHistoryFrequency(
|
||||
frequency=frequency.unit_str,
|
||||
@@ -299,12 +286,11 @@ class HistorySpec(object):
|
||||
return ''.join([self.__class__.__name__, "('", self.key_str, "')"])
|
||||
|
||||
|
||||
def days_index_at_dt(history_spec, algo_dt):
|
||||
def days_index_at_dt(history_spec, algo_dt, env):
|
||||
"""
|
||||
Get the index of a frame to be used for a get_history call with daily
|
||||
frequency.
|
||||
"""
|
||||
env = trading.environment
|
||||
# Get the previous (bar_count - 1) days' worth of market closes.
|
||||
day_delta = (history_spec.bar_count - 1) * history_spec.frequency.num
|
||||
market_closes = env.open_close_window(
|
||||
@@ -323,13 +309,12 @@ def days_index_at_dt(history_spec, algo_dt):
|
||||
return np.append(market_closes.values, algo_dt)
|
||||
|
||||
|
||||
def minutes_index_at_dt(history_spec, algo_dt):
|
||||
def minutes_index_at_dt(history_spec, algo_dt, env):
|
||||
"""
|
||||
Get the index of a frame to be used for a get_history_call with minutely
|
||||
frequency.
|
||||
"""
|
||||
# TODO: This is almost certainly going to be too slow for production.
|
||||
env = trading.environment
|
||||
return env.market_minute_window(
|
||||
algo_dt,
|
||||
history_spec.bar_count,
|
||||
@@ -337,7 +322,7 @@ def minutes_index_at_dt(history_spec, algo_dt):
|
||||
)[::-1]
|
||||
|
||||
|
||||
def index_at_dt(history_spec, algo_dt):
|
||||
def index_at_dt(history_spec, algo_dt, env):
|
||||
"""
|
||||
Returns index of a frame returned by get_history() with the given
|
||||
history_spec and algo_dt.
|
||||
@@ -352,6 +337,6 @@ def index_at_dt(history_spec, algo_dt):
|
||||
"""
|
||||
frequency = history_spec.frequency
|
||||
if frequency.unit_str == 'd':
|
||||
return days_index_at_dt(history_spec, algo_dt)
|
||||
return days_index_at_dt(history_spec, algo_dt, env)
|
||||
elif frequency.unit_str == 'm':
|
||||
return minutes_index_at_dt(history_spec, algo_dt)
|
||||
return minutes_index_at_dt(history_spec, algo_dt, env)
|
||||
|
||||
@@ -23,7 +23,6 @@ from six import itervalues, iteritems, iterkeys
|
||||
|
||||
from . history import HistorySpec
|
||||
|
||||
from zipline.finance.trading import with_environment
|
||||
from zipline.utils.data import RollingPanel, _ensure_index
|
||||
from zipline.utils.munge import ffill, bfill
|
||||
|
||||
@@ -112,7 +111,6 @@ def freq_str_and_bar_count(history_spec):
|
||||
return (history_spec.frequency.freq_str, history_spec.bar_count)
|
||||
|
||||
|
||||
@with_environment()
|
||||
def next_bar(spec, env):
|
||||
"""
|
||||
Returns a function that will return the next bar for a given datetime.
|
||||
@@ -208,6 +206,7 @@ class HistoryContainer(object):
|
||||
initial_sids,
|
||||
initial_dt,
|
||||
data_frequency,
|
||||
env,
|
||||
bar_data=None):
|
||||
"""
|
||||
A container to hold a rolling window of historical data within a user's
|
||||
@@ -229,6 +228,9 @@ class HistoryContainer(object):
|
||||
An instance of a new HistoryContainer
|
||||
"""
|
||||
|
||||
# Store a reference to the env
|
||||
self.env = env
|
||||
|
||||
# History specs to be served by this container.
|
||||
self.history_specs = history_specs
|
||||
self.largest_specs = compute_largest_specs(
|
||||
@@ -315,8 +317,7 @@ class HistoryContainer(object):
|
||||
"""
|
||||
return iterkeys(self.largest_specs)
|
||||
|
||||
@with_environment()
|
||||
def _add_frequency(self, spec, dt, data, env=None):
|
||||
def _add_frequency(self, spec, dt, data):
|
||||
"""
|
||||
Adds a new frequency to the container. This reshapes the buffer_panel
|
||||
if needed.
|
||||
@@ -350,9 +351,7 @@ class HistoryContainer(object):
|
||||
|
||||
if spec.bar_count > 1:
|
||||
# This spec has more than one bar, construct a digest panel for it.
|
||||
self.digest_panels[freq] = self._create_digest_panel(
|
||||
dt, spec=spec, env=env,
|
||||
)
|
||||
self.digest_panels[freq] = self._create_digest_panel(dt, spec=spec)
|
||||
else:
|
||||
self.cur_window_starts[freq] = dt
|
||||
self.cur_window_closes[freq] = freq.window_close(
|
||||
@@ -383,8 +382,7 @@ class HistoryContainer(object):
|
||||
)
|
||||
return field
|
||||
|
||||
@with_environment()
|
||||
def _add_length(self, spec, dt, env=None):
|
||||
def _add_length(self, spec, dt):
|
||||
"""
|
||||
Increases the length of the digest panel for spec.frequency. If this
|
||||
does not have a panel, and one is needed; a digest panel will be
|
||||
@@ -399,21 +397,17 @@ class HistoryContainer(object):
|
||||
if panel is None:
|
||||
# The old length for this frequency was 1 bar, meaning no digest
|
||||
# panel was held. We must construct a new one here.
|
||||
panel = self._create_digest_panel(
|
||||
dt, spec=spec, env=env,
|
||||
)
|
||||
panel = self._create_digest_panel(dt, spec=spec)
|
||||
|
||||
else:
|
||||
self._resize_panel(
|
||||
panel, spec.bar_count - 1, dt, freq=spec.frequency, env=env,
|
||||
)
|
||||
self._resize_panel(panel, spec.bar_count - 1, dt,
|
||||
freq=spec.frequency)
|
||||
|
||||
self.digest_panels[spec.frequency] = panel
|
||||
|
||||
return LengthDelta(spec.frequency, delta)
|
||||
|
||||
@with_environment()
|
||||
def _resize_panel(self, panel, size, dt, freq, env=None):
|
||||
def _resize_panel(self, panel, size, dt, freq):
|
||||
"""
|
||||
Resizes a panel, fills the date_buf with the correct values.
|
||||
"""
|
||||
@@ -429,26 +423,24 @@ class HistoryContainer(object):
|
||||
|
||||
panel.extend_back(missing_dts)
|
||||
|
||||
@with_environment()
|
||||
def _create_window_date_buf(self,
|
||||
window,
|
||||
unit_str,
|
||||
data_frequency,
|
||||
dt,
|
||||
env=None):
|
||||
dt):
|
||||
"""
|
||||
Creates a window length date_buf looking backwards from dt.
|
||||
"""
|
||||
if unit_str == 'd':
|
||||
# Get the properly key'd datetime64 out of the pandas Timestamp
|
||||
if data_frequency != 'daily':
|
||||
arr = env.open_close_window(
|
||||
arr = self.env.open_close_window(
|
||||
dt,
|
||||
window,
|
||||
offset=-window,
|
||||
).market_close.astype('datetime64[ns]').values
|
||||
else:
|
||||
arr = env.open_close_window(
|
||||
arr = self.env.open_close_window(
|
||||
dt,
|
||||
window,
|
||||
offset=-window,
|
||||
@@ -456,14 +448,13 @@ class HistoryContainer(object):
|
||||
|
||||
return arr
|
||||
else:
|
||||
return env.market_minute_window(
|
||||
env.previous_market_minute(dt),
|
||||
return self.env.market_minute_window(
|
||||
self.env.previous_market_minute(dt),
|
||||
window,
|
||||
step=-1,
|
||||
)[::-1].values
|
||||
|
||||
@with_environment()
|
||||
def _create_panel(self, dt, spec, env=None):
|
||||
def _create_panel(self, dt, spec):
|
||||
"""
|
||||
Constructs a rolling panel with a properly aligned date_buf.
|
||||
"""
|
||||
@@ -476,7 +467,6 @@ class HistoryContainer(object):
|
||||
spec.frequency.unit_str,
|
||||
spec.frequency.data_frequency,
|
||||
dt,
|
||||
env=env,
|
||||
)
|
||||
|
||||
panel = RollingPanel(
|
||||
@@ -488,13 +478,11 @@ class HistoryContainer(object):
|
||||
|
||||
return panel
|
||||
|
||||
@with_environment()
|
||||
def _create_digest_panel(self,
|
||||
dt,
|
||||
spec,
|
||||
window_starts=None,
|
||||
window_closes=None,
|
||||
env=None):
|
||||
window_closes=None):
|
||||
"""
|
||||
Creates a digest panel, setting the window_starts and window_closes.
|
||||
If window_starts or window_closes are None, then self.cur_window_starts
|
||||
@@ -510,7 +498,7 @@ class HistoryContainer(object):
|
||||
window_starts[freq] = freq.normalize(dt)
|
||||
window_closes[freq] = freq.window_close(window_starts[freq])
|
||||
|
||||
return self._create_panel(dt, spec, env=env)
|
||||
return self._create_panel(dt, spec)
|
||||
|
||||
def ensure_spec(self, spec, dt, bar_data):
|
||||
"""
|
||||
@@ -565,11 +553,9 @@ class HistoryContainer(object):
|
||||
for panel in self.all_panels:
|
||||
panel.set_items(self.fields)
|
||||
|
||||
@with_environment()
|
||||
def create_digest_panels(self,
|
||||
initial_sids,
|
||||
initial_dt,
|
||||
env=None):
|
||||
initial_dt):
|
||||
"""
|
||||
Initialize a RollingPanel for each unique panel frequency being stored
|
||||
by this container. Each RollingPanel pre-allocates enough storage
|
||||
@@ -601,7 +587,6 @@ class HistoryContainer(object):
|
||||
spec=largest_spec,
|
||||
window_starts=first_window_starts,
|
||||
window_closes=first_window_closes,
|
||||
env=env,
|
||||
)
|
||||
|
||||
panels[freq] = rp
|
||||
@@ -618,7 +603,8 @@ class HistoryContainer(object):
|
||||
)
|
||||
freq = '1m' if self.data_frequency == 'minute' else '1d'
|
||||
spec = HistorySpec(
|
||||
max_bars_needed + 1, freq, None, None, self.data_frequency,
|
||||
max_bars_needed + 1, freq, None, None, self.env,
|
||||
self.data_frequency,
|
||||
)
|
||||
|
||||
rp = self._create_panel(
|
||||
|
||||
+2
-3
@@ -23,7 +23,6 @@ import numpy as np
|
||||
from . utils.protocol_utils import Enum
|
||||
from . utils.math_utils import nanstd, nanmean, nansum
|
||||
|
||||
from zipline.finance.trading import with_environment
|
||||
from zipline.utils.algo_instance import get_algo_instance
|
||||
from zipline.utils.serialization_utils import (
|
||||
VERSION_LABEL
|
||||
@@ -400,8 +399,7 @@ class SIDData(object):
|
||||
def daily_get_bars(days):
|
||||
return days
|
||||
|
||||
@with_environment()
|
||||
def minute_get_bars(days, env=None):
|
||||
def minute_get_bars(days):
|
||||
cls = self.__class__
|
||||
|
||||
now = get_algo_instance().datetime
|
||||
@@ -412,6 +410,7 @@ class SIDData(object):
|
||||
if days not in cls._minute_bar_cache:
|
||||
# Cache this calculation to happen once per bar, even if we
|
||||
# use another transform with the same number of days.
|
||||
env = get_algo_instance().trading_environment
|
||||
prev = env.previous_trading_day(now)
|
||||
ds = env.days_in_range(
|
||||
env.add_trading_days(-days + 2, prev),
|
||||
|
||||
@@ -30,7 +30,6 @@ from zipline.protocol import (
|
||||
DATASOURCE_TYPE
|
||||
)
|
||||
from zipline.gens.utils import hash_args
|
||||
from zipline.finance.trading import with_environment
|
||||
|
||||
|
||||
def create_trade(sid, price, amount, datetime, source_id="test_factory"):
|
||||
@@ -51,12 +50,11 @@ def create_trade(sid, price, amount, datetime, source_id="test_factory"):
|
||||
return trade
|
||||
|
||||
|
||||
@with_environment()
|
||||
def date_gen(start,
|
||||
end,
|
||||
env,
|
||||
delta=timedelta(minutes=1),
|
||||
repeats=None,
|
||||
env=None):
|
||||
repeats=None):
|
||||
"""
|
||||
Utility to generate a stream of dates.
|
||||
"""
|
||||
@@ -111,11 +109,12 @@ class SpecificEquityTrades(object):
|
||||
delta : timedelta between internal events
|
||||
filter : filter to remove the sids
|
||||
"""
|
||||
@with_environment()
|
||||
def __init__(self, env=None, *args, **kwargs):
|
||||
def __init__(self, env, *args, **kwargs):
|
||||
# We shouldn't get any positional arguments.
|
||||
assert len(args) == 0
|
||||
|
||||
self.env = env
|
||||
|
||||
# Default to None for event_list and filter.
|
||||
self.event_list = kwargs.get('event_list')
|
||||
self.filter = kwargs.get('filter')
|
||||
@@ -206,12 +205,14 @@ class SpecificEquityTrades(object):
|
||||
end=self.end,
|
||||
delta=self.delta,
|
||||
repeats=len(self.sids),
|
||||
env=self.env,
|
||||
)
|
||||
else:
|
||||
date_generator = date_gen(
|
||||
start=self.start,
|
||||
end=self.end,
|
||||
delta=self.delta
|
||||
delta=self.delta,
|
||||
env=self.env,
|
||||
)
|
||||
|
||||
source_id = self.get_hash()
|
||||
|
||||
@@ -34,8 +34,12 @@ from six import (
|
||||
|
||||
from zipline.utils.data import MutableIndexRollingPanel
|
||||
from zipline.protocol import Event
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
|
||||
from zipline.finance import trading
|
||||
# HACK the BatchTransform module stores a trading environment to be used by
|
||||
# the transforms
|
||||
# TODO remove this hack, if not this whole module
|
||||
_batch_transform_env = TradingEnvironment()
|
||||
|
||||
log = logbook.Logger('BatchTransform')
|
||||
func_map = {'open_price': 'first',
|
||||
@@ -67,8 +71,8 @@ def downsample_panel(minute_rp, daily_rp, mkt_close):
|
||||
cur_panel = minute_rp.get_current()
|
||||
sids = minute_rp.minor_axis
|
||||
day_frame = pd.DataFrame(columns=sids, index=cur_panel.items)
|
||||
dt1 = trading.environment.normalize_date(mkt_close)
|
||||
dt2 = trading.environment.next_trading_day(mkt_close)
|
||||
dt1 = _batch_transform_env.normalize_date(mkt_close)
|
||||
dt2 = _batch_transform_env.next_trading_day(mkt_close)
|
||||
by_close = functools.partial(get_date, mkt_close, dt1, dt2)
|
||||
for item in minute_rp.items:
|
||||
frame = cur_panel[item]
|
||||
@@ -333,11 +337,11 @@ class BatchTransform(object):
|
||||
# we may get events from non-trading sources which occurr on
|
||||
# non-trading days. The book-keeping for market close and
|
||||
# trading day counting should only consider trading days.
|
||||
if trading.environment.is_trading_day(event.dt):
|
||||
_, mkt_close = trading.environment.get_open_and_close(event.dt)
|
||||
if _batch_transform_env.is_trading_day(event.dt):
|
||||
_, mkt_close = _batch_transform_env.get_open_and_close(event.dt)
|
||||
if self.bars == 'daily':
|
||||
# Daily bars have their dt set to midnight.
|
||||
mkt_close = trading.environment.normalize_date(mkt_close)
|
||||
mkt_close = _batch_transform_env.normalize_date(mkt_close)
|
||||
if event.dt == mkt_close:
|
||||
if self.downsample:
|
||||
downsample_panel(self.rolling_panel,
|
||||
|
||||
+51
-56
@@ -20,8 +20,6 @@ import datetime
|
||||
import pandas as pd
|
||||
import pytz
|
||||
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
|
||||
|
||||
__all__ = [
|
||||
'EventManager',
|
||||
@@ -191,7 +189,7 @@ class EventManager(object):
|
||||
|
||||
def handle_data(self, context, data, dt):
|
||||
for event in self._events:
|
||||
event.handle_data(context, data, dt)
|
||||
event.handle_data(context, data, dt, context.trading_environment)
|
||||
|
||||
|
||||
class Event(namedtuple('Event', ['rule', 'callback'])):
|
||||
@@ -204,11 +202,11 @@ class Event(namedtuple('Event', ['rule', 'callback'])):
|
||||
callback = callback or (lambda *args, **kwargs: None)
|
||||
return super(cls, cls).__new__(cls, rule=rule, callback=callback)
|
||||
|
||||
def handle_data(self, context, data, dt):
|
||||
def handle_data(self, context, data, dt, env):
|
||||
"""
|
||||
Calls the callable only when the rule is triggered.
|
||||
"""
|
||||
if self.rule.should_trigger(dt):
|
||||
if self.rule.should_trigger(dt, env):
|
||||
self.callback(context, data)
|
||||
|
||||
|
||||
@@ -216,12 +214,8 @@ class EventRule(six.with_metaclass(ABCMeta)):
|
||||
"""
|
||||
An event rule checks a datetime and sees if it should trigger.
|
||||
"""
|
||||
@property
|
||||
def env(self):
|
||||
return TradingEnvironment.instance()
|
||||
|
||||
@abstractmethod
|
||||
def should_trigger(self, dt):
|
||||
def should_trigger(self, dt, env):
|
||||
"""
|
||||
Checks if the rule should trigger with it's current state.
|
||||
This method should be pure and NOT mutate any state on the object.
|
||||
@@ -267,7 +261,7 @@ class ComposedRule(StatelessRule):
|
||||
self.second = second
|
||||
self.composer = composer
|
||||
|
||||
def should_trigger(self, dt):
|
||||
def should_trigger(self, dt, env):
|
||||
"""
|
||||
Composes the two rules with a lazy composer.
|
||||
"""
|
||||
@@ -275,15 +269,16 @@ class ComposedRule(StatelessRule):
|
||||
self.first.should_trigger,
|
||||
self.second.should_trigger,
|
||||
dt,
|
||||
env,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def lazy_and(first_should_trigger, second_should_trigger, dt):
|
||||
def lazy_and(first_should_trigger, second_should_trigger, dt, env):
|
||||
"""
|
||||
Lazily ands the two rules. This will NOT call the should_trigger of the
|
||||
second rule if the first one returns False.
|
||||
"""
|
||||
return first_should_trigger(dt) and second_should_trigger(dt)
|
||||
return first_should_trigger(dt, env) and second_should_trigger(dt, env)
|
||||
|
||||
|
||||
class Always(StatelessRule):
|
||||
@@ -291,7 +286,7 @@ class Always(StatelessRule):
|
||||
A rule that always triggers.
|
||||
"""
|
||||
@staticmethod
|
||||
def always_trigger(dt):
|
||||
def always_trigger(dt, env):
|
||||
"""
|
||||
A should_trigger implementation that will always trigger.
|
||||
"""
|
||||
@@ -304,7 +299,7 @@ class Never(StatelessRule):
|
||||
A rule that never triggers.
|
||||
"""
|
||||
@staticmethod
|
||||
def never_trigger(dt):
|
||||
def never_trigger(dt, env):
|
||||
"""
|
||||
A should_trigger implementation that will never trigger.
|
||||
"""
|
||||
@@ -328,15 +323,15 @@ class AfterOpen(StatelessRule):
|
||||
|
||||
self._dt = None
|
||||
|
||||
def should_trigger(self, dt):
|
||||
return self._get_open(dt) + self.offset <= dt
|
||||
def should_trigger(self, dt, env):
|
||||
return self._get_open(dt, env) + self.offset <= dt
|
||||
|
||||
def _get_open(self, dt):
|
||||
def _get_open(self, dt, env):
|
||||
"""
|
||||
Cache the open for each day.
|
||||
"""
|
||||
if self._dt is None or (self._dt.date() != dt.date()):
|
||||
self._dt = self.env.get_open_and_close(dt)[0] \
|
||||
self._dt = env.get_open_and_close(dt)[0] \
|
||||
- datetime.timedelta(minutes=1)
|
||||
|
||||
return self._dt
|
||||
@@ -358,15 +353,15 @@ class BeforeClose(StatelessRule):
|
||||
|
||||
self._dt = None
|
||||
|
||||
def should_trigger(self, dt):
|
||||
return self._get_close(dt) - self.offset <= dt
|
||||
def should_trigger(self, dt, env):
|
||||
return self._get_close(dt, env) - self.offset <= dt
|
||||
|
||||
def _get_close(self, dt):
|
||||
def _get_close(self, dt, env):
|
||||
"""
|
||||
Cache the close for each day.
|
||||
"""
|
||||
if self._dt is None or (self._dt.date() != dt.date()):
|
||||
self._dt = self.env.get_open_and_close(dt)[1]
|
||||
self._dt = env.get_open_and_close(dt)[1]
|
||||
|
||||
return self._dt
|
||||
|
||||
@@ -375,8 +370,8 @@ class NotHalfDay(StatelessRule):
|
||||
"""
|
||||
A rule that only triggers when it is not a half day.
|
||||
"""
|
||||
def should_trigger(self, dt):
|
||||
return dt.date() not in self.env.early_closes
|
||||
def should_trigger(self, dt, env):
|
||||
return dt.date() not in env.early_closes
|
||||
|
||||
|
||||
class NthTradingDayOfWeek(StatelessRule):
|
||||
@@ -389,18 +384,18 @@ class NthTradingDayOfWeek(StatelessRule):
|
||||
raise _out_of_range_error(MAX_WEEK_RANGE)
|
||||
self.td_delta = n
|
||||
|
||||
def should_trigger(self, dt):
|
||||
return _coerce_datetime(self.env.add_trading_days(
|
||||
def should_trigger(self, dt, env):
|
||||
return _coerce_datetime(env.add_trading_days(
|
||||
self.td_delta,
|
||||
self.get_first_trading_day_of_week(dt),
|
||||
self.get_first_trading_day_of_week(dt, env),
|
||||
)).date() == dt.date()
|
||||
|
||||
def get_first_trading_day_of_week(self, dt):
|
||||
def get_first_trading_day_of_week(self, dt, env):
|
||||
prev = dt
|
||||
dt = self.env.previous_trading_day(dt)
|
||||
dt = env.previous_trading_day(dt)
|
||||
while dt.date().weekday() < prev.date().weekday():
|
||||
prev = dt
|
||||
dt = self.env.previous_trading_day(dt)
|
||||
dt = env.previous_trading_day(dt)
|
||||
return prev.date()
|
||||
|
||||
|
||||
@@ -414,20 +409,20 @@ class NDaysBeforeLastTradingDayOfWeek(StatelessRule):
|
||||
self.td_delta = -n
|
||||
self.date = None
|
||||
|
||||
def should_trigger(self, dt):
|
||||
return _coerce_datetime(self.env.add_trading_days(
|
||||
def should_trigger(self, dt, env):
|
||||
return _coerce_datetime(env.add_trading_days(
|
||||
self.td_delta,
|
||||
self.get_last_trading_day_of_week(dt),
|
||||
self.get_last_trading_day_of_week(dt, env),
|
||||
)).date() == dt.date()
|
||||
|
||||
def get_last_trading_day_of_week(self, dt):
|
||||
def get_last_trading_day_of_week(self, dt, env):
|
||||
prev = dt
|
||||
dt = self.env.next_trading_day(dt)
|
||||
dt = env.next_trading_day(dt)
|
||||
# Traverse forward until we hit a week border, then jump back to the
|
||||
# previous trading day.
|
||||
while dt.date().weekday() > prev.date().weekday():
|
||||
prev = dt
|
||||
dt = self.env.next_trading_day(dt)
|
||||
dt = env.next_trading_day(dt)
|
||||
return prev.date()
|
||||
|
||||
|
||||
@@ -443,30 +438,30 @@ class NthTradingDayOfMonth(StatelessRule):
|
||||
self.month = None
|
||||
self.day = None
|
||||
|
||||
def should_trigger(self, dt):
|
||||
return self.get_nth_trading_day_of_month(dt) == dt.date()
|
||||
def should_trigger(self, dt, env):
|
||||
return self.get_nth_trading_day_of_month(dt, env) == dt.date()
|
||||
|
||||
def get_nth_trading_day_of_month(self, dt):
|
||||
def get_nth_trading_day_of_month(self, dt, env):
|
||||
if self.month == dt.month:
|
||||
# We already computed the day for this month.
|
||||
return self.day
|
||||
|
||||
if not self.td_delta:
|
||||
self.day = self.get_first_trading_day_of_month(dt)
|
||||
self.day = self.get_first_trading_day_of_month(dt, env)
|
||||
else:
|
||||
self.day = self.env.add_trading_days(
|
||||
self.day = env.add_trading_days(
|
||||
self.td_delta,
|
||||
self.get_first_trading_day_of_month(dt),
|
||||
self.get_first_trading_day_of_month(dt, env),
|
||||
).date()
|
||||
|
||||
return self.day
|
||||
|
||||
def get_first_trading_day_of_month(self, dt):
|
||||
def get_first_trading_day_of_month(self, dt, env):
|
||||
self.month = dt.month
|
||||
|
||||
dt = dt.replace(day=1)
|
||||
self.first_day = (dt if self.env.is_trading_day(dt)
|
||||
else self.env.next_trading_day(dt)).date()
|
||||
self.first_day = (dt if env.is_trading_day(dt)
|
||||
else env.next_trading_day(dt)).date()
|
||||
return self.first_day
|
||||
|
||||
|
||||
@@ -481,25 +476,25 @@ class NDaysBeforeLastTradingDayOfMonth(StatelessRule):
|
||||
self.month = None
|
||||
self.day = None
|
||||
|
||||
def should_trigger(self, dt):
|
||||
return self.get_nth_to_last_trading_day_of_month(dt) == dt.date()
|
||||
def should_trigger(self, dt, env):
|
||||
return self.get_nth_to_last_trading_day_of_month(dt, env) == dt.date()
|
||||
|
||||
def get_nth_to_last_trading_day_of_month(self, dt):
|
||||
def get_nth_to_last_trading_day_of_month(self, dt, env):
|
||||
if self.month == dt.month:
|
||||
# We already computed the last day for this month.
|
||||
return self.day
|
||||
|
||||
if not self.td_delta:
|
||||
self.day = self.get_last_trading_day_of_month(dt)
|
||||
self.day = self.get_last_trading_day_of_month(dt, env)
|
||||
else:
|
||||
self.day = self.env.add_trading_days(
|
||||
self.day = env.add_trading_days(
|
||||
self.td_delta,
|
||||
self.get_last_trading_day_of_month(dt),
|
||||
self.get_last_trading_day_of_month(dt, env),
|
||||
).date()
|
||||
|
||||
return self.day
|
||||
|
||||
def get_last_trading_day_of_month(self, dt):
|
||||
def get_last_trading_day_of_month(self, dt, env):
|
||||
self.month = dt.month
|
||||
|
||||
if dt.month == 12:
|
||||
@@ -511,7 +506,7 @@ class NDaysBeforeLastTradingDayOfMonth(StatelessRule):
|
||||
year = dt.year
|
||||
month = dt.month + 1
|
||||
|
||||
self.last_day = self.env.previous_trading_day(
|
||||
self.last_day = env.previous_trading_day(
|
||||
dt.replace(year=year, month=month, day=1)
|
||||
).date()
|
||||
return self.last_day
|
||||
@@ -543,14 +538,14 @@ class OncePerDay(StatefulRule):
|
||||
self.triggered = False
|
||||
super(OncePerDay, self).__init__(rule)
|
||||
|
||||
def should_trigger(self, dt):
|
||||
def should_trigger(self, dt, env):
|
||||
dt_date = dt.date()
|
||||
if self.date is None or self.date != dt_date:
|
||||
# initialize or reset for new date
|
||||
self.triggered = False
|
||||
self.date = dt_date
|
||||
|
||||
if not self.triggered and self.rule.should_trigger(dt):
|
||||
if not self.triggered and self.rule.should_trigger(dt, env):
|
||||
self.triggered = True
|
||||
return True
|
||||
|
||||
|
||||
+43
-40
@@ -28,8 +28,7 @@ from zipline.protocol import Event, DATASOURCE_TYPE
|
||||
from zipline.sources import (SpecificEquityTrades,
|
||||
DataFrameSource,
|
||||
DataPanelSource)
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
from zipline.finance import trading
|
||||
from zipline.finance.trading import SimulationParameters, TradingEnvironment
|
||||
from zipline.sources.test_source import create_trade
|
||||
|
||||
|
||||
@@ -44,16 +43,18 @@ def create_simulation_parameters(year=2006, start=None, end=None,
|
||||
capital_base=float("1.0e5"),
|
||||
num_days=None, load=None,
|
||||
data_frequency='daily',
|
||||
emission_rate='daily'):
|
||||
emission_rate='daily',
|
||||
env=None):
|
||||
"""Construct a complete environment with reasonable defaults"""
|
||||
if env is None:
|
||||
env = TradingEnvironment(load=load)
|
||||
if start is None:
|
||||
start = datetime(year, 1, 1, tzinfo=pytz.utc)
|
||||
if end is None:
|
||||
if num_days:
|
||||
trading.environment = trading.TradingEnvironment(load=load)
|
||||
start_index = trading.environment.trading_days.searchsorted(
|
||||
start_index = env.trading_days.searchsorted(
|
||||
start)
|
||||
end = trading.environment.trading_days[start_index + num_days - 1]
|
||||
end = env.trading_days[start_index + num_days - 1]
|
||||
else:
|
||||
end = datetime(year, 12, 31, tzinfo=pytz.utc)
|
||||
sim_params = SimulationParameters(
|
||||
@@ -62,14 +63,15 @@ def create_simulation_parameters(year=2006, start=None, end=None,
|
||||
capital_base=capital_base,
|
||||
data_frequency=data_frequency,
|
||||
emission_rate=emission_rate,
|
||||
env=env,
|
||||
)
|
||||
|
||||
return sim_params
|
||||
|
||||
|
||||
def create_random_simulation_parameters():
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
treasury_curves = trading.environment.treasury_curves
|
||||
env = TradingEnvironment()
|
||||
treasury_curves = env.treasury_curves
|
||||
|
||||
for n in range(100):
|
||||
|
||||
@@ -92,30 +94,31 @@ check treasury and benchmark data in findb, and re-run the test."""
|
||||
|
||||
sim_params = SimulationParameters(
|
||||
period_start=start_dt,
|
||||
period_end=end_dt
|
||||
period_end=end_dt,
|
||||
env=env,
|
||||
)
|
||||
|
||||
return sim_params, start_dt, end_dt
|
||||
|
||||
|
||||
def get_next_trading_dt(current, interval):
|
||||
next_dt = pd.Timestamp(current).tz_convert(trading.environment.exchange_tz)
|
||||
def get_next_trading_dt(current, interval, env):
|
||||
next_dt = pd.Timestamp(current).tz_convert(env.exchange_tz)
|
||||
|
||||
while True:
|
||||
# Convert timestamp to naive before adding day, otherwise the when
|
||||
# stepping over EDT an hour is added.
|
||||
next_dt = pd.Timestamp(next_dt.replace(tzinfo=None))
|
||||
next_dt = next_dt + interval
|
||||
next_dt = pd.Timestamp(next_dt, tz=trading.environment.exchange_tz)
|
||||
next_dt = pd.Timestamp(next_dt, tz=env.exchange_tz)
|
||||
next_dt_utc = next_dt.tz_convert('UTC')
|
||||
if trading.environment.is_market_hours(next_dt_utc):
|
||||
if env.is_market_hours(next_dt_utc):
|
||||
break
|
||||
next_dt = next_dt_utc.tz_convert(trading.environment.exchange_tz)
|
||||
next_dt = next_dt_utc.tz_convert(env.exchange_tz)
|
||||
|
||||
return next_dt_utc
|
||||
|
||||
|
||||
def create_trade_history(sid, prices, amounts, interval, sim_params,
|
||||
def create_trade_history(sid, prices, amounts, interval, sim_params, env,
|
||||
source_id="test_factory"):
|
||||
trades = []
|
||||
current = sim_params.first_open
|
||||
@@ -129,7 +132,7 @@ def create_trade_history(sid, prices, amounts, interval, sim_params,
|
||||
trade_dt = current
|
||||
trade = create_trade(sid, price, amount, trade_dt, source_id)
|
||||
trades.append(trade)
|
||||
current = get_next_trading_dt(current, interval)
|
||||
current = get_next_trading_dt(current, interval, env)
|
||||
|
||||
assert len(trades) == len(prices)
|
||||
return trades
|
||||
@@ -200,12 +203,12 @@ def create_commission(sid, value, datetime):
|
||||
return txn
|
||||
|
||||
|
||||
def create_txn_history(sid, priceList, amtList, interval, sim_params):
|
||||
def create_txn_history(sid, priceList, amtList, interval, sim_params, env):
|
||||
txns = []
|
||||
current = sim_params.first_open
|
||||
|
||||
for price, amount in zip(priceList, amtList):
|
||||
current = get_next_trading_dt(current, interval)
|
||||
current = get_next_trading_dt(current, interval, env)
|
||||
|
||||
txns.append(create_txn(sid, price, amount, current))
|
||||
current = current + interval
|
||||
@@ -222,7 +225,7 @@ def create_returns_from_list(returns, sim_params):
|
||||
data=returns)
|
||||
|
||||
|
||||
def create_daily_trade_source(sids, sim_params, concurrent=False):
|
||||
def create_daily_trade_source(sids, sim_params, env, concurrent=False):
|
||||
"""
|
||||
creates trade_count trades for each sid in sids list.
|
||||
first trade will be on sim_params.period_start, and daily
|
||||
@@ -233,11 +236,12 @@ def create_daily_trade_source(sids, sim_params, concurrent=False):
|
||||
sids,
|
||||
timedelta(days=1),
|
||||
sim_params,
|
||||
concurrent=concurrent
|
||||
env=env,
|
||||
concurrent=concurrent,
|
||||
)
|
||||
|
||||
|
||||
def create_minutely_trade_source(sids, sim_params, concurrent=False):
|
||||
def create_minutely_trade_source(sids, sim_params, env, concurrent=False):
|
||||
"""
|
||||
creates trade_count trades for each sid in sids list.
|
||||
first trade will be on sim_params.period_start, and every minute
|
||||
@@ -248,16 +252,17 @@ def create_minutely_trade_source(sids, sim_params, concurrent=False):
|
||||
sids,
|
||||
timedelta(minutes=1),
|
||||
sim_params,
|
||||
concurrent=concurrent
|
||||
env=env,
|
||||
concurrent=concurrent,
|
||||
)
|
||||
|
||||
|
||||
def create_trade_source(sids, trade_time_increment, sim_params,
|
||||
def create_trade_source(sids, trade_time_increment, sim_params, env,
|
||||
concurrent=False):
|
||||
|
||||
# If the sim_params define an end that is during market hours, that will be
|
||||
# used as the end of the data source
|
||||
if trading.environment.is_market_hours(sim_params.period_end):
|
||||
if env.is_market_hours(sim_params.period_end):
|
||||
end = sim_params.period_end
|
||||
# Otherwise, the last_close after the period_end is used as the end of the
|
||||
# data source
|
||||
@@ -271,14 +276,15 @@ def create_trade_source(sids, trade_time_increment, sim_params,
|
||||
'end': end,
|
||||
'delta': trade_time_increment,
|
||||
'filter': sids,
|
||||
'concurrent': concurrent
|
||||
'concurrent': concurrent,
|
||||
'env': env,
|
||||
}
|
||||
source = SpecificEquityTrades(*args, **kwargs)
|
||||
|
||||
return source
|
||||
|
||||
|
||||
def create_test_df_source(sim_params=None, bars='daily'):
|
||||
def create_test_df_source(sim_params=None, env=None, bars='daily'):
|
||||
if bars == 'daily':
|
||||
freq = pd.datetools.BDay()
|
||||
elif bars == 'minute':
|
||||
@@ -286,16 +292,16 @@ def create_test_df_source(sim_params=None, bars='daily'):
|
||||
else:
|
||||
raise ValueError('%s bars not understood.' % bars)
|
||||
|
||||
if sim_params:
|
||||
if sim_params and bars == 'daily':
|
||||
index = sim_params.trading_days
|
||||
else:
|
||||
if trading.environment is None:
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
if env is None:
|
||||
env = TradingEnvironment()
|
||||
|
||||
start = pd.datetime(1990, 1, 3, 0, 0, 0, 0, pytz.utc)
|
||||
end = pd.datetime(1990, 1, 8, 0, 0, 0, 0, pytz.utc)
|
||||
|
||||
days = trading.environment.days_in_range(start, end)
|
||||
days = env.days_in_range(start, end)
|
||||
|
||||
if bars == 'daily':
|
||||
index = days
|
||||
@@ -303,7 +309,7 @@ def create_test_df_source(sim_params=None, bars='daily'):
|
||||
index = pd.DatetimeIndex([], freq=freq)
|
||||
|
||||
for day in days:
|
||||
day_index = trading.environment.market_minutes_for_day(day)
|
||||
day_index = env.market_minutes_for_day(day)
|
||||
index = index.append(day_index)
|
||||
|
||||
x = np.arange(1, len(index) + 1)
|
||||
@@ -313,17 +319,17 @@ def create_test_df_source(sim_params=None, bars='daily'):
|
||||
return DataFrameSource(df), df
|
||||
|
||||
|
||||
def create_test_panel_source(sim_params=None, source_type=None):
|
||||
def create_test_panel_source(sim_params=None, env=None, source_type=None):
|
||||
start = sim_params.first_open \
|
||||
if sim_params else pd.datetime(1990, 1, 3, 0, 0, 0, 0, pytz.utc)
|
||||
|
||||
end = sim_params.last_close \
|
||||
if sim_params else pd.datetime(1990, 1, 8, 0, 0, 0, 0, pytz.utc)
|
||||
|
||||
if trading.environment is None:
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
if env is None:
|
||||
env = TradingEnvironment()
|
||||
|
||||
index = trading.environment.days_in_range(start, end)
|
||||
index = env.days_in_range(start, end)
|
||||
|
||||
price = np.arange(0, len(index))
|
||||
volume = np.ones(len(index)) * 1000
|
||||
@@ -343,17 +349,14 @@ def create_test_panel_source(sim_params=None, source_type=None):
|
||||
return DataPanelSource(panel), panel
|
||||
|
||||
|
||||
def create_test_panel_ohlc_source(sim_params=None):
|
||||
def create_test_panel_ohlc_source(sim_params, env):
|
||||
start = sim_params.first_open \
|
||||
if sim_params else pd.datetime(1990, 1, 3, 0, 0, 0, 0, pytz.utc)
|
||||
|
||||
end = sim_params.last_close \
|
||||
if sim_params else pd.datetime(1990, 1, 8, 0, 0, 0, 0, pytz.utc)
|
||||
|
||||
if trading.environment is None:
|
||||
trading.environment = trading.TradingEnvironment()
|
||||
|
||||
index = trading.environment.days_in_range(start, end)
|
||||
index = env.days_in_range(start, end)
|
||||
price = np.arange(0, len(index)) + 100
|
||||
high = price * 1.05
|
||||
low = price * 0.95
|
||||
|
||||
@@ -5,7 +5,6 @@ import os.path
|
||||
import pandas as pd
|
||||
import pytz
|
||||
import zipline
|
||||
from zipline.finance.trading import with_environment
|
||||
|
||||
|
||||
DATE_FORMAT = "%Y%m%d"
|
||||
@@ -15,7 +14,7 @@ SECURITY_LISTS_DIR = os.path.join(zipline_dir, 'resources', 'security_lists')
|
||||
|
||||
class SecurityList(object):
|
||||
|
||||
def __init__(self, data, current_date_func):
|
||||
def __init__(self, data, current_date_func, asset_finder):
|
||||
"""
|
||||
data: a nested dictionary:
|
||||
knowledge_date -> lookup_date ->
|
||||
@@ -29,6 +28,7 @@ class SecurityList(object):
|
||||
self.current_date = current_date_func
|
||||
self.count = 0
|
||||
self._current_set = set()
|
||||
self.asset_finder = asset_finder
|
||||
|
||||
def make_knowledge_dates(self, data):
|
||||
knowledge_dates = sorted(
|
||||
@@ -68,10 +68,9 @@ class SecurityList(object):
|
||||
self._cache[kd] = self._current_set
|
||||
return self._current_set
|
||||
|
||||
@with_environment()
|
||||
def update_current(self, effective_date, symbols, change_func, env=None):
|
||||
def update_current(self, effective_date, symbols, change_func):
|
||||
for symbol in symbols:
|
||||
asset = env.asset_finder.lookup_symbol(
|
||||
asset = self.asset_finder.lookup_symbol(
|
||||
symbol,
|
||||
as_of_date=effective_date
|
||||
)
|
||||
@@ -86,8 +85,9 @@ class SecurityListSet(object):
|
||||
# list implementations.
|
||||
security_list_type = SecurityList
|
||||
|
||||
def __init__(self, current_date_func):
|
||||
def __init__(self, current_date_func, asset_finder):
|
||||
self.current_date_func = current_date_func
|
||||
self.asset_finder = asset_finder
|
||||
self._leveraged_etf = None
|
||||
|
||||
@property
|
||||
@@ -95,7 +95,8 @@ class SecurityListSet(object):
|
||||
if self._leveraged_etf is None:
|
||||
self._leveraged_etf = self.security_list_type(
|
||||
load_from_directory('leveraged_etf_list'),
|
||||
self.current_date_func
|
||||
self.current_date_func,
|
||||
asset_finder=self.asset_finder
|
||||
)
|
||||
return self._leveraged_etf
|
||||
|
||||
|
||||
@@ -13,6 +13,66 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from six import BytesIO
|
||||
import pickle
|
||||
from functools import partial
|
||||
|
||||
from zipline.assets import AssetFinder
|
||||
from zipline.finance.trading import TradingEnvironment
|
||||
|
||||
# Label for the serialization version field in the state returned by
|
||||
# __getstate__.
|
||||
VERSION_LABEL = '_stateversion_'
|
||||
|
||||
|
||||
def _persistent_id(obj):
|
||||
if isinstance(obj, AssetFinder):
|
||||
return AssetFinder.PERSISTENT_TOKEN
|
||||
if isinstance(obj, TradingEnvironment):
|
||||
return TradingEnvironment.PERSISTENT_TOKEN
|
||||
return None
|
||||
|
||||
|
||||
def _persistent_load(persid, env):
|
||||
if persid == AssetFinder.PERSISTENT_TOKEN:
|
||||
return env.asset_finder
|
||||
if persid == TradingEnvironment.PERSISTENT_TOKEN:
|
||||
return env
|
||||
|
||||
|
||||
def dump_with_persistent_ids(obj, protocol=None):
|
||||
"""
|
||||
Performs a pickle dump on the given object, substituting all references to
|
||||
a TradingEnvironment or AssetFinder with tokenized representations.
|
||||
|
||||
All arguments are passed to pickle.Pickler and are described therein.
|
||||
"""
|
||||
file = BytesIO()
|
||||
pickler = pickle.Pickler(file, protocol)
|
||||
pickler.persistent_id = _persistent_id
|
||||
pickler.dump(obj)
|
||||
return file.getvalue()
|
||||
|
||||
|
||||
def load_with_persistent_ids(str, env):
|
||||
"""
|
||||
Performs a pickle load on the given string, substituting the given
|
||||
TradingEnvironment in to any tokenized representations of a
|
||||
TradingEnvironment or AssetFinder.
|
||||
|
||||
Parameters
|
||||
__________
|
||||
str : String
|
||||
The string representation of the object to be unpickled.
|
||||
env : TradingEnvironment
|
||||
The TradingEnvironment to be inserted to the unpickled object.
|
||||
|
||||
Returns
|
||||
_______
|
||||
obj
|
||||
An unpickled object formed from the parameter 'str'.
|
||||
"""
|
||||
file = BytesIO(str)
|
||||
unpickler = pickle.Unpickler(file)
|
||||
unpickler.persistent_load = partial(_persistent_load, env=env)
|
||||
return unpickler.load()
|
||||
|
||||
@@ -72,7 +72,8 @@ def create_test_zipline(**config):
|
||||
trade_source = factory.create_daily_trade_source(
|
||||
sid_list,
|
||||
test_algo.sim_params,
|
||||
concurrent=concurrent_trades
|
||||
test_algo.trading_environment,
|
||||
concurrent=concurrent_trades,
|
||||
)
|
||||
if trade_source:
|
||||
test_algo.set_sources([trade_source])
|
||||
|
||||
Reference in New Issue
Block a user