BUG: DAY_END action not emitted during minute emission

Refactor AlgorithmSimulator so that DAY_END is emitted for both
minute and daily emission, and that handling of end-of-minute
and end-of-day are separated
This commit is contained in:
Andrew Liang
2016-04-29 17:57:06 -04:00
committed by Jean Bredeche
parent a068eb374a
commit 7641247b41
5 changed files with 57 additions and 56 deletions
+13 -6
View File
@@ -2571,7 +2571,7 @@ class TestOrderCancelation(WithDataPortal,
)
def prep_algo(self, cancelation_string, data_frequency="minute",
amount=1000):
amount=1000, minute_emission=False):
code = self.code.format(cancelation_string, amount)
algo = TradingAlgorithm(
script=code,
@@ -2580,21 +2580,28 @@ class TestOrderCancelation(WithDataPortal,
period_start=self.sim_params.period_start,
period_end=self.sim_params.period_end,
env=self.env,
data_frequency=data_frequency
data_frequency=data_frequency,
emission_rate='minute' if minute_emission else 'daily'
)
)
return algo
@parameterized.expand([
(1,), (-1,),
])
def test_eod_order_cancel_minute(self, direction):
@parameter_space(
direction=[1, -1],
minute_emission=[True, False]
)
def test_eod_order_cancel_minute(self, direction, minute_emission):
"""
Test that EOD order cancel works in minute mode for both shorts and
longs, and both daily emission and minute emission
"""
# order 1000 shares of asset1. the volume is only 1 share per bar,
# so the order should be cancelled at the end of the day.
algo = self.prep_algo(
"set_cancel_policy(cancel_policy.EODCancel())",
amount=np.copysign(1000, direction),
minute_emission=minute_emission
)
log_catcher = TestHandler()
+1 -1
View File
@@ -198,7 +198,7 @@ def calculate_results(sim_params,
except KeyError:
pass
msg = perf_tracker.handle_market_close_daily(date, data_portal)
msg = perf_tracker.handle_market_close(date, data_portal)
perf_tracker.position_tracker.sync_last_sale_prices(
date, False, data_portal,
)
+34 -35
View File
@@ -303,9 +303,7 @@ class PerformanceTracker(object):
def handle_minute_close(self, dt, data_portal):
"""
Handles the close of the given minute. This includes handling
market-close functions if the given minute is the end of the market
day.
Handles the close of the given minute in minute emission.
Parameters
__________
@@ -314,9 +312,7 @@ class PerformanceTracker(object):
Returns
_______
(dict, dict/None)
A tuple of the minute perf packet and daily perf packet.
If the market day has not ended, the daily perf packet is None.
A minute perf packet.
"""
self.position_tracker.sync_last_sale_prices(dt, False, data_portal)
self.update_performance()
@@ -333,40 +329,40 @@ class PerformanceTracker(object):
account.leverage)
minute_packet = self.to_dict(emission_type='minute')
return minute_packet
# if this is the close, update dividends for the next day.
# Return the performance tuple
if dt == self.market_close:
return minute_packet, self._handle_market_close(
todays_date, data_portal._adjustment_reader,
)
else:
return minute_packet, None
def handle_market_close(self, dt, data_portal):
"""
Handles the close of the given day, in both minute and daily emission.
In daily emission, also updates performance, benchmark and risk metrics
as it would in handle_minute_close if it were minute emission.
def handle_market_close_daily(self, dt, data_portal):
Parameters
__________
dt : Timestamp
The minute that is ending
Returns
_______
A daily perf packet.
"""
Function called after handle_data when running with daily emission
rate.
"""
self.position_tracker.sync_last_sale_prices(dt, False, data_portal)
self.update_performance()
completed_date = self.day
account = self.get_account(False)
benchmark_value = self.all_benchmark_returns[completed_date]
if self.emission_rate == 'daily':
# this method is called for both minutely and daily emissions, but
# this chunk of code here only applies for daily emissions. (since
# it's done every minute, elsewhere, for minutely emission).
self.position_tracker.sync_last_sale_prices(dt, False, data_portal)
self.update_performance()
account = self.get_account(False)
self.cumulative_risk_metrics.update(
completed_date,
self.todays_performance.returns,
benchmark_value,
account.leverage)
benchmark_value = self.all_benchmark_returns[completed_date]
daily_packet = self._handle_market_close(
completed_date, data_portal._adjustment_reader,
)
return daily_packet
def _handle_market_close(self, completed_date, adjustment_reader):
self.cumulative_risk_metrics.update(
completed_date,
self.todays_performance.returns,
benchmark_value,
account.leverage)
# increment the day counter before we move markers forward.
self.day_count += 1.0
@@ -400,8 +396,11 @@ class PerformanceTracker(object):
return daily_update
# Check for any dividends, then return the daily perf packet
self.check_upcoming_dividends(next_trading_day=next_trading_day,
adjustment_reader=adjustment_reader)
self.check_upcoming_dividends(
next_trading_day=next_trading_day,
adjustment_reader=data_portal._adjustment_reader
)
return daily_update
def handle_simulation_end(self):
+2 -2
View File
@@ -81,8 +81,8 @@ cdef class MinuteSimulationClock:
if minute_emission:
yield minute, MINUTE_END
if not minute_emission:
yield minutes[-1], DAY_END
yield minutes[-1], DAY_END
cdef class DailySimulationClock:
+7 -12
View File
@@ -199,20 +199,18 @@ class AlgorithmSimulator(object):
once_a_day(dt)
elif action == DAY_END:
# End of the day.
if algo.perf_tracker.emission_rate == 'daily':
handle_benchmark(normalize_date(dt))
execute_order_cancellation_policy()
handle_benchmark(normalize_date(dt))
yield self._get_daily_message(dt, algo, algo.perf_tracker)
elif action == MINUTE_END:
handle_benchmark(dt)
minute_msg, daily_msg = \
minute_msg = \
self._get_minute_message(dt, algo, algo.perf_tracker)
yield minute_msg
if daily_msg:
yield daily_msg
risk_message = algo.perf_tracker.handle_simulation_end()
yield risk_message
@@ -256,7 +254,7 @@ class AlgorithmSimulator(object):
"""
Get a perf message for the given datetime.
"""
perf_message = perf_tracker.handle_market_close_daily(
perf_message = perf_tracker.handle_market_close(
dt, self.data_portal,
)
perf_message['daily_perf']['recorded_vars'] = algo.recorded_vars
@@ -268,12 +266,9 @@ class AlgorithmSimulator(object):
"""
rvars = algo.recorded_vars
minute_message, daily_message = perf_tracker.handle_minute_close(
minute_message = perf_tracker.handle_minute_close(
dt, self.data_portal,
)
minute_message['minute_perf']['recorded_vars'] = rvars
if daily_message:
daily_message["daily_perf"]["recorded_vars"] = rvars
return minute_message, daily_message
return minute_message