Pythonで高配当株を探す③(高配当の条件を満たす銘柄を抽出する)

Python

はじめに

前回、企業の財務指標と財務情報を取得することができるようになりました。
今回は高配当の条件を満たした銘柄を抽出するプログラムを作成しました。抽出した銘柄をcompany_metricsの情報を付けてCSVファイルに保存します。

<抽出したCSVファイルの中身>

銘柄を抽出する際に設定できる条件

作成したプログラムで設定できる条件は下記となります。

設定項目 設定値の形式 掲載プログラムの設定値
配当利回りの範囲 小数点
(3~6%の場合は0.03,0.06)
dividendYield_donw_limit = 0.03
dividendYield_upper_limit = 0.06
配当性向の上限 小数点(50%の場合は0.5) payoutratio = 0.5
配当増減のチェック期限 文字列(10年の場合は’10y’) dividends_period = ’10y’
売上高の安定性 指定無し(取得できた値で判定)
利益の安定性 指定無し(取得できた値で判定)
時価総額の下限 整数 marketcap = 100000000000
自己資本比率の下限 小数点(30%の場合は0.3) capitalAdequacyRatio = 0.3
自己資本利益率の下限 小数点(10%の場合は0.1) roe = 0.1

プログラムの実行環境

実行環境のパッケージのバージョンは下記となります。

パッケージ バージョン
python 3.10.9
yahooquery 2.3.1
pandas 1.5.2

作成したプログラム

# 特定の財務指標、財務状況が指定した条件を満たしている銘柄を抽出する
# 指定できる条件は、配当利回り(上限と下限)、配当性向、時価総額、自己資本利益率、自己資本比率、配当増減のチェック期間
# 実行に必要なデータは、get_company_financial_info.pyで生成したcompany_metrics.csv、
# 出力するファイル
# - company_match_condition.csv
#   条件を満たした銘柄の一覧

# データフレームのライブラリを読み込む
import pandas as pd

# yahooqueryのライブラリを読み込む
from yahooquery import Ticker

# 銘柄を抽出する際の条件
dividendYield_donw_limit = 0.03     # 配当利回り下限
dividendYield_upper_limit = 0.06    # 配当利回り上限
payoutratio = 0.5                   # 配当性向
marketcap = 100000000000            # 時価総額
roe = 0.1                           # 自己資本利益率
capitalAdequacyRatio = 0.3          # 自己資本比率
dividends_period = '10y'            # 配当増減のチェック期間

# メイン処理
# 引数:無し
# 戻値:無し
def main():
    # 当期の企業指標のCSVファイルを読み込む
    df_company_metrics = pd.read_csv('./company_metrics.csv', encoding='cp932')

    # 配当利回り、配当性向、時価総額、自己資本利益率が条件を満たしている銘柄を抽出する
    find_dividendYield = df_company_metrics[df_company_metrics['dividendYield'] >= dividendYield_donw_limit]
    find_dividendYield = find_dividendYield[find_dividendYield['dividendYield'] <= dividendYield_upper_limit]
    find_payoutratio = find_dividendYield[find_dividendYield['payoutRatio'] <= payoutratio] 
    find_marketcap = find_payoutratio[find_payoutratio['MarketCap'] >= marketcap]
    find_roe = find_marketcap[find_marketcap['ROE'] >= roe]

    # 配当利回り、配当性向、時価総額、自己資本利益率の条件を満たしている銘柄の証券コードを取得する
    ticker_list_conditional_match = list(find_roe['ticker'])

    # 過去の企業財務のCSVファイルを読み込む
    df_company_financial_info = pd.read_csv('./company_financial_info.csv', encoding='cp932')

    # 自己資本比率、売上高、純利益、配当履歴が高配当の条件を満たしているかを確認する
    ticker_list = []
    for ticker in ticker_list_conditional_match:
        continue_flag = 0
        selected_ticker = df_company_financial_info[df_company_financial_info['symbol'] == ticker]

        # 自己資本比率がしきい値を満たしているかを判定する
        is_cleared = selected_ticker['capitalAdequacyRatio'] >= capitalAdequacyRatio

        if False in is_cleared.values:
            print(ticker + 'は自己資本比率が' + str(capitalAdequacyRatio) + 'を満たしていない')
            continue

        # 売上高、純利益の増減を確認する
        # 両方とも増減している場合は除外する
        check_list = ['TotalRevenue', 'StockholdersEquity']

        for check in check_list:
            is_increasing = selected_ticker[check].diff().fillna(0) >= 0
            if False in is_increasing.values:
                print(ticker + 'は' + check + 'が増減している')
                continue_flag += 1

        if continue_flag == 2:
            continue

        # 過去10年の配当履歴の増減を確認する
        ticker_data = Ticker(ticker)
        ticker_data_history = ticker_data.history(period=dividends_period, interval='1mo')
        ticker_data_history_dividends = ticker_data_history['dividends']
        ticker_data_history_dividends = ticker_data_history.query('dividends != 0')

        is_increasing = ticker_data_history_dividends['dividends'].diff().fillna(0) >= 0
        if False in is_increasing.values:
            print(ticker + 'は' + '減配している')
            continue

        ticker_list.append(ticker)

    # 条件を満たした銘柄を保存する
    company_match_condition = pd.DataFrame()
    for ticker in ticker_list:
        match = df_company_metrics['ticker'].str.contains(ticker)
        company_match_condition = pd.concat([company_match_condition, df_company_metrics[match]])

    company_match_condition.to_csv('./company_match_condition.csv', encoding='cp932', index=False)


