diff --git a/tests/test_perf_tracking.py b/tests/test_perf_tracking.py index 2a46bf83..6a62a184 100644 --- a/tests/test_perf_tracking.py +++ b/tests/test_perf_tracking.py @@ -1270,3 +1270,8 @@ class TestPerformanceTracker(unittest.TestCase): msg_1['minute_perf']['period_close']) self.assertEquals(foo_event_2.dt, msg_2['minute_perf']['period_close']) + + # Ensure that a Sharpe value for cumulative metrics is being + # created. + self.assertIsNotNone(msg_1['cumulative_risk_metrics']['sharpe']) + self.assertIsNotNone(msg_2['cumulative_risk_metrics']['sharpe']) diff --git a/zipline/finance/performance/tracker.py b/zipline/finance/performance/tracker.py index 58dc6de4..154ec88d 100644 --- a/zipline/finance/performance/tracker.py +++ b/zipline/finance/performance/tracker.py @@ -114,7 +114,8 @@ class PerformanceTracker(object): self.cumulative_risk_metrics = \ risk.RiskMetricsCumulative(self.sim_params, - returns_frequency='daily') + returns_frequency='daily', + create_first_day_stats=True) self.minute_performance = PerformancePeriod( # initial cash is your capital base. diff --git a/zipline/finance/risk/cumulative.py b/zipline/finance/risk/cumulative.py index a13c8603..3b06c96e 100644 --- a/zipline/finance/risk/cumulative.py +++ b/zipline/finance/risk/cumulative.py @@ -84,7 +84,9 @@ class RiskMetricsCumulative(object): 'information', ) - def __init__(self, sim_params, returns_frequency=None): + def __init__(self, sim_params, + returns_frequency=None, + create_first_day_stats=False): """ - @returns_frequency allows for configuration of the whether the benchmark and algorithm returns are in units of minutes or days, @@ -114,6 +116,8 @@ class RiskMetricsCumulative(object): self.sim_params = sim_params + self.create_first_day_stats = create_first_day_stats + if returns_frequency is None: returns_frequency = self.sim_params.emission_rate @@ -175,6 +179,12 @@ class RiskMetricsCumulative(object): self.algorithm_returns_cont[dt] = algorithm_returns self.algorithm_returns = self.algorithm_returns_cont.valid() + if self.create_first_day_stats: + if len(self.algorithm_returns) == 1: + self.algorithm_returns = pd.Series( + {'null return': 0.0}).append( + self.algorithm_returns) + self.mean_returns = pd.rolling_mean(self.algorithm_returns, window=len(self.algorithm_returns), min_periods=1) @@ -184,6 +194,19 @@ class RiskMetricsCumulative(object): self.benchmark_returns_cont[dt] = benchmark_returns self.benchmark_returns = self.benchmark_returns_cont.valid() + if self.create_first_day_stats: + if len(self.benchmark_returns) == 1: + self.benchmark_returns = pd.Series( + {'null return': 0.0}).append( + self.benchmark_returns) + + self.mean_benchmark_returns = pd.rolling_mean( + self.benchmark_returns, + window=len(self.benchmark_returns), + min_periods=1) + + self.annualized_benchmark_returns = self.mean_benchmark_returns * 252 + self.num_trading_days = len(self.algorithm_returns) self.update_compounded_log_returns() @@ -239,6 +262,19 @@ algorithm_returns ({algo_count}) in range {start} : {end} on {dt}" self.metrics.information[dt] = self.calculate_information() self.max_drawdown = self.calculate_max_drawdown() + if self.create_first_day_stats: + # Remove placeholder 0 return + if 'null return' in self.algorithm_returns: + self.algorithm_returns = self.algorithm_returns.drop( + 'null return') + self.algorithm_returns.index = pd.to_datetime( + self.algorithm_returns.index) + if 'null return' in self.benchmark_returns: + self.benchmark_returns = self.benchmark_returns.drop( + 'null return') + self.benchmark_returns.index = pd.to_datetime( + self.benchmark_returns.index) + def to_dict(self): """ Creates a dictionary representing the state of the risk report.