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))
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专用')
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专用')
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专用')