Ejemplo n.º 1
0
    def test_booking(self):
        def mock_get_instrument(order_book_id):
            not_delisted_ins = MagicMock()
            not_delisted_ins.de_listed_date = datetime.datetime.max
            not_delisted_ins.type = "Future"

            delisted_ins = MagicMock()
            delisted_ins.de_listed_date = datetime.datetime.min
            delisted_ins.type = "Future"
            if order_book_id == "TF1812":
                return delisted_ins
            return not_delisted_ins

        self.booking.set_state(jsonpickle.encode({
            "long_positions": {
                "RB1812": {
                    "old_quantity": 1, "today_quantity": 3
                }},
            "short_positions": {
                "TF1812": {
                    "today_quantity": 4
                }
            }
        }).encode('utf-8'))


        self.assertPositions({
            (POSITION_DIRECTION.LONG, "RB1812", 3, 1),
            (POSITION_DIRECTION.SHORT, "TF1812", 4, 0)
        })

        self.env.event_bus.publish_event(Event(EVENT.TRADE, trade=Trade.__from_create__(
            0, 0, 2, SIDE.SELL, POSITION_EFFECT.OPEN, "RB1812"
        )))
        self.assertPositions({
            (POSITION_DIRECTION.LONG, "RB1812", 3, 1),
            (POSITION_DIRECTION.SHORT, "RB1812", 2, 0),
            (POSITION_DIRECTION.SHORT, "TF1812", 4, 0)
        })
        self.env.event_bus.publish_event(Event(EVENT.TRADE, trade=Trade.__from_create__(
            0, 0, 3, SIDE.SELL, POSITION_EFFECT.CLOSE, "RB1812"
        )))
        self.assertPositions({
            (POSITION_DIRECTION.LONG, "RB1812", 1, 0),
            (POSITION_DIRECTION.SHORT, "RB1812", 2, 0),
            (POSITION_DIRECTION.SHORT, "TF1812", 4, 0)
        })

        with self.mock_data_proxy_method("instruments", mock_get_instrument):
            self.env.trading_dt = datetime.datetime(2018, 9, 3)
            self.env.event_bus.publish_event(Event(EVENT.PRE_BEFORE_TRADING))
            self.assertPositions({
                (POSITION_DIRECTION.LONG, "RB1812", 0, 1),
                (POSITION_DIRECTION.SHORT, "RB1812", 0, 2),
            })
Ejemplo n.º 2
0
    def test_booking(self):
        def mock_get_instrument(order_book_id):
            not_delisted_ins = MagicMock()
            not_delisted_ins.de_listed_date = datetime.datetime.max
            not_delisted_ins.type = "Future"

            delisted_ins = MagicMock()
            delisted_ins.de_listed_date = datetime.datetime.min
            delisted_ins.type = "Future"
            if order_book_id == "TF1812":
                return delisted_ins
            return not_delisted_ins

        self.booking.set_state(
            jsonpickle.encode({
                "long_positions": {
                    "RB1812": {
                        "old_quantity": 1,
                        "today_quantity": 3
                    }
                },
                "short_positions": {
                    "TF1812": {
                        "today_quantity": 4
                    }
                }
            }).encode('utf-8'))

        self.assertPositions({(POSITION_DIRECTION.LONG, "RB1812", 3, 1),
                              (POSITION_DIRECTION.SHORT, "TF1812", 4, 0)})

        self.env.event_bus.publish_event(
            Event(EVENT.TRADE,
                  trade=Trade.__from_create__(0, 0, 2, SIDE.SELL,
                                              POSITION_EFFECT.OPEN, "RB1812")))
        self.assertPositions({(POSITION_DIRECTION.LONG, "RB1812", 3, 1),
                              (POSITION_DIRECTION.SHORT, "RB1812", 2, 0),
                              (POSITION_DIRECTION.SHORT, "TF1812", 4, 0)})
        self.env.event_bus.publish_event(
            Event(EVENT.TRADE,
                  trade=Trade.__from_create__(0, 0, 3, SIDE.SELL,
                                              POSITION_EFFECT.CLOSE,
                                              "RB1812")))
        self.assertPositions({(POSITION_DIRECTION.LONG, "RB1812", 1, 0),
                              (POSITION_DIRECTION.SHORT, "RB1812", 2, 0),
                              (POSITION_DIRECTION.SHORT, "TF1812", 4, 0)})

        with self.mock_data_proxy_method("instruments", mock_get_instrument):
            self.env.trading_dt = datetime.datetime(2018, 9, 3)
            self.env.event_bus.publish_event(Event(EVENT.PRE_BEFORE_TRADING))
            self.assertPositions({
                (POSITION_DIRECTION.LONG, "RB1812", 0, 1),
                (POSITION_DIRECTION.SHORT, "RB1812", 0, 2),
            })
