【データ可視化】株・ビットコイン・為替

# 用語

`テクニカル指標`

- ***<font color="LightSeaGreen">移動平均</font>***
    - **過去〇〇日分の平均**
    - ゴールデンクロス
        - 「短期の移動平均線」が「中期以上の移動平均線」を下から上に抜けること
        - 価格が上昇しているサイン
    - デッドクロス
        - 「短期の移動平均線」が「中期以上の移動平均線」を上から下に抜けること
        - 価格が下降しているサイン
- ***<font color="LightSeaGreen">MACD</font>***
    - **トレンドを見る指標**
        - 0以上なら上昇トレンド
        - 0以下なら下降トレンド
- ***<font color="LightSeaGreen">RSI</font>***
    - **売られ過ぎ・買われ過ぎを判断する指標**
        - 20〜30%を下回る・・・売られ過ぎ
            - 「買い」と判断する
        - 70〜80%を上回る・・・買われ過ぎ
            - 「売り」と判断する
- ***<font color="LightSeaGreen">ボリンジャーバンド</font>***
    - **売られ過ぎ・買われ過ぎを判断する指標**
    - 移動平均などの一定期間の平均に対して、一定期間の標準偏差を足したものと引いたものの2本のラインを引く
        - 一般的にプラスマイナス「標準偏差の2倍」を使うことが多い
        - 統計学の考え方から終値はこの2本の間に収まると考えられる
        - 収まらなかった場合は、売られ過ぎ・買われ過ぎだと判断する

:::note
これらの指標を用いて分析をし、**株の売買の意思決定**が行われている。
**株**の他、**Bitcoin**や**為替**、**FX**にも活用可能。
:::

:::note
これらのテクニカル指標の追加は、**pandas_datareader**や**TA-Lib**というライブラリを使用することで簡単に出来る。
:::



# 前提

Dockerのインストールを済ませておく（目安：5分）

https://qiita.com/rexid/items/dd3db91b612f0c70097c

# 環境構築
<font color="Crimson">TA-Libのインストールは環境によって上手くいかない</font> or <font color="Crimson">インストール出来るとしても手順として複雑になるケースがある</font>為、Dockerを使い環境構築を行う。

## 1. 任意のフォルダを作成
今回は`Documents/Python/data_analysis`

## 2. Dockerfileを作成し、フォルダに格納

```Dockerfile:Dockerfile
FROM --platform=linux/amd64 ubuntu:20.04

RUN apt-get update && apt-get install -y sudo wget vim curl gawk make gcc

RUN wget https://repo.continuum.io/archive/Anaconda3-2019.03-Linux-x86_64.sh && \
    sh Anaconda3-2019.03-Linux-x86_64.sh -b  && \
    rm -f Anaconda3-2019.03-Linux-x86_64.sh && \
    sudo curl -sL https://deb.nodesource.com/setup_10.x | sudo bash -  && \
    sudo apt-get install -y nodejs

ENV PATH $PATH:/root/anaconda3/bin

RUN pip install --upgrade pip
RUN pip install pandas_datareader
RUN pip install mplfinance

RUN wget --quiet http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz -O ta-lib-0.4.0-src.tar.gz && \
    tar xvf ta-lib-0.4.0-src.tar.gz && \
    cd ta-lib/ && \
    ./configure --prefix=/usr && \
    make && \
    sudo make install && \
    cd .. && \
    pip install TA-Lib && \
    rm -R ta-lib ta-lib-0.4.0-src.tar.gz

RUN mkdir /workspace

CMD ["jupyter-lab", "--ip=0.0.0.0","--port=8888" ,"--no-browser", "--allow-root", "--LabApp.token=''"]
```

## 3. ビルド
```terminal
$ docker build -t 任意のタグ名:latest フォルダまでのパス
```
:::note
パスはファイルを直接ドラックアンドドロップすれば入力される
:::

```terminal:ここまでの例
(base) sample@SampleMBP ~ % cd ~/Documents/Python/data_analysis/
(base) sample@SampleMBP data_analysis % ls
Dockerfile
(base) sample@SampleMBP data_analysis % docker build -t da:latest /Users/sample/Documents/Python/data_analysis
```

