예제 #1
0
class QA_Order():
    '''
        记录order
    '''

    def __init__(
            self,
            price=None,
            date=None,
            datetime=None,
            sending_time=None,
            trade_time=False,
            amount=0,
            market_type=None,
            frequence=None,
            towards=None,
            code=None,
            user_cookie=None,
            account_cookie=None,
            strategy=None,
            order_model=None,
            money=None,
            amount_model=AMOUNT_MODEL.BY_AMOUNT,
            broker=None,
            order_id=None,
            trade_id=False,
            _status=ORDER_STATUS.NEW,
            callback=False,
            commission_coeff=0.00025,
            tax_coeff=0.001,
            exchange_id=None,
            position_id=None,
            *args,
            **kwargs
    ):
        '''




        QA_Order 对象表示一个委托业务, 有如下字段
        - price 委托价格 (限价单用)
        - date 委托日期 (一般日线级别回测用)
        - datetime 当前时间 (分钟线级别和实时用)
        - sending_time 委托时间 (分钟线级别和实时用)
        - trade_time 成交时间 [list] (分钟/日线/实盘时用, 一笔订单多次成交会不断append进去)
        - amount 委托数量
        - frequence 频率 (回测用 DAY/1min/5min/15min/30min/...)
        - towards 买卖方向
        - code  订单的品种
        - user_cookie  订单发起者
        - account_cookie 订单发起账户的标识
        - stratgy 策略号
        - order_model  委托方式(限价/市价/下一个bar/)  type str eg 'limit'
        - money  订单金额
        - amount_model 委托量模式(按量委托/按总成交额委托) type str 'by_amount'
        - order_id   委托单id
        - trade_id   成交单id
        - _status    内部维护的订单状态
        - callback   当订单状态改变的时候 主动回调的函数(可以理解为自动执行的OnOrderAction)
        - commission_coeff 手续费系数
        - tax_coeff  印花税系数(股票)
        - exchange_id  交易所id (一般用于实盘期货)


        :param args: type tuple
        :param kwargs: type dict

        # 2018-08-12 把order变成一个状态机>
        # 以前的order只是一个信息承载的工具,现在需要让他具备状态的方法

        NEW = 100
        SUCCESS_ALL = 200
        SUCCESS_PART = 203 # success_part 是部分成交 一个中间状态 剩余的订单还在委托队列中
        QUEUED = 300  # queued 用于表示在order_queue中 实际表达的意思是订单存活 待成交
        CANCEL = 400
        CANCEL_PART = 402 # cancel_part是部分撤单(及 下单后成交了一部分 剩余的被撤单 这是一个最终状态)
        SETTLED = 500
        FAILED = 600
        '''

        self.price = price
        self.datetime = None

        # 🛠todo 移动到 Util 类中 时间处理函数
        if datetime is None and date is not None:
            self.date = date
            self.datetime = '{} 09:31:00'.format(self.date)
        elif date is None and datetime is not None:
            self.date = datetime[0:10]
            self.datetime = datetime
        elif date is not None and datetime is not None:
            self.date = date
            self.datetime = datetime
        else:
            pass
        self.sending_time = self.datetime if sending_time is None else sending_time  # 下单时间

        self.trade_time = trade_time if trade_time else []  # 成交时间
        self.amount = amount                               # 委托数量
        self.trade_amount = 0                              # 成交数量
        self.cancel_amount = 0                             # 撤销数量
        self.towards = towards                             # side
        self.code = code                                   # 委托证券代码
        self.user_cookie = user_cookie                     # 委托用户
        self.market_type = market_type                     # 委托市场类别
        self.frequence = frequence                         # 委托所在的频率(回测用)
        self.account_cookie = account_cookie
        self.strategy = strategy
        self.type = market_type                            # see below
        self.order_model = order_model
        self.amount_model = amount_model
        self.order_id = QA_util_random_with_topic(
            topic='Order'
        ) if order_id is None else order_id
        self.realorder_id = self.order_id
        self.commission_coeff = commission_coeff
        self.tax_coeff = tax_coeff
        self.trade_id = trade_id if trade_id else []
        self.market_preset = MARKET_PRESET().get_code(self.code)

        self.trade_price = 0                                       # 成交均价
        self.broker = broker
        self.callback = callback                                   # 委托成功的callback
        self.money = money                                         # 委托需要的金钱
        self.reason = None                                         # 原因列表
        self.exchange_id = exchange_id
        self.time_condition = 'GFD'                                # 当日有效
        self._status = _status

        self.position_id = position_id
        # 增加订单对于多账户以及多级别账户的支持 2018/11/12
        self.mainacc_id = None if 'mainacc_id' not in kwargs.keys(
        ) else kwargs['mainacc_id']
        self.subacc_id = None if 'subacc_id' not in kwargs.keys(
        ) else kwargs['subacc_id']
        self.direction = 'BUY' if self.towards in [
            ORDER_DIRECTION.BUY,
            ORDER_DIRECTION.BUY_OPEN,
            ORDER_DIRECTION.BUY_CLOSE
        ] else 'SELL'
        self.offset = 'OPEN' if self.towards in [
            ORDER_DIRECTION.BUY,
            ORDER_DIRECTION.BUY_OPEN,
            ORDER_DIRECTION.SELL_OPEN
        ] else 'CLOSE'

    @property
    def pending_amount(self):
        return self.amount - self.cancel_amount - self.trade_amount

    @property
    def __dict__(self):
        return {
            'price': self.price,
            'datetime': self.datetime,
            'date': self.date,
            'sending_time': self.sending_time,
            'trade_time': self.trade_time,
            'amount': self.amount,
            'trade_amount': self.trade_amount,
            'cancel_amount': self.cancel_amount,
            'towards': self.towards,
            'code': self.code,
            'user_cookie': self.user_cookie,
            'market_type': self.market_type,
            'frequence': self.frequence,
            'account_cookie': self.account_cookie,
            'strategy': self.strategy,
            'type': self.market_type,
            'order_model': self.order_model,
            'amount_model': self.amount_model,
            'order_id': self.order_id,
            'realorder_id': self.realorder_id,
            'commission_coeff': self.commission_coeff,
            'tax_coeff': self.tax_coeff,
            'trade_id': self.trade_id,
            'trade_price': self.trade_price,
            'broker': self.broker,
            'callback': self.callback,
            'money': self.money,
            'reason': self.reason,
            'exchange_id': self.exchange_id,
            'time_condition': self.time_condition,
            '_status': self.status,
            'direction': self.direction,
            'offset': self.offset
        }

    def __repr__(self):
        '''
        输出格式化对象
        :return:  字符串
        '''
        return '< QA_Order realorder_id {} datetime:{} code:{} amount:{} price:{} towards:{} btype:{} order_id:{} account:{} status:{} >'.format(
            self.realorder_id,
            self.datetime,
            self.code,
            self.amount,
            self.price,
            self.towards,
            self.type,
            self.order_id,
            self.account_cookie,
            self.status
        )

    def transform_dt(self, times):
        if isinstance(times, str):
            tradedt = datetime.datetime.strptime(times, '%Y-%m-%d %H:%M:%S') if len(
                times) == 19 else datetime.datetime.strptime(times, '%Y-%m-%d %H:%M:%S.%f')
            return tradedt.timestamp()*1000000000
        elif isinstance(times, datetime.datetime):
            return tradedt.timestamp()*1000000000

    @property
    def status(self):

        # 以下几个都是最终状态 并且是外部动作导致的
        if self._status in [ORDER_STATUS.FAILED,
                            ORDER_STATUS.NEXT,
                            ORDER_STATUS.SETTLED,
                            ORDER_STATUS.CANCEL_ALL,
                            ORDER_STATUS.CANCEL_PART]:
            return self._status

        if self.pending_amount <= 0:
            self._status = ORDER_STATUS.SUCCESS_ALL
            return self._status
        elif self.pending_amount > 0 and self.trade_amount > 0:
            self._status = ORDER_STATUS.SUCCESS_PART
            return self._status
        elif self.trade_amount == 0:
            self._status = ORDER_STATUS.QUEUED
            return self._status

    def calc_commission(self, trade_price, trade_amount):

        if self.market_type == MARKET_TYPE.FUTURE_CN:
            value = trade_price * trade_amount * \
                self.market_preset.get('unit_table', 1)
            if self.towards in [ORDER_DIRECTION.BUY_OPEN,
                                ORDER_DIRECTION.BUY_CLOSE,
                                ORDER_DIRECTION.SELL_CLOSE,
                                ORDER_DIRECTION.SELL_OPEN]:
                commission_fee = self.market_preset['commission_coeff_pervol'] * trade_amount + \
                    self.market_preset['commission_coeff_peramount'] * \
                    abs(value)
            elif self.towards in [ORDER_DIRECTION.BUY_CLOSETODAY,
                                  ORDER_DIRECTION.SELL_CLOSETODAY]:
                commission_fee = self.market_preset['commission_coeff_today_pervol'] * trade_amount + \
                    self.market_preset['commission_coeff_today_peramount'] * \
                    abs(value)
            return commission_fee
        elif self.market_type == MARKET_TYPE.STOCK_CN:
            commission_fee = trade_price * trade_amount * self.commission_coeff

            return max(commission_fee, 5)


    def create(self):
        """创建订单
        """
        # 创建一笔订单(未进入委托队列-- 在创建的时候调用)
        self._status = ORDER_STATUS.NEW

    def cancel(self):
        """撤单

        Arguments:
            amount {int} -- 撤单数量
        """

        self.cancel_amount = self.amount - self.trade_amount
        if self.trade_amount == 0:
            # 未交易  直接订单全撤
            self._status = ORDER_STATUS.CANCEL_ALL
        else:
            # 部分交易 剩余订单全撤
            self._status = ORDER_STATUS.CANCEL_PART

    def failed(self, reason=None):
        """失败订单(未成功创建入broker)

        Arguments:
            reason {str} -- 失败原因
        """
        # 订单创建失败(如废单/场外废单/价格高于涨停价/价格低于跌停价/通讯失败)
        self._status = ORDER_STATUS.FAILED
        self.reason = str(reason)

    def trade(self, trade_id, trade_price, trade_amount, trade_time):
        """trade 状态

        Arguments:
            amount {[type]} -- [description]
        """
        if self.status in [ORDER_STATUS.SUCCESS_PART, ORDER_STATUS.QUEUED]:
            trade_amount = int(trade_amount)
            trade_id = str(trade_id)

            if trade_amount < 1:

                self._status = ORDER_STATUS.NEXT
                return False
            else:
                if trade_id not in self.trade_id:
                    trade_price = float(trade_price)

                    trade_time = str(trade_time)

                    self.trade_id.append(trade_id)
                    self.trade_price = (
                        self.trade_price * self.trade_amount +
                        trade_price * trade_amount
                    ) / (
                        self.trade_amount + trade_amount
                    )
                    self.trade_amount += trade_amount
                    self.trade_time.append(trade_time)
                    res = self.callback(
                        self.code,
                        trade_id,
                        self.order_id,
                        self.realorder_id,
                        trade_price,
                        trade_amount,
                        self.towards,
                        trade_time
                    )
                    if res == 0:
                        return self.trade_message(
                            trade_id,
                            trade_price,
                            trade_amount,
                            trade_time
                        )
                    else:
                        return False
                else:
                    return False
        else:
            print(
                RuntimeError(
                    'ORDER STATUS {} CANNNOT TRADE'.format(self.status)
                )
            )
            return False

    def trade_message(self, trade_id, trade_price, trade_amount, trade_time):
        return {
            "user_id": self.account_cookie,  # //用户ID
            "order_id": self.order_id,  # //交易所单号
            "trade_id": trade_id,  # //委托单ID, 对于一个USER, trade_id 是永远不重复的
            "exchange_id": self.exchange_id,  # //交易所
            "instrument_id": self.code,  # //在交易所中的合约代码
            "exchange_trade_id": trade_id,  # //交易所单号
            "direction": self.direction,  # //下单方向
            "offset": self.offset,  # //开平标志
            "volume": trade_amount,  # //成交手数
            "price": trade_price,  # //成交价格
            "trade_date_time":  trade_time,  # //成交时间, epoch nano
            # //成交手续费
            "commission": self.calc_commission(trade_price, trade_amount),
            "seqno": ''}

    def queued(self, realorder_id):
        self.realorder_id = realorder_id
        self._status = ORDER_STATUS.QUEUED

    def settle(self):
        self._status = ORDER_STATUS.SETTLED

    def get(self, key, exception=None):
        try:
            if key is None:
                print("key is none , return none!")
                return None
            return eval('self.{}'.format(key))
        except Exception as e:
            return exception

    # 🛠todo 建议取消,直接调用var

    def callingback(self):
        """回调函数

        Returns:
            [type] -- [description]
        """

        if self.callback:
            return self.callback

    def info(self):
        '''
        :return:
        '''
        return vars(self)

    # 对象转变成 dfs
    def to_df(self):
        return pd.DataFrame([
            vars(self),
        ])

    # 🛠todo 建议取消,直接调用var?

    def to_dict(self):
        '''
        把对象中的属性转变成字典类型
        :return: dict
        '''
        return vars(self)

    def to_otgdict(self):
        """{
                "aid": "insert_order",                  # //必填, 下单请求
                # //必填, 需要与登录用户名一致, 或为登录用户的子账户(例如登录用户为user1, 则报单 user_id 应当为 user1 或 user1.some_unit)
                "user_id": account_cookie,
                # //必填, 委托单号, 需确保在一个账号中不重复, 限长512字节
                "order_id": order_id if order_id else QA.QA_util_random_with_topic('QAOTG'),
                "exchange_id": exchange_id,  # //必填, 下单到哪个交易所
                "instrument_id": code,               # //必填, 下单合约代码
                "direction": order_direction,                      # //必填, 下单买卖方向
                # //必填, 下单开平方向, 仅当指令相关对象不支持开平机制(例如股票)时可不填写此字段
                "offset":  order_offset,
                "volume":  volume,                             # //必填, 下单手数
                "price_type": "LIMIT",  # //必填, 报单价格类型
                "limit_price": price,  # //当 price_type == LIMIT 时需要填写此字段, 报单价格
                "volume_condition": "ANY",
                "time_condition": "GFD",
            }
        """
        return {
            "aid": "insert_order",                  # //必填, 下单请求
            # //必填, 需要与登录用户名一致, 或为登录用户的子账户(例如登录用户为user1, 则报单 user_id 应当为 user1 或 user1.some_unit)
            "user_id": self.account_cookie,
            # //必填, 委托单号, 需确保在一个账号中不重复, 限长512字节
            "order_id": self.order_id,
            "exchange_id": self.exchange_id,  # //必填, 下单到哪个交易所
            "instrument_id": self.code,               # //必填, 下单合约代码
            "direction": self.direction,                      # //必填, 下单买卖方向
            # //必填, 下单开平方向, 仅当指令相关对象不支持开平机制(例如股票)时可不填写此字段
            "offset":  self.offset,
            "volume":  self.amount,                             # //必填, 下单手数
            "price_type": self.order_model,  # //必填, 报单价格类型
            "limit_price": self.price,  # //当 price_type == LIMIT 时需要填写此字段, 报单价格
            "volume_condition": "ANY",
            "time_condition": "GFD",
        }

    def to_qatradegatway(self):
        """[summary]
        {'topic': 'sendorder', 
        'account_cookie': '100004', 
        'strategy_id': None, 
        'order_direction': 'SELL', 
        'order_offset': 'OPEN', 
        'code': 'rb1910', 
        'price': 3745.0, 
        'order_time': '2019-05-08 13:55:38.000000', 
        'exchange_id': 'SHFE', 
        'volume': 1.0, 
        'order_id': '5ab55219-adf6-432f-90db-f1bc5f29f4e5'}


        'topic': 'sendorder',
        'account_cookie': acc,
        'strategy_id': 'test',
        'code': code,
        'price': price[code],
        'order_direction': 'SELL',
        'order_offset': 'CLOSE',
        'volume': 1,
        'order_time': str(datetime.datetime.now()),
        'exchange_id': 'SHFE'
        """
        return {
            'topic': 'sendorder',
            'account_cookie': self.account_cookie,
            'strategy_id': self.strategy,
            'order_direction': self.direction,
            'order_offset': self.offset,
            'code': self.code.lower(),
            'price': self.price,
            'order_time': self.sending_time,
            'exchange_id': self.get_exchange(self.code),
            'volume': int(self.amount),
            'order_id': self.order_id
        }

    def to_qifi(self):

        return {
            "account_cookie": self.account_cookie,
            "user_id": self.account_cookie,
            "instrument_id": self.code,
            "towards": self.towards,
            "exchange_id": self.exchange_id,
            "order_time": self.datetime,
            "volume": self.amount,
            "price": self.price,
            "order_id": self.order_id,
            "seqno": 1,
            "direction": self.direction,                      # //
            "offset": self.offset,  # //
            "volume_orign": self.amount,
            "price_type": self.order_model,
            "limit_price": self.price,
            "time_condition": "GFD",
            "volume_condition": "ANY",
            "insert_date_time": self.transform_dt(self.datetime),
            "exchange_order_id": self.realorder_id,
            "status": self.status,
            "volume_left": self.pending_amount,
            "last_msg": "",
            "topic": "send_order"
        }

    def from_otgformat(self, otgOrder):
        """[summary]

        Arguments:
            otgOrder {[type]} -- [description]


        {'seqno': 6,
        'user_id': '106184',
        'order_id': 'WDRB_QA01_FtNlyBem',
        'exchange_id': 'SHFE',
        'instrument_id': 'rb1905',
        'direction': 'SELL',
        'offset': 'OPEN',
        'volume_orign': 50, #(总报单手数)
        'price_type': 'LIMIT', # "LIMIT" (价格类型, ANY=市价, LIMIT=限价)
        'limit_price': 3432.0, # 4500.0 (委托价格, 仅当 price_type = LIMIT 时有效)
        'time_condition': 'GFD',#  "GFD" (时间条件, IOC=立即完成,否则撤销, GFS=本节有效, GFD=当日有效, GTC=撤销前有效, GFA=集合竞价有效)
        'volume_condition': 'ANY', # "ANY" (手数条件, ANY=任何数量, MIN=最小数量, ALL=全部数量)
        'insert_date_time': 1545656460000000000,# 1501074872000000000 (下单时间(按北京时间),自unix epoch(1970-01-01 00:00:00 GMT)以来的纳秒数)
        'exchange_order_id': '        3738',
        'status': 'FINISHED', # "ALIVE" (委托单状态, ALIVE=有效, FINISHED=已完)
        'volume_left': 0,
        'last_msg': '全部成交报单已提交'} # "报单成功" (委托单状态信息)
        """
        self.order_id = otgOrder.get('order_id')
        self.account_cookie = otgOrder.get('user_id')
        self.exchange_id = otgOrder.get('exchange_id')
        self.code = str(otgOrder.get('instrument_id')).upper()
        self.offset = otgOrder.get('offset')
        self.direction = otgOrder.get('direction')
        self.towards = eval(
            'ORDER_DIRECTION.{}_{}'.format(self.direction,
                                           self.offset)
        )
        self.amount = otgOrder.get('volume_orign')
        self.trade_amount = self.amount - otgOrder.get('volume_left')
        self.price = otgOrder.get('limit_price')
        self.order_model = eval(
            'ORDER_MODEL.{}'.format(otgOrder.get('price_type'))
        )
        self.time_condition = otgOrder.get('time_condition')
        if otgOrder.get('insert_date_time') == 0:
            self.datetime = 0
        else:
            self.datetime = QA_util_stamp2datetime(
                int(otgOrder.get('insert_date_time'))
            )
        self.sending_time = self.datetime
        self.volume_condition = otgOrder.get('volume_condition')
        self.message = otgOrder.get('last_msg')

        self._status = ORDER_STATUS.NEW
        if '拒绝' in self.message or '仓位不足' in self.message:
            # 仓位不足:  一般是平今/平昨仓位不足
            self._status = ORDER_STATUS.FAILED
        if '已撤单' in self.message:
            self._status = ORDER_STATUS.CANCEL_ALL
        self.realorder_id = otgOrder.get('exchange_order_id')
        return self

    def from_dict(self, order_dict):
        '''
        从字段类型的字段 填充 对象的字段
        :param order_dict:  dict 类型
        :return: self QA_Order
        '''
        try:
            # QA_util_log_info('QA_ORDER CHANGE: from {} change to {}'.format(
            #     self.order_id, order['order_id']))
            self.price = order_dict['price']
            self.date = order_dict['date']
            self.datetime = order_dict['datetime']
            self.sending_time = order_dict['sending_time']  # 下单时间
            self.trade_time = order_dict['trade_time']
            self.amount = order_dict['amount']
            self.frequence = order_dict['frequence']
            self.market_type = order_dict['market_type']
            self.towards = order_dict['towards']
            self.code = order_dict['code']
            self.user_cookie = order_dict['user_cookie']
            self.account_cookie = order_dict['account_cookie']
            self.strategy = order_dict['strategy']
            self.type = order_dict['type']
            self.order_model = order_dict['order_model']
            self.amount_model = order_dict['amount_model']
            self.order_id = order_dict['order_id']
            self.realorder_id = order_dict['realorder_id']
            self.trade_id = order_dict['trade_id']
            self.callback = order_dict['callback']
            self.commission_coeff = order_dict['commission_coeff']
            self.tax_coeff = order_dict['tax_coeff']

            self.money = order_dict['money']
            self._status = order_dict['_status']

            self.cancel_amount = order_dict['cancel_amount']
            self.trade_amount = order_dict['trade_amount']
            self.trade_price = order_dict['trade_price']
            self.reason = order_dict['reason']

            return self
        except Exception as e:
            QA_util_log_info('Failed to tran from dict {}'.format(e))
