顶底背离的终极猜想和运用

这几天圈内都在传底蓓离什么的。作为严肃的量化自媒体,我们就不跟着吃这波瓜了。不过,我一直很关注技术指标的顶背离和底背离,一直在追问它的成因如何,以及如何预测。

底蓓离把我目光再次吸引到这个领域来,于是突然有了一个猜想。虽然我还没来得及完全证实它,但这个猜想,值得你锁定我的频道。

这个猜想是:RSI的日线顶背离,是因为周线还有上升空间。当周线RSI也达到前期高点时,就会触发回调。此时日线虽然创新高,但高位筹码不稳,回调增多,导致RSI下降。


背离的定义

Investopedia对技术指标的#顶背离定义为:

在这里插入图片描述

在国内,我们一般使用顶背离和底背离这两个术语。最早大V中较多讨论这两个术语的,可能是炒股养家或者缠中说禅,说明这一现象在实战中是比较受到关注的。

下图中的右图展示了一个日线的顶背离。左图则是对应的周线情况。

附图指标我使用的是RSI,它是一个非常好的震荡指标,深刻反映了当前市场的赚钱效应和强弱力量对比。

在图中,程序自动标注出来了k线的每一个峰和谷。这些标注使用了我们自己的自适应参数算法,在绝大多数时间、无论周期是哪个级别,都能工作得很好。不过这一次,在周线级别上,没能触发它标注出3月22日那一周的高点。


从右图中我们注意到,日线上存在2月27日和3月18日两个峰,后一个峰的价格高于前一峰,但后一个峰的RSI略小于前一峰的RSI(前高78.3,后高77.7),形成了顶背离。

我们在课程中详细介绍过一个独创但更准确地理论,在运用RSI时,不是低于30就会反弹,高于70就会回调,而是要看它跟前一个峰(或者谷)的RSI相比较,如果上涨时,RSI高于前一个峰对应的RSI,则有可能回调。

但这个结论也有自身的问题:一是在图中,日线在2月27日之前,就已经突破了2024年1月25日下降通道中高点RSI,为何一直到2月27日才回调?我们在课程中已经解决了这个问题。


二是为何在2月27日之后,股价还能一直上涨,直到3月18日出现顶背离?这个顶背离问题,我也一直没有思路,但自己着手写了好几个检测顶背离的例程。

猜想和验证

现在我们给出回答第二个问题的一个猜想,即尽管2月27日的日线RSI已经达到高位,但周线RSI仍在低位,它没有表示反对和阻止上涨的意思,因此日线短暂调整后,在其它因素趋动下继续上涨,直到3月22日那一周,盘中突破前高60.5,才引发了一个周线级别的大回调。

!!!tip
从3月21日起,到3月27日止,中证1000连续回调超过6.94%,从而引发反弹,这是另外一个故事和机会。我们在前面的一篇文章中介绍过,统计数据给出3月27日收盘后,反弹概率超过91.4%的结论,这种情况,应该坚决**抄底**。

RSI是反转指标。它只能以一定概率给出会不会反转,但你不应该指望它给出趋势延续的预测。那是趋势类指标的任务。最重要的趋势类指标,莫过于判断均线的斜率,如果线性回归误差在可接受范围以内的话。在回归误差较大而失效的情况下,课程中也给出了一个非常鲁棒的方法。

我们还是拿数据验证一下:


# 日线2月27日、3月18日顶背离,前者RSI 78.3,后者RSI 77.7
dclose = dbars["close"].astype(np.float64)
drsi = ta.RSI(dclose, 6)

for dt in (datetime.date(2024, 2, 27), 
           datetime.date(2024, 3, 18)):
    mask = dbars["frame"] == np.datetime64(dt)
    i = np.flatnonzero(mask)[0]
    print(dt, dclose[i], drsi[i])

# --- output ---
# 2024-02-27 5394.03 78.3
# 2024-03-18 5648.01 77.7

从数据看出,尽管日线价格在上涨,但RSI却下降了,构成了日线顶背离。

接着看周线:

# 周线rsi前高出现于2023年11月17日,数值为60.5
wclose = wbars["close"].astype(np.float64).copy()

