Пример #1
0
 def submit_order(self, order):
     account = self._env.get_account(order.order_book_id)
     self._env.event_bus.publish_event(
         Event(EVENT.ORDER_PENDING_NEW, account=account, order=copy(order)))
     if order.is_final():
         return
     order.active()
     self._env.event_bus.publish_event(
         Event(EVENT.ORDER_CREATION_PASS,
               account=account,
               order=copy(order)))
     self._match(account, order)
Пример #2
0
 def submit_order(self, order):
     account = self._env.get_account(order.order_book_id)
     self._env.event_bus.publish_event(
         Event(EVENT.ORDER_PENDING_NEW, account=account, order=order))
     if order.is_final():
         return
     if self._env.config.base.frequency == '1d' and not self._match_immediately:
         self._delayed_orders.append((account, order))
         return
     self._open_orders.append((account, order))
     order.active()
     self._env.event_bus.publish_event(
         Event(EVENT.ORDER_CREATION_PASS, account=account, order=order))
     if self._match_immediately:
         self._match()
Пример #3
0
 def update(self, universe):
     if isinstance(universe, (six.string_types, Instrument)):
         universe = [universe]
     new_set = set(universe)
     if new_set != self._set:
         self._set = new_set
         Environment.get_instance().event_bus.publish_event(
             Event(EVENT.POST_UNIVERSE_CHANGED, universe=self._set))
Пример #4
0
def output_profile_result(env):
    stdout_trap = six.StringIO()
    env.profile_deco.print_stats(stdout_trap)
    profile_output = stdout_trap.getvalue()
    profile_output = profile_output.rstrip()
    six.print_(profile_output)
    env.event_bus.publish_event(
        Event(EVENT.ON_LINE_PROFILER_RESULT, result=profile_output))
Пример #5
0
    def init(self):
        if not self._init:
            return

        with ExecutionContext(EXECUTION_PHASE.ON_INIT):
            with ModifyExceptionFromType(EXC_TYPE.USER_EXC):
                self._init(self._user_context)

        Environment.get_instance().event_bus.publish_event(Event(EVENT.POST_USER_INIT))
Пример #6
0
    def cancel_order(self, order):
        account = self._env.get_account(order.order_book_id)

        self._env.event_bus.publish_event(
            Event(EVENT.ORDER_PENDING_CANCEL, account=account, order=order))

        order.mark_cancelled(
            _(u"{order_id} order has been cancelled by user.").format(
                order_id=order.order_id))

        self._env.event_bus.publish_event(
            Event(EVENT.ORDER_CANCELLATION_PASS, account=account, order=order))

        try:
            self._open_orders.remove((account, order))
        except ValueError:
            try:
                self._delayed_orders.remove((account, order))
            except ValueError:
                pass
Пример #7
0
 def _clear_de_listed(self, event):
     de_listed = set()
     env = Environment.get_instance()
     for o in self._set:
         i = env.data_proxy.instruments(o)
         if i.de_listed_date <= env.trading_dt:
             de_listed.add(o)
     if de_listed:
         self._set -= de_listed
         env.event_bus.publish_event(
             Event(EVENT.POST_UNIVERSE_CHANGED, universe=self._set))
Пример #8
0
 def after_trading(self, event):
     for account, order in self._open_orders:
         order.mark_rejected(
             _(u"Order Rejected: {order_book_id} can not match. Market close."
               ).format(order_book_id=order.order_book_id))
         self._env.event_bus.publish_event(
             Event(EVENT.ORDER_UNSOLICITED_UPDATE,
                   account=account,
                   order=order))
     self._open_orders = self._delayed_orders
     self._delayed_orders = []
Пример #9
0
    def _match(self, order_book_id=None):
        open_orders = self._open_orders
        if order_book_id is not None:
            open_orders = [(a, o) for (a, o) in self._open_orders
                           if o.order_book_id == order_book_id]
        self._matcher.match(open_orders)
        final_orders = [(a, o) for a, o in self._open_orders if o.is_final()]
        self._open_orders = [(a, o) for a, o in self._open_orders
                             if not o.is_final()]

        for account, order in final_orders:
            if order.status == ORDER_STATUS.REJECTED or order.status == ORDER_STATUS.CANCELLED:
                self._env.event_bus.publish_event(
                    Event(EVENT.ORDER_UNSOLICITED_UPDATE,
                          account=account,
                          order=order))
