EDGARのデータを取得

EDGAR(Electronic Data Gathering, Analysis, and Retrieval system)とは、米国の証券取引委員会の運営するサイトです。 米国の法による法定開示書類が管理されています。ここでは米国企業の財務諸表も管理されています。

今回は指定した企業の財務諸表を取得して、データをプロットしてみようと思います。

import os
from sec_edgar_downloader import Downloader

dl = Downloader("./data/")
ticker_symbol = "MSFT"

if os.path.exists(f"./data/sec-edgar-filings/{ticker_symbol}/10-K/"):
    print("ダウンロード済みです。")
elif dl.get("10-K", ticker_symbol, after="2021-01-01", before="2021-12-31") > 0:
    print("ダウンロードに成功しました。")
else:
    print("ダウンロードに失敗しました。")
ダウンロード済みです。

10-Kに含まれる表を抜き出す

pandasのread_htmlを用いることでテーブルをDataFrameの形で抜き出すことができます。

import glob
import pandas as pd

filing_details_filepath = glob.glob(
    f"./data/sec-edgar-filings/{ticker_symbol}/10-K/*/filing-details.html"
)[0]
tables = pd.read_html(filing_details_filepath)

CASH FLOWS STATEMENTSのテーブルを抽出

「CASH FLOWS STATEMENTS」のページのテーブルを抽出します。 様々な方法が考えられますが、ここでは「Cash and cash equivalents, end of period」というワードを見つけたらそのテーブルを抜き出すように指定しています。

cs_table = None  # CASH FLOWS STATEMENTSのページのテーブル
for table in tables:
    tab_html = table.to_html()
    if "Cash and cash equivalents, end of period" in tab_html:
        cs_table = table

cs_table.head(10)
0123456789101112
0(In millions)NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
3Year Ended June 30,NaN20212021NaNNaN20202020NaNNaN20192019NaN
4NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
5OperationsNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
6Net incomeNaN$61271NaNNaN$44281NaNNaN$39240NaN
7Adjustments to reconcile net income to net cas...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
8Depreciation, amortization, and otherNaNNaN11686NaNNaNNaN12796NaNNaNNaN11682NaN
9Stock-based compensation expenseNaNNaN6118NaNNaNNaN5289NaNNaNNaN4652NaN

データの前処理

NaNが多く含まれる上、文字列扱いになっていてこのままでは数値を読み取れません。 NaNや不要な記号を取り除き、文字列を数値に変換します。

import numpy as np

# 「(」「)」「,」の文字列を削除する
cs_table = cs_table.replace([",", "\)", "\("], "", regex=True)
cs_table = cs_table.replace([""], np.nan)  # 空白セルはnan扱いにする
cs_table.head(10)
0123456789101112
0In millionsNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
3Year Ended June 30NaN20212021NaNNaN20202020NaNNaN20192019NaN
4NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
5OperationsNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
6Net incomeNaN$61271NaNNaN$44281NaNNaN$39240NaN
7Adjustments to reconcile net income to net cas...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
8Depreciation amortization and otherNaNNaN11686NaNNaNNaN12796NaNNaNNaN11682NaN
9Stock-based compensation expenseNaNNaN6118NaNNaNNaN5289NaNNaNNaN4652NaN
# データがない列を削除する
row_num = cs_table.shape[0]

for colname in cs_table.columns:
    if cs_table[colname].isna().sum() > row_num * 0.8:  # 8割以上の行がNaNの列は
        cs_table.drop(colname, inplace=True, axis=1)  # 不要な列として削除する
cs_table.head(10)
03711
0In millionsNaNNaNNaN
1NaNNaNNaNNaN
2NaNNaNNaNNaN
3Year Ended June 30202120202019
4NaNNaNNaNNaN
5OperationsNaNNaNNaN
6Net income612714428139240
7Adjustments to reconcile net income to net cas...NaNNaNNaN
8Depreciation amortization and other116861279611682
9Stock-based compensation expense611852894652
# NaNの多い行も削除する
col_num = cs_table.shape[1]
cs_table[cs_table.isna().sum(axis=1) < col_num * 0.8]
cs_table.columns = ["item", "2021", "2020", "2019"]
cs_table = cs_table[["item", "2019", "2020", "2021"]]
# years = cs_table.fillna('').query("item.str.contains('Year Ended')").iloc[0, 1:]

データをプロットする

import matplotlib.pyplot as plt

years = ["2019", "2020", "2021"]

for item_name in cs_table["item"][:10]:
    try:
        data = [float(v) for v in cs_table.query(f"item=='{item_name}'").iloc[0, 1:]]
        plt.plot(data)
        plt.xticks([i for i in range(len(years))], years)
        plt.title(item_name)
        plt.grid()
        plt.show()
    except IndexError:
        pass

png

png

png

png

png

png

png