From 6a0c494ce09002ca302be9f836de5209085fc818 Mon Sep 17 00:00:00 2001 From: Eddie Hebert Date: Wed, 25 Sep 2013 12:26:56 -0400 Subject: [PATCH] MAINT: Use pandas for values directly derived from returns in risk. Remove more use of lists for storing internal risk values to use pandas structures, for easier matching of time to value. Accordingy, convert use of -1 for getting last value, to use current dt. --- zipline/finance/performance.py | 2 +- zipline/finance/risk/cumulative.py | 65 +++++++++++++++--------------- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/zipline/finance/performance.py b/zipline/finance/performance.py index f7f2bafb..60bdb1e1 100644 --- a/zipline/finance/performance.py +++ b/zipline/finance/performance.py @@ -357,7 +357,7 @@ class PerformanceTracker(object): bench_minute_returns) bench_since_open = \ - self.intraday_risk_metrics.benchmark_period_returns[-1] + self.intraday_risk_metrics.benchmark_period_returns[dt] benchmark_returns = pd.Series({todays_date: bench_since_open}) diff --git a/zipline/finance/risk/cumulative.py b/zipline/finance/risk/cumulative.py index 73aada7f..9e88f543 100644 --- a/zipline/finance/risk/cumulative.py +++ b/zipline/finance/risk/cumulative.py @@ -93,10 +93,10 @@ class RiskMetricsCumulative(object): self.algorithm_returns = None self.benchmark_returns = None - self.compounded_log_returns = [] - - self.algorithm_period_returns = [] - self.benchmark_period_returns = [] + self.compounded_log_returns = pd.Series(index=cont_index) + self.algorithm_period_returns = pd.Series(index=cont_index) + self.benchmark_period_returns = pd.Series(index=cont_index) + self.excess_returns = pd.Series(index=cont_index) self.latest_dt = cont_index[0] @@ -107,7 +107,6 @@ class RiskMetricsCumulative(object): self.information = [] self.max_drawdown = 0 self.current_max = -np.inf - self.excess_returns = [] self.daily_treasury = {} def get_minute_index(self, sim_params): @@ -136,10 +135,10 @@ class RiskMetricsCumulative(object): self.update_compounded_log_returns() - self.algorithm_period_returns.append( - self.calculate_period_returns(self.algorithm_returns)) - self.benchmark_period_returns.append( - self.calculate_period_returns(self.benchmark_returns)) + self.algorithm_period_returns[dt] = \ + self.calculate_period_returns(self.algorithm_returns) + self.benchmark_period_returns[dt] = \ + self.calculate_period_returns(self.benchmark_returns) if not self.algorithm_returns.index.equals( self.benchmark_returns.index @@ -176,8 +175,10 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" treasury_period_return self.treasury_period_return = \ self.daily_treasury[treasury_end] - self.excess_returns.append( - self.algorithm_period_returns[-1] - self.treasury_period_return) + self.excess_returns[self.latest_dt] = ( + self.algorithm_period_returns[self.latest_dt] + - + self.treasury_period_return) self.metrics.beta[dt] = self.calculate_beta() self.metrics.alpha[dt] = self.calculate_alpha(dt) self.metrics.sharpe[dt] = self.calculate_sharpe() @@ -191,23 +192,24 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" Returns a dict object of the form: """ period_label = self.last_return_date.strftime("%Y-%m") + dt = self.latest_dt rval = { 'trading_days': len(self.algorithm_returns.valid()), 'benchmark_volatility': - self.metrics.benchmark_volatility[self.latest_dt], + self.metrics.benchmark_volatility[dt], 'algo_volatility': - self.metrics.algorithm_volatility[self.latest_dt], + self.metrics.algorithm_volatility[dt], 'treasury_period_return': self.treasury_period_return, - 'algorithm_period_return': self.algorithm_period_returns[-1], - 'benchmark_period_return': self.benchmark_period_returns[-1], - 'beta': self.metrics.beta[self.latest_dt], - 'alpha': self.metrics.alpha[self.latest_dt], - 'excess_return': self.excess_returns[-1], + 'algorithm_period_return': self.algorithm_period_returns[dt], + 'benchmark_period_return': self.benchmark_period_returns[dt], + 'beta': self.metrics.beta[dt], + 'alpha': self.metrics.alpha[dt], + 'excess_return': self.excess_returns[dt], 'max_drawdown': self.max_drawdown, 'period_label': period_label } - rval['sharpe'] = self.metrics.sharpe[self.latest_dt] + rval['sharpe'] = self.metrics.sharpe[dt] rval['sortino'] = self.sortino[-1] rval['information'] = self.information[-1] @@ -256,30 +258,27 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" compound = 0.0 # BUG? Shouldn't this be set to log(1.0 + 0) ? - if len(self.compounded_log_returns) == 0: - self.compounded_log_returns.append(compound) + if len(self.compounded_log_returns[:self.latest_dt]) == 0: + self.compounded_log_returns[self.latest_dt] = compound else: - self.compounded_log_returns.append( - self.compounded_log_returns[-1] + - compound - ) + self.compounded_log_returns[self.latest_dt] = \ + self.compounded_log_returns[self.latest_dt] + compound def calculate_period_returns(self, returns): - returns = np.array(returns) return (1. + returns).prod() - 1 def update_current_max(self): if len(self.compounded_log_returns) == 0: return - if self.current_max < self.compounded_log_returns[-1]: - self.current_max = self.compounded_log_returns[-1] + if self.current_max < self.compounded_log_returns[self.latest_dt]: + self.current_max = self.compounded_log_returns[self.latest_dt] def calculate_max_drawdown(self): if len(self.compounded_log_returns) == 0: return self.max_drawdown cur_drawdown = 1.0 - math.exp( - self.compounded_log_returns[-1] - + self.compounded_log_returns[self.latest_dt] - self.current_max) if self.max_drawdown < cur_drawdown: @@ -292,7 +291,7 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" http://en.wikipedia.org/wiki/Sharpe_ratio """ return sharpe_ratio(self.metrics.algorithm_volatility[self.latest_dt], - self.algorithm_period_returns[-1], + self.algorithm_period_returns[self.latest_dt], self.treasury_period_return) def calculate_sortino(self, mar=None): @@ -303,7 +302,7 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" mar = self.treasury_period_return return sortino_ratio(np.array(self.algorithm_returns), - self.algorithm_period_returns[-1], + self.algorithm_period_returns[self.latest_dt], mar) def calculate_information(self): @@ -318,9 +317,9 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" """ http://en.wikipedia.org/wiki/Alpha_(investment) """ - return alpha(self.algorithm_period_returns[-1], + return alpha(self.algorithm_period_returns[self.latest_dt], self.treasury_period_return, - self.benchmark_period_returns[-1], + self.benchmark_period_returns[self.latest_dt], self.metrics.beta[dt]) def calculate_volatility(self, daily_returns):