nov_17 = np.datetime64(datetime.date(2023,11, 17))
i = np.flatnonzero(wbars["frame"] == nov_17)[0]

rsi = np.round(ta.RSI(wclose, 6), 1)
rsi[i]

前高为60.5。这里有一个技巧,如果没看明白,可以给我留言:

# 3月22日,周线rsi数值盘中突破 61.9,高于前高60.5,触发回调

mar_22 = np.datetime64(datetime.date(2024, 3, 22))
i = np.flatnonzero(wbars["frame"] == mar_22)[0]

wclose[i] = wbars["high"][i]

rsi = ta.RSI(wclose.astype(np.float64), 6)
rsi[i]

rsi后高为61.9,因此触发回调,并且这个阻力得到了确认。

在这里插入图片描述

引申结论及思考

在这个市场上,存在各种不同操作频率(这是FFT和wavelet应该有用的原因)的资金。


对高频量化,他们看的是tick级数据,可能持有几分钟就会调仓;散户和量化多在日线和周线频率上操作,持有数天就调仓;长线资金以季度为单位。越是长线的资金,资金量越大,调仓时对走向的影响越强。

现在,你应该已经猜到了,有一部分资金会在日线RSI高点时撤出;大量的资金会在周线的RSI高点撤出;而更大量的资金会在月线的RSI高点撤出。

但我猜没有资金会根据季线的RSI高点撤出。许多真理,都不能线性外推。

我这么说的原因是,季线资金会按照基本面来进行操作,而不是技术面。有的同学会拿基本面因子与技术面因子揉在一起,无论是多因子回归,还是机器学习,这都是不对的。它们只会相互打架、抵消。

所以,从现在起,你应该给你的股票上个闹钟,计算出它的日线、周线和月线RSI前期高点,然后实时监控这些指标。

一旦三者都达到高点,这轮行情就结束了。如果月线达到高点,日线和周线不在高位,但发生过顶背离,那么,势必在高位产生过滞胀(量在堆积,但上涨幅度不大),此时主力的筹码很多已经被交换掉了。

此时不走很危险。接下来的回调时间,可能以月计。老胡说,“我不割肉,你怎么割我?”但胡锡进终究是等不到那一天。

在这里插入图片描述

