2023年QMT量化交易第三课:网格交易策略
首发回答
感谢您关注该问题,该问题由资深孔经理做了首答
下面是首发回答的具体内容,如果对该问题还有疑问,欢迎关注进一步交流。
Hello,大家好呀,欢迎大家观看QMT量化交易教程,我会用7天时间带领大家熟悉QMT,今天我们来看下QMT量化交易教程第二课:网格交易策略。

大家想学习QMT的话可以加我联系方式,然后找我要一个QMT的测试账号。登录测试账号,照着视频里的代码自己敲一遍,这样学习效果比较好。我这里也有现成的代码,如果有需要的话也可以找我。

本次教学的内容主要分为两个部分。上半部分,我会从投资中经常碰到的三个问题出发。引出我们今天要重点讲解的交易策略,也就是网格交易策略,然后介绍网格交易策略的基本原理。下半部分,我会带大家看一下网格交易策略如何在QMT平台上实现。上个视频我们已经讲完上半部分,今天我们来讲下半部分,如何用QMT实现网格交易策略。

首先用我给的测试账号登录系统,登录进去以后,这里有一个我已经写好的网格交易策略。

第一步还是先导入numpy和pandas库。

import numpy as np
import pandas as pd



接下来看看init函数,通过ContextInfo.stockcode来获取主图代码,加上市场后,赋值给tradestock,然后通过set_universe函数来订阅股票。

def init(ContextInfo):
#设置主图股票代码为买卖标的
ContextInfo.tradestock = ContextInfo.stockcode "." ContextInfo.market
ContextInfo.set_universe([ContextInfo.tradestock])



接下来设置网格交易初始初始建仓的资金比例,根据之前的策略,初始仓位是60%,接着我们设置网格交易的步长,这里设置为基准价的0.5%。

# 设置建仓资金比例
ContextInfo.weight = 0.60
# 设置网格的步长,以基准价的百分比表示
ContextInfo.step = 0.005 #步长设置参数

接下来设置网格线,这里我们用基准价的百分比来设置。我这里用一个数组来代表网格线,另外我们用一个很小的数和一个很大的数,来代表网格的上下极限值。我们把数组打印出来看看。我们可以看到,基准是1,然后是0.997,代表基准价的0.997倍,接下来是0.994一直到0.985,代表5个网格线,最上面一个是0.182,这个用来控制持仓上下限。

然后是资金帐号,这里可以设置为我们实盘的资金帐号。

# 设置网格线的价格,以基准价的百分比表示
ContextInfo.band = pd.Series([0.2,1,1,1,1,1,1,1,1,1,1,1,10])
pd.Series([-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6])*ContextInfo.step
print(ContextInfo.band)
ContextInfo.accountid='1011328'

ContextInfo.short代表短期均线长度,设置为5,middle代表中期均线长度,设置为20,long代表长期均线长度,设置为40。这三个参数主要用于利用均线多头排列来建仓的。

ContextInfo.short=5
ContextInfo.middle=20
ContextInfo.long=40

Price变量,代表基准价。

ContextInfo.price=0

Holdings_list是一个列表,用于记录持仓数量,我们主要用到的还是第一个数,也即是开仓时的数量。

ContextInfo.holdings_list=[]

接下来是目标仓位,上一个视频讲过,在同一区间内,买入和卖出在同一个价格区间内的目标仓位是不同的,卖出的时候比买入的时候多一个网格交易的数量的股票,因此这里我们使用Buy_Lable和Sell_Lable两个列表来代表买入和卖出的目标仓位,-1代表卖出一个单位的股票,这里的一个单位,代表初始持仓的10%。

#对应区间的目标仓位,买入和卖出在同一价格区间的目标仓位不一致,需分别列出,以相对底仓的变动表示
ContextInfo.Buy_Lable=pd.Series([5,4,3,2,1,0,-1,-2,-3,-4,-5,-5])
ContextInfo.Sell_Lable=pd.Series([5,5,4,3,2,1,0,-1,-2,-3,-4,-5])

接下来两个变量number_plus和number_down代表买入的次数和卖出的次数。

ContextInfo.number_plus = 0
ContextInfo.number_down = 0

初始化变量以后,我们来看下handlebar函数。这个函数放了我们的策略逻辑,然后系统会根据回测周期重复的调用,每个时间间隔运行一次。比如默认周期设置为3分钟,则handlebar会根据这个3分钟周期频率运行一次。另外系统最低支持tick级别的回测,大家可以选择分笔线,这个就代表tick级频率。交易也可以选择tick级别的交易

然后进入到网格交易策略handlebar主函数里面,前三行,这里不是策略的主要内容,主要是用于显示目前回测运行到哪个时间点了,方便我们进行问题排查。大家可以直接把这三行代码复制到自己的策略里。

