Пример #1
0
    def update_position(self, current_position, order_amount, current_price, order_type, timestamp):
        """

        :param timestamp:
        :type timestamp:
        :param current_position:
        :type current_position: Position
        :param order_amount:
        :type order_amount:
        :param current_price:
        :type current_price:
        :param order_type:
        :type order_type:
        """
        if order_type == ORDER_TYPE_LONG:
            need_money = (order_amount * current_price) * (1 + self.slippage + self.buy_cost)
            if self.latest_account['cash'] < need_money:
                raise NotEnoughMoneyError()

            self.latest_account['cash'] -= need_money

            # 计算平均价
            long_amount = current_position['long_amount'] + order_amount
            current_position['average_long_price'] = (current_position['average_long_price'] * current_position[
                'long_amount'] + current_price * order_amount) / long_amount

            current_position['long_amount'] = long_amount

            if current_position['trading_t'] == 0:
                current_position['available_long'] += order_amount

        elif order_type == ORDER_TYPE_SHORT:
            need_money = (order_amount * current_price) * (1 + self.slippage + self.buy_cost)
            if self.latest_account['cash'] < need_money:
                raise NotEnoughMoneyError

            self.latest_account['cash'] -= need_money

            short_amount = current_position['short_amount'] + order_amount
            current_position['average_short_price'] = (current_position['average_short_price'] * current_position[
                'short_amount']
                                                       + current_price * order_amount) / short_amount

            current_position['short_amount'] = short_amount

            if current_position['trading_t'] == 0:
                current_position['available_short'] += order_amount

        elif order_type == ORDER_TYPE_CLOSE_LONG:
            self.latest_account['cash'] += (order_amount * current_price * (1 - self.slippage - self.sell_cost))

            current_position['available_long'] -= order_amount
            current_position['long_amount'] -= order_amount

        elif order_type == ORDER_TYPE_CLOSE_SHORT:
            self.latest_account['cash'] += 2 * (order_amount * current_position['average_short_price'])
            self.latest_account['cash'] -= order_amount * current_price * (1 + self.slippage + self.sell_cost)

            current_position['available_short'] -= order_amount
            current_position['short_amount'] -= order_amount

        # save the order info to db
        order_id = '{}_{}_{}_{}'.format(self.trader_name, order_type, current_position['security_id'],
                                        to_time_str(timestamp, TIME_FORMAT_ISO8601))
        order = Order(id=order_id, timestamp=to_pd_timestamp(timestamp), trader_name=self.trader_name,
                      security_id=current_position['security_id'], order_price=current_price, order_amount=order_amount,
                      order_type=order_type,
                      status='success')
        self.session.add(order)
        self.session.commit()
