文章声明:本内容为个人的业余研究,和任何单位,机构没有关系,文章出现的股票代码,全部只是测试例子,不做投资参考,投资有风险,代码学习使用,不做商业用途
qmt方面我也比较熟悉,最近在看ptrade感觉比qmt简单太多了。qmt一个大qmt,一个miniqmt。写起来比较复杂,qmt,ptrade各有所长,给群友写量化教程,把全部qmt迁移到ptrade,方便大家研究使用,重点提示一下ptrade的实盘是不支持回测的,需要利用模拟盘
qmt时间运行函数比较少一个handle 一个run_time,ptrade时间运行函数比较多
网页链接我全部上线了可以看http://120.78.132.143:9999/xms_quants.html,也可以共众号里面看
里面就有我上线的ptrade教程
策略运行周期
回测支持日线级别、分钟级别运行,详见handle_data方法。
交易支持日线级别、分钟级别、tick级别运行,日线级别和分钟级别详见handle_data方法,tick级别运行详见run_interval和tick_data方法。
频率:日线级别
当选择日线频率时,回测和交易都是每天运行一次,运行时间为每天盘后。
频率:分钟级别
当选择分钟频率时,回测和交易都是每分钟运行一次,运行时间为每根分钟K线结束。
频率:tick级别
当选择tick频率时,交易最小频率可以达到3秒运行一次。
策略运行时间
盘前运行:
9:30分钟之前为盘前运行时间,交易环境支持运行在run_daily中指定交易时间(如time='09:15')运行的函数;回测环境和交易环境支持运行before_trading_start函数
盘中运行:
9:31(回测)/9:30(交易)~15:00分钟为盘中运行时间,分钟级别回测环境和交易环境支持运行在run_daily中指定交易时间(如time='14:30')运行的函数;回测环境和交易环境支持运行handle_data函数;交易环境支持运行run_interval函数
盘后运行:
15:30分钟为盘后运行时间,回测环境和交易环境支持运行after_trading_end函数(该函数为定时运行);15:00之后交易环境支持运行在run_daily中指定交易时间(如time='15:10')运行的函数,
handle_data(函数1)
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日继续运行)。
例子代码
'''
作者:西蒙斯量化
微信:xms_quants1
使用场景
该函数仅在回测、交易模块可用
接口说明
该函数在交易时间内按指定的周期频率运行,是用于处理策略交易的主要模块,根据策略保存时的周期参数分为每分钟运行和每天运行,是策略运行的唯二必须定义函数之一。
注意事项:
该函数每个单位周期执行一次
如果是日线级别策略,每天执行一次。股票回测场景下,在15:00执行;股票交易场景下,执行时间为券商实际配置时间。
如果是分钟级别策略,每分钟执行一次,股票回测场景下,执行时间为9:31 -- 15:00,股票交易场景下,执行时间为9:30 -- 14:59。
回测与交易中,handle_data函数不会在非交易日触发(如回测或交易起始日期为2015年12月21日,则策略在2016年1月1日-3日时,handle_data不会运行,4日继续运行)。
'''
import pandas as pd
def initialize(context):
g.security = "600570.SS"
set_universe([g.security])
def get_xms_account(context):
'''
获取西蒙斯账户数据
'''
df=pd.DataFrame()
df['可用金额']=[context.portfolio.cash]
df['总资产']=[context.portfolio.portfolio_value]
df['持仓价值']=[context.portfolio.positions_value]
df['已使用现金']=[context.portfolio.capital_used]
df['当前收益比例']=[context.portfolio.returns]
df['初始账户总资产']=[context.portfolio.pnl]
df['开始时间']=[context.portfolio.start_date]
return df
def get_xms_position(context):
'''
获取西蒙斯持股数据
'''
data=pd.DataFrame()
positions=context.portfolio.positions
stock_list=list(set(positions.keys()))
print('持股数量{}'.format(len(stock_list)))
for stock in stock_list:
df=pd.DataFrame()
df['证券代码']=[positions[stock].sid]
df['可以数量']=[positions[stock].enable_amount]
df['持有数量']=[positions[stock].amount]
df['最新价']=[positions[stock].last_sale_price ]
df['成本价']=[positions[stock].cost_basis ]
df['今日买入']=[positions[stock].today_amount ]
df['持股类型']=[positions[stock].business_type ]
data=pd.concat([data,df],ignore_index=True)
return data
def get_xms_order(context):
'''
获取西蒙斯委托数据
'''
orders=get_orders()
print("委托数量{}".format(len(orders)))
data=pd.DataFrame()
if len(orders)>0:
for ors in orders:
df=pd.DataFrame()
df['订单号']=[ors.id]
df['订单产生时间']=[ors.dt]
df['指定价格']=[ors.limit ]
df['证券代码']=[ors.symbol ]
df['委托数量']=[ors.amount ]
df['订单生成时间']=[ors.created ]
df['成交数量']=[ors.filled ]
df['委托编号']=[ors.entrust_no]
df['盘口档位']=[ors.priceGear ]
df['订单状态']=[ors.status ]
data=pd.concat([data,df],ignore_index=True)
else:
data=data
return data
def get_xms_position_on(context,security=''):
''''
获取西蒙斯单股的持股情况
'''
pos=get_positions(security=security)
df=pd.DataFrame()
if len(pos)>0:
df['证券代码']=[pos[security].sid]
df['可以数量']=[pos[security].enable_amount]
df['持有数量']=[pos[security].amount]
df['最新价']=[pos[security].last_sale_price ]
df['成本价']=[pos[security].cost_basis ]
df['今日买入']=[pos[security].today_amount ]
df['持股类型']=[pos[security].business_type ]
else:
df=df
return df
def handle_data(context, data):
'''
每一个数据周期调用一次下面的函数,回测口语点击运行,实盘只有在交易时间会触发
'''
df=get_xms_account(context)
print(df)
df=get_xms_position(context)
print(df)
df=get_xms_order(context)
print(df)
df=get_xms_position_on(context,security='600031.SS')
print(df)
run_interval -函数2 按设定周期处理
run_interval(context, func, seconds=10)
使用场景
该函数仅在交易模块可用
接口说明
该函数用于以设定时间间隔(单位为秒)周期性运行指定函数,可对运行触发时间间隔进行指定。
注意事项:
1、该函数只能在初始化阶段initialize函数中调用。
2、该函数可以多次设定,会以多个线程并行运行,但要小心不同线程之间的逻辑关联处理
3、seconds设置最小时间间隔为3秒,小于3秒默认设定为3秒。
参数
context: Context对象,存放有当前的账户及持仓信息(Context);
func:自定义函数名称,此函数必须以context作为参数(Callable[[Context], None]);
seconds:设定时间间隔(单位为秒),取值为正整数(int)。
例子
'''
作者:西蒙斯量化
微信:xms_quants1
使用场景
该函数仅在回测、交易模块可用
接口说明
该函数在交易时间内按指定的周期频率运行,是用于处理策略交易的主要模块,根据策略保存时的周期参数分为每分钟运行和每天运行,是策略运行的唯二必须定义函数之一。
注意事项:
该函数每个单位周期执行一次
如果是日线级别策略,每天执行一次。股票回测场景下,在15:00执行;股票交易场景下,执行时间为券商实际配置时间。
如果是分钟级别策略,每分钟执行一次,股票回测场景下,执行时间为9:31 -- 15:00,股票交易场景下,执行时间为9:30 -- 14:59。
回测与交易中,handle_data函数不会在非交易日触发(如回测或交易起始日期为2015年12月21日,则策略在2016年1月1日-3日时,handle_data不会运行,4日继续运行)。
'''
import pandas as pd
def initialize(context):
g.security = "600570.SS"
set_universe([g.security])
def get_xms_account(context):
'''
获取西蒙斯账户数据
'''
df=pd.DataFrame()
df['可用金额']=[context.portfolio.cash]
df['总资产']=[context.portfolio.portfolio_value]
df['持仓价值']=[context.portfolio.positions_value]
df['已使用现金']=[context.portfolio.capital_used]
df['当前收益比例']=[context.portfolio.returns]
df['初始账户总资产']=[context.portfolio.pnl]
df['开始时间']=[context.portfolio.start_date]
return df
def get_xms_position(context):
'''
获取西蒙斯持股数据
'''
data=pd.DataFrame()
positions=context.portfolio.positions
stock_list=list(set(positions.keys()))
print('持股数量{}'.format(len(stock_list)))
for stock in stock_list:
df=pd.DataFrame()
df['证券代码']=[positions[stock].sid]
df['可以数量']=[positions[stock].enable_amount]
df['持有数量']=[positions[stock].amount]
df['最新价']=[positions[stock].last_sale_price ]
df['成本价']=[positions[stock].cost_basis ]
df['今日买入']=[positions[stock].today_amount ]
df['持股类型']=[positions[stock].business_type ]
data=pd.concat([data,df],ignore_index=True)
return data
def get_xms_order(context):
'''
获取西蒙斯委托数据
'''
orders=get_orders()
print("委托数量{}".format(len(orders)))
data=pd.DataFrame()
if len(orders)>0:
for ors in orders:
df=pd.DataFrame()
df['订单号']=[ors.id]
df['订单产生时间']=[ors.dt]
df['指定价格']=[ors.limit ]
df['证券代码']=[ors.symbol ]
df['委托数量']=[ors.amount ]
df['订单生成时间']=[ors.created ]
df['成交数量']=[ors.filled ]
df['委托编号']=[ors.entrust_no]
df['盘口档位']=[ors.priceGear ]
df['订单状态']=[ors.status ]
data=pd.concat([data,df],ignore_index=True)
else:
data=data
return data
def get_xms_position_on(context,security=''):
''''
获取西蒙斯单股的持股情况
'''
pos=get_positions(security=security)
df=pd.DataFrame()
if len(pos)>0:
df['证券代码']=[pos[security].sid]
df['可以数量']=[pos[security].enable_amount]
df['持有数量']=[pos[security].amount]
df['最新价']=[pos[security].last_sale_price ]
df['成本价']=[pos[security].cost_basis ]
df['今日买入']=[pos[security].today_amount ]
df['持股类型']=[pos[security].business_type ]
else:
df=df
return df
def handle_data(context, data):
'''
每一个数据周期调用一次下面的函数,回测口语点击运行,实盘只有在交易时间会触发
'''
df=get_xms_account(context)
print(df)
df=get_xms_position(context)
print(df)
df=get_xms_order(context)
print(df)
df=get_xms_position_on(context,security='600031.SS')
print(df)
tick_data(函数3)
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。
例子
'''
作者:西蒙斯量化
微信:xms_quants1
只处理tick数据
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。
'''
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
def tick_data(context,data):
# 获取买一价
security = g.security
current_price = eval(data[security]['tick']['bid_grp'][0])[1][0]
log.info(current_price)
# 获取买二价
# current_price = eval(data[security]['tick']['bid_grp'][0])[2][0]
# 获取买三量
# current_amount = eval(data[security]['tick']['bid_grp'][0])[3][1]
# 获取tick最高价
# current_high_price = data[security]['tick']['high_px'][0]
# 最近一笔逐笔成交的成交量
# transaction = data[security]["transcation"]
# 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
run_daily-函数4按日周期处理
run_daily(context, func, time='9:31')
使用场景
该函数仅在回测、交易模块可用
接口说明
该函数用于以日为单位周期性运行指定函数,可对运行触发时间进行指定。
注意事项:
1、该函数只能在初始化阶段initialize函数中调用。
2、该函数可以多次设定,以实现多个定时任务。
3、股票策略回测中,当回测周期为分钟时,time的取值指定在09:31~11:30与13:00~15:00之间,当回测周期为日时,无论设定值是多少都只会在15:00执行;交易中不受此时间限制。
参数
context: Context对象,存放有当前的账户及持仓信息(Context);
func:自定义函数名称,此函数必须以context作为参数(Callable[[Context], None]);
time:指定周期运行具体触发运行时间点,交易场景可设置范围:00:00~23:59,必传字段。
例子
'''
作者:西蒙斯 量化
微信:xms_quants1
run_daily-按日周期处理
run_daily(context, func, time='9:31')
使用场景
该函数仅在回测、交易模块可用
接口说明
该函数用于以日为单位周期性运行指定函数,可对运行触发时间进行指定。
注意事项:
1、该函数只能在初始化阶段initialize函数中调用。
2、该函数可以多次设定,以实现多个定时任务。
3、股票策略回测中,当回测周期为分钟时,time的取值指定在09:31~11:30与13:00~15:00之间,当回测周期为日时,无论设定值是多少都只会在15:00执行;交易中不受此时间限制。
参数
context: Context对象,存放有当前的账户及持仓信息(Context);
func:自定义函数名称,此函数必须以context作为参数(Callable[[Context], None]);
time:指定周期运行具体触发运行时间点,交易场景可设置范围:00:00~23:59,必传字段。
'''
import pandas as pd
def initialize(context):
g.security = "600570.SS"
set_universe([g.security])
#每天10点获取账户数据
run_daily(context,get_xms_account,time='10:00')
#每天9点半获取持股数据,注意时间前面没有0,和qmt的c.run_time有0不一样
run_daily(context,get_xms_position,time ='9:30')
#每天下午买入
run_daily(context,buy,time ='14:30')
def buy(context):
order(security='600570.SS', amount=100, limit_price=18.23)
def get_xms_account(context):
'''
获取西蒙斯账户数据
'''
df=pd.DataFrame()
df['可用金额']=[context.portfolio.cash]
df['总资产']=[context.portfolio.portfolio_value]
df['持仓价值']=[context.portfolio.positions_value]
df['已使用现金']=[context.portfolio.capital_used]
df['当前收益比例']=[context.portfolio.returns]
df['初始账户总资产']=[context.portfolio.pnl]
df['开始时间']=[context.portfolio.start_date]
return df
def get_xms_position(context):
'''
获取西蒙斯持股数据
'''
data=pd.DataFrame()
positions=context.portfolio.positions
stock_list=list(set(positions.keys()))
print('持股数量{}'.format(len(stock_list)))
for stock in stock_list:
df=pd.DataFrame()
df['证券代码']=[positions[stock].sid]
df['可以数量']=[positions[stock].enable_amount]
df['持有数量']=[positions[stock].amount]
df['最新价']=[positions[stock].last_sale_price ]
df['成本价']=[positions[stock].cost_basis ]
df['今日买入']=[positions[stock].today_amount ]
df['持股类型']=[positions[stock].business_type ]
data=pd.concat([data,df],ignore_index=True)
return data
def get_xms_order(context):
'''
获取西蒙斯委托数据
'''
orders=get_orders()
print("委托数量{}".format(len(orders)))
data=pd.DataFrame()
if len(orders)>0:
for ors in orders:
df=pd.DataFrame()
df['订单号']=[ors.id]
df['订单产生时间']=[ors.dt]
df['指定价格']=[ors.limit ]
df['证券代码']=[ors.symbol ]
df['委托数量']=[ors.amount ]
df['订单生成时间']=[ors.created ]
df['成交数量']=[ors.filled ]
df['委托编号']=[ors.entrust_no]
df['盘口档位']=[ors.priceGear ]
df['订单状态']=[ors.status ]
data=pd.concat([data,df],ignore_index=True)
else:
data=data
return data
def get_xms_position_on(context,security=''):
''''
获取西蒙斯单股的持股情况
'''
pos=get_positions(security=security)
df=pd.DataFrame()
if len(pos)>0:
df['证券代码']=[pos[security].sid]
df['可以数量']=[pos[security].enable_amount]
df['持有数量']=[pos[security].amount]
df['最新价']=[pos[security].last_sale_price ]
df['成本价']=[pos[security].cost_basis ]
df['今日买入']=[pos[security].today_amount ]
df['持股类型']=[pos[security].business_type ]
else:
df=df
return df
def handle_data(context, data):
'''
每一个数据周期调用一次下面的函数,回测口语点击运行,实盘只有在交易时间会触发
'''
order(security='600570.SS', amount=100, limit_price=18.23)
其他的函数比如开票前,盘后,使用比较少
before_trading_start(可选)
before_trading_start(context, data)
使用场景
该函数仅在回测、交易模块可用
接口说明
该函数在每天开始交易前被调用一次,用于添加每天都要初始化的信息,如无盘前初始化需求,该函数可以在策略中不做定义。
注意事项:
-
在回测中,该函数在每个回测交易日8:30分执行。
-
在交易中,该函数在开启交易时立即执行,从隔日开始每天9:10分(默认)执行。
-
当在9:10前开启交易时,受行情未更新原因在该函数内调用实时行情接口会导致数据有误。可通过在该函数内sleep至9:10分或调用实时行情接口改为run_daily执行等方式进行避免。
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)
after_trading_end(可选)
after_trading_end(context, data)
使用场景
该函数仅在回测、交易模块可用
接口说明
该函数会在每天交易结束之后调用,用于处理每天收盘后的操作,如无盘后处理需求,该函数可以在策略中不做定义。
注意事项:
-
该函数只会执行一次
-
该函数执行时间为由券商配置决定,一般为15:30。
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)
文章详情
ptrade量化教程---策略运行周期例子https://mp.weixin.qq.com/s/x6TKdDXXGr_BNtIfaQ6mQQ
'''
作者:西蒙斯量化
微信:xms_quants1
'''
import pandas as pd
def initialize(context):
g.security = "600570.SS"
set_universe([g.security])
def get_xg_account(context):
'''
获取西蒙斯账户数据
'''
df=pd.DataFrame()
df['可用金额']=[context.portfolio.cash]
df['总资产']=[context.portfolio.portfolio_value]
df['持仓价值']=[context.portfolio.positions_value]
df['已使用现金']=[context.portfolio.capital_used]
df['当前收益比例']=[context.portfolio.returns]
df['初始账户总资产']=[context.portfolio.pnl]
df['开始时间']=[context.portfolio.start_date]
return df
def get_xg_position(context):
'''
获取西蒙斯持股数据
'''
data=pd.DataFrame()
positions=context.portfolio.positions
stock_list=list(set(positions.keys()))
print('持股数量{}'.format(len(stock_list)))
for stock in stock_list:
df=pd.DataFrame()
df['证券代码']=[positions[stock].sid]
df['可以数量']=[positions[stock].enable_amount]
df['持有数量']=[positions[stock].amount]
df['最新价']=[positions[stock].last_sale_price ]
df['成本价']=[positions[stock].cost_basis ]
df['今日买入']=[positions[stock].today_amount ]
df['持股类型']=[positions[stock].business_type ]
data=pd.concat([data,df],ignore_index=True)
return data
def get_xg_order(context):
'''
获取西蒙斯委托数据
'''
orders=get_orders()
print("委托数量{}".format(len(orders)))
data=pd.DataFrame()
if len(orders)>0:
for ors in orders:
df=pd.DataFrame()
df['订单号']=[ors.id]
df['订单产生时间']=[ors.dt]
df['指定价格']=[ors.limit ]
df['证券代码']=[ors.symbol ]
df['委托数量']=[ors.amount ]
df['订单生成时间']=[ors.created ]
df['成交数量']=[ors.filled ]
df['委托编号']=[ors.entrust_no]
df['盘口档位']=[ors.priceGear ]
df['订单状态']=[ors.status ]
data=pd.concat([data,df],ignore_index=True)
else:
data=data
return data
def get_xg_position_on(context,security=''):
''''
获取西蒙斯单股的持股情况
'''
pos=get_positions(security=security)
df=pd.DataFrame()
if len(pos)>0:
df['证券代码']=[pos[security].sid]
df['可以数量']=[pos[security].enable_amount]
df['持有数量']=[pos[security].amount]
df['最新价']=[pos[security].last_sale_price ]
df['成本价']=[pos[security].cost_basis ]
df['今日买入']=[pos[security].today_amount ]
df['持股类型']=[pos[security].business_type ]
else:
df=df
return df
def handle_data(context, data):
order(security='600031.SS', amount=100, limit_price=None)
order(security='600111.SS', amount=100, limit_price=None)
df=get_xg_account(context)
print(df)
df=get_xg_position(context)
print(df)
df=get_xg_order(context)
print(df)
df=get_xg_position_on(context,security='600031.SS')
print(df)