【Python】Plotlyで外国人投資家の売買動向の推移を可視化する

プログラミング
この記事は約20分で読めます。

以下の投稿で外国人投資家の売買動向を知ることが大切ということと、そのデータがJPX(日本取引所グループ)のホームページから取得できることを書きました。
また、その際にPythonのPlotlyを使って、JPXのデータを可視化した結果を載せたのですが、せっかくですので、そのデータの可視化方法を書いておきたいと思います。

株式売買状況データの準備

外国人投資家の売買動向を確認する方法に従い、2019年のエクセルデータをJPXからダウンロードしてきて、dataというフォルダにいれます。そしてdataのフォルダと同じ階層にvisualization.ipynbというjupyter notebookを作成します。以下のようなフォルダ構成の想定です。

.
├── data
│   ├── stock_val_1_190101.xls
│   ├── stock_val_1_190102.xls
│   ├── stock_val_1_190103.xls
│   ├── stock_val_1_190104.xls
│   ├── stock_val_1_190105.xls
│   ├── stock_val_1_190201.xls
... (省略)
│   ├── stock_val_1_190904.xls
│   ├── stock_val_1_191001.xls
│   ├── stock_val_1_191002.xls
│   ├── stock_val_1_191003.xls
│   └── stock_val_1_191004.xls
└── visualization.ipynb

モジュールのインポート

今回は以下のモジュールを使用します。
pandas:データをテーブル形式で扱うモジュール
xlrd:エクセルを操作するモジュール
glob:ファイルをパスを取得するモジュール
plotly.graph_objects:グラフを可視化するモジュール

import pandas as pd
import xlrd
import glob
import plotly.graph_objects as go

エクセルファイルのパス一覧取得

データの準備ができたので、globモジュールを使って、dataフォルダ内のファイルのパスを取得します。以下のコードになります。

#dataフォルダ内のエクセルファイルのpathをfilesに格納 
files = sorted(glob.glob('data/*'))

エクセルファイル読み込み

エクセルファイルのパス一覧が取得できたので、実際にエクセルファイルを読み込んでいきます。
まずは2019年10月第4週のデータを読み込み、データを取得したいと思います。
以下のコードで、エクセルの東証1部のシートを読み込むことができます。

#2019年10月4週目のエクセルファイルを選択
file = files[-1]

#エクセルファイルを読み込み
wb = xlrd.open_workbook(file)

#エクセルのシート名をすべて読み込む
sheet_names = wb.sheet_names()

#シート名「TSE 1st」(東証1部)のシートを選択
sheet = wb.sheet_by_name(sheet_names[0])

セルデータの取得

エクセルシートのデータは、以下のように記載するとA4セル(4行目1列)の値を取得することができます。

print(sheet.cell(3,0).value)
>> '2019年10月第4週 2019/10 week4  ( 10/21 - 10/25 )'

どのセルにどのデータが入っているかを確認しながら値を取得していく必要があります。
けっこう面倒ですが、頑張って位置を見比べながら以下の関数を作成しました。
全部まとめて書いても良かったのですが、後々わかりやすいようにテーブル毎に関数を作成しています。

#自己売買、委託売買
def get_proprietary_brokage(_sheet, _data):
    _data.extend([_sheet.cell(12,8).value,_sheet.cell(13,8).value,_sheet.cell(14,8).value,
                  _sheet.cell(15,8).value, _sheet.cell(16,8).value,_sheet.cell(17,8).value,])
    return _data

#委託売買の内訳
def get_brokerage_trading(_sheet, _data):
    _data.extend([_sheet.cell(23,8).value,_sheet.cell(24,8).value,_sheet.cell(25,8).value,
                  _sheet.cell(26,8).value,_sheet.cell(27,8).value,_sheet.cell(28,8).value,
                  _sheet.cell(29,8).value,_sheet.cell(30,8).value,_sheet.cell(31,8).value,
                  _sheet.cell(32,8).value,_sheet.cell(33,8).value,_sheet.cell(34,8).value])
    return _data

#法人売買の内訳
def get_brokerage_institutions(_sheet, _data):
    _data.extend([_sheet.cell(37,8).value,_sheet.cell(38,8).value,_sheet.cell(39,8).value,
                  _sheet.cell(40,8).value,_sheet.cell(41,8).value,_sheet.cell(42,8).value,
                  _sheet.cell(43,8).value,_sheet.cell(44,8).value,_sheet.cell(45,8).value,
                  _sheet.cell(46,8).value,_sheet.cell(47,8).value,_sheet.cell(48,8).value,])
    return _data

