見出し画像

マイ決算スケジュールを作成するのだ!の巻

このプログラムでは保有銘柄の決算日をスケジュール表にすることができます。

それだけでなく、例えば、半導体不足で、新車の製造が滞り、中古車価格が高騰する昨今、業績が気になる車関連の銘柄を纏めて、決算の前後関係を一目で確認できるスケジュール表が作成できます。

先行して発表される関連銘柄の決算を把握しておけば、後に発表される銘柄の決算に向けて投資方針を考えるのに参考になるかもしれません。

そんな便利ツールを作ってみました。
取得できるスケジュール表は下記の様な図になります。
(注意:関連銘柄のリストアップは手動です。)

画像4

しかし、いくつか注意事項があります。

注意事項
1.リトライで、途中から処理が再実行できるように対応していますが、処理がタイムアウトになる事が多いです。10件のデータ取得で2回から3回ぐらい(下手するともっと)リトライする必要があるかもしれません。
2.ADR系の銘柄は決算日が取得できずエラーになると思います。
3.決算情報の元データが誤っている可能性コーディングのバグがある可能性もあるので、重要な情報は別途裏どりをしてください。

では、実行方法の説明です。

1.ライブラリをインストール

下記の2つのライブラリをインストールします。

pip install yahoo_fin
pip install yfinance

2.ファイル準備

ティッカーとカテゴリを記載した「ticker.csv」ファイルを準備します。

カテゴリは横のラインを揃えて見やすくするものなので、関連が近いものをまとめると良い。(ただし、決算日が重なる場合は、文字が重なるのであえてカテゴリを分けた方が良い。)

画像3

1行目:ヘッダー「Ticker,Cat1」の固定値を入力。
2行目以降:「ティッカー,カテゴリ」を入力。
カテゴリが思い付かない場合は、例②の様にカンマ以降、空欄でもよい。
その場合は、「業種」がプログラムで補填されます。

サンプルファイル

3.ファイルの配置

下記のフォルダマークをクリックする。

画像1

下記の様にファイルをドラックしてアップロードする。

画像3

4.データ格納ファイルの作成(初期化)

処理途中のデータを格納するための初期ファイルを作成するコードです。

import yfinance as yf
import pandas as pd
import datetime
from datetime import datetime as dt
import time

dfstock = pd.read_csv("ticker.csv", index_col="Ticker")

# カテゴリが空の場合、業種を補填する処理
for i in range(len(dfstock)):
 if pd.isnull(dfstock.Cat1[i]):
   Industry = yf.Ticker(dfstock.index[i]).info["industry"]
   dfstock.iloc[i,0]=Industry
   print("\r now loading -->>  " + dfstock.index[i]+ "  ---" ,end="")
   time.sleep(3)
print("\r ------------ end ---------------" ,end="")

dfstock=dfstock.assign(NextDate=dt.strftime(datetime.date.today()-datetime.timedelta(days=10), '%Y-%m-%d'),
           NextEst="",CurrentDate="",Act="",Est="",
           Surprise="",Update="")
dfstock.to_csv('result.csv')

5.決算日の情報取得処理

決算日の情報を取得する処理です。

タイムアウトになる事が多いため、何回か再実行する必要があるかもしれません。すぐに再実行をしてもエラーとなる場合は、1~3分後くらいに、この処理以降を実行してください。(何回かやってみましたが、タイムアウトが解消される規則性は良く分かりません。)

import yahoo_fin.stock_info as si
import yfinance as yf
import pandas as pd
import datetime
import time
from datetime import datetime as dt
import matplotlib.pyplot as plt
%matplotlib inline
df_up = pd.read_csv("result.csv", index_col="Ticker")
codelist = df_up.index.values.tolist()
      
# EPS取得処理  
for i in range(len(codelist)):
  ticker=codelist[i]
  # 処理中のティッカーを標準出力(上書き)  
  print("\r now loading -->>  " + ticker+ "  ---" ,end="")
  if (df_up["NextDate"][df_up.index==ticker].iloc[-1] < (dt.strftime((datetime.date.today()-datetime.timedelta(days=0)), '%Y-%m-%d'))):
      try:
          aapl_earnings_hist = si.get_earnings_history(ticker)
      except IndexError as e:
          print("\n Retry after 1-3 minute, or remove ticker.")
          break
      
      df =pd.DataFrame.from_dict(aapl_earnings_hist).loc[:,["startdatetime","epsestimate",  "epsactual",  "epssurprisepct"]].head(30)
      df.rename(columns={'epsestimate':'EPS_Estimate','epsactual':'EPS_Actual','epssurprisepct':'EPS_Surprise'},inplace=True)
      df['day'] = pd.to_datetime(df["startdatetime"], format='%Y-%m-%d')
      df['startdatetime'] = df['day'].dt.strftime('%Y-%m-%d')
      df = df.sort_index(axis='index',ascending=False)
      
      MarketCap = yf.Ticker(ticker).info['marketCap'] 
      # 実績がなく予想だけ入っているものを抽出し、予定日とする。
      try:
          NextDate=df["startdatetime"][df["EPS_Actual"].isnull() & df["EPS_Estimate"].notnull()].iloc[-1]
          NextEst=df["EPS_Estimate"][df["EPS_Actual"].isnull() & df["EPS_Estimate"].notnull()].iloc[-1]
      except IndexError as e:
          NextDate=df["startdatetime"].iloc[-1]
      # 対象のデータに取得した情報を上書き
      df_up.loc[(df_up.index.values==ticker) & (df_up.NextDate < (dt.strftime(datetime.date.today(),'%Y-%m-%d'))),
                ["NextDate","NextEst","CurrentDate","Act","Est","Surprise","MarketCap","Update"]]=[
          NextDate,NextEst,
          df.dropna()["startdatetime"].iloc[-1],
          df.dropna()["EPS_Actual"].iloc[-1],
          df.dropna()["EPS_Estimate"].iloc[-1],
          df.dropna()["EPS_Surprise"].iloc[-1],
          MarketCap,
          dt.strftime(datetime.date.today(), '%Y-%m-%d')]
      # CSVファイルを更新
      df_up.to_csv('result.csv')
      time.sleep(3)