예제 #2
0
class QA_Position():
    """一个持仓模型:/兼容股票期货/兼容保证金持仓

    兼容快期DIFF协议

    基础字段

    code [str]  品种名称 
    volume_long_today [float] 今仓 多单持仓
    volume_long_his   [float] 昨仓 多单持仓
    volume_short_today [float] 今仓 空单持仓
    volume_short_his  [float] 昨仓 空单持仓

    volume_long_frozen_his [float] 多单昨日冻结
    volume_long_frozen_today [float] 多单今日冻结
    volume_short_frozen_his [float] 空单昨日冻结
    volume_short_frozen_today [float] 空单今日冻结

    margin_long  [float] 多单保证金
    margin_short [float] 空单保证金

    open_price_long [float] 多单开仓价
    open_price_short [float] 空单开仓价
    position_price_long [float] 逐日盯市的前一交易日的结算价
    position_price_short [float] 逐日盯市的前一交易日的结算价

    open_cost_long [float] 多单开仓成本(指的是保证金冻结)
    open_cost_short [float] 空单开仓成本
    position_cost_long [float] 多单持仓成本(指的是基于逐日盯市制度下的成本价)
    position_cost_short [float] 空单持仓成本


    market_type=MARKET_TYPE.STOCK_CN [enum] 市场类别
    exchange_id=EXCHANGE_ID.SZSE [enum] 交易所id(支持股票/期货)
    name=None [str] 名称


    功能:

    1/ 支持当价格变化后的 持仓的自行计算更新
    2/ 支持调仓模型(未加入)
    3/ 支持仓位风控(未加入)
    4/ 支持资金分配和PMS内部资金结算(moneypreset)

    PMS 内部可以预分配一个资金限额, 方便pms实时计算属于PMS的收益

    兼容QA_Account的创建/拆入Positions库

    QAPosition 不对订单信息做正确性保证, 需要自行在外部构建 OMS系统 {QACEPEngine/QAAccountPro}

    """

    def __init__(self,
                 code='000001',
                 account_cookie='quantaxis',
                 portfolio_cookie='portfolio',
                 username='******',
                 user_cookie = '',
                 moneypreset=100000,  # 初始分配资金
                 frozen=None,
                 moneypresetLeft=None,
                 volume_long_today=0,
                 volume_long_his=0,
                 volume_short_today=0,
                 volume_short_his=0,

                 volume_long_frozen_his=0,
                 volume_long_frozen_today=0,
                 volume_short_frozen_his=0,
                 volume_short_frozen_today=0,

                 margin_long=0,
                 margin_short=0,

                 open_price_long=0,
                 open_price_short=0,
                 position_price_long=0,  # 逐日盯市的前一交易日的结算价
                 position_price_short=0,  # 逐日盯市的前一交易日的结算价

                 open_cost_long=0,
                 open_cost_short=0,
                 position_cost_long=0,
                 position_cost_short=0,
                 position_id=None,

                 market_type=None,
                 exchange_id=None,
                 trades=None,
                 orders=None,
                 name=None,
                 commission=0,
                 auto_reload=False,
                 allow_exceed=False,

                 spms_id=None,
                 oms_id=None,
                 *args,
                 **kwargs

                 ):

        self.code = code
        self.account_cookie = account_cookie
        self.portfolio_cookie = portfolio_cookie
        self.user_cookie = user_cookie
        self.username = username
        self.time = ''
        self.market_preset = MARKET_PRESET().get_code(self.code)
        self.position_id = str(
            uuid.uuid4()) if position_id is None else position_id
        self.moneypreset = moneypreset
        self.moneypresetLeft = self.moneypreset if moneypresetLeft is None else moneypresetLeft
        """{'name': '原油',
            'unit_table': 1000,
            'price_tick': 0.1,
            'buy_frozen_coeff': 0.1,
            'sell_frozen_coeff': 0.1,
            'exchange': 'INE',
            'commission_coeff_peramount': 0,
            'commission_coeff_pervol': 20.0,
            'commission_coeff_today_peramount': 0,
            'commission_coeff_today_pervol': 0.0}
        """
        self.rule = 'FIFO'
        self.name = name

        if market_type is None:

            self.market_type = MARKET_TYPE.FUTURE_CN if re.search(
                r'[a-zA-z]+', self.code) else MARKET_TYPE.STOCK_CN
        self.exchange_id = exchange_id

        self.volume_long_his = volume_long_his
        self.volume_long_today = volume_long_today
        self.volume_short_his = volume_short_his
        self.volume_short_today = volume_short_today

        self.volume_long_frozen_his = volume_long_frozen_his
        self.volume_long_frozen_today = volume_long_frozen_today
        self.volume_short_frozen_his = volume_short_frozen_his
        self.volume_short_frozen_today = volume_short_frozen_today

        self.margin_long = margin_long
        self.margin_short = margin_short

        self.open_price_long = open_price_long
        self.open_price_short = open_price_short

        self.position_price_long = open_price_long if position_price_long == 0 else position_price_long
        self.position_price_short = open_price_short if position_price_short == 0 else position_price_short

        self.open_cost_long = open_cost_long if open_cost_long != 0 else open_price_long * \
            self.volume_long*self.market_preset.get('unit_table', 1)
        self.open_cost_short = open_cost_short if open_cost_short != 0 else open_price_short * \
            self.volume_short*self.market_preset.get('unit_table', 1)
        self.position_cost_long = position_cost_long if position_cost_long != 0 else self.position_price_long * \
            self.volume_long*self.market_preset.get('unit_table', 1)
        self.position_cost_short = position_cost_short if position_cost_short != 0 else self.position_price_short * \
            self.volume_short*self.market_preset.get('unit_table', 1)

        self.last_price = 0
        self.commission = commission
        self.trades = [] if trades is None else trades
        self.orders = {} if orders is None else orders
        self.frozen = {} if frozen is None else frozen
        self.spms_id = spms_id
        self.oms_id = oms_id
        if auto_reload:
            self.reload()
        self.allow_exceed = allow_exceed

    def __repr__(self):
        return '< QAPOSITION {} amount {}/{} >'.format(
            self.code,
            self.volume_long,
            self.volume_short
        )

    def read_diff(self, diff_slice):
        """[summary]

        Arguments:
            diff_slice {dict} -- [description]

            {'user_id': '100002',
            'exchange_id': 'SHFE',
            'instrument_id': 'rb1905',
            'volume_long_today': 0,
            'volume_long_his': 0,
            'volume_long': 0,
            'volume_long_frozen_today': 0,
            'volume_long_frozen_his': 0,
            'volume_long_frozen': 0,
            'volume_short_today': 0,
            'volume_short_his': 0,
            'volume_short': 0,
            'volume_short_frozen_today': 0,
            'volume_short_frozen_his': 0,
            'volume_short_frozen': 0,
            'open_price_long': 4193.0,
            'open_price_short': 4192.0,
            'open_cost_long': 0.0,
            'open_cost_short': 0.0,
            'position_price_long': 4193.0,
            'position_price_short': 4192.0,
            'position_cost_long': 0.0,
            'position_cost_short': 0.0,
            'last_price': 4137.0,
            'float_profit_long': 0.0,
            'float_profit_short': 0.0,
            'float_profit': 0.0,
            'position_profit_long': 0.0,
            'position_profit_short': 0.0,
            'position_profit': 0.0,
            'margin_long': 0.0,
            'margin_short': 0.0,
            'margin': 0.0}

        Returns:
            QA_Position -- [description]
        """
        self.account_cookie = diff_slice['user_id']
        self.code = diff_slice['instrument_id']
        self.volume_long_today = diff_slice['volume_long_today']
        self.volume_long_his = diff_slice['volume_long_his']
        self.volume_long_frozen_today = diff_slice['volume_long_frozen_today']
        self.volume_long_frozen_his = diff_slice['volume_long_frozen_his']
        self.volume_short_today = diff_slice['volume_short_today']
        self.volume_short_his = diff_slice['volume_short_his']
        self.volume_short_frozen_today = diff_slice['volume_short_frozen_today']
        self.volume_short_frozen_his = diff_slice['volume_short_frozen_his']
        self.open_price_long = diff_slice['open_price_long']
        self.open_price_short = diff_slice['open_price_short']
        self.open_cost_long = diff_slice['open_cost_long']
        self.open_cost_short = diff_slice['open_cost_short']
        self.position_price_long = diff_slice['position_price_long']
        self.position_price_short = diff_slice['position_price_short']
        self.position_cost_long = diff_slice['position_cost_long']
        self.position_cost_short = diff_slice['position_cost_short']
        self.margin_long = diff_slice['margin_long']
        self.margin_short = diff_slice['margin_short']
        self.exchange_id = diff_slice['exchange_id']
        self.market_type = MARKET_TYPE.FUTURE_CN
        return self

    @property
    def volume_long(self):
        return self.volume_long_today + self.volume_long_his + self.volume_long_frozen
    @property
    def volume_short(self):
        return self.volume_short_his + self.volume_short_today+ self.volume_short_frozen

    @property
    def volume_long_frozen(self):
        return self.volume_long_frozen_his + self.volume_long_frozen_today

    @property
    def volume_short_frozen(self):
        return self.volume_short_frozen_his + self.volume_short_frozen_today

    @property
    def margin(self):
        return self.margin_long + self.margin_short

    @property
    def float_profit_long(self):
        if self.market_preset is not None:
            return self.last_price * self.volume_long * self.market_preset.get(
                'unit_table',
                1
            ) - self.open_cost_long

    @property
    def float_profit_short(self):
        if self.market_preset is not None:
            return self.open_cost_short - self.last_price * self.volume_short * self.market_preset.get(
                'unit_table',
                1
            )

    @property
    def float_profit(self):
        return self.float_profit_long + self.float_profit_short

    @property
    def position_profit_long(self):
        if self.market_preset is not None:
            return self.last_price * self.volume_long * self.market_preset.get(
                'unit_table',
                1
            ) - self.position_cost_long

    @property
    def position_profit_short(self):
        if self.market_preset is not None:
            return self.position_cost_short - self.last_price * self.volume_short * self.market_preset.get(
                'unit_table',
                1
            )

    @property
    def position_profit(self):
        return self.position_profit_long + self.position_profit_short

    @property
    def static_message(self):
        return {
            # 基础字段
            'code': self.code,  # 品种名称
            'instrument_id': self.code,
            'user_id': self.account_cookie,
            'portfolio_cookie': self.portfolio_cookie,
            'username': self.username,
            'position_id': self.position_id,
            'account_cookie': self.account_cookie,
            'user_cookie': self.user_cookie,
            'frozen': self.frozen,
            'name': self.name,
            'spms_id': self.spms_id,
            'oms_id': self.oms_id,
            'market_type': self.market_type,
            'exchange_id': self.exchange_id,  # 交易所ID
            'moneypreset': self.moneypreset,
            'moneypresetLeft': self.moneypresetLeft,
            'lastupdatetime': str(self.time),
            # 持仓量
            'volume_long_today': self.volume_long_today,
            'volume_long_his': self.volume_long_his,
            'volume_long': self.volume_long,
            'volume_short_today': self.volume_short_today,
            'volume_short_his': self.volume_short_his,
            'volume_short': self.volume_short,
            # 平仓委托冻结(未成交)
            'volume_long_frozen_today': self.volume_long_frozen_today,
            'volume_long_frozen_his': self.volume_long_frozen_his,
            'volume_long_frozen': self.volume_long_frozen,
            'volume_short_frozen_today': self.volume_short_frozen_today,
            'volume_short_frozen_his': self.volume_short_frozen_his,
            'volume_short_frozen': self.volume_short_frozen,
            # 保证金
            'margin_long': self.margin_long,       # 多头保证金
            'margin_short': self.margin_short,
            'margin': self.margin,
            # 持仓字段
            'position_price_long': self.position_price_long,  # 多头成本价
            'position_cost_long': self.position_cost_long,   # 多头总成本(  总市值)
            'position_price_short': self.position_price_short,
            'position_cost_short': self.position_cost_short,
            # 平仓字段
            'open_price_long': self.open_price_long,  # 多头开仓价
            'open_cost_long': self.open_cost_long,  # 多头开仓成本
            'open_price_short': self.open_price_short,  # 空头开仓价
            'open_cost_short': self.open_cost_short,  # 空头成本
            # 历史字段
            'trades': self.trades,
            'orders': self.orders
        }

    @property
    def hold_detail(self):
        return {
            # 持仓量
            'volume_long_today': self.volume_long_today,
            'volume_long_his': self.volume_long_his,
            'volume_long': self.volume_long,
            'volume_short_today': self.volume_short_today,
            'volume_short_his': self.volume_short_his,
            'volume_short': self.volume_short
        }

    @property
    def realtime_message(self):
        return {
            # 扩展字段
            "last_price": self.last_price,
            # //多头浮动盈亏  ps.last_price * ps.volume_long * ps.ins->volume_multiple - ps.open_cost_long;
            "float_profit_long": self.float_profit_long,
            # //空头浮动盈亏  ps.open_cost_short - ps.last_price * ps.volume_short * ps.ins->volume_multiple;
            "float_profit_short": self.float_profit_short,
            # //浮动盈亏 = float_profit_long + float_profit_short
            "float_profit": self.float_profit,
            "position_profit_long": self.position_profit_long,  # //多头持仓盈亏
            "position_profit_short": self.position_profit_short,  # //空头持仓盈亏
            # //持仓盈亏 = position_profit_long + position_profit_short
            "position_profit": self.position_profit
        }

    @property
    def message(self):
        msg = self.static_message
        msg.update(self.realtime_message)
        return msg

    def order_check(self, amount: float, price: float, towards: int, order_id: str) -> bool:
        res = False
        if towards == ORDER_DIRECTION.BUY_CLOSE:
            # print('buyclose')
            #print(self.volume_short - self.volume_short_frozen)
            # print(amount)
            if (self.volume_short - self.volume_short_frozen) >= amount:
                # check
                self.volume_short_frozen_today += amount
                res = True
            else:
                print('BUYCLOSE 仓位不足')

        elif towards == ORDER_DIRECTION.BUY_CLOSETODAY:
            if (self.volume_short_today - self.volume_short_frozen_today) >= amount:
                self.volume_short_frozen_today += amount
                res = True
            else:
                print('BUYCLOSETODAY 今日仓位不足')
        elif towards == ORDER_DIRECTION.SELL_CLOSE:
            # print('sellclose')
            #print(self.volume_long - self.volume_long_frozen)
            # print(amount)
            if (self.volume_long - self.volume_long_frozen) >= amount:
                self.volume_long_frozen_today += amount
                res = True
            else:
                print('SELL CLOSE 仓位不足')

        elif towards == ORDER_DIRECTION.SELL_CLOSETODAY:
            if (self.volume_long_today - self.volume_short_frozen_today) >= amount:
                # print('sellclosetoday')
                #print(self.volume_long_today - self.volume_long_frozen)
                # print(amount)
                self.volume_long_frozen_today += amount
                return True
            else:
                print('SELLCLOSETODAY 今日仓位不足')
        elif towards in [ORDER_DIRECTION.BUY_OPEN,
                         ORDER_DIRECTION.SELL_OPEN,
                         ORDER_DIRECTION.BUY]:
            """
            冻结的保证金
            """
            moneyneed = float(amount) * float(price) * float(
                self.market_preset.get('unit_table',
                                       1)
            ) * float(self.market_preset.get('buy_frozen_coeff',
                                             1))

            if (self.moneypresetLeft > moneyneed) or self.allow_exceed:
                self.moneypresetLeft -= moneyneed
                self.frozen[order_id] = moneyneed
                res = True
            else:
                print('开仓保证金不足 TOWARDS{} Need{} HAVE{}'.format(
                    towards, moneyneed, self.moneypresetLeft))

        return res

    def send_order(self, amount: float, price: float, towards: int):
        order_id = str(uuid.uuid4())
        if self.order_check(amount, price, towards, order_id):
            #print('order check success')
            order = {
                'position_id': str(self.position_id),
                'account_cookie': self.account_cookie,
                'instrument_id': self.code,
                'towards': int(towards),
                'exchange_id': str(self.exchange_id),
                'order_time': str(self.time),
                'volume': float(amount),
                'price': float(price),
                'order_id': order_id,
                'status': ORDER_STATUS.NEW
            }
            self.orders[order_id] = order
            return order
        else:
            print(RuntimeError('ORDER CHECK FALSE: {}'.format(self.code)))
            return False

    def update_pos(self, price, amount, towards):
        """支持股票/期货的更新仓位

        Arguments:
            price {[type]} -- [description]
            amount {[type]} -- [description]
            towards {[type]} -- [description]

            margin: 30080
            margin_long: 0
            margin_short: 30080
            open_cost_long: 0
            open_cost_short: 419100
            open_price_long: 4193
            open_price_short: 4191
            position_cost_long: 0
            position_cost_short: 419100
            position_price_long: 4193
            position_price_short: 4191
            position_profit: -200
            position_profit_long: 0
            position_profit_short: -200
        """
        self.on_price_change(price)
        temp_cost = float(amount)*float(price) * \
            float(self.market_preset.get('unit_table', 1))
        profit = 0
        if towards == ORDER_DIRECTION.BUY:
            # 股票模式/ 期货买入开仓
            marginValue = temp_cost 
            
            self.margin_long += marginValue
            # 重算开仓均价
            self.open_price_long = (
                self.open_price_long * self.volume_long + amount * price
            ) / (
                amount + self.volume_long
            )
            # 重算持仓均价
            self.position_price_long = (
                self.position_price_long * self.volume_long + amount * price
            ) / (
                amount + self.volume_long
            )
            # 增加今仓数量 ==> 会自动增加volume_long
            self.volume_long_today += amount
            #
            self.open_cost_long += temp_cost
            self.position_cost_long += temp_cost
            self.moneypresetLeft -= marginValue



        elif towards == ORDER_DIRECTION.SELL:
            # 股票卖出模式:
            # 今日买入仓位不能卖出
            if self.volume_long_his >= amount:
                
                self.position_cost_long = self.position_cost_long * \
                    (self.volume_long - amount)/self.volume_long
                self.open_cost_long = self.open_cost_long * \
                    (self.volume_long-amount)/self.volume_long

                self.volume_long_his -= amount

                #self.volume_long_frozen_today -= amount
                marginValue = -1*(self.position_price_long * amount)
                self.margin_long += marginValue
                profit = (price - self.position_price_long) * amount 
                self.moneypresetLeft += (-marginValue + profit)
            else:
                return 0,0

        elif towards == ORDER_DIRECTION.BUY_OPEN:

            # 增加保证金
            marginValue = temp_cost * \
                self.market_preset.get('buy_frozen_coeff',1)
            self.margin_long += marginValue
            # 重算开仓均价
            self.open_price_long = (
                self.open_price_long * self.volume_long + amount * price
            ) / (
                amount + self.volume_long
            )
            # 重算持仓均价
            self.position_price_long = (
                self.position_price_long * self.volume_long + amount * price
            ) / (
                amount + self.volume_long
            )
            # 增加今仓数量 ==> 会自动增加volume_long
            self.volume_long_today += amount
            #
            self.open_cost_long += temp_cost
            self.position_cost_long += temp_cost
            self.moneypresetLeft -= marginValue

        elif towards == ORDER_DIRECTION.SELL_OPEN:
            # 增加保证金
            """
            1. 增加卖空保证金
            2. 重新计算 开仓成本
            3. 重新计算 持仓成本
            4. 增加开仓cost
            5. 增加持仓cost
            6. 增加空单仓位
            """
            marginValue = temp_cost * \
                self.market_preset['sell_frozen_coeff']
            self.margin_short += marginValue
            # 重新计算开仓/持仓成本
            self.open_price_short = (
                self.open_price_short * self.volume_short + amount * price
            ) / (
                amount + self.volume_short
            )
            self.position_price_short = (
                self.position_price_short * self.volume_short + amount * price
            ) / (
                amount + self.volume_short
            )
            self.open_cost_short += temp_cost
            self.position_cost_short += temp_cost
            self.volume_short_today += amount
            self.moneypresetLeft -= marginValue

        elif towards == ORDER_DIRECTION.BUY_CLOSETODAY:
            if self.volume_short_today > amount:
                self.position_cost_short = self.position_cost_short * \
                    (self.volume_short-amount)/self.volume_short
                self.open_cost_short = self.open_cost_short * \
                    (self.volume_short-amount)/self.volume_short
                #self.volume_short_today -= amount
                self.volume_short_frozen_today += amount
                # close_profit = (self.position_price_short - price) * volume * position->ins->volume_multiple;
                marginValue = -(self.position_price_short * amount*self.market_preset.get('unit_table') *\
                    self.market_preset['sell_frozen_coeff'])

                self.margin_short += marginValue     
                profit = (self.position_price_short - price
                          ) * amount * self.market_preset.get('unit_table')

                self.moneypresetLeft += (-marginValue + profit)

                # 释放保证金
                # TODO
                # self.margin_short
                #self.open_cost_short = price* amount

        elif towards == ORDER_DIRECTION.SELL_CLOSETODAY:
            if self.volume_long_today > amount:
                self.position_cost_long = self.position_cost_long * \
                    (self.volume_long - amount)/self.volume_long
                self.open_cost_long = self.open_cost_long * \
                    (self.volume_long-amount)/self.volume_long
                #self.volume_long_today -= amount
                self.volume_long_frozen_today += amount

                marginValue = -1*(self.position_price_long * amount*self.market_preset.get('unit_table') *\
                    self.market_preset.get('buy_frozen_coeff',1))
                self.margin_long += marginValue     
                profit = (price - self.position_price_long) * \
                    amount * self.market_preset.get('unit_table')
                self.moneypresetLeft += (-marginValue + profit)

        elif towards == ORDER_DIRECTION.BUY_CLOSE:
            # 有昨仓先平昨仓
            self.position_cost_short = self.position_cost_short * \
                (self.volume_short-amount)/self.volume_short
            self.open_cost_short = self.open_cost_short * \
                (self.volume_short-amount)/self.volume_short
            # if self.volume_short_his >= amount:
            #     self.volume_short_his -= amount
            # else:
            #     self.volume_short_today -= (amount - self.volume_short_his)
            #     self.volume_short_his = 0
            self.volume_short_frozen_today -= amount

            marginValue = -1*(self.position_price_short * amount*self.market_preset.get('unit_table',1) *\
                self.market_preset['sell_frozen_coeff'])
            profit = (self.position_price_short - price
                      ) * amount * self.market_preset.get('unit_table')
            self.margin_short += marginValue          

            self.moneypresetLeft += (-marginValue + profit)
        elif towards == ORDER_DIRECTION.SELL_CLOSE:
            # 有昨仓先平昨仓
            print(self.curpos)
            self.position_cost_long = self.position_cost_long * \
                (self.volume_long - amount)/self.volume_long
            self.open_cost_long = self.open_cost_long * \
                (self.volume_long-amount)/self.volume_long
            # if self.volume_long_his >= amount:
            #     self.volume_long_his -= amount
            # else:
            #     self.volume_long_today -= (amount - self.volume_long_his)
            #     self.volume_long_his = 0
            self.volume_long_frozen_today -= amount
            marginValue = -1*(self.position_price_long * amount*self.market_preset.get('unit_table',1) *\
                self.market_preset.get('buy_frozen_coeff',1))
            profit = (price - self.position_price_long) * \
                amount * self.market_preset.get('unit_table',1)
            self.margin_long += marginValue     
            self.moneypresetLeft += (-marginValue + profit)
        # 计算收益/成本

        return marginValue, profit


    def settle(self):
        """收盘后的结算事件
        """
        self.volume_long_his += self.volume_long_today
        self.volume_long_today = 0
        self.volume_long_frozen_today = 0
        self.volume_short_his += self.volume_short_today
        self.volume_short_today = 0
        self.volume_short_frozen_today = 0

    @property
    def curpos(self):
        return {
            'volume_long': self.volume_long,
            'volume_short': self.volume_short,
            'volume_long_frozen': self.volume_long_frozen,
            'volume_short_frozen': self.volume_short_frozen
        }

    @property
    def close_available(self):
        """可平仓数量

        Returns:
            [type] -- [description]
        """
        return {
            'volume_long': self.volume_long - self.volume_long_frozen,
            'volume_short': self.volume_short - self.volume_short_frozen
        }



    def change_moneypreset(self, money):
        self.moneypreset = money

    def save(self):
        """save&update

        save data to mongodb | update
        """
        print(self.static_message)
        save_position(self.static_message)

    def reload(self):
        res = DATABASE.positions.find_one({
            'account_cookie': self.account_cookie,
            'portfolio_cookie': self.portfolio_cookie,
            'user_cookie': self.user_cookie,
            'username': self.username,
            'position_id': self.position_id
        })
        if res is None:
            self.save()
        else:
            self.loadfrommessage(res)

    def calc_commission(self, trade_price, trade_amount, trade_towards,):
        if self.market_type == MARKET_TYPE.FUTURE_CN:
                # 期货不收税
                # 双边手续费 也没有最小手续费限制
            value = trade_price * trade_amount * \
                MARKET_PRESET().get_unit(self.code)

            commission_fee_preset = MARKET_PRESET().get_code(self.code)
            if trade_towards in [ORDER_DIRECTION.BUY_OPEN,
                                ORDER_DIRECTION.BUY_CLOSE,
                                ORDER_DIRECTION.SELL_CLOSE,
                                ORDER_DIRECTION.SELL_OPEN]:
                commission_fee = commission_fee_preset['commission_coeff_pervol'] * trade_amount + \
                    commission_fee_preset['commission_coeff_peramount'] * \
                    abs(value)
            elif trade_towards in [ORDER_DIRECTION.BUY_CLOSETODAY,
                                ORDER_DIRECTION.SELL_CLOSETODAY]:
                commission_fee = commission_fee_preset['commission_coeff_today_pervol'] * trade_amount + \
                    commission_fee_preset['commission_coeff_today_peramount'] * \
                    abs(value)
            return commission_fee

    def loadfrommessage(self, message):
        self.__init__(
            code=message['code'],
            account_cookie=message['account_cookie'],
            frozen=message['frozen'],
            user_cookie=message['user_cookie'],
            portfolio_cookie=message['portfolio_cookie'],
            username=message['username'],
            moneypreset=message['moneypreset'],  # 初始分配资金
            moneypresetLeft=message['moneypresetLeft'],
            volume_long_today=message['volume_long_today'],
            volume_long_his=message['volume_long_his'],
            volume_short_today=message['volume_short_today'],
            volume_short_his=message['volume_short_his'],

            volume_long_frozen_his=message['volume_long_frozen_his'],
            volume_long_frozen_today=message['volume_long_frozen_today'],
            volume_short_frozen_his=message['volume_short_frozen_his'],
            volume_short_frozen_today=message['volume_short_frozen_today'],

            margin_long=message['margin_long'],
            margin_short=message['margin_short'],

            open_price_long=message['open_price_long'],
            open_price_short=message['open_price_short'],
            # 逐日盯市的前一交易日的结算价
            position_price_long=message['position_price_long'],
            # 逐日盯市的前一交易日的结算价
            position_price_short=message['position_price_short'],

            open_cost_long=message['open_cost_long'],
            open_cost_short=message['open_cost_short'],
            position_cost_long=message['position_cost_long'],
            position_cost_short=message['position_cost_short'],
            position_id=message['position_id'],

            market_type=message['market_type'],
            exchange_id=message['exchange_id'],
            trades=message['trades'],
            orders=message['orders'],
            #commission=message['commission'],
            name=message['name'])
        if self.volume_long+ self.volume_short >0:
            self.last_price =( self.open_price_long*self.volume_long + self.open_price_short*self.volume_short)/(self.volume_long+ self.volume_short)
        else:
            self.last_price = 0
        
        return self

    def on_order(self, order: QA_Order):
        """这里是一些外部操作导致的POS变化

        - 交易过程的外部手动交易
        - 风控状态下的监控外部交易

        order_id 是外部的
        trade_id 不一定存在
        """

        if order['order_id'] not in self.frozen.keys():
            print('OUTSIDE ORDER')
            # self.frozen[order['order_id']] = order[]
            # 回放订单/注册进订单系统
            order = self.send_order(
                order.get('amount', order.get('volume')),
                order['price'],
                eval('ORDER_DIRECTION.{}_{}'.format(
                    order.get('direction'),
                    order.get('offset')
                ))
            )
            self.orders[order]['status'] = ORDER_STATUS.QUEUED

    def on_transaction(self, transaction: dict):
        towards = transaction.get(
            'towards',
            eval(
                'ORDER_DIRECTION.{}_{}'.format(
                    transaction.get('direction'),
                    transaction.get('offset')
                )
            )
        )
        transaction['towards'] = towards
        # TODO:
        # 在这里可以加入更多关于PMS交易的代码
        try:
            self.update_pos(
                transaction['price'],
                transaction.get('amount',
                                transaction.get('volume')),
                towards
            )
            self.moneypresetLeft += self.frozen.get(transaction['order_id'], 0)
            # 当出现外部交易的时候, 直接在frozen中注册订单
            self.frozen[transaction['order_id']] = 0
            self.orders[transaction['order_id']] = ORDER_STATUS.SUCCESS_ALL
            self.trades.append(transaction)
        except Exception as e:
            raise e

    def on_price_change(self, price):
        self.last_price = price

    def on_bar(self, bar):
        """只订阅这个code的数据

        Arguments:
            bar {[type]} -- [description]
        """
        self.last_price = bar['close']
        # print(self.realtime_message)
        pass

    def on_tick(self, tick):
        """只订阅当前code的tick

        Arguments:
            tick {[type]} -- [description]
        """
        self.last_price = tick['LastPrice']
        # print(self.realtime_message)
        pass

    def on_signal(self, signal):
        raise NotImplementedError('此接口为内部接口 为CEP专用')

    def callback_sub(self):
        raise NotImplementedError('此接口为内部接口 为CEP专用')

    def callback_pub(self):
        raise NotImplementedError('此接口为内部接口 为CEP专用')
