diff --git a/tests/test_events_through_risk.py b/tests/test_events_through_risk.py index 6ebef976..8c463fa6 100644 --- a/tests/test_events_through_risk.py +++ b/tests/test_events_through_risk.py @@ -163,172 +163,177 @@ class TestEventsThroughRisk(unittest.TestCase): crm.sharpe[-1], decimal=6) - @trading.use_environment(trading.TradingEnvironment()) 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) - 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') - sim_params = SimulationParameters( - period_start=start_date, - period_end=end_date, - emission_rate='daily', - data_frequency='minute') + algo = BuyAndHoldAlgorithm( + sim_params=sim_params, + data_frequency='minute') - algo = BuyAndHoldAlgorithm( - sim_params=sim_params, - data_frequency='minute') + first_date = datetime.datetime(2006, 1, 3, tzinfo=pytz.utc) + first_open, first_close = \ + trading.environment.get_open_and_close(first_date) - first_date = datetime.datetime(2006, 1, 3, tzinfo=pytz.utc) - first_open, first_close = \ - trading.environment.get_open_and_close(first_date) + second_date = datetime.datetime(2006, 1, 4, tzinfo=pytz.utc) + second_open, second_close = \ + trading.environment.get_open_and_close(second_date) - second_date = datetime.datetime(2006, 1, 4, tzinfo=pytz.utc) - second_open, second_close = \ - trading.environment.get_open_and_close(second_date) + third_date = datetime.datetime(2006, 1, 5, tzinfo=pytz.utc) + third_open, third_close = \ + trading.environment.get_open_and_close(third_date) - third_date = datetime.datetime(2006, 1, 5, tzinfo=pytz.utc) - third_open, third_close = \ - trading.environment.get_open_and_close(third_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 + }), + ] - 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 - }), - ] + 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 + }), + ] - 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 - }), - ] + algo.benchmark_return_source = benchmark_data + algo.sources = list([trade_bar_data]) + gen = algo._create_generator(sim_params) - algo.benchmark_return_source = benchmark_data - algo.sources = list([trade_bar_data]) - gen = algo._create_generator(sim_params) + crm = algo.perf_tracker.cumulative_risk_metrics - crm = algo.perf_tracker.cumulative_risk_metrics + first_msg = gen.next() - first_msg = gen.next() + self.assertIsNotNone(first_msg, + "There should be a message emitted.") - self.assertIsNotNone(first_msg, "There should be a message emitted.") + # 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.") - # 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.assertTrue( + np.isnan(crm.algorithm_volatility[-1]), + "On the first day algorithm volatility does not exist.") - self.assertTrue( - np.isnan(crm.algorithm_volatility[-1]), - "On the first day algorithm volatility does not exist.") + second_msg = gen.next() - second_msg = gen.next() + self.assertIsNotNone(second_msg, "There should be a message " + "emitted.") - self.assertIsNotNone(second_msg, "There should be a message emitted.") + self.assertEqual(1, len(algo.portfolio.positions), + "Number of positions should stay the same.") - 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.050022510129558301, + crm.algorithm_returns[-1], + decimal=6) - # 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) + third_msg = gen.next() - third_msg = gen.next() + self.assertEqual(1, len(algo.portfolio.positions), + "Number of positions should stay the same.") - self.assertEqual(1, len(algo.portfolio.positions), - "Number of positions should stay the same.") + self.assertIsNotNone(third_msg, "There should be a message " + "emitted.") - 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) + # 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) diff --git a/tests/test_perf_tracking.py b/tests/test_perf_tracking.py index bc043f67..cf84b33c 100644 --- a/tests/test_perf_tracking.py +++ b/tests/test_perf_tracking.py @@ -107,49 +107,51 @@ class TestDividendPerformance(unittest.TestCase): ) self.assertEqual(after.hour, 13) - @trading.use_environment(trading.TradingEnvironment()) def test_long_position_receives_dividend(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 - ) + with trading.TradingEnvironment(): + #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 + ) - dividend = factory.create_dividend( - 1, - 10.00, - # declared date, when the algorithm finds out about - # the dividend - events[1].dt, - # ex_date, when the algorithm is credited with the - # dividend - events[1].dt, - # pay date, when the algorithm receives the dividend. - events[2].dt - ) + dividend = factory.create_dividend( + 1, + 10.00, + # declared date, when the algorithm finds out about + # the dividend + events[1].dt, + # ex_date, when the algorithm is credited with the + # dividend + events[1].dt, + # pay date, when the algorithm receives the dividend. + events[2].dt + ) - txn = create_txn(events[0], 10.0, 100) - events.insert(0, txn) - events.insert(1, dividend) - results = calculate_results(self, events) + txn = create_txn(events[0], 10.0, 100) + events.insert(0, txn) + events.insert(1, dividend) + results = calculate_results(self, events) - self.assertEqual(len(results), 5) - cumulative_returns = \ - [event['cumulative_perf']['returns'] for event in results] - self.assertEqual(cumulative_returns, [0.0, 0.0, 0.1, 0.1, 0.1]) - daily_returns = [event['daily_perf']['returns'] for event in results] - self.assertEqual(daily_returns, [0.0, 0.0, 0.10, 0.0, 0.0]) - cash_flows = [event['daily_perf']['capital_used'] for event in results] - self.assertEqual(cash_flows, [-1000, 0, 1000, 0, 0]) - cumulative_cash_flows = \ - [event['cumulative_perf']['capital_used'] for event in results] - self.assertEqual(cumulative_cash_flows, [-1000, -1000, 0, 0, 0]) - cash_pos = \ - [event['cumulative_perf']['ending_cash'] for event in results] - self.assertEqual(cash_pos, [9000, 9000, 10000, 10000, 10000]) + self.assertEqual(len(results), 5) + cumulative_returns = \ + [event['cumulative_perf']['returns'] for event in results] + self.assertEqual(cumulative_returns, [0.0, 0.0, 0.1, 0.1, 0.1]) + daily_returns = [event['daily_perf']['returns'] + for event in results] + self.assertEqual(daily_returns, [0.0, 0.0, 0.10, 0.0, 0.0]) + cash_flows = [event['daily_perf']['capital_used'] + for event in results] + self.assertEqual(cash_flows, [-1000, 0, 1000, 0, 0]) + cumulative_cash_flows = \ + [event['cumulative_perf']['capital_used'] for event in results] + self.assertEqual(cumulative_cash_flows, [-1000, -1000, 0, 0, 0]) + cash_pos = \ + [event['cumulative_perf']['ending_cash'] for event in results] + self.assertEqual(cash_pos, [9000, 9000, 10000, 10000, 10000]) def test_post_ex_long_position_receives_no_dividend(self): #post some trades in the market @@ -1026,92 +1028,94 @@ class TestPerformanceTracker(unittest.TestCase): else: yield event - @trading.use_environment(trading.TradingEnvironment()) def test_minute_tracker(self): """ Tests minute performance tracking.""" - start_dt = trading.environment.exchange_dt_in_utc( - datetime.datetime(2013, 3, 1, 9, 31)) - end_dt = trading.environment.exchange_dt_in_utc( - datetime.datetime(2013, 3, 1, 16, 0)) + with trading.TradingEnvironment(): + start_dt = trading.environment.exchange_dt_in_utc( + datetime.datetime(2013, 3, 1, 9, 31)) + end_dt = trading.environment.exchange_dt_in_utc( + datetime.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) + sim_params = SimulationParameters( + period_start=start_dt, + period_end=end_dt, + emission_rate='minute' + ) + tracker = perf.PerformanceTracker(sim_params) - foo_event_1 = factory.create_trade('foo', 10.0, 20, start_dt) - order_event_1 = Order(**{ - 'sid': foo_event_1.sid, - 'amount': -25, - 'dt': foo_event_1.dt - }) - bar_event_1 = factory.create_trade('bar', 100.0, 200, start_dt) - txn_event_1 = Transaction(sid=foo_event_1.sid, - amount=-25, - dt=foo_event_1.dt, - price=10.0, - commission=0.50) - benchmark_event_1 = Event({ - 'dt': start_dt, - 'returns': 1.0, - 'type': DATASOURCE_TYPE.BENCHMARK - }) + foo_event_1 = factory.create_trade('foo', 10.0, 20, start_dt) + order_event_1 = Order(**{ + 'sid': foo_event_1.sid, + 'amount': -25, + 'dt': foo_event_1.dt + }) + bar_event_1 = factory.create_trade('bar', 100.0, 200, start_dt) + txn_event_1 = Transaction(sid=foo_event_1.sid, + amount=-25, + dt=foo_event_1.dt, + price=10.0, + commission=0.50) + benchmark_event_1 = Event({ + 'dt': start_dt, + 'returns': 1.0, + 'type': DATASOURCE_TYPE.BENCHMARK + }) - foo_event_2 = factory.create_trade( - 'foo', 11.0, 20, start_dt + datetime.timedelta(minutes=1)) - bar_event_2 = factory.create_trade( - 'bar', 11.0, 20, start_dt + datetime.timedelta(minutes=1)) - benchmark_event_2 = Event({ - 'dt': start_dt + datetime.timedelta(minutes=1), - 'returns': 2.0, - 'type': DATASOURCE_TYPE.BENCHMARK - }) + foo_event_2 = factory.create_trade( + 'foo', 11.0, 20, start_dt + datetime.timedelta(minutes=1)) + bar_event_2 = factory.create_trade( + 'bar', 11.0, 20, start_dt + datetime.timedelta(minutes=1)) + benchmark_event_2 = Event({ + 'dt': start_dt + datetime.timedelta(minutes=1), + 'returns': 2.0, + 'type': DATASOURCE_TYPE.BENCHMARK + }) - events = [ - foo_event_1, - order_event_1, - benchmark_event_1, - txn_event_1, - bar_event_1, - foo_event_2, - benchmark_event_2, - bar_event_2, - ] + events = [ + foo_event_1, + order_event_1, + benchmark_event_1, + txn_event_1, + bar_event_1, + foo_event_2, + benchmark_event_2, + bar_event_2, + ] - grouped_events = itertools.groupby( - events, operator.attrgetter('dt')) + grouped_events = itertools.groupby( + events, operator.attrgetter('dt')) - messages = {} - for date, group in grouped_events: - tracker.set_date(date) - for event in group: - tracker.process_event(event) - tracker.handle_minute_close(date) - msg = tracker.to_dict() - messages[date] = msg + messages = {} + for date, group in grouped_events: + tracker.set_date(date) + for event in group: + tracker.process_event(event) + tracker.handle_minute_close(date) + msg = tracker.to_dict() + messages[date] = msg - self.assertEquals(2, len(messages)) + self.assertEquals(2, len(messages)) - msg_1 = messages[foo_event_1.dt] - msg_2 = messages[foo_event_2.dt] + msg_1 = messages[foo_event_1.dt] + msg_2 = messages[foo_event_2.dt] - self.assertEquals(1, len(msg_1['minute_perf']['transactions']), - "The first message should contain one transaction.") - # Check that transactions aren't emitted for previous events. - self.assertEquals(0, len(msg_2['minute_perf']['transactions']), - "The second message should have no transactions.") + self.assertEquals(1, len(msg_1['minute_perf']['transactions']), + "The first message should contain one " + "transaction.") + # Check that transactions aren't emitted for previous events. + self.assertEquals(0, len(msg_2['minute_perf']['transactions']), + "The second message should have no " + "transactions.") - self.assertEquals(1, len(msg_1['minute_perf']['orders']), - "The first message should contain one orders.") - # Check that orders aren't emitted for previous events. - self.assertEquals(0, len(msg_2['minute_perf']['orders']), - "The second message should have no orders.") + self.assertEquals(1, len(msg_1['minute_perf']['orders']), + "The first message should contain one orders.") + # Check that orders aren't emitted for previous events. + self.assertEquals(0, len(msg_2['minute_perf']['orders']), + "The second message should have no orders.") - # Ensure that period_close moves through time. - # Also, ensure that the period_closes are the expected dts. - self.assertEquals(foo_event_1.dt, - msg_1['minute_perf']['period_close']) - self.assertEquals(foo_event_2.dt, - msg_2['minute_perf']['period_close']) + # Ensure that period_close moves through time. + # Also, ensure that the period_closes are the expected dts. + self.assertEquals(foo_event_1.dt, + msg_1['minute_perf']['period_close']) + self.assertEquals(foo_event_2.dt, + msg_2['minute_perf']['period_close']) diff --git a/zipline/finance/trading.py b/zipline/finance/trading.py index 08164538..6c39d0ad 100644 --- a/zipline/finance/trading.py +++ b/zipline/finance/trading.py @@ -18,7 +18,6 @@ import pytz import logbook import datetime -from functools import wraps from delorean import Delorean import pandas as pd from pandas import DatetimeIndex @@ -319,18 +318,3 @@ class SimulationParameters(object): emission_rate=self.emission_rate, first_open=self.first_open, last_close=self.last_close) - - -class use_environment(object): - """A decorator to wrap a method in a particular - trading environment.""" - - def __init__(self, environment): - self.env = environment - - def __call__(self, func): - @wraps(func) - def wrapper(*args, **kwargs): - with self.env: - return func(*args, **kwargs) - return wrapper