Ejemplo n.º 3
0
 def _on_pre_bar(self, event):
     if self.open_oders:
         data = self._query_filled_orders()
         if data is not None:
             for item in data:
                 trade_no = item[u'成交编号']
                 if trade_no in self._trade_no:
                     continue
                 entrust_no = item[u'合同编号']
                 order_id = self._order_id_map.get(entrust_no, None)
                 if order_id:
                     order = self._orders.get(order_id, None)
                     if order:
                         account = self._env.get_account(
                             order.order_book_id)
                         user_system_log.info(repr(item))
                         trade = Trade.__from_create__(
                             order_id=order.order_id,
                             price=float(item[u'成交均价']),
                             amount=int(item[u'成交数量']),
                             side=order.side,
                             position_effect=order.position_effect,
                             order_book_id=order.order_book_id,
                             frozen_price=order.frozen_price,
                         )
                         order.fill(trade)
                         self._env.event_bus.publish_event(
                             Event(EVENT.TRADE,
                                   account=account,
                                   trade=trade,
                                   order=order))
                         self._trade_no.add(trade_no)
Ejemplo n.º 4
0
    def on_trade(self, trade_dict):
        self.on_debug('交易回报: %s' % str(trade_dict))
        if self._data_update_date != date.today():
            self._cache.cache_trade(trade_dict)
        else:
            account = Environment.get_instance().get_account(
                trade_dict.order_book_id)

            if trade_dict.trade_id in account._backward_trade_set:
                return

            try:
                order = self.order_objects[trade_dict.order_id]
            except KeyError:
                order = Order.__from_create__(trade_dict.order_book_id,
                                              trade_dict.amount,
                                              trade_dict.side,
                                              trade_dict.style,
                                              trade_dict.position_effect)
            commission = cal_commission(trade_dict, order.position_effect)
            trade = Trade.__from_create__(trade_dict.order_id,
                                          trade_dict.price,
                                          trade_dict.amount,
                                          trade_dict.side,
                                          trade_dict.position_effect,
                                          trade_dict.order_book_id,
                                          trade_id=trade_dict.trade_id,
                                          commission=commission,
                                          frozen_price=trade_dict.price)

            order.fill(trade)
            self._env.event_bus.publish_event(
                RqEvent(EVENT.TRADE, account=account, trade=trade))
Ejemplo n.º 5
0
 def _on_post_bar(self, event):
     if self._open_orders:
         data = self._query_filled_orders()
         if data is not None:
             for item in data:
                 trade_no = item[u'成交编号']
                 if trade_no in self._trade_no:
                     continue
                 entrust_no = item[u'合同编号']
                 order_id = self._order_id_map.get(entrust_no, None)
                 if order_id:
                     order = self._open_orders.get(order_id, None)
                     if order:
                         trade = Trade.__from_create__(
                             order_id=order.order_id,
                             price=float(item[u'成交均价']),
                             amount=int(item[u'成交数量']),
                             side=order.side,
                             position_effect=order.position_effect,
                             order_book_id=order.order_book_id,
                             frozen_price=order.frozen_price,
                         )
                         account = self._env.get_account(order.order_book_id)
                         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=order))
                         self._trade_no.add(trade_no)
                         if order.is_final():
                             str_order_id = str(order.order_id)
                             del self._open_orders[str_order_id]
                             del self._order_id_map[entrust_no]
                             del self._order_id_map[str_order_id]
