よっしーの私的空間

機械学習を中心に興味のあることについて更新します

J-Quantsデータを使用した重要指標(PER,PBR,ROE)推移の算出方法について

株価の割安さや収益性をはかる指標としてPER,PBR,ROEは非常に重要だと思います。ただ、これら指標の過去データの取得方法についてあまり情報が見つかりませんでした。無いなら自分で導こうということで、試行錯誤してみたのでブログにまとめます。

1.各種指標について

指標に関する説明は簡単に整理しますが、詳しくは色んなサイトで解説されています。

① PER(Price Earning Ratio):株価収益率

② PBR(Price Book-value Ratio):株価純資産倍率

ROE(Return On Equity):自己資本利益率

2.データ取得元:J-Quants

J-QuantsはJPX(日本取引所グループ)が個人投資家向けに運営するAPIデータ配信サービスです。API経由で最新の正確な金融データが簡単に取得できるおすすめのサービスですが、いくつか注意点があります。

  • 用途が個人の私的利用に限定されているのでデータの第三者配信やデータを利用したアプリの提供などが禁止されている。
  • 無償プラン、有償プランがあるが、ちゃんと分析しようとすると確実に有償プランが必要になる。

詳しくはJ-Quantsサイトを参照ください。

jpx-jquants.com

3.J-Quantsからのデータ取得方法

まずは上記J-Quantsサイトでアカウントを作成します。アカウント作成時にメールアドレスとパスワードを登録するのですが、それは後程API呼び出し時にも使います。 その後、プランを選択します。お試しで使いたい場合は無料プランで登録しましょう。

ここまで来たら準備完了です。PythonからAPIを呼び出せます。金融データを呼び出すためにはまずはIDトークンが必要になります。IDトークンはアカウント作成時に登録したメールアドレスとパスワードが必要になります。

import requests
import json

# アカウント情報格納
data={"mailaddress":"<YOUR EMAIL_ADDRESS>", "password":"<YOUR PASSWORD>"}

# リフレッシュトークンの取得
r_post = requests.post("https://api.jquants.com/v1/token/auth_user", data=json.dumps(data))
REFRESH_TOKEN = r_post.json()['refreshToken']

# IDトークンの取得
r_post = requests.post(f"https://api.jquants.com/v1/token/auth_refresh?refreshtoken={REFRESH_TOKEN}")
idToken = r_post.json()['idToken']

次に金融データを呼び出します。金融データの種類によって呼び出すAPIは異なります。例えば「株価四本値」の場合は"https://api.jquants.com/v1/prices/daily_quotes"です。以下は2024/4/1~5/1の任天堂の株価四本値を取得してpandas.DataFrameに格納する例です。

import pandas as pd

# リクエストのヘッダー情報とパラメータを設定
headers = {'Authorization': 'Bearer {}'.format(idToken)}
params = {'code': '79740', 'from':'20240401', 'to':'20240501'}

r = requests.get("https://api.jquants.com/v1/prices/daily_quotes",params=params, headers=headers)
df = pd.DataFrame(r.json()['daily_quotes'])

上記のcodeの部分は基本的に4桁の銘柄コードに”0”を末尾に付けたものですが、正確な情報は上場銘柄一覧のAPIを呼び出すことで確認することが可能です。

4.データ取得とPER,PBR,ROEの計算

PER,PBR,ROEを計算する場合は、株価四本値と財務情報のAPIが必要になります。財務情報APIでEPSとBPSを取得、株価四本値APIで株価を取得してそれらを計算することでPER,PBR,ROEを計算します。

import pandas as pd

# リクエストのヘッダー情報とパラメータを設定
headers = {'Authorization': 'Bearer {}'.format(idToken)}
params = {'code': '79740'}

# 株価四本値の取得
r = requests.get("https://api.jquants.com/v1/prices/daily_quotes",params=params, headers=headers)
df_quotes = pd.DataFrame(r.json()['daily_quotes'])

# 財務情報の取得
r = requests.get("https://api.jquants.com/v1/fins/statements", params=params, headers=headers)
df_statements = pd.DataFrame(r.json()['statements'])

EPSは現在値と会社予想値がありますが、将来予測を目的としているため、会社予想値を採用したいと思います。該当する変数は「ForecastEarningsPerShare」です。ただ、データを見ていただければ分かると思いますが、欠損値があります。これは年度末のデータに見られる傾向で、年度末時点でEPSは確定しているため発生しているものと思われます。そのため、欠損値は次年度のEPS「NextYearForecastEarningsPerShare」で補完します。そのうえで、株価データと突合してPERとPBRを計算します。

def replace_null(df, col):
    df.loc[df[col]=='', col] = None
    df[col] = df[col].fillna(method='ffill')
    return df

df_statements .loc[df_statements ['ForecastEarningsPerShare']=='', 'CurrentFiscalYearEndDate'] = df_statements ['NextFiscalYearEndDate']
df_statements .loc[df_statements ['ForecastEarningsPerShare']=='', 'ForecastEarningsPerShare'] = df_statements ['NextYearForecastEarningsPerShare']

df_statements = replace_null(df_statements , 'BookValuePerShare')
df_statements = replace_null(df_statements , 'NextFiscalYearStartDate')

df_statements = replace_null(df_statements , 'ForecastEarningsPerShare')
df_statements = replace_null(df_statements , 'BookValuePerShare')
df_statements ['ForecastEarningsPerShare'] = df_statements ['ForecastEarningsPerShare'].astype(float)
df_statements ['BookValuePerShare'] = df_statements ['BookValuePerShare'].astype(float)

df_adj = df_quotes[~(df_quotes['AdjustmentFactor']==1)].copy()

for index, row in df_adj.iterrows():
    # EPS
    adj_date = row['Date']
    adj_factor = row['AdjustmentFactor']
    df_stats.loc[df_stats['CurrentFiscalYearEndDate']<adj_date, 'ForecastEarningsPerShare'] = df_stats['ForecastEarningsPerShare']*adj_factor
    # BPS
    df_stats.loc[df_stats['NextFiscalYearStartDate']<adj_date, 'BookValuePerShare'] = df_stats['BookValuePerShare']*adj_factor

df_stats = df_stats.loc[~(df_stats.duplicated(subset=['DisclosedDate'], keep='last'))]

df= df_quotes.merge(df_statements , how='left', left_on='Date', right_on='DisclosedDate')
df['ForecastEarningsPerShare'] = df['ForecastEarningsPerShare'].fillna(method='ffill')
df['BookValuePerShare'] = df['BookValuePerShare'].fillna(method='ffill')
df['DisclosedDate'] = df['DisclosedDate'].fillna(method='ffill')
df['per'] = df['AdjustmentClose'] / df['ForecastEarningsPerShare']
df['pbr'] = df['AdjustmentClose'] / df['BookValuePerShare']
df['roe'] = df['pbr'] / df['per']