def handlebar(ContextInfo):
index = ContextInfo.barpos
timetag = ContextInfo.get_bar_timetag(index)
print(timetag_to_datetime(timetag, '%Y%m%d %H:%M:%S'))

接下来是获取持仓,调用get_holdings函数,这是一个我们自定义的函数,传入的参数是accountid和’STOCK’,我们来看下这个函数。首先定义了一个空字典,这个字典用来存储股票持仓。接下来我们继续调用get_trade_detail_data函数,这是一个获取账户信息的函数,传入资金帐号,datatype是账户的类别,这里穿的是’STOCK’,代表股票账户,然后再传一个’POSITION’,代表获取持仓。把返回结果赋值给resultlist,这是一个列表,列表里存的是POSITION持仓对象,我们可以通过文档来看这个POSITION对象,里面有很多字段,我们只需要股票代码和数量这两个最关键的字段。这里用一个for循环展开所有的POSITION对象,holdinglist这个字典的键设置为股票代码m_strInstrumentID加市场m_strExchangeID,比如000001.SZ,值设置为持仓量m_nVolume,除以100的意思是把多少股转化为多少手。最终把字典返回。把返回的结果赋值给holdings。

#获取持仓信息{code.market:手数}
def get_holdings(accountid,datatype):
holdinglist={}
resultlist=get_trade_detail_data(accountid,datatype,"POSITION")
for obj in resultlist:
holdinglist[obj.m_strInstrumentID "." obj.m_strExchangeID]=obj.m_nVolume/100
#返回{code.market:持仓手数}
return holdinglist

接下来用get_totalvalue函数获取总资产,这个函数第一课已讲过,这里我们不再赘述。这两个获取持仓和获取资金的函数,大家可以直接复制,用在后面自己的策略中,减少工作量。

#=============建仓=======================
holdings=get_holdings(ContextInfo.accountid,'STOCK')
totalvalue=get_totalvalue(ContextInfo.accountid,'STOCK')

接下来,我们去判定当前是否有持仓,if not holdings,假设没有持仓,需要进行建仓操作。这几行代码是用来计算移动均线的,首先去获取历史行情,调用get_history_data函数获取历史行情,第一个参数是K线的数量,最大40日均线,因此传41,然后我们策略是3分钟频率的策略,因此传’3m’,’m’代表分钟,’close’代表收盘价,历史收盘行情赋值给’h’。接下来用np.mean来计算5日,20日,40日均线,分别复制给ma5,ma20,ma40。当满足ma20大于ma40,ma5大于ma20,也就是均线多头排列时,调用order_target_value开仓,之前我们也讲过,开仓时用60%的资金开仓,因此第二个参数设置为

ContextInfo.weight*totalvalue,weight是0.6,totalvalue是总的资金。把开仓时的价格,也就是基准价赋值给price。然后打印出来。

if not holdings:
h=ContextInfo.get_history_data(41,'3m','close')
ma5=np.mean(h[ContextInfo.tradestock][-ContextInfo.short-1:-1])
ma20=np.mean(h[ContextInfo.tradestock][-ContextInfo.middle-1:-1])
ma40=np.mean(h[ContextInfo.tradestock][-ContextInfo.long-1:-1])
if ma20>ma40 and ma5>ma20:
order_target_value(ContextInfo.tradestock,ContextInfo.weight*totalvalue,
ContextInfo,ContextInfo.accountid)
ContextInfo.price=h[ContextInfo.tradestock][-1]

一旦我们有了底仓之后,接下来就去进行的网格交易操作,这个if holdings就是我们有底仓就开始进行网格交易操作。

首先将当前持仓保存在holdings_list这个列表里,然后去获取底仓,底仓就是我们通过均线多头排列开仓的数量。

#=============网格交易====================
if holdings:
#print(111)
ContextInfo.holdings_list.append(holdings[ContextInfo.tradestock])
#底仓为仓位记录的首位
basic_holdings= ContextInfo.holdings_list[0]

接下来计算网格线的具体价格,band是百分比,乘以基准价后,就变成具体网格线的价格。这里我们打印出来看下,第一个非常小,最后一个数非常大,用这两个数来作为持仓上下限的控制条件,因为价格一般不会突破这两个值,因此最多卖出50%的股票,最多买入50%的股票。

#网格线的具体价格
Limit_price = np.array(ContextInfo.band)*ContextInfo.price
print(Limit_price)

用get_history_data获取最近2根K线的价格,为什么是2根,因为我们要去判断价格上涨还是下跌。

Con_close= ContextInfo.get_history_data(2,'3m','close')[ContextInfo.tradestock]