<think>我们首先需要明确MACD顶背离背离的定义:-顶背离:股价创新高,但MACD指标的高点却比前一次高点低。-底背离:股价创新低,但MACD指标的低点却比前一次低点高。实现步骤:1.计算MACD指标(包括DIF、DEAMACD柱)。2.寻找股价的峰值(顶背离时)谷值(底背离时),以及对应的MACD值。3.比较相邻的两个股价峰值(或谷值)对应的MACD值,判断是否符合背离条件。注意:-背离通常需要连续的两个高点(顶背离)或两个低点(底背离)来比较。-由于股价MACD的波动,我们需要在一定的窗口内寻找最近的高点或低点。我们将按照以下步骤实现:1.计算MACD指标:我们可以使用`talib`库,或者自己编写计算函数。考虑到talib可能安装不便,这里我们使用自己编写的函数(或使用pandas的ewm计算)。2.寻找股价的局部高点局部低点:可以使用滚动窗口寻找极值点(例如,比较某点比前后若干点都高/低)。3.匹配股价高点MACD的对应高点,然后比较相邻两个高点(或低点)的股价MACD值的变化方向。具体实现:步骤1:计算MACD我们使用标准方法:快速EMA(一般12日),慢速EMA(一般26日),DIF=快速EMA-慢速EMA,DEA为DIF的9日EMA(也称MACD信号线),MACD柱=(DIF-DEA)*2。步骤2:寻找股价的峰谷顶背离:寻找股价的局部高点,要求该高点比前后N根K线的高点都高(N可调,比如5)。底背离:寻找股价的局部低点,要求该低点比前后N根K线的低点都低。步骤3:比较相邻的两个峰(或谷)对应的股价MACD值(通常用DIF值)顶背离:当前股价高点高于前一个股价高点,但当前DIF值低于前一个高点的DIF值。底背离:当前股价低点低于前一个股价低点,但当前DIF值高于前一个低点的DIF值。注意:在实际操作中,我们可能还需要考虑时间上的连续性,即两个相邻的峰(谷)之间不能间隔太远(比如不超过60根K线)。代码结构:1.计算MACD(包括DIF,DEA,MACD柱)。2.标记股价的局部高点局部低点。3.提取局部高点序列局部低点序列。4.遍历局部高点序列,比较相邻两个高点对应的股价DIF值,判断顶背离。5.遍历局部低点序列,比较相邻两个低点对应的股价DIF值,判断底背离。注意:由于背离的判断通常需要最新的K线与之前的比较,因此我们可能只需要最近出现的两个高点(或两个低点)即可。然而,为了在图表上标注多个背离,我们可能需要找出所有满足条件的背离点。这里我们选择最近的两个高点(低点)进行判断,但需要注意的是,可能同时存在多个背离(比如连续多个顶背离),所以我们要在局部高点序列中逐一比较相邻的两个高点(不一定是连续的,但时间顺序是递增的)。由于我们更关注最近发生的背离,所以从最新往前推,找到最近的背离信号。实现方案:我们将编写一个函数,输入为股价(收盘价或最高价,通常用收盘价)对应的时间序列,计算MACD,然后找出背离点。注意:在寻找局部高点时,我们使用一个滚动窗口,比如窗口大小为5(即一个点要同时比左边两个右边两个都高才是局部高点)。同时,为了避免噪音,我们可以要求相邻两个高点之间至少间隔一定的K线数量(比如5根)。步骤2详细:寻找局部高点/低点局部高点:假设有数组`highs`(这里用最高价或者收盘价?通常顶背离用最高价,底背离用最低价,但有时也用收盘价。这里按需求,一般我们用最高价找顶背离,最低价找底背离)。方法:使用`argrelextrema`函数(scipy.signal中的函数)或者自己通过滚动窗口实现。由于我们可能没有scipy,所以自己实现:局部高点:对每个位置i,检查[i-窗口,i+窗口]内的最大值是否为i位置,如果是,则标记为高点。同样,低点也是检查最小值。但是,这样会找到很多点,我们需要过滤掉中间的小波动,要求两个相邻的高点(低点)之间有一定的距离(时间间隔)。步骤3:背离判断顶背离:从最近的高点开始,比较每个相邻的高点对(按照时间顺序,取连续两个高点)。如果当前高点(较新的)的股价高于前一个高点(较旧的),而当前高点的DIF值却小于前一个高点的DIF值,则标记为顶背离。底背离:从最近的低点开始,比较相邻的低点对。如果当前低点的股价低于前一个低点,而当前低点的DIF值大于前一个低点的DIF值,则标记为底背离。注意:有时候可能有多个连续背离,所以我们遍历所有相邻的低点对(高点对)进行判断。代码示例:我们使用pandas进行数据操作。假设我们有DataFrame数据`df`,包含日期(索引)、最高价(high)、最低价(low)、收盘价(close)。首先,计算MACD:如果没有talib,我们使用pandas的ewm函数计算指数移动平均:步骤1:计算MACD快速EMA(12日):`df['ema12']=df['close'].ewm(span=12,adjust=False).mean()`慢速EMA(26日):`df['ema26']=df['close'].ewm(span=26,adjust=False).mean()`DIF:`df['dif']=df['ema12']-df['ema26']`DEA:`df['dea']=df['dif'].ewm(span=9,adjust=False).mean()`MACD柱:`df['macd']=(df['dif']-df['dea'])*2`步骤2:寻找局部高点低点定义窗口大小,比如5。注意:避免使用未来信息,所以滚动窗口应该只使用过去当前的数据,但寻找极值点通常需要左右窗口。然而,在实盘中,我们无法使用未来的窗口,所以这里我们只使用左侧窗口(即只比较当前点与之前的点)。但是,这样可能会导致在最新点处标记的高点不够准确(因为它右边没有数据,我们不知道它是否还会被突破)。为了实时性,我们只能使用左侧窗口,即当前点比左边窗口内的点都高,且比当前最新的点都高(直到被突破)。但为了简化,我们采用固定窗口,并假设在计算时我们只对已经走完的K线进行判断(即不判断当前未完成的K线)。我们这里以收盘价最高价为例:顶背离用最高价序列,底背离用最低价序列。我们写一个函数来寻找局部高点低点:由于我们只需要最近发生的背离,所以可以只检查最近一段时间的数据(比如最近300根K线)。寻找局部高点(只考虑已完成的K线,即不包含当前正在形成的K线):我们定义函数`find_peaks``find_valleys`,用滚动窗口的方法(左侧窗口)。但是,为了简单,我们可以用:局部高点:当前最高价大于前N根K线的最高价,同时大于后N根K线的最高价?但我们不能使用未来数据,所以改为:当前最高价大于前N根K线的最高价,并且大于后M根K线(但只能用到当前为止)。如果我们只计算到当前,那么当前K线后面的数据是没有的,所以这里我们只能使用左侧窗口(即从当前开始往前的窗口)。调整:我们可以使用左侧的窗口(包括当前)来定义,即当前高点至少是最近N根K线(包括当前)的最高价,并且当前K线必须是这个窗口的最高价,同时当这个窗口移动时,当前点比下一个窗口的最高价要高(这种方法复杂)。另一种简单方法:当前高点比前1根、前2根、...、前N根的高点都高,那么它是一个局部高点(因为未来数据未知,所以无法确定,但在历史数据中我们可以使用未来数据(因为历史已经固定),但注意在实际交易中我们只能用历史固定数据)。因此,对于历史数据,我们可以使用中心窗口(包括左右),而对于最新数据,我们只能使用左侧窗口。这里我们考虑用历史数据(已固定),所以可以采用中心窗口:局部高点:对于位置i(索引),满足在[i-窗口,i+窗口]内,i处的最高价是最大值。同样,局部低点:i处的最低价是[i-窗口,i+窗口]内的最小值。然后,我们过滤掉相邻过近的高点(比如两个高点之间间隔小于5根K线,保留更高的那个)以避免重复。步骤3:背离检测对于局部高点序列(按时间顺序排列,从早到晚),我们遍历相邻的两个高点:若后一个高点的最高价>前一个高点的最高价,而后一个高点的DIF值<前一个高点的DIF值,则发生顶背离。底背离类似:对于局部低点序列,相邻两个低点,若后一个最低价<前一个最低价,而后一个低点的DIF值>前一个低点的DIF值,则底背离。注意:我们通常只关注最近发生的背离,所以从序列末尾开始找最近的背离。代码步骤:1.计算MACD。2.使用一个窗口大小(例如5)来寻找局部高点索引低点索引。3.提取局部高点:从`high`序列中取出这些点的最高价对应的DIF值;局部低点同理。4.对局部高点点按位置排序(时间顺序),然后从第一个到最后一个遍历,相邻两个点进行背离判断。同样,对低点序列遍历。5.标记出发生顶背离背离的位置。但是,由于我们可能需要标注在图表上,所以通常只需要最新出现的背离。另一种方法:只取最近的两个高点(低点)进行判断。但这样可能会漏掉之前的背离。因此,我们可以在所有高点序列中遍历相邻的高点对,然后记录下所有符合条件的背离点。这里我们分别找出所有顶背离背离,然后选取最近发生的。考虑到实际需求,我们可能更希望得到最近的一个背离信号,例如最近有顶背离,则可能是一个卖出信号。因此,我们可以在遍历局部高点序列时,从最新开始(即时间最近的)找连续两个高点进行判断。这里相邻的高点不一定是时间上连续的(因为中间可能有低点),但在局部高点序列中,它们是连续的。具体做法:对于按时间顺序排列的局部高点序列(索引从小到大,时间从早到晚),我们取最后两个高点(也就是最新的两个高点),判断它们是否满足顶背离条件。如果不满足,再考虑倒数第二个倒数第三个,等等。因为我们只需要最近的信号。但要注意,如果最新高点出现后,再出现一个更高的高点,那么这个高点将取代成为新的高点。所以我们只比较最近的两个高点(即序列最后两个)?实际上,我们需要比较的是:最近形成的一个高点与上一个高点(即前一个高点)之间的比较。这两个高点在时间上并不一定相邻(可能有其他小高点),但它们在局部高点序列中是相邻的(因为局部高点序列已经剔除了中间的小高点)。所以,在局部高点序列中,我们取最后两个点(也就是时间上最近的相邻两个高点)进行判断。底背离同理。因此,我们只需要检查局部高点序列中的最后两个点(如果存在两个或以上的话)是否满足顶背离条件。同样,局部低点序列的最后两个点是否满足底背离条件。这样,我们就能得到最近是否发生背离。实现:代码:步骤1:计算MACD步骤2:寻找局部高点低点步骤3:从局部高点序列中取出最后两个点,比较;从局部低点序列中取出最后两个点,比较。注意:我们寻找的局部高点低点都是基于已经结束的K线(即历史数据)。代码中需要注意:我们处理的数据是历史数据,所以可以用整个数据序列。局部高点/低点函数:我们将使用滚动窗口(中心窗口)来寻找局部极值点。可以使用`scipy.signal`中的`argrelextrema`,但为了减少依赖,我们自行实现。自行实现函数:注意:对于数据的开头结尾,窗口可能会超出范围,所以我们需要处理边界。为了方便,我们将只考虑中间部分的数据(即前后有足够多数据的部分)。我们编写一个简单的函数,输入一个序列,窗口大小,返回局部高点(索引数组)局部低点(索引数组)。考虑到时间,我们简化边界处理:只处理从窗口开始到窗口结束的数据。函数`find_local_extrema(series,window=5)`:高点:对每个位置i(从窗口开始到总长度-窗口),如果series[i]等于[i-window:i+window+1]这个窗口中的最大值,并且这个最大值是唯一的(或者我们只要求i处的值就是最大值,不管是否唯一),则标记为高点。低点同理,取最小值。但这样会有重复标记(相邻多个点都是最大值,但其实只算一个高点)。为了减少重复,我们要求局部高点必须严格大于窗口内所有其他值(即等于最大值且唯一)。或者,我们要求该点就是窗口内的最大值,并且该点比左右相邻的值要大?这样更准确。但实际上,我们使用:该点是窗口内的最大值,并且该点的值大于左右相邻的值(这样可以避免在连续平坦的情况下标记多个点)。但为了简单,我们采用:该点是整个窗口的最大值,并且该点不等于左右相邻(即避免连续平台)。但由于窗口内可能有平坦,我们取中间的那个?或者只要满足是最大值就标记,然后通过后续过滤(比如两个高点间隔太近,取最高的那个)。这里我们先采用:整个窗口内最大值的位置,如果有多个连续相同的最大值,只取中间位置?这样实现起来复杂。因此,我们采用一个简单方法:先找到所有满足比左边window大小右边window大小都大的点(即该点比左侧window个数据都大,且比右侧window个数据都大)[^2]。这样,我们就能找到局部高点。但是,这需要用到未来数据(右边的window)。所以对于实时应用,这个方法不可行,但对于历史数据可以。由于我们处理的是历史数据,所以可以使用。步骤:创建两个数组:`peaks=[]``valleys=[]`。循环遍历索引,从窗口开始`window`,到`len(series)-window`(因为需要右边有window个数据):当前索引为i,取窗口[i-window,i+window]内的最大值max_value最小值min_value。如果当前值`series[i]`等于max_value,并且`series[i]`大于`series[i-1]``series[i+1]`(以避免平台),则i是局部高点。同理,如果当前值等于min_value,并且小于左右相邻,则i是局部低点。但是,在窗口内可能有多个相同的高点,我们只取中间的那个?或者实际上,这样的定义会使得在平台处所有点都会被跳过(因为需要大于左右相邻)。所以平台不会被标记。这样,我们就能得到一组局部高点低点。然后,我们再过滤间隔过近的高点:如果两个高点之间间隔小于2*window+1,则保留较高的那个(因为我们的窗口是2*window+1,所以两个高点之间至少应该间隔2*window+1,否则就是同一个高点区域)。但我们不强制要求,因为实际中可能有多个波峰。所以我们只按照步骤3中所述,取最近的两个高点判断即可。然后,我们提取这些高点的位置,按时间顺序排列(因为我们的索引是从0开始递增的,所以位置索引也是时间顺序),然后取最后两个点进行判断。注意:在局部高点序列中,我们取位置索引最大的两个点(即最新的两个)。最后,我们比较:顶背离:设highs_list是局部高点索引列表(按索引从小到大排序),取最后两个点:idx1,idx2(其中idx2是较新的高点,idx1是前一个高点)比较:highs[idx2]>highs[idx1]且difs[idx2]< difs[idx1]底背离:lows_list,取最后两个点:idx1,idx2(idx2是较新的低点)比较:lows[idx2]< lows[idx1]且difs[idx2]>difs[idx1]如果满足条件,则发生了背离。由于我们的数据索引是0,1,...,len-1,最新数据在最后,所以局部高点索引数组最后的值是最大的索引,对应最新的高点。代码实现:假设我们有数据df,列包括'high','low','close',我们计算MACD。然后,寻找高点低点(窗口大小window=5,可调),得到高点的索引低点的索引。然后,按索引排序(本来就是从小到大):高点索引数组:peak_indices低点索引数组:valley_indices然后提取最后两个高点:如果len(peak_indices)>=2:idx1=peak_indices[-2]#前一个高点idx2=peak_indices[-1]#当前高点ifdf['high'][idx2]>df['high'][idx1]anddf['dif'][idx2]< df['dif'][idx1]:#发生顶背离print(f"顶背离发生在{idx1}{idx2}")同样,底背离:如果len(valley_indices)>=2:idx1=valley_indices[-2]#前一个低点idx2=valley_indices[-1]#当前低点ifdf['low'][idx2]< df['low'][idx1]anddf['dif'][idx2]>df['dif'][idx1]:#发生底背离print(f"底背离发生在{idx1}{idx2}")注意:这里我们用收盘价计算MACD的DIF,而高点判断用的是最高价,低点判断用的是最低价。但DIF是用收盘价计算的,所以这里是匹配收盘价对应的DIF最高价/最低价?实际上,我们需要的是:在高点位置,记录该位置的DIF值。由于DIF在一天内是一个值(通常我们用收盘价计算,所以代表当天的DIF值),而高点位置我们用的是当天的最高价(或最低价),所以是可以的(因为每个位置i的DIF值是该收盘价计算得到的,而最高价最低价发生在同一天,DIF只有一个值,所以直接取同一天的DIF值即可)。因此,代码中,每个位置i,我们用当天计算好的DIF值(在i位置)。但是,需要注意的是,MACD计算使用的是收盘价,而背离判断中,股价的高低点通常用最高价最低价。因此,在寻找局部高点时,使用最高价序列,而低点使用最低价序列,但对应的DIF值都是当天的(用收盘价计算的)。这样做是常见的做法,因为虽然当天的最高价最低价可能更极端,但DIF值是以收盘价计算的,所以当天的收盘价不一定是最高的。也就是说,最高价出现的当天,收盘价可能较低,导致DIF值也较低。这正体现了背离:价格有新高,但收盘相对没这么高,导致DIF值下降。因此,实现上是合理的。但是,还有一种做法:用收盘价判断背离(即寻找收盘价的局部高点低点)。这样就MACD计算保持一致。这两种方法都是可行的,实际中两种都有人用。这里我们按照常见的做法:顶背离用最高价序列(因为最高价创了新高),底背离用最低价序列(因为最低价创新低),但对应的是同一天的收盘价计算的DIF值。完整代码框架:1.导入包:pandas2.定义函数:计算MACD3.定义函数:寻找局部高点低点(中心窗口法)4.计算MACD5.寻找局部高点低点6.分别检查顶背离背离注意:我们只检查最近的两对,因为我们只关心最近的背离信号。代码示例:由于篇幅,我们只写出主要代码,并注释。由于我们可能没有scipy,所以我们自己实现中心窗口的极值点查找。注意:中心窗口查找需要未来数据,所以只适用于历史数据。在实盘中,需要调整(比如只使用左侧数据)[^3],这里我们不考虑实盘,只考虑历史数据回测。现在开始写代码:</think> ### Python实现MACD顶底背离判断 #### 实现思路 MACD的顶背离背离是重要的技术分析信号: - **顶背离**:股价创新高,但MACD指标未创新高(通常是DIF或MACD柱状图高点下移) - **底背离**:股价创新低,但MACD指标未创新低(通常是DIF或MACD柱状图低点上移) #### 实现步骤 ```python import pandas as pd import numpy as np import matplotlib.pyplot as plt def calculate_macd(close, fast=12, slow=26, signal=9): """ 计算MACD指标 返回DataFrame: [dif, dea, macd] """ ema_fast = close.ewm(span=fast, adjust=False).mean() ema_slow = close.ewm(span=slow, adjust=False).mean() dif = ema_fast - ema_slow dea = dif.ewm(span=signal, adjust=False).mean() macd = (dif - dea) * 2 return pd.DataFrame({'DIF': dif, 'DEA': dea, 'MACD': macd}) def find_divergence(high, low, macd_df, window=5, threshold=0.2): """ 识别顶底背离 window: 检测窗口大小 threshold: 幅度阈值(避免微小波动误判) """ dif = macd_df['DIF'] patterns = pd.Series(index=macd_df.index, dtype=str) # 识别顶背离 for i in range(window, len(high)-1): # 找最近两个高点 peak1 = high.iloc[i-window:i].idxmax() peak2 = high.iloc[i-window+1:i+1].idxmax() if (high[peak2] > high[peak1]) and (dif[peak2] + threshold < dif[peak1]): patterns[peak2] = '顶背离' # 识别底背离 for i in range(window, len(low)-1): # 找最近两个低点 trough1 = low.iloc[i-window:i].idxmin() trough2 = low.iloc[i-window+1:i+1].idxmin() if (low[trough2] < low[trough1]) and (dif[trough2] > dif[trough1] + threshold): patterns[trough2] = '底背离' return patterns # 示例使用 if __name__ == "__main__": # 获取股票数据(示例) from pandas_datareader import data as pdr import yfinance as yf yf.pdr_override() # 获取数据 stock_data = pdr.get_data_yahoo('AAPL', start='2020-01-01', end='2023-01-01') # 计算MACD macd_df = calculate_macd(stock_data['Close']) # 识别背离 divergence_signals = find_divergence( high=stock_data['High'], low=stock_data['Low'], macd_df=macd_df, window=20, threshold=0.15 ) # 筛选出背离信号点 top_divergence = divergence_signals[divergence_signals == '顶背离'] bottom_divergence = divergence_signals[divergence_signals == '底背离'] # 可视化 plt.figure(figsize=(14, 10)) ax1 = plt.subplot(2, 1, 1) plt.plot(stock_data['Close'], label='Price') plt.scatter(top_divergence.index, stock_data.loc[top_divergence.index, 'Close'], marker='v', c='red', s=100, label='顶背离') plt.scatter(bottom_divergence.index, stock_data.loc[bottom_divergence.index, 'Close'], marker='^', c='green', s=100, label='底背离') plt.title('股票价格与背离信号') plt.legend() ax2 = plt.subplot(2, 1, 2) plt.plot(macd_df['DIF'], label='DIF') plt.plot(macd_df['DEA'], label='DEA') plt.bar(macd_df.index, macd_df['MACD'], label='MACD柱', color=np.where(macd_df['MACD']>0, 'r', 'g')) plt.title('MACD指标') plt.legend() plt.show() ``` #### 关键参数说明 1. **MACD计算参数** - `fast=12`:快线周期(默认12日EMA) - `slow=26`:慢线周期(默认26日EMA) - `signal=9`:信号线周期(默认9日EMA) 2. **背离检测参数** - `window=20`:检测窗口(默认20根K线) - `threshold=0.2`:差异阈值(过滤微小波动) 3. **改进建议** - 添加成交量验证(背离时成交量应萎缩) - 多时间周期验证(日线/周线背离结合) - 优化拐点检测算法(使用动态阈值) #### 注意事项 1. MACD背离是滞后指标,建议结合其他技术指标验证 2. 收盘价计算可能在实盘中有轻微偏差 3. 不同品种(股票/期货)需要调整参数 4. 大周期(周线/月线)背离信号更可靠 > 系统可针对不同品种自动优化参数配置,并对识别结果进行统计分析验证有效性[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

量化风云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值