Exemple #1
0
def stock_order_shares(id_or_ins, amount, price=None, style=None):
    auto_switch_order_value = Environment.get_instance(
    ).config.mod.sys_accounts.auto_switch_order_value
    account, position, ins = _get_account_position_ins(id_or_ins)
    return _order_shares(assure_instrument(id_or_ins), amount,
                         cal_style(price, style), position.quantity,
                         auto_switch_order_value)
Exemple #2
0
def order_lots(id_or_ins, amount, price=None, style=None):
    # type: (Union[str, Instrument], int, Optional[float], Optional[OrderStyle]) -> Optional[Order]
    """
    指定手数发送买/卖单。如有需要落单类型当做一个参量传入,如果忽略掉落单类型,那么默认是市价单(market order)。

    :param id_or_ins: 下单标的物
    :param int amount: 下单量, 正数代表买入,负数代表卖出。将会根据一手xx股来向下调整到一手的倍数,比如中国A股就是调整成100股的倍数。
    :param float price: 下单价格,默认为None,表示 :class:`~MarketOrder`, 此参数主要用于简化 `style` 参数。
    :param style: 下单类型, 默认是市价单。目前支持的订单类型有 :class:`~LimitOrder` 和 :class:`~MarketOrder`

    :example:

    .. code-block:: python

        #买入20手的平安银行股票,并且发送市价单:
        order_lots('000001.XSHE', 20)
        #买入10手平安银行股票,并且发送限价单,价格为¥10:
        order_lots('000001.XSHE', 10, style=LimitOrder(10))

    """
    ins = assure_instrument(id_or_ins)
    auto_switch_order_value = Environment.get_instance(
    ).config.mod.sys_accounts.auto_switch_order_value
    return _order_shares(ins, amount * int(ins.round_lot),
                         cal_style(price, style), auto_switch_order_value)
Exemple #3
0
def _get_account_position_ins(id_or_ins):
    ins = assure_instrument(id_or_ins)
    try:
        account = Environment.get_instance().portfolio.accounts[
            DEFAULT_ACCOUNT_TYPE.STOCK]
    except KeyError:
        raise KeyError(
            _(u"order_book_id: {order_book_id} needs stock account, please set and try again!"
              ).format(order_book_id=ins.order_book_id))
    position = account.get_position(ins.order_book_id, POSITION_DIRECTION.LONG)
    return account, position, ins
Exemple #4
0
def _get_account_position_ins(id_or_ins):
    ins = assure_instrument(id_or_ins)
    account = Environment.get_instance().portfolio.accounts[
        DEFAULT_ACCOUNT_TYPE.STOCK]
    position = account.get_position(ins.order_book_id, POSITION_DIRECTION.LONG)
    return account, position, ins
Exemple #5
0
def order_target_portfolio(target_portfolio):
    # type: (Dict[Union[str, Instrument], float]) -> List[Order]
    """
    买入/卖出证券以批量调整证券的仓位,以期使其持仓市值占账户总权益的比重达到指定值。

    :param target_portfolio: 下单标的物及其目标市值占比的字典

    :example:

    .. code-block:: python

        # 调整仓位,以使平安银行和万科 A 的持仓占比分别达到 10% 和 15%
        order_target_portfolio({
            '000001.XSHE': 0.1
            '000002.XSHE': 0.15
        })
    """

    if isinstance(target_portfolio, pd.Series):
        # FIXME: kind of dirty
        total_percent = sum(target_portfolio)
    else:
        total_percent = sum(target_portfolio.values())
    if total_percent > 1 and not np.isclose(total_percent, 1):
        raise RQInvalidArgument(
            _(u"total percent should be lower than 1, current: {}").format(
                total_percent))

    env = Environment.get_instance()
    account = env.portfolio.accounts[DEFAULT_ACCOUNT_TYPE.STOCK]
    account_value = account.total_value
    target_quantities = {}
    for id_or_ins, target_percent in target_portfolio.items():
        order_book_id = assure_order_book_id(id_or_ins)
        if target_percent < 0:
            raise RQInvalidArgument(
                _(u"target percent of {} should between 0 and 1, current: {}").
                format(order_book_id, target_percent))
        price = env.data_proxy.get_last_price(order_book_id)
        if not is_valid_price(price):
            user_system_log.warn(
                _(u"Order Creation Failed: [{order_book_id}] No market data").
                format(order_book_id=order_book_id))
            continue
        target_quantities[order_book_id] = (account_value * target_percent /
                                            price, price)

    close_orders, open_orders = [], []
    current_quantities = {
        p.order_book_id: p.quantity
        for p in account.get_positions()
        if p.direction == POSITION_DIRECTION.LONG
    }
    for order_book_id, quantity in current_quantities.items():
        if order_book_id not in target_portfolio:
            close_orders.append(
                Order.__from_create__(order_book_id, quantity, SIDE.SELL,
                                      MarketOrder(), POSITION_EFFECT.CLOSE))

    for order_book_id, (target_quantity, price) in target_quantities.items():
        ins = assure_instrument(order_book_id)
        round_lot = 100
        if order_book_id in current_quantities:
            delta_quantity = target_quantity - current_quantities[order_book_id]
        else:
            delta_quantity = target_quantity

        if _is_ksh(ins):
            # KSH can buy(sell) 201, 202 shares
            delta_quantity = _get_ksh_amount(delta_quantity)
        else:
            delta_quantity = int(
                Decimal(delta_quantity) / Decimal(round_lot)) * round_lot

        if delta_quantity > 0:
            open_order = Order.__from_create__(order_book_id, delta_quantity,
                                               SIDE.BUY, MarketOrder(),
                                               POSITION_EFFECT.OPEN)
            open_order.set_frozen_price(price)
            open_orders.append(open_order)
        elif delta_quantity < -1:
            close_order = Order.__from_create__(order_book_id,
                                                abs(delta_quantity), SIDE.SELL,
                                                MarketOrder(),
                                                POSITION_EFFECT.CLOSE)
            close_order.set_frozen_price(price)
            close_orders.append(close_order)

    submit_orders = []
    for order in chain(close_orders, open_orders):
        if env.can_submit_order(order):
            submit_orders.append(order)
            env.broker.submit_order(order)
    return submit_orders