예제 #3
0
class QA_Position():
    """一个持仓模型:/兼容股票期货/兼容保证金持仓

    兼容快期DIFF协议

    基础字段

    code [str]  品种名称 
    volume_long_today [float] 今仓 多单持仓
    volume_long_his   [float] 昨仓 多单持仓
    volume_short_today [float] 今仓 空单持仓
    volume_short_his  [float] 昨仓 空单持仓

    volume_long_frozen_his [float] 多单昨日冻结
    volume_long_frozen_today [float] 多单今日冻结
    volume_short_frozen_his [float] 空单昨日冻结
    volume_short_frozen_today [float] 空单今日冻结

    margin_long  [float] 多单保证金
    margin_short [float] 空单保证金

    open_price_long [float] 多单开仓价
    open_price_short [float] 空单开仓价
    position_price_long [float] 逐日盯市的前一交易日的结算价
    position_price_short [float] 逐日盯市的前一交易日的结算价

    open_cost_long [float] 多单开仓成本(指的是保证金冻结)
    open_cost_short [float] 空单开仓成本
    position_cost_long [float] 多单持仓成本(指的是基于逐日盯市制度下的成本价)
    position_cost_short [float] 空单持仓成本


    market_type=MARKET_TYPE.STOCK_CN [enum] 市场类别
    exchange_id=EXCHANGE_ID.SZSE [enum] 交易所id(支持股票/期货)
    name=None [str] 名称


    功能:

    1/ 支持当价格变化后的 持仓的自行计算更新
    2/ 支持调仓模型(未加入)
    3/ 支持仓位风控(未加入)
    4/ 支持资金分配和PMS内部资金结算(moneypreset)

    PMS 内部可以预分配一个资金限额, 方便pms实时计算属于PMS的收益

    """
    def __init__(
            self,
            code='000001',
            account_cookie='quantaxis',
            moneypreset=100000,  # 初始分配资金
            volume_long_today=0,
            volume_long_his=0,
            volume_short_today=0,
            volume_short_his=0,
            volume_long_frozen_his=0,
            volume_long_frozen_today=0,
            volume_short_frozen_his=0,
            volume_short_frozen_today=0,
            margin_long=0,
            margin_short=0,
            open_price_long=0,
            open_price_short=0,
            position_price_long=0,  # 逐日盯市的前一交易日的结算价
            position_price_short=0,  # 逐日盯市的前一交易日的结算价
            open_cost_long=0,
            open_cost_short=0,
            position_cost_long=0,
            position_cost_short=0,
            market_type=MARKET_TYPE.STOCK_CN,
            exchange_id=EXCHANGE_ID.SZSE,
            name=None,
            *args,
            **kwargs):

        self.code = code
        self.account_cookie = account_cookie
        self.time = ''
        self.market_preset = MARKET_PRESET().get_code(self.code)
        self.position_id = str(uuid.uuid4())
        self.moneypreset = moneypreset
        self.moneypresetLeft = self.moneypreset
        """{'name': '原油',
            'unit_table': 1000,
            'price_tick': 0.1,
            'buy_frozen_coeff': 0.1,
            'sell_frozen_coeff': 0.1,
            'exchange': 'INE',
            'commission_coeff_peramount': 0,
            'commission_coeff_pervol': 20.0,
            'commission_coeff_today_peramount': 0,
            'commission_coeff_today_pervol': 0.0}
        """
        self.rule = 'FIFO'
        self.name = name
        self.market_type = market_type
        self.exchange_id = exchange_id

        self.volume_long_his = volume_long_his
        self.volume_long_today = volume_long_today
        self.volume_short_his = volume_short_his
        self.volume_short_today = volume_short_today

        self.volume_long_frozen_his = volume_long_frozen_his
        self.volume_long_frozen_today = volume_long_frozen_today
        self.volume_short_frozen_his = volume_short_frozen_his
        self.volume_short_frozen_today = volume_short_frozen_today

        self.margin_long = margin_long
        self.margin_short = margin_short

        self.open_price_long = open_price_long
        self.open_price_short = open_price_short

        self.position_price_long = open_price_long if position_price_long == 0 else position_price_long
        self.position_price_short = open_price_short if position_price_short == 0 else position_price_short

        self.open_cost_long = open_cost_long if open_cost_long != 0 else open_price_long * \
            self.volume_long*self.market_preset.get('unit_table', 1)
        self.open_cost_short = open_cost_short if open_cost_short != 0 else open_price_short * \
            self.volume_short*self.market_preset.get('unit_table', 1)
        self.position_cost_long = position_cost_long if position_cost_long != 0 else self.position_price_long * \
            self.volume_long*self.market_preset.get('unit_table', 1)
        self.position_cost_short = position_cost_short if position_cost_short != 0 else self.position_price_short * \
            self.volume_short*self.market_preset.get('unit_table', 1)

        self.last_price = 0
        self.trades = {}

    def __repr__(self):
        return '< QAPOSITION {} amount {}/{} >'.format(self.code,
                                                       self.volume_long,
                                                       self.volume_short)

    def read_diff(self, diff_slice):
        """[summary]
        
        Arguments:
            diff_slice {dict} -- [description]

            {'user_id': '100002',
            'exchange_id': 'SHFE',
            'instrument_id': 'rb1905',
            'volume_long_today': 0,
            'volume_long_his': 0,
            'volume_long': 0,
            'volume_long_frozen_today': 0,
            'volume_long_frozen_his': 0,
            'volume_long_frozen': 0,
            'volume_short_today': 0,
            'volume_short_his': 0,
            'volume_short': 0,
            'volume_short_frozen_today': 0,
            'volume_short_frozen_his': 0,
            'volume_short_frozen': 0,
            'open_price_long': 4193.0,
            'open_price_short': 4192.0,
            'open_cost_long': 0.0,
            'open_cost_short': 0.0,
            'position_price_long': 4193.0,
            'position_price_short': 4192.0,
            'position_cost_long': 0.0,
            'position_cost_short': 0.0,
            'last_price': 4137.0,
            'float_profit_long': 0.0,
            'float_profit_short': 0.0,
            'float_profit': 0.0,
            'position_profit_long': 0.0,
            'position_profit_short': 0.0,
            'position_profit': 0.0,
            'margin_long': 0.0,
            'margin_short': 0.0,
            'margin': 0.0}

        Returns:
            QA_Position -- [description]
        """
        self.account_cookie = diff_slice['user_id']
        self.code = diff_slice['instrument_id']
        self.volume_long_today = diff_slice['volume_long_today']
        self.volume_long_his = diff_slice['volume_long_his']
        self.volume_long_frozen_today = diff_slice['volume_long_frozen_today']
        self.volume_long_frozen_his = diff_slice['volume_long_frozen_his']
        self.volume_short_today = diff_slice['volume_short_today']
        self.volume_short_his = diff_slice['volume_short_his']
        self.volume_short_frozen_today = diff_slice[
            'volume_short_frozen_today']
        self.volume_short_frozen_his = diff_slice['volume_short_frozen_his']
        self.open_price_long = diff_slice['open_price_long']
        self.open_price_short = diff_slice['open_price_short']
        self.open_cost_long = diff_slice['open_cost_long']
        self.open_cost_short = diff_slice['open_cost_short']
        self.position_price_long = diff_slice['position_price_long']
        self.position_price_short = diff_slice['position_price_short']
        self.position_cost_long = diff_slice['position_cost_long']
        self.position_cost_short = diff_slice['position_cost_short']
        self.margin_long = diff_slice['margin_long']
        self.margin_short = diff_slice['margin_short']
        self.exchange_id = diff_slice['exchange_id']
        self.market_type = MARKET_TYPE.FUTURE_CN
        return self

    @property
    def volume_long(self):
        return self.volume_long_today + self.volume_long_his

    @property
    def volume_short(self):
        return self.volume_short_his + self.volume_short_today

    @property
    def volume_long_frozen(self):
        return self.volume_long_frozen_his + self.volume_long_frozen_today

    @property
    def volume_short_frozen(self):
        return self.volume_short_frozen_his + self.volume_short_frozen_today

    @property
    def margin(self):
        return self.margin_long + self.margin_short

    @property
    def float_profit_long(self):
        if self.market_preset is not None:
            return self.last_price * self.volume_long * self.market_preset.get(
                'unit_table', 1) - self.open_cost_long

    @property
    def float_profit_short(self):
        if self.market_preset is not None:
            return self.open_cost_short - self.last_price * self.volume_short * self.market_preset.get(
                'unit_table', 1)

    @property
    def float_profit(self):
        return self.float_profit_long + self.float_profit_short

    @property
    def position_profit_long(self):
        if self.market_preset is not None:
            return self.last_price * self.volume_long * self.market_preset.get(
                'unit_table', 1) - self.position_cost_long

    @property
    def position_profit_short(self):
        if self.market_preset is not None:
            return self.position_cost_short - self.last_price * self.volume_short * self.market_preset.get(
                'unit_table', 1)

    @property
    def position_profit(self):
        return self.position_profit_long + self.position_profit_short

    @property
    def static_message(self):
        return {
            # 基础字段
            'code': self.code,  # 品种名称
            'instrument_id': self.code,
            'user_id': self.account_cookie,
            'name': self.name,
            'market_type': self.market_type,
            'exchange_id': self.exchange_id,  # 交易所ID
            # 持仓量
            'volume_long_today': self.volume_long_today,
            'volume_long_his': self.volume_long_his,
            'volume_long': self.volume_long,
            'volume_short_today': self.volume_short_today,
            'volume_short_his': self.volume_short_his,
            'volume_short': self.volume_short,
            # 平仓委托冻结(未成交)
            'volume_long_frozen_today': self.volume_long_frozen_today,
            'volume_long_frozen_his': self.volume_long_frozen_his,
            'volume_long_frozen': self.volume_long_frozen,
            'volume_short_frozen_today': self.volume_short_frozen_today,
            'volume_short_frozen_his': self.volume_short_frozen_his,
            'volume_short_frozen': self.volume_short_frozen,
            # 保证金
            'margin_long': self.margin_long,  # 多头保证金
            'margin_short': self.margin_short,
            'margin': self.margin,
            # 持仓字段
            'position_price_long': self.position_price_long,  # 多头成本价
            'position_cost_long': self.position_cost_long,  # 多头总成本(  总市值)
            'position_price_short': self.position_price_short,
            'position_cost_short': self.position_cost_short,
            # 平仓字段
            'open_price_long': self.open_price_long,  # 多头开仓价
            'open_cost_long': self.open_cost_long,  # 多头开仓成本
            'open_price_short': self.open_price_short,  # 空头开仓价
            'open_cost_short': self.open_cost_short  # 空头成本
        }

    @property
    def realtime_message(self):
        return {
            # 扩展字段
            "last_price": self.last_price,
            # //多头浮动盈亏  ps.last_price * ps.volume_long * ps.ins->volume_multiple - ps.open_cost_long;
            "float_profit_long": self.float_profit_long,
            # //空头浮动盈亏  ps.open_cost_short - ps.last_price * ps.volume_short * ps.ins->volume_multiple;
            "float_profit_short": self.float_profit_short,
            # //浮动盈亏 = float_profit_long + float_profit_short
            "float_profit": self.float_profit,
            "position_profit_long": self.position_profit_long,  # //多头持仓盈亏
            "position_profit_short": self.position_profit_short,  # //空头持仓盈亏
            # //持仓盈亏 = position_profit_long + position_profit_short
            "position_profit": self.position_profit
        }

    def order_check(self, amount: float, price: float, towards: int) -> bool:
        res = False
        if towards == ORDER_DIRECTION.BUY_CLOSE:
            print('buyclose')
            print(self.volume_short - self.volume_short_frozen)
            print(amount)
            if (self.volume_short - self.volume_short_frozen) >= amount:
                # check
                self.volume_short_frozen_today += amount
                res = True

        elif towards == ORDER_DIRECTION.BUY_CLOSETODAY and (
                self.volume_short_today -
                self.volume_short_frozen_today) >= amount:
            self.volume_short_frozen_today += amount
            res = True

        elif towards == ORDER_DIRECTION.SELL_CLOSE:
            print('sellclose')
            print(self.volume_long - self.volume_long_frozen)
            print(amount)
            if (self.volume_long - self.volume_long_frozen) >= amount:
                self.volume_long_frozen_today += amount
                res = True

        elif towards == ORDER_DIRECTION.SELL_CLOSETODAY and (
                self.volume_long_today -
                self.volume_short_frozen_today) >= amount:
            print('sellclosetoday')
            print(self.volume_long_today - self.volume_long_frozen)
            print(amount)
            self.volume_long_frozen_today += amount
            return True
        elif towards in [
                ORDER_DIRECTION.BUY_OPEN, ORDER_DIRECTION.SELL_OPEN,
                ORDER_DIRECTION.BUY
        ]:
            """
            冻结的保证金
            """
            moneyneed = float(amount) * float(price) * float(
                self.market_preset.get('unit_table', 1)) * float(
                    self.market_preset.get('buy_frozen_coeff', 1))
            if self.moneypresetLeft > moneyneed:
                self.moneypresetLeft -= moneyneed
                res = True

        return res

    def send_order(self, amount: float, price: float, towards: int):
        if self.order_check(amount, price, towards):
            print('order check success')

            return {
                'position_id': str(self.position_id),
                'account_cookie': self.account_cookie,
                'instrument_id': self.code,
                'towards': int(towards),
                'exchange_id': str(self.exchange_id),
                'order_time': str(self.time),
                'volume': float(amount),
                'price': float(price),
                'order_id': str(uuid.uuid4())
            }
        else:
            return RuntimeError('ORDER CHECK FALSE: {}'.format(self.code))

    def update_pos(self, price, amount, towards):
        """支持股票/期货的更新仓位

        Arguments:
            price {[type]} -- [description]
            amount {[type]} -- [description]
            towards {[type]} -- [description]

            margin: 30080
            margin_long: 0
            margin_short: 30080
            open_cost_long: 0
            open_cost_short: 419100
            open_price_long: 4193
            open_price_short: 4191
            position_cost_long: 0
            position_cost_short: 419100
            position_price_long: 4193
            position_price_short: 4191
            position_profit: -200
            position_profit_long: 0
            position_profit_short: -200
        """

        temp_cost = float(amount)*float(price) * \
            float(self.market_preset.get('unit_table', 1))

        if towards == ORDER_DIRECTION.BUY:
            # 股票模式/ 期货买入开仓
            self.volume_long_today += amount
        elif towards == ORDER_DIRECTION.SELL:
            # 股票卖出模式:
            # 今日买入仓位不能卖出
            if self.volume_long_his > amount:
                self.volume_long_his -= amount

        elif towards == ORDER_DIRECTION.BUY_OPEN:

            # 增加保证金
            temp_margin = temp_cost * \
                self.market_preset['buy_frozen_coeff']
            self.margin_long += temp_margin
            # 重算开仓均价
            self.open_price_long = (self.open_price_long * self.volume_long +
                                    amount * price) / (amount +
                                                       self.volume_long)
            # 重算持仓均价
            self.position_price_long = (
                self.position_price_long * self.volume_long +
                amount * price) / (amount + self.volume_long)
            # 增加今仓数量 ==> 会自动增加volume_long
            self.volume_long_today += amount
            #
            self.open_cost_long += temp_cost
            self.position_cost_long += temp_cost
            self.moneypresetLeft -= temp_margin

        elif towards == ORDER_DIRECTION.SELL_OPEN:
            # 增加保证金
            """
            1. 增加卖空保证金
            2. 重新计算 开仓成本
            3. 重新计算 持仓成本
            4. 增加开仓cost
            5. 增加持仓cost
            6. 增加空单仓位
            """

            self.margin_short += temp_cost * \
                self.market_preset['sell_frozen_coeff']
            # 重新计算开仓/持仓成本
            self.open_price_short = (
                self.open_price_short * self.volume_short +
                amount * price) / (amount + self.volume_short)
            self.position_price_short = (
                self.position_price_short * self.volume_short +
                amount * price) / (amount + self.volume_short)
            self.open_cost_short += temp_cost
            self.position_cost_short += temp_cost
            self.volume_short_today += amount

        elif towards == ORDER_DIRECTION.BUY_CLOSETODAY:
            if self.volume_short_today > amount:
                self.position_cost_short = self.position_cost_short * \
                    (self.volume_short-amount)/self.volume_short
                self.open_cost_short = self.open_cost_short * \
                    (self.volume_short-amount)/self.volume_short
                self.volume_short_today -= amount
                self.volume_short_frozen_today += amount
                # close_profit = (self.position_price_short - price) * volume * position->ins->volume_multiple;
                marginValue = temp_cost * self.market_preset['buy_frozen_coeff']
                profit = (self.position_price_short - price
                          ) * amount * self.market_preset.get('unit_table')
                # 释放保证金
                # TODO
                # self.margin_short
                #self.open_cost_short = price* amount

        elif towards == ORDER_DIRECTION.SELL_CLOSETODAY:
            if self.volume_long_today > amount:
                self.position_cost_long = self.position_cost_long * \
                    (self.volume_long - amount)/self.volume_long
                self.open_cost_long = self.open_cost_long * \
                    (self.volume_long-amount)/self.volume_long
                self.volume_long_today -= amount
                self.volume_long_frozen_today += amount

        elif towards == ORDER_DIRECTION.BUY_CLOSE:
            # 有昨仓先平昨仓
            self.position_cost_short = self.position_cost_short * \
                (self.volume_short-amount)/self.volume_short
            self.open_cost_short = self.open_cost_short * \
                (self.volume_short-amount)/self.volume_short
            if self.volume_short_his >= amount:
                self.volume_short_his -= amount
            else:
                self.volume_short_today -= (amount - self.volume_short_his)
                self.volume_short_his = 0
            self.volume_short_frozen_today -= amount
        elif towards == ORDER_DIRECTION.SELL_CLOSE:
            # 有昨仓先平昨仓
            self.position_cost_long = self.position_cost_long * \
                (self.volume_long - amount)/self.volume_long
            self.open_cost_long = self.open_cost_long * \
                (self.volume_long-amount)/self.volume_long
            if self.volume_long_his >= amount:
                self.volume_long_his -= amount
            else:
                self.volume_long_today -= (amount - self.volume_long_his)
                self.volume_long_his = 0
            self.volume_long_frozen_today -= amount
        # 计算收益/成本

    def settle(self):
        """收盘后的结算事件
        """
        self.volume_long_his += self.volume_long_today
        self.volume_long_today = 0
        self.volume_long_frozen_today = 0
        self.volume_short_his += self.volume_short_today
        self.volume_short_today = 0
        self.volume_short_frozen_today = 0

    @property
    def curpos(self):
        return {
            'volume_long': self.volume_long,
            'volume_short': self.volume_short
        }

    @property
    def close_available(self):
        """可平仓数量

        Returns:
            [type] -- [description]
        """
        return {
            'volume_long': self.volume_long - self.volume_long_frozen,
            'volume_short': self.volume_short - self.volume_short_frozen
        }

    def change_moneypreset(self, money):
        self.moneypreset = money

    def save(self):
        pass

    def reload(self):
        pass

    def on_order(self, order: QA_Order):
        pass

    def on_transaction(self, transaction: dict):
        towards = transaction.get(
            'towards',
            eval('ORDER_DIRECTION.{}_{}'.format(transaction.get('direction'),
                                                transaction.get('offset'))))
        #TODO:
        #在这里可以加入更多关于PMS交易的代码
        try:
            self.update_pos(
                transaction['price'],
                transaction.get('amount', transaction.get('volume')), towards)
        except Exception as e:
            raise e

        print(self.static_message)

    def on_pirce_change(self, price):
        self.last_price = price

    def on_bar(self, bar):
        """只订阅这个code的数据

        Arguments:
            bar {[type]} -- [description]
        """
        self.last_price = bar['close']
        print(self.realtime_message)
        pass

    def on_tick(self, tick):
        """只订阅当前code的tick

        Arguments:
            tick {[type]} -- [description]
        """
        self.last_price = tick['LastPrice']
        print(self.realtime_message)
        pass

    def on_signal(self, signal):
        raise NotImplementedError('此接口为内部接口 为CEP专用')

    def callback_sub(self):
        raise NotImplementedError('此接口为内部接口 为CEP专用')

    def callback_pub(self):
        raise NotImplementedError('此接口为内部接口 为CEP专用')
