量化投资系列文章:

Backtrader 教程 — Python 量化投资原来这么简单(1)

Python 量化投资原来这么简单(2) —MACD策略(+26.9%)

Python 量化投资原来这么简单(3) —A股回测MACD策略

Github仓库:https://github.com/Ckend/pythondict-quant


今天我们来使用backtrader试试另一个量化投资策略:KDJ策略,KDJ是最常用的指标之一,其中文名叫“随机指标”。它通过统计学原理,识别N个交易日内最高价、最低价、最新收盘价三者之间的比例关系来计算随机值(RSV),然后再根据加权移动平均线(EMA)的方法来计算K值、D值、J值。

具体计算方法如下:

  • RSV = (收盘价-N周期最低价)/(N周期最高价-N周期最低价)*100
  • K值 = RSV的N周期加权移动平均值
  • D值 = K值的N周期加权移动平均值
  • J值 = 3K-2D

一般来说,RSV的N周期选择9,K和D的N周期选择3。

基本概念大家都懂了,那如何根据KDJ值决定买入和卖出呢?

当J值上穿K值的时候,是买入信号,此时买入。

当J值下穿K值的时候,是卖出信号,此时卖出。

这个策略有用吗?让我们来试试看。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上噢,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),准备开始输入命令安装依赖。

当然,我更推荐大家用VSCode编辑器,把本文代码Copy下来,在编辑器下方的终端运行命令安装依赖模块,多舒服的一件事啊:Python 编程的最好搭档—VSCode 详细指南。

在终端输入以下命令安装我们所需要的依赖模块:

pip install backtrader

看到 Successfully installed xxx 则说明安装成功。

Backtrader基本使用请看我们前一篇文章:
backtrader教程—量化投资原来这么简单(1)

本文全部代码,请在Python实用宝典后台回复:量化投资4 进行下载。

2.单一KDJ策略

如果你以前没用过backtrader,请先看:

backtrader教程—量化投资原来这么简单(1)

进行学习,不然你会有点蒙。直接下载代码学习也是一种方式,但前提是你的自学本领够强。

首先我们需要先计算K、D、J三个值,前面我们也说过了他们的计算方式:

  • RSV = (收盘价-N周期最低价)/(N周期最高价-N周期最低价)*100
  • K值 = RSV的N周期加权移动平均值
  • D值 = K值的N周期加权移动平均值
  • J值 = 3K-2D

知道了计算方式,那之后的工作就简单了:

        # 9个交易日内最高价
        self.high_nine = bt.indicators.Highest(self.data.high, period=9)
        # 9个交易日内最低价
        self.low_nine = bt.indicators.Lowest(self.data.low, period=9)
        # 计算rsv值
        self.rsv = 100 * bt.DivByZero(
            self.data_close - self.low_nine, self.high_nine - self.low_nine, zero=None
        )
        # 计算rsv的3周期加权平均值,即K值
        self.K = bt.indicators.EMA(self.rsv, period=3)
        # D值=K值的3周期加权平均值
        self.D = bt.indicators.EMA(self.K, period=3)
        # J=3*K-2*D
        self.J = 3 * self.K - 2 * self.D

最后决定买入点和卖出点:

    # Python 实用宝典
    def next(self):
        self.log("Close, %.2f" % self.dataclose[0])
        if self.order:
            return

        if not self.position:
            # J - D 值
            condition1 = self.J[-1] - self.D[-1]
            condition2 = self.J[0] - self.D[0]
            if condition1 < 0 and condition2 > 0:
                self.log("BUY CREATE, %.2f" % self.dataclose[0])
                self.order = self.buy()

        else:
            condition = (self.dataclose[0] - self.bar_executed_close) / self.dataclose[0]
            if condition > 0.1 or condition < -0.1:
                self.log("SELL CREATE, %.2f" % self.dataclose[0])
                self.order = self.sell()