Пример #2
0
    def order(self,
              entity_id,
              current_price,
              current_timestamp,
              order_amount=0,
              order_pct=1.0,
              order_price=0,
              order_type=ORDER_TYPE_LONG,
              order_money=0):
        """
        下单

        Parameters
        ----------
        entity_id : str
            交易标的id

        current_price : float
            当前价格

        current_timestamp: timestamp
            下单的时间

        order_amount : int
            数量

        order_pct : float
            使用可用现金(仓位)的百分比,0.0-1.0

        order_price : float
            用于限价交易

        order_type : {ORDER_TYPE_LONG,ORDER_TYPE_SHORT,ORDER_TYPE_CLOSE_LONG,ORDER_TYPE_CLOSE_SHORT}
            交易类型

        Returns

        """

        # 市价交易,就是买卖是"当时"并"一定"能成交的
        # 简单起见,目前只支持这种方式
        if order_price == 0:
            current_position = self.get_current_position(entity_id=entity_id)

            if not current_position:
                trading_t = get_trading_meta(entity_id=entity_id)['trading_t']
                current_position = {
                    'trader_name': self.trader_name,
                    'entity_id': entity_id,
                    'long_amount': 0,
                    'available_long': 0,
                    'average_long_price': 0,
                    'short_amount': 0,
                    'available_short': 0,
                    'average_short_price': 0,
                    'profit': 0,
                    'value': 0,
                    'trading_t': trading_t
                }
                # add it to latest account
                self.latest_account['positions'].append(current_position)

            # 按钱交易
            if order_money > 0:
                # 开多
                if order_type == ORDER_TYPE_LONG:
                    if current_position['short_amount'] > 0:
                        raise InvalidOrderError(
                            "close the short position before open long")

                    if order_money > self.latest_account['cash']:
                        raise NotEnoughMoneyError()

                    cost = current_price * (1 + self.slippage + self.buy_cost)
                    # 买的数量
                    order_amount = order_money // cost

                    if order_amount > 0:
                        self.update_position(current_position, order_amount,
                                             current_price, order_type,
                                             current_timestamp)
                    else:
                        raise NotEnoughMoneyError()
                # 开空
                elif order_type == ORDER_TYPE_SHORT:
                    if current_position['long_amount'] > 0:
                        raise InvalidOrderError(
                            "close the long position before open short")

                    if order_money > self.latest_account['cash']:
                        raise NotEnoughMoneyError()

                    cost = current_price * (1 + self.slippage + self.buy_cost)

                    order_amount = order_money // cost
                    if order_amount > 0:
                        self.update_position(current_position, order_amount,
                                             current_price, order_type,
                                             current_timestamp)
                    else:
                        raise NotEnoughMoneyError()
                else:
                    raise InvalidOrderParamError(
                        'close long/short not support order_money')

            # 按数量交易
            elif order_amount > 0:
                # 开多
                if order_type == ORDER_TYPE_LONG:
                    if current_position['short_amount'] > 0:
                        raise InvalidOrderError(
                            "close the short position before open long")

                    self.update_position(current_position, order_amount,
                                         current_price, order_type,
                                         current_timestamp)
                # 开空
                elif order_type == ORDER_TYPE_SHORT:
                    if current_position['long_amount'] > 0:
                        raise InvalidOrderError(
                            "close the long position before open short")

                    self.update_position(current_position, order_amount,
                                         current_price, order_type,
                                         current_timestamp)
                # 平多
                elif order_type == ORDER_TYPE_CLOSE_LONG:
                    if current_position['available_long'] >= order_amount:
                        self.update_position(current_position, order_amount,
                                             current_price, order_type,
                                             current_timestamp)
                    else:
                        raise NotEnoughPositionError()
                # 平空
                elif order_type == ORDER_TYPE_CLOSE_SHORT:
                    if current_position['available_short'] >= order_amount:
                        self.update_position(current_position, order_amount,
                                             current_price, order_type,
                                             current_timestamp)
                    else:
                        raise Exception("not enough position")

            # 按仓位比例交易
            elif 0 < order_pct <= 1:
                # 开多
                if order_type == ORDER_TYPE_LONG:
                    if current_position['short_amount'] > 0:
                        raise InvalidOrderError(
                            "close the short position before open long")

                    cost = current_price * (1 + self.slippage + self.buy_cost)
                    want_pay = self.latest_account['cash'] * order_pct
                    # 买的数量
                    order_amount = want_pay // cost
                    if order_amount > 0:
                        self.update_position(current_position, order_amount,
                                             current_price, order_type,
                                             current_timestamp)
                    else:
                        raise NotEnoughMoneyError()
                # 开空
                elif order_type == ORDER_TYPE_SHORT:
                    if current_position['long_amount'] > 0:
                        raise InvalidOrderError(
                            "close the long position before open short")

                    cost = current_price * (1 + self.slippage + self.buy_cost)
                    want_pay = self.latest_account['cash'] * order_pct

                    order_amount = want_pay // cost
                    if order_amount > 0:
                        self.update_position(current_position, order_amount,
                                             current_price, order_type,
                                             current_timestamp)
                    else:
                        raise NotEnoughMoneyError()

                # 平多
                elif order_type == ORDER_TYPE_CLOSE_LONG:
                    if current_position['available_long'] > 0:
                        if order_pct == 1.0:
                            order_amount = current_position['available_long']
                        else:
                            order_amount = math.floor(
                                current_position['available_long'] * order_pct)

                        if order_amount != 0:
                            self.update_position(current_position,
                                                 order_amount, current_price,
                                                 order_type, current_timestamp)
                        else:
                            self.logger.warning(
                                "{} available_long:{} order_pct:{} order_amount:{}",
                                entity_id, current_position['available_long'],
                                order_pct, order_amount)
                    else:
                        raise NotEnoughPositionError()
                # 平空
                elif order_type == ORDER_TYPE_CLOSE_SHORT:
                    if current_position['available_short'] > 0:
                        if order_pct == 1.0:
                            order_amount = current_position['available_short']
                        else:
                            order_amount = math.floor(
                                current_position['available_short'] *
                                order_pct)

                        if order_amount != 0:
                            self.update_position(current_position,
                                                 order_amount, current_price,
                                                 order_type, current_timestamp)
                        else:
                            self.logger.warning(
                                "{} available_long:{} order_pct:{} order_amount:{}",
                                entity_id, current_position['available_long'],
                                order_pct, order_amount)
                    else:
                        raise Exception("not enough position")
