Press "Enter" to skip to content

做套:惊呆了,探究如果机器用KDJ法对股票进行做套的胜率,竟高达%80

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

 

做套:惊呆了!探究如果机器用KDJ法对股票进行做套的胜率,竟高达%80。

 

接上一篇:惊呆了,探究如果机器用MACD法对股票进行做套的胜率,竟高达%80

 

今天在整理自研量化系统的代码屎山时,也无意间想记录一下如果仅仅严格按照KDJ法对买入的股票进行做套,胜率将会是多少呢?

 

接下来就来尝试一下,首先得简单了解一下什幺是KDJ,这个我也不多解释了,“dddd”,所以简单百度百科一下:
随机指标KDJ一般是用于股票分析的统计体系,根据统计学原理
,通过一个特定的周期(常为9日、9周等)内出现过的最高价、最低价及最后一个计算周期的收盘价及这三者之间的比例关系,来计算最后一个计算周期的未成熟随机值
RSV,然后根据平滑移动平均线
的方法来计算K值、D值与J值,并绘成曲线图来研判股票走势。

 

简单了解完之后就可以开始实现了:

 

第一步导入数据:

 

df = pd.read_csv("2021-11-19.csv")

 

这里用一下2021年11月19号的上证A股所有股票的日分钟数据

 

 

忽略’code’列股票代码显示不全的问题,从数据库备份转csv时没注意code特征列数值的属性,但对这次实验不造成影响,后期把“0”补回去就好了,就是csv保存时把前面的“0”都去掉了,数据量有54w条,足够大了。

 

构造计算KDJ的函数

 

这里就需要用到kdj的公式了

自己查,很简单的

完整的计算kdj函数的代码为:

 

def CalculateKDJ(price_list, _kdj):
    """
    :param price_list: 
    :param _kdj: 列表 例如 [0, 0, 0]
    :return:
    """
    RSV = 0
    if max(price_list) - min(price_list) != 0:
        RSV = (price_list[-1] - min(price_list)) / (max(price_list) - min(price_list)) * 100
    K = 2 / 3 * _kdj[0] + 1 / 3 * RSV
    D = 2 / 3 * _kdj[1] + 1 / 3 * K
    J = 3 * K - 2 * D
    return [round(K, 2), round(D, 2), round(J, 2)]

 

此外,还利用sklearn的线性模型库linear_model构造一个可以计算一段时间内价格变动趋势的函数,其实就是分析线性方程组的斜率,从而得知在这段时间,价格变动的趋势

 

def CalculateTrend(price_list):
    """
    :param price_list: 
    :return:
    """
    regr = linear_model.LinearRegression()
    X = list()
    for x in range(1, len(price_list) + 1):
        X.append([x])
    regr.fit(X, price_list)
    return regr.coef_.tolist()[0]

 

重头戏来了,函数都备好了,万事俱备只欠东风,得构造一个逻辑函数或称为步骤函数去利用数据然后作出决策,然后再判断决策是否正确

 

做套的两件大事(不要做反套):

卖的时候比原本持仓价格要高
买的时候比原本持仓价格要低

因此在函数中设置一个阈值”threshold”来从当这个原本持仓价格

 

初始值设立:

Ki-1表示前一天的K值,若无前一天的K值,则用50来代替。Di-1表示前一天的D值,若无前一天的D值,则用50来代替。所以初始KDJ设为[50,50,0]。
原本持仓价格我们不可能每一个股票都输入一个持仓价格,因此我将持仓价格设置为当天开盘的数据,其实原本持仓价格只是从当一个阈值效果,帮助我们不要做反套,所以这样设立也确实没多大问题。
不设立买入和卖出限制的股数,因为要尽可能的多测试样例,但这在现时中是不合理的,因为我们买入卖出的股份不可能是无限多。所以在想要使用的时候,可以添加一个限制操作股数的值,当买或卖达到了这个值,就不能也不用再操作这只股票了

但KDJ就是遵循多种操作方式:

 