print("\r ------------ end ---------------" ,end="")

6.決算スケジュール表の作成

格納したファイルからデータを読み込んでスケジュールを作成します。

import pandas as pd
import numpy as np
from datetime import datetime as dt
import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib import gridspec
%matplotlib inline

# CSVを読み込んでデータフレームに格納
df=pd.read_csv("result.csv")
df=df.loc[:,{"Ticker","NextDate","NextEst","Cat1","MarketCap"}]
df=df.reindex(columns=["NextDate","Ticker","Cat1","NextEst","MarketCap"])
df['Date'] = pd.to_datetime(df["NextDate"], format='%Y-%m-%d')
df["MarketCap2"]=(df["MarketCap"].astype(int)/1000000000).round().astype(int)
df=df.set_index('NextDate')
df = df.sort_values('Cat1',ascending=True)
df = df.sort_index(axis='index',ascending=True)

# スタートとエンドを設定
start = datetime.date.today().strftime("%Y-%m-%d")
end = (datetime.date.today() + datetime.timedelta(days=120)).strftime("%Y-%m-%d")
df=df.loc[start:end,:]
df["Cat2"]=""
j=0
df.iloc[0,6]=df.iloc[0,1]
for i in range(len(df)-1):
 if df.index[i]+df.Cat1[i]==df.index[i+1]+df.Cat1[i+1] :
   df.iloc[i+1,6]=df.iloc[i+1,1]+str(j+1)
   j=j+1
 else:
   df.iloc[i+1,6]=df.iloc[i+1,1]
   j=0

labels = df["Cat2"].unique()
labels = sorted(labels)

# 業種別でわけるためのY軸の値を設定
j=0
for i in range(len(labels)):
  df.loc[df["Cat2"]==labels[i],"secno"]=200+j
  j=j+200

# 業種別ソート(日付が近いものをキレイにずらすため)
df = df.sort_values('Cat2',ascending=True)

# グラフを描画
fig = plt.figure(facecolor='white',figsize=(20,len(labels)),tight_layout=True)
spec = gridspec.GridSpec(ncols=1, nrows=1,height_ratios=[1],width_ratios=[1])
ax1 =  fig.add_subplot(spec[0,0], title='Earning Schedule')

# グラフの色を設定("Set3" "Paired" "tab20")
cmap = plt.get_cmap("tab10") 

# グラフを描画
for i in range(len(labels)):
  df2=df.loc[df["Cat2"]==labels[i],:]
  ax1.scatter(df2["Date"],df2["secno"], s=df2["MarketCap2"]*2, c=[cmap(i)], alpha=0.5)

# 時価総額が高いものでデータを絞り込み(文字の重なりを抑制できる)
df.loc[df["MarketCap2"]<0,"Ticker"]=""

# ティッカーの文字列をグラフに挿入
for i, txt in enumerate(df.index.values):

 # 割り算の商で日付が近いものずらす処理
  ax1.annotate(" "+df["Ticker"].values[i], (df["Date"].values[i], df["secno"].values[i]-50+i%2*100),fontsize=10)
  ax1.annotate("  "+str(df["NextEst"].values[i]), (df["Date"].values[i], df["secno"].values[i]-100+i%2*100),fontsize=8)

# 軸等のグラフの設定(カテゴリ数で大きさを変動)
ax1.set_ylim([0,len(labels)*200+200])
ax1.set_yticks(np.arange(200, (len(labels)+2)*200, 200))
ax1.set_yticklabels(labels)
ax1.xaxis.set_major_locator(mdates.DayLocator(bymonthday=None, interval=1, tz=None))
ax1.xaxis.set_major_formatter(mdates.DateFormatter("%m-%d"))
ax1.tick_params(width=0.01,length=0.01, colors='gray', grid_color='gray', grid_alpha=0.1,labelsize=14)
ax1.xaxis.set_tick_params(rotation=90,size=4)
plt.grid(True)
plt.show()
plt.close()
# ここまで

7.実行結果

下記の様な実行結果が得られます。

画像5

確認方法
 横軸:決算予定日
 縦軸:カテゴリ
 円の大きさ:時価総額
 文字:銘柄予想EPS

参考になれば幸いです。

では!

おつかれさん「缶コーヒー1杯ぐらい、ご馳走してあげよう」という太っ腹な方がいれば、投げ銭をお願いします!
課金しなくても、参考になったら「ハートボタンクリック、フォロー、リツイート」をお願いします。
読まれる可能性があがるので、次の記事を書くやる気が出ます

課金した場合の「おまけ」現在のところありませんが、

上記のプログラムで作成したスケジュール表を、何パターンかアップする予定です。(これから関連性を考えながら、カテゴリ分けをするので、今回の決算というよりは、今後の参考という感じで、気長に、あまり期待せずにお待ちください。)

ここから先は

697字 / 4画像

¥ 100

この記事が気に入ったらチップで応援してみませんか?