#金融機関売買の内訳
def get_brokerage_financial(_sheet, _data):
    _data.extend([_sheet.cell(51,8).value,_sheet.cell(52,8).value,_sheet.cell(53,8).value,
                  _sheet.cell(54,8).value,_sheet.cell(55,8).value,_sheet.cell(56,8).value,
                  _sheet.cell(57,8).value,_sheet.cell(58,8).value,_sheet.cell(59,8).value,
                  _sheet.cell(60,8).value,_sheet.cell(61,8).value,_sheet.cell(62,8).value,])
    return _data

#個人、自己売買の現金、信用売買
def get_individual_proprietary(_sheet, _data):
    _data.extend([_sheet.cell(67,2).value,_sheet.cell(67,4).value,
                  _sheet.cell(68,2).value,_sheet.cell(68,4).value,
                  _sheet.cell(69,2).value,_sheet.cell(69,4).value,
                  _sheet.cell(70,2).value,_sheet.cell(70,4).value])
    return data
    
#海外投資家の個人法人売買
def get_foreign(_sheet, _data): 
    _data.extend([_sheet.cell(74,3).value,_sheet.cell(74,5).value,
                  _sheet.cell(75,3).value,_sheet.cell(75,5).value])
    return _data

data = []
data = get_proprietary_brokerage(sheet, data)
data = get_brokerage_trading(sheet, data)
data = get_brokerage_institutions(sheet, data)
data = get_brokerage_financial(sheet, data)
data = get_individual_proprietary(sheet, data)
data = get_foreign(sheet, data)

データフレーム化

取得したデータをpandasのデータフレームに変換します。
colsの中は列名を設定しているだけです。
最後の3行は、文字列のデータを数値に変換しています。

cols = [
    'proprietary_sales', 'proprietary_purchases','proprietary_total',
    'brokerage_sales', 'brokerage_purchases','brokerage_total',

    'brokerage_inst_sales', 'brokerage_inst_purchases','brokerage_inst_total',
    'brokerage_ind_sales', 'brokerage_ind_purchases','brokerage_ind_total',
    'brokerage_fore_sales', 'brokerage_fore_purchases','brokerage_fore_total',
    'brokerage_sec_sales', 'brokerage_sec_purchases','brokerage_sec_total',

    'brokerage_inv_sales', 'brokerage_inv_purchases','brokerage_inv_total',
    'brokerage_bus_sales', 'brokerage_bus_purchases','brokerage_bus_total',
    'brokerage_oth_sales', 'brokerage_oth_purchases','brokerage_oth_total',
    'brokerage_fin_sales', 'brokerage_fin_purchases','brokerage_fin_total',

    'brokerage_life_sales', 'brokerage_life_purchases','brokerage_life_total',
    'brokerage_citybk_sales', 'brokerage_citybk_purchases','brokerage_citybk_total',
    'brokerage_trustbk_sales', 'brokerage_trustbk_purchases','brokerage_trustbk_total',
    'brokerage_othfin_sales', 'brokerage_othfin_purchases','brokerage_othfin_total',

    'brokerage_indcash_sales', 'brokerage_indcash_purchases',
    'brokerage_indmargin_sales', 'brokerage_indmargin_purchases',    
    'proprietary_cash_sales', 'proprietary_cash_purchases',
    'proprietary_margin_sales', 'proprietary_margin_purchases',

    'brokerage_foreinst_sales', 'brokerage_foreinst_purchases',
    'brokerage_foreind_sales', 'brokerage_foreind_purchases']

#データフレーム作成
df = pd.DataFrame(columns = cols)
for j in range(len(df.columns)):
    df.loc[0, df.columns[j]] = data[j]

#データフレームのデータを数値に変換
for c in df:
    df[c] = df[c].str.replace(',','')
    df[c] = df[c].astype(float)

上記を実行すると以下のような1行54列のデータフレームが得られているとおもいます。

2019年の全データをデータフレーム化

上記は2019年10月第4週だけのデータになるので、2019年1月第1週からのデータをすべて読み込みたいと思います。その前に、第何週目のデータかわかるようにweek情報を取り出す関数を作っておきます。

def get_weeks(_file, _weeks):
    _weeks.append('20' + file[-10:-6] + '-' + file[-6:-4])
    return _weeks

weeks = []
weeks = get_weeks(file, weeks)
print(weeks)

>> ['201910-04']

週を取り込む関数ができたので、以下のコードでデータフレームを作成します。

