python股票分析挖掘预测技术指标知识大全之KDJ详解(3)

本人股市多年的老韭菜,各种股票分析书籍,技术指标书籍阅历无数,萌发想法,何不自己开发个股票预测分析软件,选择python因为够强大,它提供了很多高效便捷的数据分析工具包。

我们已经初步的接触与学习其中数据分析中常见的3大利器---Numpy,Pandas,Matplotlib库。

也简单介绍一下数据获取的二种方法,通过金融数据接口和爬虫获取。

上一章介绍了指标之王MACD,这一章我们重点介绍一下随机指标KDJ.

   KDJ指标详解

(1)KDJ指标简介 

KDJ指标中文名叫随机指标,是由·蓝恩博士(George Lane)最早提出的。集中包含了弱指量概念和移平均线点,可以用来衡量股价脱离正常价格范的偏离程度。

,它起先用于期货市场的分析,后被广泛用于股市的中短期趋势分析,是期货和股票市场上最常用的技术分析工具。

随机指标KDJ一般是用于股票分析的统计体系,根据统计学原理,通过一个特定的周期(常为9日、9周等)内出现过的最高价、最低价及最后一个计算周期的收盘价及这三者之间的比例关系,来计算最后一个计算周期的未成熟随机值RSV,然后根据平滑移动平均线的方法来计算K值、D值与J值,并绘成曲线图来研判股票走势。

(2)KDJ指标计算方法

KDJ程是,首先取指定周期(一般是9天)内出现过的股票最高价、最低价和最后一个交易日的收价,随后通三者的比例关系来算出未成熟随机RSV,并在此基上再用平滑移平均线的方式来KDJ值。计算完成后,把KDJ值绘成曲线图,以此来判股票走,具体的算法如下所示。

第一步:计算周期内(n日、n周等,n一般是9)的RSV值,RSV也叫未成熟随机指标值,是K值、D值和J值的基础。以n日周期例,算公式如下所示。

nRSV =CnLn/HnLn× 100

 其中,Cn是第n日(一般是最后一日)的收价,Lnn日范内的最低价,Hnn日范内的最高价,根据上述公式可知,RSV值的取值范围是1100。如果要n周的RSV值,则Cn还是最后一日的收盘价,但LnHn则是n周内的最低价和最高价。

 第二步:根据RSV计算KD值,方法如下

当日K= 2/3 × 前一日K1/3 × 当日的RSV

当日D= 2/3 × 前一日D1/3 × 当日K

程中,如果没有前一日值或D值,则可以用数字50来代替。

实际使用程中,一般是以9周期来KD线,根据上述公式,首先是计算出最近9日的RSV值,即未成熟随机值,计算公式是9RSV = CL9÷H9L9× 100。其中各参数含在步一中已提到,其次再按本步所示算当日的KD

需要明的是,上式中的平滑因子2/31/3是可以更改的,不在股市交易践中,两个被默认设2/31/3

第三步:计算J值。J算公式J = 3×K - 2×D。从使用角度来看,J实质是反映K值和D值的乖离程度,它的范围上可超过100,下可低于0

最早的KDJ只有K线和D线两条线,那个时候也被称为KD,随着分析技展,KDKDJ,引入J后,能提高KDJ标预判行情的能力。

在按上述三个步骤计算出每天的KDJ三个之后,把它们连接起来,就可以看到KDJ标线了。

python代码实现:

import pandas as pd
import talib
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
 
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111)
df = pd.read_csv("600276.csv")
df['date'] = pd.to_datetime(df['date'])
df['date'] = df['date'].apply(lambda x: x.strftime('%Y-%m-%d'))
df['K'], df['D'] = talib.STOCH(df['high'].values, df['low'].values, df['close'].values, fastk_period=9, slowk_period=3,
                               slowk_matype=0, slowd_period=3, slowd_matype=0)