コマンド実行後、完了まで20分以上要する


## 4. イメージIDを確認
```terminal
$ docker images
```

```terminal:実行結果例
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
da           latest    87dc656c5b2f   2 minutes ago   3.86GB
```


## 5. JupyterLabを起動
```terminal
$ docker run -p ローカルの任意のポート番号:8888 -v フォルダまでのパス:/workspace -–name ビルド時のタグ名 イメージID
```

```terminal:例
(base) sample@SampleMBP data_analysis % docker run -p 8888:8888 -v /Users/sample/Documents/Python/data_analysis:/workspace --name da 87dc656c5b2f
```

***コマンド実行後にブラウザで下記URLにアクセスし、JupyterLabが起動したら環境構築完了🎉***
（例）http://127.0.0.1:8888/

![スクリーンショット 2022-10-15 16.49.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/5359b68d-10ce-616f-8815-defa04f751e4.png)

---

:::note
ローカルと同期されている為、workspaceディレクトリに移動すればDockerfileが存在することを確認できる
:::

![スクリーンショット 2022-10-15 16.53.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/6075ad7d-6a32-8535-e5a1-ee90b512724b.png)

:::note
workspaceディレクトリ配下に任意の実行ファイルを作成する
:::




# テクニカル指標を表示させる関数を作成

## 1. ライブラリのインポート

```py
import pandas as pd
import talib as ta
# ファイナンスに特化した可視化ライブラリ
import mplfinance as mpf
# 日経平均やNASDAQ、個別銘柄の株価データを取得できるライブラリ
from pandas_datareader import data
# matplotlibのpyplotモジュールを使用
import matplotlib.pyplot as plt
# JupyterLab上で作成したグラフを表示
%matplotlib inline
import warnings
# すべての警告を表示させない
warnings.simplefilter('ignore')
```

## 2. 共通処理を関数として定義

```py
def data_analysis(df):

    date = df.index
    close = df['Adj Close']

    # 過去5日、25日、50日の移動平均を算出する為に定義
    span01 = 5
    span02 = 25
    span03 = 50

    # 移動平均を算出。smaは単純移動平均の略称
    df['sma01'] = close.rolling(window=span01).mean()
    df['sma02'] = close.rolling(window=span02).mean()
    df['sma03'] = close.rolling(window=span03).mean()

    plt.figure(figsize=(30, 60))

    # 移動平均
    plt.subplot(5,1,1)
    plt.plot(date, close, label='Adj Close', color='#99b898')
    plt.plot(date, df['sma01'], label='sma01', color='#e84a5f')
    plt.plot(date, df['sma02'], label='sma02', color='#ff847c')
    plt.plot(date, df['sma03'], label='sma03', color='#feceab')

    # 出来高
    plt.subplot(5,1,2)
    plt.bar(date, df['Volume'], label='Volume', color='gray')
    plt.legend()

    # MACD
    plt.subplot(5,1,3)
    df['macd'], df['macdsignal'], df['macdhist'] = ta.MACD(close, fastperiod=12, slowperiod=26, signalperiod=9)
    plt.fill_between(date, df['macdhist'], color='gray', alpha=0.5, label='MACD_hist')
    plt.hlines(0, start_date, end_date, 'gray', linestyles='dashed')
    plt.legend()

    # RSI
    plt.subplot(5,1,4)
    df['RSI'] = ta.RSI(close, timeperiod=span02)
    plt.plot(date, df['RSI'], label='RSI', color='gray')
    plt.ylim(0, 100)
    plt.hlines([30, 50, 70], start_date, end_date, 'gray', linestyles='dashed')
    plt.legend()

    # ボリンジャーバンド
    plt.subplot(5,1,5)
    df['upper'], df['middle'], df['lower'] = ta.BBANDS(close, timeperiod=span02, nbdevup=2, nbdevdn=2, matype=0)
    plt.plot(date, close, label='Adj Close', color='#99b898')
    plt.fill_between(date, df['upper'], df['lower'], color='gray', alpha=0.3)
    plt.legend()
```


# 日経平均株価のデータ可視化
```py
start_date = '2021-01-01'
end_date = '2022-10-15'

df = data.DataReader('^N225', 'yahoo', start_date, end_date)

data_analysis(df)
```

