Pythonで高配当株を探す④(高配当株のレポートを作成する)

Python

はじめに

前回、高配当株の条件を設定し、その条件を満たす銘柄を抽出するプログラムを作成しました。抽出した結果はCSVファイルに保存しましたが、保存したCSVファイルの内容は抽出した銘柄の情報(数値)だけで、少し味気ない印象を受けました。

そこで、抽出した情報(数値)でグラフ化してレポートを出力するプログラムを作成しました。Webアプリの作成に興味があったのと、htmlとJavaScriptの学習も兼ねて、レポートはhtmlとJavaScriptで作成することにしました。

<作成したレポートのサンプル>

プログラムの概要

  • レポート生成プログラムはPythonで作成しています。
  • レポートはhtmlとjavascriptで作成しています。
  • レポートを作成するための情報はPythonで収集してhtml形式で出力します。
  • レポート内のグラフはJavascriptのライブラリであるchart.jsを使用しています。
  • レポートは銘柄ごとに作成しています。
  • レポートのトップページを作成し、各銘柄のレポートを参照するタブを作成しています。
  • レポートに記載する内容
    項目 記載例
    証券コード 3231.T
    市場・商品区分 プライム(内国株式)
    業種(33業種 17業種) 不動産業 不動産
    配当金 130.0
    配当利回り 0.0385
    配当性向 0.2832
    時価総額 587858837504.0
    売上高 654734983168.0
    ROE 0.10132
    配当履歴 過去10年分(棒グラフ)
    株価チャート 過去10年分の月初のOpen値(線グラフ)
    売上高 取得できた過去2~4年分(棒グラフ)
    株主資本 取得できた過去2~4年分(棒グラフ)
    総資産 取得できた過去2~4年分(棒グラフ)
    自己資本比率 取得できた過去2~4年分(棒グラフ)
    自己資本利益率 取得できた過去2~4年分(棒グラフ)

    プログラムの実行環境

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

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

    「Jinja2」はレポートを作成するときに、その機能を使用します。
    「Jinja2」は下記を実行するとインストールできます。

    pip install jinja2

    プログラム実行前に準備するファイル・フォルダの一覧

    プログラムを実行する前に準備しおくファイルとフォルダを下記にまめました。

    ファイル名 内容 配置場所
    generate_report.py レポートを生成するプログラム 任意のフォルダ
    company_match_condition.csv 高配当の条件を満たした銘柄一覧のCSVファイル。
    前回のプログラムを実行すると取得できます。
    generate_report.pyと同一フォルダ
    company_financial_info.csv 各銘柄の財務情報を保存したCSVファイル。
    前々回のプログラムを実行すると取得できます。
    generate_report.pyと同一フォルダ
    chart_template.js レポート内のグラフを作成するjavascript [generate_report.pyと同一フォルダ]\report\template
    head_parts.html レポートのトップページ用のhtmlを生成する際に使用 [generate_report.pyと同一フォルダ]\report\template
    js_parts.html レポートのトップページ用のhtmlを生成する際に使用 [generate_report.pyと同一フォルダ]\report\template
    report_template.html 各銘柄のレポート用のhtmlを生成する際に使用 [generate_report.pyと同一フォルダ]\report\template

    上記のファイルを一括でダウンロードしたい場合は、下記のリンクからダウンロードしてください。

    作成したプログラムとテンプレート

    レポートを作成するためのプログラムとテンプレートは下記となります。プログラム名、テンプレート名をクリックするとコードが表示されます。

    作成したプログラム

    generate_report.py
    # 高配当の条件を満たした銘柄の財務指標、財務情報からレポートを作成する
    # 実行に必要なファイル
    # - company_match_condition.csv (高配当の条件を満たした銘柄を記録したCSVファイル。find_high_yield.pyで生成する)
    # - company_financial_info.csv (各銘柄の財務情報を記録したCSVファイル。get_company_financial_info.pyで生成する)
    # - chart_template.js (レポートのグラフを表示するjavascriptのテンプレート)
    # - report_template.html (レポート内容のテンプレート)
    # - head_parts.html (レポートのトップページのheadパーツ)
    # - js_parts.html (レポートトップページのjavascriptパーツ)
    # 生成するファイル
    # ファイルはreportフォルダ配下に生成される
    # - ./report/report.top.html (レポートのトップページ)
    # - ./generated/(証券コード)_chart.js (各証券コードごとのグラフ)
    # - ./generated/(証券コード)_report.html (各証券コードごとのレポート)
    
    
    # yahooqueryのライブラリを読み込む
    from yahooquery import Ticker
    
    # テンプレートエンジンのjinja2のライブラリを読み込む
    from jinja2 import Environment
    from jinja2 import FileSystemLoader
    
    import pandas as pd
    import os
    
    
    # メイン処理
    # 引数:無し
    # 戻値:無し
    def main():
        # 高配当の条件を満たした銘柄のCSVファイルを読み込む
        company_match_condition = read_file('./company_match_condition.csv')
    
        # 各銘柄の財務情報を読み込む
        company_financial_info = read_file('./company_financial_info.csv')
    
        # chartを作成するテンプレートを読み込む
        chart_template = read_file('./report/template/chart_template.js')
    
        # レポートページのテンプレートを読み込む
        report_template = read_file('./report/template/report_template.html')
    
        # 生成したhtmlとjavascriptを保存するフォルダを用意する
        folder_path = './report/generated/'
        if not os.path.exists(folder_path):
            os.makedirs(folder_path)
    
        # レポートを作成する
        for index, row in company_match_condition.iterrows():
            # レポートページを生成する
            generate_report(row, report_template, folder_path)
    
            # レポートページのグラフ表示のjavascriptを作成する
            generate_chart_js(row, chart_template, company_financial_info, folder_path)
    
        # レポートのトップページを生成する
        generate_report_top(folder_path)
    
    
    # 読み込むファイルの存在を確認し、存在する場合は読み込む
    # 引数: 読み込むファイルパス
    # 戻値: 読み込んだファイルデータ(Dataframe)
    def read_file(file_path):
        # 指定したファイルの存在を確認する
        is_file = os.path.isfile(file_path)
        if is_file:
            # csvファイルの場合
            if file_path.endswith('.csv'):
                print()
                return pd.read_csv(file_path, encoding='cp932', index_col=None)
    
            # headのパーツ、jsのパーツの場合
            elif file_path.endswith('parts.html') or file_path.endswith('parts.html'):
                with open(file_path, encoding='UTF-8') as f:
                    parts = f.read()
                    return parts
    
            # jsファイル、htmlファイルの場合
            elif file_path.endswith('.js') or file_path.endswith('.html'):
                # テンプレートファイルのフォルダを指定する
                env = Environment(loader=FileSystemLoader('./'))
                return env.get_template(file_path)
    
        else:
            print('{0}を読み込めません。'.format(file_path))
            exit()
    
    
    # 日付のリストを全て結合して1つの変数に整形する
    # 引数:日付を保存しているリスト
    # 戻値:整形した日付(str)
    def shape_date_list(date_list):
        shaped_date_str = ''
        for date in date_list:
            shaped_date_str = shaped_date_str + '"' + date + '"' + ','
    
        return shaped_date_str
    
    
    # データのリストを全て結合して1つの変数に整形する
    # 引数:データを保存しているリスト
    # 戻値:整形したデータ(str)
    def shape_data_list(data_list):
        shaped_data_str = ''
        for Data in data_list:
            shaped_data_str = shaped_data_str + str(Data) + ','
    
        return shaped_data_str
    
    
    # 指定した証券コードと指定した属性の値を取得する
    # 引数: 履歴を取得する証券コード、取得する属性
    # 戻値: 取得した属性値(str)、取得した属性値の記録された日付(str)
    def get_ticker_attr(ticker, attr):
        ticker_data = Ticker(ticker)
    
        # 過去10年の履歴を取得する
        ticker_data_history = ticker_data.history(period='10y', interval='1mo')
        ticker_data_history_attr = ticker_data_history[attr]
        # 取得する属性がdividends(配当)の場合は、0を行を除外する
        if attr == 'dividends':
            ticker_data_history_attr = ticker_data_history.query('dividends != 0')
    
        # indexは証券コードと日付のMultiIndexになっているので、indexをリセットして日付と取得する属性だけを抽出する
        new_index = ticker_data_history_attr.reset_index()
        ticker_date_attr = new_index[['date', attr]]
    
        # 履歴の日付を抽出し、datetime型をstr型に変換する
        attr_date_list = ticker_date_attr['date'].tolist()
        attr_date_list = [dt.strftime('%Y/%m/%d') for dt in attr_date_list]
    
        # テンプレートにデータを渡すために、1つの変数にまとめる
        # リストのままjinja2のテンプレートに渡すと、[]が付いた状態で渡してしまう
        # それぞれのリストから値を取り出して、1つの変数にまとめる
        attr = shape_data_list(ticker_date_attr[attr])
        attr_date = shape_date_list(attr_date_list)
    
        return attr, attr_date
    
    
    # 財務情報から指定した銘柄の特定の属性を抽出し、1つの変数にまとめて戻す
    # 引数:財務情報、証券コード、抽出する属性
    # 戻値:抽出した属性値(str)、抽出した属性値を記録した日付(str)
    def get_attr_and_convert_str(company_financial_info, ticker, attr):
        # 配当履歴を抽出する場合
        if attr == 'dividends':
            dividends, dividends_date = get_ticker_attr(ticker, attr)
    
            return dividends, dividends_date
    
        # 株価チャートを抽出する場合
        if attr == 'stockchart':
            stockchart, stockchart_date = get_ticker_attr(ticker, 'open')
    
            return stockchart, stockchart_date
    
        # 高配当銘柄の財務情報を抽出する
        specific_company_financial_info = company_financial_info[company_financial_info['symbol'] == ticker]
    
        # 指定した属性を抽出する
        get_attr = specific_company_financial_info[['asOfDate', attr]]
    
        # テンプレートにデータを渡すために、1つの変数にまとめる
        # リストのままjinja2のテンプレートに渡すと、[]が付いた状態で渡してしまう
        # それぞれのリストから値を取り出して、1つの変数にまとめる
        attr_str = shape_data_list(get_attr[attr])
        attr_date_str = shape_date_list(get_attr['asOfDate'])
    
        return attr_str, attr_date_str
    
    
    # レポートページを生成する
    # 引数: レポートページを作成する銘柄の基本情報、レポートページのテンプレート、生成したレポートページを保存するパス
    # 戻値: 無し
    def generate_report(row, report_template, folder_path):
        # テンプレートに渡す値を整理する
        # 渡す値:証券コード、銘柄、業種、配当金、配当利回り、配当性向、時価総額、売上高、自己資本利益率
        report_data = {'ticker': row['ticker'],
                       'ticker_name': row['ticker_name'],
                       'market_product_category': row['market_product_category'],
                       'type_33': row['type_33'],
                       'type_17': row['type_17'],
                       'dividendRate': row['dividendRate'],
                       'dividendYield': row['dividendYield'],
                       'payoutRatio': row['payoutRatio'],
                       'MarketCap': row['MarketCap'],
                       'totalRevenue': row['totalRevenue'],
                       'ROE': row['ROE']}
    
        # reportのテンプレートに値を渡す
        report = report_template.render(report_data)
    
        # 生成したHTMLをファイルに書き込む
        with open(folder_path + row['ticker'] + '_report.html', 'w', encoding='UTF-8') as f:
            f.write(report)
    
    
    # レポートページで使用するグラフを表示するjavascriptを生成する
    # 引数: 銘柄情報基本、javascriptのテンプレート、銘柄の財務情報、生成したjavascriptを保存するパス
    # 戻値: 無し
    def generate_chart_js(row, chart_template, company_financial_info, folder_path):
        # 配当履歴、売上高、株主資本、総資産、自己資本比率、自己資本利益率と、記録した日付を抽出する
        attrs = ['stockchart', 'dividends', 'TotalRevenue', 'StockholdersEquity', 'TotalAssets', 'capitalAdequacyRatio', 'ROE']
        for attr in attrs:
            data, date_str = get_attr_and_convert_str(company_financial_info, row['ticker'], attr)
    
            if attr == 'stockchart':
                stockchart = data
                stockchart_date = date_str
    
            elif attr == 'dividends':
                dividends = data
                dividends_date = date_str
    
            elif attr == 'TotalRevenue':
                totalrevenue = data
                totalrevenue_date = date_str
    
            elif attr == 'StockholdersEquity':
                stockholdersequity = data
                stockholdersequity_date = date_str
    
            elif attr == 'TotalAssets':
                totalassets = data
                totalassets_date = date_str
    
            elif attr == 'capitalAdequacyRatio':
                capitaladequacyratio = data
                capitaladequacyratio_date = date_str
    
            elif attr == 'ROE':
                roe = data
                roe_date = date_str
    
        # テンプレートに渡す変数を定義する
        chart_data = {
            'dividends': dividends,
            'dividends_date': dividends_date,
            'stockchart': stockchart,
            'stockchart_date': stockchart_date,
            'totalRevenue': totalrevenue,
            'totalRevenue_date': totalrevenue_date,
            'stockholdersEquity': stockholdersequity,
            'stockholdersEquity_date': stockholdersequity_date,
            'totalAssets': totalassets,
            'totalAssets_date': totalassets_date,
            'capitalAdequacyRatio': capitaladequacyratio,
            'capitalAdequacyRatio_date': capitaladequacyratio_date,
            'roe': roe,
            'roe_date': roe_date
        }
    
        # chartのテンプレートに変数を渡す
        chart = chart_template.render(chart_data)
    
        # 生成したHTMLをファイルに書き込む
        with open(folder_path + row['ticker'] + '_chart.js', 'w', encoding='UTF-8') as f:
            f.write(chart)
    
    
    # レポートのトップページを生成する
    # 引数:生成したレポートを保存したパス
    # 戻値:無し
    def generate_report_top(folder_path):
        # report_top.htmlが存在したら削除する
        if os.path.isfile(folder_path + 'report_top.html'):
            os.remove(folder_path + 'report_top.html')
    
        # headのパーツを読み込む
        head_parts = read_file('./report/template/head_parts.html')
    
        # jsのパーツを読み込む
        js_parts = read_file('./report/template/js_parts.html')
    
        # 生成されたレポートページの数をカウントする
        count = 0
        html_files = []
        for filename in os.listdir(folder_path):
            if filename.endswith('.html'):
                html_files.append(filename)
                count += 1
    
        # レポートのトップページのhtmlを生成する
        with open('./report/report_top.html', 'w', encoding='UTF-8') as f:
            f.write(head_parts)
            f.write('\t<div class=\"tab\">\n')
            for i in range(count):
                if i == 0:
                    f.write('\t\t<button class="tablinks active" onclick="openTab(event, \'Tab{0}\')">{1}</button>\n'.format(i, html_files[i]))
                else:
                    f.write('\t\t<button class="tablinks" onclick="openTab(event, \'Tab{0}\')">{1}</button>\n'.format(i, html_files[i]))
    
            f.write('\t</div>\n')
    
            f.write('\t<div id="Tab0" class="tabcontent active">\n')
            for i in range(count):
                if i == 0:
                    f.write('\t\t<object type="text/html" data="generated/{0}" style="width:100%; height:100%;"></object>\n'.format(html_files[i]))
                    f.write('\t</div>\n')
                else:
                    f.write('\t<div id="Tab{0}" class="tabcontent">\n'.format(i))
                    f.write('\t\t<object type="text/html" data="generated/{0}" style="width:100%; height:100%;"></object>\n'.format(html_files[i]))
                    f.write('\t</div>\n')
    
            f.write(js_parts)
    
    
    if __name__ == "__main__":
        main()

    作成したテンプレート

    chart_template.js
    // データの設定
    var barData_dividends = {
    	labels: [{{ dividends_date }}],
    	datasets: [
    		{
    			label: "配当履歴",
    			backgroundColor: "rgba(255,99,132,0.2)",
    			borderColor: "rgba(255,99,132,1)",
    			borderWidth: 1,
    			hoverBackgroundColor: "rgba(255,99,132,0.4)",
    			hoverBorderColor: "rgba(255,99,132,1)",
    			data: [{{ dividends }}]
    		}
    	]
    };
    
    var barData_stockchart = {
    	labels: [{{ stockchart_date }}],
    	datasets: [
    		{
    			label: "株価チャート(open値)",
    			backgroundColor: "rgba(255,99,132,0.2)",
    			borderColor: "rgba(255,99,132,1)",
    			borderWidth: 1,
    			hoverBackgroundColor: "rgba(255,99,132,0.4)",
    			hoverBorderColor: "rgba(255,99,132,1)",
    			data: [{{ stockchart }}]
    		}
    	]
    };
    var barData_totalRevenue = {
    	labels: [{{ totalRevenue_date }}],
    	datasets: [
    		{
    			label: "売上高",
    			backgroundColor: "rgba(255,99,132,0.2)",
    			borderColor: "rgba(255,99,132,1)",
    			borderWidth: 1,
    			hoverBackgroundColor: "rgba(255,99,132,0.4)",
    			hoverBorderColor: "rgba(255,99,132,1)",
    			data: [{{ totalRevenue }}]
    		}
    	]
    };
    
    var barData_stockholdersEquity = {
    	labels: [{{ stockholdersEquity_date }}],
    	datasets: [
    		{
    			label: "株主資本",
    			backgroundColor: "rgba(255,99,132,0.2)",
    			borderColor: "rgba(255,99,132,1)",
    			borderWidth: 1,
    			hoverBackgroundColor: "rgba(255,99,132,0.4)",
    			hoverBorderColor: "rgba(255,99,132,1)",
    			data: [{{ stockholdersEquity }}]
    		}
    	]
    };
    
    var barData_totalAssets = {
    	labels: [{{ totalAssets_date }}],
    	datasets: [
    		{
    			label: "総資産",
    			backgroundColor: "rgba(255,99,132,0.2)",
    			borderColor: "rgba(255,99,132,1)",
    			borderWidth: 1,
    			hoverBackgroundColor: "rgba(255,99,132,0.4)",
    			hoverBorderColor: "rgba(255,99,132,1)",
    			data: [{{ totalAssets }}]
    		}
    	]
    };
    
    var barData_capitalAdequacyRatio = {
    	labels: [{{ capitalAdequacyRatio_date }}],
    	datasets: [
    		{
    			label: "自己資本比率",
    			backgroundColor: "rgba(255,99,132,0.2)",
    			borderColor: "rgba(255,99,132,1)",
    			borderWidth: 1,
    			hoverBackgroundColor: "rgba(255,99,132,0.4)",
    			hoverBorderColor: "rgba(255,99,132,1)",
    			data: [{{ capitalAdequacyRatio }}]
    		}
    	]
    };
    
    var barData_roe = {
    	labels: [{{ roe_date }}],
    	datasets: [
    		{
    			label: "自己資本利益比率",
    			backgroundColor: "rgba(255,99,132,0.2)",
    			borderColor: "rgba(255,99,132,1)",
    			borderWidth: 1,
    			hoverBackgroundColor: "rgba(255,99,132,0.4)",
    			hoverBorderColor: "rgba(255,99,132,1)",
    			data: [{{ roe }}]
    		}
    	]
    };
    
    window.onload = function() {
    	var ctx1 = document.getElementById("barChart_dividends").getContext("2d");
    	window.myBar1 = new Chart(ctx1, {
    		type: "bar",
    		data: barData_dividends,
    		options: {
    			responsive: true,
    			legend: {
    				position: "top"
    			}
    		}
    	});
    
    	var ctx2 = document.getElementById("barChart_stockchart").getContext("2d");
    	window.myBar2 = new Chart(ctx2, {
    		type: "line",
    		data: barData_stockchart,
    		options: {
    			responsive: true,
    			legend: {
    				position: "top"
    			}
    		}
    	});
    
    	var ctx3 = document.getElementById("barChart_totalRevenue").getContext("2d");
    	window.myBar3 = new Chart(ctx3, {
    		type: "bar",
    		data: barData_totalRevenue,
    		options: {
    			responsive: true,
    			legend: {
    				position: "top"
    			}
    		}
    	});
    
    	var ctx4 = document.getElementById("barChart_stockholdersEquity").getContext("2d");
    	window.myBar4 = new Chart(ctx4, {
    		type: "bar",
    		data: barData_stockholdersEquity,
    		options: {
    			responsive: true,
    			legend: {
    				position: "top"
    			}
    		}
    	});
    
    	var ctx5 = document.getElementById("barChart_totalAssets").getContext("2d");
    	window.myBar5 = new Chart(ctx5, {
    		type: "bar",
    		data: barData_totalAssets,
    		options: {
    			responsive: true,
    			legend: {
    				position: "top"
    			}
    		}
    	});
    
    	var ctx6 = document.getElementById("barChart_capitalAdequacyRatio").getContext("2d");
    	window.myBar6 = new Chart(ctx6, {
    		type: "bar",
    		data: barData_capitalAdequacyRatio,
    		options: {
    			responsive: true,
    			legend: {
    				position: "top"
    			}
    		}
    	});
    
    	var ctx7 = document.getElementById("barChart_roe").getContext("2d");
    	window.myBar7 = new Chart(ctx7, {
    		type: "bar",
    		data: barData_roe,
    		options: {
    			responsive: true,
    			legend: {
    				position: "top"
    			}
    		}
    	});
    
    };
    head_parts.html
    <!DOCTYPE html>
    <html>
    <head>
        <title>条件を満たす銘柄</title>
        <style>
            .tab {
                overflow: hidden;
                border: 1px solid #ccc;
                background-color: #f1f1f1;
                display: flex;
            }
    
            .tab button {
                background-color: inherit;
                border: none;
                outline: none; 
                cursor: pointer;
                padding: 14px 16px;
                transition: 0.3s;
                flex-grow: 1;
            }
    
            .tab button:hover {
                background-color: #ddd;
            }
    
            .tab button.active {
                background-color: #ccc;
            }
    
            .tabcontent {
                display: none;
                height: 700px;
                padding: 6px 12px;
                border: 1px solid #ccc;
                border-top: none;
                flex-grow: 1;
            }
        </style>
    </head>
    <body>
    js_parts.html
    <script>
      function openTab(evt, tabName) {
          var i, tabcontent, tablinks;
          tabcontent = document.getElementsByClassName("tabcontent");
          for (i = 0; i < tabcontent.length; i++) {
              tabcontent[i].style.display = "none";
          }
          tablinks = document.getElementsByClassName("tablinks");
          for (i = 0; i < tablinks.length; i++) {
              tablinks[i].className = tablinks[i].className.replace(" active", "");
          }
          document.getElementById(tabName).style.display = "block";
          evt.currentTarget.className += " active";
      }
      document.getElementsByClassName("tablinks")[0].click();
    </script>
    </body>
    </html>
    report_template.html
    <!DOCTYPE html>
    <html>
    <head>
    	<title>{{ticker_name}}</title>
    	<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    </head>
    <body>
    	<h2>{{ticker_name}}</h2>
    	<table width="80%" border="1">
    		<tr>
    			<td>証券コード</td>
    			<td>{{ticker}}</td>
    		</tr>
    		<tr>
    			<td>市場・商品区分</td>
    			<td>{{market_product_category}}</td>
    		</tr>
    		<tr>
    			<td>業種</td>
    			<td>{{type_33}} {{type_17}}</td>
    		</tr>
    		<tr>
    			<td>配当金</td>
    			<td>{{dividendRate}}</td>
    		</tr>
    		<tr>
    			<td>配当利回り</td>
    			<td>{{dividendYield}}</td>
    		</tr>
    		<tr>
    			<td>配当性向</td>
    			<td>{{payoutRatio}}</td>
    		</tr>
    		<tr>
    			<td>時価総額</td>
    			<td>{{MarketCap}}</td>
    		</tr>
    		<tr>
    			<td>売上高</td>
    			<td>{{totalRevenue}}</td>
    		</tr>
    		<tr>
    			<td>ROE</td>
    			<td>{{ROE}}</td>
    		</tr>
    		<tr>
    			<td>配当履歴</td>
    			<td><canvas id="barChart_dividends"></canvas></td>
    		</tr>
    		<tr>
    			<td>株価チャート</td>
    			<td><canvas id="barChart_stockchart"></canvas></td>
    		</tr>
    		<tr>
    			<td>売上高</td>
    			<td><canvas id="barChart_totalRevenue"></canvas></td>
    		</tr>
    		<tr>
    			<td>株主資本</td>
    			<td><canvas id="barChart_stockholdersEquity"></canvas></td>
    		</tr>
    		<tr>
    			<td>総資産</td>
    			<td><canvas id="barChart_totalAssets"></canvas></td>
    		</tr>
    		<tr>
    			<td>自己資本比率</td>
    			<td><canvas id="barChart_capitalAdequacyRatio"></canvas></td>
    		</tr>
    		<tr>
    			<td>自己資本利益比率</td>
    			<td><canvas id="barChart_roe"></canvas></td>
    		</tr>
    	</table>
    	<script src="{{ticker}}_chart.js"></script>
    </body>
    </html>

    プログラムの実行前と実行後のファイル構成

    プログラムの実行前と実行後のファイル構成を下記にまとめました。

    プログラムの実行前のフォルダ構成

    作業フォルダ
        │  company_financial_info.csv
        │  company_match_condition.csv
        │  company_metrics.csv
        │  generate_report.py
        └─report
            │
            ├─generated
            │
            └─template
                   chart_template.js
                   head_parts.html
                   js_parts.html
                   report_template.html

    プログラムの実行後のフォルダ構成

    • reportフォルダの直下に[report_top.html]が生成されます。
    • generatedフォルダの直下に[証券コード.T_chart.js]と[証券コード.T_report.html]が生成されます。
    作業フォルダ
        │  company_financial_info.csv
        │  company_match_condition.csv
        │  company_metrics.csv
        │  generate_report.py
        └─report
            │  report_top.html
            │
            ├─generated
            │      3231.T_chart.js
            │      3231.T_report.html
            │      4974.T_chart.js
            │      4974.T_report.html
            │      6013.T_chart.js
            │      6013.T_report.html
            │      6432.T_chart.js
            │      6432.T_report.html
            │      7839.T_chart.js
            │      7839.T_report.html
            │
            └─template
                   chart_template.js
                   head_parts.html
                   js_parts.html
                   report_template.html

    プログラムの実行方法

    1. プログラム実行前に準備するファイル・フォルダの一覧」を参照してプログラムの実行に必要なファイル、フォルダを用意する。
    2. 掲載しているプログラムを任意のプログラム名で保存してください。ここでは「generate_report.py」としています。
    3. ファイル・フォルダ、プログラムの用意が済んだら下記のコマンドでプログラムを実行します。
      python generate_report.py
    4. 必要なファイルが揃っていない場合、下記のようなメッセージが表示されます。プログラムの実行に必要なファイルを用意し、再度実行してみてください。
      ./company_financial_info.csvを読み込めません。
    5. プログラムの実行は10~20秒ほどで完了します。
    6. [report]フォルダ内に[report_top.html]が生成されます。
    7. [report_top.html]をブラウザで参照すると、高配当の条件を満たした銘柄の情報を閲覧できます。

    次回、試したいこと

    レポートを生成するプログラムを作成しましたが、率直な感想として、以下の点が改善の余地があります。

    • レイアウトとグラフのデザインがダサく、魅力的ではありません。
    • 数値がカンマや単位といった整形がされておらず、読みにくいです。
    • レポートを見ても、抽出条件や選択基準が明確ではありません。
    • 会社概要が記載されていないため、どのような会社なのか一目で判別できません。

    まずは、レポートに会社概要を含める処理を追加してみることにします。会社概要の情報はchatGPTやBing AIから取得することで、できるだけ手間をかけずに取得することを考えています。

    コメント

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