Exemple #6
0
def _submit_order(id_or_ins, amount, side, position_effect, style):
    amount = int(amount)
    if amount == 0:
        user_system_log.warn(_(u"Order Creation Failed: Order amount is 0."))
        return None
    if isinstance(style, LimitOrder) and style.get_limit_price() <= 0:
        raise RQInvalidArgument(_(u"Limit order price should be positive"))

    instrument = assure_instrument(id_or_ins)
    order_book_id = instrument.order_book_id
    env = Environment.get_instance()
    if env.config.base.run_type != RUN_TYPE.BACKTEST and instrument.type == INSTRUMENT_TYPE.FUTURE:
        if "88" in order_book_id:
            raise RQInvalidArgument(
                _(u"Main Future contracts[88] are not supported in paper trading."
                  ))
        if "99" in order_book_id:
            raise RQInvalidArgument(
                _(u"Index Future contracts[99] are not supported in paper trading."
                  ))

    price = env.get_last_price(order_book_id)
    if not is_valid_price(price):
        user_system_log.warn(
            _(u"Order Creation Failed: [{order_book_id}] No market data").
            format(order_book_id=order_book_id))
        return

    env = Environment.get_instance()

    orders = []
    if position_effect in (POSITION_EFFECT.CLOSE_TODAY, POSITION_EFFECT.CLOSE):
        direction = POSITION_DIRECTION.LONG if side == SIDE.SELL else POSITION_DIRECTION.SHORT
        position = env.portfolio.get_position(order_book_id,
                                              direction)  # type: Position
        if position_effect == POSITION_EFFECT.CLOSE_TODAY:
            if amount > position.today_closable:
                user_system_log.warning(
                    _("Order Creation Failed: "
                      "close today amount {amount} is larger than today closable quantity {quantity}"
                      ).format(amount=amount,
                               quantity=position.today_closable))
                return []
            orders.append(
                Order.__from_create__(order_book_id, amount, side, style,
                                      POSITION_EFFECT.CLOSE_TODAY))
        else:
            quantity, old_quantity = position.quantity, position.old_quantity
            if amount > quantity:
                user_system_log.warn(
                    _(u"Order Creation Failed: close amount {amount} is larger than position quantity {quantity}"
                      ).format(amount=amount, quantity=quantity))
                return []
            if amount > old_quantity:
                if old_quantity != 0:
                    # 如果有昨仓,则创建一个 POSITION_EFFECT.CLOSE 的平仓单
                    orders.append(
                        Order.__from_create__(order_book_id, old_quantity,
                                              side, style,
                                              POSITION_EFFECT.CLOSE))
                # 剩下还有仓位,则创建一个 POSITION_EFFECT.CLOSE_TODAY 的平今单
                orders.append(
                    Order.__from_create__(order_book_id, amount - old_quantity,
                                          side, style,
                                          POSITION_EFFECT.CLOSE_TODAY))
            else:
                # 创建 POSITION_EFFECT.CLOSE 的平仓单
                orders.append(
                    Order.__from_create__(order_book_id, amount, side, style,
                                          POSITION_EFFECT.CLOSE))
    elif position_effect == POSITION_EFFECT.OPEN:
        orders.append(
            Order.__from_create__(order_book_id, amount, side, style,
                                  position_effect))
    else:
        raise NotImplementedError()

    if len(orders) > 1:
        user_system_log.warn(
            _("Order was separated, original order: {original_order_repr}, new orders: [{new_orders_repr}]"
              ).
            format(
                original_order_repr=
                "Order(order_book_id={}, quantity={}, side={}, position_effect={})"
                .format(order_book_id, amount, side, position_effect),
                new_orders_repr=", ".join([
                    "Order({}, {}, {}, {})".format(o.order_book_id, o.quantity,
                                                   o.side, o.position_effect)
                    for o in orders
                ])))

    for o in orders:
        if o.type == ORDER_TYPE.MARKET:
            o.set_frozen_price(price)
        if env.can_submit_order(o):
            env.broker.submit_order(o)
        else:
            orders.remove(o)

    # 向前兼容,如果创建的order_list 只包含一个订单的话,直接返回对应的订单,否则返回列表
    if len(orders) == 1:
        return orders[0]
    else:
        return orders