【Python】株価データ分析 株価チャートを描く～mplfinance編 その１～

## 修正（2021.11.27)

データ（株価データ）によっては，
高値と安値の線を引くためのデータ（hlinesに渡すデータ）がfloatでないというエラーが発生しましたので，

```python
# エラー箇所
hlines=[df['High'].max(), df['Low'].min()]
```

次のように修正しています

```python
# float変換
max = float(df['High'].max())
min = float(df['Low'].min())
hlines=[max, min]
```

## はじめに

前回の[【Python】東証上場銘柄の株価データを取得する（その２）](https://qiita.com/tnozoo/items/fd684087f4d9b3dec8cb)では
pandas_datareader を使って株価データを取得した

Python で株価チャートを描くには mplfinace，plotly を使うのがよさそうで，
今回は取得した株価データをmplfinanceを使って株価チャートを描いてみたい

まずは，mplfinace編 その１として，いくつかのチャートを描いてみたい
本記事を書く上で，[matplotlib/mplfinance](https://github.com/matplotlib/mplfinance)を参考にしている

## 準備

まずはともかく，mplfinance のインストールをする

conda の場合

```
conda install mplfinance
```

pip の場合

```
pip install mplfinance
```

## データ用意

自分銘柄一覧（my.xlsx）と東証上場銘柄一覧（date_j.xls）を読み込む

[前回](https://qiita.com/tnozoo/items/fd684087f4d9b3dec8cb)を参考にしてほしいが，自分銘柄一覧（my.xlsx）とは，自分の保有銘柄の一覧で（仮に，トヨタ，日産，ホンダ，ＡＮＡ，ＪＡＬを保有しているとしている），
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/ca9b4323-fabf-cbb3-ecce-717176ef5c00.png)
東証上場銘柄一覧（data_j.xls）とは，[日本取引所グループ](https://www.jpx.co.jp/markets/statistics-equities/misc/01.html)にある東証上場銘柄の一覧ファイルのことだ

まずは，自分銘柄と東証上場銘柄一覧を読み込んで，自分銘柄のDataFrameを作る

```python
import pandas as pd
import pandas_datareader.data as pdr
import datetime
from dateutil.relativedelta import relativedelta
## 自分銘柄と東証上場銘柄一覧を読み込む
my_df = pd.read_excel('my.xlsx', sheet_name = 'Sheet1', dtype = str)
topix_df = pd.read_excel('data_j.xls', dtype = str)
## 自分銘柄のDataFrameを作る
code_set = set(my_df['コード'].tolist())
df = topix_df[topix_df['コード'].isin(code_set)]
df
```

<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>日付</th>
      <th>コード</th>
      <th>銘柄名</th>
      <th>市場・商品区分</th>
      <th>33業種コード</th>
      <th>33業種区分</th>
      <th>17業種コード</th>
      <th>17業種区分</th>
      <th>規模コード</th>
      <th>規模区分</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>2886</th>
      <td>20211029</td>
      <td>7201</td>
      <td>日産自動車</td>
      <td>市場第一部（内国株）</td>
      <td>3700</td>
      <td>輸送用機器</td>
      <td>6</td>
      <td>自動車・輸送機</td>
      <td>2</td>
      <td>TOPIX Large70</td>
    </tr>
    <tr>
      <th>2888</th>
      <td>20211029</td>
      <td>7203</td>
      <td>トヨタ自動車</td>
      <td>市場第一部（内国株）</td>
      <td>3700</td>
      <td>輸送用機器</td>
      <td>6</td>
      <td>自動車・輸送機</td>
      <td>1</td>
      <td>TOPIX Core30</td>
    </tr>
    <tr>
      <th>2926</th>
      <td>20211029</td>
      <td>7267</td>
      <td>本田技研工業</td>
      <td>市場第一部（内国株）</td>
      <td>3700</td>
      <td>輸送用機器</td>
      <td>6</td>
      <td>自動車・輸送機</td>
      <td>1</td>
      <td>TOPIX Core30</td>
    </tr>
    <tr>
      <th>3793</th>
      <td>20211029</td>
      <td>9201</td>
      <td>日本航空</td>
      <td>市場第一部（内国株）</td>
      <td>5150</td>
      <td>空運業</td>
      <td>12</td>
      <td>運輸・物流</td>
      <td>4</td>
      <td>TOPIX Mid400</td>
    </tr>
    <tr>
      <th>3794</th>
      <td>20211029</td>
      <td>9202</td>
      <td>ＡＮＡホールディングス</td>
      <td>市場第一部（内国株）</td>
      <td>5150</td>
      <td>空運業</td>
      <td>12</td>
      <td>運輸・物流</td>
      <td>2</td>
      <td>TOPIX Large70</td>
    </tr>
  </tbody>
</table>
</div>

チャートを描き方を学ぶのが目的なので，先頭の銘柄（日産自動車）だけにしておく

```python
code = df['コード'].tolist()[0]
company = df['銘柄名'].tolist()[0]
```

６か月分のデータを取得

```python
ed = datetime.datetime.now() # 本日
st = ed - relativedelta(months = 6) # 6か月前
df = pdr.DataReader(code + '.T', 'yahoo', st, ed)
```

これでデータの準備はできた

## ローソク足を描く

```python
import mplfinance as mpf
mpf.plot(data = df, type = 'candle')
```
![output_13_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/30ac7215-9f27-0047-d86c-e1446bf7b20f.png)

mplfinance をインポートして，plot 関数を呼ぶ
plot に渡す data は，DataFrame で，Open，High，Low，Closeの列が必要
index は，DatetimeIndex の必要がある
pandas_datareaderを使って取得した株価データは，これらの要件を満たしているので何も考えなくてもよい


```python
>>> type(df)
pandas.core.frame.DataFrame

>>> df.columns
Index(['High', 'Low', 'Open', 'Close', 'Volume', 'Adj Close'], dtype='object')

>>> type(df.index)
pandas.core.indexes.datetimes.DatetimeIndex
```

## 出来高を表示する

volume = True とするだけでよい

```python
mpf.plot(df, type = 'candle', volume = True)
```
![output_20_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/eedf8faf-6036-ae31-7555-63df3f8a8ef9.png)

## 移動平均を表示する

mavで日数を渡せばよい

２つでも，３つでも日数を並べればよい

```python
mpf.plot(df, type = 'candle', volume = True, mav = (9,17))
```
![output_24_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/27192a50-f13c-9603-6c3b-faead06fda48.png)

```python
mpf.plot(df, type = 'candle', volume = True, mav = (9,17,26))
```
![output_25_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/784b4058-cd56-6fa6-f79f-ee92cfe0ff29.png)

## スタイルを変える

まずはよく使う設定の辞書を作っておく

```python
kwargs = dict(type = 'candle', volume = True, mav = (9,17,26))
```

使えるスタイルは

```python
>>> mpf.available_styles()
    ['binance',
     'blueskies',
     'brasil',
     'charles',
     'checkers',
     'classic',
     'default',
     'ibd',
     'kenan',
     'mike',
     'nightclouds',
     'sas',
     'starsandstripes',
     'yahoo']
```

yahoo

```python
## yahoo
mpf.plot(df, **kwargs, style = 'yahoo')
```
![output_30_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/61a7e8a0-5ebe-ead0-3566-1a4221e33e7a.png)

starsandstripes

```python
## starsandstripes
mpf.plot(df, **kwargs, style = 'starsandstripes')
```
![output_32_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/9dfa3597-63a5-4a7b-60be-df5aefa12dcf.png)

## 線を引く

期間内の，高値と安値に線を引いてみる

ちなみに，高値と安値は

```python
>>> df['High'].max(), df['Low'].min()
(654.2999877929688, 516.5)
```

設定の辞書でyahooにしておく

```python
kwargs = dict(type = 'candle', volume = True, mav = (9,17,26), style = 'yahoo')
```

hlines で横線を引く際の y座標（株価）を指定する
終値ベースでの高値と安値

```python
mpf.plot(df, **kwargs, hlines = [float(df['Close'].max()), float(df['Close'].min())])
```
![output_36_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/2fe50c48-7b0f-9dea-6058-4a9bd5948c17.png)


ちょっと線が太いので，線幅を指定する
（終値から，高値，安値に変えておく）
先ほどは，hlines にリストを渡していたが，辞書を渡す
辞書にy座標（株価）と線幅を渡す

```python
max = float(df['High'].max())
min = float(df['Low'].min())
mpf.plot(df, **kwargs, hlines = dict(hlines=[max, min], linewidths=(.5, .5)))
```
![output_38_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/c7b2d7df-9903-1469-8056-35f7f397da3e.png)
うん，細くなった，素敵

次は，安値と高値を結んだ線を引いてみる

高値をとった日は

```python
>>> df['High'].idxmax()
Timestamp('2021-11-19 00:00:00')
```

安値をとった日は

```python
>>> df['Low'].idxmin()
Timestamp('2021-10-07 00:00:00')
```

設定の辞書でstarsandstripesにしておいて，
ごちゃごちゃしてきそうなので，移動平均もついでにやめておく

```python
kwargs = dict(type = 'candle', style = 'starsandstripes')
```

alines に，2点の座標（安値と高値）を渡す必要があるので，
two_points に，安値の座標（安値をとった日付，安値）と高値の座標（高値をとった日付，高値）を設定する

```python
two_points  = [(df['High'].idxmax(), df['High'].max()),(df['Low'].idxmin(),df['Low'].min())]
mpf.plot(df, **kwargs,
            hlines = dict(hlines=[max, min], linewidths=(.5, .5), colors=('r','r')),
            alines = dict(alines=two_points, linewidths=(.5), colors=('b')))
```
![output_45_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/2fc6aa06-152c-21d9-62c5-4e8515c6d75b.png)
いいね！

線を太くし，透かす
それぞれ，linewidth，alphaで設定する

```python
mpf.plot(df, **kwargs,
            hlines = dict(hlines=[max, min], linewidths=(.5, .5), colors=('r','r')),
            alines = dict(alines=two_points, linewidths=(40), colors=('b'), alpha=0.2))
```
![output_46_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/09d1c56c-97ec-fa0e-cacf-b2490ff3e800.png)
いいね！！

## グラフをファイルに出力する

savefig に，ファイル名(fname）とDPIを与える

```python
mpf.plot(df, **kwargs,
            hlines = dict(hlines=[max, min], linewidths=(.5, .5), colors=('r','r')),
            alines = dict(alines=two_points, linewidths=(40), colors=('b'), alpha=0.2),
            savefig = dict(fname='nissan.png',dpi=100))
```

## おわりに

今回は，株価チャートを mplfinance を使って描いてみた
次回は，MACDやボリンジャーバンドを描いたり，
複数銘柄を並べて描くようなことをやってみたい