From 32835b87f393004661160ed69fd3bbcdae7d0d6e Mon Sep 17 00:00:00 2001 From: Eddie Hebert Date: Tue, 7 May 2013 18:34:41 -0400 Subject: [PATCH 1/4] MAINT: Rename perfomances intraday_perf to minute_perf. minute_perf is more precise than intraday_perf as a naming scheme for the performance packet type. --- tests/test_perf_tracking.py | 12 ++++++------ zipline/finance/performance.py | 7 +------ zipline/finance/risk.py | 2 +- zipline/gens/tradesimulation.py | 4 ++-- 4 files changed, 10 insertions(+), 15 deletions(-) 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..6a08ddc2 100644 --- a/zipline/finance/performance.py +++ b/zipline/finance/performance.py @@ -278,14 +278,9 @@ class PerformanceTracker(object): '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( + _dict['minute_perf'] = self.todays_performance.to_dict( self.saved_dt) _dict['cumulative_risk_metrics'] = \ self.cumulative_risk_metrics.to_dict() diff --git a/zipline/finance/risk.py b/zipline/finance/risk.py index 355ac845..d4a23a39 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( diff --git a/zipline/gens/tradesimulation.py b/zipline/gens/tradesimulation.py index 73011605..136cdd9c 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' } @@ -185,7 +185,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): From 2d850d0970c3f488a23b3e07f8a0a34d7a984ac3 Mon Sep 17 00:00:00 2001 From: fawce Date: Tue, 7 May 2013 16:32:35 -0400 Subject: [PATCH 2/4] BUG: Fix calculation of cumulative risk stats. - Use current dt instead of market_close. - Handle intraday close - Remove zeroing out of sharpe etc. --- zipline/finance/performance.py | 31 ++++++++++++++++++------------- zipline/finance/risk.py | 13 +++---------- zipline/gens/tradesimulation.py | 1 + 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/zipline/finance/performance.py b/zipline/finance/performance.py index 6a08ddc2..492200f0 100644 --- a/zipline/finance/performance.py +++ b/zipline/finance/performance.py @@ -322,9 +322,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() @@ -335,22 +333,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) @@ -364,6 +360,15 @@ 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 + self.market_open, self.market_close = \ + trading.environment.next_open_and_close(self.market_open) + 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 d4a23a39..e5f99a00 100644 --- a/zipline/finance/risk.py +++ b/zipline/finance/risk.py @@ -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 136cdd9c..8d4e0ecf 100644 --- a/zipline/gens/tradesimulation.py +++ b/zipline/gens/tradesimulation.py @@ -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 From 3d8674ffb69dae4a189f63745fbb2517cb736deb Mon Sep 17 00:00:00 2001 From: fawce Date: Tue, 7 May 2013 18:44:44 -0400 Subject: [PATCH 3/4] MAINT: Cleaned up to_dict highlighting daily and minutely difference. Make the difference between the two emission rates more exact. --- zipline/finance/performance.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/zipline/finance/performance.py b/zipline/finance/performance.py index 492200f0..c5aa5bbc 100644 --- a/zipline/finance/performance.py +++ b/zipline/finance/performance.py @@ -270,20 +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': - _dict['intraday_risk_metrics'] = \ - self.intraday_risk_metrics.to_dict() - _dict['minute_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 From ede847166373b9eac9c562ed9efff71f63a4cd92 Mon Sep 17 00:00:00 2001 From: fawce Date: Tue, 7 May 2013 18:44:44 -0400 Subject: [PATCH 4/4] BUG: Fix next trading calculation. If we are in a day beyond the historical data use the last close, instead. Relevant for trading current data. --- zipline/finance/performance.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/zipline/finance/performance.py b/zipline/finance/performance.py index c5aa5bbc..b459d819 100644 --- a/zipline/finance/performance.py +++ b/zipline/finance/performance.py @@ -362,8 +362,11 @@ class PerformanceTracker(object): # increment the day counter before we move markers forward. self.day_count += 1.0 # move the market day markers forward - self.market_open, self.market_close = \ - trading.environment.next_open_and_close(self.market_open) + 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.