Ejemplo n.º 6
0
    def _match(self, account, order):
        # TODO support tick cal
        env = Environment.get_instance()
        bar = env.get_bar(order.order_book_id)
        bar_status = bar._bar_status

        if bar_status == BAR_STATUS.ERROR:
            listed_date = bar.instrument.listed_date.date()
            if listed_date == self._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.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)
            self._env.event_bus.publish_event(Event(EVENT.ORDER_UNSOLICITED_UPDATE, account=account, order=order))
            return

        if isinstance(order.style, LimitOrder):
            deal_price = order.style.get_limit_price()
        else:
            deal_price = bar.close

        deal_price = min(deal_price, bar.high)
        deal_price = max(deal_price, bar.low)

        deal_price = self._slippage_decider.get_trade_price(order.side, deal_price)

        if (order.side == SIDE.BUY and bar_status == BAR_STATUS.LIMIT_UP) or (
                order.side == SIDE.SELL and bar_status == BAR_STATUS.LIMIT_DOWN):
            user_system_log.warning(_(u"You have traded {order_book_id} with {quantity} lots in {bar_status}").format(
                order_book_id=order.order_book_id,
                quantity=order.quantity,
                bar_status=bar_status
            ))
        ct_amount = account.portfolio.positions.get_or_create(order.order_book_id).cal_close_today_amount(order.quantity, order.side)
        trade = Trade.__from_create__(
            order_id=order.order_id,
            calendar_dt=self._calendar_dt,
            trading_dt=self._trading_dt,
            price=deal_price,
            amount=order.quantity,
            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._commission_decider.get_commission(account.type, trade)
        trade._tax = self._tax_decider.get_tax(account.type, trade)
        order.fill(trade)

        env.event_bus.publish_event(Event(EVENT.TRADE, account=account, trade=trade))
Ejemplo n.º 7
0
    def test_booking(self):
        def mock_get_instrument(order_book_id):
            not_delisted_ins = MagicMock()
            not_delisted_ins.de_listed_date = datetime.datetime.max

            delisted_ins = MagicMock()
            delisted_ins.de_listed_date = datetime.datetime.min
            if order_book_id == "TF1812":
                return delisted_ins
            return not_delisted_ins

        self.assertPositions({(POSITION_DIRECTION.LONG, "RB1812", 3, 1),
                              (POSITION_DIRECTION.SHORT, "TF1812", 4, 0)})

        self.env.event_bus.publish_event(
            Event(EVENT.TRADE,
                  trade=Trade.__from_create__(0, 0, 2, SIDE.SELL,
                                              POSITION_EFFECT.OPEN, "RB1812")))
        self.assertPositions({(POSITION_DIRECTION.LONG, "RB1812", 3, 1),
                              (POSITION_DIRECTION.SHORT, "RB1812", 2, 0),
                              (POSITION_DIRECTION.SHORT, "TF1812", 4, 0)})
        self.env.event_bus.publish_event(
            Event(EVENT.TRADE,
                  trade=Trade.__from_create__(0, 0, 3, SIDE.SELL,
                                              POSITION_EFFECT.CLOSE,
                                              "RB1812")))
        self.assertPositions({(POSITION_DIRECTION.LONG, "RB1812", 1, 0),
                              (POSITION_DIRECTION.SHORT, "RB1812", 2, 0),
                              (POSITION_DIRECTION.SHORT, "TF1812", 4, 0)})

        with self.mock_env_method("get_instrument", mock_get_instrument):
            self.env.trading_dt = datetime.datetime(2018, 8, 31)
            self.env.event_bus.publish_event(Event(EVENT.POST_SETTLEMENT))
            self.assertPositions({
                (POSITION_DIRECTION.LONG, "RB1812", 0, 1),
                (POSITION_DIRECTION.SHORT, "RB1812", 0, 2),
            })
Ejemplo n.º 8
0
    def make_trade(cls, vnpy_trade, order_id=None):
        order_id = order_id if order_id is not None else next(Order.order_id_gen)
        calendar_dt = parse(vnpy_trade.tradeTime)
        trading_dt = cls.make_trading_dt(calendar_dt)
        price = vnpy_trade.price
        amount = vnpy_trade.volume
        side = cls.SIDE_REVERSE[vnpy_trade.direction]
        position_effect = cls.make_position_effect(vnpy_trade.exchange, vnpy_trade.offset)
        order_book_id = cls.make_order_book_id(vnpy_trade.symbol)
        commission = cls.get_commission(order_book_id, position_effect, price, amount)
        frozen_price = vnpy_trade.price

        return Trade.__from_create__(
            order_id, calendar_dt, trading_dt, price, amount, side, position_effect,  order_book_id,
            commission=commission, frozen_price=frozen_price)
Ejemplo n.º 9
0
 def _handle_dividend_payable(self, trading_date):
     # type: (date) -> float
     # 返回总资金的变化量
     if not self._dividend_receivable:
         return 0
     payable_date, dividend_value = self._dividend_receivable
     if payable_date != trading_date:
         return 0
     self._dividend_receivable = None
     if self.dividend_reinvestment:
         last_price = self.last_price
         self.apply_trade(Trade.__from_create__(
             None, last_price, dividend_value / last_price, SIDE.BUY, POSITION_EFFECT.OPEN, self._order_book_id
         ))
         return 0
     else:
         return dividend_value
Ejemplo n.º 10
0
    def _handle_transform(self):
        if not self._pending_transform:
            return
        for predecessor, (successor, conversion_ratio) in six.iteritems(self._pending_transform):
            predecessor_position = self._positions.pop(predecessor)

            self._apply_trade(Trade.__from_create__(
                order_id=None,
                price=predecessor_position.avg_price / conversion_ratio,
                amount=predecessor_position.quantity * conversion_ratio,
                side=SIDE.BUY,
                position_effect=POSITION_EFFECT.OPEN,
                order_book_id=successor
            ))
            user_system_log.warn(_(u"{predecessor} code has changed to {successor}, change position by system").format(
                predecessor=predecessor, successor=successor))

        self._pending_transform.clear()
Ejemplo n.º 11
0
def make_trade(vnpy_trade, order_id=None):
    order_id = order_id if order_id is not None else next(Order.order_id_gen)
    price = vnpy_trade.price
    amount = vnpy_trade.volume
    side = SIDE_REVERSE[vnpy_trade.direction]
    position_effect = make_position_effect(vnpy_trade.exchange,
                                           vnpy_trade.offset)
    order_book_id = make_order_book_id(vnpy_trade.symbol)
    commission = cal_commission(order_book_id, position_effect, price, amount)
    frozen_price = vnpy_trade.price

    return Trade.__from_create__(order_id,
                                 price,
                                 amount,
                                 side,
                                 position_effect,
                                 order_book_id,
                                 commission=commission,
                                 frozen_price=frozen_price)
Ejemplo n.º 12
0
    def _handle_dividend_book_closure(self, trading_date):
        for order_book_id, position in six.iteritems(self._positions):
            if position.quantity == 0:
                continue

            dividend = Environment.get_instance(
            ).data_proxy.get_dividend_by_book_date(order_book_id, trading_date)
            if dividend is None:
                continue

            dividend_per_share = sum(dividend['dividend_cash_before_tax'] /
                                     dividend['round_lot'])
            if np.isnan(dividend_per_share):
                raise RuntimeError(
                    "Dividend per share of {} is not supposed to be nan.".
                    format(order_book_id))

            position.dividend_(dividend_per_share)

            if StockAccount.dividend_reinvestment:
                last_price = position.last_price
                dividend_value = position.quantity * dividend_per_share
                self._static_total_value += dividend_value
                self._apply_trade(
                    Trade.__from_create__(None, last_price,
                                          dividend_value / last_price,
                                          SIDE.BUY, POSITION_EFFECT.OPEN,
                                          order_book_id))
            else:
                self._dividend_receivable[order_book_id] = {
                    'quantity': position.quantity,
                    'dividend_per_share': dividend_per_share,
                }

                try:
                    self._dividend_receivable[order_book_id][
                        'payable_date'] = self._int_to_date(
                            dividend['payable_date'][0])
                except ValueError:
                    self._dividend_receivable[order_book_id][
                        'payable_date'] = self._int_to_date(
                            dividend['ex_dividend_date'][0])
Ejemplo n.º 13
0
    def _match(self, account, order):
        # type: (AbstractAccount, Order) -> Iterable[Trade]
        if order.position_effect != POSITION_EFFECT.EXERCISE:
            raise NotImplementedError("match_exercise is not able to handle {} order".format(order.position_effect))
        price = self._env.data_proxy.get_last_price(order.order_book_id)
        position = account.get_position(order.order_book_id, order.position_direction)  # type: AbstractPosition
        quantity = min(position.closable, order.quantity)

        if quantity == 0:
            order.mark_cancelled(_(u"Order Cancelled: {} has not no exercisable quantity").format(
                order.order_book_id
            ))
        else:
            trade = Trade.__from_create__(
                order.order_id, price, quantity, order.side, POSITION_EFFECT.EXERCISE, order.order_book_id,
                right_type=order.right_type
            )
            trade._commission = self._env.get_trade_commission(trade)
            trade._tax = self._env.get_trade_tax(trade)
            yield trade
Ejemplo n.º 14
0
    def settlement(self, trading_date):
        # type: (date) -> float
        super(StockPosition, self).settlement(trading_date)

        if self.quantity == 0:
            return 0
        if self.direction != POSITION_DIRECTION.LONG:
            raise RuntimeError(
                "direction of stock position {} is not supposed to be short".
                format(self._order_book_id))
        next_date = self._env.data_proxy.get_next_trading_date(trading_date)
        instrument = self._env.data_proxy.instruments(self._order_book_id)
        delta_cash = 0
        if instrument.de_listed_at(next_date):
            try:
                transform_data = self._env.data_proxy.get_share_transformation(
                    self._order_book_id)
            except NotImplementedError:
                pass
            else:
                if transform_data is not None:
                    successor, conversion_ratio = transform_data
                    self._env.portfolio.get_account(successor).apply_trade(
                        Trade.__from_create__(
                            order_id=None,
                            price=self.avg_price / conversion_ratio,
                            amount=self.quantity * conversion_ratio,
                            side=SIDE.BUY,
                            position_effect=POSITION_EFFECT.OPEN,
                            order_book_id=successor))
                    for direction in POSITION_DIRECTION:
                        successor_position = self._env.portfolio.get_position(
                            successor, direction)
                        successor_position.update_last_price(self._last_price /
                                                             conversion_ratio)
                    # 把购买 successor 消耗的 cash 补充回来
                    delta_cash = self.market_value
            if self.cash_return_by_stock_delisted:
                delta_cash = self.market_value
            self._today_quantity = self._old_quantity = 0
        return delta_cash
Ejemplo n.º 15
0
 def _handle_dividend_payable(self, trading_date):
     # type: (date) -> float
     # 返回总资金的变化量
     if not self._dividend_receivable:
         return 0
     payable_date, dividend_value = self._dividend_receivable
     if payable_date != trading_date:
         return 0
     self._dividend_receivable = None
     if self.dividend_reinvestment:
         last_price = self.last_price
         amount = int(Decimal(dividend_value) / Decimal(last_price))
         round_lot = self._instrument.round_lot
         amount = int(Decimal(amount) / Decimal(round_lot)) * round_lot
         if amount > 0:
             self.apply_trade(
                 Trade.__from_create__(None, last_price, amount, SIDE.BUY,
                                       POSITION_EFFECT.OPEN,
                                       self._order_book_id))
         return dividend_value - amount * last_price
     else:
         return dividend_value
Ejemplo n.º 16
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)
Ejemplo n.º 17
0
    def match(self, open_orders):
        for account, order in open_orders:

            bar = self._board[order.order_book_id]
            bar_status = bar._bar_status

            if bar_status == BAR_STATUS.ERROR:
                listed_date = bar.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

            deal_price = self._deal_price_decider(bar)
            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
            else:
                if self._bar_limit and order.side == SIDE.BUY and bar_status == BAR_STATUS.LIMIT_UP:
                    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
                elif self._bar_limit and order.side == SIDE.SELL and bar_status == BAR_STATUS.LIMIT_DOWN:
                    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._bar_limit:
                if order.side == SIDE.BUY and bar_status == BAR_STATUS.LIMIT_UP:
                    continue
                if order.side == SIDE.SELL and bar_status == BAR_STATUS.LIMIT_DOWN:
                    continue

            volume_limit = round(
                bar.volume *
                self._volume_percent) - self._turnover[order.order_book_id]
            round_lot = bar.instrument.round_lot
            volume_limit = (volume_limit // round_lot) * round_lot
            if volume_limit <= 0:
                if order.type == ORDER_TYPE.MARKET:
                    reason = _(
                        'Order Cancelled: market order {order_book_id} volume {order_volume}'
                        ' 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)
            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.side, deal_price)
            trade = Trade.__from_create__(
                order_id=order.order_id,
                calendar_dt=self._calendar_dt,
                trading_dt=self._trading_dt,
                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._commission_decider.get_commission(
                account.type, trade)
            trade._tax = self._tax_decider.get_tax(account.type, trade)
            order.fill(trade)
            self._turnover[order.order_book_id] += fill

            Environment.get_instance().event_bus.publish_event(
                Event(EVENT.TRADE, account=account, trade=trade))

            if order.type == ORDER_TYPE.MARKET and order.unfilled_quantity != 0:
                reason = _(
                    "Order Cancelled: market order {order_book_id} volume {order_volume} is"
                    " larger than 25 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)
                order.mark_cancelled(reason)
Ejemplo n.º 18
0
def _fake_trade(order_book_id, quantity, price):
    return Trade.__from_create__(0, price, abs(quantity),
                                 SIDE.BUY if quantity > 0 else SIDE.SELL,
                                 POSITION_EFFECT.OPEN, order_book_id)
Ejemplo n.º 19
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:
            if order.position_effect != POSITION_EFFECT.EXERCISE:
                if order.side == SIDE.BUY and deal_price >= price_board.get_limit_up(
                        order_book_id):
                    order.mark_rejected(
                        _("Order Cancelled: current bar [{order_book_id}] reach the limit_up price."
                          ).format(order_book_id=order.order_book_id))
                    self._env.event_bus.publish_event(
                        Event(EVENT.ORDER_UNSOLICITED_UPDATE,
                              account=account,
                              order=copy(order)))
                    return

                if order.side == SIDE.SELL and deal_price <= price_board.get_limit_down(
                        order_book_id):
                    order.mark_rejected(
                        _("Order Cancelled: current bar [{order_book_id}] reach the limit_down price."
                          ).format(order_book_id=order.order_book_id))
                    self._env.event_bus.publish_event(
                        Event(EVENT.ORDER_UNSOLICITED_UPDATE,
                              account=account,
                              order=copy(order)))
                    return

        ct_amount = account.calc_close_today_amount(order_book_id,
                                                    order.quantity,
                                                    order.position_direction)
        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(trade)
        trade._tax = self._env.get_trade_tax(trade)
        order.fill(trade)

        self._env.event_bus.publish_event(
            Event(EVENT.TRADE, account=account, trade=trade,
                  order=copy(order)))
Ejemplo n.º 20
0
    def match(self, account, order, open_auction):
        # type: (Account, Order, bool) -> None
        if order.position_effect == POSITION_EFFECT.EXERCISE:
            raise NotImplementedError
        order_book_id = order.order_book_id
        instrument = self._env.get_instrument(order_book_id)

        if open_auction:
            deal_price = self._open_auction_deal_price_decider(
                order_book_id, order.side)
        else:
            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._env.trading_dt.date():
                reason = _(
                    u"Order Cancelled: current security [{order_book_id}] can not be traded"
                    u" 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)
            return

        price_board = self._env.price_board
        if order.type == ORDER_TYPE.LIMIT:
            if order.side == SIDE.BUY and order.price < deal_price:
                return
            if order.side == SIDE.SELL and order.price > deal_price:
                return
            # 是否限制涨跌停不成交
            if self._price_limit:
                if order.side == SIDE.BUY and deal_price >= price_board.get_limit_up(
                        order_book_id):
                    return
                if order.side == SIDE.SELL and deal_price <= price_board.get_limit_down(
                        order_book_id):
                    return
            if self._liquidity_limit:
                if order.side == SIDE.BUY and price_board.get_a1(
                        order_book_id) == 0:
                    return
                if order.side == SIDE.SELL and price_board.get_b1(
                        order_book_id) == 0:
                    return
        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)
                    return
                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)
                    return
            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)
                    return
                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)
                    return

        if self._volume_limit:
            if open_auction:
                volume = self._env.data_proxy.get_open_auction_bar(
                    order_book_id, self._env.calendar_dt).volume
            else:
                volume = self._env.get_bar(order_book_id).volume
            if volume == volume:
                volume_limit = round(
                    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)
                    return

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

        ct_amount = account.calc_close_today_amount(order_book_id, fill,
                                                    order.position_direction)
        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(trade)
        trade._tax = self._env.get_trade_tax(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)