然后利用pandas的cut函数,来当前价格在哪个网格区间。

#获取当前价格对应的区间
lable=pd.cut(Con_close[-1],Limit_price,labels=False)

然后计算每次固定的交易数量,这里用了int强制类型转换,目的是为了使得买卖数量为100的整数倍。

#固定的交易量
trade_volume = int(0.1*basic_holdings/100)*100

然后计算买入和卖出的目标仓位,注意买入和卖出的时候目标仓位是不同的,卖出的目标仓位要比买入的时候多一个固定交易数量。

Buy_aim_Position= basic_holdings pd.Series(ContextInfo.Buy_Lable*trade_volume)
Sell_aim_Position= basic_holdings pd.Series(ContextInfo.Sell_Lable*trade_volume)

d,获取当前索引,用于计算下面的p,p是当前净值。

d = ContextInfo.barpos #当前K线索引号
p = ContextInfo.get_net_value(d)

接下来,判断股价上涨还是下跌,当股价上涨时,需要卖出股票,这里我们要用到卖出的目标仓位Sell_aim_Position,用当前仓位减去卖出仓位,就得到了需要调仓的数量Sell_volume,当调仓数量大于0的时候,意思是股价向上突破格值,需要 卖出股票。这里我们调用order_shares函数,这个函数是按照数量下单的函数,然后卖出次数number_down加1,打印出来。

#价格上涨部分卖出
if Con_close[1]>Con_close[0]:
Sell_volume = holdings[ContextInfo.tradestock]-Sell_aim_Position[lable]
#print(Sell_volume)
#过滤掉无效的价格波动
if Sell_volume >0:
ContextInfo.draw_text(1>0,p 0.01*p,"S")
order_shares(ContextInfo.tradestock,-Sell_volume*100,'fix',Limit_price[lable],ContextInfo,ContextInfo.accountid)
ContextInfo.number_down =1
print('down',ContextInfo.number_down)

价格下跌也是相同的处理,先计算买入调仓数量Buy_volume,然后画出标记,买入股票,买入次数加1,打印。

#价格下跌部分买入
if Con_close[1]Buy_volume = Buy_aim_Position[lable]-holdings[ContextInfo.tradestock]
#过滤掉无效的价格波动
if Buy_volume>0:
ContextInfo.draw_text(1>0,p 0.01*p,"B")
order_shares(ContextInfo.tradestock,Buy_volume *100,'fix',Limit_price[lable 1],ContextInfo,ContextInfo.accountid)
ContextInfo.number_plus =1
print('plus',ContextInfo.number_plus)


编辑完策略代码以后,我们就可以点击左上角“回测”这个按钮,就能得到回测结果。

资深孔经理 当前我在线
帮助428 好评2210 入驻3年
“大鹏一日乘风起,扶摇直上九万里“
一对一咨询
1 收藏 追问
举报

还有12位专业答主对该问题做了解答

资深孔经理的相关回答 查看更多>
什么是网格交易?哪家券商支持同花顺网格交易?
你好,网格交易就是选择一个合适的基准价,设定好的涨幅与跌幅,以及需要成交数量,在达到这个条件,对买卖的行为进行自动化的操作。大型的券商支持同花顺网格交易。网格交易优势:1.智能盯盘:对于上班族没...
资深孔经理 1520
网格交易的券商有哪些
您好,网格交易的券商还是比较少的,目前有网格交易的券商基本上都是头部券商,比如:华泰证券,中金公司,银河证券,国金[图片1]证券,安信证券,国泰君安都是比较不错的。头部券商每年投入的软件研发比较...
资深孔经理 1043
量化交易系统ptrade和QMT详细对比,选择大于努力
目前市面上针对个人量化投资者,比较火的两款量化交易终端分别是PTrade和QMT,大家在选择的时候可能会比较纠结选哪个,今天我给大家盘点下ptrade和qmt的不同点,方便大...
资深孔经理 1944
2023年0基础QMT量化交易系统详细指南
QMT量化交易系统是一套可以自行回测、模拟和交易的量化交易系统,支持python以及VBA语言编程可以程序化地访问证券公司进行自动交易。快速投资QMT系统是目前实盘使用最多的...
资深孔经理 1848
什么是网格交易?网格交易为什么如此受大家欢迎?
您好,所谓网格策略,简单来说就是自动化的低吸高抛,非常适用于当前的震荡行情。和传统的高抛低吸策略不同的是,网格策略是自动化的交易,可以避免被情绪或者其他信息所干扰。自动网格交易软件都有:迅投QM...
资深孔经理 2400
评论
浏览更多不如立即追问,99%用户选择
立即追问

已有32,242,202用户获得帮助