df['K'].fillna(0,inplace=True)
df['D'].fillna(0,inplace=True)
df['J']=3*df['K']-2*df['D']
ax.plot(df["date"], df["K"], label ="K")
ax.plot(df["date"], df["D"], label ="D")
ax.plot(df["date"], df["J"], label ="J")
plt.legend()
ax.xaxis.set_major_locator(ticker.MaxNLocator(20))
def format_date(x, pos=None):
    # 由于前面股票数据在 date 这个位置传入的都是int
    # 因此 x=0,1,2,...
    # date_tickers 是所有日期的字符串形式列表
    if x < 0 or x > len(df['date']) - 1:
        return ''
    return df['date'][int(x)]
 
 
ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')
plt.show()

显示效果: 

(3)KDJ顶背离

Python中,KDJ顶背离可以通过计算KDJ指标的最高点与股价的最高点之间的关系来确定。具体步骤如下:

  1. 计算KDJ指标的最高点:根据KDJ指标的计算公式,需要找到KDJ指标的最高点。这可以通过比较不同周期的KDJ值来确定。
  2. 确定股价的最高点:与KDJ指标的最高点相对应,需要找到股价的最高点。这可以通过比较不同周期的收盘价来确定。
  3. 判断顶背离:如果KDJ指标的最高点出现在股价的最高点之前,则说明出现了顶背离。此时,可以考虑卖出股票。

需要注意的是,KDJ指标的计算涉及到平滑处理,因此在实际计算中需要注意平滑周期的选择。同时,顶背离并不一定意味着股价一定会下跌,还需要结合其他技术指标和基本面分析进行综合判断。

代码:

import pandas as pd  
import numpy as np  
  
# 读取数据  
data = pd.read_csv('002761.csv')  
  
# 计算KDJ指标  
data['k'] = data['close'].ewm(span=9, min_periods=1, adjust=False).mean() * 3 / data['close'].ewm(span=3, min_periods=1, adjust=False).mean()  
data['d'] = data['k'].ewm(span=3, min_periods=1, adjust=False).mean()  
data['j'] = 3 * data['k'] - 2 * data['d']  
  
# 计算顶背离  
data['top_divergence'] = np.where((data['high'].shift(1) > data['high']) & (data['j'].shift(1) < data['j']), True, False)  
  
# 输出结果  
print(data[['high', 'j', 'top_divergence']])

 

(4)KDJ底背离

KDJ底背离是指当股价K线图上的股票走势一谷比一谷低,股价在向下跌,而KDJ曲线图上的KDJ指标的走势在低位一底比一底高,这叫底背离现象。底背离现象一般是股价将低位反转的信号,表明股价中短期内即将上涨,是买入的信号。

实战技巧:

  1. 当股价在高位,KDJ在80以上出现顶背离时,可以认为股价即将反转向下,投资者可以及时卖出股票。
  2. 当股价在低位,KDJ也在低位(50以下)出现底背离时,一般要反复出现几次底背离才能确认,并且投资者只能做战略建仓或做短期投资。

代码:

import pandas as pd  
import numpy as np  
  
# 读取数据  
data = pd.read_csv('007611.csv')  
  
# 计算KDJ指标  
data['k'] = data['close'].ewm(span=9, min_periods=1, adjust=False).mean() * 3 / data['close'].ewm(span=3, min_periods=1, adjust=False).mean()  
data['d'] = data['k'].ewm(span=3, min_periods=1, adjust=False).mean()  
data['j'] = 3 * data['k'] - 2 * data['d']  
  
# 计算底背离  
data['bottom_divergence'] = np.where((data['low'].shift(1) < data['low']) & (data['j'].shift(1) > data['j']), True, False)  
  
# 输出结果  
print(data[['low', 'j', 'bottom_divergence']])

注释:KDJ顶背离成功率远远高于底背离 

(5)KDJ超买超卖指标

