diff --git a/tests/test_perf_tracking.py b/tests/test_perf_tracking.py index 28775ee7..e2ae3a4d 100644 --- a/tests/test_perf_tracking.py +++ b/tests/test_perf_tracking.py @@ -1098,21 +1098,21 @@ class TestPerformanceTracker(unittest.TestCase): msg_1 = messages[foo_event_1.dt] msg_2 = messages[foo_event_2.dt] - self.assertEquals(1, len(msg_1['intraday_perf']['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['intraday_perf']['transactions']), + self.assertEquals(0, len(msg_2['minute_perf']['transactions']), "The second message should have no transactions.") - self.assertEquals(1, len(msg_1['intraday_perf']['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['intraday_perf']['orders']), + 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['intraday_perf']['period_close']) + msg_1['minute_perf']['period_close']) self.assertEquals(foo_event_2.dt, - msg_2['intraday_perf']['period_close']) + msg_2['minute_perf']['period_close']) diff --git a/zipline/finance/performance.py b/zipline/finance/performance.py index ce46f57a..b459d819 100644 --- a/zipline/finance/performance.py +++ b/zipline/finance/performance.py @@ -270,25 +270,16 @@ class PerformanceTracker(object): 'period_end': self.period_end, 'capital_base': self.capital_base, 'cumulative_perf': self.cumulative_performance.to_dict(), - 'progress': self.progress + 'progress': self.progress, + 'cumulative_risk_metrics': self.cumulative_risk_metrics.to_dict() } if emission_type == 'daily': - _dict.update({'cumulative_risk_metrics': - self.cumulative_risk_metrics.to_dict(), - 'daily_perf': - self.todays_performance.to_dict()}) - if emission_type == 'minute': - # Currently reusing 'todays_performance' for intraday trading - # result, should be analogous, but has the potential for needing - # its own configuration down the line. - # Naming as intraday to make clear that these results are - # being updated per minute - _dict['intraday_risk_metrics'] = \ - self.intraday_risk_metrics.to_dict() - _dict['intraday_perf'] = self.todays_performance.to_dict( - self.saved_dt) - _dict['cumulative_risk_metrics'] = \ - self.cumulative_risk_metrics.to_dict() + _dict.update({'daily_perf': self.todays_performance.to_dict()}) + elif emission_type == 'minute': + _dict.update({ + 'intraday_risk_metrics': self.intraday_risk_metrics.to_dict(), + 'minute_perf': self.todays_performance.to_dict(self.saved_dt) + }) return _dict @@ -327,9 +318,7 @@ class PerformanceTracker(object): perf_period.calculate_performance() def handle_minute_close(self, dt): - - todays_date = self.market_close.replace(hour=0, minute=0, second=0, - microsecond=0) + todays_date = dt.replace(hour=0, minute=0, second=0, microsecond=0) minute_returns = self.minute_performance.returns self.minute_performance.rollover() @@ -340,22 +329,20 @@ class PerformanceTracker(object): self.intraday_risk_metrics.update(dt, algo_minute_returns, bench_minute_returns) - # the intraday risk metrics compound the minutely returns of the - # benchmark. - bench_since_open = self.intraday_risk_metrics.benchmark_returns[-1] - benchmark_returns = pd.Series({dt: bench_since_open}) + + bench_since_open = \ + self.intraday_risk_metrics.benchmark_period_returns[-1] + + benchmark_returns = pd.Series({todays_date: bench_since_open}) # if we've reached market close, check on dividends if dt == self.market_close: for perf_period in self.perf_periods: perf_period.update_dividends(todays_date) - algorithm_returns = pd.Series({dt: self.todays_performance.returns}) - - self.intraday_risk_metrics.update(dt, - algorithm_returns, - benchmark_returns) - + algorithm_returns = pd.Series({ + todays_date: self.todays_performance.returns + }) self.cumulative_risk_metrics.update(todays_date, algorithm_returns, benchmark_returns) @@ -369,6 +356,18 @@ class PerformanceTracker(object): ) self.returns.append(todays_return_obj) + def handle_intraday_close(self): + self.intraday_risk_metrics = \ + risk.RiskMetricsIterative(self.sim_params) + # increment the day counter before we move markers forward. + self.day_count += 1.0 + # move the market day markers forward + if self.market_close < trading.environment.last_trading_day: + _, self.market_close = \ + trading.environment.next_open_and_close(self.market_open) + else: + self.market_close = self.sim_params.last_close + def handle_market_close(self): # add the return results from today to the list of DailyReturn objects. todays_date = self.market_close.replace(hour=0, minute=0, second=0, diff --git a/zipline/finance/risk.py b/zipline/finance/risk.py index 355ac845..e5f99a00 100644 --- a/zipline/finance/risk.py +++ b/zipline/finance/risk.py @@ -649,7 +649,7 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" self.algorithm_volatility.append( self.calculate_volatility(self.algorithm_returns)) - # caching the treasury rates for the live case is a + # caching the treasury rates for the minutely case is a # big speedup, because it avoids searching the treasury # curves on every minute. treasury_end = self.algorithm_returns.index[-1].replace( @@ -693,16 +693,9 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" 'period_label': period_label } - if self.sim_params.emission_rate == 'daily': - # Some risk metrics only make sense in a context of daily - # risk calculations. - rval['sharpe'] = self.sharpe[-1] - rval['sortino'] = self.sortino[-1] - rval['information'] = self.information[-1] - elif self.sim_params.emission_rate == 'minute': - rval['sharpe'] = 0.0 - rval['sortino'] = 0.0 - rval['information'] = 0.0 + rval['sharpe'] = self.sharpe[-1] + rval['sortino'] = self.sortino[-1] + rval['information'] = self.information[-1] return {k: None if check_entry(k, v) diff --git a/zipline/gens/tradesimulation.py b/zipline/gens/tradesimulation.py index 73011605..8d4e0ecf 100644 --- a/zipline/gens/tradesimulation.py +++ b/zipline/gens/tradesimulation.py @@ -26,7 +26,7 @@ log = Logger('Trade Simulation') class AlgorithmSimulator(object): EMISSION_TO_PERF_KEY_MAP = { - 'minute': 'intraday_perf', + 'minute': 'minute_perf', 'daily': 'daily_perf' } @@ -170,6 +170,7 @@ class AlgorithmSimulator(object): tp.rollover() if mkt_close < self.algo.perf_tracker.last_close: mkt_close = self.get_next_close(mkt_close) + self.algo.perf_tracker.handle_intraday_close() risk_message = self.algo.perf_tracker.handle_simulation_end() yield risk_message @@ -185,7 +186,7 @@ class AlgorithmSimulator(object): elif self.algo.perf_tracker.emission_rate == 'minute': self.algo.perf_tracker.handle_minute_close(date) perf_message = self.algo.perf_tracker.to_dict() - perf_message['intraday_perf']['recorded_vars'] = rvars + perf_message['minute_perf']['recorded_vars'] = rvars return perf_message def get_next_close(self, mkt_close):