量化研究 | 周期趋势分析和 MAD 指标

松鼠Quant
2025-03-25


图片

量化策略开发,高质量社群,交易思路分享等

工具推荐

· 参数筛选工具

· Ai帮你编写策略

· 订单流图表

· 加入2025俱乐部

· Ai投研助手课程

在这里,我们来认识一下移动平均差(MAD)指标,并且讲讲它被创造出来的原因。这个指标很可靠,而且简单易懂。

我一直在做一个研究项目,目的是深入了解市场数据里的周期特点。最后,这个研究让我开发出了一个新的趋势指标——移动平均差(MAD)振荡器。

在本文中,我会展示这个新指标,详细说说我的研究和它怎么被开发出来的,还会描述振荡器能展示出什么内容,这会帮助大家理解它的基本原理。同时,我也会给出它的代码,这样大家就可以自己用起来了。

我觉得大家会发现这个趋势指标在各种输入参数下都很可靠,而且它还有一种简洁的美。

振荡器样式的指标

我开始研究项目的时候,想用一种方式展示一个振荡器,来观察当移动平均线的长度变化时振荡器会怎么表现。这可能会给我正在寻找的周期特点提供一些线索。这个想法就是把振荡器作为移动平均线长度的函数,用一系列颜色来展示。

制作振荡器样式指标的一个办法就是从价格本身减去价格的移动平均线。移动平均值里包含了数据的直流(零频率)分量和低频分量。所以,从价格里减去移动平均线,就会得到一个指标,这个指标的平均值基本为零,而且包含了数据里的高频周期分量。

“周期/趋势分析”能以多种颜色显示振荡器,作为移动平均线长度的函数。

图片

图1:循环模式。“周期/趋势分析”展示了对移动平均值范围内纯周期的反应。

图片

图2:趋势模式。“周期/趋势分析”把趋势强度显示为显示宽度。最红线和最黄线之间的距离代表了趋势的强度。当红线在顶部时,趋势向上;当红线在底部时,趋势向下。

图片

图3:MAD指标EMINI标准普尔500指数期货连续合约,2019年1月1日至2021年7月1日。MAD(移动平均差)指标把趋势显示成一个按价格百分比缩放的振荡器。

循环模式

在“周期/趋势分析”这个代码用配色方案来显示振荡器,默认模式是“周期”。在这种模式下,从收盘价开始的价格被覆盖成30个周期的正弦波。画一条青色线来显示输入价格。两条移动平均线之间的差别是后来添加的,所以现在先不管这条线。移动平均线和振荡器(osc)数组是在5到30根柱线的范围内算出来的。当长度从5变到30时,每个osc被分配一个从255到0的绿色值。这个值和红色结合,当长度是5的时候,产生亮黄色的综合颜色;当长度是30的时候,颜色是红色。

“循环”模式的结果在图1里展示出来了。对于最短的移动平均线,指标输出几乎比输入超前90度。这不奇怪,因为短均线和价格差不多,只是稍微延迟了一点。当取差值的时候,它看起来像个动量函数。而动量类似于微积分里的导数,正弦波的导数是余弦波。换句话说,指标输出的相位比输入超前大约90度。

当移动平均线的长度是周期周期的一半时,指标输出和价格输入完全同步。同样,这也不奇怪,因为半个周期内的正弦波的总和和同一参考系里的价格周期完全同相。当移动平均线的长度超过半个周期周期时,该指标就有相对滞后的相位了。

趋势模式

当把代码里的CTMode输入从“cycle”改成“trend”来运行的时候,惊喜就来了。这个输入的改变导致包含理论正弦波数据输入的代码块在代码运行时被忽略了。在这种情况下,收盘价不会被覆盖,我们就能看到指标被应用到实际数据上了。被应用到收盘价的指标例子在图2里展示了出来。

这个趋势指标在一系列输入参数下都很可靠,同时又很简洁。

导致MAD指标产生的过程, 对我来说很惊讶的结果是主要效果是最红线和最黄线之间的距离反映了趋势的强度。当红线在顶部的时候,趋势向上;当红线在底部的时候,趋势向下。

另外,所有指标里的高频波浪线看起来几乎一样。这是因为当价格和它的平均值之间有差别时,所有指标线都有相似的高频成分。

所以,我们的想法是通过取两个振荡器的差别来显示趋势。当取差值的时候,高频成分就被抵消了。如果两条移动平均线的长度差是主导周期周期的一半,那么结果就会和输入价格完全同相。你可以通过把画的绿线里的第二条移动平均线的长度改成20来验证这一点。这样两条移动平均线的长度差就是15,正好是30根柱线周期长度的一半。结果就是绿线被青线覆盖,说明两者完全同相。

