diff --git a/tests/test_perf_tracking.py b/tests/test_perf_tracking.py index 23c34172..088d88dc 100644 --- a/tests/test_perf_tracking.py +++ b/tests/test_perf_tracking.py @@ -862,6 +862,56 @@ class TestDividendPerformance(unittest.TestCase): [event['cumulative_perf']['capital_used'] for event in results] self.assertEqual(cumulative_cash_flows, [0, 0, 0, 0, 0]) + @with_environment() + def test_no_dividend_at_simulation_end(self, env=None): + # post some trades in the market + events = factory.create_trade_history( + 1, + [10, 10, 10, 10, 10], + [100, 100, 100, 100, 100], + oneday, + self.sim_params + ) + dividend = factory.create_dividend( + 1, + 10.00, + # declared date, when the algorithm finds out about + # the dividend + events[-3].dt, + # ex_date, the date before which the algorithm must hold stock + # to receive the dividend + events[-2].dt, + # pay date, when the algorithm receives the dividend. + # This pays out on the day after the last event + env.next_trading_day(events[-1].dt) + ) + + # Set the last day to be the last event + self.sim_params.period_end = events[-1].dt + self.sim_params._update_internal() + + # Simulate a transaction being filled prior to the ex_date. + txns = [create_txn(events[0], 10.0, 100)] + results = calculate_results( + self, + events, + dividend_events=[dividend], + txns=txns, + ) + + self.assertEqual(len(results), 5) + cumulative_returns = \ + [event['cumulative_perf']['returns'] for event in results] + self.assertEqual(cumulative_returns, [0.0, 0.0, 0.0, 0.0, 0.0]) + daily_returns = [event['daily_perf']['returns'] for event in results] + self.assertEqual(daily_returns, [0.0, 0.0, 0.0, 0.0, 0.0]) + cash_flows = [event['daily_perf']['capital_used'] for event in results] + self.assertEqual(cash_flows, [-1000, 0, 0, 0, 0]) + cumulative_cash_flows = \ + [event['cumulative_perf']['capital_used'] for event in results] + self.assertEqual(cumulative_cash_flows, + [-1000, -1000, -1000, -1000, -1000]) + class TestDividendPerformanceHolidayStyle(TestDividendPerformance): diff --git a/zipline/finance/performance/tracker.py b/zipline/finance/performance/tracker.py index 1b8b21e2..3c529bc9 100644 --- a/zipline/finance/performance/tracker.py +++ b/zipline/finance/performance/tracker.py @@ -346,7 +346,7 @@ class PerformanceTracker(object): if txn: self.process_transaction(txn) - def check_upcoming_dividends(self, next_trading_day): + def check_upcoming_dividends(self, completed_date): """ Check if we currently own any stocks with dividends whose ex_date is the next trading day. Track how much we should be payed on those @@ -361,6 +361,13 @@ class PerformanceTracker(object): # period, so bail. return + # Get the next trading day and, if it is outside the bounds of the + # simulation, bail. + next_trading_day = TradingEnvironment.instance().\ + next_trading_day(completed_date) + if (next_trading_day is None) or (next_trading_day >= self.last_close): + return + # Dividends whose ex_date is the next trading day. We need to check if # we own any of these stocks so we know to pay them out when the pay # date comes. @@ -402,13 +409,9 @@ class PerformanceTracker(object): bench_since_open, account) - # if this is the close, save the returns objects for cumulative risk - # calculations and update dividends for the next day. + # if this is the close, update dividends for the next day. if dt == self.market_close: - next_trading_day = TradingEnvironment.instance().\ - next_trading_day(todays_date) - if next_trading_day: - self.check_upcoming_dividends(next_trading_day) + self.check_upcoming_dividends(todays_date) def handle_intraday_market_close(self, new_mkt_open, new_mkt_close): """ @@ -460,9 +463,8 @@ class PerformanceTracker(object): self.todays_performance.period_open = self.market_open self.todays_performance.period_close = self.market_close - next_trading_day = env.next_trading_day(completed_date) - if next_trading_day: - self.check_upcoming_dividends(next_trading_day) + # Check for any dividends + self.check_upcoming_dividends(completed_date) return daily_update