内置指标F-N
backtrader内置指标从F到N字母开头的主要指标如下:其中有好几个都是属于基本操作符basicops的内容,还有一些hma,mabase的内容。
'FibonacciPivotPoint',
'FindFirstIndex', 'FindFirstIndexHighest', 'FindFirstIndexLowest', #basicops.py
'FindLastIndex', 'FindLastIndexHighest', 'FindLastIndexLowest',
'Highest', 'Lowest',
'HeikinAshi',
'Ichimoku',
'HullMovingAverage', # hma.py
'HullMovingAverageEnvelope',
'HullMovingAverageOscillator',
'HurstExponent', # hurst.py
'KnowSureThing', # # Depends on Momentum # kst.py
'Momentum',
'MomentumOscillator',
'LaguerreFilter', # 拉格朗日RSI
'LaguerreRSI',
'LinePlotterIndicator', # 画Line
'MACD', # MACD
'MACDHisto',
'MeanDeviation', # CCI中用到的平均偏差
'MinusDirectionalIndicator', # DMI中的MDI
'MovingAverageBase', #mabase.py
'MovingAverageSimple', 'MovingAverageSimpleEnvelope', 'MovingAverageSimpleOscillator',
剔除一些指标后,F到N我们主要来看这几个:
- FibonacciPivotPoint
- HeikinAshi
- Ichimoku
- KnowSureThing
- MACD
009_FibonacciPivotPoint
A_术语
FibonacciPivotPoint即斐波那契枢轴点。我一开始怎么都无法get到枢轴点这个词,于是我们要查询一些内容来给出它在自己认知中的定义
Pivot Point 在中文中通常翻译为“枢轴点”。在技术分析中,它用于确定潜在的支撑和阻力水平,帮助交易者识别市场可能的转折点。
"Pivot" 这个词在中文中有多种翻译和解释,具体取决于它的使用上下文。以下是一些常见的翻译:
- 枢轴:在机械或物理结构中,指支撑旋转或转动的部分。
- 支点、中心、关键点、轴心、基准 ...
在金融和交易领域,“Pivot Point”翻译为“枢轴点”而不是“基准点”的原因主要基于历史沿革,功能特性,语言习惯,专业术语的一致性等
枢轴点(Pivot Point)在某些方面与缠论中的中枢概念有相似之处。
就像我当前还是喜欢把position叫做持仓而非“头寸”一样,这里我仍把它理解为中枢。
B_公式与应用
斐波那契枢轴点指标在indicators\pivotpoint.py文件中,并列的有三个指标分别是
- PivotPoint
- FibonacciPivotPoint
- DemarkPivotPoint
简单看一下源码,默认参数 open=False, close=False, lv1=0.382,lv=0.618, lv3=1.0,这三个level很明显是黄金分割的数值。
class FibonacciPivotPoint(Indicator):
lines = ('p', 's1', 's2', 's3', 'r1', 'r2', 'r3')
plotinfo = dict(subplot=False)
params = (
('open', False), # add opening price to the pivot point
('close', False), # use close twice in the calcs
('_autoplot', True), # attempt to plot on real target data
('level1', 0.382),
('level2', 0.618),
('level3', 1.0),
)
def __init__(self):
o = self.data.open
h = self.data.high # current high
l = self.data.low # current high
c = self.data.close # current high
if self.p.close:
self.lines.p = p = (h + l + 2.0 * c) / 4.0
elif self.p.open:
self.lines.p = p = (h + l + c + o) / 4.0
else:
self.lines.p = p = (h + l + c) / 3.0
self.lines.s1 = p - self.p.level1 * (h - l)
self.lines.s2 = p - self.p.level2 * (h - l)
self.lines.s3 = p - self.p.level3 * (h - l)
self.lines.r1 = p + self.p.level1 * (h - l)
self.lines.r2 = p + self.p.level2 * (h - l)
self.lines.r3 = p + self.p.level3 * (h - l)
于是,再学习一下斐波那契与黄金分割的关系:
在技术分析中,斐波那契回调水平(Fibonacci retracement levels)通常是基于黄金分割数(大约0.618)来确定的。
FibonacciPivotPoint
会根据前一天的最高价、最低价和收盘价来计算当天的支撑和阻力水平。这些水平通常是通过将前一天的波动范围乘以斐波那契比率(0.382, 0.618等)来得到的。斐波那契数列是由意大利数学家列昂纳多·斐波那契(Leonardo Fibonacci)在13世纪引入西方数学的,虽然这些数列的概念更早存在于印度数学中。斐波那契数列与黄金分割之间的联系是在后来的数学研究中被发现的,但斐波那契的名字已经成为了这些数列的代名词。
在技术分析领域,“斐波那契”已经成为一种习惯性的术语,用来指代那些基于黄金分割比例的技术工具和方法。比如斐波那契回调(Fibonacci Retracements)、斐波那契扩展(Fibonacci Extensions)、斐波那契扇形(Fibonacci Fans)等都是常用的技术分析工具。
所以,FibonacciPivotPoint
指标就是根据前一天的三个价格的计算值再根据黄金分割的三个水平,计算得到的上方三个压力位(阻力位resistance)以及下方的三个支撑位(support),用以指导今天的股价范围。
示例代码及图形输出如下:
class FibonacciPivotPointStrategy(BaseSt):
params = (
('stra_name','PivotPoint'),
('tradeCnt',1),
('sucessCnt',0),
)
def __init__(self):
self.order = None
self.fibonacci_pivot = bt.indicators.FibonacciPivotPoint(
self.data,_autoplot=False )
-------------------------
由图形可见,这个指标默认会直接把3条Support和3条resistance都直接绘制出来,图线显得密密麻麻,而且是每天的价格都在这几条线之间的,所以它是类似于预估的数值,不产生金叉/死叉等买卖的策略,这个应该可以用于日内交易,需要把周期切换到分钟。这个指标可以放到股票软件中,在backtrader绘图上真的看都看不了。
在移植到股票软件时,要注意一下,当天的3压力3支撑都是基于昨天的K线(high+low+close)计算的,因为当天的三个值要等走完了才能出的来。另外挺有意思的发现就是如果是上涨趋势,始终贴着R3在走,下降趋势就始终贴着S3在走。
010_HeikinAshi
A_简介与公式
我一直以为这是个日本人的名字,结果一查并不是。
Heikin Ashi 并不是指某个日本人的名字,而是这种图表类型名称的直译。在日语中,“平均”(Heikin)和“足”(Ashi)分别代表了“平均值”和“足迹”或“步骤”,在这里可以理解为“数据点”。合在一起指的是这种图表通过计算开盘价、最高价、最低价和收盘价的平均值来展示价格走势。
这种图表类型是由日本交易者设计的,但并不是以某个特定的日本人的名字命名的。它是一种技术分析工具,通过计算特定平均值来平衡和平滑价格数据的图表类型,旨在揭示价格走势的“足迹”或路径。这种图表通过其独特的计算方式,旨在减少价格波动的噪音,更清晰地展示市场趋势。
直接看源码,指标的发明和设计可能是很困难的,但理解起来有的真的很简单,从源码上看,
def __init__(self):
o = self.data.open
h = self.data.high
l = self.data.low
c = self.data.close
self.l.ha_close = ha_close = (o + h + l + c) / 4.0
self.l.ha_open = ha_open = (self.l.ha_open(-1) + ha_close(-1)) / 2.0
self.l.ha_high = bt.Max(h, ha_open, ha_close)
self.l.ha_low = bt.Min(l, ha_open, ha_close)
HeikinAshi把传统的开、高、低、收通过计算,重新定义了ha_close,ha_open,ha_high和ha_low,我们放到示例代码中绘制图形
class HekinAshi_test(BaseSt):
params = (
('stra_name','HekinAshi_test'),
('tradeCnt',1),
('sucessCnt',0),
)
def __init__(self):
HekinAshi_t = bt.indicators.HeikinAshi(self.data)
backtrader会把ha_开、高、低、收都连线得到,由于ha_high是 h和ha_open,ha_close的最大值,一般的情况都是high的值,同理ha_low基本上都是low的值,而ha_open/ha_close就要通过计算得到了,上图中间两条应该就是ha_open和ha_close,但是这个在backtrader的绘图里真的很难去观察,所以还是要移植到股票软件的指标公式里。
B_股票软件中使用
HA_C:=(O+H+L+C)/4.0;
HA_O:=EMA(REF(HA_C,1),2);
HA_H:=MAX(MAX(H,HA_O),HA_C);
HA_L:=MIN(MIN(L,HA_O),HA_C);
DRAWKLINE(HA_H,HA_O,HA_L,HA_C);
B1:=CROSS(C,HA_C);
S1:=CROSS(HA_O,C);
N1:=BARSLAST(B1);
N2:=BARSLAST(S1);
B3:=COUNT(B1,N2)>1;
S3:=COUNT(S1,N1)>1;
DRAWICON(B1 AND NOT(B3),L,7);
DRAWICON(S1 AND NOT(S3),H,8);
然后出来的情况如图所示,HeikinAshi指标能够把跳空缺口以及假阴线等都过滤掉,能够平滑价格波动,减少市场的随机波动对决策的影响,使趋势更加明显,这里简单的使用当收盘价cross这个HA_Close时为买点,而收盘价下穿HA_open时为卖点,从图中看趋势是判断的很清楚的,并且自带成对的买卖点,不会出现不匹配的情况,但存在问题的位置也很明显,例如右数第1个绿圈图,遇到这种跳空下跌的情况,等走完这根K线已经亏损不少了,但我们的买卖策略要到收盘价卖出。不过这种上涨过程中都已经出来红三兵的形态的情况下突然下杀出来个断头铡刀本身就属于小概率特殊事件,应该从策略中的计算中进行剔除。
011_Ichimoku
A_简介与公式
这又是一个日语指标,同上,Ichimoku并不是某个日本人的名字。
Ichimoku(一目均衡表)并不是指某个日本人的名字,而是由两位日本交易者的名字组合而成的术语。这个术语来源于Ichimoku Kinkō Hyō(一目均衡表)的简称,其中:
- Ichimoku(一目)意味着“一眼”或“一览”,指的是通过这个指标可以一目了然地把握市场的整体情况。
- Kinkō(均衡)指的是平衡或均衡,暗示这个指标旨在寻找市场的平衡点。
- Hyō(表)意味着图表或表格。
Ichimoku Kinkō Hyō 由记者和交易者Goichi Hosada在1930年代开发,他结合了另一位交易者Tosuki Ginko的理论。这个指标的设计初衷是为了提供一个全面的市场分析工具,帮助交易者识别趋势、潜在的支撑和阻力水平以及交易信号。
在日语中,“一目均衡表”直译为“一览均衡表”,意指通过这个图表可以一目了然地把握市场的均衡状态和趋势。这个指标通过其独特的计算方式,包括转换线、基准线、延迟线和云图等,为交易者提供了一个综合的市场视角。
Ichimoku Cloud由多个部分组成,包括:
转换线(Tenkan-sen):是最近时间段的高点和低点的平均值。通常使用9个时间段的周期。
基准线(Kijun-sen):是更长时间周期的高点和低点的平均值。通常使用26个时间段的周期。
延迟线(Senkou Span A和B):是转换线和基准线的平均值,但是是之前某个时间周期的值。通常使用52个时间段的周期。
云图(Cloud):由两条延迟线组成,上面一条是Senkou Span B,下面一条是Senkou Span A。
领先线(Chikou Span):是当前时间段的收盘价,但是绘制在之前的某个时间周期之后。通常使用26个时间段的周期。
介绍说的挺厉害的,让我们先在backtrader里绘制一下图线看看:
a
这个指标出来的图形感觉很复杂,有多条线,还有红、绿的色块区间,所以我们还需要通过源码来搞清楚每条线代表的意思。
lines = ('tenkan_sen', 'kijun_sen',
'senkou_span_a', 'senkou_span_b', 'chikou_span',)
params = (
('tenkan', 9),
('kijun', 26),
('senkou', 52),
('senkou_lead', 26), # forward push
('chikou', 26), # backwards push
)
def __init__(self):
hi_tenkan = Highest(self.data.high, period=self.p.tenkan)
lo_tenkan = Lowest(self.data.low, period=self.p.tenkan)
self.l.tenkan_sen = (hi_tenkan + lo_tenkan) / 2.0
hi_kijun = Highest(self.data.high, period=self.p.kijun)
lo_kijun = Lowest(self.data.low, period=self.p.kijun)
self.l.kijun_sen = (hi_kijun + lo_kijun) / 2.0
senkou_span_a = (self.l.tenkan_sen + self.l.kijun_sen) / 2.0
self.l.senkou_span_a = senkou_span_a(-self.p.senkou_lead)
hi_senkou = Highest(self.data.high, period=self.p.senkou)
lo_senkou = Lowest(self.data.low, period=self.p.senkou)
senkou_span_b = (hi_senkou + lo_senkou) / 2.0
self.l.senkou_span_b = senkou_span_b(-self.p.senkou_lead)
self.l.chikou_span = self.data.close(self.p.chikou)
这里的参数都用了日语的发音的词,查了一下,发现这几个发音跟中文也很像,天间TianJian - Tenkan,基准Jizhun- Kijun , 先后xianhou - Senkou。
在日语中,“線”(sen)意味着“线”。
- Tenkan-sen(天間線):转换线,表示短期价格变动的趋势线。
- Kijun-sen(基線):基准线,表示中期价格变动的趋势线。
- Senkou Span(先後線):延迟线,由两条线组成,用于预测未来价格趋势。
Chikou(地獄):“地獄”在日语中意味着“地狱”,这里用作隐喻,表示价格落后于市场的步伐。领先线(Chikou Span)是当前周期的收盘价,但是绘制在之前的一定时间周期之后
B_指标的理解与股票软件中使用
观察源码,首先是计算转换线和基准线,其实就是短周期(默认9)和中周期(默认26)的最高价与最低价的平均值连线,而延迟线有2根,a和b,其中b就是长周期(默认52)的最高价和最低价的平均值连线,而a是短周期平均线和中周期平均线再做平均。
放到股票软件中来进行学习(其实TDX是有一目均衡表这个指标的),可以一步一步的显示计算得到的图线。见图上半部分,红色为转换线(短周期平均值连线),蓝色为基准线(中周期平均值连线),绿色为延迟线A(短+中)/2,灰色为延迟线B(长周期平均值连线)。
如果不去看A和B,那么转换线和基准线的关系就像是双均线,是可以用金叉买死叉卖的策略的,但ICHIMOKU并不只是双均线,延迟线A又是均线再做平均值,即均线二次处理。另外通过A与B的关系,绘制了栅格线即所谓的云图(图的下半部分),这里也可以用带状线来示意显示,但是带状线会遮住云图中的K线。
从ICHIMOKU指标的多条线与云图来看,这个指标并不是简单的单条件策略,其本身就有很多的混合策略在里面:
- 如果只看收盘价与转换线(快线)的关系,相当于是单均线策略,可以用收盘价上穿转换线买入,下穿转换线卖出的策略。
- 如果只看转换线和基准线的关系,则双均线策略也可以使用。
- 云图的上下线有着支撑或压力的作用,比如12月到1月的中间就是触碰云图就反向下运行了。
- 云图与收盘价或转换线之间空间还可以指示乖离率,比如11月份前云图向上、股价向下形成增大的空间,即相当于乖离过大就会把股价拉回
- 云图如果上限和下限之间空间比较宽,则还有箱体的作用,股价会在云图内运行
- 穿过云图后有相当于金叉/死叉的效果,下穿后继续向下,上穿后继续向上运行......
混合策略就会比较复杂,当前重点是快速完成内置指标的大致印象,所以暂时不对混合策略进行编写,如果只简单使用了单均线或双均线或穿越云图的金叉/死叉策略则没有一目均衡的意义,所以这个指标我们暂时不进行回测了。
这个指标TDX里内置就有,但默认参数不太一样,分别是7,22,44,通过这个指标可以比较清楚的知道当前股价是在上行区间还是下行区间等。由于线比较多,就很容易出现支撑或压力不在这条就在另外一条上的情况,图上看着有很大的参考价值,但在有效的组合策略未实现之前,也容易被乱用,不尊重前置条件和限制条件,反而会产生错大失误。或许这也是股票软件里的指标不配策略或者只配经典的简单策略的原因。
012_KnowSureThing
KnowSureThing(KST)按单词翻译是:知道 肯定/当然 事情,它的中文命名是“确然指标”,个人理解为:我知道这事情肯定要发生。
Know Sure Thing(KST)指标的中文命名是“确然指标”。这个指标是由马丁·普林格(Martin Pring)开发的。KST是一个基于动量(Momentum)的指标,它通过结合不同周期的移动平均线(MA)来衡量价格的动量。KST指标的核心思想是通过计算价格在不同时间周期内的变化率(Rate-of-Change, ROC),并将其加权平均,以捕捉价格趋势的动量和变化。这种基于动量的计算方式使得KST指标能够反映市场在不同时间框架内的力量和趋势持续性,从而为交易决策提供依据。
A_前置指标 Momentum
Backtrader 的内置指标
Momentum
是一个衡量价格变化的动量指标,它通过计算当前价格与特定周期前的价格之间的差异来工作。其核心思想是捕捉价格在一定时间周期内的变化速度,从而为交易决策提供参考。
由动量计算我们可以对比一下我们熟悉的路程、时间与速度的关系,速度=路程/时间,或者速度是距离的一阶导数,而加速度又是速度的一阶层数,是距离的2阶导数。
动量指标(Momentum Indicator)通常用来衡量价格在特定时间周期内的变化速度。动量指标与价格的一阶导数(即价格随时间的变化率)在概念上有相似之处。
在个人理解上,可以把股票的价格看作是速度,而动量指标相当于加速度变化,这样可以比较轻松地理解:当动量指标正向增加,即踩油门加速;如果动量变为0即松开油门虽然加速度没有了,但股价会维持一定的速度继续向上;而当动量指标变为负,即踩刹车减速,从踩了刹车速度会下降但车子停下来还要继续惯性冲出一段来理解股价在动量指标变为负后仍可能继续上涨。
动量指标的计算方式可以表示为:
动量 = 当前价格−N周期前的价格
这里的“N周期”可以是任何时间单位,比如日、周、月等。动量指标的值可以是正的也可以是负的,正值通常表示价格上涨的动量,而负值则表示价格下跌的动量。
动量指标的关键点在于:
- 趋势确认:动量指标可以帮助确认趋势的存在。如果价格和动量指标都上升,那么趋势可能是上升的;如果两者都下降,则趋势可能是下降的。
- 趋势强度:动量指标的绝对值大小可以反映趋势的强度。动量指标的值越大,表明价格变化的速度越快,趋势的强度也越大。
- 趋势反转信号:当动量指标与价格之间出现背离时,可能预示着趋势的反转。例如,如果价格创新高而动量指标未能创新高,这可能是趋势即将反转的信号。
再看源码,Momentum指标位于indicators\Momentum.py中,而这个文件中有4个类,分别是
- Momentum
- MomentumOscillator
- RateOfChange
- RateOfChange100
这4个类都是动量相关的指标,可以一起进行学习,默认周期参数的值为12,
class Momentum(Indicator):
def __init__(self):
self.l.momentum = self.data - self.data(-self.p.period)
class MomentumOscillator(Indicator):
def __init__(self):
self.l.momosc = 100.0 * (self.data / self.data(-self.p.period))
class RateOfChange(Indicator):
def __init__(self):
dperiod = self.data(-self.p.period)
self.l.roc = (self.data - dperiod) / dperiod
class RateOfChange100(Indicator):
def __init__(self):
self.l.roc100 = 100.0 * ROC(self.data, period=self.p.period)
由源码可知:
- Momentum就是当天收盘价减去12天前的收盘价
- MomentumOsc就是用当天收盘价除以12天前再乘以100,得到当前收盘价与12天前的百分比关系
- ROC是先计算Momentum即价格差,再用当前收盘价减去价格差后除以价格差
- ROC100就是ROC的百分比表现形式
Momentum就是差值(不同的股票价格不同,差异很大,无法直接使用),而ROC100就是差值相对于前一个价格的百分比,ROC是以小数表示的中间变量,通过把Momentum无量纲化(归一化),将数据转换缩放到一个特定的范围内,例如[-1,1],就实现了所有股票都可以应用的指标。
这就是为什么KnowSureThing指标源码中是"depends on Momentum",而简介中不说Momentum而是说计算价格在不同时间周期内的变化率(Rate-of-Change, ROC)的原因。
B_在股票软件中MTM和ROC
MomenTuM →MTM,这样就明白MTM其实就是Momentum指标的缩写形式了。股票软件中内置有MTM和ROC指标,它们归属于“超买超卖型”。
看一下它们的指标公式,从公式上与backtrader中的计算公式是一致的。
N=12;
M=6;
MTM:CLOSE-REF(CLOSE,MIN(BARSCOUNT(C),N));
MTMMA:MA(MTM,M);
NN:=MIN(BARSCOUNT(C),N);
ROC:100*(CLOSE-REF(CLOSE,NN))/REF(CLOSE,NN);
MAROC:MA(ROC,M);
在股票软件中,给MTM和ROC都添加了一条6日的平均线。我们简单的在这两个指标中添加一下买卖策略,由于MTM是差值,不同的股票价格结果不一致,使用MTM的话只能采用MTM与MTMMA的交叉做策略;而ROC是百分比,可应用于各个股票价格,所以可以根据数值做更多的策略,比如上穿或下穿零轴(我们知道加速度>0才会加速,<0就会减速),简单的策略如图
由图可知,MTM的金叉死叉策略触发率太高了,对比出来ROC的穿0轴策略就显得好上一些。考虑到车速还与阻力总和有关系,比如说同样10%油门(假设对应成交量条件)平路上会一直加速,但上坡时车速还一直往下掉必须增大油门,所以单纯的ROC是有条件考虑不到的,还需要分段以及分条件进行调整,这个以后再说。
C_股票软件中显示收益率
Backtrader回测中的很多知识和经验也可以反过来用到股票软件的指标公式里。比如前面2节讲到的出现多个连续买点的情况怎么去除等,这里我们尝试着在图上显示出某个指标策略的收益率。
想法很简单:
- 以上穿0轴为买点,记录周期数(BARSLAST),以下穿0轴为卖点同样记录周期数;
- 在卖点位置计算卖点收盘价与买点周期数位置的收盘价的正负百分比即收益率;
- 累加收益率
B1:=CROSS(MAROC,0);
S1:=CROSS(0,MAROC);
DRAWICON(B1,ROC,7); //绘制B
DRAWICON(S1,ROC,8); //绘制S
N1:=BARSLAST(B1);
N2:=BARSLAST(S1);
R2:IF(S1,(C-REF(C,N1))/REF(C,N1)*100.0,0),COLORRED;
DRAWTEXT(S1,R2,VAR2STR(R2,2));
收益率:SUM(R2,252),COLORGREEN,LINETHICK3;
DRAWTEXT(S1,收益率-0.5,VAR2STR(收益率,2));
结果如图所示,这样就可以把简单策略的收益率直接显示在图上了,对于多条件或分段等复杂策略的研究尝试,或是对参数的调节也可以直接在股票软件中先粗略的运算了,效率提高了不少。
通过观察,明显的在上升段收益率大多数都是增加,但在下降段每多一次交易收益率都会下降,这样就很快速的把ROC的应用需要先确认是上升段还是下降段的补充条件得到了。
D_KST的计算公式
先看一下KST指标的计算方法:
KST指标的计算方法如下:
- 首先计算不同周期的ROC值,通常是通过当前价格与过去某个时间周期的价格之差,然后除以过去价格来计算得出。
- 接着,对每个ROC值计算其对应的移动平均线(SMA),以平滑数据并减少短期波动的影响。
- 然后,将这些平滑后的ROC值按照一定的权重相加,得到KST值。通常,较短周期的ROC值会有较小的权重,而较长周期的ROC值会有较大的权重。
- 最后,计算KST值的移动平均线作为信号线,用于判断KST指标的交叉点,从而产生交易信号。
KST指标之所以基于动量,是因为它关注的是价格变化的速度和方向,这是动量指标的典型特征。动量指标通常用于识别市场趋势的强度和可能的转折点。通过结合不同时间周期的动量,KST指标能够提供一个更全面的市场视角,帮助交易者识别和确认趋势,以及潜在的趋势反转点。
在实际应用中,当KST指标线穿越其信号线时,可能会产生买入或卖出的信号。此外,KST指标与价格之间的背离也可能预示着趋势的减弱或反转。由于KST指标结合了多个时间周期的动量,它能够减少短期市场的噪音,提供更为可靠的交易信号。
接着,我们看源码:
class KnowSureThing(bt.Indicator):
lines = ('kst', 'signal',)
params = (
('rp1', 10), ('rp2', 15), ('rp3', 20), ('rp4', 30),
('rma1', 10), ('rma2', 10), ('rma3', 10), ('rma4', 10),
('rsignal', 9),
('rfactors', [1.0, 2.0, 3.0, 4.0]),
('_rmovav', SMA),
('_smovav', SMA),
)
def __init__(self):
rcma1 = self.p._rmovav(ROC100(period=self.p.rp1), period=self.p.rma1)
rcma2 = self.p._rmovav(ROC100(period=self.p.rp2), period=self.p.rma2)
rcma3 = self.p._rmovav(ROC100(period=self.p.rp3), period=self.p.rma3)
rcma4 = self.p._rmovav(ROC100(period=self.p.rp4), period=self.p.rma4)
self.l.kst = sum([rfi * rci for rfi, rci in
zip(self.p.rfactors, [rcma1, rcma2, rcma3, rcma4])])
self.l.signal = self.p._smovav(self.l.kst, period=self.p.rsignal)
通过源码和上面的计算公式,我们能比较清楚的知道KST做了什么:分别计算10,15,20,30为周期的ROC百分比,然后在乘上权重因子1,2,3,4进行累加得到kst,将kst再做9日的平均线得到signal。
E_KST策略回测
根据说明进行策略设置为金叉买死叉卖的经典策略。
在实际应用中,当KST指标线穿越其信号线时,可能会产生买入或卖出的信号。
此外,KST指标与价格之间的背离也可能预示着趋势的减弱或反转。
class St_kst_01(BaseSt):
params = (
('stra_name','KnowSureThing策略'),
('tradeCnt',1),
('sucessCnt',0),)
def __init__(self):
self.order = None
kst1 = bt.indicators.KST(self.data)
self.crsup = bt.indicators.CrossUp(kst1.l.kst,kst1.l.signal )
self.crsdn = bt.indicators.CrossDown(kst1.l.kst,kst1.l.signal)
def next(self):
if self.order: # 检查是否有指令等待执行
return
if not self.position: # 没有持仓 才会进入
if self.crsup:
self.order = self.buy() # 执行买入
else:
if self.crsdn:
self.order = self.sell() # 执行卖出
对11支股票进行回测的结果如下
与KAMA策略对比做个参考,在不进行分段调整的情况下,KST策略出手频率较低,2年20次,平均要1个月左右才出手一次,成功率并不高,在30~50%左右,大多数股票的收益均低于KAMA,也可以看到可能是最大亏损比较高造成的,添加了分段调整后应该会有进步空间。
013_MACD
A_简介与公式
在内置指标A开头那一节中,在讲加速度振荡器指标时,我们就拿MACD与加速度振荡器指标做过对比,它们的逻辑是一致的,只不过一个用了EMA而另一个用了SMA,然后参数设置不一样。
MACD(Moving Average Convergence Divergence,移动平均收敛发散指标)是一种在技术分析中常用的趋势跟踪动量指标,主要用于识别股票价格的动量变化、趋势强度以及潜在的价格反转信号。MACD由以下三个部分组成:
DIF(差离值):DIF是MACD指标的核心,它通过计算两个不同周期的指数移动平均线(EMA)之间的差值来得到。常用的周期组合是12日EMA和26日EMA,DIF计算公式如下: DIF=EMA12−EMA26
DEA(信号线):DEA是DIF的移动平均线,通常采用9日EMA。DEA的计算公式如下: DEA=EMA(DIF,9)
MACD柱(直方图):MACD柱是DIF和DEA之间的差值,它以柱状图的形式表示,可以直观地反映DIF和DEA之间的距离。MACD柱的计算公式如下: MACD柱=DIF−DEA
MACD指标的应用主要基于以下几个方面:
趋势识别:当DIF和DEA都在零线以上,并且DIF在DEA之上时,通常被看作是上升趋势;相反,如果两者都在零线以下,并且DIF在DEA之下,则可能表示下降趋势。
交叉信号:DIF与DEA的交叉通常被视为买入或卖出的信号。当DIF从下方穿越DEA时,称为“金叉”,可能是买入信号;当DIF从上方穿越DEA时,称为“死叉”,可能是卖出信号。
背离信号:当价格创新高(或新低)而MACD指标未能创新高(或新低)时,称为顶背离(或底背离),这可能预示着趋势即将反转。
柱状图变化:MACD柱的高度变化也可以提供交易信号。柱状图的缩短可能表示趋势的减弱,而柱状图的增长则可能表示趋势的加强。
我们把MACD称作“指标之王”,这一称号主要基于以下几个原因:
广泛应用和有效性:MACD是被历史走势检验过的最有效的技术指标之一,也是运用最广泛的指标。
易于理解和使用:MACD指标的计算过程相对简单
影响力强大:许多专业交易员和投资机构都会使用MACD来制定交易策略,使其成为一种影响力强大的技术分析工具。它的顶底背离被认为是非常有效的“抄底逃顶”方法,是趋势理论、波浪理论具体化的重要工具。
可与其他技术指标结合使用:MACD可以与其他技术指标如KDJ、RSI等结合使用,提高预测的准确性。
反映市场趋势和动能变化:MACD指标不仅能显示价格的趋势方向,还能通过柱状图的变化反映市场的动能变化。
提前预警市场趋势的反转:通过观察MACD指标与价格走势的背离情况,能够提前预警市场趋势的反转。
适用于不同市场情况:MACD指标适用于不同的市场情况,包括上涨趋势、下跌趋势以及趋势反转等。
在backtrader中内置之标有MACD和MACDHisto,它们均在indicators\macd.py文件里,我们来学习一下源码
class MACD(Indicator): # 继承自Indicator
def __init__(self):
super(MACD, self).__init__()
me1 = self.p.movav(self.data, period=self.p.period_me1)
me2 = self.p.movav(self.data, period=self.p.period_me2)
self.lines.macd = me1 - me2
self.lines.signal = self.p.movav(self.lines.macd,
period=self.p.period_signal)
class MACDHisto(MACD): # 继承自MACD
plotlines = dict(histo=dict(_method='bar', alpha=0.50, width=1.0))
def __init__(self):
super(MACDHisto, self).__init__()
self.lines.histo = self.lines.macd - self.lines.signal
从源码可知,在backtrader里把MACD拆分成了MACD和MACDHisto两个类,而MACDHisto继承自MACD类,只是计算了macd-signal的值,并以柱状图(_method='bar')的形式绘制出来。
B_自定义MACD类
在前面的章节里,我们已经从基础学习和实践中懂得怎么进行指标的自定义,一般而言可以采用二种方式:
- 直接从Indicator来,完全自己写
- 继承某个指标,只是重写某些内容比如绘图属性等
而MACD类是最佳的实践自定义指标的。内置指标MACD恰好有两个类分别对应上面的两种方式。这里我们可以自己创建一个类来实现MACD指标。
class My_MACD(bt.Indicator): # 注意这里大写I
lines = ('dif', 'dea','macd') # 3个列字段
params = (('period_me1',12), # 三个默认参数的值
('period_me2', 26),
('period_signal', 9),)
plotlines = dict(signal=dict(ls='--'),macd=dict(_method='bar', alpha=0.50, width=1.0))
def __init__(self):
#用EMA生成 12日的ema均线
me1 = bt.indicators.EMA(self.data, period=self.p.period_me1)
#生成慢线 26是的ema均线
me2 = bt.indicators.EMA(self.data, period=self.p.period_me2)
self.l.dif = me1 - me2 # ema12-ema26的值放到列字段 这个就是DIF
# 对DIF进行ema9得到DEA
self.l.dea = bt.indicators.EMA(self.l.dif, period=self.p.period_signal)
self.l.macd = self.l.dif - self.l.dea # DIF - DEA就是macd中的红绿柱
将这个类创建的指标与内置MACDHisto指标放在一起进行对比,可以看到效果是一致的。
C_经典MACD策略与回测
在股票软件中一般都会有MACD专家系统,如下图
打开指标公式得到代码为:
DIFF:=EMA(CLOSE,SHORT) - EMA(CLOSE,LONG);
DEA := EMA(DIFF,M);
MACD := 2*(DIFF-DEA);
ENTERLONG:CROSS(MACD,0);
EXITLONG:CROSS(0,MACD);
这里使用的买点是MACD上穿0,其实就是dif上穿dea,因为MACD = 2*(dif-dea);买点是MACD下穿0,也就是dif下穿dea。
将MACD专家系统的经典策略放到backtrader中进行回测,代码如下
class St_MACD_class(BaseSt):
params = (
('stra_name','经典MACD'),
('mashort',12),
('malong',26),
('tradeCnt',1),
('sucessCnt',0),)
def __init__(self):
self.order = None
self.MACD1 = bt.indicators.MACDHisto(self.data)
self.crs = myCross2(self.MACD1.macd,self.MACD1.signal)
def next(self):
if self.order: # 检查是否有指令等待执行
return
if not self.position: # 没有持仓 才会进入
if self.crs.l.crsup:
self.order = self.buy() # 执行买入
else:
if self.crs.l.crsdn:
self.order = self.sell() # 执行卖出
一次性对30支股票进行了回测,统计结果如下表显示,MACD与KST策略相比,某些股票会有相对较好的收益,MACD的出手次数大约是30次/2年,即每月1~1.5次。MACD对于30支股票的平均收益率为-0.5%,KST为-1.2%。
一旦回测的股票数据较多,就很难一个一个去分析,这个时候可以用正态分布(样本>=30)来进行统计,例如上面的回测数据都保存在\analyzer_list.csv中,则可以在Notebook中进行计算和绘制图形
# 根据策略收益绘制正态分布图
list1 = df3.iloc[::2,-1].tolist() # 策略1-MACD的收益
list2= df3.iloc[1::2,-1].tolist() # 策略2-KST的收益
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
# 计算两个列表的平均值和标准差
mean1, std1 = np.mean(list1), np.std(list1)
mean2, std2 = np.mean(list2), np.std(list2)
# 生成x轴上的值
x = np.linspace(min(min(list1), min(list2)), max(max(list1), max(list2)), 100)
# 计算两个正态分布的概率密度函数
pdf1 = norm.pdf(x, mean1, std1)
pdf2 = norm.pdf(x, mean2, std2)
# 绘制正态分布图
plt.plot(x, pdf1, label='MACD')
plt.plot(x, pdf2, label='KST')
plt.legend()
# 显示图表
plt.show()
得到的图形如下,从而可以看到MACD的正收益部分要比KST大上一块,从这30支股票来讲,MACD经典策略比较好。
D_MACD底背离的实现
参考文章:
基本概念
在Backtrader中编写MACD底背离策略,首先需要理解MACD底背离的概念。MACD底背离是指当股价创出新低,但MACD指标没有创出新低,反而比前一低点要高,这通常被视为股价可能反转向上的信号。
策略分析
底背离至少要使用2个指标,包括MACD和最低价,因此它属于混合策略,原本不在内置指标实践的章节里的,但由于MACD实在是太出名了,所以这里就稍稍进阶了一下,让我们一起把这个底背离的策略写出来。
首先是MACD的周期问题,在上面的参考文章里有位作者是先找到最低价,然后获取最低价对应的DIFF的值,他使用的是“获取过去30日收盘价的最低值”作为起始量化的切入点。但这样的设置并不能反应真实的情况,因为有的金叉到死叉就超过30天,而有的30天内出现连续好几次的反复交叉。个人觉得比较好的周期就是直接用MACD的金叉死叉周期,它是封闭的系统,1个金叉必然对应1个死叉。
于是底背离可以用死叉做切入点,(顶背离则可以用金叉做切入点),每一轮死叉到金叉之间就可以用最小值来计算K线的值和DIFF的值,然后把这一轮的与上一轮的最小值进行比较就得到了是否底背离成立。要实现这一策略,需要用2组变量来记录,1组是记录上一个周期的最低值,第2组记录当前周期的最低值。
代码实现
class MACD_Bottom_Divergence_Strategy(BaseSt):
params = (('macd1', 12), ('macd2', 26), ('macdsig', 9),('stra_name','MACD底背离'),
('tradeCnt',1),
('sucessCnt',0),)
def __init__(self):
macd1 = bt.ind.MACD(self.data.close)
self.macd = macd1.l.macd
self.signal = macd1.l.signal
self.crsup = bt.indicators.CrossUp(self.macd, self.signal) # 确定金叉和死叉
self.crsdn = bt.indicators.CrossDown(self.macd, self.signal)
self.curr_low = self.data.low[0] # 给当前一轮赋初值 # 可以用收盘价,这里使用最低价
self.curr_macd = -100.0
self.prev_low = 0 # 初始化low可以为0因为股价不为0,
self.prev_macd = -100.0 # 初始化macd,但macd不能用0,因为macd在过程中可以出现0,所以给个-100
def next(self):
if self.crsdn: # 先根据MACD的死叉,本轮最低值用当前值初始化
self.curr_low = self.data.low[0]
self.curr_macd = self.macd[0]
dt = bt.num2date(self.data.datetime[0])
print('crsdn',dt, 'prev',self.prev_low,self.prev_macd) # 显示上一轮的最低值
else:
if self.data.low[0]<self.curr_low: #没有死叉则比大小并保存最小值
self.curr_low = self.data.low[0]
if self.macd[0]<self.curr_macd:
self.curr_macd = self.macd[0]
if not self.position: # 检查是否有持仓
if self.prev_low != 0 and self.prev_macd!=-100.0: # 第一轮没有prev,剔除
if self.crsup: # 金叉买入(判断滞后了)
print('crsup,当前低价%.2f,上一轮低价%.2f,当前dif最低%.2f,上一轮dif最低%.2f'%(self.curr_low,self.prev_low, self.curr_macd, self.prev_macd))
if (self.curr_low < self.prev_low) and (self.curr_macd >= self.prev_macd): #满足底背离买入
self.buy()
else:
if self.crsdn: # 死叉直接卖出
self.order = self.sell()
if self.crsup: # 金叉则表示一轮MACD完成,将当前值赋给上一轮值
self.prev_low = self.curr_low
self.prev_macd = self.curr_macd
运行后得到以下图线
底背离准不准?这个真要看选择的标的,有的股票它都不会触发底背离,而有的好不容易有一次底背离成功后立即又死叉再金叉(如上图),这种要添加代码让它用后面的金叉做买点(没那么简单),还有的股票会背离了又再次背离的。
在实际应用中,底背离通常需要结合其他因素一起研判,比如成交量、其他技术指标或者市场新闻等,以提高判断的准确性。此外,底背离形态的出现并不一定意味着股价马上会反转,它仅仅提供了一个可能的信号,需要投资者进一步分析和确认。在实践中,MACD指标的背离一般出现在强势行情中比较可靠,而在股价低位时,一般要反复出现几次背离后才能确认。
这里的策略为了容易实现,采用了金叉买入死叉卖出而没有改变,其实不需要等金叉就可以发现底背离信号已经产生了,在日内交易过程中(例如分时线)有时还没有金叉但背离的趋势已经很明显,这里就需要灵活运用(其实主要是因为策略复杂还没完善无法直接执行)。
E_MACD小结
MACD(Moving Average Convergence Divergence)中文叫做“移动平均收敛发散指标”,
"Convergence" 翻译成中文是“收敛”,指的是事物逐渐接近或趋向于一个共同点或状态。
"Divergence" 翻译成中文是“发散”,指的是事物逐渐远离或趋向于不同的方向或状态。
均线计算操作步骤
MACD在均线的基础上进行了一些简单的操作步骤:
首先是双均线计算,双均线计算一般就是快线与慢线的关系(大于、等于、小于)在指标里还有交叉,两根均线的差值产生了第一根line即DIF(Difference,差值),很明显DIF=0的时候两条均线是交叉的;
接着是二次均线的处理。二次均线处理是一种技术分析方法,它涉及到对移动平均线(MA)的进一步加工和应用,以提高交易信号的准确性和可靠性。在MACD中就使用了对双均线的差值再进行移动平均的操作产生了DEA("DEA"是"Difference Exponential Average"的缩写),它代表了DIF(的指数移动平均线。
然后再次使用双均线计算,即DIF与DEA两条线之间的关系,或许是为了在图上把差值显示更清楚,公式还采用了乘以2的放大操作。
最后,MACD柱状图的增长和缩短便实现了“发散”与“收敛”的可视化操作。
自定义指标的编写
MACD类是最佳的实践自定义指标的,其实在backtrader的策略开发的时候,如果有自己特殊的想法和思路,或者如果自己还不能清楚某个指标的原理和逻辑,就可以尝试着用自定义指标来实现一下。这个就很像股票软件里面自己编写指标公式,你会发现当熟练了自定义指标的编写的时候,股票软件里的指标公式编写就会变得轻松起来。
但是,还是要把一系列的内置指标都了解一遍的基础上再去做这个,避免重复造轮子的情况发生,更能避免造出方轮子或者四不像的情况发生。就比如说前一阵子想做一个平均振幅(周期为N)的指标,几分钟写出了一个每日振幅的公式(用当日最高-最低/收盘价),然后就卡在如果今天是跳空高开,周平均振幅就会是不对的,这个问题想了很久,花了很多时间。但其实只要实践过一遍ATR指标就能轻松解决,所以首先要拓宽眼界。
常见的MACD策略
- 首先是金叉、死叉策略,这个在股票软件中称为专家系统。
- 其次是零轴策略,很多文章谈到零轴之上与零轴之下的问题。
- 还有就是背离策略。
小结
我们在实践内置指标的时候,还会根据指标本身拓展出其他一些东西,比如说Fibonacci与黄金分割,比如说HeikinAshi不是日本人名,还比如说一目均衡表中每条线之间的关系以及多条线采用的策略分类,再比如说动量指标与速度、加速度的关系,股票软件中如何显示策略的收益率等,以及MACD与自定义指标类的编写,MACD指标公式的均线策略,MACD的经典策略与底背离策略等。
逐渐我们发现,有一些内置指标比较简单,买卖的策略也可以比较简单,而有一些内置指标就很复杂(比如一目均衡表等),往往需要比较复杂的逻辑,这个时候买卖策略就需要研究、实践再研究的过程。