**移動平均**
![スクリーンショット 2022-10-16 16.03.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/7023442f-2088-c6bc-70d2-3718c65f2ed6.png)



**出来高（取引量）**
![スクリーンショット 2022-10-16 16.03.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/69d7443f-1099-03ac-20f5-146a9ca39dd2.png)



**MACD**
![スクリーンショット 2022-10-16 16.03.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/71977b3a-a495-04a8-20a7-8bc3673879ec.png)



**RSI**
![スクリーンショット 2022-10-16 16.03.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/9873569a-4fe6-12da-626b-4762a4d8e96e.png)



**ボリンジャーバンド**
![スクリーンショット 2022-10-16 16.04.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/e38803c1-9563-2aa9-a54c-8b4a831f0cfd.png)


#### 補足
```py
df.head(10)
```

![スクリーンショット 2022-10-16 16.07.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/0964683a-09a8-3012-d02b-b637254c6f2c.png)


|用語  |意味  |
|---|---|
|High  |高値  |
|Low  |安値  |
|Open  |始値  |
|Close  |終値  |
|Volume  |出来高（株取引された量）  |
|Adj Close  |調整後の終値  |


# ビットコインのデータ可視化
```py
start_date = '2022-01-01'
end_date = '2022-10-15'

df = data.DataReader('BTC-JPY', 'yahoo', start_date, end_date)

data_analysis(df)
```

**移動平均**
![スクリーンショット 2022-10-16 15.50.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/beda18ea-7f26-ccba-2c85-00d8a9493b35.png)


**出来高（取引量）**
![スクリーンショット 2022-10-16 15.50.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/3c83ae0e-69a4-fade-20d4-cc1224ddb37d.png)


**MACD**
![スクリーンショット 2022-10-16 15.51.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/66d146b3-480b-b769-075c-76e7ed405b6d.png)


**RSI**
![スクリーンショット 2022-10-16 15.51.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/1ee6fd07-1abe-5d2e-82e8-9d94397e73c8.png)




**ボリンジャーバンド**

![スクリーンショット 2022-10-16 15.51.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/22ac0929-8fab-559a-8b5e-fd6b200d1a9a.png)





# 為替のデータ可視化

:::note warn
為替の場合は出来高が無いため、関数を微修正
:::

```py
def data_analysis(df):

    date = df.index
    close = df['Adj Close']

    # 過去5日、25日、50日の移動平均を算出する為に定義
    span01 = 5
    span02 = 25
    span03 = 50

    # 移動平均を算出。smaは単純移動平均の略称
    df['sma01'] = close.rolling(window=span01).mean()
    df['sma02'] = close.rolling(window=span02).mean()
    df['sma03'] = close.rolling(window=span03).mean()

    plt.figure(figsize=(30, 60))

    # 移動平均
    plt.subplot(4,1,1)
    plt.plot(date, close, label='Adj Close', color='#99b898')
    plt.plot(date, df['sma01'], label='sma01', color='#e84a5f')
    plt.plot(date, df['sma02'], label='sma02', color='#ff847c')
    plt.plot(date, df['sma03'], label='sma03', color='#feceab')

    # MACD
    plt.subplot(4,1,2)
    df['macd'], df['macdsignal'], df['macdhist'] = ta.MACD(close, fastperiod=12, slowperiod=26, signalperiod=9)
    plt.fill_between(date, df['macdhist'], color='gray', alpha=0.5, label='MACD_hist')
    plt.hlines(0, start_date, end_date, 'gray', linestyles='dashed')
    plt.legend()

    # RSI
    plt.subplot(4,1,3)
    df['RSI'] = ta.RSI(close, timeperiod=span02)
    plt.plot(date, df['RSI'], label='RSI', color='gray')
    plt.ylim(0, 100)
    plt.hlines([30, 50, 70], start_date, end_date, 'gray', linestyles='dashed')
    plt.legend()

    # ボリンジャーバンド
    plt.subplot(4,1,4)
    df['upper'], df['middle'], df['lower'] = ta.BBANDS(close, timeperiod=span02, nbdevup=2, nbdevdn=2, matype=0)
    plt.plot(date, close, label='Adj Close', color='#99b898')
    plt.fill_between(date, df['upper'], df['lower'], color='gray', alpha=0.3)
    plt.legend()
```