Пример #3
0
    def update_position(self, current_position, order_amount, current_price,
                        order_type, timestamp):
        """

        :param timestamp:
        :type timestamp:
        :param current_position:
        :type current_position: Position
        :param order_amount:
        :type order_amount:
        :param current_price:
        :type current_price:
        :param order_type:
        :type order_type:
        """
        if order_type == ORDER_TYPE_LONG:
            need_money = (order_amount * current_price) * (1 + self.slippage +
                                                           self.buy_cost)
            if self.account.cash < need_money:
                if self.rich_mode:
                    self.input_money()
                else:
                    raise NotEnoughMoneyError()

            self.account.cash -= need_money

            # 计算平均价
            long_amount = current_position.long_amount + order_amount
            if long_amount == 0:
                current_position.average_long_price = 0
            current_position.average_long_price = (
                current_position.average_long_price *
                current_position.long_amount +
                current_price * order_amount) / long_amount

            current_position.long_amount = long_amount

            if current_position.trading_t == 0:
                current_position.available_long += order_amount

        elif order_type == ORDER_TYPE_SHORT:
            need_money = (order_amount * current_price) * (1 + self.slippage +
                                                           self.buy_cost)
            if self.account.cash < need_money:
                if self.rich_mode:
                    self.input_money()
                else:
                    raise NotEnoughMoneyError()

            self.account.cash -= need_money

            short_amount = current_position.short_amount + order_amount
            current_position.average_short_price = (
                current_position.average_short_price *
                current_position.short_amount +
                current_price * order_amount) / short_amount

            current_position.short_amount = short_amount

            if current_position.trading_t == 0:
                current_position.available_short += order_amount

        elif order_type == ORDER_TYPE_CLOSE_LONG:
            self.account.cash += order_amount * current_price * (
                1 - self.slippage - self.sell_cost)
            # FIXME:如果没卖完,重新计算计算平均价

            current_position.available_long -= order_amount
            current_position.long_amount -= order_amount

        elif order_type == ORDER_TYPE_CLOSE_SHORT:
            self.account.cash += 2 * (order_amount *
                                      current_position.average_short_price)
            self.account.cash -= order_amount * current_price * (
                1 + self.slippage + self.sell_cost)

            current_position.available_short -= order_amount
            current_position.short_amount -= order_amount

        # save the order info to db
        order_id = "{}_{}_{}_{}".format(
            self.trader_name, order_type, current_position.entity_id,
            to_time_str(timestamp, TIME_FORMAT_ISO8601))
        order = Order(
            id=order_id,
            timestamp=to_pd_timestamp(timestamp),
            trader_name=self.trader_name,
            entity_id=current_position.entity_id,
            order_price=current_price,
            order_amount=order_amount,
            order_type=order_type,
            level=self.level.value,
            status="success",
        )
        self.session.add(order)
        self.session.commit()