KDJ指标的超买和超卖区域的划分标准如下:

  1. 当D值大于90时,股价易产生瞬间回档;D值小于15时,股价易产生瞬间反弹。
  2. 在常态行情中,D值大于80后股价经常向下回跌;D值小于20后股价易于回升。在极端行情中,D值大于90,股价易产生瞬间回档;D值小于15,股价易产生瞬间反弹。
  3. 当白色的K值在50以上的高水平,形成一顶比一顶低的现象,并且K值由上向下连续两次交叉黄色的D值时,股价会产生较大的跌幅。
  4. 当白色的K线由下向上交叉黄色的D线失败转而向下探底后,K线再次向上交叉D线,两线所夹的空间叫做向上反转风洞。当出现向上反转风洞时股价将上涨。反之叫做向下反转风洞。出现向下反转风洞时股价将下跌。
  5. 当K值大于80,短期内股价容易向下出现回档;K值小于20,短期内股价容易向上出现反弹;但在极强、极弱行情中K、D指标会在超买、超卖区内徘徊,此时应参考VR、ROC指标以确定走势的强弱。
  6. 在常态行情中,D值大于80后股价经常向下回跌;D值小于20后股价易于回升。在极端行情中,D值大于90,股价易产生瞬间回档;D值小于15,股价易产生瞬间反弹。

代码实现:

import pandas as pd  
import numpy as np  
  
# 读取数据  
data = pd.read_csv('000786.csv')  
  
# 计算KDJ指标  
data['k'] = data['close'].ewm(span=9, min_periods=1, adjust=False).mean() * 3 / data['close'].ewm(span=3, min_periods=1, adjust=False).mean()  
data['d'] = data['k'].ewm(span=3, min_periods=1, adjust=False).mean()  
data['j'] = 3 * data['k'] - 2 * data['d']  
  
# 计算超买和超卖区域  
data['overbought'] = np.where((data['j'] > 80), True, False)  
data['oversold'] = np.where((data['j'] < 20), True, False)  
  
# 输出结果  
print(data[['j', 'overbought', 'oversold']])

注意:超卖超买指标最好结合背离指标一起运用,才能自己成功概率! 

 (6)KDJ金叉死叉指标

金叉是指K线从下往上穿过D线,形成有效的向上突破。这通常被视为一个买入信号,因为它预示着股票价格的上涨趋势。实战中,当KDJ三线在超卖区形成金叉时,股价成功反弹的可能性较高。另外,KDJ金叉后出现小幅震荡整理向上的形态更好,这说明资金在不断吸筹等待后期的快速拉升。

死叉则是指K线从上往下穿过D线,形成所谓的“死叉”,表明股票价格的趋势可能向下。这通常被视为一个卖出信号,因为它预示着股票价格的下跌。当高位死叉形成后,一定要及时止盈止损。

完整代码:

# !/usr/bin/env python
# coding=utf-8
import matplotlib.pyplot as plt
import pandas as pd
import pandas
from mpl_finance import candlestick2_ochl
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter
import tkinter.messagebox
import efinance as ef
# 计算KDJ
plt.rcParams['font.family'] = 'Heiti TC'
plt.rcParams['font.sans-serif'] = ['SimHei']
def calKDJ(df):
    df['MinLow'] = df['low'].rolling(9, min_periods=9).min()
    # 填充NaN数据
    df['MinLow'].fillna(value = df['low'].expanding().min(), inplace = True)
    df['MaxHigh'] = df['high'].rolling(9, min_periods=9).max()
    df['MaxHigh'].fillna(value = df['high'].expanding().max(), inplace = True)
    df['RSV'] = (df['close'] - df['MinLow']) / (df['MaxHigh'] - df['MinLow']) * 100
    for i in range(len(df)):
        if i==0:    # 第一天
            df.loc[i,'K']=50
            df.loc[i,'D']=50
        if i>0:
            df.loc[i,'K']=df.loc[i-1,'K']*2/3 + 1/3*df.loc[i,'RSV']
            df.loc[i,'D']=df.loc[i-1,'D']*2/3 + 1/3*df.loc[i,'K']
        df.loc[i,'J']=3*df.loc[i,'K']-2*df.loc[i,'D']
    return df
