手记

Python进阶量化交易专栏场外篇8- 矢量化计算KDJ指标

欢迎大家订阅《教你用 Python 进阶量化交易》专栏!为了能够提供给大家更轻松的学习过程,笔者在专栏内容之外已陆续推出一些手记来辅助同学们学习本专栏内容,目前已推出如下扩展篇:

在第一篇《管理概率==理性交易》中笔者结合一个简单的市场模型介绍了为什么在没有概率优势的前提下参与交易会亏钱,其实股票交易和玩一个游戏、做一个项目理念是相通的,需要章法、需要制定策略,否则就和抛硬币赌博一样一样的,用量化交易可以帮助我们管理好概率,更理性的去下单。

在第二篇《线性回归拟合股价沉浮》中笔者在专栏《股票交易策略开发:走势线性回归选股策略》小节的基础上对线性回归方法的策略应用做进一步的扩展介绍。由于线性回归作用于股票收盘价的整个周期,前后两段完全相反的周期会彼此作用,最终影响拟合的角度值,于是笔者设定窗口期用移动窗口的方式拟合股价的走势,寻找角度曲线的拐点以预示新一轮的反转走势,给大家提供一个衍生的策略思路。

在第三篇《最大回撤评价策略风险》中笔者在专栏
《股票交易数据可视化:买卖区间下策略收益绘制》的基础上对策略的最大回撤指标做一定的扩展介绍。投资是有风险的,那么如何去衡量这个风险呢?最大回撤率就是一种直观的将风险切实量化的指标,它描述了买入股票后,在策略出现最糟糕的情况下会损失多少钱,这也直接关系到了风险策略中止损因子的设定。

在第四篇《寻找最优化策略参数》中笔者在专栏
《股票交易策略开发:趋势突破择时策略》的基础上对寻找最优化策略参数的方法做一些扩展介绍。对于寻找最优化参数的方法可以选择枚举法或者蒙特卡洛法。枚举法适用于解决效率要求不高,样本规模小的问题。蒙特卡洛法得到的结果并不一定是最优的,但是在大规模样品的场合下可以更快地找到近似最优结果。

在第五篇《标记A股市场涨跌周期》中笔者在专栏
《股票交易数据的自动下载》的基础上对matplotlib绘图工具的使用方法做一些扩展介绍,在A股历史走势图中标记出市场涨跌周期。

在第六篇《Tushare Pro接口介绍》中笔者在《股票交易数据的自动下载》的基础上扩展介绍使用Tushare Pro版本获取财经和股票交易数据的方法。

在第七篇《装饰器计算代码时间》中笔者在《用装饰器注册股票池》的基础上对装饰器的进行扩展介绍,通过装饰器方式实现timeit测试函数执行时间功能。


本次场外篇笔者在《技术分析常用指标绘制》的基础上对KDJ指标的计算进行扩展介绍,由之前for…in循环遍历方式升级为矢量化方式,并且用自制的@timeit装饰器对比两种方式的效率。

KDJ指标在各大股票行情软件中都会体现,一般在股票K线图下方,如下图所示:

关于KDJ指标的特点和它的来龙去脉,笔者在专栏中有具体的介绍。在专栏中KDJ指标的实现是采用for…in循环遍历的方式,目的是让同学们更容易理解,但是在效率上并不是最佳的。先看下当前实现KDJ指标的数值,如下所示:

print(df_stockload.loc[:,['K', 'D','J']].head(20))
print(df_stockload.loc[:,['K', 'D','J']].tail(10))

                    K          D          J
Date                                       
2018-01-02        NaN        NaN        NaN
2018-01-03        NaN        NaN        NaN
2018-01-04        NaN        NaN        NaN
2018-01-05        NaN        NaN        NaN
2018-01-08        NaN        NaN        NaN
2018-01-09        NaN        NaN        NaN
2018-01-10        NaN        NaN        NaN
2018-01-11        NaN        NaN        NaN
2018-01-12  50.000000  50.000000  50.000000
2018-01-15  43.006532  47.668844  33.681909
2018-01-16  43.311542  46.216410  37.501805
2018-01-17  35.018155  42.483658  20.087149
2018-01-18  28.835633  37.934317  10.638267
2018-01-19  21.474105  32.447580  -0.472844
2018-01-22  21.143383  28.679514   6.071121
2018-01-23  20.387414  25.915481   9.331281
2018-01-24  26.739757  26.190239  27.838792
2018-01-25  34.780534  29.053671  46.234261
2018-01-26  43.876661  33.994668  63.640648
2018-01-29  41.339019  36.442785  51.131487
                    K          D          J