Пример #4
0
    def order(
        self,
        entity_id,
        current_price,
        current_timestamp,
        order_amount=0,
        order_pct=1.0,
        order_price=0,
        order_type=ORDER_TYPE_LONG,
        order_money=0,
    ):
        """
        下单

        Parameters
        ----------
        entity_id : str
            交易标的id

        current_price : float
            当前价格

        current_timestamp: timestamp
            下单的时间

        order_amount : int
            数量

        order_pct : float
            使用可用现金(仓位)的百分比,0.0-1.0

        order_price : float
            用于限价交易

        order_type : {ORDER_TYPE_LONG,ORDER_TYPE_SHORT,ORDER_TYPE_CLOSE_LONG,ORDER_TYPE_CLOSE_SHORT}
            交易类型

        Returns

        """

        # 市价交易,就是买卖是"当时"并"一定"能成交的
        # 简单起见,目前只支持这种方式
        if order_price == 0:
            current_position = self.get_current_position(entity_id=entity_id)

            if not current_position:
                trading_t = self.entity_schema.get_trading_t()
                current_position = Position(
                    trader_name=self.trader_name,
                    entity_id=entity_id,
                    long_amount=0,
                    available_long=0,
                    average_long_price=0,
                    short_amount=0,
                    available_short=0,
                    average_short_price=0,
                    profit=0,
                    value=0,
                    trading_t=trading_t,
                )
                # add it to latest account
                self.account.positions.append(current_position)

            # 按钱交易
            if order_money > 0:
                # 开多
                if order_type == ORDER_TYPE_LONG:
                    if current_position.short_amount > 0:
                        raise InvalidOrderError(
                            "close the short position before open long")

                    if order_money > self.account.cash:
                        if self.rich_mode:
                            self.input_money()
                        else:
                            raise NotEnoughMoneyError()

                    cost = current_price * (1 + self.slippage + self.buy_cost)
                    # 买的数量
                    order_amount = order_money // cost

                    if order_amount < 1:
                        self.logger.error(
                            f"invalid order_money:{order_money}, cost:{cost}, order_amount:{order_amount}"
                        )
                        return

                    self.update_position(current_position, order_amount,
                                         current_price, order_type,
                                         current_timestamp)
                # 开空
                elif order_type == ORDER_TYPE_SHORT:
                    if current_position.long_amount > 0:
                        raise InvalidOrderError(
                            "close the long position before open short")

                    if order_money > self.account.cash:
                        if self.rich_mode:
                            self.input_money()
                        else:
                            raise NotEnoughMoneyError()

                    cost = current_price * (1 + self.slippage + self.buy_cost)

                    order_amount = order_money // cost

                    if order_amount < 1:
                        self.logger.error(
                            f"invalid order_money:{order_money}, cost:{cost}, order_amount:{order_amount}"
                        )
                        return
                    self.update_position(current_position, order_amount,
                                         current_price, order_type,
                                         current_timestamp)
                else:
                    raise InvalidOrderParamError(
                        "close long/short not support order_money")

            # 按数量交易
            elif order_amount > 0:
                # 开多
                if order_type == ORDER_TYPE_LONG:
                    if current_position.short_amount > 0:
                        raise InvalidOrderError(
                            "close the short position before open long")

                    self.update_position(current_position, order_amount,
                                         current_price, order_type,
                                         current_timestamp)
                # 开空
                elif order_type == ORDER_TYPE_SHORT:
                    if current_position.long_amount > 0:
                        raise InvalidOrderError(
                            "close the long position before open short")

                    self.update_position(current_position, order_amount,
                                         current_price, order_type,
                                         current_timestamp)
                # 平多
                elif order_type == ORDER_TYPE_CLOSE_LONG:
                    if current_position.available_long >= order_amount:
                        self.update_position(current_position, order_amount,
                                             current_price, order_type,
                                             current_timestamp)
                    else:
                        raise NotEnoughPositionError()
                # 平空
                elif order_type == ORDER_TYPE_CLOSE_SHORT:
                    if current_position.available_short >= order_amount:
                        self.update_position(current_position, order_amount,
                                             current_price, order_type,
                                             current_timestamp)
                    else:
                        raise Exception("not enough position")

            # 按仓位比例交易
            elif 0 < order_pct <= 1:
                # 开多
                if order_type == ORDER_TYPE_LONG:
                    if current_position.short_amount > 0:
                        raise InvalidOrderError(
                            "close the short position before open long")

                    cost = current_price * (1 + self.slippage + self.buy_cost)
                    want_pay = self.account.cash * order_pct
                    # 买的数量
                    order_amount = want_pay // cost

                    if order_amount < 1:
                        if self.rich_mode:
                            self.input_money()
                            order_amount = max(
                                (self.account.cash * order_pct) // cost, 1)
                        else:
                            raise NotEnoughMoneyError()
                    self.update_position(current_position, order_amount,
                                         current_price, order_type,
                                         current_timestamp)
                # 开空
                elif order_type == ORDER_TYPE_SHORT:
                    if current_position.long_amount > 0:
                        raise InvalidOrderError(
                            "close the long position before open short")

                    cost = current_price * (1 + self.slippage + self.buy_cost)
                    want_pay = self.account.cash * order_pct

                    order_amount = want_pay // cost

                    if order_amount < 1:
                        if self.rich_mode:
                            self.input_money()
                            order_amount = max(
                                (self.account.cash * order_pct) // cost, 1)
                        else:
                            raise NotEnoughMoneyError()

                    self.update_position(current_position, order_amount,
                                         current_price, order_type,
                                         current_timestamp)

                # 平多
                elif order_type == ORDER_TYPE_CLOSE_LONG:
                    if current_position.available_long > 0:
                        if order_pct == 1.0:
                            order_amount = current_position.available_long
                        else:
                            order_amount = math.floor(
                                current_position.available_long * order_pct)

                        if order_amount != 0:
                            self.update_position(current_position,
                                                 order_amount, current_price,
                                                 order_type, current_timestamp)
                        else:
                            self.logger.warning(
                                f"{entity_id} available_long:{current_position.available_long} order_pct:{order_pct} order_amount:{order_amount}"
                            )
                    else:
                        raise NotEnoughPositionError()
                # 平空
                elif order_type == ORDER_TYPE_CLOSE_SHORT:
                    if current_position.available_short > 0:
                        if order_pct == 1.0:
                            order_amount = current_position.available_short
                        else:
                            order_amount = math.floor(
                                current_position.available_short * order_pct)

                        if order_amount != 0:
                            self.update_position(current_position,
                                                 order_amount, current_price,
                                                 order_type, current_timestamp)
                        else:
                            self.logger.warning(
                                f"{entity_id} available_long:{current_position.available_long} order_pct:{order_pct} order_amount:{order_amount}"
                            )
                    else:
                        raise Exception("not enough position")
Пример #5
0
    def order(self, security_id, current_price, current_timestamp, order_amount=0, order_pct=1.0, order_price=0,
              order_type=ORDER_TYPE_LONG):
        """
        下单

        Parameters
        ----------
        security_id : str
            交易标的id

        current_price : float
            当前价格

        current_timestamp: timestamp
            下单的时间

        order_amount : int
            数量

        order_pct : float
            使用可用现金(仓位)的百分比,0.0-1.0

        order_price : float
            用于限价交易

        order_type : {ORDER_TYPE_LONG,ORDER_TYPE_SHORT,ORDER_TYPE_CLOSE_LONG,ORDER_TYPE_CLOSE_SHORT}
            交易类型

        Returns
        -------


        """

        # 市价交易,就是买卖是"当时"并"一定"能成交的
        # 简单起见,目前只支持这种方式
        if order_price == 0:
            current_position: Position = self.get_current_position(security_id=security_id)
            the_id = '{}_{}_{}'.format(self.trader_name, security_id,
                                       to_time_str(current_timestamp, TIME_FORMAT_ISO8601))

            if not current_position:
                current_position = Position(id=the_id, trader_name=self.trader_name, timestamp=current_timestamp,
                                            security_id=security_id, long_amount=0, available_long=0,
                                            average_long_price=0, short_amount=0,
                                            available_short=0, average_short_price=0, profit=0, value=0)
            else:
                current_position = Position(id=the_id, trader_name=self.trader_name, timestamp=current_timestamp,
                                            security_id=security_id, long_amount=current_position.long_amount,
                                            available_long=current_position.available_long,
                                            average_long_price=current_position.average_long_price,
                                            short_amount=current_position.short_amount,
                                            available_short=current_position.available_short,
                                            average_short_price=current_position.average_short_price,
                                            profit=current_position.profit, value=current_position.value)

            # 按数量交易
            if order_amount > 0:
                # 开多
                if order_type == ORDER_TYPE_LONG:
                    if current_position.short_amount > 0:
                        raise InvalidOrderError("close the short position before open long")

                    self.update_position(current_position, order_amount, current_price, order_type)
                # 开空
                elif order_type == ORDER_TYPE_SHORT:
                    if current_position.long_amount > 0:
                        raise InvalidOrderError("close the long position before open short")

                    self.update_position(current_position, order_amount, current_price, order_type)
                # 平多
                elif order_type == ORDER_TYPE_CLOSE_LONG:
                    if current_position.available_long >= order_amount:
                        self.update_position(current_position, order_amount, current_price, order_type)
                    else:
                        raise NotEnoughPositionError()
                # 平空
                elif order_type == ORDER_TYPE_CLOSE_SHORT:
                    if current_position.available_short >= order_amount:
                        self.update_position(current_position, order_amount, current_price, order_type)
                    else:
                        raise Exception("not enough position")

            # 按仓位比例交易
            elif 0 < order_pct <= 1:
                # 开多
                if order_type == ORDER_TYPE_LONG:
                    if current_position.short_amount > 0:
                        raise InvalidOrderError("close the short position before open long")

                    cost = current_price * (1 + self.slippage + self.buy_cost)
                    want_pay = self.latest_account.cash * order_pct
                    # 买的数量
                    order_amount = want_pay // cost
                    if order_amount > 0:
                        self.update_position(current_position, order_amount, current_price, order_type)
                    else:
                        raise NotEnoughMoneyError()
                # 开空
                elif order_type == ORDER_TYPE_SHORT:
                    if current_position.long_amount > 0:
                        raise InvalidOrderError("close the long position before open short")

                    cost = current_price * (1 + self.slippage + self.buy_cost)
                    want_pay = self.latest_account.cash * order_pct

                    order_amount = want_pay // cost
                    if order_amount > 0:
                        self.update_position(current_position, order_amount, current_price, order_type)
                    else:
                        raise NotEnoughMoneyError()

                # 平多
                elif order_type == ORDER_TYPE_CLOSE_LONG:
                    if current_position.available_long > 1:
                        if order_pct == 1.0:
                            order_amount = current_position.available_long
                        else:
                            order_amount = math.floor(current_position.available_long * order_pct)

                        if order_amount != 0:
                            self.update_position(current_position, order_amount, current_price, order_type)
                        else:
                            self.logger.warning("{} available_long:{} order_pct:{} order_amount:{}", security_id,
                                                current_position.available_long, order_pct, order_amount)
                    else:
                        raise NotEnoughPositionError()
                # 平空
                elif order_type == ORDER_TYPE_CLOSE_SHORT:
                    if current_position.available_short > 1:
                        if order_pct == 1.0:
                            order_amount = current_position.available_short
                        else:
                            order_amount = math.floor(current_position.available_short * order_pct)

                        if order_amount != 0:
                            self.update_position(current_position, order_amount, current_price, order_type)
                        else:
                            self.logger.warning("{} available_long:{} order_pct:{} order_amount:{}", security_id,
                                                current_position.available_long, order_pct, order_amount)
                    else:
                        raise Exception("not enough position")

            self.update_account(security_id, current_position, current_timestamp)