Пример #10
0
    def test_on_tick(self):
        from rqrobot.events import EVENT, Event

        self.assertEqual(self.benchmark_account.total_value,
                         self.benchmark_account_total_cash)
        self.assertEqual(len(self.benchmark_account.positions), 0)

        mock_event = Event(EVENT.TICK,
                           tick=mock_tick(mock_instrument(self.benchmark),
                                          last=3000))

        self.env.event_bus.publish_event(mock_event)

        self.assertAlmostEqual(
            self.benchmark_account.positions[self.benchmark].quantity,
            4000 / 3000)
        self.env.event_bus.publish_event(mock_event)
        self.assertAlmostEqual(
            self.benchmark_account.positions[self.benchmark].quantity,
            4000 / 3000)
Пример #11
0
        def check_before_trading(e):
            if self._last_before_trading == event.trading_dt.date():
                return False

            if self._env.config.extra.is_hold:
                return False

            if self._last_before_trading:
                # don't publish settlement on first day
                publish_settlement()

            self._last_before_trading = e.trading_dt.date()
            update_time(e)
            event_bus.publish_event(PRE_BEFORE_TRADING)
            event_bus.publish_event(
                Event(EVENT.BEFORE_TRADING,
                      calendar_dt=e.calendar_dt,
                      trading_dt=e.trading_dt))
            event_bus.publish_event(POST_BEFORE_TRADING)

            return True
Пример #12
0
    def test_on_bar(self):
        from rqrobot.events import EVENT, Event

        self.assertEqual(self.benchmark_account.total_value,
                         self.benchmark_account_total_cash)
        self.assertEqual(len(self.benchmark_account.positions), 0)

        mock_event = Event(EVENT.PRE_BAR,
                           bar_dict={
                               self.benchmark:
                               mock_bar(mock_instrument(self.benchmark),
                                        close=3000)
                           })

        self.env.event_bus.publish_event(mock_event)

        self.assertAlmostEqual(
            self.benchmark_account.positions[self.benchmark].quantity,
            4000 / 3000)
        self.env.event_bus.publish_event(mock_event)
        self.assertAlmostEqual(
            self.benchmark_account.positions[self.benchmark].quantity,
            4000 / 3000)
