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

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

关于回测平台、历史数据,可以在这里下载:http://www.yunkuanke.com/#/introduce
这个平台的数据都是经过清洗的,而且策略不会外露,有保密系统,还是比较安全的。
想学习更多量化策略,也可以来这里看看:http://www.yunkuanke.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:

# -*- 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+RATE*std)
        downLine.append(temp-RATE*std)
    _else_:
        _return__
__    __
__    _#判断买卖条件
buyList=[]
sellList=[]
_for _i,stock _in _enumerate(TRADE_LIST):
    quote=_sdk_.getQuote(stock)
    close=quote.close
    _if _close<downLine[i]: #价格突破下轨时卖出
        sellList.append(stock)
        # buyList.append(stock)
    _if _close>upLine[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()

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

罗伯特 - 巴卡雷纳是美国著名的基金经理。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,从夏普比率来看不是很理想。

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

单位净值和回撤如下:

策略的行业偏差如下:

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