diff --git a/tests/risk/test_risk_cumulative.py b/tests/risk/test_risk_cumulative.py index ff10ebcc..856883d1 100644 --- a/tests/risk/test_risk_cumulative.py +++ b/tests/risk/test_risk_cumulative.py @@ -62,52 +62,59 @@ class TestRisk(unittest.TestCase): def test_algorithm_volatility_06(self): algo_vol_answers = answer_key.RISK_CUMULATIVE.volatility for dt, value in algo_vol_answers.iteritems(): + dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt) np.testing.assert_almost_equal( - self.cumulative_metrics_06.metrics.algorithm_volatility[dt], + self.cumulative_metrics_06.algorithm_volatility[dt_loc], value, err_msg="Mismatch at %s" % (dt,)) def test_sharpe_06(self): for dt, value in answer_key.RISK_CUMULATIVE.sharpe.iteritems(): + dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt) np.testing.assert_almost_equal( - self.cumulative_metrics_06.metrics.sharpe[dt], + self.cumulative_metrics_06.sharpe[dt_loc], value, err_msg="Mismatch at %s" % (dt,)) def test_downside_risk_06(self): for dt, value in answer_key.RISK_CUMULATIVE.downside_risk.iteritems(): + dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt) np.testing.assert_almost_equal( value, - self.cumulative_metrics_06.metrics.downside_risk[dt], + self.cumulative_metrics_06.downside_risk[dt_loc], err_msg="Mismatch at %s" % (dt,)) def test_sortino_06(self): for dt, value in answer_key.RISK_CUMULATIVE.sortino.iteritems(): + dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt) np.testing.assert_almost_equal( - self.cumulative_metrics_06.metrics.sortino[dt], + self.cumulative_metrics_06.sortino[dt_loc], value, decimal=4, err_msg="Mismatch at %s" % (dt,)) def test_information_06(self): for dt, value in answer_key.RISK_CUMULATIVE.information.iteritems(): + dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt) np.testing.assert_almost_equal( value, - self.cumulative_metrics_06.metrics.information[dt], + self.cumulative_metrics_06.information[dt_loc], err_msg="Mismatch at %s" % (dt,)) def test_alpha_06(self): for dt, value in answer_key.RISK_CUMULATIVE.alpha.iteritems(): + dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt) np.testing.assert_almost_equal( - self.cumulative_metrics_06.metrics.alpha[dt], + self.cumulative_metrics_06.alpha[dt_loc], value, err_msg="Mismatch at %s" % (dt,)) def test_beta_06(self): for dt, value in answer_key.RISK_CUMULATIVE.beta.iteritems(): + dt_loc = self.cumulative_metrics_06.cont_index.get_loc(dt) np.testing.assert_almost_equal( value, - self.cumulative_metrics_06.metrics.beta[dt], + self.cumulative_metrics_06.beta[dt_loc], err_msg="Mismatch at %s" % (dt,)) def test_max_drawdown_06(self): diff --git a/tests/test_events_through_risk.py b/tests/test_events_through_risk.py index 2ee965d9..b8d8ee24 100644 --- a/tests/test_events_through_risk.py +++ b/tests/test_events_through_risk.py @@ -161,7 +161,7 @@ class TestEventsThroughRisk(unittest.TestCase): decimal=6) np.testing.assert_almost_equal( - crm.metrics.sharpe[current_dt], + crm.sharpe[dt_loc], expected_sharpe[current_dt], decimal=6, err_msg="Mismatch at %s" % (current_dt,)) @@ -294,6 +294,7 @@ class TestEventsThroughRisk(unittest.TestCase): gen = algo._create_generator(sim_params) crm = algo.perf_tracker.cumulative_risk_metrics + dt_loc = crm.cont_index.get_loc(algo.datetime) first_msg = next(gen) @@ -309,7 +310,7 @@ class TestEventsThroughRisk(unittest.TestCase): self.assertEquals( 0, - crm.metrics.algorithm_volatility[algo.datetime.date()], + crm.algorithm_volatility[dt_loc], "On the first day algorithm volatility does not exist.") second_msg = next(gen) diff --git a/zipline/finance/risk/cumulative.py b/zipline/finance/risk/cumulative.py index 283c223a..41b0ff5f 100644 --- a/zipline/finance/risk/cumulative.py +++ b/zipline/finance/risk/cumulative.py @@ -155,9 +155,14 @@ class RiskMetricsCumulative(object): self.latest_dt_loc = 0 self.latest_dt = cont_index[0] - self.metrics = pd.DataFrame(index=cont_index, - columns=self.METRIC_NAMES, - dtype=float) + self.benchmark_volatility = empty_cont.copy() + self.algorithm_volatility = empty_cont.copy() + self.beta = empty_cont.copy() + self.alpha = empty_cont.copy() + self.sharpe = empty_cont.copy() + self.downside_risk = empty_cont.copy() + self.sortino = empty_cont.copy() + self.information = empty_cont.copy() self.drawdowns = empty_cont.copy() self.max_drawdowns = empty_cont.copy() @@ -257,10 +262,9 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" raise Exception(message) self.update_current_max() - metrics = self.metrics - metrics.benchmark_volatility.iloc[dt_loc] = \ + self.benchmark_volatility[dt_loc] = \ self.calculate_volatility(self.benchmark_returns) - metrics.algorithm_volatility.iloc[dt_loc] = \ + self.algorithm_volatility[dt_loc] = \ self.calculate_volatility(self.algorithm_returns) # caching the treasury rates for the minutely case is a @@ -279,13 +283,13 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" self.excess_returns[dt_loc] = ( self.algorithm_cumulative_returns[dt_loc] - self.treasury_period_return) - metrics.beta.iloc[dt_loc] = self.calculate_beta() - metrics.alpha.iloc[dt_loc] = self.calculate_alpha() - metrics.sharpe.iloc[dt_loc] = self.calculate_sharpe() - metrics.downside_risk.iloc[dt_loc] = \ + self.beta[dt_loc] = self.calculate_beta() + self.alpha[dt_loc] = self.calculate_alpha() + self.sharpe[dt_loc] = self.calculate_sharpe() + self.downside_risk[dt_loc] = \ self.calculate_downside_risk() - metrics.sortino.iloc[dt_loc] = self.calculate_sortino() - metrics.information.iloc[dt_loc] = self.calculate_information() + self.sortino[dt_loc] = self.calculate_sortino() + self.information[dt_loc] = self.calculate_information() self.max_drawdown = self.calculate_max_drawdown() self.max_drawdowns[dt_loc] = self.max_drawdown self.max_leverage = self.calculate_max_leverage() @@ -299,13 +303,12 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" dt = self.latest_dt dt_loc = self.latest_dt_loc period_label = dt.strftime("%Y-%m") - metrics = self.metrics rval = { 'trading_days': self.num_trading_days, 'benchmark_volatility': - metrics.benchmark_volatility.iloc[dt_loc], + self.benchmark_volatility[dt_loc], 'algo_volatility': - metrics.algorithm_volatility.iloc[dt_loc], + self.algorithm_volatility[dt_loc], 'treasury_period_return': self.treasury_period_return, # Though the two following keys say period return, # they would be more accurately called the cumulative return. @@ -315,11 +318,11 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" self.algorithm_cumulative_returns[dt_loc], 'benchmark_period_return': self.benchmark_cumulative_returns[dt_loc], - 'beta': metrics.beta.iloc[dt_loc], - 'alpha': metrics.alpha.iloc[dt_loc], - 'sharpe': metrics.sharpe.iloc[dt_loc], - 'sortino': metrics.sortino.iloc[dt_loc], - 'information': metrics.information.iloc[dt_loc], + 'beta': self.beta[dt_loc], + 'alpha': self.alpha[dt_loc], + 'sharpe': self.sharpe[dt_loc], + 'sortino': self.sortino[dt_loc], + 'information': self.information[dt_loc], 'excess_return': self.excess_returns[dt_loc], 'max_drawdown': self.max_drawdown, 'max_leverage': self.max_leverage, @@ -332,7 +335,7 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" def __repr__(self): statements = [] for metric in self.METRIC_NAMES: - value = getattr(self.metrics, metric)[-1] + value = getattr(self, metric)[-1] if isinstance(value, list): if len(value) == 0: value = np.nan @@ -390,7 +393,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_loc], + self.algorithm_volatility[self.latest_dt_loc], self.annualized_mean_returns_cont[self.latest_dt_loc], self.daily_treasury[self.latest_dt.date()]) @@ -401,14 +404,14 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" return sortino_ratio( self.annualized_mean_returns_cont[self.latest_dt_loc], self.daily_treasury[self.latest_dt.date()], - self.metrics.downside_risk[self.latest_dt_loc]) + self.downside_risk[self.latest_dt_loc]) def calculate_information(self): """ http://en.wikipedia.org/wiki/Information_ratio """ return information_ratio( - self.metrics.algorithm_volatility[self.latest_dt_loc], + self.algorithm_volatility[self.latest_dt_loc], self.annualized_mean_returns_cont[self.latest_dt_loc], self.annualized_mean_benchmark_returns_cont[self.latest_dt_loc]) @@ -420,7 +423,7 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" self.annualized_mean_returns_cont[self.latest_dt_loc], self.treasury_period_return, self.annualized_mean_benchmark_returns_cont[self.latest_dt_loc], - self.metrics.beta.iloc[self.latest_dt_loc]) + self.beta[self.latest_dt_loc]) def calculate_volatility(self, daily_returns): if len(daily_returns) <= 1: