def test_crosscheck_realtimeclock_with_minutesimulationclock(self): """Tests that RealtimeClock behaves like MinuteSimulationClock""" for minute_emission in (False, True): # MinuteSimulationClock also relies on to_datetime, shall not be # created in the patch block msc = MinuteSimulationClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(8, 45), "US/Eastern"), minute_emission ) msc_events = list(msc) with patch('zipline.gens.realtimeclock.pd.to_datetime') as to_dt, \ patch('zipline.gens.realtimeclock.sleep') as sleep: rtc = iter(RealtimeClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(8, 45), "US/Eastern"), minute_emission )) self.internal_clock = \ pd.Timestamp("2017-04-20 00:00", tz='UTC') to_dt.side_effect = self.get_clock sleep.side_effect = self.advance_clock rtc_events = list(rtc) for rtc_event, msc_event in zip_longest(rtc_events, msc_events): self.assertEquals(rtc_event, msc_event) self.assertEquals(len(rtc_events), len(msc_events))
def test_midday_start(self): """Tests that RealtimeClock is able to execute if started mid-day""" msc = MinuteSimulationClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(8, 45), "US/Eastern"), False ) msc_events = list(msc) with patch('zipline.gens.realtimeclock.pd.to_datetime') as to_dt, \ patch('zipline.gens.realtimeclock.sleep') as sleep: rtc = RealtimeClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(8, 45), "US/Eastern"), False ) to_dt.side_effect = self.get_clock sleep.side_effect = self.advance_clock self.internal_clock = pd.Timestamp("2017-04-20 15:00", tz='UTC') rtc_events = list(rtc) # Count the mid-day position in the MinuteSimulationClock's events: # Simulation Tick: 2017-04-20 00:00:00+00:00 - 1 (SESSION_START) # Simulation Tick: 2017-04-20 12:45:00+00:00 - 4 (BEFORE_TRADING_START) # Simulation Tick: 2017-04-20 13:31:00+00:00 - 0 (BAR) msc_midday_position = 2 + 90 - 1 self.assertEquals(rtc_events[0], msc_events[0]) # Session start bar # BEFORE_TRADING_START is not fired as we're in mid-day self.assertEquals(rtc_events[1:], msc_events[msc_midday_position:])
def __init__(self, start=start_default, end=end_default): with warnings.catch_warnings(): warnings.simplefilter('ignore') _all_days = date_range(start, end, freq=self.day, tz='UTC') self._lunch_break_starts = days_at_time(_all_days, lunch_break_start, self.tz, 0) self._lunch_break_ends = days_at_time(_all_days, lunch_break_end, self.tz, 0) TradingCalendar.__init__(self, start=start_default, end=end_default) self.schedule = pd.DataFrame( index=_all_days, columns=[ 'market_open', 'market_close', 'lunch_break_start', 'lunch_break_end' ], data={ 'market_open': self._opens, 'market_close': self._closes, 'lunch_break_start': self._lunch_break_starts, 'lunch_break_end': self._lunch_break_ends }, dtype='datetime64[ns]', )
def test_current_session(self): regular_minutes = self.trading_calendar.minutes_for_sessions_in_range( self.equity_minute_bar_days[0], self.equity_minute_bar_days[-1] ) bts_minutes = days_at_time( self.equity_minute_bar_days, time(8, 45), "US/Eastern" ) # some other non-market-minute three_oh_six_am_minutes = days_at_time( self.equity_minute_bar_days, time(3, 6), "US/Eastern" ) all_minutes = [regular_minutes, bts_minutes, three_oh_six_am_minutes] for minute in list(concat(all_minutes)): bar_data = self.create_bardata(lambda: minute) self.assertEqual( self.trading_calendar.minute_to_session_label(minute), bar_data.current_session )
def __init__(self, start=start_default, end=end_default): with warnings.catch_warnings(): warnings.simplefilter('ignore') _all_days = date_range(start, end, freq=self.day, tz='UTC') self._lunch_break_starts = days_at_time(_all_days, lunch_break_start, self.tz, 0) self._lunch_break_ends = days_at_time(_all_days, lunch_break_end, self.tz, 0) TradingCalendar.__init__(self, start=start_default, end=end_default)
def test_bts_after_session(self): clock = MinuteSimulationClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(19, 5), "US/Eastern"), False ) all_events = list(clock) # since 19:05 Eastern is after the NYSE is closed, we don't emit # BEFORE_TRADING_START. therefore, each day has SESSION_START, # 390 BARs, and then SESSION_END def _check_session_bts_after(session_label, events): minutes = self.nyse_calendar.minutes_for_session(session_label) self.assertEqual(392, len(events)) self.assertEqual(events[0], (session_label, SESSION_START)) for i in range(1, 391): self.assertEqual(events[i], (minutes[i - 1], BAR)) self.assertEqual(events[-1], (minutes[389], SESSION_END)) for i in range(0, 2): _check_session_bts_after( self.sessions[i], all_events[(i * 392): ((i + 1) * 392)] )
def test_bts_before_session(self): clock = MinuteSimulationClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(6, 17), "US/Eastern"), False) all_events = list(clock) def _check_session_bts_first(session_label, events, bts_dt): minutes = self.nyse_calendar.minutes_for_session(session_label) self.assertEqual(393, len(events)) self.assertEqual(events[0], (session_label, SESSION_START)) self.assertEqual(events[1], (bts_dt, BEFORE_TRADING_START_BAR)) for i in range(2, 392): self.assertEqual(events[i], (minutes[i - 2], BAR)) self.assertEqual(events[392], (minutes[-1], SESSION_END)) _check_session_bts_first( self.sessions[0], all_events[0:393], pd.Timestamp("2016-07-15 6:17", tz='US/Eastern')) _check_session_bts_first( self.sessions[1], all_events[393:786], pd.Timestamp("2016-07-18 6:17", tz='US/Eastern')) _check_session_bts_first( self.sessions[2], all_events[786:], pd.Timestamp("2016-07-19 6:17", tz='US/Eastern'))
def test_bts_after_session(self): clock = MinuteSimulationClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(19, 5), "US/Eastern"), False) all_events = list(clock) # since 19:05 Eastern is after the NYSE is closed, we don't emit # BEFORE_TRADING_START. therefore, each day has SESSION_START, # 390 BARs, and then SESSION_END def _check_session_bts_after(session_label, events): minutes = self.nyse_calendar.minutes_for_session(session_label) self.assertEqual(392, len(events)) self.assertEqual(events[0], (session_label, SESSION_START)) for i in range(1, 391): self.assertEqual(events[i], (minutes[i - 1], BAR)) self.assertEqual(events[-1], (minutes[389], SESSION_END)) for i in range(0, 2): _check_session_bts_after(self.sessions[i], all_events[(i * 392):((i + 1) * 392)])
def _create_clock(self): # This method is taken from TradingAlgorithm. # The clock has been replaced to use RealtimeClock trading_o_and_c = self.trading_calendar.schedule.ix[ self.sim_params.sessions] assert self.sim_params.emission_rate == 'minute' minutely_emission = True market_opens = trading_o_and_c['market_open'] market_closes = trading_o_and_c['market_close'] # The calendar's execution times are the minutes over which we actually # want to run the clock. Typically the execution times simply adhere to # the market open and close times. In the case of the futures calendar, # for example, we only want to simulate over a subset of the full 24 # hour calendar, so the execution times dictate a market open time of # 6:31am US/Eastern and a close of 5:00pm US/Eastern. execution_opens = \ self.trading_calendar.execution_time_from_open(market_opens) execution_closes = \ self.trading_calendar.execution_time_from_close(market_closes) # FIXME generalize these values before_trading_start_minutes = days_at_time(self.sim_params.sessions, time(8, 45), "US/Eastern") return RealtimeClock(self.sim_params.sessions, execution_opens, execution_closes, before_trading_start_minutes, minute_emission=minutely_emission, time_skew=self.broker.time_skew)
def verify_bts_during_session(self, bts_time, bts_session_times, bts_idx): def _check_session_bts_during(session_label, events, bts_dt): minutes = self.nyse_calendar.minutes_for_session(session_label) self.assertEqual(393, len(events)) self.assertEqual(events[0], (session_label, SESSION_START)) for i in range(1, bts_idx): self.assertEqual(events[i], (minutes[i - 1], BAR)) self.assertEqual(events[bts_idx], (bts_dt, BEFORE_TRADING_START_BAR)) for i in range(bts_idx + 1, 391): self.assertEqual(events[i], (minutes[i - 2], BAR)) self.assertEqual(events[392], (minutes[-1], SESSION_END)) clock = MinuteSimulationClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, bts_time, "US/Eastern"), False) all_events = list(clock) _check_session_bts_during(self.sessions[0], all_events[0:393], bts_session_times[0]) _check_session_bts_during(self.sessions[1], all_events[393:786], bts_session_times[1]) _check_session_bts_during(self.sessions[2], all_events[786:], bts_session_times[2])
def test_afterhours_start(self): """Tests that RealtimeClock returns immediately if started after RTH""" with patch('zipline.gens.realtimeclock.pd.to_datetime') as to_dt, \ patch('zipline.gens.realtimeclock.sleep') as sleep: rtc = RealtimeClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(8, 45), "US/Eastern"), False ) to_dt.side_effect = self.get_clock sleep.side_effect = self.advance_clock self.internal_clock = pd.Timestamp("2017-04-20 20:05", tz='UTC') events = list(rtc) self.assertEquals(len(events), 2) # SESSION_START & which always triggered. _, event_type = events[0] self.assertEquals(event_type, SESSION_START) event_time, event_type = events[1] self.assertEquals(event_time, pd.Timestamp("2017-04-20 20:05", tz='UTC')) self.assertEquals(event_type, BEFORE_TRADING_START_BAR)
def test_before_trading_start(self, test_name, num_days, freq, emission_rate): params = factory.create_simulation_parameters( num_days=num_days, data_frequency=freq, emission_rate=emission_rate) def fake_benchmark(self, dt): return 0.01 with patch.object(BenchmarkSource, "get_value", self.fake_minutely_benchmark): algo = BeforeTradingAlgorithm(sim_params=params, env=self.env) algo.run(FakeDataPortal(self.env)) self.assertEqual( len(algo.perf_tracker.sim_params.sessions), num_days ) bts_minutes = days_at_time( params.sessions, time(8, 45), "US/Eastern" ) self.assertTrue( bts_minutes.equals( pd.DatetimeIndex(algo.before_trading_at) ), "Expected %s but was %s." % (params.sessions, algo.before_trading_at))
def __init__(self, start=start_default, end=end_default, path=RQALPHA_BUNDLE_PATH): super(RqalphaAStockTradingCalendar, self).__init__() self._data_source = BaseDataSource(path) _all_days = self._data_source.get_trading_calendar() _all_days = _all_days[_all_days.slice_indexer(start, end)] # `DatetimeIndex`s of standard opens/closes for each day. self._opens = days_at_time(_all_days, self.open_time, self.tz, self.open_offset) self._closes = days_at_time(_all_days, self.close_time, self.tz, self.close_offset) # In pandas 0.16.1 _opens and _closes will lose their timezone # information. This looks like it has been resolved in 0.17.1. # http://pandas.pydata.org/pandas-docs/stable/whatsnew.html#datetime-with-tz # noqa self.schedule = pd.DataFrame( index=_all_days, columns=['market_open', 'market_close'], data={ 'market_open': self._opens, 'market_close': self._closes, }, dtype='datetime64[ns]', ) # Simple cache to avoid recalculating the same minute -> session in # "next" mode. Analysis of current zipline code paths show that # `minute_to_session_label` is often called consecutively with the same # inputs. self._minute_to_session_label_cache = LRU(1) self.market_opens_nanos = self.schedule.market_open.values. \ astype(np.int64) self.market_closes_nanos = self.schedule.market_close.values. \ astype(np.int64) self._trading_minutes_nanos = self.all_minutes.values. \ astype(np.int64) self.first_trading_session = _all_days[0] self.last_trading_session = _all_days[-1]
def __init__(self, sessions, execution_opens, execution_closes, before_trading_start_minutes, minute_emission, time_skew=pd.Timedelta("0s"), is_broker_alive=None): self.sessions = sessions self.execution_opens = execution_opens self.execution_closes = execution_closes self.before_trading_start_minutes = before_trading_start_minutes self.minute_emission = minute_emission self.time_skew = time_skew self.is_broker_alive = is_broker_alive or (lambda: True) self._last_emit = None self.lunch_break_start = days_at_time(sessions,time(11,30),tz='Asia/Shanghai') self.lunch_break_end = days_at_time(sessions,time(13),tz='Asia/Shanghai') self._before_trading_start_bar_yielded = False
def manually_minutes(start, end, calendar): """构造日历指定期间的交易分钟(限定在一个交易日内)""" if start.date() != end.date(): raise ValueError('开始时间与结束时间必须在同一天') if calendar.use_lunch_break: am_close = days_at_time([start.normalize()], calendar.lunch_break_start_time, calendar.tz) pm_open = days_at_time([end.normalize()], calendar.lunch_break_end_time, calendar.tz) am = pd.date_range(start=start, end=(am_close - Timedelta(minutes=1))[0], freq="min") pm = pd.date_range(start=(pm_open + Timedelta(minutes=1))[0], end=end, freq="min") expected = am.union(pm) else: expected = pd.date_range(start=satrt, end=end, freq="min") return expected
def test_midday_start(self): """Tests that RealtimeClock is able to execute if started mid-day""" msc = MinuteSimulationClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(8, 45), "US/Eastern"), False ) msc_events = list(msc) with patch('zipline.gens.realtimeclock.pd.to_datetime') as to_dt, \ patch('zipline.gens.realtimeclock.sleep') as sleep: rtc = RealtimeClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(8, 45), "US/Eastern"), False ) to_dt.side_effect = self.get_clock sleep.side_effect = self.advance_clock self.internal_clock = pd.Timestamp("2017-04-20 15:00", tz='UTC') rtc_events = list(rtc) # Count the mid-day position in the MinuteSimulationClock's events: # Simulation Tick: 2017-04-20 00:00:00+00:00 - 1 (SESSION_START) # Simulation Tick: 2017-04-20 12:45:00+00:00 - 4 (BEFORE_TRADING_START) # Simulation Tick: 2017-04-20 13:31:00+00:00 - 0 (BAR) msc_midday_position = 2 + 90 self.assertEquals(rtc_events[0], msc_events[0]) # Session start bar # before_trading_start is fired immediately if we're after 8:45 EDT event_time, event_type = rtc_events[1] self.assertEquals(event_time, pd.Timestamp("2017-04-20 15:00", tz='UTC')) self.assertEquals(event_type, BEFORE_TRADING_START_BAR) self.assertEquals(rtc_events[2:], msc_events[msc_midday_position:])
def __init__(self, sessions, execution_opens, execution_closes, before_trading_start_minutes, minute_emission, time_skew=pd.Timedelta("0s")): self.sessions = sessions self.execution_opens = execution_opens self.execution_closes = execution_closes self.before_trading_start_minutes = before_trading_start_minutes self.minute_emission = minute_emission self.time_skew = time_skew self._last_emit = None self.lunch_break_start = days_at_time(sessions, time(11, 30), tz='Asia/Shanghai') self.lunch_break_end = days_at_time(sessions, time(13), tz='Asia/Shanghai') self._before_trading_start_bar_yielded = False
def verify_bts_during_session(self, bts_time, bts_session_times, bts_idx): def _check_session_bts_during(session_label, events, bts_dt): minutes = self.nyse_calendar.minutes_for_session(session_label) self.assertEqual(393, len(events)) self.assertEqual(events[0], (session_label, SESSION_START)) for i in range(1, bts_idx): self.assertEqual(events[i], (minutes[i - 1], BAR)) self.assertEqual( events[bts_idx], (bts_dt, BEFORE_TRADING_START_BAR) ) for i in range(bts_idx + 1, 391): self.assertEqual(events[i], (minutes[i - 2], BAR)) self.assertEqual(events[392], (minutes[-1], SESSION_END)) clock = MinuteSimulationClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, bts_time, "US/Eastern"), False ) all_events = list(clock) _check_session_bts_during( self.sessions[0], all_events[0:393], bts_session_times[0] ) _check_session_bts_during( self.sessions[1], all_events[393:786], bts_session_times[1] ) _check_session_bts_during( self.sessions[2], all_events[786:], bts_session_times[2] )
def test_time_skew(self): """Tests that RealtimeClock's time_skew parameter behaves as expected""" for time_skew in (pd.Timedelta("2 hour"), pd.Timedelta("-120 sec")): with patch('zipline.gens.realtimeclock.pd.to_datetime') as to_dt, \ patch('zipline.gens.realtimeclock.sleep') as sleep: clock = RealtimeClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(11, 31), "US/Eastern"), False, time_skew) to_dt.side_effect = self.get_clock sleep.side_effect = self.advance_clock start_time = pd.Timestamp("2017-04-20 15:31", tz='UTC') self.internal_clock = start_time events = list(clock) # Event 0 is SESSION_START which always happens at 00:00. ts, event_type = events[1] self.assertEquals(ts, start_time + time_skew)
def test_bts_before_session(self): clock = MinuteSimulationClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(6, 17), "US/Eastern"), False ) all_events = list(clock) def _check_session_bts_first(session_label, events, bts_dt): minutes = self.nyse_calendar.minutes_for_session(session_label) self.assertEqual(393, len(events)) self.assertEqual(events[0], (session_label, SESSION_START)) self.assertEqual(events[1], (bts_dt, BEFORE_TRADING_START_BAR)) for i in range(2, 392): self.assertEqual(events[i], (minutes[i - 2], BAR)) self.assertEqual(events[392], (minutes[-1], SESSION_END)) _check_session_bts_first( self.sessions[0], all_events[0:393], pd.Timestamp("2016-07-15 6:17", tz='US/Eastern') ) _check_session_bts_first( self.sessions[1], all_events[393:786], pd.Timestamp("2016-07-18 6:17", tz='US/Eastern') ) _check_session_bts_first( self.sessions[2], all_events[786:], pd.Timestamp("2016-07-19 6:17", tz='US/Eastern') )
def _create_clock(self): # This method is taken from TradingAlgorithm. # The clock has been replaced to use RealtimeClock trading_o_and_c = self.trading_calendar.schedule.ix[ self.sim_params.sessions] assert self.sim_params.emission_rate == 'minute' minutely_emission = True market_opens = trading_o_and_c['market_open'] market_closes = trading_o_and_c['market_close'] # The calendar's execution times are the minutes over which we actually # want to run the clock. Typically the execution times simply adhere to # the market open and close times. In the case of the futures calendar, # for example, we only want to simulate over a subset of the full 24 # hour calendar, so the execution times dictate a market open time of # 6:31am US/Eastern and a close of 5:00pm US/Eastern. execution_opens = \ self.trading_calendar.execution_time_from_open(market_opens) execution_closes = \ self.trading_calendar.execution_time_from_close(market_closes) # FIXME generalize these values before_trading_start_minutes = days_at_time( self.sim_params.sessions, time(8, 45), self.trading_calendar.tz ) return RealtimeClock( self.sim_params.sessions, execution_opens, execution_closes, before_trading_start_minutes, minute_emission=minutely_emission, time_skew=self.broker.time_skew, is_broker_alive=self.broker.is_alive )
def test_time_skew(self): """Tests that RealtimeClock's time_skew parameter behaves as expected""" for time_skew in (pd.Timedelta("2 hour"), pd.Timedelta("-120 sec")): with patch('zipline.gens.realtimeclock.pd.to_datetime') as to_dt, \ patch('zipline.gens.realtimeclock.sleep') as sleep: clock = RealtimeClock( self.sessions, self.opens, self.closes, days_at_time(self.sessions, time(11, 31), "US/Eastern"), False, time_skew ) to_dt.side_effect = self.get_clock sleep.side_effect = self.advance_clock start_time = pd.Timestamp("2017-04-20 15:31", tz='UTC') self.internal_clock = start_time events = list(clock) # Event 0 is SESSION_START which always happens at 00:00. ts, event_type = events[1] self.assertEquals(ts, start_time + time_skew)
def test_days_at_time(self, day, day_offset, time_offset, tz, expected): days = pd.DatetimeIndex([pd.Timestamp(day, tz=tz)]) result = days_at_time(days, time_offset, tz, day_offset)[0] expected = pd.Timestamp(expected, tz=tz).tz_convert('UTC') self.assertEqual(result, expected)