Quantitative Investment series:

Backtrader — Quantitative Investing in Python (part 1)

MACD Strategy (+26.9%)

Python quantitative investment combat tutorial (3) — A share back test MACD strategy

Github Repository: github.com/Ckend/pytho…


Today we are going to use Backtrader to try out another quantitative investment strategy: the KDJ strategy, one of the most commonly used indicators, which is called “random indicator” in Chinese. It calculates random value (RSV) by identifying the proportion relationship among the highest price, lowest price and latest closing price within N trading days through statistical principle, and then calculates K value, D value and J value according to weighted moving average (EMA) method.

The specific calculation method is as follows:

  • RSV = (close price -n cycle low price)/(N cycle high price -n cycle low price) *100
  • K value = n-cycle weighted moving average of RSV
  • D value = n-periodic weighted moving average of K value
  • _k = 3-2 _d J value

Generally speaking, the n-period of RSV is 9, and the n-period of K and D is 3.

Now that you know the basic concepts, how do you decide to buy and sell based on the KDJ value?

When J crosses K, it is a buy signal.

When J goes below K, it’s a sell signal, so sell.

Does this strategy work? Let’s try it.

1. Prepare

Before you begin, make sure Python and PIP are successfully installed on your computer. If not, please visit this article: Super Detailed Python Installation Guide to install Python. If you are using Python for data analysis, you can install Anaconda directly: Python data analysis and mining helper – Anaconda

In Windows, open Cmd(Start – Run – Cmd). In Apple, open Terminal(command+ space enter Terminal).

Of course, I recommend that you use the VSCode editor, Copy this code, and run commands in the terminal below the editor to install dependency modules.

Enter the following command from the terminal to install the dependency modules we need:

pip install backtrader

If Successfully installed XXX is displayed, the installation is successful.

See our previous article: Backtrader Tutorial — Quantitative Investing tutorial (1)

You can download all the code for this article in Python: Quantitative Investment 4.

2. Single KDJ strategy

If you haven’t used Backtrader before, take a look:

Backtrader — Quantitative Investing (part 1)

Study, or you’ll be a little confused. Downloading code is another way to learn, but only if you are good at self-learning.

First of all, we need to calculate K, D and J. We have also mentioned their calculation methods previously:

  • RSV = (close price -n cycle low price)/(N cycle high price -n cycle low price) *100
  • K value = n-cycle weighted moving average of RSV
  • D value = n-periodic weighted moving average of K value
  • _k = 3-2 _d J value

Now that we know how to calculate, it’s easy:

        # 9 trading day high
        self.high_nine = bt.indicators.Highest(self.data.high, period=9)
        # 9 trading day low
        self.low_nine = bt.indicators.Lowest(self.data.low, period=9)
        # Calculate RSV value
        self.rsv = 100 * bt.DivByZero(
            self.data_close - self.low_nine, self.high_nine - self.low_nine, zero=None
        )
        # Calculate the 3-cycle weighted average of RSV, i.e. K value
        self.K = bt.indicators.EMA(self.rsv, period=3)
        # D value = 3-period weighted average of K value
        self.D = bt.indicators.EMA(self.K, period=3)
        # J=3*K-2*D
        self.J = 3 * self.K - 2 * self.D
Copy the code

Finally decide on buy and sell points:

    # Python utility guide
    def next(self):
        self.log("Close, %.2f" % self.dataclose[0])
        if self.order:
            return

        if not self.position:
            # j-d value
            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]
            ifCondition > 0.1 or condition < -0.1: self.log()"SELL CREATE, %.2f" % self.dataclose[0])
                self.order = self.sell()
Copy the code

However, as can be seen from the sell strategy, I did not use the way of J under K to sell the stock for the time being. Instead, I used the 10% restriction as a sell signal to see how this strategy performed.

Here, as in the previous article, I use 10,000 yuan as the principal to backtest the trend of 002859 stock from January 1, 2010 to April 21, 2020:

The effect was not very good. The principal was 10,000 yuan, and 9,892 yuan was left, that is, there was still a loss. From the point of gain and loss, the strategy did lose more times, one more than the profit.

But this is our restrictive sell condition, what if we put K under J as a sell signal?

With BackTrader, it’s really easy for us to do this buy/sell signal adjustment:

    # Python utility guide
    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 value
            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()
Copy the code

What was the effect?

Oh, my god. That’s not a good one. 10,000 yuan of principal, 9,029 yuan left.

However, there is not enough evidence to deny the value of this strategy. Next, we try to combine it with MACD strategy.

3. Perform multiple policy test

Looking back at the charts, I found that the KDJ indicator has a big delay in determining a buy signal, much more than the MACD, but its sell signal is good and sensitive.

Therefore, we can consider the introduction of MACD strategy, using MACD decision to buy, KDJ signal decision to sell. MACD policy-related variables are introduced:

        # MACD Policy parameters
        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)
Copy the code

As to why the MACD strategy is calculated this way, see our previous article: Python Quantitative Investing Tutorial (2) — MACD Strategy (+26.9%). So our articles are linked, if you haven’t read them, please remember to catch up.

In the two pictures above, you can see two very different lines. These are two 3-day EMA lines. We can eliminate them because they don’t have much value. Add a plot=False argument to keep them from showing:

        # Calculate the 3-cycle weighted average of RSV, i.e. K value
        self.K = bt.indicators.EMA(self.rsv, period=3, plot=False)
        # D value = 3-period weighted average of K value
        self.D = bt.indicators.EMA(self.K, period=3, plot=False)
Copy the code

Buy based on the buy signal of MACD strategy and sell based on the sell signal of KDJ strategy:

        if not self.position:
            # Buy based on 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:
            # Sell based on KDJ strategy
            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()
Copy the code

The test results are as follows:

I got 10057.06 and made 57 yuan. Of course, it’s better than nothing with a pure KDJ strategy. The problem with this strategy, however, is that it sold too safely when it could have made a lot of money, so that it actually lost more money than it gained.

Of course, we cannot see the overall quality of this strategy from A single stock. In the next quantitative investment article (about 2020/05/09), we will randomly select 1000 stocks from A shares to verify the overall return of this composite strategy. Stay tuned for the latest updates to the Python Utility Bible.

So that’s the end of our article, if you enjoyed our Python tutorial today, please keep checking us out, and if it helped, please give us a thumbs up/check it out below. If you have any questions, please leave them in the comments below, and we’ll be patient to answer them!


Python utility guide

It’s not just a bible

Welcome to Python

Quantitative Investing in Python (part 4) — KDJ Strategy