예제 #4
0
class QA_Position():
    """一个持仓模型:/兼容股票期货/兼容保证金持仓

    兼容快期DIFF协议

    基础字段

    code [str]  品种名称 
    volume_long_today [float] 今仓 多单持仓
    volume_long_his   [float] 昨仓 多单持仓
    volume_short_today [float] 今仓 空单持仓
    volume_short_his  [float] 昨仓 空单持仓

    volume_long_frozen_his [float] 多单昨日冻结
    volume_long_frozen_today [float] 多单今日冻结
    volume_short_frozen_his [float] 空单昨日冻结
    volume_short_frozen_today [float] 空单今日冻结

    margin_long  [float] 多单保证金
    margin_short [float] 空单保证金

    open_price_long [float] 多单开仓价
    open_price_short [float] 空单开仓价
    position_price_long [float] 逐日盯市的前一交易日的结算价
    position_price_short [float] 逐日盯市的前一交易日的结算价

    open_cost_long [float] 多单开仓成本(指的是保证金冻结)
    open_cost_short [float] 空单开仓成本
    position_cost_long [float] 多单持仓成本(指的是基于逐日盯市制度下的成本价)
    position_cost_short [float] 空单持仓成本


    market_type=MARKET_TYPE.STOCK_CN [enum] 市场类别
    exchange_id=EXCHANGE_ID.SZSE [enum] 交易所id(支持股票/期货)
    name=None [str] 名称


    功能:

    1/ 支持当价格变化后的 持仓的自行计算更新
    2/ 支持调仓模型(未加入)
    3/ 支持仓位风控(未加入)

    """

    def __init__(self,
                 code='000001',
                 account_cookie='quantaxis',
                 moneypreset=100000,  # 初始分配资金
                 volume_long_today=0,
                 volume_long_his=0,
                 volume_short_today=0,
                 volume_short_his=0,

                 volume_long_frozen_his=0,
                 volume_long_frozen_today=0,
                 volume_short_frozen_his=0,
                 volume_short_frozen_today=0,

                 margin_long_his=0,
                 margin_short_his=0,
                 margin_long_today=0,
                 margin_short_today=0,

                 open_price_long=0,
                 open_price_short=0,
                 position_price_long=0,  # 逐日盯市的前一交易日的结算价
                 position_price_short=0,  # 逐日盯市的前一交易日的结算价

                 open_cost_long=0,
                 open_cost_short=0,
                 position_cost_long=0,
                 position_cost_short=0,


                 market_type=MARKET_TYPE.STOCK_CN,
                 exchange_id=EXCHANGE_ID.SZSE,
                 name=None,

                 ):

        self.code = code
        self.account_cookie = account_cookie
        self.market_preset = MARKET_PRESET().get_code(self.code)
        self.position_id = uuid.uuid4()
        self.moneypreset = moneypreset
        """{'name': '原油',
            'unit_table': 1000,
            'price_tick': 0.1,
            'buy_frozen_coeff': 0.1,
            'sell_frozen_coeff': 0.1,
            'exchange': 'INE',
            'commission_coeff_peramount': 0,
            'commission_coeff_pervol': 20.0,
            'commission_coeff_today_peramount': 0,
            'commission_coeff_today_pervol': 0.0}
        """
        self.rule = 'FIFO'
        self.name = name
        self.market_type = market_type
        self.exchange_id = exchange_id

        self.volume_long_his = volume_long_his
        self.volume_long_today = volume_long_today
        self.volume_short_his = volume_short_his
        self.volume_short_today = volume_short_today

        self.volume_long_frozen_his = volume_long_frozen_his
        self.volume_long_frozen_today = volume_long_frozen_today
        self.volume_short_frozen_his = volume_short_frozen_his
        self.volume_short_frozen_today = volume_short_frozen_today

        self.margin_long_his = margin_long_his
        self.margin_short_his = margin_short_his
        self.margin_long_today = margin_long_today
        self.margin_short_today = margin_short_today

        self.open_price_long = open_price_long
        self.open_price_short = open_price_short

        self.position_price_long = open_price_long if position_price_long == 0 else position_price_long
        self.position_price_short = open_price_short if position_price_short == 0 else position_price_short

        self.open_cost_long = open_cost_long if open_cost_long != 0 else open_price_long * \
            self.volume_long*self.market_preset.get('unit_table', 1)
        self.open_cost_short = open_cost_short if open_cost_short != 0 else open_price_short * \
            self.volume_short*self.market_preset.get('unit_table', 1)
        self.position_cost_long = position_cost_long if position_cost_long != 0 else self.position_price_long * \
            self.volume_long*self.market_preset.get('unit_table', 1)
        self.position_cost_short = position_cost_short if position_cost_short != 0 else self.position_price_short * \
            self.volume_short*self.market_preset.get('unit_table', 1)

        self.last_price = 0

    def __repr__(self):
        return '< QAPOSITION {} amount {}/{} >'.format(self.code, self.volume_long, self.volume_short)

    @property
    def volume_long(self):
        return self.volume_long_today+self.volume_long_his

    @property
    def volume_short(self):
        return self.volume_short_his + self.volume_short_today

    @property
    def volume_long_frozen(self):
        return self.volume_long_frozen_his + self.volume_long_frozen_today

    @property
    def volume_short_frozen(self):
        return self.volume_short_frozen_his + self.volume_short_frozen_today

    @property
    def margin_long(self):
        return self.margin_long_his + self.margin_long_today

    @property
    def margin_short(self):
        return self.margin_short_his + self.margin_short_today

    @property
    def margin(self):
        return self.margin_long + self.margin_short

    @property
    def float_profit_long(self):
        if self.market_preset is not None:
            return self.last_price * self.volume_long * self.market_preset.get('unit_table', 1) - self.open_cost_long

    @property
    def float_profit_short(self):
        if self.market_preset is not None:
            return self.open_cost_short - self.last_price * self.volume_short * self.market_preset.get('unit_table', 1)

    @property
    def float_profit(self):
        return self.float_profit_long + self.float_profit_short

    @property
    def position_profit_long(self):
        if self.market_preset is not None:
            return self.last_price * self.volume_long * self.market_preset.get('unit_table', 1) - self.position_cost_long

    @property
    def position_profit_short(self):
        if self.market_preset is not None:
            return self.position_cost_short - self.last_price * self.volume_short * self.market_preset.get('unit_table', 1)

    @property
    def position_profit(self):
        return self.position_profit_long + self.position_profit_short

    @property
    def static_message(self):
        return {
            # 基础字段
            'code': self.code,  # 品种名称
            'instrument_id': self.code,
            'user_id': self.account_cookie,
            'name': self.name,
            'market_type': self.market_type,
            'exchange_id': self.exchange_id,  # 交易所ID
            # 持仓量
            'volume_long_today': self.volume_long_today,
            'volume_long_his': self.volume_long_his,
            'volume_long': self.volume_long,
            'volume_short_today': self.volume_short_today,
            'volume_short_his': self.volume_short_his,
            'volume_short': self.volume_short,
            # 平仓委托冻结(未成交)
            'volume_long_frozen_today': self.volume_long_frozen_today,
            'volume_long_frozen_his': self.volume_long_frozen_his,
            'volume_long_frozen': self.volume_long_frozen,
            'volume_short_frozen_today': self.volume_short_frozen_today,
            'volume_short_frozen_his': self.volume_short_frozen_his,
            'volume_short_frozen': self.volume_short_frozen,
            # 保证金
            'margin_long': self.margin_long,       # 多头保证金
            'margin_short': self.margin_short,
            'margin': self.margin,
            # 持仓字段
            'position_price_long': self.position_price_long,  # 多头成本价
            'position_cost_long': self.position_cost_long,   # 多头总成本(  总市值)
            'position_price_short': self.position_price_short,
            'position_cost_short': self.position_cost_short,
            # 平仓字段
            'open_price_long': self.open_price_long,  # 多头开仓价
            'open_cost_long': self.open_cost_long,  # 多头开仓成本
            'open_price_short': self.open_price_short,  # 空头开仓价
            'open_cost_short': self.open_cost_short  # 空头成本
        }

    @property
    def realtime_message(self):
        return {
            # 扩展字段
            "last_price": self.last_price,
            # //多头浮动盈亏  ps.last_price * ps.volume_long * ps.ins->volume_multiple - ps.open_cost_long;
            "float_profit_long": self.float_profit_long,
            # //空头浮动盈亏  ps.open_cost_short - ps.last_price * ps.volume_short * ps.ins->volume_multiple;
            "float_profit_short": self.float_profit_short,
            # //浮动盈亏 = float_profit_long + float_profit_short
            "float_profit": self.float_profit,
            "position_profit_long": self.position_profit_long,  # //多头持仓盈亏
            "position_profit_short": self.position_profit_short,  # //空头持仓盈亏
            # //持仓盈亏 = position_profit_long + position_profit_short
            "position_profit": self.position_profit
        }

    def receive_order(self, order:QA_Order):
        #self.update_pos(order.)
        pass

    def update_pos(self, price, amount, towards):
        """支持股票/期货的更新仓位

        Arguments:
            price {[type]} -- [description]
            amount {[type]} -- [description]
            towards {[type]} -- [description]

            margin: 30080
            margin_long: 0
            margin_short: 30080
            open_cost_long: 0
            open_cost_short: 419100
            open_price_long: 4193
            open_price_short: 4191
            position_cost_long: 0
            position_cost_short: 419100
            position_price_long: 4193
            position_price_short: 4191
            position_profit: -200
            position_profit_long: 0
            position_profit_short: -200
        """
        temp_cost = amount*price * \
            self.market_preset.get('unit_table', 1)
        # if towards == ORDER_DIRECTION.SELL_CLOSE:
        if towards == ORDER_DIRECTION.BUY:
            # 股票模式/ 期货买入开仓
            self.volume_long_today += amount
        elif towards == ORDER_DIRECTION.SELL:
            # 股票卖出模式:
            # 今日买入仓位不能卖出
            if self.volume_long_his > amount:
                self.volume_long_his -= amount

        elif towards == ORDER_DIRECTION.BUY_OPEN:

            # 增加保证金
            self.margin_long += temp_cost * \
                self.market_preset['buy_frozen_coeff']
            # 重算开仓均价
            self.open_price_long = (
                self.open_price_long * self.volume_long + amount*price) / (amount + self.volume_long)
            # 重算持仓均价
            self.position_price_long = (
                self.position_price_long * self.volume_long + amount * price) / (amount + self.volume_long)
            # 增加今仓数量 ==> 会自动增加volume_long
            self.volume_long_today += amount
            #
            self.open_cost_long += temp_cost

        elif towards == ORDER_DIRECTION.SELL_OPEN:
            # 增加保证金

            self.margin_short += temp_cost * \
                self.market_preset['sell_frozen_coeff']
            # 重新计算开仓/持仓成本
            self.open_price_short = (
                self.open_price_short * self.volume_short + amount*price) / (amount + self.volume_short)
            self.position_price_short = (
                self.position_price_short * self.volume_short + amount * price) / (amount + self.volume_short)
            self.open_cost_short += temp_cost
            self.volume_short_today += amount

        elif towards == ORDER_DIRECTION.BUY_CLOSETODAY:
            if self.volume_short_today > amount:
                self.position_cost_short = self.position_cost_short * \
                    (self.volume_short-amount)/self.volume_short
                self.open_cost_short = self.open_cost_short * \
                    (self.volume_short-amount)/self.volume_short
                self.volume_short_today -= amount
                # close_profit = (self.position_price_short - price) * volume * position->ins->volume_multiple;

                #self.volume_short_frozen_today += amount
                # 释放保证金
                # TODO
                # self.margin_short
                #self.open_cost_short = price* amount

        elif towards == ORDER_DIRECTION.SELL_CLOSETODAY:
            if self.volume_long_today > amount:
                self.position_cost_long = self.position_cost_long * \
                    (self.volume_long - amount)/self.volume_long
                self.open_cost_long = self.open_cost_long * \
                    (self.volume_long-amount)/self.volume_long
                self.volume_long_today -= amount

        elif towards == ORDER_DIRECTION.BUY_CLOSE:
            # 有昨仓先平昨仓
            self.position_cost_short = self.position_cost_short * \
                (self.volume_short-amount)/self.volume_short
            self.open_cost_short = self.open_cost_short * \
                (self.volume_short-amount)/self.volume_short
            if self.volume_short_his >= amount:
                self.volume_short_his -= amount
            else:
                self.volume_short_today -= (amount - self.volume_short_his)
                self.volume_short_his = 0
        elif towards == ORDER_DIRECTION.SELL_CLOSE:
            # 有昨仓先平昨仓
            self.position_cost_long = self.position_cost_long * \
                (self.volume_long - amount)/self.volume_long
            self.open_cost_long = self.open_cost_long * \
                (self.volume_long-amount)/self.volume_long
            if self.volume_long_his >= amount:
                self.volume_long_his -= amount
            else:
                self.volume_long_today -= (amount - self.volume_long_his)
                self.volume_long_his -= amount

        # 计算收益/成本

    def settle(self):
        """收盘后的结算事件
        """
        self.volume_long_his += self.volume_long_today
        self.volume_long_today = 0
        self.volume_long_frozen_today = 0
        self.volume_short_his += self.volume_short_today
        self.volume_short_today = 0
        self.volume_short_frozen_today = 0

    @property
    def curpos(self):
        return {
            'volume_long': self.volume_long,
            'volume_short': self.volume_short
        }

    @property
    def close_available(self):
        """可平仓数量

        Returns:
            [type] -- [description]
        """
        return {
            'volume_long': self.volume_long - self.volume_long_frozen,
            'volume_short': self.volume_short - self.volume_short_frozen
        }

    def change_moneypreset(self, money):
        self.moneypreset = money

    def save(self):
        pass

    def reload(self):
        pass

    def on_pirce_change(self, price):
        self.last_price = price

    def on_bar(self, bar):
        """只订阅这个code的数据

        Arguments:
            bar {[type]} -- [description]
        """
        self.last_price = bar['close']
        print(self.realtime_message)
        pass

    def on_tick(self, tick):
        """只订阅当前code的tick

        Arguments:
            tick {[type]} -- [description]
        """
        self.last_price = tick['LastPrice']
        print(self.realtime_message)
        pass

    def on_signal(self, signal):
        raise NotImplementedError('此接口为内部接口 为CEP专用')

    def callback_sub(self):
        raise NotImplementedError('此接口为内部接口 为CEP专用')

    def callback_pub(self):
        raise NotImplementedError('此接口为内部接口 为CEP专用')