```py
start_date = '2022-01-01'
end_date = '2022-10-15'

# 日本円とUSドル
df = data.DataReader('DEXJPUS', 'fred', start_date, end_date)

# df.head()

# カラム名を変更
df = df.rename(columns={'DEXJPUS':'Adj Close'})

# 欠損値Nanを削除(FX市場が閉じている日はNanで表示されている為)
df = df.dropna()

data_analysis(df)
```

**移動平均**
![スクリーンショット 2022-10-16 15.54.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/5e7c1bc8-9496-67fa-c689-75fe4b525bab.png)


**MACD**
![スクリーンショット 2022-10-16 15.54.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/00b78407-99d4-1c8c-e16f-6271840840f5.png)


**RSI**
![スクリーンショット 2022-10-16 15.55.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/f694b65b-8f5e-5860-5120-7fe18694c18b.png)


**ボリンジャーバンド**
![スクリーンショット 2022-10-16 15.55.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/c2a32780-bff6-9c72-098f-8da7ad3cc962.png)


# すべてのテクニカル指標をまとめて表示する場合

## 関数を定義
```py
def all_technical_analysis(df):

    # MACD
    # ta.MACD(調整後の終値, 短期移動平均, 長期移動平均, MACDシグナル)
    df['macd'], df['macdsignal'], df['macdhist'] = ta.MACD(df['Adj Close'], fastperiod=12, slowperiod=26, signalperiod=9)

    # ボリンジャーバンド
    # matype: 0=SMA, 1=EMA, 2=WMA, 3=DEMA, 4=TEMA, 5=TRIMA, 6=KAMA, 7=MAMA, 8=T3 (デフォルト=SMA)
    # 上のボリンジャーバンド, 移動平均, 下のボリンジャーバンド = ta.BBANDS(調整後の終値, 日経平均日数, 上のラインの標準偏差, 下のラインの標準偏差, 移動平均の計算方法)
    df['upper'], df['middle'], df['lower'] = ta.BBANDS(df['Adj Close'], timeperiod=25, nbdevup=2, nbdevdn=2, matype=0)

    # RSI
    df['RSI'] = ta.RSI(df['Adj Close'], timeperiod=25)

    # グラフに追加したい項目を代入
    apds = [
        mpf.make_addplot(df['upper'], color='g'),
        mpf.make_addplot(df['middle'], color='b'),
        mpf.make_addplot(df['lower'], color='r'),
        mpf.make_addplot(df['macdhist'], type='bar', color='gray', width=1.0, panel=1, alpha=0.5, ylabel='MACD'),
        mpf.make_addplot(df['RSI'], type='line', panel=2, alpha=0.5, ylabel='RSI')
    ]

    mpf.plot(df, type='candle', figsize=(30, 10), style='yahoo', volume=True, addplot=apds, volume_panel=3, panel_ratios=(5,2,2,1))

    # 画像として保存する場合は以下に変更
    # mpf.plot(df, type='candle', figsize=(30, 10), style='yahoo', volume=True, addplot=apds, volume_panel=3, panel_ratios=(5,2,2,1), savefig='株価テクニカル分析.png')
```

## 日経平均株価データの可視化

```py
start_date = '2022-01-01'
end_date = '2022-10-15'

# 日経平均株価を取得
df = data.DataReader('^N225', 'yahoo', start_date, end_date)

all_technical_analysis(df)
```

![スクリーンショット 2022-10-16 18.21.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2689074/64ba7f8d-d25f-d60e-0943-65d09cd70814.png)



関連
---
- [日経平均株価/個別銘柄の移動平均と出来高を可視化](https://qiita.com/rexid/items/4148e29300f47966066e)
- [日経平均株価のテクニカル分析用データ作成](https://qiita.com/rexid/items/4c390b3c5a769a26dc88)
- [日経平均株価のチャート分析用グラフ作成](https://qiita.com/rexid/items/63d74b8e9d2bc9eeeb44)