cols = [
    'proprietary_sales', 'proprietary_purchases','proprietary_total',
    'brokerage_sales', 'brokerage_purchases','brokerage_total',

    'brokerage_inst_sales', 'brokerage_inst_purchases','brokerage_inst_total',
    'brokerage_ind_sales', 'brokerage_ind_purchases','brokerage_ind_total',
    'brokerage_fore_sales', 'brokerage_fore_purchases','brokerage_fore_total',
    'brokerage_sec_sales', 'brokerage_sec_purchases','brokerage_sec_total',

    'brokerage_inv_sales', 'brokerage_inv_purchases','brokerage_inv_total',
    'brokerage_bus_sales', 'brokerage_bus_purchases','brokerage_bus_total',
    'brokerage_oth_sales', 'brokerage_oth_purchases','brokerage_oth_total',
    'brokerage_fin_sales', 'brokerage_fin_purchases','brokerage_fin_total',

    'brokerage_life_sales', 'brokerage_life_purchases','brokerage_life_total',
    'brokerage_citybk_sales', 'brokerage_citybk_purchases','brokerage_citybk_total',
    'brokerage_trustbk_sales', 'brokerage_trustbk_purchases','brokerage_trustbk_total',
    'brokerage_othfin_sales', 'brokerage_othfin_purchases','brokerage_othfin_total',

    'brokerage_indcash_sales', 'brokerage_indcash_purchases',
    'brokerage_indmargin_sales', 'brokerage_indmargin_purchases',    
    'proprietary_cash_sales', 'proprietary_cash_purchases',
    'proprietary_margin_sales', 'proprietary_margin_purchases',

    'brokerage_foreinst_sales', 'brokerage_foreinst_purchases',
    'brokerage_foreind_sales', 'brokerage_foreind_purchases'
     ]

#データフレームの作成
df = pd.DataFrame(columns = cols)

weeks = []
for i in range(len(files)):
    file = files[i]
    wb = xlrd.open_workbook(file)
    sheet_names = wb.sheet_names()
    sheet = wb.sheet_by_name(sheet_names[0])
    
    #週情報の取得
    weeks = get_weeks(file, weeks)
    
    #エクセル内のデータの取得
    data = []
    data = get_proprietary_brokerage(sheet, data)
    data = get_brokerage_trading(sheet, data)
    data = get_brokerage_institutions(sheet, data)
    data = get_brokerage_financial(sheet, data)
    data = get_individual_proprietary(sheet, data)
    data = get_foreign(sheet, data)
    
    for j in range(len(df.columns)):
        df.loc[i, df.columns[j]] = data[j]

#テキストデータの数値化
for c in df:
    df[c] = df[c].str.replace(',','')
    df[c] = df[c].astype(float)

上記を実行すると以下のようなデータが得られていると思います。

【Python】Plotlyによるデータの可視化

plotlyはグラフを綺麗に可視化してくれるモジュールです。
慣れるまで少し時間がかかりますが、使えるようになれば、非常に見栄えの良いグラフがかけるのでおすすめです。

詳細な使い方は今回は割愛させていだきます。細かい使い方は公式のページに結構親切に書かれているので、こちらを参照してください。

委託売買金額の推移の可視化結果

委託売買の法人、個人、外国人投資家、証券会社の売買代金のtotal値の可視化を行うプログラムが以下になります。

fig = go.Figure(
    data = [
        go.Bar(x = weeks, y = df['brokerage_inst_total'], name = 'brokerage_inst_total'),
        go.Bar(x = weeks, y = df['brokerage_ind_total'], name = 'brokerage_ind_total'),
        go.Bar(x = weeks, y = df['brokerage_fore_total'], name = 'brokerage_fore_total'),
        go.Bar(x = weeks, y = df['brokerage_sec_total'], name = 'brokerage_sec_total')
    ],
    layout = go.Layout(
        xaxis = dict(showgrid=False, tickangle=-60),
        margin=dict(l=0, r=20, t=20, b=100, autoexpand=True), height=300, width=1000)
)
fig.update_layout(barmode='group')
fig.show()

実行すると以下のようなグラフが得られます。

外国人投資家の売買動向の推移の可視化

外国人投資家の売買動向を可視化するプログラムは以下になります。

fig = go.Figure(
    data = [
        go.Bar(x = weeks, y = df['brokerage_fore_sales'], name = 'brokerage_fore_sales',yaxis='y1'),
        go.Bar(x = weeks, y = df['brokerage_fore_purchases'], name = 'brokerage_fore_purchases',yaxis='y1'),
        go.Scatter(x = weeks, y = df['brokerage_fore_sales'] - df['brokerage_fore_purchases'] , name = 'balance',  yaxis='y2')
    ],
    layout = go.Layout(
        xaxis = dict(showgrid=False, tickangle=-60),
        yaxis = dict(title = 'brokerage_fore_sales_purchases', side = 'left', showgrid=False),
        yaxis2 = dict(title = 'balance', side = 'right',showgrid=False, overlaying = 'y'),
        margin=dict(l=20, r=10, t=20, b=100, autoexpand=True),
        legend=dict(x=1.05, xanchor='left', y=1, yanchor='auto'),
        height=400,
        width=1000)
)
fig.update_layout(barmode='group')
fig.show()

上記を実行すると以下のような結果が得られます。

以上、Plotlyで外国人投資家の売買動向の推移を可視化するでした。

タイトルとURLをコピーしました