【量化基础策略示例】收益 385%,附代码

本篇为大家介绍两个基础量化策略示例,BollingBand 策略和罗伯特-巴卡雷纳成长型投资法示例,希望可以为大家带来一点帮助~

关于回测平台、历史数据,可以在这里下载:http://www.链接失效或指向广告已经被屏蔽.com/# /introduce
这个平台的数据都是经过清洗的,而且策略不会外露,有保密系统,还是比较安全的。
想学习更多量化策略,也可以来这里看看:http://www.链接失效或指向广告已经被屏蔽.com/# /lzClass
想学习更多关于量化投资策略相关内容的,可以关注微信:量化投资与金融科技(微信号:QuantumFintech)
微信二维码:

BollingBand策略示例

策略简介

布林线(Bollinger Band) 是美国股市分析家约翰·布林根据统计学中的标准差原理设计出来的一种非常简单实用的技术分析指标。一般而言,股价的运动总是围绕某一价值中枢(如均线、成本线等)在一定的范围内变动,布林线指标正是在上述条件的基础上,引进了“股价通道”的概念,其认为股价通道的宽窄随着股价波动幅度的大小而变化,而且股价通道又具有变异性,它会随着股价的变化而自动调整。它由三条轨道线组成,其中上下两条线分别可以看成是价格的压力线和支撑线,在两条线之间是一条价格平均线,一般情况价格线在由上下轨道组成的带状区间游走,而且随价格的变化而自动调整轨道的位置。当波带变窄时,激烈的价格波动有可能随即产生;若高低点穿越带边线时,立刻又回到波带内,则会有回档产生。正是由于它具有灵活性、直观性和趋势性的特点,布林线渐渐成为投资者广为应用的市场上热门指标。

计算公式

在所有的指标计算中,BOLL指标的计算方法是最复杂的之一,其中引进了统计学中的标准差概念,涉及到中轨线(MB)、上轨线(UP)和下轨线(DN)的计算。另外,和其他指标的计算一样,由于选用的计算周期的不同,BOLL指标也包括日BOLL指标、周BOLL指标、月BOLL指标年BOLL指标以及分钟BOLL指标等各种类型。经常被用于股市研判的是日BOLL指标和周BOLL指标。虽然它们的计算时的取值有所不同,但基本的计算方法一样。 以日BOLL指标计算为例,其计算方法如下:

中轨线=N日的移动平均线
上轨线=中轨线+两倍的标准差
下轨线=中轨线-两倍的标准差

具体的计算过程为:

  1. 计算MA
    MA=N日内的收盘价之和÷N
  2. 计算标准差MD
    MD=平方根N日的(C-MA)的两次方之和除以N
  3. 计算MB、UP、DN线
    MB=(N-1)日的MA
    UP=MB+2×MD
    DN=MB-2×MD

制定策略

布林线作为经典的技术分析指标,在市场实际应用中有各种各样的解读。在这里我们选取最简单的一种应用方式加以实现:
如果价格向上突破布林线上轨,落在上轨线上方,此时应买入;
如果价格向下突破布林下轨,落在下轨线下方,此时应卖出。
可以看出这是一个典型的趋势跟随型策略。当价格突破上轨时,表明股价在正常波动之外,显示出上扬趋势,是股价强势的信号,此时应买入,反之亦然。

收益曲线


收益归因:


小结

可以看到,该策略在2006.1.1-2017.1.1这个时间段实现了36%的年化收益率(复合年化收益率15.9%),取得了不错的成果。

布林线作为经典的技术分析指标,应用范围远不止于此。很多其他指标,像KDJ、MACD等都可以通过低位向上交叉来作为买入讯号或通过高位向下交叉来作为卖出讯号,但这些指标都有一个缺点,就是在股价盘整的时候会失去作用或产生骗线,给投资者带来损失。通常在股价盘整的过程中,投资者最想知道的一定是股价要盘整到什么时候才会产生行情。因为如果太早买入股票,而股票却又迟迟不涨,资金的利用率就会降低,而且投资者还要承担股价下跌的风险。而布林线指标则恰恰可以在这时发挥其神奇的作用,通过其开口变化,对盘整的结束给予正确的提示,通常,我们可以选择布林线开口缩小到一定程度时进场,避免过早买入股票。

此外,布林线还有显示支撑和压力位置、显示超买超卖、指示趋势、显示通道等作用,具有信号明确,使用灵活的优点。更多的应用就留给读者,结合云宽客平台去继续探索了。

Code:

