3.【PTrade使用指南】- 策略引擎介绍

策略引擎简介
业务流程框架
PTrade量化引擎以事件触发为基础,通过初始化事件(initialize)、盘前事件(before_trading_start)、盘中事件(handle_data)、盘后事件(after_trading_end)来完成每个交易日的策略任务。
initialize和handle_data是一个允许运行策略的最基础结构,也就是必选项,before_trading_start和after_trading_end是可以按需运行的。
handle_data仅满足日线和分钟级别的盘中处理,tick级别的盘中处理则需要通过tick_data或者run_interval来实现。
ptrade还支持委托主推事件(on_order_response)、交易主推事件(on_trade_response),可以通过委托和成交的信息来处理策略逻辑,是tick级的一个补充。
除了以上的一些事件以外,ptrade也支持通过定时任务来运行策略逻辑,可以通过run_dAIly接口实现。
initialize(必选)
initialize(context)
使用场景
该函数仅在回测、交易模块可用
接口说明
该函数用于初始化一些全局变量,是策略运行的唯二必须定义函数之一。
注意事项:
-
该函数只会在回测和交易启动的时候运行一次。
可调用接口
参数
context: Context对象,存放有当前的账户及持仓信息;
返回
None
示例
def initialize(context):#g为全局对象g.security = '600570.SS'set_universe(g.security)def handle_data(context, data):order('600570.SS',100)
before_trading_start(可选)
before_trading_start(context, data)
使用场景
该函数仅在回测、交易模块可用
接口说明
该函数在每天开始交易前被调用一次,用于添加每天都要初始化的信息,如无盘前初始化需求,该函数可以在策略中不做定义。
注意事项:
-
在回测中,该函数在每个回测交易日8:30分执行。
-
在交易中,该函数在开启交易时立即执行,从隔日开始每天9:10分(默认)执行。
-
当在9:10前开启交易时,受行情未更新原因在该函数内调用实时行情接口会导致数据有误。 可通过在该函数内sleep至9:10分或调用实时行情接口改为run_daily执行等方式进行避免。
可调用接口
参数
context: Context对象,存放有当前的账户及持仓信息;
data:保留字段暂无数据;
返回
None
示例
def initialize(context):#g为全局变量g.security = '600570.SS'set_universe(g.security)def before_trading_start(context, data):log.info(g.security)def handle_data(context, data):order('600570.SS',100)
handle_data(必选)
handle_data(context, data)
使用场景
该函数仅在回测、交易模块可用
接口说明
该函数在交易时间内按指定的周期频率运行,是用于处理策略交易的主要模块,根据策略保存时的周期参数分为每分钟运行和每天运行,是策略运行的唯二必须定义函数之一。
注意事项:
-
该函数每个单位周期执行一次
-
如果是日线级别策略,每天执行一次。股票回测场景下,在15:00执行;股票交易场景下,执行时间为券商实际配置时间。
-
如果是分钟级别策略,每分钟执行一次,股票回测场景下,执行时间为9:31 -- 15:00,股票交易场景下,执行时间为9:30 -- 14:59。
-
回测与交易中,handle_data函数不会在非交易日触发(如回测或交易起始日期为2015年12月21日,则策略在2016年1月1日-3日时, handle_data不会运行,4日继续运行)。
可调用接口
参数
context: Context对象,存放有当前的账户及持仓信息;
data:是一个类对象,实现了类似字典的通过key获取value的方法,可以通过股票代码获取代码对应的BarData对象,对象中包含当前周期(日线策略是当天,分钟策略是当前分钟)的数据;
注意:为了加速,data中的数据只包含股票池中所订阅标的的信息,可使用data[security]的方式来获取当前周期对应的标的信息;
返回
None
示例
def initialize(context):#g为全局变量g.security = '600570.SS'set_universe(g.security)def handle_data(context, data):# 通过data对象获取股票当前周期最新价current_price = data[g.security].price# 用当前最新价委托下单order('600570.SS', 100, limit_price=current_price)
after_trading_end(可选)
after_trading_end(context, data)
使用场景
该函数仅在回测、交易模块可用
接口说明
该函数会在每天交易结束之后调用,用于处理每天收盘后的操作,如无盘后处理需求,该函数可以在策略中不做定义。
注意事项:
-
该函数只会执行一次
-
该函数执行时间为由券商配置决定,一般为15:30。
可调用接口
参数
context: Context对象,存放有当前的账户及持仓信息;
data:保留字段暂无数据;
返回
None
示例
def initialize(context):#g为全局变量g.security = '600570.SS'set_universe(g.security)def handle_data(context, data):order('600570.SS',100)def after_trading_end(context, data):log.info(g.security)
tick_data(可选)
tick_data(context, data)
使用场景
该函数仅交易模块可用
接口说明
该函数可以用于处理tick级别策略的交易逻辑,每隔3秒执行一次,如无tick处理需求,该函数可以在策略中不做定义。
注意事项:
-
该函数执行时间为9:30 -- 14:59。
-
该函数中的data和handle_data函数中的data是不一样的,请勿混肴。
-
参数data中包含的逐笔委托,逐笔成交数据需开通level2行情才能获取到数据,否则对应数据返回None。
-
参数data中的tick数据取自get_snapshot()并转换为DataFrame格式, 如要更快速的获取快照强烈建议直接使用get_snapshot()获取。
-
当调用set_parameters()并设置tick_data_no_l2="1"时, 参数data中将不包含逐笔委托、逐笔成交字段,当券商有l2行情时配置该参数可提升data取速;
-
当策略执行时间超过3s时,将会丢弃中间堵塞的tick_data。
-
在收盘后,将会清空队列中未执行的tick_data。
-
参数data中包含的逐笔委托,逐笔成交数据正常返回DataFrame格式,异常时返回None。
可调用接口
参数
context: Context对象,存放有当前的账户及持仓信息;
data: 一个字典(dict),key为对应的标的代码(如:'600570.SS'),value为一个字典(dict),包含order(逐笔委托)、tick(当前tick数据)、transaction(逐笔成交)三项
结构如下:
{'股票代码': { 'order(最近一条逐笔委托)':DataFrame/None, 'tick(当前tick数据)':DataFrame, 'transaction(最近一条逐笔成交)':DataFrame/None, } }
每项具体介绍:
order - 逐笔委托对应DataFrame包含字段: business_time:时间戳毫秒级 hq_px:价格 business_amount:委托量 order_no:委托编号 business_direction:成交方向trans_kind:委托类型tick - tick数据对应DataFrame包含字段: amount:持仓量 bid_grp:买档位,dict类型,内容如:{1:[42.71,200,0],2:[42.74,200,0],3:[42.75,700,...,以档位为Key,以list为Value,每个Value包含:委托价格、委托数量和委托笔数; business_amount:成交数量; business_amount_in:内盘成交量; business_amount_out:外盘成交量 business_balance:成交金额; business_count:成交笔数; circulation_amount:流通股本; current_amount:最近成交量(现手); down_px:跌停价格; end_trade_date:最后交易日 entrust_diff:委差; entrust_rate:委比; high_px:最高价; hsTimeStamp:时间戳,格式为YYYYMMDDHHMISS,如20170711141612,表示2017年7月11日14时16分12秒的tick数据信息; last_px:最新成交价; low_px:最低价; offer_grp:卖档位,dict类型,内容如:{1:[42.71,200,0],2:[42.74,200,0],3:[42.75,700,...,以档位为Key,以list为Value,每个Value包含:委托价格、委托数量和委托笔数; open_px:今开盘价; pb_rate:市净率; pe_rate:动态市盈率; preclose_px:昨收价; prev_settlement:昨结算 px_change_rate: 涨跌幅 settlement:结算价 start_trade_date:首个交易日 tick_size:最小报价单位 total_bid_turnover: 委买金额 total_bidqty: 委买量 total_offer_turnover: 委卖金额 total_offerqty: 委卖量 trade_mins:交易时间,距离开盘已过交易时间,如100则表示每日240分钟交易时间中的第100分钟; trade_status:交易状态; turnover_ratio:换手率 up_px:涨停价格; vol_ratio:量比; wavg_px:加权平均价; transaction - 逐笔成交对应DataFrame包含字段: business_time:时间戳毫秒级; hq_px:价格; business_amount:成交量; trade_index:成交编号; business_direction:成交方向; buy_no: 叫买方编号; sell_no: 叫卖方编号; trans_flag: 成交标记; trans_identify_am: 盘后逐笔成交序号标识; channel_num: 成交通道信息;
返回
None
示例
import astdef initialize(context):g.security = '600570.SS'set_universe(g.security)def tick_data(context,data):# 获取买一价security = g.security current_price = ast.literal_eval(data[security]['tick']['bid_grp'][0])[1][0]log.info(current_price)# 获取买二价# current_price = ast.literal_eval(data[security]['tick']['bid_grp'][0])[2][0]# 获取买三量# current_amount = ast.literal_eval(data[security]['tick']['bid_grp'][0])[3][1]# 获取tick最高价# current_high_price = data[security]['tick']['high_px'][0]# 获取最近一笔逐笔成交的成交量# transaction = data[security]["transaction"]# business_amount = list(transaction["business_amount"])# if len(business_amount) > 0:# log.info("最近一笔逐笔成交的成交量:%s" % business_amount[0])# 获取最近一笔逐笔委托的委托类型# order = data[security]["order"]# trans_kind = list(order["trans_kind"])# if len(trans_kind) > 0:# log.info("最近一笔逐笔委托的委托类型:%s" % trans_kind[0])if current_price > 38.19:# 按买一档价格下单order_tick(security, 100, 1)def handle_data(context, data):pass
on_order_response(可选)-委托主推
on_order_response(context, order_list)
使用场景
该函数仅在交易模块可用,对接jz_ufx不支持该函数
接口说明
该函数会在委托主推回调时响应,比引擎、get_order()和get_orders()函数更新Order状态的速度更快,适合对速度要求比较高的策略。
注意事项:
-
目前可接收股票、可转债、ETF、LOF、期货代码的主推数据。
-
当接到策略外交易产生的主推时(需券商配置默认不推送),由于没有对应的Order对象,主推信息中order_id字段赋值为""。
-
当主推先于委托应答返回时,由于无法根据entrust_no匹配对应的Order对象,主推信息中order_id字段赋值为""。
-
当在主推里调用委托接口时,需要进行判断处理避免无限迭代循环问题。
-
当券商配置接收策略外交易产生的主推且策略调用set_parameters()并设置receive_other_response="1"时, 策略中将接收非本交易产生的主推。
-
撤单委托主推信息中成交数量均处理为正数。
可调用委托接口
参数
context: Context对象,存放有当前的账户及持仓信息;
order_list:一个列表,当前委托单发生变化时,发生变化的委托单列表。委托单以字典形式展现,内容包括:'entrust_no'(委托编号), 'error_info'(错误信息), 'order_time'(委托时间), 'stock_code'(股票代码), 'amount'(委托数量), 'price'(委托价格), 'business_amount'(成交数量), 'status'(委托状态), 'entrust_type'(委托类别), 'entrust_prop'(委托属性), 'order_id'(Order对象编号);
返回
None
接收到的主推格式如下:
本交易委托产生的主推:[{'price': 32.82, 'status': '2', 'amount': 1100, 'order_id': '0e27467920464390aa10a7a53da4d49a', 'stock_code': '600570.SS', 'order_time': '2022-09-21 14:38:35', 'business_amount': 0.0, 'entrust_type': '0', 'entrust_no': '700104', 'error_info': '', 'entrust_prop': '0'}]本交易撤单产生的主推:[{'price': 32.82, 'status': '2', 'amount': 1100, 'order_id': '0e27467920464390aa10a7a53da4d49a', 'stock_code': '600570.SS', 'order_time': '2022-09-21 14:38:37', 'business_amount': 0.0, 'entrust_type': '2', 'entrust_no': '700105', 'error_info': '', 'entrust_prop': '0'}]非本交易委托产生的主推:[{'price': 32.82, 'status': '2', 'amount': 1100, 'order_id': '', 'stock_code': '600570.SS', 'order_time': '2022-09-21 14:41:19', 'business_amount': 0.0, 'entrust_type': '0', 'entrust_no': '700106', 'error_info': '', 'entrust_prop': '0'}]非本交易撤单产生的主推:[{'price': 32.82, 'status': '2', 'amount': 1100, 'order_id': '', 'stock_code': '600570.SS', 'order_time': '2022-09-21 14:41:30', 'business_amount': 0.0, 'entrust_type': '2', 'entrust_no': '700107', 'error_info': '', 'entrust_prop': '0'}]
示例
def initialize(context):g.security = ['600570.SS','002416.SZ']set_universe(g.security)g.flag = 0def on_order_response(context, order_list):log.info(order_list)if(g.flag==0):order('600570.SS', 100)g.flag = 1else:log.info("end")def handle_data(context, data):order('600570.SS', 100)
on_trade_response(可选)-成交主推
on_trade_response(context, trade_list)
使用场景
该函数仅在交易模块可用
接口说明
该函数会在成交主推回调时响应,比引擎和get_trades()函数更新Order状态的速度更快,适合对速度要求比较高的策略。
注意事项:
-
目前可接收股票、可转债、ETF、LOF、期货代码的主推数据。
-
当接到策略外交易产生的主推时(需券商配置默认不推送),由于没有对应的Order对象,主推信息中order_id字段赋值为""。
-
当主推先于委托应答返回时,由于无法根据entrust_no匹配对应的Order对象,主推信息中order_id字段赋值为""。
-
当在主推里调用委托接口时,需要进行判断处理避免无限迭代循环问题。
-
当券商配置接收策略外交易产生的主推且策略调用set_parameters()并设置receive_other_response="1"时, 策略中将接收非本交易产生的主推。
-
撤单成交主推信息中成交数量均处理为正数。
-
withdraw_no(撤单原委托号)仅在撤单成交主推信息中才有对应值,在委托成交主推中该字段赋'0'默认值。
-
撤单成交主推信息中entrust_no在异构柜台情况下与withdraw_no一致,因此策略中请勿将该字段作为撤单成交主推信息的关联字段。
可调用委托接口
参数
context: Context对象,存放有当前的账户及持仓信息;
trade_list:一个列表,当前成交单发生变化时,发生变化的成交单列表。成交单以字典形式展现,内容包括:'entrust_no'(委托编号),'business_time'(成交时间),'stock_code'(股票代码),'entrust_bs'(委托方向),'business_amount'(成交数量),'business_price'(成交价格),'business_balance'(成交额),'business_id'(成交编号),'status',(委托状态)(对接jz_ufx、ctp期货柜台该字段为空),'order_id'(Order对象编号),'cancel_info'(废单原因),'withdraw_no'(撤单原委托号),'real_type' (成交类型编号),'real_status'(成交状态编号);
返回
None
接收到的主推格式如下:
本交易委托产生的主推:[{'order_id': '0e27467920464390aa10a7a53da4d49a', 'entrust_bs': '1', 'status': '7', 'business_id': '58', 'withdraw_no': '0', 'business_time': '2022-09-21 14:38:11', 'stock_code': '600570.SS', 'business_balance': 32820.0, 'business_price': 32.82, 'business_amount': 1000, 'entrust_no': '700104', 'cancel_info': ' ', 'real_type': '0', 'real_status': '0'}]本交易撤单产生的主推:[{'order_id': '0e27467920464390aa10a7a53da4d49a', 'entrust_bs': '1', 'status': '5', 'business_id': '0', 'withdraw_no': '700104', 'business_time': '2022-09-21 14:38:13', 'stock_code': '600570.SS', 'business_balance': -3282.0, 'business_price': 32.82, 'business_amount': 100, 'entrust_no': '700105', 'cancel_info': ' ', 'real_type': '2', 'real_status': '0'}]非本交易委托产生的主推:[{'order_id': '', 'entrust_bs': '1', 'status': '7', 'business_id': '59', 'withdraw_no': '0', 'business_time': '2022-09-21 14:40:56', 'stock_code': '600570.SS', 'business_balance': 32820.0, 'business_price': 32.82, 'business_amount': 1000, 'entrust_no': '700106', 'cancel_info': ' ', 'real_type': '0', 'real_status': '0'}]非本交易撤单产生的主推:[{'order_id': '', 'entrust_bs': '1', 'status': '7', 'business_id': '0', 'withdraw_no': '700106', 'business_time': '2022-09-21 14:41:06', 'stock_code': '600570.SS', 'business_balance': 0.0, 'business_price': 32.82, 'business_amount': 0, 'entrust_no': '700107', 'cancel_info': '交易主机繁忙', 'real_type': '2', 'real_status': '0'}]
示例
def initialize(context):g.security = ['600570.SS','002416.SZ']set_universe(g.security)g.flag = 0def on_trade_response(context, trade_list):log.info(trade_list)if(g.flag==0):order('600570.SS', 100)g.flag = 1else:log.info("end")def handle_data(context, data):order('600570.SS', 100)