Date                                       
2018-12-18  22.180222  30.130738   6.279189
2018-12-19  15.725781  25.329086  -3.480829
2018-12-20  14.709213  21.789128   0.549383
2018-12-21  13.972795  19.183684   3.551017
2018-12-24  19.037423  19.134930  18.842410
2018-12-25  22.215432  20.161764  26.322768
2018-12-26  25.336607  21.886712  32.236398
2018-12-27  19.391069  21.054831  16.063544
2018-12-28  16.260719  19.456794   9.868570
2019-01-02  20.035902  19.649830  20.808046

将KDJ实现部分的代码封装为函数cal_kdj_loop(),并用装饰器@timer_para打印该函数执行的时间,运行时间如下所示:

Time of %s used: %s 0 0.28521588100000006

接下来介绍下矢量化实现的方法,仅仅只要6行代码即可,减少了一半以上,如下所示:

def cal_kdj_vector(df_data):
    low_list = df_data['Low'].rolling(9, min_periods=1).min()
    high_list = df_data['High'].rolling(9, min_periods=1).max()
    rsv = (df_data['Close'] - low_list) / (high_list - low_list) * 100
    df_data['K'] = rsv.ewm(com=2, adjust=False).mean()
    df_data['D'] = df_data['K'].ewm(com=2, adjust=False).mean()
    df_data['J'] = 3 * df_data['K'] - 2 * df_data['D']

    return df_data

此处使用了pandas.DataFrame.ewm()函数平滑KD值,该函数提供指数加权平滑功能,函数原型如下所示:

DataFrame.ewm(com=None, span=None, halflife=None, alpha=None, min_periods=0, adjust=True, ignore_na=False, axis=0)

当adjust为False时,以递归方式计算加权平均值:

weighted_average[0] = arg[0] 
weighted_average[i] = (1-alpha)*weighted_average[i-1] + alpha*arg[i]

com为2则alpha为1/3,于是K值为(2/3*前一日K值 + 1/3 当日RSV值),不过此处K值初值为rsv[0],而专栏中默认设定为50,因此计算得到的具体数值在开始阶段会有所不同。

计算得到的KDJ指标的数值,如下所示:

print(df_stockload.loc[:,['K', 'D','J']].head(20))
print(df_stockload.loc[:,['K', 'D','J']].tail(10))

                    K          D          J
Date                                       
2018-01-02  66.666490  66.666490  66.666490
2018-01-03  71.895300  68.409427  78.867046
2018-01-04  70.152422  68.990425  72.476416
2018-01-05  62.112192  66.697681  52.941214
2018-01-08  65.721838  66.372400  64.420714
2018-01-09  60.677308  64.474036  53.083853
2018-01-10  71.076537  66.674870  79.879872
2018-01-11  73.920300  69.090013  83.580874
2018-01-12  66.273665  68.151231  62.518535
2018-01-15  53.855643  63.386035  34.794858
2018-01-16  50.544282  59.105450  33.421945
2018-01-17  39.839982  52.683628  14.152691
2018-01-18  32.050185  45.805813   4.538927
2018-01-19  23.617139  38.409589  -5.967759
2018-01-22  22.572072  33.130417   1.455384
2018-01-23  21.339874  29.200236   5.619150
2018-01-24  27.374730  28.591734  24.940722
2018-01-25  35.203850  30.795772  44.020004
2018-01-26  44.158871  35.250139  61.976336
2018-01-29  41.527159  37.342479  49.896519
                    K          D          J
Date                                       
2018-12-18  22.180222  30.130738   6.279189
2018-12-19  15.725781  25.329086  -3.480829
2018-12-20  14.709213  21.789128   0.549383
2018-12-21  13.972795  19.183684   3.551017
2018-12-24  19.037423  19.134930  18.842410
2018-12-25  22.215432  20.161764  26.322768
2018-12-26  25.336607  21.886712  32.236398
2018-12-27  19.391069  21.054831  16.063544
2018-12-28  16.260719  19.456794   9.868570
2019-01-02  20.035902  19.649830  20.808046

代码量减少了,那么效率是否提高了呢?将函数cal_kdj_vector()用装饰器@timer_para打印该函数执行的时间,运行时间如下所示:

Time of %s used: %s 0 0.03495547999999982

矢量化方式计算KDJ指标相比于使用for…in循环方式效率提高了12倍!!!以下为两种方式实现的KDJ指标可视化绘制:

关于完整代码可以加入专栏交流群获取。更多的量化交易内容欢迎大家订阅专栏阅读!!

4人推荐
随时随地看视频
慕课网APP

热门评论

元宵大师,你好,请问可以给我这篇的完整代码吗,谢谢

查看全部评论