Пример #13
0
    def match(self, open_orders):
        price_board = self._env.price_board
        for account, order in open_orders:
            order_book_id = order.order_book_id
            instrument = self._env.get_instrument(order_book_id)

            deal_price = self._deal_price_decider(order_book_id, order.side)
            if not is_valid_price(deal_price):
                listed_date = instrument.listed_date.date()
                if listed_date == self._trading_dt.date():
                    reason = _(
                        u"Order Cancelled: current security [{order_book_id}] can not be traded in listed date [{listed_date}]"
                    ).format(
                        order_book_id=order.order_book_id,
                        listed_date=listed_date,
                    )
                else:
                    reason = _(
                        u"Order Cancelled: current bar [{order_book_id}] miss market data."
                    ).format(order_book_id=order.order_book_id)
                order.mark_rejected(reason)
                continue

            if order.type == ORDER_TYPE.LIMIT:
                if order.side == SIDE.BUY and order.price < deal_price:
                    continue
                if order.side == SIDE.SELL and order.price > deal_price:
                    continue
                # 是否限制涨跌停不成交
                if self._price_limit:
                    if order.side == SIDE.BUY and deal_price >= price_board.get_limit_up(
                            order_book_id):
                        continue
                    if order.side == SIDE.SELL and deal_price <= price_board.get_limit_down(
                            order_book_id):
                        continue
                if self._liquidity_limit:
                    if order.side == SIDE.BUY and price_board.get_a1(
                            order_book_id) == 0:
                        continue
                    if order.side == SIDE.SELL and price_board.get_b1(
                            order_book_id) == 0:
                        continue
            else:
                if self._price_limit:
                    if order.side == SIDE.BUY and deal_price >= price_board.get_limit_up(
                            order_book_id):
                        reason = _(
                            "Order Cancelled: current bar [{order_book_id}] reach the limit_up price."
                        ).format(order_book_id=order.order_book_id)
                        order.mark_rejected(reason)
                        continue
                    if order.side == SIDE.SELL and deal_price <= price_board.get_limit_down(
                            order_book_id):
                        reason = _(
                            "Order Cancelled: current bar [{order_book_id}] reach the limit_down price."
                        ).format(order_book_id=order.order_book_id)
                        order.mark_rejected(reason)
                        continue
                if self._liquidity_limit:
                    if order.side == SIDE.BUY and price_board.get_a1(
                            order_book_id) == 0:
                        reason = _(
                            "Order Cancelled: [{order_book_id}] has no liquidity."
                        ).format(order_book_id=order.order_book_id)
                        order.mark_rejected(reason)
                        continue
                    if order.side == SIDE.SELL and price_board.get_b1(
                            order_book_id) == 0:
                        reason = _(
                            "Order Cancelled: [{order_book_id}] has no liquidity."
                        ).format(order_book_id=order.order_book_id)
                        order.mark_rejected(reason)
                        continue

            if self._volume_limit:
                bar = self._env.bar_dict[order_book_id]
                volume_limit = round(
                    bar.volume *
                    self._volume_percent) - self._turnover[order.order_book_id]
                round_lot = instrument.round_lot
                volume_limit = (volume_limit // round_lot) * round_lot
                if volume_limit <= 0:
                    if order.type == ORDER_TYPE.MARKET:
                        reason = _(
                            u"Order Cancelled: market order {order_book_id} volume {order_volume}"
                            u" due to volume limit").format(
                                order_book_id=order.order_book_id,
                                order_volume=order.quantity)
                        order.mark_cancelled(reason)
                    continue

                unfilled = order.unfilled_quantity
                fill = min(unfilled, volume_limit)
            else:
                fill = order.unfilled_quantity

            ct_amount = account.positions.get_or_create(
                order.order_book_id).cal_close_today_amount(fill, order.side)
            price = self._slippage_decider.get_trade_price(order, deal_price)

            trade = Trade.__from_create__(
                order_id=order.order_id,
                price=price,
                amount=fill,
                side=order.side,
                position_effect=order.position_effect,
                order_book_id=order.order_book_id,
                frozen_price=order.frozen_price,
                close_today_amount=ct_amount)
            trade._commission = self._env.get_trade_commission(
                account_type_str2enum(account.type), trade)
            trade._tax = self._env.get_trade_tax(
                account_type_str2enum(account.type), trade)
            order.fill(trade)
            self._turnover[order.order_book_id] += fill

            self._env.event_bus.publish_event(
                Event(EVENT.TRADE, account=account, trade=trade, order=order))

            if order.type == ORDER_TYPE.MARKET and order.unfilled_quantity != 0:
                reason = _(
                    u"Order Cancelled: market order {order_book_id} volume {order_volume} is"
                    u" larger than {volume_percent_limit} percent of current bar volume, fill {filled_volume} actually"
                ).format(order_book_id=order.order_book_id,
                         order_volume=order.quantity,
                         filled_volume=order.filled_quantity,
                         volume_percent_limit=self._volume_percent * 100.0)
                order.mark_cancelled(reason)
Пример #14
0
def run(config, source_code=None, user_funcs=None):
    env = Environment(config)
    persist_helper = None
    init_succeed = False
    mod_handler = ModHandler()

    try:
        # avoid register handlers everytime
        # when running in ipython
        set_loggers(config)
        basic_system_log.debug("\n" + pformat(config.convert_to_dict()))

        if source_code is not None:
            env.set_strategy_loader(SourceCodeStrategyLoader(source_code))
        elif user_funcs is not None:
            env.set_strategy_loader(UserFuncStrategyLoader(user_funcs))
        else:
            env.set_strategy_loader(
                FileStrategyLoader(config.base.strategy_file))
        env.set_global_vars(GlobalVars())
        mod_handler.set_env(env)
        mod_handler.start_up()

        if not env.data_source:
            env.set_data_source(BaseDataSource(config.base.data_bundle_path))
        env.set_data_proxy(DataProxy(env.data_source))

        Scheduler.set_trading_dates_(env.data_source.get_trading_calendar())
        scheduler = Scheduler(config.base.frequency)
        mod_scheduler._scheduler = scheduler

        env._universe = StrategyUniverse()

        _adjust_start_date(env.config, env.data_proxy)

        _validate_benchmark(env.config, env.data_proxy)

        # FIXME
        start_dt = datetime.datetime.combine(config.base.start_date,
                                             datetime.datetime.min.time())
        env.calendar_dt = start_dt
        env.trading_dt = start_dt

        broker = env.broker
        assert broker is not None
        env.portfolio = broker.get_portfolio()

        try:
            env.booking = broker.get_booking()
        except NotImplementedError:
            pass

        env.benchmark_portfolio = create_benchmark_portfolio(env)

        event_source = env.event_source
        assert event_source is not None

        bar_dict = BarMap(env.data_proxy, config.base.frequency)
        env.set_bar_dict(bar_dict)

        if env.price_board is None:
            from .core.bar_dict_price_board import BarDictPriceBoard
            env.price_board = BarDictPriceBoard()

        ctx = ExecutionContext(const.EXECUTION_PHASE.GLOBAL)
        ctx._push()

        env.event_bus.publish_event(Event(EVENT.POST_SYSTEM_INIT))

        scope = create_base_scope(config.base.run_type == RUN_TYPE.BACKTEST)
        scope.update({"g": env.global_vars})

        apis = api_helper.get_apis()
        scope.update(apis)

        scope = env.strategy_loader.load(scope)

        if env.config.extra.enable_profiler:
            enable_profiler(env, scope)

        ucontext = StrategyContext()
        user_strategy = Strategy(env.event_bus, scope, ucontext)
        scheduler.set_user_context(ucontext)

        if not config.extra.force_run_init_when_pt_resume:
            with run_with_user_log_disabled(disabled=config.base.resume_mode):
                user_strategy.init()

        if config.extra.context_vars:
            for k, v in six.iteritems(config.extra.context_vars):
                setattr(ucontext, k, v)

        from .core.executor import Executor
        executor = Executor(env)

        if config.base.persist:
            persist_provider = env.persist_provider
            if persist_provider is None:
                raise RuntimeError(
                    _(u"Missing persist provider. You need to set persist_provider before use persist"
                      ))
            persist_helper = PersistHelper(persist_provider, env.event_bus,
                                           config.base.persist_mode)
            env.set_persist_helper(persist_helper)
            persist_helper.register('core', CoreObjectsPersistProxy(scheduler))
            persist_helper.register('user_context', ucontext)
            persist_helper.register('global_vars', env.global_vars)
            persist_helper.register('universe', env._universe)
            if isinstance(event_source, Persistable):
                persist_helper.register('event_source', event_source)
            persist_helper.register('portfolio', env.portfolio)
            if env.benchmark_portfolio:
                persist_helper.register('benchmark_portfolio',
                                        env.benchmark_portfolio)
            for name, module in six.iteritems(env.mod_dict):
                if isinstance(module, Persistable):
                    persist_helper.register('mod_{}'.format(name), module)
            # broker will restore open orders from account
            if isinstance(broker, Persistable):
                persist_helper.register('broker', broker)
            persist_helper.register('executor', executor)

            env.event_bus.publish_event(Event(EVENT.BEFORE_SYSTEM_RESTORED))
            persist_helper.restore()
            env.event_bus.publish_event(Event(EVENT.POST_SYSTEM_RESTORED))

        init_succeed = True

        # When force_run_init_when_pt_resume is active,
        # we should run `init` after restore persist data
        if config.extra.force_run_init_when_pt_resume:
            assert config.base.resume_mode == True
            with run_with_user_log_disabled(disabled=False):
                env._universe._set = set()
                user_strategy.init()

        executor.run(bar_dict)

        if env.profile_deco:
            output_profile_result(env)
    except CustomException as e:
        if init_succeed and env.config.base.persist and persist_helper and env.config.base.persist_mode == const.PERSIST_MODE.ON_CRASH:
            persist_helper.persist()

        code = _exception_handler(e)
        mod_handler.tear_down(code, e)
    except Exception as e:
        if init_succeed and env.config.base.persist and persist_helper and env.config.base.persist_mode == const.PERSIST_MODE.ON_CRASH:
            persist_helper.persist()

        exc_type, exc_val, exc_tb = sys.exc_info()
        user_exc = create_custom_exception(exc_type, exc_val, exc_tb,
                                           config.base.strategy_file)

        code = _exception_handler(user_exc)
        mod_handler.tear_down(code, user_exc)
    else:
        if (env.config.base.persist and persist_helper
                and env.config.base.persist_mode
                == const.PERSIST_MODE.ON_NORMAL_EXIT):
            persist_helper.persist()
        result = mod_handler.tear_down(const.EXIT_CODE.EXIT_SUCCESS)
        system_log.debug(_(u"strategy run successfully, normal exit"))
        return result
Пример #15
0
    def _match(self, account, order):
        order_book_id = order.order_book_id
        price_board = self._env.price_board

        last_price = price_board.get_last_price(order_book_id)

        if not is_valid_price(last_price):
            instrument = self._env.get_instrument(order_book_id)
            listed_date = instrument.listed_date.date()
            if listed_date == self._env.trading_dt.date():
                reason = _(
                    "Order Cancelled: current security [{order_book_id}] can not be traded in listed date [{listed_date}]"
                ).format(
                    order_book_id=order_book_id,
                    listed_date=listed_date,
                )
            else:
                reason = _(
                    u"Order Cancelled: current bar [{order_book_id}] miss market data."
                ).format(order_book_id=order_book_id)
            order.mark_rejected(reason)
            self._env.event_bus.publish_event(
                Event(EVENT.ORDER_UNSOLICITED_UPDATE,
                      account=account,
                      order=copy(order)))
            return

        if order.type == ORDER_TYPE.LIMIT:
            deal_price = order.frozen_price
        else:
            deal_price = last_price

        if self._price_limit:
            """
            在 Signal 模式下,不再阻止涨跌停是否买进,price_limit 参数表示是否给出警告提示。
            """
            if order.side == SIDE.BUY and deal_price >= price_board.get_limit_up(
                    order_book_id):
                user_system_log.warning(
                    _(u"You have traded {order_book_id} with {quantity} lots in {bar_status}"
                      ).format(order_book_id=order_book_id,
                               quantity=order.quantity,
                               bar_status=BAR_STATUS.LIMIT_UP))
                return
            if order.side == SIDE.SELL and deal_price <= price_board.get_limit_down(
                    order_book_id):
                user_system_log.warning(
                    _(u"You have traded {order_book_id} with {quantity} lots in {bar_status}"
                      ).format(order_book_id=order_book_id,
                               quantity=order.quantity,
                               bar_status=BAR_STATUS.LIMIT_DOWN))
                return

        ct_amount = account.positions.get_or_create(
            order_book_id).cal_close_today_amount(order.quantity, order.side)
        trade_price = self._slippage_decider.get_trade_price(order, deal_price)
        trade = Trade.__from_create__(order_id=order.order_id,
                                      price=trade_price,
                                      amount=order.quantity,
                                      side=order.side,
                                      position_effect=order.position_effect,
                                      order_book_id=order_book_id,
                                      frozen_price=order.frozen_price,
                                      close_today_amount=ct_amount)
        trade._commission = self._env.get_trade_commission(
            account_type_str2enum(account.type), trade)
        trade._tax = self._env.get_trade_tax(
            account_type_str2enum(account.type), trade)
        order.fill(trade)

        self._env.event_bus.publish_event(
            Event(EVENT.TRADE, account=account, trade=trade,
                  order=copy(order)))
Пример #16
0
 def publish_settlement():
     event_bus.publish_event(PRE_SETTLEMENT)
     event_bus.publish_event(Event(EVENT.SETTLEMENT))
     event_bus.publish_event(POST_SETTLEMENT)
Пример #17
0
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from rqrobot.events import EVENT, Event
from rqrobot.utils.rq_json import convert_dict_to_json, convert_json_to_dict

PRE_BEFORE_TRADING = Event(EVENT.PRE_BEFORE_TRADING)
POST_BEFORE_TRADING = Event(EVENT.POST_BEFORE_TRADING)
PRE_BAR = Event(EVENT.PRE_BAR)
POST_BAR = Event(EVENT.POST_BAR)
PRE_TICK = Event(EVENT.PRE_TICK)
POST_TICK = Event(EVENT.POST_TICK)
PRE_AFTER_TRADING = Event(EVENT.PRE_AFTER_TRADING)
POST_AFTER_TRADING = Event(EVENT.POST_AFTER_TRADING)
PRE_SETTLEMENT = Event(EVENT.PRE_SETTLEMENT)
POST_SETTLEMENT = Event(EVENT.POST_SETTLEMENT)


class Executor(object):
    def __init__(self, env):
        self._env = env
        self._last_before_trading = None
Пример #18
0
 def before_trading(self, event):
     for account, order in self._open_orders:
         order.active()
         self._env.event_bus.publish_event(
             Event(EVENT.ORDER_CREATION_PASS, account=account, order=order))
Пример #19
0
    def events(self, start_date, end_date, frequency):
        if frequency == "1d":
            # 根据起始日期和结束日期,获取所有的交易日,然后再循环获取每一个交易日
            for day in self._env.data_proxy.get_trading_dates(
                    start_date, end_date):
                date = day.to_pydatetime()
                dt_before_trading = date.replace(hour=0, minute=0)

                dt_bar = self._get_day_bar_dt(date)
                dt_after_trading = self._get_after_trading_dt(date)

                yield Event(EVENT.BEFORE_TRADING,
                            calendar_dt=dt_before_trading,
                            trading_dt=dt_before_trading)
                yield Event(EVENT.BAR, calendar_dt=dt_bar, trading_dt=dt_bar)
                yield Event(EVENT.AFTER_TRADING,
                            calendar_dt=dt_after_trading,
                            trading_dt=dt_after_trading)
        elif frequency == '1m':
            for day in self._env.data_proxy.get_trading_dates(
                    start_date, end_date):
                before_trading_flag = True
                date = day.to_pydatetime()
                last_dt = None
                done = False

                dt_before_day_trading = date.replace(hour=8, minute=30)

                while True:
                    if done:
                        break
                    exit_loop = True
                    trading_minutes = self._get_trading_minutes(date)
                    for calendar_dt in trading_minutes:
                        if last_dt is not None and calendar_dt < last_dt:
                            continue

                        if calendar_dt < dt_before_day_trading:
                            trading_dt = calendar_dt.replace(year=date.year,
                                                             month=date.month,
                                                             day=date.day)
                        else:
                            trading_dt = calendar_dt
                        if before_trading_flag:
                            before_trading_flag = False
                            yield Event(EVENT.BEFORE_TRADING,
                                        calendar_dt=calendar_dt -
                                        datetime.timedelta(minutes=30),
                                        trading_dt=trading_dt -
                                        datetime.timedelta(minutes=30))
                        if self._universe_changed:
                            self._universe_changed = False
                            last_dt = calendar_dt
                            exit_loop = False
                            break
                        # yield handle bar
                        yield Event(EVENT.BAR,
                                    calendar_dt=calendar_dt,
                                    trading_dt=trading_dt)
                    if exit_loop:
                        done = True

                dt = self._get_after_trading_dt(date)
                yield Event(EVENT.AFTER_TRADING, calendar_dt=dt, trading_dt=dt)
        elif frequency == "tick":
            data_proxy = self._env.data_proxy
            for day in data_proxy.get_trading_dates(start_date, end_date):
                date = day.to_pydatetime()
                last_tick = None
                last_dt = None
                dt_before_day_trading = date.replace(hour=8, minute=30)
                while True:
                    for tick in data_proxy.get_merge_ticks(
                            self._get_universe(), date, last_dt):
                        # find before trading time

                        calendar_dt = tick.datetime

                        if calendar_dt < dt_before_day_trading:
                            trading_dt = calendar_dt.replace(year=date.year,
                                                             month=date.month,
                                                             day=date.day)
                        else:
                            trading_dt = calendar_dt

                        if last_tick is None:
                            last_tick = tick

                            yield Event(EVENT.BEFORE_TRADING,
                                        calendar_dt=calendar_dt -
                                        datetime.timedelta(minutes=30),
                                        trading_dt=trading_dt -
                                        datetime.timedelta(minutes=30))

                        if self._universe_changed:
                            self._universe_changed = False
                            break

                        last_dt = calendar_dt
                        yield Event(EVENT.TICK,
                                    calendar_dt=calendar_dt,
                                    trading_dt=trading_dt,
                                    tick=tick)

                    else:
                        break

                dt = self._get_after_trading_dt(date)
                yield Event(EVENT.AFTER_TRADING, calendar_dt=dt, trading_dt=dt)
        else:
            raise NotImplementedError(
                _("Frequency {} is not support.").format(frequency))