取两个振荡器指标的差值在数学上和只取两个移动平均线的差值是一样的,因为每个振荡器里的价格项都被抵消掉了。

“有思想的人”的MACD所以这就是它了。虽然推导过程有点复杂,但MAD(移动平均差)指标实际上就是两个简单移动平均线的差值,它们的平均长度相差大约数据里主要周期周期的一半。随着较短移动平均线的长度增加,指标会变得更平滑。较长的移动平均线的长度应该是较短的移动平均线的长度加上数据里主导周期周期的一半。如果不知道主导周期,就把较长移动平均线的长度设为较短移动平均线长度的两倍就行。

作为移动平均线的差别,MAD指标就像是一个“有思想的人”的MACD,因为设置移动平均线的长度是合乎逻辑的。而且,简单的移动平均有线性相位响应,所以差分消除了对第三次平滑平均的需求。

MAD指标为了方便,这个指标被画成收盘价的百分比。归一化项是让指标尽可能平滑的平均值。

MAD指标的例子在图3里展示了出来。这个指标对相对比较宽范围内的参数变化不太敏感。

下个月,我会扩展这个概念,并且提出对这个指标的修改。我会展示怎么用它来改善交易时机并且减少错误信号。

策略代码:周期/趋势分析

































































Params    String CTMode("trend"); // "cycle" 或 "trend"
Vars    Numeric Price(0);    Integer Length(0);    Integer NormalLength(0);    Numeric Color1(0);    Numeric Color2(0);    Numeric Color3(0);Array<Numeric> Osc;
Events    OnBar(ArrayRef<Integer> indexs)    {        Price = Close;
If (CTMode == "cycle")        {            Price = Sin(2*pi * CurrentBar / 30);            PlotNumeric("Price", Price, Cyan, 4, 4);            PlotNumeric("MA5-MA30", Average(Price, 5) - Average(Price, 30), Green, 4, 4);        }
        Color1 = 255;        Color3 = 0;
For Length = 5 To 30        {            Osc[Length] = Price - Average(Price, Length);        }    PlotNumeric("ZeroLine", 0,0, White, 1);For Length = 5 To 30        {            Color2 = 306 - 10.2 * Length;If (Length == 4) PlotNumeric("S4", Osc[Length], 0,RGB(Color1, Color2, Color3));If (Length == 5) PlotNumeric("S5", Osc[Length], 0,RGB(Color1, Color2, Color3));If (Length == 6) PlotNumeric("S6", Osc[Length], 0,RGB(Color1, Color2, Color3));If (Length == 7) PlotNumeric("S7", Osc[Length], 0,RGB(Color1, Color2, Color3));If (Length == 8) PlotNumeric("S8", Osc[Length], 0,RGB(Color1, Color2, Color3));If (Length == 9) PlotNumeric("S9", Osc[Length], 0,RGB(Color1, Color2, Color3));If (Length == 10) PlotNumeric("S10", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 11) PlotNumeric("S11", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 12) PlotNumeric("S12", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 13) PlotNumeric("S13", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 14) PlotNumeric("S14", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 15) PlotNumeric("S15", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 16) PlotNumeric("S16", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 17) PlotNumeric("S17", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 18) PlotNumeric("S18", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 19) PlotNumeric("S19", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 20) PlotNumeric("S20", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 21) PlotNumeric("S21", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 22) PlotNumeric("S22", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 23) PlotNumeric("S23", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 24) PlotNumeric("S24", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 25) PlotNumeric("S25", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 26) PlotNumeric("S26", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 27) PlotNumeric("S27", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 28) PlotNumeric("S28", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 29) PlotNumeric("S29", Osc[Length],0, RGB(Color1, Color2, Color3));If (Length == 30) PlotNumeric("S30", Osc[Length],0, RGB(Color1, Color2, Color3));        }    }

MAD:


















Params    Numeric ShortLength(8); // 短周期Numeric LongLength(23); // 长周期
Vars    Series<Numeric> MAD(0); // 移动平均差
EventsOnBar(ArrayRef<Integer> indexs)    {// 计算移动平均差        MAD = 100 * (Average(Close, ShortLength) - Average(Close, LongLength)) / Average(Close, LongLength);
// 绘制图表        PlotNumeric("MAD", MAD,0, Red);        PlotNumeric("ZeroLine", 0,0, White,   1);    }

防迷路


图片

微   信|小松鼠-松鼠Quant

微信号|viquant01

本期源码 《MAD 》

2025量化俱乐部


分享