在第1节中,我们学习了移动平均线的原理,中位数以及正态分布的概念,并通过python手工做了一个双均线的策略回测。了解了怎么用pandas计算移动平均线(rolling+mean),怎么得到某一列上1个的值(shift),以及Cross的实现方式,还有通过循环得到EMA上一值与当前close的运算等。这让我们对于指标、公式的应用有了一个粗略的理解,也可以开始编写一些指标公式了。
但是,最好的学习是先临摹,所以我们先详细的学习和实践一下backtrader内置的指标。
内置指标
参考文档
- Indicators - Reference - Backtrader
- BackTrader 中文文档(六) - 绝不原创的飞龙 - 博客园 (cnblogs.com)
第1个是官方英文版,第2个是有些名称和说明翻译成了中文的。我们以官方的文档为准。
01_内置指标列表
首先,获取内置指标列表,在官网页面上,通过inspect审查检查列表所在的“Table of contents”元素所在位置如图所示:
然后使用requests把HTML提取出来,再使用XPATH把文本提取出来,由输出结果可知,一共276个指标。
import requests
url1 = 'https://www.backtrader.com/docu/indautoref'
response = requests.get(url = url1)
texts = response.text
from lxml import etree
tree1 = etree.HTML(texts)
li_list = tree1.xpath('//nav[@class="md-nav md-nav--secondary"]/ul/li/a/span/text()')
li1 = [x.strip() for x in li_list]
len(li1),li1
------------------------------
(276,
['AccelerationDecelerationOscillator',
'Accum',
'AdaptiveMovingAverage',
'AdaptiveMovingAverageEnvelope',
'AdaptiveMovingAverageOscillator',
'AllN',
'AnyN',
'ApplyN',
'AroonDown',
'AroonOscillator',
'AroonUp',
'AroonUpDown',
'AroonUpDownOscillator',
'Average',
'AverageDirectionalMovementIndex',
'AverageDirectionalMovementIndexRating',
'AverageTrueRange',
'AwesomeOscillator',
'BaseApplyN',
'BollingerBands',
'BollingerBandsPct',
'CointN',
'CommodityChannelIndex',
'CrossDown',
'CrossOver',
'CrossUp',
'DV2',
'DemarkPivotPoint',
'DetrendedPriceOscillator',
'DicksonMovingAverage',
'DicksonMovingAverageEnvelope',
'DicksonMovingAverageOscillator',
'DirectionalIndicator',
'DirectionalMovement',
'DirectionalMovementIndex',
'DoubleExponentialMovingAverage',
'DoubleExponentialMovingAverageEnvelope',
'DoubleExponentialMovingAverageOscillator',
'DownDay',
'DownDayBool',
'DownMove',
'Envelope',
'ExponentialMovingAverage',
'ExponentialMovingAverageEnvelope',
'ExponentialMovingAverageOscillator',
'ExponentialSmoothing',
'ExponentialSmoothingDynamic',
'FibonacciPivotPoint',
'FindFirstIndex',
'FindFirstIndexHighest',
'FindFirstIndexLowest',
'FindLastIndex',
'FindLastIndexHighest',
'FindLastIndexLowest',
'Fractal',
'HeikinAshi',
'Highest',
'HullMovingAverage',
'HullMovingAverageEnvelope',
'HullMovingAverageOscillator',
'HurstExponent',
'Ichimoku',
'KnowSureThing',
'LaguerreFilter',
'LaguerreRSI',
'LinePlotterIndicator',
'Lowest',
'MACD',
'MACDHisto',
'MeanDeviation',
'MinusDirectionalIndicator',
'Momentum',
'MomentumOscillator',
'MovingAverageBase',
'MovingAverageSimple',
'MovingAverageSimpleEnvelope',
'MovingAverageSimpleOscillator',
'NonZeroDifference',
'OLS_BetaN',
'OLS_Slope_InterceptN',
'OLS_TransformationN',
'OperationN',
'Oscillator',
'OscillatorMixIn',
'ParabolicSAR',
'PercentChange',
'PercentRank',
'PercentagePriceOscillator',
'PercentagePriceOscillatorShort',
'PeriodN',
'PivotPoint',
'PlusDirectionalIndicator',
'PrettyGoodOscillator',
'PriceOscillator',
'RSI_EMA',
'RSI_SMA',
'RSI_Safe',
'RateOfChange',
'RateOfChange100',
'ReduceN',
'RelativeMomentumIndex',
'RelativeStrengthIndex',
'Signal',
'SmoothedMovingAverage',
'SmoothedMovingAverageEnvelope',
'SmoothedMovingAverageOscillator',
'StandardDeviation',
'Stochastic',
'StochasticFast',
'StochasticFull',
'SumN',
'TripleExponentialMovingAverage',
'TripleExponentialMovingAverageEnvelope',
'TripleExponentialMovingAverageOscillator',
'Trix',
'TrixSignal',
'TrueHigh',
'TrueLow',
'TrueRange',
'TrueStrengthIndicator',
'UltimateOscillator',
'UpDay',
'UpDayBool',
'UpMove',
'Vortex',
'WeightedAverage',
'WeightedMovingAverage',
'WeightedMovingAverageEnvelope',
'WeightedMovingAverageOscillator',
'WilliamsAD',
'WilliamsR',
'ZeroLagExponentialMovingAverage',
'ZeroLagExponentialMovingAverageEnvelope',
'ZeroLagExponentialMovingAverageOscillator',
'ZeroLagIndicator',
'ZeroLagIndicatorEnvelope',
'ZeroLagIndicatorOscillator',
'haDelta'])
这里把指标分得非常的细致,实际上源码里是按组进行分类的,比如Cross的一个py文件里就包含了 'CrossDown', 'CrossOver', 'CrossUp' 三个指标,又比如RSI一个文件里包含了'UpDay','DownDay','UpDayBool','DownDayBool','RelativeStrengthIndex','RSI_Safe','RSI_SMA','RSI_EMA' 八个指标。所以我们虽然以这里的字母排列顺序进行实践,但实践中还要依据源码把相关联的几个指标放在一起进行学习。
02_内置指标A系列
000_A系列主要指标
'AccelerationDecelerationOscillator', # AccDecOsc系列
'AwesomeOscillator',
'AdaptiveMovingAverage', # KAMA系列
'AdaptiveMovingAverageEnvelope',
'AdaptiveMovingAverageOscillator',
'AroonDown', # Arron系列
'AroonOscillator',
'AroonUp', 'AroonUpDown',
'AroonUpDownOscillator',
'AverageDirectionalMovementIndex', # ADI(属于DMI)
'AverageDirectionalMovementIndexRating',# ADIR(属于DMI)
'AllN', 'Accum', 'AnyN', 'ApplyN', 'Average', 'AverageTrueRange', # 其他
将A开头的18个指标按组分5个部分,分别是AccDecOsc,KAMA, Arron, DMI中的ADI/ADIR以及其他。由于ADI/ADIR是属于DMI的,这个放到D开头的指标再去详细说明,于是A系列的主要指标是3个:
- 加减速度振荡器指标
- 考夫曼自适应均线
- 阿隆指标
001_AccDecOsc系列
A_简介与公式
A开头的系列,第1个是AccDecOsc,中文名加速度/减速度振荡器,官方文档有指标说明的链接,可以跳转过去进行学习,或者直接交给AI进行翻译和总结即可。
- Accelerator Oscillator | AC Indicator | Acceleration/Deceleration Oscillator | IFCM
加速器振荡器(AC Indicator - Accelerator Oscillator)
加速器振荡器是一种衡量当前市场驱动力加速度或减速度的指标。
该指标的工作原理基于其创建者Bill Williams的理论,即在价格运动方向变化之前,其变化的动量应该下降。
测试加速度/减速度振荡器的实际应用
加速度/减速度振荡器是一种技术分析工具,可以帮助您更有效地进行交易。
如何使用加速器振荡器
加速器振荡器是一个围绕中位数0.00(零)水平波动的指标,这对应于市场驱动力的加速度相对平衡。
正值表明牛市趋势正在增强,而负值可能被视为熊市趋势的发展。
AC指标在市场实际趋势反转之前改变其方向,因此它作为可能的趋势方向变化的早期警告信号。
要随着市场驱动力进入市场,需要观察值和颜色。
连续两个高于零水平的柱状图建议进入多头市场。
至少两个低于零水平的色柱状图可能被视为做空的指令。
加速器振荡器公式(计算)
在加速器振荡器公式中,AC条形图是驱动力条形图的5/34值与5周期简单移动平均值之间的差值,从该条形图中取出。
AO = SMA(中位数价格, 5) - SMA(中位数价格, 34)
AC = AO - SMA(AO, 5)
加速器振荡器指标被计算为Awesome Oscillator(AO)与其5周期平均值之间的差值。
外汇指标常见问题解答(FAQ
由AI给出的解释可见,加速度振荡器指标是用于外汇市场的一个常见指标,我们可以从参考网页上的图可知这个示意图用的是欧元兑美元的汇率,网页上给出的买点是连续2根绿柱(国内的绿涨红跌)站上零轴,而卖点是连续2根红柱在零轴之下。
然后来看backtrader的源码公式,
class AccelerationDecelerationOscillator(bt.Indicator):
'''
Formula:
- AcdDecOsc = AwesomeOscillator - SMA(AwesomeOscillator, period)
'''
lines = ('accde', )
params = ( ('period', 5),
('movav', MovAv.SMA), )
def __init__(self):
ao = AwesomeOscillator()
self.l.accde = ao - self.p.movav(ao, period=self.p.period)
super(AccelerationDecelerationOscillator, self).__init__()
class AwesomeOscillator(bt.Indicator):
'''
Formula:
- median price = (high + low) / 2
- AO = SMA(median price, 5)- SMA(median price, 34)
'''
lines = ('ao',)
params = ( ('fast', 5),
('slow', 34),
('movav', MovAv.SMA), )
def __init__(self):
median_price = (self.data.high + self.data.low) / 2.0
sma1 = self.p.movav(median_price, period=self.p.fast)
sma2 = self.p.movav(median_price, period=self.p.slow)
self.l.ao = sma1 - sma2
super(AwesomeOscillator, self).__init__()
这个公式由2个指标组成,先是调用AwesomeOscillator(AO)
- 计算(H+L)/2即K线的平均值;
- 然后以这个平均值做双均线,默认快线为5,慢线为34,
- 最终AO=快线-慢线
然后回到AC中来做AO - MA(AO,5)的值。逻辑上很简单,在股票软件中也可以快速实现
MEDIAN:=(H+L)/2;
SMA5:=MA(MEDIAN,M1),COLORRED,LINETHICK2;
SMA34:=MA(MEDIAN,M2)COLORBLUE,LINETHICK2;
AO:=SMA5-SMA34;
AC:AO-MA(AO,5);
B_公式拓展
在整个公式中,我们看到
- 这里用的是K线平均数值而不是收盘价close
- 有快线和慢线(short, long)
- 中间变量AO是快线减去慢线
- 再对中间变量AO做移动平均
这跟MACD的逻辑几乎一样了,不同的是MACD使用的EMA,另外最后的macd为画线需要乘上了2,其他也就是默认均线参数的不同,这里是(5,34),而MACD默认是(12,26),如果我们把MACD代码的这几个不同点改写如下:
//MACD
SHORT:=12;
LONG:=26;
MID:=9;
DIF:EMA(CLOSE,SHORT)-EMA(CLOSE,LONG);
DEA:EMA(DIF,MID);
MACD:(DIF-DEA)*2,COLORSTICK;
//改写
M1:=5;
M2:=34;
DIF:=MA(CLOSE,M1)-MA(CLOSE,M2); //EMA改MA,参数改为5,34
DEA:=MA(DIF,5); //EMA改MA,参数改为5
MACD2:(DIF-DEA),COLORSTICK; // 不乘2
然后,把AC的图与原MACD放在一起进行比较,如图
- ACCDEOSC与MACD它们的colorstick的趋势也几乎是一致的,即使一个用了MA的5,34,而另一个用了EMA的12,26,仍能看到它们极其相似。
- 我们看到光标位置,MACD金叉的同时,AC的线也恰好上穿0轴,前三个红色的比较明显的柱状线,基本在上穿0轴前面都是MACD金叉。
- MACD的图上还显示了DIF和DEA,其实就分别对应了AO和MA(AO,5)只是这两个在图上不显示而已,而MACD的柱线是(DIF-DEA)*2,就相当于[AO-MA(AO,5)]*2了。
C_回测策略与统计
根据上面的公式拓展分析,加速度振荡器指标与MACD会比较接近,因此做了这两个策略的回测评价对比,对自选股中的22支股票进行了回测,最后的评价数据如图
最后期末权益平均值MACD策略为100584.16,而加速度振荡器策略是96855略少一些,从平均MAR率来看,MACD是0.08对比AccDecOSC的-0.11也是MACD略好一些,而从总交易次数看,回测以2年为总时长,MACD总交易次数平均值为29次,而AccDecOSC的总交易平均值为46次,由此可见加速度振荡器策略的灵敏度非常的高,差不多接近了KDJ的(14,3,3)的交易频次。
D_公式买卖点的讨论
上面的买卖点使用的是AC线上穿0轴和下穿0轴,而根据说明页上的买点应该在连续2次站上0轴的位置,这样的话理论分析它就会比上穿0轴晚至少1根K线,一般的情况下买入晚卖出晚收益就会减少,这张图的上面是穿零轴的,下面是2根连续站上零轴的,两者是交易总次数是相当的,的确是下面的收益会差一些。
于是我们再往极端的方向上走一走,先忽略站上零轴这个条件,只要满足连续2根向上就买入,这个策略我们命名为加速度振荡器策略3,它的buy/sell代码如下
if not self.position: # 没有持仓 才会进入
# 使用2根向上的位置买入
if self.AC[-1]>self.AC[-2] and self.AC[0]> self.AC[-1]:
self.order = self.buy() # 执行买入
else:
if self.AC[-1]<self.AC[-2] and self.AC[0]< self.AC[-1]:
self.order = self.sell() # 执行卖出
然后,我们对基准,MACD,双均线,BOLL,加速度1,加速度3都进行回测,得到.csv文件;再使用pandas读取文件来检查一些我们认为重要的评价指标,就得到如下结果
- 极端的加速度策略3,在某些股票上表现很强,如国芳收益率在15%以上,但大多数的股票表现就不怎么样了
- 极端的策略3,其交易总次数已经从MACD的平均29次飙升到65次
- 一般而言,布林线策略是胜率比较高的,但它的收益并不高,并且有些股票不适用
- 对于连续下跌行情的股票,双均线往往是亏钱最少的那个(例如旷达和美锦,美锦基准下跌2.3w,而双均线只亏了10.9块钱)
E_小结
从指标的参数网页上,我们看到它的示意图是以外汇做标的,也就是这个指标恐怕是为期货和外汇制作的。 通过分析,对比MACD的计算以及在股票上的回测结果数据统计,加速度振荡器公式过于灵敏了, 这种指标可能适合超短线操作。 或许这个指标在日内超短交易中有它的优势,但对于日线,我觉得只做参考吧。
002_KAMA系列
参考文档
- 免费的通达信公式版考夫曼自适应均线 (360doc.com)
- 自适应均线策略-CSDN博客
A_简介与公式
AdaptiveMovingAverage系列,其实就是KAMA(考夫曼自适应均线)
Kaufman的自适应移动平均线(KAMA)是一种自适应移动平均线指标,它可以根据市场波动程度自动调整移动平均线的参数。
这个指标公式并不困难,但开始理解很困难!还是先看源码
from .kama import *
# -----
class AdaptiveMovingAverage(MovingAverageBase):
'''
Formula:
- direction = close - close_period
- volatility = sumN(abs(close - close_n), period)
- effiency_ratio = abs(direction / volatility)
- fast = 2 / (fast_period + 1)
- slow = 2 / (slow_period + 1)
- smfactor = squared(efficienty_ratio * (fast - slow) + slow)
- smfactor1 = 1.0 - smfactor
- The initial seed value is a SimpleMovingAverage
'''
alias = ('KAMA', 'MovingAverageAdaptive',)
lines = ('kama',)
params = (('fast', 2), ('slow', 30))
def __init__(self):
direction = self.data - self.data(-self.p.period)
volatility = SumN(abs(self.data - self.data(-1)), period=self.p.period)
er = abs(direction / volatility) # efficiency ratio
fast = 2.0 / (self.p.fast + 1.0) # fast ema smoothing factor
slow = 2.0 / (self.p.slow + 1.0) # slow ema smoothing factor
sc = pow((er * (fast - slow)) + slow, 2) # scalable constant
self.lines[0] = ExponentialSmoothingDynamic(self.data,
period=self.p.period,
alpha=sc)
super(AdaptiveMovingAverage, self).__init__()
我们还是先把这段代码送到AI去解析
这段代码定义了一个名为
AdaptiveMovingAverage
的类,它继承自MovingAverageBase
类。这个类实现了一个自适应移动平均线(Kaufman's Adaptive Moving Average,简称 KAMA),这是一种根据市场趋势和波动性动态调整平滑因子的移动平均线。下面是这段代码的逐行解析:
alias = ('KAMA', 'MovingAverageAdaptive',)
定义了这个指标的别名,可以在Backtrader中通过这些别名来引用它。
params = (('fast', 2), ('slow', 30))
定义了两个参数fast
和slow
,分别用于指定快速和慢速EMA平滑因子的周期,默认值分别为2和30。
direction = self.data - self.data(-self.p.period)
计算市场方向,即当前数据点与周期前的数据点的差值。
volatility = SumN(abs(self.data - self.data(-1)), period=self.p.period)
计算市场波动性,即周期内价格与前一天价格差的绝对值的累加。
er = abs(direction / volatility)
计算效率比率,即市场方向与波动性的比值。
fast = 2.0 / (self.p.fast + 1.0)
计算快速EMA平滑因子。
slow = 2.0 / (self.p.slow + 1.0)
计算慢速EMA平滑因子。
sc = pow((er * (fast - slow)) + slow, 2)
计算可扩展常数(scalable constant),这是用于计算平滑因子的关键变量。
self.lines[0] = ExponentialSmoothingDynamic(self.data, period=self.p.period, alpha=sc)
使用动态指数平滑方法来计算KAMA值,其中alpha
参数是可扩展常数。这个类的主要作用是根据市场趋势和波动性动态调整平滑因子,从而提供一个更加灵活的移动平均线,以适应市场的变化。这种类型的移动平均线在技术分析中非常有用,因为它可以更好地捕捉趋势变化
接着,我们来看一下公式的定义:
有了这些做基础,我们可以一步一步来进行KAMA的一步步的理解了。
首先是direction (DIR)和volatility (VIT),direction方向表示的是当天收盘价与N天前(先假设默认period=10)的收盘价的差值,即这10天的区间涨跌幅度;而volatility波动性是每天和前一天收盘价的差值的绝对值累加。打个比方,10天前收盘为10块钱,然后涨一天跌一天都是0.5块,到了第10天,区间涨跌幅度为 0,但波动幅度是0.5*10 = 5块;此时就可以计算ER(efficiency rate)效率比率 = DIR/VIT = 0。如果10天连涨,那么区间涨幅也是5块,则ER = 5/5 = 1即效率比率为1。
从上面的一系列计算,可以看到ER在单边上涨或下跌的情况下,其ER越接近1,而波动越多导致收盘价与10天前收盘价相差不大时,ER接近于0。
然后再看计算可扩展常数sc,在参数fast和slow默认为2和30的情况下,计算 fast = 2/3 = 0.667 ,以及 slow = 2/31 = 0.0645 是2个固定值,从而sc就变成了 (ER*0.67 + 0.0645)^2,对于这个sc而言,还是跟随前面计算的ER而变化,即区间涨跌比较大ER接近1,sc.max = (1*0.67+0.0645)^2 = 0.44,而区间涨跌比较小ER设定为0.01时,sc.min = 0.005。
最后再使用动态指数平滑方法来计算AMA的值,这里又用到上一节像EMA那样当前K线前一天的值要用来做计算的情况,上面公式中AMAValue[1]就代表前一天的AMAValue。而需要的alpha就是刚刚计算的sc的值。
class ExponentialSmoothingDynamic(ExponentialSmoothing):
'''
Averages a given data over a period using exponential smoothing
Formula:
- av = prev * (1 - alpha) + data * alpha
'''
alias = ('ExpSmoothingDynamic',)
def __init__(self):
super(ExponentialSmoothingDynamic, self).__init__()
minperioddiff = max(0, self.alpha._minperiod - self.p.period)
self.lines[0].incminperiod(minperioddiff)
def next(self):
self.line[0] = \
self.line[-1] * self.alpha1[0] + self.data[0] * self.alpha[0]
#---------------
self.alpha1 = 1.0 - self.alpha
因此,如果alpha(sc)的值接近1,也就是涨跌幅度比较大的时候,sc*当天的收盘价 + (1-sc)*昨天的AMA就会受今天的收盘价影响大,就会有比较大的AMA的值变动,否则就是受今天的收盘价影响小且AMA的值变动非常小。
B_公式应用与拓展
KAMA是自适应移动平均线,也属于MA系列,因此只要添加了这个指标就会在主图上绘制出来,首先我们把指标先init出来
class KAMA1(BaseSt):
params = (
('stra_name','KAMA策略'),
('p1',5),
('fast',2),
('slow',30),
('tradeCnt',1),
('sucessCnt',0),)
def __init__(self):
self.order = None
self.kama1 = bt.indicators.KAMA(self.data,period=self.p.p1)
接着,买入与卖出的判断,从单均线的指标上看可以有几种buy/sell的判定方法,第1种是KAMA公式中根据昨天的价格与今天的比较,价格变化变为上涨为买点,价格变化变为下跌为卖点;第2种简单的用收盘价与KAMA线的Cross来判断。
self.lines[0] = ExponentialSmoothingDynamic(self.data,
period=self.p.period,
alpha=sc)
因此,我们把2个策略都做出来,然后进行回测比较
# 第1种
def __init__(self):
self.order = None
self.kama1 = bt.indicators.KAMA(self.data,period=self.p.p1)
def next(self):
if self.order: # 检查是否有指令等待执行
return
goldcrs = (self.kama1[0] > self.kama1[-1]) & (self.kama1[-1] < self.kama1[-2])
deadcrs = (self.kama1[0] < self.kama1[-1]) & (self.kama1[-1] > self.kama1[-2])
if not self.position: # 没有持仓 才会进入
if goldcrs:
self.order = self.buy() # 执行买入
else:
if deadcrs:
self.order = self.sell() # 执行卖出
# 第2种
def __init__(self):
self.order = None
self.kama1 = bt.indicators.KAMA(self.data,period=self.p.p1)
self.crs = bt.indicators.CrossOver( self.data.close,self.kama1)
def next(self):
if self.order: # 检查是否有指令等待执行
return
if not self.position: # 没有持仓 才会进入
if self.crs>0:
self.order = self.buy() # 执行买入
else:
if self.crs<0:
self.order = self.sell() # 执行卖出
多支股票回测结果统计如下:
大多数股票使用上面2种买入/卖出完全是一样的结局,只有少数几支股票会有一点点的差别,但从胜率和盈亏比等各个指标来看几乎没有区别,因此我们就可认为这两个buy/sell是等效的,直接用第一个策略就可以了。
C_反向操作的情况对比
在实践的过程中,在cross输入时有一次把两个参数(close,kama1)的次序写反了,但有趣的是居然得到了一个胜率相当高的结果。
# 正向
策略为 KAMA策略2 , 期末总资金 114721.63 盈利为 14721.63 总共交易次数为 28 ,交易成功率为 25.0%
# 反向
策略为 KAMA反向 , 期末总资金 106240.32 盈利为 6240.32 总共交易次数为 17 ,交易成功率为 88.2%
从这支股票的情况来分析,反向做即收盘价下跌破KAMA线产生买点买入,等2~3天涨回来,特别是突破kama的阳线会比较长,于是在收盘价卖出就可能得到一个超短的"超跌反抽"盈利。这么看起来超跌反抽或反弹的盈利概率是比较大的,这个也可能恰好遇到了所谓的洗盘。但是一完成反抽就卖出了,所以从Trades的标记看,反向做的胜率虽然高,但每次都只拿到反抽的差价,反而会完美地错过大行情。因此反向做属于典型的多赚小钱,偶尔亏大钱的策略,它可能用在振荡行情中是一个不错的超短线麻雀战法。
而正向的kama,虽然胜率不高,但绝不会错失任何一次的大行情,一旦产生较大的上涨行情,就能获取到不菲的收益。
D_回测与统计与小结
一支股票在某个时间段只能算是特殊情况,多支股票同时回测增加样本数才能接近真实的概率。于是对11支股票做了正向和反向的KAMA策略,结果如下
从数据上看,正向的KAMA策略,其最大亏损基本都控制的很不错,除了国芳以外,其他的都在-4000以内,胜率基本上只有25~35%,但只要是这支股票有较好的行情,其最大盈利就可以很高,比如小商品城的32784以及国芳的24608等,如果运气不好股票一直处于下跌区间,则最大盈利比较低比如一重只有1818等。也就是说,正向KAMA的稳定性相当不错,而且相当于自带止损效果,一旦出现大跌就会被止损。
正向KAMA相当的稳健,但是稳健也就意味着风险小其收益自然也不会非常大,对于一支趋势向上的股票来讲,就是能获取中间一段的收益,它不用于抄底,也不能逃顶,以下面的数据统计来看,1是亏损控制很不错(-28%做到-8%, -19%做到-1%, -25%的做到-3.6%)基本上不会产生大的亏损;2是盈利效率并不高(15.6%做到9.8%, 76%的只做到22.3% , 63%的也只有15%不到)。
名称 策略 最大回撤 胜率 盈亏比 盈亏时间比 净利润 区间涨幅 策略收益
0 广汇能源 KAMA策略2 13.49 25.81 0.72 2.09 -6909.03 -28.38 -8.11
2 长沙银行 KAMA策略2 5.48 33.33 1.77 4.10 9805.33 15.59 9.81
4 华新水泥 KAMA策略2 8.72 26.67 0.94 2.07 -1079.63 -19.45 -1.08
6 小商品城 KAMA策略2 18.33 14.81 1.58 1.06 16679.40 76.01 22.30
8 中国一重 KAMA策略2 16.75 15.15 0.27 0.68 -13173.11 -24.75 -13.17
10 西部矿业 KAMA策略2 12.76 25.93 1.68 2.05 14721.63 63.30 14.72
12 蓝色光标 KAMA策略2 24.61 21.43 0.92 1.25 -3220.05 4.24 -2.79
14 国芳集团 KAMA策略2 10.20 39.13 2.94 2.58 36947.07 -10.81 37.86
16 报喜鸟 KAMA策略2 11.95 34.78 1.13 1.37 2353.06 -4.02 4.64
18 神马股份 KAMA策略2 8.02 28.00 0.71 1.35 -4500.17 -18.86 -4.00
20 保税科技 KAMA策略2 9.92 22.73 0.79 1.96 -3635.04 -24.75 -3.64
再看反向的KAMA策略,恰恰与正向的KAMA相反,其最大盈利基本上都在3000左右,但最大亏损可能很可怕,比如国芳-11528, 报喜鸟-10488,广汇-10444等,特别是在下跌行情中,容易产生严重的亏损,因此如果要使用反向的KAMA做超跌反弹一定要先设置好止损线。不过反向的KAMA策略的胜率真的是高,我们看到上面好几支的胜率都在75%左右,也就是4次能对3次,因此在做好止损的情况下,用KAMA反向赚点小钱还是可以的。
加了止损的统计数据见上表,止损1使用的是时间止损,当前设定买入后7天(超跌反抽)自动卖出,但时间上有很多的不确定性,也许暴跌就是跌了3天20%,到第7天再止损跟3天没大区别,于是又设置了止损2,设置为下跌百分比止损,按照最大盈利在3000左右,3000/50000约6%,盈亏比设置1.5 则-4%止损,实际上价格可能在暴跌的时候破-4%当天直接破了-10%也有可能。所以,根据上表,大部分的股票在设置止损后,其最大亏损大幅降低且策略收益增加,但某些股票可能走了一些特殊的走势,在反向策略胜率比较低的时候加止损没有效果,比如 国芳胜率35%左右,止损收益比不止损还低,保税胜率50%,止损收益也比不止损要低。
以上,KAMA反向只适合部分股票,在振荡行情中做超短线的超跌反弹,此时胜率比较高(75%)左右,可以作为某些混合或综合策略的一个控制因子,但本身直接做策略容易遭遇超级大的跌幅,风险比较大且收益并不高,即使加上止损也并不理想,不建议使用。
E_应用于股票软件
常用的股票软件里没有内置KAMA这样的指标公式,所以我们需要自己在输入公式,根据前面的python的源码,可以很轻松地完成指标公式的编写,从源码
def __init__(self):
direction = self.data - self.data(-self.p.period)
volatility = SumN(abs(self.data - self.data(-1)), period=self.p.period)
er = abs(direction / volatility) # efficiency ratio
fast = 2.0 / (self.p.fast + 1.0) # fast ema smoothing factor
slow = 2.0 / (self.p.slow + 1.0) # slow ema smoothing factor
sc = pow((er * (fast - slow)) + slow, 2) # scalable constant
self.lines[0] = ExponentialSmoothingDynamic(self.data,
period=self.p.period,
alpha=sc)
到指标公式
DIR:=ABS(CLOSE-REF(CLOSE,N));
VIR:=SUM(ABS(CLOSE-REF(CLOSE,1)),N);
ER:=DIR/VIR;
CS:=ER*(2/3-2/31)+2/31;
CQ:=CS*CS;
AMA1:DMA(CLOSE,CQ),COLORGREEN,LINETHICK3;
AMA2:IF(AMA1>REF(AMA1,1),AMA1,DRAWNULL),COLORRED,LINETHICK3; //如果大于前一天值画红线
通过向上画红线,向下画绿线的方式,分出持仓和买入,卖出的位置,然后还可以添加一些箭头和线来观察比较细节的情况,以下图为例,在一段行情中,触发了7组买/卖,根据前面的统计数据,KAMA的胜率约在25%左右,即4次成功1次。
从图上情况分析:
- 在振荡区,多半会以小亏出局;
- 在下跌区,绿线没有买点,所以可以较好的控制亏损
- 在上涨段,往往是由于第一根阳线涨幅比较大而导致计算出来的KAMA向上翻红,这里收盘买进相对于底部而言已经上涨了不少,中段的上涨是能吃到的,但是到顶后向下又回吐了很大一部分利润,所以相比较WAVE指标的波端,KAMA指标在这波上涨中的收益效率只有WAVE的1/3左右。
- 获得的利润似乎与SAR指标的情况比较近似
003_Aroon阿隆系列
- 参考文档
- 阿隆指标_百度百科 (baidu.com)
- 一个“罕见”的因子--Aroon指标 - 知乎 (zhihu.com)
- 阿隆(Aroon)指标策略指南 - 知乎 (zhihu.com)
- 阿隆:必知阿隆指标策略(+ 详细指南) (businessyield.com)
- 阿隆(Aroon)技术指标在量化交易中的应用 | 干货-CSDN博客
- SF02_RE | 阿隆指标与动态出场_策略_跟踪止损_参数设置 (sohu.com)
- 探索那些小众却实用的交易指标(三):阿隆(Aroon)_财经头条 (sina.com.cn)
A_简介与公式
先引用其他文章的介绍
在技术分析中阿隆(Aroon)是一个很独特的技术指标,“Aroon”一词来自梵文,寓意为“黎明曙光”。它不像MA、MACD、KDJ那样广为人所熟悉,它推出的时间更晚,直到1995年才被图莎尔·钱德(Tushar Chande)发明出来,作者还发明了钱德动量摆动指标(CMO)和日内动量指数(IMI)。如果说一个技术指标知道的人越多,使用的人也越多,那么其赚钱能力也越低,那么相对新颖的阿隆指标则恰恰相反,站在这个角度看这是一个不错的选择。
阿隆指标通过计算当前K线距离前最高价和最低价之间的K线数量,来帮助交易者预测价格走势与趋势区域的相对位置关系变化。它有两部分组成,即:阿隆上线(AroonUp)和阿隆下线(AroonDown),这两条线在0~100之间上下移动,虽然命名为上线和下线,但从图表上看并不像BOLL指标那样是真正意义上的上线和下线。
简单理解下来,阿隆指标是通过计算最近1次最高价和最近1次最低价的时间,通过它们之间的关系来预估一定周期内上涨或下跌的概率,应该是计算时间周期类型的指标。
接着先在策略类里把它的指标曲线显示出来,这时需要看一下源码,因为这里有5个用Aroon开头的指标,我们需要知道它们的关系和使用方法。
class _AroonBase(Indicator):
def __init__(self):
if self._up:
hhidx = FindFirstIndexHighest(self.data.high, period=idxperiod)
self.up = (100.0 / self.p.period) * (self.p.period - hhidx)
if self._down:
llidx = FindFirstIndexLowest(self.data.low, period=idxperiod)
self.down = (100.0 / self.p.period) * (self.p.period - llidx)
class AroonUp(_AroonBase):
lines = ('aroonup',)
def __init__(self):
super(AroonUp, self).__init__()
self.lines.aroonup = self.up
class AroonDown(_AroonBase):
lines = ('aroondown',)
def __init__(self):
super(AroonDown, self).__init__()
self.lines.aroondown = self.down
class AroonUpDown(AroonUp, AroonDown):
alias = ('AroonIndicator',)
class AroonOscillator(_AroonBase):
def __init__(self):
super(AroonOscillator, self).__init__()
self.lines.aroonosc = self.up - self.down
class AroonUpDownOscillator(AroonUpDown, AroonOscillator):
alias = ('AroonUpDownOsc',)
部分源码见上面代码区,Aroon.py文件中共有6个class,其中第一个是内部类 _AroonBase,其他5个类(Indicators-Reference列表中)都是基于它产生的,其中
- AroonUp, AroonDown生成了阿隆上线和阿隆下线,在指标应用的时候通过AroonUpDown()完成,在backtrader绘制图中副图上显示这2条线
- AroonOscillator 其实就是 AroonUp - AroonDown,在指标应用的时候通过AroonUpDownOscillator()来实现,副图上会显示3条线
class Aroon1(BaseSt):
params = (
('stra_name','Aroon1'),
('p1',25),
('tradeCnt',1),
('sucessCnt',0),)
def __init__(self):
self.order = None
self.aroon1 = bt.indicators.AroonUpDown(self.data,period=self.p.p1)
self.aroonosc1 = bt.indicators.AroonUpDownOscillator(self.data,period=self.p.p1)
我们在策略类里添加这两种不同的表现方式,输出的副图就会不一样,简版的AroonUpDown就2条线,而*Oscillator会多出一条AroonUp - AroonDown的线,如下图。
B_买卖点策略
根据上面的信息,简版的Aroon只有2条线,因此buy/sell点会根据这2条线的关系来计算设置,而AroonOsc会有第3条线,所以可以用第3条线来调整控制买卖点。
从网上得到的信息,Aroon的使用方法如下几种描述:
(1) 当 AROON_UP 上穿 70,并且 AROON>0,说明上涨趋势形成,产生买入信号;
(2) 当 AROON_DOWN 上穿 70,并且 AROON<0,说明下跌趋势形成,产生卖出信号;
(3) 当 AROON_UP 下穿 50,并且 AROON<0,说明上涨趋势减弱,可能反转下跌,产生卖出信号;
(4) 当 AROON_DOWN 下穿 50,并且 AROON>0,说明下跌趋势减弱,可能反转上涨,产生买入信号。
买入信号:
当AROON_UP上穿70并且AROON > 0时,通常表示上涨趋势的形成,买入。
如果AROON_UP向上穿过AROON_DOWN并继续上升,也是一个买入信号。
卖出信号:
当AROON_DOWN上穿70并且AROON < 0时,通常表示下跌趋势的形成,卖出。
如果AROON_DOWN向下穿过AROON_UP并继续下降,也是一个卖出信号。
趋势减弱信号:
当AROON_UP下穿50并且AROON < 0时,可能表示上涨趋势减弱,可能会反转下跌,这时可以考虑卖出。
相反,当AROON_DOWN下穿50并且AROON > 0时,可能表示下跌趋势减弱,可能会反转上涨,这时可以考虑买入。
当 AroonUp大于AroonDown,并且AroonUp大于50,多头开仓;
当 AroonUp小于AroonDown,或者AroonUp小于50,多头平仓;
当 AroonDown大于AroonUp,并且AroonDown大于50,空头开仓;
当 AroonDown小于AroonUp,或者AroonDown小于50,空头平仓;
不同的说法和逻辑就容易让初遇者无所适从,需要自己一边实践一边梳理。其实,指标已经出来了,如何利用指标找到合适的买卖点本来就是一个需要花时间研究的过程,比如MACD指标传统的就是金叉死叉策略,现在很多人把零轴也作为一个关键参考值等等。
我们在研究指标的策略的时候,需要考虑到我国的股票是不能做空的,而国际上没这个限制,因此把应用于国际股票市场或者期货、外汇市场的指标拿过来用的时候,千万要分清多头与空头。例如MACD指标金叉买入是多头买入,但如果先出现了死叉,国际市场就可以先空头开仓卖出,再来到金叉的时候其实有2个动作,1是空头平仓,2是平仓后还需要多头买入。此时再来看Aroon的四条就会感觉好懂一点了,AroonUp的大于50/70或小于50是多头的开仓和平仓,AroonDown的大于/小于是空头的,那么在我国股票市场,就可以暂时先不考虑空头的那一对策略。而只需要使用AroonUp上穿70且Aroon>0买入和AroonUp下穿50且Aroon<0卖出的这组条件了。
def __init__(self):
self.order = None
self.aroon1 = bt.indicators.AroonUpDown(self.data,period=self.p.p1)
# self.aroonosc1 = bt.indicators.AroonUpDownOscillator(self.data,period=self.p.p1)
self.crsup = bt.indicators.CrossUp(self.aroon1.l.aroonup, 70)
self.crsdn = bt.indicators.CrossDown(self.aroon1.l.aroonup, 50)
def next(self):
if self.order: # 检查是否有指令等待执行
return
if not self.position: # 没有持仓 才会进入
if self.crsup and (self.aroon1.aroonup - self.aroon1.aroondown) >0:
self.order = self.buy() # 执行买入
else:
if self.crsdn and (self.aroon1.aroonup - self.aroon1.aroondown) <0:
self.order = self.sell() # 执行卖出
-------------------------
run_main_plot_ex2 (df_list,Aroon1,0)
--------------------------
策略为 Aroon1 , 期末总资金 127803.47 盈利为 27803.47 总共交易次数为 4 ,交易成功率为 80.0%
最终资产价值: 127803.47
如果使用简版的Aroon,则Aroon=AroonUp - AroonDown需要自己计算和参与判定,语句上会显得有些复杂,因此直接用Oscillator那个指标会方便一些,效果反正是一样的。
从图上看,完成的交易一共4次,第4次买入后价格跳水,盈利达到27803,前面KAMA是14721,显然Aroon交易次数少,成功率高,盈亏比较好。
C_回测与统计
前面已经知道了,单支股票说明不了什么,偶然性因素太高了,还是需要多支股票回测进行统计。下表是11支股票的回测结果评价,与Kama正向策略放在一起进行比较
Aroon策略有着鲜明的特点:
- 交易次数非常少,2年的周期内出手只有10次左右
- 成功率总体较高,但有个别股票一次都没有,即容易受到偶然性影响
- 最大盈利有些会高于Kama,没有Kama的天然自带止损,需要添加止损
- 似乎对于有色,游戏等周期性比较强的股票适用性强
D_应用于股票软件
Aroon指标公式在通达信中作为内置指标公式存在,但要注意公式与Backtrader的并不一致,且只计算得到AroonUp和AroonDown的值,并没有买卖策略以及Aroon的值。
// 股票软件内置Aroon指标
N:=25;
上轨:(N-HHVBARS(H,N))/N*100,COLORRED;
下轨:(N-LLVBARS(H,N))/N*100,COLORGREEN;
与backtrader指标不一致的地方见源码,上轨是一致的,下轨TDX中取的还是H,而backtrader的down用的是low。
if self._up:
hhidx = FindFirstIndexHighest(self.data.high, period=idxperiod) # 取high
self.up = (100.0 / self.p.period) * (self.p.period - hhidx)
if self._down:
llidx = FindFirstIndexLowest(self.data.low, period=idxperiod) # 取low
self.down = (100.0 / self.p.period) * (self.p.period - llidx)
我们还是根据backtrader的交易策略制作TDX的指标公式并画出买卖点如下图,副图1是内置的Aroon指标,仅显示2条线,副图2的Aroon2是更改后的指标。在股票软件里显示可以更容易的放大、缩小以及调整参数等,可以看到当股价波浪式向上运行,AroonUp的值会随着波浪上穿至100,然后在50~100之间波动,会出现多个买点的原因可能就是由于buy/Sell的值设置的不同,中间有20的死区。如果使用50、50的设置,则可以形成逻辑的闭环,不会再产生多出的买点。但很可能回测的收益等就变了。
03_A系列主要指标小结
A开头的18个指标按组分5个部分,分别是AccDecOsc,KAMA, Arron, DMI中的ADI/ADIR以及其他。
这里重点实践了其中的3个,分别是加速度振荡器,KAMA以及AROON三个指标。
加速度振荡器指标多用于期货、外汇市场,灵敏度高,容易触发信号,但似乎对A股优势并不大,这个指标与MACD的逻辑基本一致,使用的是短均线-长均线的差值再进行移动平均值的方式。
KAMA是考夫曼自适应移动平均线,它是根据市场波动程度自动调整移动平均线的参数,KAMA具有较好的稳健性,并自带止损的功能。
AROON阿隆指标是计算极值距离当前的时间差的指标,它在国际股票市场或期货市场有着多头和空头两路操作,到A股只需要应用多头这一路操作即可,阿隆指标交易次数会比较少,在比较极限的情况下(如单边上涨)收益会高于KAMA,但在单边下跌由于取消了空头操作,表现不佳。
总之,指标已经计算得到了,但怎么运用指标去进行买卖点的判断仍是一个复杂的问题,有些时候我们甚至可以尝试反向操作(如在KAMA中回测了反向)或其他奇葩操作,然后通过大量股票回测来统计它的评价指标和数值,从而确认它们是否可用,这就是使用backtrader进行回测的优势所在。某个指标有时恰好在某支股票上有很不错的表现,这是偶然性,大量的回测后可能你会发现这个策略在其他股票上就没有效果......