# K与D值永远介于0到100之间。D大于80时,行情呈现超买现象。D小于20时,行情呈现超卖现象。
# J指标取值超过100和低于0,都属于价格的非正常区域,大于100为超买,小0为超卖。
# 当K值由较小逐渐大于D值,在图形上显示K线从下方上穿D线,所以在图形上K线向上突破D线时,俗称金叉,即为买进的讯号
# 当K值由较大逐渐小于D值,在图形上显示K线从上方下穿D线,所以在图形上K线向下突破D线时,俗称死叉,即为卖出的讯号

 

为了探究其中哪个更适合用于”做套”,可以把它看成超短期交易,所以可视化一下KDJ的分布规律:

首先获取到全部的股票的日KDJ全部数据

data = {
 'K':list(),'D':list(),'J':list()}
for code in set(df['code'].to_list()):
price_list = df[df['code'] == code]['最新价'].to_list()
threshold = price_list[0]
# Ki-1表示前一天的K值,若无前一天的K值,则用50来代替。
# Di-1表示前一天的D值,若无前一天的D值,则用50来代替。
_KDJ = [50, 50, 0]
for i in range(9, len(price_list), 9):
    KDJ = CalculateKDJ(price_list[i - 9:i], _kdj=_KDJ)
    data['K'].append(KDJ[0])
    data['D'].append(KDJ[1])
    data['J'].append(KDJ[2])
    _KDJ = KDJ
data = pd.DataFrame(data)

 

 

随随便便看看吧,会的也不是很多,看一下每列分布吧:

 

从左往右依次为K,D,J的分布情况:

 

 

符合:K与D值永远介于0到100之间,J指标可超过100和低于0

 

但对于D大于80时,行情呈现超买现象。D小于20时,行情呈现超卖现象。根据数据列分布情况,我觉得这个可能对于超短期帮助不大,因此待会实验,也添加一个条件试验一下就好了。

 

D值和J值的变化曲线:

 

 

然后我叠加了一个用于判断趋势的函数:

 

当判断到买时趋势是向下的(<0),则放弃购买

 

当判断到卖时趋势是向上的(>0),则放弃售卖

 

判断胜负的方式用,买入(卖出)时的价格低于(高于)接下来10分钟的平均价,则判为胜。

 

for code in tqdm(set(df['code'].to_list())):
        price_list = df[df['code'] == code]['最新价'].to_list()
        r = 0
        t = 0
        threshold = price_list[0]
        # Ki-1表示前一天的K值,若无前一天的K值,则用50来代替。
        # Di-1表示前一天的D值,若无前一天的D值,则用50来代替。
        _KDJ = [50, 50, 0]
        for i in range(5, len(price_list), 5):
            KDJ = CalculateKDJ(price_list[i - 5:i], _kdj=_KDJ)
            if price_list[i] < threshold:
                if KDJ[2] >= 100:
                    if CalculateTrend(price_list[i - 5:i]) > 0:
                        buy['code'].append(code)
                        buy['买入价'].append(price_list[i])
                        buy['买入后十分钟平均价:'].append(np.mean(price_list[i + 1:i + 11]))
                        r += 1 if price_list[i] <= np.mean(price_list[i + 1:i + 11]) else -1
                        t += 1
            if price_list[i] > threshold:
                if KDJ[2] <= 0:
                    if CalculateTrend(price_list[i - 5:i]) < 0:
                        sell['code'].append(code)
                        sell['卖出价'].append(price_list[i])
                        sell['卖出后十分钟平均价:'].append(np.mean(price_list[i + 1:i + 11]))
                        r += 1 if price_list[i] >= np.mean(price_list[i + 1:i + 11]) else -1
                        t += 1
            _KDJ = KDJ
        if t != 0:
            rate['code'].append(code)
            rate['胜率'].append(r / t)

 

一通捣鼓下来,观看实验效果:

 

仅用“J指标取值超过100和低于0,都属于价格的非正常区域,大于100为超买,小0为超卖。”

 

胜率为

 

用“J指标取值超过100和低于0,都属于价格的非正常区域,大于100为超买,小0为超卖。”和

 

D大于80时,行情呈现超买现象。D小于20时,行情呈现超卖现象。“胜率为

 

,反而降低了

 

用“当K值由较小逐渐大于D值,在图形上显示K线从下方上穿D线,所以在图形上K线向上突破D线时,俗称金叉,即为买进的讯号”和“当K值由较大逐渐小于D值,在图形上显示K线从上方下穿D线,所以在图形上K线向下突破D线时,俗称死叉,即为卖出的讯号”胜率为
可见J值更敏感,对于这种“日内做套”的手段,胜率显得更高一点。

 