=PERIOD:
temp=0
_for _i _in _range(PERIOD):
priceList.append(priceData[stock][i].close)
temp+=priceData[stock][i].close
temp=temp/PERIOD
MA.append(temp)
priceList=np.array(priceList)
std=np.std(priceList,ddof=1)
SD.append(std)
upLine.append(temp+RATEstd)
downLine.append(temp-RATE
std)
else:
_return__


_ # 判断买卖条件
buyList=[]
sellList=[]
_for _i,stock _in _enumerate(TRADE_LIST):
quote=sdk.getQuote(stock)
close=quote.close
_if _closeupLine[i]: # 价格突破上轨时买入

sellList.append(stock)

    buyList.append(stock)

_if _sellList: # 卖出应售股票
_for _stock _in _sellList:
pos=sdk.getPositions(code=stock)
_if _pos:
quote=sdk.getQuote(stock)
sdk.makeOrder(stock,quote.current,pos[0].optPosition,-1)
sdk.sdklog([stock,quote.current,pos[0].optPosition,-1],'sell')

_if _buyList: # 买入应购股票
budget=sdk.getAccountInfo().availableCash/len(buyList)
_for _stock _in _buyList:
quote = sdk.getQuote(stock)
volume = (int(budget /(quote.current(1+config['feeRate'])))//100)100
sdk.makeOrder(stock, quote.current, volume, 1)
sdk.sdklog([stock, quote.current, volume, 1], 'buy')

_def _main():

将策略函数加入

config['initial'] = initial
config['strategy'] = strategy
config['preparePerDay'] = initPerDay

启动SDK

SDKCoreEngine(**config).run()

_if _name == "main":
main()
">

-- coding:utf-8 --

_from _CloudQuant _import _SDKCoreEngine # 导入量子金服SDK
_from _CloudQuant _import _AssetType
_from _CloudQuant _import _QuoteCycle
_from _CloudQuant _import _OrderType
_import _numpy _as _np # 使用numpy
np.seterr(invalid='ignore')

config = {
'username': 'username',
'password': 'password',
'rootpath': 'c:/cStrategy', # 客户端所在路径
'assetType': AssetType.Stock,
'initCapitalStock': 1000000, # 初始资金
'startDate': 20060101, # 交易开始日期
'endDate': 20170101, # 交易结束日期
'cycle': QuoteCycle.D, # 回放粒度为日线
'feeRate': 0.001,
'feeLimit': 5,
'strategyName': 'BollingerBandy', # 策略名

-- coding:utf-8 --

_from _CloudQuant _import _SDKCoreEngine # 导入量子金服SDK
_from _CloudQuant _import _AssetType
_from _CloudQuant _import _QuoteCycle
_from _CloudQuant _import _OrderType
_import _numpy _as _np # 使用numpy
np.seterr(invalid='ignore')

config = {
'username': 'username',
'password': 'password',
'rootpath': 'c:/cStrategy', # 客户端所在路径
'assetType': AssetType.Stock,
'initCapitalStock': 1000000, # 初始资金
'startDate': 20060101, # 交易开始日期
'endDate': 20170101, # 交易结束日期
'cycle': QuoteCycle.D, # 回放粒度为日线
'feeRate': 0.001,
'feeLimit': 5,
'strategyName': 'BollingerBandy', # 策略名
"logfile": "BollingerBandy.log",
'dealByVolume': False
}

TRADE_LIST=['000001'] # 设定要交易的股票,这里选取一支用作示例
PERIOD=20 # 设定观察期限
RATE=2 # 设定参数

_def _initial(sdk):
_pass

def _initPerDay(sdk):
_pass


def _strategy(sdk):

获取历史数据,长度为PERIOD

priceData=sdk.getLatest(TRADE_LIST,count=PERIOD,timefreq="D")

计算上、中、下三轨

MA=[]
priceList = []
SD=[]
upLine=[]
downLine=[]
_for _stock _in _TRADE_LIST:
_if _len(priceData[stock])>=PERIOD:
temp=0
_for _i _in _range(PERIOD):
priceList.append(priceData[stock][i].close)
temp+=priceData[stock][i].close
temp=temp/PERIOD
MA.append(temp)
priceList=np.array(priceList)
std=np.std(priceList,ddof=1)
SD.append(std)
upLine.append(temp+RATEstd)
downLine.append(temp-RATE
std)
else:
_return__


_ # 判断买卖条件
buyList=[]
sellList=[]
_for _i,stock _in _enumerate(TRADE_LIST):
quote=sdk.getQuote(stock)
close=quote.close
_if _closeupLine[i]: # 价格突破上轨时买入

sellList.append(stock)

    buyList.append(stock)

_if _sellList: # 卖出应售股票
_for _stock _in _sellList:
pos=sdk.getPositions(code=stock)
_if _pos:
quote=sdk.getQuote(stock)
sdk.makeOrder(stock,quote.current,pos[0].optPosition,-1)
sdk.sdklog([stock,quote.current,pos[0].optPosition,-1],'sell')

_if _buyList: # 买入应购股票
budget=sdk.getAccountInfo().availableCash/len(buyList)
_for _stock _in _buyList:
quote = sdk.getQuote(stock)
volume = (int(budget /(quote.current(1+config['feeRate'])))//100)100
sdk.makeOrder(stock, quote.current, volume, 1)
sdk.sdklog([stock, quote.current, volume, 1], 'buy')

_def _main():

将策略函数加入

config['initial'] = initial
config['strategy'] = strategy
config['preparePerDay'] = initPerDay

启动SDK

SDKCoreEngine(**config).run()

_if _name == "main":
main()

-- coding:utf-8 --

_from _CloudQuant _import _SDKCoreEngine # 导入量子金服SDK
_from _CloudQuant _import _AssetType
_from _CloudQuant _import _QuoteCycle
_from _CloudQuant _import _OrderType
_import _numpy _as _np # 使用numpy
np.seterr(invalid='ignore')

config = {
'username': 'username',
'password': 'password',
'rootpath': 'c:/cStrategy', # 客户端所在路径
'assetType': AssetType.Stock,
'initCapitalStock': 1000000, # 初始资金
'startDate': 20060101, # 交易开始日期
'endDate': 20170101, # 交易结束日期
'cycle': QuoteCycle.D, # 回放粒度为日线
'feeRate': 0.001,
'feeLimit': 5,
'strategyName': 'BollingerBandy', # 策略名

罗伯特-巴卡雷纳成长型投资法

罗伯特-巴卡雷纳是美国著名的基金经理。1986年前创立莫内塔基金公司,1987年的大崩盘,能够全身而退,保证正收益,1990年的波斯湾危机也一闪而过,1991年年度报酬率达56%,至此成为家喻户晓的知名基金经理人,是名副其实的投资大师。

策略思路

罗伯特-巴卡雷纳是对于股票池设定了几个严格的筛选指标,具体为:

  1. 每股获利20%以上
  2. 税前边际盈余10%以上
  3. 负债占股东权益不得超过50%
  4. 每季度盈余成长必须高于5%
  5. 市场上股票价格必须合理,合理股价=盈余成长率 _美股盈余 _0.75.

策略量化实现:

  1. 过去3年平均税前利润大于10%
  2. 最近一季负债占股东权益低于50%
  3. 最近5季平均每季税前利润(EBT)成长率大于5%
  4. 合理股价系数=合理股价/市场股价,大于1。
    合理股价=EBT成长率 _每股权益(EPS) _4
  5. 每月最后一个交易日换仓。

首先,我们剔除了每股获利指标,因为每股获利EPS指标脱离股价便会失去对比意义,而如果我们使用EPS/P,这个指标实质上是PE的倒数,而获利指标和市场价格之间的关系,事实上在合理股价系数中已经涵盖,因此这个因子的功能是重复的,我们选择将它剔除。

对于上述因子1、2、3,我们基本保持了对大师思想的照搬。对于因子4,合理股价的计算中,系数的选取需要根据不同市场或是相同市场的不同时期进行弹性更改。而我们设定这个系数基于两个原因:

第一:我们首先考察了因子1、2、3设定的阈值,若只选其中一个因子阈值进行股票筛选,则3个因子评价筛选出的股票数量处于一个数量级上,因此,我们希望我们设定的系数,能够让因子4单独筛选出的股票与前三个因子处于相同数量级。

第二:对于市场上所有股票的市场价格,以及它们的盈利指标,我们可以将这个系数的市场平均值反推处理。综合上述两个原因进行考虑,我们最终将这个系数设定为4。

策略回测

回测区间选择为2016年1月1日至2016年12月31日,目标股票池为全部符合条件的A股。策略回测指标如下:

由图可见,策略在回测期内年化收益8.3%,还是比较可观的;最大回撤10.8%,略微偏高;夏普比率止盈0.554,从夏普比率来看不是很理想。

策略的风险与收益归因图如下:

单位净值和回撤如下:

策略的行业偏差如下:

下面是策略的代码部分,欢迎大家批评指正:


关键字:交易策略, 量化投资, 投资策略, 算法交易

原文发布于宽客论坛,点击阅读原文

风险提示及免责条款

市场有风险,投资需谨慎。本文不构成个人投资建议,也未考虑到个别用户特殊的投资目标、财务状况或需要。用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部