PythonでYahoo!ファイナンスの時系列データで75日移動平均線を表示する

# 目次
株のデータ収集についての記事一覧を[こちら](https://qiita.com/fjunya/items/dbe5ef36246c88acd983)に記載しております。

# 参考記事
[Pythonで日経平均の推移を観察する (with Quandl API)](https://qiita.com/dark_thiele/items/072008b9bdf1145237fc)

# 目的
- Yahoo!ファイナンスから取得した時系列データを使用して株価のチャートを表示
- Yahoo!ファイナンスから取得した時系列データを使用して移動平均線を表示

# 事前準備
- [PythonでYahoo!ファイナンスの時系列データをDBに登録する](https://qiita.com/fjunya/items/626525eadbf98d34df4f)の作業が終わっていること
- pandas、matplotlibをインストールする

# 実装
## 株価チャートを表示
Djangoのカスタムコマンドを使用して株価チャートを表示する処理を実装します。Djangoのカスタムコマンドの使用方法については[こちら](https://docs.djangoproject.com/en/2.2/howto/custom-management-commands/)をご参照ください。
引数に証券コードとデータ表示開始月を指定するコマンドを作成します。

```python:view_stock_chart.py
from django.core.management.base import BaseCommand
from app.models import RawPrices
import pandas as pd
import matplotlib.pyplot as plt

import logging
logger = logging.getLogger(__name__)


class Command(BaseCommand):
    help = ''

    def add_arguments(self, parser):
        parser.add_argument('code', type=int, help="証券コードを指定してください")
        parser.add_argument('start_date', type=str, help="yyyy-mm形式で指定してください")

    def handle(self, *args, **options):
        self.view_stock_chart(options['code'], options['start_date'])

    def view_stock_chart(self, code, start_date):
        rawPrices = RawPrices.objects\
            .filter(code=code)\
            .filter(date__gt=start_date + "-01")\
            .order_by('date')
        rawPriceList = list(map(lambda x: [x.date, x.open_price, x.close_price], rawPrices))
        columns = ["date", "open_price", "close_price"]
        df = pd.DataFrame(rawPriceList, columns=columns)
        df.date = pd.to_datetime(df.date)
        df.set_index("date", inplace=True) #inplace=Falseの場合は返り値のみに状態が反映される
        df.plot()
        plt.xlabel('Date')
        plt.ylabel('Stock price')
        plt.show()
```
コマンドを実行して株価チャートを表示する。
今回はサイボウズ(証券コード:4776)の2019年の株価を表示

```
python manage.py view_stock_chart 4776 2019-01
```
![cybozu_chart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149245/5499f8bc-616d-4c32-892f-a5ccf175e773.png)

##75日移動平均線を表示
###移動平均線とは
移動平均線とは、一定期間の株価の平均値を線としてつなぎ合わせた指標。
###移動平均線の計算方法
移動平均線の計算方法は[マネーパートナーズ](https://www.moneypartners.co.jp/support/tech/sma.html)と[楽天証券](https://faq.rakuten-sec.co.jp/faq_detail.html?id=1102025)の計算方法を参考にしております。
5日移動平均線を計算する場合は以下のような計算式になります。
（1日目終値＋2日目終値＋3日目終値＋4日目終値＋5日目終値）÷5

| 日       |       終値 |
|:-----------------|------------------:|
| 1日目             |              100円 |
| 2日目             |              110円 |
| 3日目             |              90円 |
| 4日目             |              100円 |
| 5日目             |              130円 |
| 6日目             |              130円 |
上記表の場合の5日移動平均線の計算式は以下のようになります。
(100 + 110 + 90 + 100 + 130) ÷ 5 = 106

###pandasのrollingを使用して移動平均値を求める
pandasのrollingを使用すると簡単に移動平均を求めることが可能です。
rollingを使うと以下のように簡単に移動平均を求められます。

```python
df = pd.DataFrame([100,110,90,100,130,130])
print(df.rolling(window=5).mean()) #5移動平均を表示
```
実行結果

```
       0
0    NaN
1    NaN
2    NaN
3    NaN
4  106.0
5  112.0
```
(100+110+90+100+130)÷5の計算結果が106になります。
(110+90+100+130+130)÷5の計算結果が112になります。 
###75日移動平均線を表示する
view_stock_chart.pyを以下のように修正します。

```python:view_stock_chart.py
from django.core.management.base import BaseCommand
from app.models import RawPrices
import pandas as pd
import matplotlib.pyplot as plt
import datetime

import logging
logger = logging.getLogger(__name__)


class Command(BaseCommand):
    help = ''

    def add_arguments(self, parser):
        parser.add_argument('code', type=int, help="証券コードを指定してください")
        parser.add_argument('start_date', type=str, help="yyyy-mm形式で指定してください")

    def handle(self, *args, **options):
        self.view_stock_chart(options['code'], options['start_date'])

    def view_stock_chart(self, code, start_date_str):
        start_date = datetime.datetime.strptime(start_date_str + "-01", "%Y-%m-%d")
        # 75日移動平均線を求める為に余分にデータを取得。土日を考慮して110日より前から取得
        rawPrices = RawPrices.objects\
            .filter(code=code)\
            .filter(date__gt=start_date - datetime.timedelta(days=110))\
            .order_by('date')
        rawPriceList = list(map(lambda x: [x.date, x.open_price, x.close_price], rawPrices))
        columns = ["date", "open_price", "close_price"]
        df = pd.DataFrame(rawPriceList, columns=columns)
        df.date = pd.to_datetime(df.date)
        df.set_index("date", inplace=True)
        df.loc[start_date_str:, ['open_price', 'close_price']].plot()
        # 移動平均線を求める為に、全てのデータから計算(表示する期間だけで計算すると最初の方の移動平均線を求められない為)
        roll_mean = df.close_price.rolling(window=75).mean() #75日移動平均線を求めるので75を指定
        # 移動平均線を表示
        roll_mean.loc[start_date_str:].plot()
        plt.xlabel('Date')
        plt.ylabel('Stock price')
        plt.show()
```
サイボウズ(証券コード:4776)の2018年10月からの株価と移動平均線を表示

```
python manage.py view_stock_chart 4776 2018-10
```
緑の線が75日移動平均線となります。
![cybozu_moving_average.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149245/7546d0a2-6f61-83a2-8ca1-6ac2004ef1ff.png)