不过从卖出策略中可以看到,我暂时没有使用J下穿K值的方式来卖出股票,而是采用涨跌10%的限制性条件作为卖出信号,看看这样的策略表现如何。

这里和上篇文章一样,咱用10000元作为本金,对002859这只股票,回测其2010年1月1日至2020年4月21日期间的走势:

效果不是很好,本金10000元,最后剩余9892元,也就是还亏损了。从盈利和亏损点上来看,该策略确实亏损次数更多,比盈利次数多了一次。

不过这是我们基于限制性卖出的条件,如果是J值下穿K值作为卖出信号呢?

基于backtrader,我们做这样的买入卖出信号调整真的非常简单:

    # Python 实用宝典
    def next(self):
        self.log("Close, %.2f" % self.dataclose[0])
        if self.order:
            return

        condition1 = self.J[-1] - self.D[-1]
        condition2 = self.J[0] - self.D[0]
        if not self.position:
            # J - D 值
            if condition1 < 0 and condition2 > 0:
                self.log("BUY CREATE, %.2f" % self.dataclose[0])
                self.order = self.buy()

        else:
            if condition1 > 0 or condition2 < 0:
                self.log("SELL CREATE, %.2f" % self.dataclose[0])
                self.order = self.sell()

效果如何?

我勒个去,您这个不太靠谱啊,10000元本金只剩9029元了。

但是这样并没有足够证据否认这个策略的价值,接下来我们尝试将它和MACD策略结合在一起使用。

3.多策略回测

通过回测得到的图表,我发现,KDJ指标在决定买入信号的时候有很大的延迟,比MACD的买入信号延迟重得多,但是它的卖出信号却不错,很敏感。

所以我们可以考虑将MACD策略也引入进来,使用MACD决策买入,KDJ信号决策卖出。引入MACD策略相关变量:

        # MACD策略参数
        me1 = EMA(self.data, period=12)
        me2 = EMA(self.data, period=26)
        self.macd = me1 - me2
        self.signal = EMA(self.macd, period=9)
        bt.indicators.MACDHisto(self.data)

至于为什么MACD策略是这么计算的,请看我们上一篇文章:Python 量化投资原来这么简单(2) —MACD策略(+26.9%)。所以我们的文章是环环相扣的哦,如果没有阅读,请记得回头补上。

从上面两张图中,大家可以看到两条变化非常大的线,这是两条3日EMA的线。我们可以将其取消掉,因为它们没有太多价值。加一个plot=False参数即可让它们不显示:

        # 计算rsv的3周期加权平均值,即K值
        self.K = bt.indicators.EMA(self.rsv, period=3, plot=False)
        # D值=K值的3周期加权平均值
        self.D = bt.indicators.EMA(self.K, period=3, plot=False)

基于MACD策略的买入信号进行买入,KDJ策略的卖出信号进行卖出:

        if not self.position:
            # 买入基于MACD策略
            condition1 = self.macd[-1] - self.signal[-1]
            condition2 = self.macd[0] - self.signal[0]
            if condition1 < 0 and condition2 > 0:
                self.log('BUY CREATE, %.2f' % self.dataclose[0])
                self.order = self.buy()

        else:
            # 卖出基于KDJ策略
            condition1 = self.J[-1] - self.D[-1]
            condition2 = self.J[0] - self.D[0]
            if condition1 > 0 or condition2 < 0:
                self.log("SELL CREATE, %.2f" % self.dataclose[0])
                self.order = self.sell()

回测效果如下:

最终得到10057.06,赚了57块钱。。当然,总比单纯KDJ策略不赚的好。但是这个策略依然存在问题,它在很多能赚大钱的时候,过于保险地将股票卖出了,以至于其亏损的次数其实大于盈利的次数。

当然,单纯从一只股票上我们是无法看出这个策略的整体好坏的,下一篇量化投资文章(大约在2020/05/09),我们将在A股中随机取1000只股票,来验证这个复合策略的整体收益。敬请期待Python实用宝典的最新更新哦。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Pandas 性能优化

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。