if __name__ == "__main__":
    main()

プログラムの実行方法

  1. プログラムの実行には、下記のCSVファイルが必要です。
    ・company_metrics.csv
    ・company_financial_info.csv
    前回、作成したプログラムでCSVファイルを作成しておいてください。
  2. 掲載しているプログラムを任意のプログラム名で保存してください。ここでは「find_high-yield.py」としています。
  3. CSVファイルとプログラムを同じフォルダに保存したら下記のコマンドでプログラムを実行します。
    python find_high-yield.py
  4. 条件に満たしていない銘柄が見つかると、下記のようなメッセージを表示します。
    7202.TはTotalRevenueが増減している
    7202.Tは減配している
    7261.TはTotalRevenueが増減している
    7261.Tは減配している
  5. プログラムの実行は30秒から60秒ほどで完了します。
  6. プログラムが終了すると、高配当の条件を満たした銘柄が掲載された下記のCSVファイルが生成されます。
    ・company_match_condition.csv

銘柄選定の条件の変更方法

銘柄選定の条件は、プログラムの下記の箇所で設定しています。

# 銘柄を抽出する際の条件
dividendYield_donw_limit = 0.03     # 配当利回り下限
dividendYield_upper_limit = 0.06    # 配当利回り上限
payoutratio = 0.5                   # 配当性向
marketcap = 100000000000            # 時価総額
roe = 0.1                           # 自己資本利益率
capitalAdequacyRatio = 0.3          # 自己資本比率
dividends_period = '10y'            # 配当増減のチェック期間

実行結果

2023年4月29日に下記の条件で銘柄を抽出してみました。

条件 条件値
配当利回りの範囲 3~6%
配当性向 50%以下
配当増減の条件 10年間、減配していない
時価総額 1,000億円以上
自己資本比率 30%以上
自己資本利益率 10%以上
売上と利益 データ取得できた期間で両方とも減っていない

上記の条件を満たした銘柄は下記でした。

証券コード 銘柄 配当(当期)
3231.T 野村不動産ホールディングス 120
4974.T タカラバイオ 75
6013.T タクマ 48
6432.T 竹内製作所 208
7839.T SHOEI 85
8572.T アコム 10

次回、試したいこと

抽出した銘柄の情報は数値だけで少し味気ない感じがします。
株価や売上、利益、配当の推移のグラフを追加して、レポート形式で出力できるようにしてみます。レポートはHTMLで作成する予定です。