# 绘制KDJ线
def drawKDJAndKLine(stockCode,startDate,endDate):
    df = ef.stock.get_quote_history(stockCode)
    # 将数据存储到 csv 文件中
    df.to_csv(f'{stockCode}.csv', encoding='utf-8-sig', index=None)
    filename=stockCode+startDate+endDate+'.csv'
    getStockDataFromAPI(stockCode,startDate,endDate)
    df = pd.read_csv('600276.csv')
    stockDataFrame = calKDJ(df)
    # 创建子图
    (axPrice, axKDJ) = figure.subplots(2, sharex=True)
    # 调用方法,在第axPrice子图中绘制K线图
    candlestick2_ochl(ax = axPrice,
                  opens=stockDataFrame["open"].values, closes=stockDataFrame["close"].values,
                  highs=stockDataFrame["high"].values, lows=stockDataFrame["low"].values,
                  width=0.75, colorup='red', colordown='green')
    axPrice.set_title("K线图和均线图")    # 设置子图标题
    stockDataFrame['close'].rolling(window=3).mean().plot(ax=axPrice,color="red",label='3日均线')
    stockDataFrame['close'].rolling(window=5).mean().plot(ax=axPrice,color="blue",label='5日均线')
    stockDataFrame['close'].rolling(window=10).mean().plot(ax=axPrice,color="green",label='10日均线')
    axPrice.legend(loc='best')      # 绘制图例
    axPrice.set_ylabel("价格(单位:元)")
    axPrice.grid(linestyle='-.')    # 带网格线
    # 在axKDJ子图中绘制KDJ
    stockDataFrame['K'].plot(ax=axKDJ,color="blue",label='K')
    stockDataFrame['D'].plot(ax=axKDJ,color="green",label='D')
    stockDataFrame['J'].plot(ax=axKDJ,color="purple",label='J')
    plt.legend(loc='best')          # 绘制图例

    plt.rcParams['font.family'] = 'Heiti TC'
    plt.rcParams['font.sans-serif']=['SimHei']
    axKDJ.set_title("KDJ图")        # 设置子图的标题
    axKDJ.grid(linestyle='-.')      # 带网格线
    # 设置x轴坐标的标签和旋转角度
    major_index=stockDataFrame.index[stockDataFrame.index%5==0]
    major_xtics=stockDataFrame['date'][stockDataFrame.index%5==0]
    plt.xticks(major_index,major_xtics)
    plt.setp(plt.gca().get_xticklabels(), rotation=30)
# 从API中获取股票数据
def getStockDataFromAPI(stockCode,startDate,endDate):
    try:
        # 给股票代码加ss前缀来获取上证股票的数据
        stock = pandas.get_quote_history(stockCode+'.ss')

        if(len(stock)<1):
            # 如果没取到数据,则抛出异常
            raise Exception()
        # 删除最后一行,因为get_data_yahoo会多取一天的股票交易数据
        stock.drop(stock.index[len(stock)-1],inplace=True)  # 在本地留份csv
        filename=''+stockCode+startDate+endDate+'.csv'
        stock.to_csv(filename)
    except Exception as e:
        print('Error when getting the data of:' + stockCode)
        print(repr(e))
# 设置tkinter窗口
win = tkinter.Tk()
win.geometry('925x800')     # 设置大小
win.title("K线均线整合KDJ")
# 放置控件
tkinter.Label(win,text='股票代码:').place(x=10,y=20)
tkinter.Label(win,text='开始时间:').place(x=10,y=50)
tkinter.Label(win,text='结束时间:').place(x=10,y=80)
stockCodeVal = tkinter.StringVar()
startDateVal = tkinter.StringVar()
endDateVal = tkinter.StringVar()
stockCodeEntry = tkinter.Entry(win,textvariable=stockCodeVal)
stockCodeEntry.place(x=70,y=20)
stockCodeEntry.insert(0,'600640')
startDateEntry = tkinter.Entry(win,textvariable=startDateVal)
startDateEntry.place(x=70,y=50)
startDateEntry.insert(0,'2023-03-01')
endDateEntry = tkinter.Entry(win,textvariable=endDateVal)
endDateEntry.place(x=70,y=80)
endDateEntry.insert(0,'2023-06-31')
def draw():     # 绘制按钮的处理函数
    plt.clf()   # 先清空所有在plt上的图形
    stockCode=stockCodeVal.get()
    startDate=startDateVal.get()
    endDate=endDateVal.get()
    drawKDJAndKLine(stockCode,startDate,endDate)
    canvas.draw()
tkinter.Button(win,text='绘制',width=12,command=draw).place(x=200,y=50)
def reset():
    stockCodeEntry.delete(0,tkinter.END)
    stockCodeEntry.insert(0,'600640')
    startDateEntry.delete(0,tkinter.END)
    startDateEntry.insert(0,'2023-03-01')
    endDateEntry.delete(0,tkinter.END)
    endDateEntry.insert(0,'2023-06-31')
    plt.clf()
    canvas.draw()