完整代码:

 

import pandas as pd
from sklearn import linear_model
from tqdm import tqdm
import numpy as np
def CalculateKDJ(price_list, _kdj):
    """
    :param price_list: 
    :param _kdj: 列表 例如 [0, 0, 0]
    :return:
    """
    RSV = 0
    if max(price_list) - min(price_list) != 0:
        RSV = (price_list[-1] - min(price_list)) / (max(price_list) - min(price_list)) * 100
    K = 2 / 3 * _kdj[0] + 1 / 3 * RSV
    D = 2 / 3 * _kdj[1] + 1 / 3 * K
    J = 3 * K - 2 * D
    return [round(K, 2), round(D, 2), round(J, 2)]
def CalculateTrend(price_list):
    """
    :param price_list: 
    :return:
    """
    regr = linear_model.LinearRegression()
    X = list()
    for x in range(1, len(price_list) + 1):
        X.append([x])
    regr.fit(X, price_list)
    return regr.coef_.tolist()[0]
if __name__ == '__main__':
    # K与D值永远介于0到100之间。D大于80时,行情呈现超买现象。D小于20时,行情呈现超卖现象。
    # J指标取值超过100和低于0,都属于价格的非正常区域,大于100为超买,小0为超卖。
    # 当K值由较小逐渐大于D值,在图形上显示K线从下方上穿D线,所以在图形上K线向上突破D线时,俗称金叉,即为买进的讯号
    # 当K值由较大逐渐小于D值,在图形上显示K线从上方下穿D线,所以在图形上K线向下突破D线时,俗称死叉,即为卖出的讯号
    df = pd.read_csv("min_test_data.csv")
    buy = {
 'code': list(), '买入价': list(), '买入后十分钟平均价:': list()}
    sell = {
 'code': list(), '卖出价': list(), '卖出后十分钟平均价:': list()}
    rate = {
 'code': list(), '胜率': list()}
    for code in tqdm(set(df['code'].to_list())):
        price_list = df[df['code'] == code]['最新价'].to_list()
        r = 0
        t = 0
        threshold = price_list[0]
        # Ki-1表示前一天的K值,若无前一天的K值,则用50来代替。
        # Di-1表示前一天的D值,若无前一天的D值,则用50来代替。
        _KDJ = [50, 50, 0]
        for i in range(5, len(price_list), 5):
            KDJ = CalculateKDJ(price_list[i - 5:i], _kdj=_KDJ)
            if price_list[i] < threshold:
                if KDJ[2] >= 100:
                    if CalculateTrend(price_list[i - 5:i]) > 0:
                        buy['code'].append(code)
                        buy['买入价'].append(price_list[i])
                        buy['买入后十分钟平均价:'].append(np.mean(price_list[i + 1:i + 11]))
                        r += 1 if price_list[i] <= np.mean(price_list[i + 1:i + 11]) else -1
                        t += 1
            if price_list[i] > threshold:
                if KDJ[2] <= 0:
                    if CalculateTrend(price_list[i - 5:i]) < 0:
                        sell['code'].append(code)
                        sell['卖出价'].append(price_list[i])
                        sell['卖出后十分钟平均价:'].append(np.mean(price_list[i + 1:i + 11]))
                        r += 1 if price_list[i] >= np.mean(price_list[i + 1:i + 11]) else -1
                        t += 1
            _KDJ = KDJ
        if t != 0:
            rate['code'].append(code)
            rate['胜率'].append(r / t)
    buy = pd.DataFrame(buy)
    print(buy.head())
    sell = pd.DataFrame(sell)
    print(sell.head())
    rate = pd.DataFrame(rate)
    print(rate.head())
    print(rate['胜率'].sum() / len(rate))
 t != 0:
            rate['code'].append(code)
            rate['胜率'].append(r / t)
    buy = pd.DataFrame(buy)
    print(buy.head())
    sell = pd.DataFrame(sell)
    print(sell.head())
    rate = pd.DataFrame(rate)
    print(rate.head())
    print(rate['胜率'].sum() / len(rate))

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注