Ejemplo n.º 21
0
 def _create_trade(self, obid, quantity, side, position_effect):
     trade = Trade.__from_create__(0, 0, quantity, side, position_effect,
                                   obid)
     return trade
Ejemplo n.º 22
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)

            if np.isnan(price_board.get_last_price(order_book_id)):
                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

            deal_price = self._deal_price_decider(order_book_id, order.side)
            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.side, deal_price)
            trade = Trade.__from_create__(
                order_id=order.order_id,
                calendar_dt=self._calendar_dt,
                trading_dt=self._trading_dt,
                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._commission_decider.get_commission(
                account.type, trade)
            trade._tax = self._tax_decider.get_tax(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))

            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 25 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)
                order.mark_cancelled(reason)
Ejemplo n.º 23
0
 def _create_trade(self, obid, quantity, side, position_effect):
     trade = Trade.__from_create__(0, 0, quantity, side, position_effect, obid)
     return trade
Ejemplo n.º 24
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 np.isnan(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=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.side, deal_price)
        trade = Trade.__from_create__(order_id=order.order_id,
                                      calendar_dt=self._env.calendar_dt,
                                      trading_dt=self._env.trading_dt,
                                      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._commission_decider.get_commission(
            account.type, trade)
        trade._tax = self._tax_decider.get_tax(account.type, trade)
        order.fill(trade)

        self._env.event_bus.publish_event(
            Event(EVENT.TRADE, account=account, trade=trade))
Ejemplo n.º 25
0
def _fake_trade(order_book_id, quantity, price):
    return Trade.__from_create__(0, price, abs(quantity),
                                 SIDE.BUY if quantity > 0 else SIDE.SELL,
                                 POSITION_EFFECT.OPEN, order_book_id)
Ejemplo n.º 26
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.side, 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._commission_decider.get_commission(account.type, trade)
        trade._tax = self._tax_decider.get_tax(account.type, trade)
        order.fill(trade)

        self._env.event_bus.publish_event(Event(EVENT.TRADE, account=account, trade=trade, order=copy(order)))
Ejemplo n.º 27
0
    def match(self, account, order, open_auction):
        # type: (Account, Order, bool) -> None
        #
        """限价撮合:
        订单买价>卖x价
        买量>卖x量,按照卖x价成交,订单减去卖x量,继续撮合卖x+1,直至该tick中所有报价被买完。买完后若有剩余买量,则在下一个tick继续撮合。
        买量<卖x量,按照卖x价成交。
        反之亦然
        市价单:
        按照该tick,a1,b1进行成交,剩余订单直接撤单
        """
        order_book_id = order.order_book_id

        self._pop_volume_and_price(order)
        if order.side == SIDE.BUY:
            if len(self._a_volume[order_book_id]) == 0:
                return
            volume_limit = self._a_volume[order_book_id][0]
            matching_price = self._a_price[order_book_id][0]
        else:
            if len(self._b_volume[order_book_id]) == 0:
                return
            volume_limit = self._b_volume[order_book_id][0]
            matching_price = self._b_price[order_book_id][0]

        if order.type == ORDER_TYPE.MARKET:
            amount = volume_limit
        else:
            if volume_limit != volume_limit:
                return
            amount = volume_limit
            if amount == 0.0 and order.unfilled_quantity != 0:
                # if order.unfilled_quantity != 0:
                return self.match(account, order, open_auction)

        if matching_price != matching_price:
            return

        if not (order.position_effect in self.SUPPORT_POSITION_EFFECTS
                and order.side in self.SUPPORT_SIDES):
            raise NotImplementedError
        if order.type == ORDER_TYPE.LIMIT:
            if order.side == SIDE.BUY and order.price < matching_price:
                return
            if order.side == SIDE.SELL and order.price > matching_price:
                return
        fill = order.unfilled_quantity
        ct_amount = account.calc_close_today_amount(order_book_id, fill,
                                                    order.position_direction)

        trade = Trade.__from_create__(order_id=order.order_id,
                                      price=matching_price,
                                      amount=min(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(trade)
        trade._tax = self._env.get_trade_tax(trade)
        order.fill(trade)
        self._env.event_bus.publish_event(
            Event(EVENT.TRADE, account=account, trade=trade, order=order))

        if order.side == SIDE.BUY:
            self._a_volume[order.order_book_id][0] -= min(amount, fill)
        else:
            self._b_volume[order.order_book_id][0] -= min(amount, fill)

        if order.type == ORDER_TYPE.MARKET and order.unfilled_quantity != 0:
            reason = _(
                "Order Cancelled: market order {order_book_id} fill {filled_volume} actually"
            ).format(
                order_book_id=order.order_book_id,
                filled_volume=order.filled_quantity,
            )
            order.mark_cancelled(reason)
            return
        if order.unfilled_quantity != 0:
            self.match(account, order, open_auction)