tkinter.Button(win,text='重置',width=12,command=reset).place(x=200,y=80)
# 以对话框的形式输出买点
def printBuyPoints():
    stockCode=stockCodeVal.get()
    startDate=startDateVal.get()
    endDate=endDateVal.get()
    filename=''+stockCode+startDate+endDate+'.csv'
    getStockDataFromAPI(stockCode,startDate,endDate)
    df = pd.read_csv('600276.csv')
    stockDf = calKDJ(df)
    cnt=0
    buyDate=''
    while cnt<=len(stockDf)-1:
        if(cnt>=5): # 略过前几天的误差
            #规则1:前一天J值大于10,当天J值小于10,是买点、
            if stockDf.iloc[cnt]['J']<10 and stockDf.iloc[cnt-1]['J']>10:
                buyDate = buyDate+stockDf.iloc[cnt]['date'] + ','
                cnt=cnt+1
                continue
            # 规则2:K,D均在20之下,出现K线上穿D线的金叉现象
            # 规则1和规则2是“或”的关系,所以当满足规则1时直接continue
            if stockDf.iloc[cnt]['K']>stockDf.iloc[cnt]['D'] and stockDf.iloc[cnt-1]['D']>stockDf.iloc[cnt-1]['K']:
                # 满足上穿条件后再判断K和D均小于20
                if stockDf.iloc[cnt]['K']< 20 and stockDf.iloc[cnt]['D']<20:
                    buyDate = buyDate + stockDf.iloc[cnt]['date'] + ','
        cnt=cnt+1
    # 完成后,通过对话框的形式显示买入日期
    tkinter.messagebox.showinfo('提示买点',buyDate)
tkinter.Button(win,text='计算买点',width=12,command=printBuyPoints).place(x=300,y=50)
# 以对话框的形式输出卖点
def printSellPoints():
    stockCode=stockCodeVal.get()
    startDate=startDateVal.get()
    endDate=endDateVal.get()
    filename=''+stockCode+startDate+endDate+'.csv'
    getStockDataFromAPI(stockCode,startDate,endDate)
    df = pd.read_csv('600276.csv')
    stockDf = calKDJ(df)
    cnt=0
    sellDate=''
    while cnt<=len(stockDf)-1:
        if(cnt>=5): # 略过前几天的误差
            # 规则1:前一天J值小于100,当天J值大于100,是卖点、
            if stockDf.iloc[cnt]['J']>100 and stockDf.iloc[cnt-1]['J']<100:
                sellDate = sellDate+stockDf.iloc[cnt]['date'] + ','
                cnt=cnt+1
                continue
            # 规则2:K,D均在80之上,出现K线下穿D线的死叉现象
            if stockDf.iloc[cnt]['K']<stockDf.iloc[cnt]['D'] and stockDf.iloc[cnt-1]['D']<stockDf.iloc[cnt-1]['K']:
                # 满足上穿条件后再判断K和D均大于80
                if stockDf.iloc[cnt]['K']> 80 and stockDf.iloc[cnt]['D']>80:
                    sellDate = sellDate + stockDf.iloc[cnt]['date'] + ','
        cnt=cnt+1
    # 完成后,通过对话框的形式显示买入日期
    tkinter.messagebox.showinfo('kdj死叉卖点',sellDate)
tkinter.Button(win,text='kdj死叉计算卖点',width=12,command=printSellPoints).place(x=300,y=80)

# 开始整合figure和win
figure = plt.figure()
canvas = FigureCanvasTkAgg(figure, win)
canvas.get_tk_widget().config(width=875,height=600)
canvas.get_tk_widget().place(x=0,y=100)
win.mainloop()

图片显示: 

注意:kdj的金叉和死叉一定要结合其他指标应用,经过统计这个指标成功概率不高。 

kdj指标基本应用学的差不多了,希望大家交流学习 

 

  • 28
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Adam_new

谢谢您的鼓励

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

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

打赏作者

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

抵扣说明:

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

余额充值