通过三种不同方式,分别写在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
该博客主要介绍用Python实现策略交易,涉及期货委托挂单、止损止盈等内容。阐述了不同挂单类型的触发机制,以及上海、郑州和大连期货市场平仓规则差异。还给出了参数定义、初始化逻辑及各函数实现代码,用于处理交易数据和订单状态。
959

被折叠的 条评论
为什么被折叠?