コメント

  1. さきたま より:

    すごい!!
    私も丁度pythonを活用して株価のデータ分析を行っていたので
    タイムリーでめちゃくちゃ勉強になりました。
    ためになる情報をありがとうございます。

    次回のレポート化も楽しみにしてます
    そして、私も精進します!

  2. CityWalker より:

    作成されたプログラムの共有ありがとうございます。
    とても勉強になります。

    ところで上記PGを実行すると、以下のメッセージが出たのですが、私の操作のどこに誤りがあるのかわからず苦慮しています。何か思い当たる点がございましたら、ご教示いただけましたら幸いです。

    File “”, line 33
    find_payoutratio = find_dividendYield[find_dividendYield[‘payoutRatio’] = marketcap]
    ^
    SyntaxError: invalid syntax

    • sakurater より:

      勉強の一助になれて幸いです。
      掲載したプログラムを確認し、掲載したプログラムに誤りがあることを確認しました。
      プログラムの33行目で改行が抜けていました。
      掲載したプログラムの内容も更新しました。

  3. CityWalker より:

    sakurater 様

    早速のご回答、ご対応ありがとうございます。
    誠実なレスポンスに感じ入ります!!!

    またサイトの細部にまで心配りされていること、納得のできる論理展開にも人柄が伝わってきます。

    sakurater様が展開される学習テーマは、きわめて実践的で、かつ安心感があります。

    これからもsakurater様のページで学び続けたいと思います。
    あらためてお礼申しあげます。

  4. CityWalker より:

    更新していただいた上記コードを実行すると新たなエラーが出てきました。
    私の学習は一進一退です。

    TypeError Traceback (most recent call last)
    in ()
    90
    91 if __name__ == “__main__”:
    —> 92 main()

    6 frames
    in main()
    29
    30 # 配当利回り、配当性向、時価総額、自己資本利益率が条件を満たしている銘柄を抽出する
    —> 31 find_dividendYield = df_company_metrics[df_company_metrics[‘dividendYield’] >= dividendYield_donw_limit]
    32 find_dividendYield = find_dividendYield[find_dividendYield[‘dividendYield’] <= dividendYield_upper_limit]
    33 find_payoutratio = find_dividendYield[find_dividendYield['payoutRatio'] 72 return method(self, other)
    73
    74 return new_method

    /usr/local/lib/python3.10/dist-packages/pandas/core/arraylike.py in __ge__(self, other)
    60 @unpack_zerodim_and_defer(“__ge__”)
    61 def __ge__(self, other):
    —> 62 return self._cmp_method(other, operator.ge)
    63
    64 # ————————————————————-

    /usr/local/lib/python3.10/dist-packages/pandas/core/series.py in _cmp_method(self, other, op)
    6241
    6242 with np.errstate(all=”ignore”):
    -> 6243 res_values = ops.comparison_op(lvalues, rvalues, op)
    6244
    6245 return self._construct_result(res_values, name=res_name)

    /usr/local/lib/python3.10/dist-packages/pandas/core/ops/array_ops.py in comparison_op(left, right, op)
    285
    286 elif is_object_dtype(lvalues.dtype) or isinstance(rvalues, str):
    –> 287 res_values = comp_method_OBJECT_ARRAY(op, lvalues, rvalues)
    288
    289 else:

    /usr/local/lib/python3.10/dist-packages/pandas/core/ops/array_ops.py in comp_method_OBJECT_ARRAY(op, x, y)
    73 result = libops.vec_compare(x.ravel(), y.ravel(), op)
    74 else:
    —> 75 result = libops.scalar_compare(x.ravel(), y, op)
    76 return result.reshape(x.shape)
    77

    /usr/local/lib/python3.10/dist-packages/pandas/_libs/ops.pyx in pandas._libs.ops.scalar_compare()

    TypeError: ‘>=’ not supported between instances of ‘str’ and ‘float’

    • sakurater より:

      一進一退の学習も、進歩の一部だと思います。努力していることは素晴らしいことですし、自己成長のプロセスで一進一退が起こることは誰にでもあると思います。私も日々、一進一退を繰り返しながら、少しでも進歩できるように学習しています。不明なことがあれば何でもお聞きください。一緒に学び続けましょう。

      ■状況
      ——-
      エラーメッセージを見ると「TypeError: ‘>=’ not supported between instances of ‘str’ and ‘float’」とあります。
      これは31行目の処理で、文字列型変数とfloat型変数を不等号’>=’で比較して発生したエラーです。

      31行目の処理を確認すると、下記の値が文字列型になっているのが原因となります。
      df_company_metrics[df_company_metrics[‘dividendYield’]

      30行目に下記を挿入し、df_company_metricsの’dividendYield’の型を確認してみてください。
      「print(df_company_metrics.dtypes)」
      本来であれば「dividendYield float64」と表示されるはずですが、おそらく「dividendYield object」と表示されている思われます。

      ■対処
      ——-
      対処方法は2つあります。
      ●対処方法1.「company_metrics.csv」の再取得
      原因の可能性として、「company_metrics.csv」の取得に失敗している可能性があります。
      一度「company_metrics.csv」を削除して、再取得してみてください。

      ●対処方法2.コードの改修
      運用対処になってしまいますが、上記で改善しないようであれば、30行目と31行目に下記を追記してみてください。
      ‘dividendYield’列の型をobjectからfloatに更新します。

      # データフレームの ‘dividendYield’ 列を浮動小数点数に変換
      df_company_metrics[‘dividendYield’] = df_company_metrics[‘dividendYield’].astype(float)

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