株価分析(MACD)

# はじめに

前回の記事、[株価分析(RSI)](https://qiita.com/mahoutsukaino-deshi/items/ebe897c06e8f71851a24) の続編です。今回はMACDを使用します。MACDは移動平均を使った指標です。前にSMA(単純移動平均線)についての記事を書いていますが、MACDではEMA(指数平滑移動平均線)を使用しています。MACDについての詳しい説明は他に譲るとして[^1]、早速使っていきたいと思います。
MACDの戦略は下記のようにしました。

- MACDとMACDシグナルのゴールデンクロスで買い
- MACDとMACDシグナルのデッドクロスで売り
- MACDがマイナスからプラスになったら買い
- MACDがプラスからマイナスになったら売り

今回は下記のような流れで進めていきたいと思います。

1. 2011年〜2018年の8年間で最適な長期、短期、シグナル期間の組み合わせを見つける。
2. 上記の最適な組み合わせを使用して、2019年〜2020年のシミュレートを行う。
3. 2011年〜2020年の10年間の最適な長期、短期、シグナル期間の組み合わせを見つける。

[^1]: MINKABのページ「[MACDとは？特徴・使い方を基礎から応用まで徹底解説](https://fx.beginner.minkabu.jp/startfx/technical_macd.html)」の説明が詳しいですね。

# MACD Strategyクラス

MACD Strategyクラスは下記のように実装しました。
MACDの計算はいつも通りTA-Libで行っています。
期間はTA-Libのデフォルト値と同じ値にしています。

```python
class MacdStrategy(Strategy):
    '''
    MACD Strategy
    '''
    fastperiod = 12
    slowperiod = 26
    signalperiod = 9

    def init(self):
        close = self.data['Adj Close']
        self.macd, self.macdsignal, _ = self.I(
            talib.MACD, close,
            fastperiod=self.fastperiod,
            slowperiod=self.slowperiod,
            signalperiod=self.signalperiod)

    def next(self):
        '''
        MACDとMACDシグナルのゴールデンクロスで買い
        MACDとMACDシグナルのデッドクロスで売り
        MACDがマイナスからプラスになったら買い
        MACDがプラスからマイナスになったら売り
        '''
        if crossover(self.macd, self.macdsignal):
            self.buy()
        elif crossover(self.macd, self.macdsignal):
            self.sell()
        elif crossover(self.macd, 0):
            self.buy()
        elif crossover(0, self.macd):
            self.sell()
```

このデフォルト値を使った状態で2011年〜2020年の日経平均株価でをシミュレートしてみるとリターンは177%でした。年率で考えると10.7%です。前回求めたRSIの最適値でのリターンが214%(年率13.5%)だったことを考えると、期待できそうな予感がします。

# 2011年〜2018年の8年間の最適な組み合わせを見つける

日経平均株価を使用して、2011年〜2018年の8年間の最適な組み合わせを見つけていきます。
各期間の範囲は下記のようにしました。
また、EMA長期期間 > EMA短期期間 となるように制約も入れています。

|期間|最小値|最大値|
|-|-:|-:|
|EMA短期|5|50|
|EMA長期|5|50|
|MACDシグナル期間|5|50|

```python
    bt = Backtest(
        df,
        MacdStrategy,
        cash=INIT_CASH,
        trade_on_close=False,
        exclusive_orders=True
    )

    stats, heatmap = bt.optimize(
        fastperiod=range(5, 51),
        slowperiod=range(5, 51),
        signalperiod=range(5, 51),
        return_heatmap=True,
        constraint=lambda p: p.fastperiod < p.slowperiod)
```
この期間の最適な組み合わせでのリターンは216%でした。8年間で216%なので、年率で考えると15.4%くらいになります。

```text
Start                     2011-01-04 00:00:00
End                       2018-12-28 00:00:00
Duration                   2915 days 00:00:00
Exposure Time [%]                     97.1007
Equity Final [$]                  3.16202e+06
Equity Peak [$]                    3.6104e+06
Return [%]                            216.202
Buy & Hold Return [%]                 92.4849
Return (Ann.) [%]                     15.9004
Volatility (Ann.) [%]                 23.5399
Sharpe Ratio                         0.675464
Sortino Ratio                         1.12638
Calmar Ratio                         0.599543
Max. Drawdown [%]                    -26.5209
Avg. Drawdown [%]                    -3.45087
Max. Drawdown Duration      484 days 00:00:00
Avg. Drawdown Duration       32 days 00:00:00
# Trades                                  145
Win Rate [%]                          62.7586
Best Trade [%]                        18.9492
Worst Trade [%]                      -10.4943
Avg. Trade [%]                       0.799388
Max. Trade Duration          84 days 00:00:00
Avg. Trade Duration          20 days 00:00:00
Profit Factor                         1.79997
Expectancy [%]                       0.889616
SQN                                    2.0116
_strategy                 MacdStrategy(fas...
_equity_curve                             ...
_trades                        Size  Entry...
```

最適な期間の組み合わせは、EMA短期=9日、EMA長期=48日、シグナル=５日 となりました。

```text
MacdStrategy(fastperiod=9,slowperiod=48,signalperiod=5)
```

# 2019年〜2020年の2年間でシミュレートしてみる

では、上記の最適値を使って2019年〜2020年をシミュレートしてみます。
MacdStrategyクラス内の期間を下記のように変更してプログラムを実行します。

```python
class MacdStrategy(Strategy):
    '''
    MACD Strategy
    '''
    fastperiod = 9
    slowperiod = 48
    signalperiod = 5
    (以下省略)
```
下記が実行結果です。リターンは54%と少なく感じますが、2年間なので年率に換算すると24%くらいになりかなり良い結果です。2019年〜2020年の間にはコロナによる株価の暴落もあったのですが、それもうまく乗り越えられたようです。

```text
Start                     2019-01-04 00:00:00
End                       2020-12-30 00:00:00
Duration                    726 days 00:00:00
Exposure Time [%]                     87.3706
Equity Final [$]                  1.54643e+06
Equity Peak [$]                   1.54694e+06
Return [%]                             54.643
Buy & Hold Return [%]                 40.2936
Return (Ann.) [%]                     25.5397
Volatility (Ann.) [%]                 22.5301
Sharpe Ratio                          1.13358
Sortino Ratio                         2.23523
Calmar Ratio                          1.62558
Max. Drawdown [%]                    -15.7111
Avg. Drawdown [%]                     -3.0758
Max. Drawdown Duration      194 days 00:00:00
Avg. Drawdown Duration       25 days 00:00:00
# Trades                                   27
Win Rate [%]                          51.8519
Best Trade [%]                        16.1861
Worst Trade [%]                       -6.4028
Avg. Trade [%]                        1.63782
Max. Trade Duration          64 days 00:00:00
Avg. Trade Duration          24 days 00:00:00
Profit Factor                         2.82347
Expectancy [%]                        1.77853
SQN                                   1.72547
_strategy                        MacdStrategy
_equity_curve                             ...
_trades                       Size  EntryB...
```

# 2010年〜2020年の10年間の最適な組み合わせを見つける

では、10年間を通した最適な組み合わせはどうなるのでしょうか？
結果だけを載せます。

```text
Start                     2011-01-04 00:00:00
End                       2020-12-30 00:00:00
Duration                   3648 days 00:00:00
Exposure Time [%]                     97.7134
Equity Final [$]                  5.74037e+06
Equity Peak [$]                   5.74225e+06
Return [%]                            474.037
Buy & Hold Return [%]                 163.934
Return (Ann.) [%]                        19.7
Volatility (Ann.) [%]                 23.7815
Sharpe Ratio                         0.828377
Sortino Ratio                          1.4699
Calmar Ratio                         0.702859
Max. Drawdown [%]                    -28.0284
Avg. Drawdown [%]                    -2.88859
Max. Drawdown Duration      925 days 00:00:00
Avg. Drawdown Duration       32 days 00:00:00
# Trades                                  227
Win Rate [%]                          55.9471
Best Trade [%]                        22.0555
Worst Trade [%]                      -10.5505
Avg. Trade [%]                       0.775317
Max. Trade Duration          80 days 00:00:00
Avg. Trade Duration          16 days 00:00:00
Profit Factor                         1.92129
Expectancy [%]                       0.856358
SQN                                   2.87072
_strategy                 MacdStrategy(fas...
_equity_curve                             ...
_trades                        Size  Entry...
```

なんとリターンは474%となりました。年率に換算すると19%です。
最適な期間の組み合わせは、EMA短期=5日、EMA長期=47日、シグナル=6日 となりました。

```text
MacdStrategy(fastperiod=5,slowperiod=47,signalperiod=6)
```

# 最後に

時期や銘柄によって最適な組み合わせは変化すると思いますが、このMACDは活用できそうです。
MACDは人気のある指標だと言われていますが、その理由がわかったような気がします。
これまでの結果を下記にまとめておきます。

|指標|リターン(10年)|リターン(年率)|売買戦略|
|-|-:|-:|-|
|SMA|140%|9%|短期と長期のゴールデンクロス/デッドクロスで売買。|
|RSI|214%|12%|基準となる上限/下限を超えたときに売買。|
|MACD|474%|19%|MACDとMACDシグナルのゴールデンクロス/デッドクロスで売買。<br/>MACDの符号が変わったときに売買。|
※年率は複利換算。

プログラムソースは[GitHub](https://github.com/mahoutsukaino-deshi/stock_macd)に置いています。