通过三种不同方式,分别写在handle_bar、timer、order_status中,选择实现,代码如下:
# 本Python代码主要用于策略交易 # 可以自己import我们平台支持的第三方python模块,比如pandas、numpy等。 from PythonApi import * import pandas as pd import os #import time#为了区分,对标记为“保值、融资、备兑”的订单不做处理
#市价成交的订单,报单后有报单ID,显示类型为限价,成交后有系统编号,Order在委托记录中 #限价挂单委托一直有效,有系统ID,上报交易所分配报单ID #停损挂单报单ID电脑分配,未成交委托上无显示时间记录 #所以,limit挂单由交易商跟踪触发,stop挂单由本地计算机跟踪触发,而非挂单形式由本策略实时价格跟踪触发
#上海品种有“平今”和“平仓”之分,当天建的仓单只能用“平今”指令才能平掉,平历史仓位需选择“平仓”。郑州和大连的对此不做区分,类型“平仓”都是先平“老仓”再平“新仓”。 #IN,SQ/ZJ,DQ,ZQ,对于SQ,IN市场,先挂平今单?
#上报交易所的平仓和持仓对应上,否则“可平数量不足!”。同样,上报交易所的平今和今持对应上,否则“可平今数量不足!”。 #所以,当委托挂单有系统编号的平仓时,无法再次委托限价平仓(平仓前先撤限价委托平仓订单(止赢单)!)
#竞价:报价、撮合、成交,中国期货都是限价单,撮合成交:询价,卖一价>=投标价,买一价,即ASK>=BID #buy 触发卖一价成交(buy open:开多,buy close:平空),sell 触发买一价成交(sell open:开空,sell close:平多) #buy limit price>=ASK 你的报价等于或高于当前“卖一”价即撮合成交 #ASK>buy limit price 你的报价小于当前“卖一”价即挂单委托,在买盘中排队: #BID>=sell limit price 你的报价等于或低于当前“买一”价即撮合成交 #sell limit price>BID 你的报价大于当前“买一”价即挂单委托,在卖盘中排队,即挂单止赢:
#buy stop price>ASK 你的定价高于当前“卖一”价,挂单不委托报单,否则立即成交(ASK>=buy stop price 止损) #BID>sell stop price 你的定价低于当前“买一”价,挂单不委托报单,否则立即成交(sell stop price>=BID 止损) #所以stop不报单: submitted 无 stop type #当前所有持仓在程序文件夹的 Document\portfolios_all.csv 所有历史委托记录在 orders_record.csv,在策略关闭时才会保存
# 参数定义区,这里定义的参数可以直接在context对象中获取。--(选择实现)def parameter(): #input_par(PAR_NAME,DFT,MIN,MAX,STEP) input_par("TP_Point",100,-1,10000,1) input_par("SL_Point",100,-1,10000,1) input_par("PH_Type",0,0,2,1) #0:默认值,捕获所有订单,下单成交时(非保值)同步下委托TP,SL单 #根据成交价计算TP,SL,隔日或软件重启止损委托清空 #止损点,止盈点改变不能同步修改(可手动通过未成交委托修改) #1:捕获所有有效交易账户和交易品种的持仓,每隔一秒根据持仓均价计算TP,SL,下委托TP,SL单(非保值),撤单清空后会重新下 #在全局变量设置止损点,止盈点,-1为一键全平,改变其他值时可以同步修改(撤单,重新委托) #无法通过未成交委托手动修改委托价(与上冲突),手动修改又会改回策略设置的止损,止盈 #策略开启时即时价格应该在止赢和止损范围之内,超过即不发委托 #2:针对默认账号合约池品种,根据实时tick,时差一般1-2秒 #不发送委托,监测实时价格,价格超过即平仓 #程序关闭即无效,策略开启,价格跳动、bar数据更新有效 #请注意策略开启时即时价格超过止赢和止损范围外直接平仓(如果有持仓)
# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。--(必须实现)def init(context): # 在context中保存全局变量 setextdata("止损点",0) setextdata("止盈点",0) settimer(timer,1000) context.trade_symbol=context.universe[0] context.trade_account="" context.i=context.print_i=0 if context.run_info.run_type=="paper_trading": if get_account(53,''): context.trade_account=str(get_account(1,'')) context.df_orders_record = pd.DataFrame() context.df_portfolios_all=df_portfolio_get() context.trade_open_info = {'order_id':0,'order_book_id':context.trade_symbol,'side':'buy','datetime':0,'price':0,'quantity':0,'filled_quantity':0,'type':'market','position_effect':'open', 'sign':0,'account':context.trade_account,"order_equity":0,'system_id':0,'stoploss':0,'takeprofit':0,'stop_id':0,'limit_id':0,'time_frame':'self'} context.file_path =os.getcwd()+"//Document//" if not os.path.exists(context.file_path): print ('新建文件夹:',context.file_path) os.makedirs(context.file_path) # print("策略启动") #调试打印输出 print(context.run_info.base_book_id+" 策略启动: "+context.run_info.run_type+": "+context.run_info.frequency)
# before_trading此函数会在每天基准合约的策略交易开始前被调用,当天只会被调用一次。--(选择实现) def before_trading(context): if len(context.df_portfolios_all): #context.PH_Type=1 pass
#------------------------------------------------- # 你选择的品种的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新。--(必须实现)def handle_bar(context): # 开始编写你的主要的算法逻辑。 if not context.run_info.run_type=="paper_trading" or not context.PH_Type==2: return #使用buy_open、sell_close等方法下单 #下单示例: #buy_open(context.s1, "Market", volume = 100) # 市价开多 #buy_open(context.s1, "Limit", 25.45, 100) # 限价开多 #bid=get_dynainf(order_book_id,28) #ask=get_dynainf(order_book_id,34) context.i+=1 for universe_i in context.universe: if istradertime(universe_i): portfolio_calc=get_portfolio (universe_i,0) if portfolio_calc is not None: _point=get_dynainf (universe_i,208) _price=get_dynainf (universe_i,7)#最新成交价格 if _point>0 and _price>0: order_id=0 if portfolio_calc.buy_quantity>0: stop_price=portfolio_calc.buy_avg_open_price-context.SL_Point*_point profit_price=portfolio_calc.buy_avg_open_price+context.TP_Point*_point if stop_price>_price or _price>profit_price:#bid:sell stop price>=BID or BID>=sell limit price order_id=sell_close(universe_i,"market",volume=portfolio_calc.buy_quantity)#对手盘报价委托,市价单,成交为限价对手价,即买一卖一 if context.i>=context.print_i: print(universe_i+":buy_quantity:%d"%portfolio_calc.buy_quantity+" stoploss:%f"%stop_price+" takeprofit:%f"%profit_price) context.print_i=context.i+1000 #get_dynainf (universe_i,207) if portfolio_calc.sell_quantity>0: stop_price=portfolio_calc.sell_avg_open_price+context.SL_Point*_point profit_price=portfolio_calc.sell_avg_open_price-context.TP_Point*_point if _price>stop_price or profit_price>_price:#ask:ASK>=buy stop price or buy limit price>=ASK order_id=buy_close(universe_i,"market",volume=portfolio_calc.sell_quantity)#buy_close(order_book_id,"limit",price=ask...) if context.i>=context.print_i: print(universe_i+":sell_quantity:%d"%portfolio_calc.sell_quantity+" stoploss:%f"%stop_price+" takeprofit:%f"%profit_price) context.print_i=context.i+1000 if order_id==-1: print(universe_i+" can't close order!") elif order_id!=0: print(universe_i+" send close order:%d"%order_id) else: print("canot get dynainf:"+universe_i)
#trade_portfolio = get_portfolio(context.trade_symbol,0,context.trade_account) #trade_portfolio = get_portfolio(order.order_book_id,0,order.account,calc=False) #orders_unsettled = get_orders(context.trade_symbol,0,context.trade_account) #orders_filled = get_orders(context.trade_symbol,1,context.trade_account)//context.trade_open_info
def timer(context): #tick_begin = time.clock()#time.ctime() *1000 if getextdata("止损点")!=0 and context.SL_Point!=getextdata("止损点"): context.SL_Point=getextdata("止损点") print("止损更新:%d"%context.SL_Point) if getextdata("止盈点")!=0 and context.TP_Point!=getextdata("止盈点"): context.TP_Point=getextdata("止盈点") print("止盈更新:%d"%context.TP_Point) if not context.run_info.run_type=="paper_trading" or not context.PH_Type==1: return context.i+=1 for account_id in get_account_book(): if get_account(53,account_id)==1 and get_account(2,account_id)!=255: try: portfolio_list=get_portfolio_book(0, account_id)#context.universe if len(portfolio_list): for order_book_id in portfolio_list: if istradertime(order_book_id): portfolio=get_portfolio (order_book_id, 0, account_id,calc=False) if portfolio is not None: _point=get_dynainf (order_book_id,208) _price=get_dynainf (order_book_id,7)#ask,bid /history_bars(order_book_id,2, 'self', 'close',True,True)[-1] sh_market=order_book_id.find("SQ")>=0 or order_book_id.find("IN")>=0 df_unsettled=day_orders_sort(order_book_id,account_id,0) buy_quantity=portfolio.buy_today_quantity if (sh_market and portfolio.buy_quantity>portfolio.buy_today_quantity>0) else max(portfolio.buy_quantity,portfolio.buy_today_quantity)#是否有平今之分 sell_quantity=portfolio.sell_today_quantity if (sh_market and portfolio.sell_quantity>portfolio.sell_today_quantity>0) else max(portfolio.sell_quantity,portfolio.sell_today_quantity) if _point>0 and _price>0: if buy_quantity>0: order_id=0 stop_price=portfolio.buy_avg_open_price-context.SL_Point*_point if context.SL_Point>0 else 0 profit_price=portfolio.buy_avg_open_price+context.TP_Point*_point if context.TP_Point>0 else 0 if len(df_unsettled): long_sl_select=df_unsettled[(df_unsettled["position_effect"]=="close") & (df_unsettled.type=="stop") & (df_unsettled.side=="sell")] long_tp_select=df_unsettled[(df_unsettled["position_effect"]=="close") & (df_unsettled.type=="limit") & (df_unsettled.side=="sell")] if len(long_sl_select):#unfilled_quantity if long_sl_select.sign[-1]==1: stop_price=0 elif buy_quantity==long_sl_select.quantity[-1] and -_point<=stop_price-long_sl_select.price[-1]<=_point:#df_unsettled.index stop_price=0 else: cancel_order (long_sl_select.order_id[0],account=account_id) if len(long_tp_select): if buy_quantity==long_tp_select.quantity[-1] and -_point<=profit_price-long_tp_select.price[-1]<=_point: profit_price=0 else: cancel_order (long_tp_select.order_id[0],account=account_id) if context.SL_Point==-1 or context.TP_Point==-1: order_id=sell_close(order_book_id,"market",volume=buy_quantity,account=account_id) else: if _price>stop_price>0:#_price>portfolio.buy_avg_holding_price and _portfolio.buy_quantity>_portfolio.buy_today_quantity order_id=sell_close(order_book_id,"stop",price=stop_price,volume=buy_quantity,account=account_id) if profit_price>_price: order_id=sell_close(order_book_id,"limit",price=profit_price,volume=buy_quantity,account=account_id) if order_id==-1:#订单id ,当返回-1表示下单失败 print(account_id+order_book_id+" can't send order!") elif order_id!=0: print(account_id+order_book_id+" send order:%d"%order_id) break if sell_quantity>0: order_id=0 stop_price=portfolio.sell_avg_open_price+context.SL_Point*_point if context.SL_Point>0 else 0 profit_price=portfolio.sell_avg_open_price-context.TP_Point*_point if context.TP_Point>0 else 0 if len(df_unsettled): short_sl_select=df_unsettled[(df_unsettled["position_effect"]=="close") & (df_unsettled.type=="stop") & (df_unsettled.side=="buy")] short_tp_select=df_unsettled[(df_unsettled["position_effect"]=="close") & (df_unsettled.type=="limit") & (df_unsettled.side=="buy")] if len(short_sl_select): if short_sl_select.sign[-1]==1: stop_price=0 elif sell_quantity==short_sl_select.quantity[-1] and -_point<=stop_price-short_sl_select.price[-1]<=_point: stop_price=0 else: cancel_order (short_sl_select.order_id[0],account=account_id) if len(short_tp_select): if sell_quantity==short_tp_select.quantity[-1] and -_point<=profit_price-short_tp_select.price[-1]<=_point: profit_price=0 else: cancel_order (short_tp_select.order_id[0],account=account_id) if context.SL_Point==-1 or context.TP_Point==-1: order_id=buy_close(order_book_id,"market",volume=sell_quantity,account=account_id) else: if _price<stop_price: order_id=buy_close(order_book_id,"stop",price=stop_price,volume=sell_quantity,account=account_id) if 0<profit_price<_price: order_id=buy_close(order_book_id,"limit",price=profit_price,volume=sell_quantity,account=account_id) if order_id==-1: print(account_id+order_book_id+" can't send order!") elif order_id!=0: print(account_id+order_book_id+" send order:%d"%order_id) break else: print("canot get dynainf:"+order_book_id) if is_data_update (order_book_id)==1: continue else: print('data not updated:'+get_dynainf(order_book_id,219)) elif istradertime(context.run_info.base_book_id): if context.i>=context.print_i: print("isnot tradertime:"+order_book_id+"@{}".format(context.now))#get_dynainf (context.run_info.base_book_id,207) context.print_i=context.i+1000 orders_unsettled = get_orders("all", 0, account_id) if orders_unsettled is not None: cancel_list=[] unsettled_last=get_orders_id (orders_unsettled[-1].order_id,orders_unsettled[-1].account)#orders_unsettled[0].datetime for order in orders_unsettled: if order.sign==1: continue if istradertime(order.order_book_id): if order.position_effect =="close":#order_last.status =='submitted' if order.type=="limit" or order.type=="stop": if unsettled_last.order_book_id==order.order_book_id and unsettled_last.order_id!=order.order_id: if unsettled_last.position_effect=="close" and unsettled_last.type==order.type and unsettled_last.side==order.side: if order.datetime<unsettled_last.datetime: cancel_list.append(order.order_id) cancel_order (order.order_id,account=account_id) order_portfolio = get_portfolio(order.order_book_id,0,account_id,calc=False)#order.account if order_portfolio is not None: if order.side=="sell": if order.quantity!=order_portfolio.buy_quantity and order.quantity!=order_portfolio.buy_today_quantity:# and -_point<=stop_price-order.price<=_point cancel_list.append(order.order_id) cancel_order (order.order_id,account=account_id) if order.side=="buy": if order.quantity>order_portfolio.sell_quantity and order.quantity!=order_portfolio.sell_today_quantity:# != cancel_list.append(order.order_id) cancel_order (order.order_id,account=account_id) else: cancel_list.append(order.order_id) write_logging(order.message) cancel_order (order.order_id,account=account_id) elif istradertime(context.run_info.base_book_id): if context.i>=context.print_i: print("isnot tradertime:"+order.order_book_id+"@{}".format(context.now)) context.print_i=context.i+1000 if len(cancel_list): print(order.order_book_id+" cancel orders:{}".format(cancel_list)) except: print("timer error!") #exit(context) elif istradertime(context.run_info.base_book_id): print("invalid account:"+account_id)
# order_status当委托下单,成交,撤单等与下单有关的动作时,该方法就会被调用。---(选择实现) def order_status(context,order): order_refesh=day_orders_sort() if len(order_refesh): if len(context.df_orders_record): df_select=order_refesh.loc[order_refesh.index>context.df_orders_record.index[-1]]#&(order_refesh.order_id!=context.df_orders_record.order_id[-1]) if len(df_select): context.df_orders_record=context.df_orders_record.append(df_select) print("get orders:") print(df_select) else: context.df_orders_record=order_refesh print("get orders:") print(context.df_orders_record) if order.status=='submitted': if order.type=="limit":#stop 不报单 print(order.order_book_id+":"+order.message+":%d"%order.order_id+" 限价:%f"%order.price) _bid=get_dynainf(order.order_book_id,20) _ask=get_dynainf(order.order_book_id,21) _point=get_dynainf (order.order_book_id,208) if order.side=="sell" and order.price>_bid+_point: print("sell limit order.bid:%f"%_bid) elif order.side=="buy" and _ask-_point>order.price: print("buy limit order.ask:%f"%_ask) elif order.position_effect=="close":# market close order_portfolio=get_portfolio (order.order_book_id, order.sign, order.account,calc=False) if order_portfolio is not None and order_portfolio.pnl!=0: print(order.order_book_id+":closeing profit:%f"%order_portfolio.pnl) if order.status=='tradeing': print(order.order_book_id+":tradeing quantity:%f"%order.trade_quantity+":tradeing price:%f"%order.trade_price)#context.trade_symbol if order.status=='filled': print(order.order_book_id+":filled quantity:%f"%order.filled_quantity+":filled price:%f"%order.price) context.df_portfolios_all=df_portfolio_get(calc=False) if len(context.df_portfolios_all): print("get portfolio:") print(context.df_portfolios_all) order_dict={ 'order_id':order.order_id, 'order_book_id':order.order_book_id, 'side':order.side, 'datetime':order.datetime, 'price':order.price, 'quantity':order.quantity, 'filled_quantity':order.filled_quantity, 'type':order.type, 'position_effect':order.position_effect, 'sign':order.sign, 'account':order.account, 'system_id':order.system_id,#type(order.system_id)len(order.system_id) 'order_equity':get_account(6,order.account), 'time_frame':context.run_info.frequency,} if order.position_effect=="open" : #if context.trade_symbol==order.order_book_id and context.trade_account==order.account: context.trade_symbol=order.order_book_id context.trade_account=order.account context.trade_open_info.update(order_dict) if context.PH_Type==0 and order.sign==0:# order.type=="market" or order.type=="limit" _point=get_dynainf (order.order_book_id,208) _price=get_dynainf (order.order_book_id,7) if _point>0 and _price>0 and order.filled_quantity>0: stop_id=limit_id=0 if order.side=="buy": buy_ask=get_dynainf(order.order_book_id,21) if order.type=="market" else order.price stoploss=buy_ask-context.SL_Point*_point if context.SL_Point>0 else 0 takeprofit=buy_ask+context.TP_Point*_point if context.TP_Point>0 else 0 if _price>stoploss>0: stop_id=sell_close(order.order_book_id,"stop",price=stoploss,volume=order.filled_quantity,account=order.account) if takeprofit>_price: limit_id=sell_close(order.order_book_id,"limit",price=takeprofit,volume=order.filled_quantity,account=order.account) if order.side=="sell": sell_bid=get_dynainf(order.order_book_id,20) if order.type=="market" else order.price stoploss=sell_bid+context.SL_Point*_point if context.SL_Point>0 else 0 takeprofit=sell_bid-context.TP_Point*_point if context.TP_Point>0 else 0 if _price<stoploss: stop_id=buy_close(order.order_book_id,"stop",price=stoploss,volume=order.filled_quantity,account=order.account) if 0<takeprofit<_price: limit_id=buy_close(order.order_book_id,"limit",price=takeprofit,volume=order.filled_quantity,account=order.account) if stop_id==-1 or limit_id==-1: print(order.account+order.order_book_id+" can't send order!") elif stop_id!=0 or limit_id!=0: context.trade_open_info.update({'stoploss':stoploss,'takeprofit':takeprofit,"stop_id":stop_id,"limit_id":limit_id,}) print(context.trade_open_info) if order.status=="inactive": try: print(order.order_book_id+':无效单:%d'%order.order_id) orders_unsettled = day_orders_sort(order.order_book_id, order.account,0) if len(orders_unsettled): limit_select=orders_unsettled[(orders_unsettled.position_effect=="close") & (orders_unsettled.type=="limit")]#'submitted'cancelled if len(limit_select): print(order.order_book_id+':可平数量不足,请先撤单:{}'.format(limit_select.order_id.tolist())) print(limit_select) except: print('无效单:%d'%order.order_id) if order.status=="cancelled": print(order.order_book_id+':'+order.message+':%d'%order.order_id) if not istradertime(order.order_book_id): print(order.order_book_id+" isnot tradertime!") if order.status=="disconnected": print(order.account+':连接断开') if order.status=="connected": print(order.account+':账号连接') # after_trading函数会在每天交易结束后被调用,当天只会被调用一次。 --(选择实现) def after_trading(context): pass # exit函数会在测评结束或者停止策略运行时会被调用。---(选择实现) def exit(context): try: pd.Series(context.trade_open_info).to_json(context.file_path+"trade_info.json") if len(context.df_orders_record): context.df_orders_record.to_csv(context.file_path+"orders_record.csv", encoding = "utf_8_sig") if len(context.df_portfolios_all): context.df_portfolios_all.to_csv(context.file_path+"portfolios_all.csv", encoding = "utf_8_sig") killtimer(timer) except: pass def day_orders_sort(symbol="all",account="",order_all=1): #返回 list of Order对象,委托记录中的记录 orders_list_0 = get_orders (symbol,order_all,account)#list if orders_list_0 is not None: #list.sort(key=None,reverse=False) orders_1ist_1=sorted(orders_list_0,key=lambda x:x.datetime)#[get_orders_id (i.order_id) for i in orders_list]#list orders_1ist_2=[[order.order_id,order.order_book_id,order.side,order.price,order.quantity,order.filled_quantity,order.type,order.status,order.position_effect,order.sign,order.message,order.system_id,order.account] for order in orders_1ist_1]#,0.0,0.0,0.0,"" df_orders_record=pd.DataFrame(orders_1ist_2,index=[order.datetime for order in orders_1ist_1],columns=['order_id','order_book_id','side','price','quantity','filled_quantity','type','status','position_effect','sign','message','system_id','account']) return df_orders_record#DataFrame.sort_index(axis=0, level=None, ascending=True, inplace=False, kind=’quicksort’, na_position=’last’, sort_remaining=True, by=None) return pd.DataFrame() def df_portfolio_get(symbol="all",account="all",type=2,calc=True): portfolio_list=[] account_list=get_account_book() if account=="all" else [account] for account_id in account_list: symbol_list=get_portfolio_book (type, account_id) if symbol=="all" else [symbol] if len(symbol_list): for order_book_id in symbol_list: portfolio=get_portfolio (order_book_id, type, account_id,calc) portfolio_info=[account_id,order_book_id,portfolio.moneyrate,portfolio.pnl,portfolio.buy_margin,portfolio.buy_today_quantity,portfolio.buy_quantity,portfolio.buy_avg_open_price,portfolio.buy_avg_holding_price, portfolio.sell_margin,portfolio.sell_today_quantity,portfolio.sell_quantity,portfolio.sell_avg_open_price,portfolio.sell_avg_holding_price] portfolio_list.append(portfolio_info) if len(portfolio_list): df_portfolio=pd.DataFrame(portfolio_list,index=range(len(portfolio_list)),columns= ['account_id','order_book_id','moneyrate','pnl','buy_margin','buy_today_quantity','buy_quantity','buy_avg_open_price','buy_avg_holding_price', 'sell_margin','sell_today_quantity','sell_quantity','sell_avg_open_price','sell_avg_holding_price']) return(df_portfolio) return pd.DataFrame()
# order_action当查询交易接口信息时返回的通知---(选择实现) #def order_action(context,type, account, datas) # pass