PeopleQuant帮助文档:最小开仓数量规定下如何实现自动调仓
#大单拆分lots = 100 #总仓100手lot = 5 #单笔5手if position.pos_long < lots:if lots - position.pos_long >= lot: L = lotelse : L = lots - position.pos_longtask = api.create_task(OpenClose(api,quote,position,"kaiduo",lot=L,price='对手价',n_price_tick=5))while not task.done(): api.wait_update() #等待成交完成if position.pos_long > lots:if position.pos_long - lots >= lot: L = lotelse : L = position.pos_long - lotstask = api.create_task(OpenClose(api,quote,position,"pingduo",lot=L,price='对手价',n_price_tick=5))while not task.done(): api.wait_update() #等待成交完成
if L >= quote.open_min_limit_order_volume:task = api.create_task(OpenClose(api,quote,position,"kaiduo",lot=L,price='对手价',n_price_tick=5))while not task.done(): api.wait_update() #等待成交完成
L = max(L,quote.open_min_limit_order_volume)
OpenClose还有两个实用的参数,n_price_tick表示排队价偏离报单价格多少跳不成交就撤单,che_time表示等待多少时间不成交就撤单,一般行情没有变动的情况下,继续等待即可无需撤单,所以che_time应用的场景更少,但在对最小开仓数量大于1的合约调仓时就会比较有用,例如当行情波动不大,多等几秒钟说不定又全部成交了,不用立即撤单,相比于立即撤单补仓和对超出持仓减仓,可能会减少不必要的损失。
所以,使用OpenClose,用户可以实现四种灵活的调仓,1、等待che_time秒并且排队价偏离报单价格n_price_tick跳后撤单,2、撤单后放弃补仓,3、撤单后按最小数量补仓,4、补仓后超出部分再平仓。
天勤中实现的OpenClose代码放在文末,下面再推荐下PeopleQuant中的调仓实现。
在PeopleQuant中首先也是推荐使用类似功能的open_close函数,open_close是比OpenClose功能更全的下单函数,调仓过程和使用OpenClose结构类似,最低开仓数量通过参数open_min_volume传入,支持多线程或协程中用法,具体可参考安装包中的示例。
其次,在PeopleQuant中可使用对open_close进一步封装的调仓工具auto_pos_thread(多线程版)和auto_pos_async(异步协程版),并使用函数set_pos_volume设置目标持仓,例如:
#设置多头目标仓位100手set_pos_volume(rb2601, pos_long=100 )#设置多头目标仓位100手,以排队价下单set_pos_volume(rb2601, pos_long=100, price = "排队价" )#设置空头目标仓位10手set_pos_volume(rb2601, pos_short=10)#同时设置多头目标仓位100手、空头目标仓位10手,auto_pos会先完成多头调仓再完成空头调仓set_pos_volume(rb2601, pos_long=100, pos_short=10)#设置多头目标仓位10手, 最低开仓数量4手(如菜粕交易所规定最低开仓4手)set_pos_volume(RM601, pos_long=10, open_min_volume=4)#设置多头目标仓位10手, 最低开仓数量4手,价格偏离3跳撤单set_pos_volume(RM601, pos_long=10, open_min_volume=4,n_price_tick=3)#设置多头目标仓位10手, 最低开仓数量4手,价格偏离3跳同时等待了5秒撤单set_pos_volume(RM601, pos_long=10, open_min_volume=4,n_price_tick=3,che_time=5)
所以,使用set_pos_volume可以灵活的对多头或空头单独调仓或同时调仓,传入price设置下单价格,传入open_min_volume设置最小开仓数量,传入n_price_tick和che_time设置撤单偏离跳数和等待时间。
撤单后需要补仓时,当前pos_long,目标持仓lots,则传入持仓设置为pos_long+max(lots-pos_long,open_min_volume),即目标数量是当前持仓+剩余数量与最小开仓数量的最大值。
if position.pos_long < lots:L = pos_long + max(lots-pos_long, 4)set_pos_volume(RM601, pos_long=L, open_min_volume=4,n_price_tick=3,che_time=5)
对多出数量减仓时,在开完仓后执行调仓:
if position.pos_long > lots:set_pos_volume(RM601, pos_long=lots)
具体用法可查阅安装包中的智能调仓示例和相关函数的源代码。欢迎安装PeopleQuant使用,支持Python3.12以上版本安装:
pip install -U PeopleQuant
github仓库地址,欢迎收藏:
https://github.com/zhuxueli-cta/PeopleQuant
欢迎关注公众号,一起学习量化交易
最后,附上天勤中实现的OpenClose代码:
async def _OpenClose(api,quote={},position={},kaiping='',lot=0,price=None,advanced=None,order_close_chan=True,trade_chan=None,block=True,n_price_tick=1,che_time=0,order_info='无',signal_price=float('nan'),close_minutes=3,**kw):'''Args:kaiping: str,交易方向,开多"kaiduo",开空"kaikong",平多"pingduo",平空"pingkong"lot: int,下单手数price: float or str,下单价格,默认对手价,可选"停板价","对手价","排队价",或float类型的价格advanced: str,高级委托指令,默认None,可选"FOK","FAK",推荐Noneorder_close_chan:TqChan,发送平仓结果到外部(最新用法建议从返回值获取交易结果)trade_chan:TqChan,发送成交结果到外部(最新用法建议从返回值获取交易结果)block: bool,是否阻塞等待成交完成,默认True,即等待成交完成n_price_tick: int,盘口排队价偏离委托价多少个最小变动价位不成交主动撤单,默认1che_time: int,多少秒不成交主动撤单,默认0,即不按时间撤单order_info: str,报单备注信息,默认为"无"signal_price: float,信号位价格,默认为nanclose_minutes:3,夜盘离尾盘多少分钟撤单,默认3分钟kw: dict,其他可选参数,如"OrderDict","Order_Log","name","close_minutes"等return shoushu, junjia, che_count, day_order,symbol, kaiping,lot,price, last_msg, quote_volume, profit_count,profit_money, order_id,order_wrong,signal_price,order_info,quote,position'''kw.update({"kaiping":kaiping,"lot":lot,"price":price,"advanced":advanced,"order_close_chan":True,"trade_chan":True,"block":block,"n_price_tick":n_price_tick,"che_time":che_time,"order_info":order_info,"signal_price":signal_price,"close_minutes":close_minutes})if "name" not in kw: kw["name"] = "name" #策略名quote_volume = quote.ask_volume1 if kaiping in ["kaiduo","pingkong"] else quote.bid_volume1 #盘口挂单量order_wrong = False #是否错单n_price_tick = int(n_price_tick)che_time = int(che_time)symbol = quote.instrument_id #品种代码product_id = quote.product_idno_backtest = "backtest" not in kw or not kw["backtest"] #是否回测quote_datetime = time_to_datetime(quote.datetime)equal_time = no_backtest and quote_datetime.hour == datetime.now().hour #行情时间是否等于本机时间if close_minutes:quote_time = (quote_datetime+timedelta(minutes=close_minutes)).time()trading_time = quote.trading_timeif trading_time['night'] : #是否有夜盘night_end = trading_time['night'][-1][-1]time_list = [int(i) for i in night_end.split(':') ]#夜盘收盘时间night_end_time = time(time_list[0] if time_list[0] < 24 else time_list[0]-24,time_list[1],time_list[2])#close_minutes分钟后夜盘收盘,停止交易if abs(datetime.now().timestamp() - quote_datetime.timestamp())<=close_minutes*2*60 and (time_list[0] >= 24 and time(8) > quote_time >= night_end_time or time_list[0] < 24 and quote_time >= night_end_time):return {"shoushu":0, "junjia":float("nan"), "che_count":0, "day_order":0, "symbol":symbol, "kaiping":kaiping,"lot":lot,"price":price,"last_msg":f"临近夜盘收盘停止交易" ,"quote_volume":quote_volume,"profit_count":0,"profit_money":0, "order_id":[],"order_wrong":True if equal_time else False,"signal_price":signal_price,"order_info":order_info,"quote":quote,"position":position}#print(quote.datetime,'已经触发下单,品种:',symbol,'方向:',kaiping,'手数:',lot,'信号位:',signal_price)if not price or price == '超价':if quote.bid_price1 == quote.bid_price1:price_buy = quote.bid_price1 + quote.price_tickelse: price_buy = quote.last_price #停板时以最新价报单if quote.ask_price1 == quote.ask_price1:price_sell = quote.ask_price1 - quote.price_tickelse: price_sell = quote.last_priceelif price == '对手价':if quote.ask_price1 == quote.ask_price1:price_buy = quote.ask_price1else: price_buy = quote.last_price #停板时以最新价报单if quote.bid_price1 == quote.bid_price1:price_sell = quote.bid_price1else: price_sell = quote.last_priceelif price == '停板价':price_buy = quote.upper_limitprice_sell = quote.lower_limitelif price == '排队价':if quote.bid_price1 == quote.bid_price1:price_buy = quote.bid_price1else: price_buy = quote.last_price #停板时以最新价报单if quote.ask_price1 == quote.ask_price1:price_sell = quote.ask_price1else: price_sell = quote.last_priceadvanced = Noneelif price == price :if price >= quote.upper_limit :price_buy = price_sell = quote.upper_limit #超出停板时以停板价报单elif price <= quote.lower_limit:price_buy = price_sell = quote.lower_limit #超出停板时以停板价报单else: price_buy = price_sell = price #其他限定价if price_buy < quote.ask_price1 and kaiping in ["kaiduo","pingkong"]:advanced = Noneif price_sell > quote.bid_price1 and kaiping in ["pingduo","kaikong"]:advanced = Noneelif price != price:if quote.last_price == quote.upper_limit and kaiping in ["kaiduo","pingkong"]:price_buy = price_sell = quote.last_priceelif quote.last_price == quote.lower_limit and kaiping in ["pingduo","kaikong"]:price_buy = price_sell = quote.last_priceelse: price_buy = price_sell = priceprice_buy = min(price_buy, quote.upper_limit) #买入价格不能高于涨停价price_sell = max(price_sell, quote.lower_limit) #卖出价格不能低于跌停价if (price_buy == quote.upper_limit and kaiping in ["kaiduo","pingkong"] orprice_sell == quote.lower_limit and kaiping in ["pingduo","kaikong"]):advanced = None #无对手价时不能用高级委托指令if not no_backtest: #回测模式限价手数有值则取值if quote.max_limit_order_volume > 0: lot = min(lot, quote.max_limit_order_volume)if 'kai' in kaiping and quote.open_max_limit_order_volume > 0: lot = min(lot,quote.open_max_limit_order_volume)else: #非回测模式取值lot = min(lot, quote.max_limit_order_volume)if 'kai' in kaiping : lot = min(lot,quote.open_max_limit_order_volume)lot = int(lot)if price_buy != price_buy or price_sell != price_sell or lot <= 0 or 'kai' in kaiping and lot < quote.open_min_limit_order_volume:#以持仓数量平仓时平仓数量为0可能是服务器故障持仓未更新(也可能其他程序超额平仓,或清仓代码正常所需非本策略bug),等待更新后可继续下单,其他情况下的报价和手数错误应退出交易if not (lot == position.pos_long == 0 and kaiping == 'pingduo' or lot == position.pos_short == 0 and kaiping=='pingkong'): order_wrong = Truereturn {"shoushu":0, "junjia":float("nan"), "che_count":0, "day_order":0, "symbol":symbol, "kaiping":kaiping,"lot":lot,"price":price_buy if kaiping in ["kaiduo","pingkong"] else price_sell,"last_msg":f"报单错误,下单价格{price},下单手数{lot},最大限价单{quote.max_limit_order_volume},最大限价开仓单{quote.open_max_limit_order_volume},最小限价开仓单{quote.open_min_limit_order_volume}" ,"quote_volume":quote_volume,"profit_count":0,"profit_money":0, "order_id":[],"order_wrong":order_wrong,"signal_price":signal_price,"order_info":order_info,"quote":quote,"position":position}#liquid = quote.ask_price1 - quote.bid_price1 <= quote.price_tick*10shoushu = 0 #已成交手数junjia = 0.0 #成交均价che_count, day_order = 0, 0 #报撤单次数profit_count, profit_money = 0, 0 #平仓盈亏点数和盈亏金额ping_jin,ping_zuo,order = None,None,None #委托单对象last_msg, order_id = "", [] #委托单状态信息和单号#while position.pos_long != position.volume_long or position.pos_short != position.volume_short: await update_chan.recv() #新单之前已检查过if kaiping== 'pingduo': #交易方向为平多#可能服务器故障持仓未更新,等待更新if not position.pos_long or position.open_price_long != position.open_price_long:return {"shoushu":0, "junjia":float("nan"), "che_count":0, "day_order":0, "symbol":symbol, "kaiping":kaiping,"lot":lot,"price":price_buy if kaiping in ["kaiduo","pingkong"] else price_sell,"last_msg":f"多头持仓错误,多头持仓手数{position.pos_long},多头持仓价格{position.open_price_long}" ,"quote_volume":quote_volume,"profit_count":0,"profit_money":0, "order_id":[],"order_wrong":order_wrong,"signal_price":signal_price,"order_info":order_info,"quote":quote,"position":position}pos_direction = "多" #原持仓方向pos0 = position.pos_long #原多头持仓手数price0 = position.open_price_long #原多头开仓均价#margin0 = position.margin_long #原多头占用保证金if 0 < lot <= position.pos_long_today : #小于等于今仓,平今ping_jin=api.insert_order(symbol=symbol, direction='SELL', offset='CLOSETODAY', volume=lot, limit_price=price_sell,advanced=advanced)elif 0 < position.pos_long_today < lot <= position.pos_long: #优先平今,剩余仓位平昨ping_zuo=api.insert_order(symbol=symbol, direction='SELL', offset='CLOSE', volume=lot-position.pos_long_today, limit_price=price_sell,advanced=advanced) #先平昨再平今ping_jin=api.insert_order(symbol=symbol, direction='SELL', offset='CLOSETODAY', volume=position.pos_long_today, limit_price=price_sell,advanced=advanced)elif 0 == position.pos_long_today < lot <= position.pos_long: #只有昨仓ping_zuo=api.insert_order(symbol=symbol, direction='SELL', offset='CLOSE', volume=lot, limit_price=price_sell,advanced=advanced)elif kaiping=='pingkong': #交易方向为平空if not position.pos_short or position.open_price_short != position.open_price_short:return {"shoushu":0, "junjia":float("nan"), "che_count":0, "day_order":0, "symbol":symbol, "kaiping":kaiping,"lot":lot,"price":price_buy if kaiping in ["kaiduo","pingkong"] else price_sell,"last_msg":f"空头持仓错误,空头持仓手数{position.pos_short},空头持仓价格{position.open_price_short}" ,"quote_volume":quote_volume,"profit_count":0,"profit_money":0, "order_id":[],"order_wrong":order_wrong,"signal_price":signal_price,"order_info":order_info,"quote":quote,"position":position}pos_direction = "空" #原持仓方向pos0 = position.pos_short #原空头持仓手数price0 = position.open_price_short #原空头开仓均价#margin0 = position.margin_short #原空头占用保证金if 0 < lot <= position.pos_short_today : #小于等于今仓,平今ping_jin=api.insert_order(symbol=symbol, direction='BUY', offset='CLOSETODAY', volume=lot, limit_price=price_buy,advanced=advanced)elif 0 < position.pos_short_today < lot <= position.pos_short:ping_zuo=api.insert_order(symbol=symbol, direction='BUY', offset='CLOSE', volume=lot-position.pos_short_today, limit_price=price_buy,advanced=advanced)ping_jin=api.insert_order(symbol=symbol, direction='BUY', offset='CLOSETODAY', volume=position.pos_short_today, limit_price=price_buy,advanced=advanced)elif 0 == position.pos_short_today < lot <= position.pos_short:ping_zuo=api.insert_order(symbol=symbol, direction='BUY', offset='CLOSE', volume=lot, limit_price=price_buy,advanced=advanced)elif kaiping== 'kaiduo': #交易方向为开多order = api.insert_order(symbol=symbol, direction='BUY', offset='OPEN', volume=lot, limit_price=price_buy,advanced=advanced)elif kaiping=='kaikong': #交易方向为开空order = api.insert_order(symbol=symbol, direction="SELL", offset="OPEN", volume=lot, limit_price=price_sell,advanced=advanced)all_trades_id = set() # 记录所有的 trade_idasync with api.register_update_notify() as update_chan:t = datetime.now().timestamp() #时间起点if ping_zuo is not None:order_id.append(ping_zuo.order_id)last_price = quote.last_pricewhile ping_zuo.status != "FINISHED" or (ping_zuo.volume_orign - ping_zuo.volume_left) != sum([trade.volume for trade in ping_zuo.trade_records.values()]): #平昨单是否完成if not advanced and not block :break #当日有效单,且无需等待是否完成quote_volume = quote.ask_volume1 if kaiping in ["kaiduo","pingkong"] else quote.bid_volume1quote_time = (time_to_datetime(quote.datetime)+timedelta(minutes=close_minutes)).time()#等待che_time秒还不成交撤单,或者价格偏离委托价n_price_tick不成交撤单,适用于advanced=None的情况if ping_zuo.status != "FINISHED" and not advanced and (che_time>0 and n_price_tick<=0 and datetime.now().timestamp() - t >= che_time or n_price_tick>0 and che_time<=0 and((ping_zuo.direction=="BUY" and quote.bid_price1 >= ping_zuo.limit_price+quote.price_tick*n_price_tick) or(ping_zuo.direction=="SELL" and quote.ask_price1 <= ping_zuo.limit_price-quote.price_tick*n_price_tick))and last_price != quote.last_price == quote.last_priceor che_time>0 and n_price_tick>0 and datetime.now().timestamp() - t >= che_time and((ping_zuo.direction=="BUY" and quote.bid_price1 >= ping_zuo.limit_price+quote.price_tick*n_price_tick) or(ping_zuo.direction=="SELL" and quote.ask_price1 <= ping_zuo.limit_price-quote.price_tick*n_price_tick))and last_price != quote.last_price == quote.last_priceor (close_minutes and trading_time['night'] and abs(t - quote_datetime.timestamp())<=close_minutes*2*60 and ( time_list[0] >= 24 and time(8) > quote_time >= night_end_time or time_list[0] < 24 and quote_time >= night_end_time))):api.cancel_order(ping_zuo)while ping_zuo.status != "FINISHED":await update_chan.recv() #等待撤单完成,防止重复撤单await update_chan.recv() #更新委托单if isinstance(trade_chan,TqChan):rest_trades_id = set(ping_zuo.trade_records) - all_trades_idfor trade_id in rest_trades_id:# 新收到的 trade 提取成字典发送到 chand = {k: v for k, v in ping_zuo.trade_records[trade_id].items() if not k.startswith("_")}d.update({"signal_price":signal_price,"order_info":order_info})await trade_chan.send(d)all_trades_id.add(trade_id)else:day_order += 1 #报单数加1volume = ping_zuo.volume_orign-ping_zuo.volume_left #成交手数while volume > 0 and ping_zuo.trade_price != ping_zuo.trade_price: await update_chan.recv() #更新成交均价if abs(ping_zuo.volume_left)>0 or ping_zuo.volume_orign<=0 or volume<=0 or not isinstance(volume,int) :che_count += 1 #撤单次数增加last_msg += ping_zuo.last_msgif volume > 0: #有成交shoushu += volume #计算已成交手数junjia += ping_zuo.trade_price*volumeif ping_jin is not None:order_id.append(ping_jin.order_id)last_price = quote.last_pricewhile ping_jin.status != "FINISHED" or (ping_jin.volume_orign - ping_jin.volume_left) != sum([trade.volume for trade in ping_jin.trade_records.values()]): #平今单是否完成if not advanced and not block :breakquote_volume = quote.ask_volume1 if kaiping in ["kaiduo","pingkong"] else quote.bid_volume1quote_time = (time_to_datetime(quote.datetime)+timedelta(minutes=close_minutes)).time()if ping_jin.status != "FINISHED" and not advanced and (che_time>0 and n_price_tick<=0 and datetime.now().timestamp() - t >= che_time or n_price_tick>0 and che_time<=0 and((ping_jin.direction=='BUY' and quote.bid_price1 >= ping_jin.limit_price+quote.price_tick*n_price_tick) or(ping_jin.direction=='SELL' and quote.ask_price1 <= ping_jin.limit_price-quote.price_tick*n_price_tick))and last_price != quote.last_price == quote.last_priceor che_time>0 and n_price_tick>0 and datetime.now().timestamp() - t >= che_time and((ping_jin.direction=='BUY' and quote.bid_price1 >= ping_jin.limit_price+quote.price_tick*n_price_tick) or(ping_jin.direction=='SELL' and quote.ask_price1 <= ping_jin.limit_price-quote.price_tick*n_price_tick))and last_price != quote.last_price == quote.last_priceor (close_minutes and trading_time['night'] and abs(t - quote_datetime.timestamp())<=close_minutes*2*60 and ( time_list[0] >= 24 and time(8) > quote_time >= night_end_time or time_list[0] < 24 and quote_time >= night_end_time))):api.cancel_order(ping_jin)while ping_jin.status != "FINISHED":await update_chan.recv() #等待撤单完成await update_chan.recv() #if isinstance(trade_chan,TqChan):rest_trades_id = set(ping_jin.trade_records) - all_trades_idfor trade_id in rest_trades_id:# 新收到的 trade 提取成字典发送到 chand = {k: v for k, v in ping_jin.trade_records[trade_id].items() if not k.startswith("_")}d.update({"signal_price":signal_price,"order_info":order_info})await trade_chan.send(d)all_trades_id.add(trade_id)else:day_order += 1volume = ping_jin.volume_orign-ping_jin.volume_leftwhile volume > 0 and ping_jin.trade_price != ping_jin.trade_price: await update_chan.recv()if abs(ping_jin.volume_left)>0 or ping_jin.volume_orign<=0 or volume<=0 or not isinstance(volume,int) :che_count += 1 #撤单次数增加last_msg += ping_jin.last_msgif volume > 0:shoushu += volumejunjia += ping_jin.trade_price*volumeif order is not None:order_id.append(order.order_id)last_price = quote.last_pricewhile order.status != "FINISHED" or (order.volume_orign - order.volume_left) != sum([trade.volume for trade in order.trade_records.values()]): #开仓是否完成if not advanced and not block :breakquote_volume = quote.ask_volume1 if kaiping in ["kaiduo","pingkong"] else quote.bid_volume1quote_time = (time_to_datetime(quote.datetime)+timedelta(minutes=close_minutes)).time()if order.status != "FINISHED" and not advanced and (che_time>0 and n_price_tick<=0 and datetime.now().timestamp() - t >= che_time or n_price_tick>0 and che_time<=0 and((order.direction=='BUY' and quote.bid_price1 >= order.limit_price+quote.price_tick*n_price_tick) or(order.direction=='SELL' and quote.ask_price1 <= order.limit_price-quote.price_tick*n_price_tick))and last_price != quote.last_price == quote.last_priceor che_time>0 and n_price_tick>0 and datetime.now().timestamp() - t >= che_time and((order.direction=='BUY' and quote.bid_price1 >= order.limit_price+quote.price_tick*n_price_tick) or(order.direction=='SELL' and quote.ask_price1 <= order.limit_price-quote.price_tick*n_price_tick))and last_price != quote.last_price == quote.last_priceor (close_minutes and trading_time['night'] and abs(t - quote_datetime.timestamp())<=close_minutes*2*60 and ( time_list[0] >= 24 and time(8) > quote_time >= night_end_time or time_list[0] < 24 and quote_time >= night_end_time))):api.cancel_order(order)while order.status != "FINISHED":await update_chan.recv() #等待撤单完成await update_chan.recv() #if isinstance(trade_chan,TqChan):rest_trades_id = set(order.trade_records) - all_trades_idfor trade_id in rest_trades_id:# 新收到的 trade 提取成字典发送到 chand = {k: v for k, v in order.trade_records[trade_id].items() if not k.startswith("_")}d.update({"signal_price":signal_price,"order_info":order_info})await trade_chan.send(d)all_trades_id.add(trade_id)else:day_order += 1volume = order.volume_orign-order.volume_leftwhile volume > 0 and order.trade_price != order.trade_price: await update_chan.recv()if abs(order.volume_left)>0 or order.volume_orign<=0 or volume<=0 or not isinstance(volume,int) :che_count += 1 #撤单次数增加last_msg += order.last_msgif volume > 0:shoushu += volume #计算已成交手数junjia = order.trade_price*volumeif shoushu:if no_backtest: await asyncio.sleep(1) #等待1秒,确保持仓更新,降低下单频率防范异常错误下频繁报撤单#position的价格、仓位非同步更新,此处通过ctp查询以便进一步同步while (position.pos_long != position.volume_long or position.pos_short != position.volume_shortor position.pos_long and position.open_price_long != position.open_price_longor position.pos_short and position.open_price_short != position.open_price_shortor not position.pos_long and position.open_price_long == position.open_price_longor not position.pos_short and position.open_price_short == position.open_price_short): await update_chan.recv()junjia = junjia/shoushu #计算成交均价#junjia = round(junjia/shoushu,quote.price_decs) #保留和报价同样小数位if kaiping in ['pingduo','pingkong'] and order_close_chan:if kaiping== 'pingduo':pos_c = position.pos_long #平仓后剩余多头手数price_c = position.open_price_long #平仓后剩余多头开仓均价#margin_c = position.margin_long #平仓后剩余多头保证金elif kaiping=='pingkong':pos_c = position.pos_short #平仓后剩余空头手数price_c =position.open_price_short #平仓后剩余空头开仓均价#margin_c = position.margin_short #平仓后剩余空头保证金if pos_c > 0:price_o = (pos0*price0 - pos_c*price_c)/shoushu #被平仓的理论开仓均价else :price_o = price0if kaiping=='pingduo':profit_count = junjia - price_o #盈利点数elif kaiping=='pingkong':profit_count = price_o - junjia #盈利点数count_percent = round(profit_count/price_o,5) if price_o else 0 #盈利点率#margin_release = (margin0 if margin0==margin0 else 0) - (margin_c if margin_c==margin_c else 0)#释放保证金,平仓释放的保证金为理论投入资金#margin_release = (margin0 if margin0==margin0 else 0) * shoushu/pos0 #释放保证金,按仓位比计算,避免外部平仓产生影响profit_money = shoushu * profit_count * quote.volume_multiple #盈利金额if isinstance(order_close_chan,TqChan):#成交记录order_list = [symbol,pos_direction,price_o,junjia,shoushu,profit_count,profit_money,count_percent,signal_price,order_info,quote.datetime]await order_close_chan.send(order_list) #把计算后的结果发送出去else: #错单原因junjia = float('nan')#集合竞价,未到开盘时间等待60秒if "拒绝" in last_msg and ("竞价" in last_msg or "竟价" in last_msg or "交易时间" in last_msg): await asyncio.sleep(60)elif ("拒绝" in last_msg or "限制" in last_msg or "不足" in last_msg or "超过" in last_msg or "不支持" in last_msg or "低于" in last_msgor "权限" in last_msg or "平仓" in last_msg or "开仓" in last_msg):order_wrong = True#print(quote.datetime,'已经成交手数:',shoushu,'成交均价:',junjia,'品种:',symbol,'方向:',kaiping,'信号位:',signal_price,"order_info",order_info)return {"shoushu":shoushu, "junjia":junjia, "che_count":che_count, "day_order":day_order, "symbol":symbol, "kaiping":kaiping, "lot":lot, "price":price_buy if kaiping in ["kaiduo","pingkong"] else price_sell, "last_msg":last_msg,"quote_volume":quote_volume,"profit_count":profit_count, "profit_money":profit_money, "order_id":order_id,"order_wrong":order_wrong,"signal_price":signal_price,"order_info":order_info,"quote":quote,"position":position} #返回成交手数、成交均价,和主动撤单次数,若无成交则均价为nan值
夜雨聆风