応用編まとめ|高配当株スクリーニング自動化パイプラインの全体像と発展編接続

Chelsea-Labs #20 サムネイル

免責事項

本記事は投資助言を目的としたものではなく、技術・分析手法の紹介です。記事中のコード・パイプライン設計は教育目的であり、特定の銘柄・金融商品の売買を推奨するものではありません。投資判断はご自身の責任で行ってください。本記事中に J-Quants API から取得した実データは掲載していません(利用規約に基づく方針、詳細は 記事#13)。応用編シリーズの全テーブル・ビュー仕様は2026年5月時点の設計で、規制改定・サービス変更により修正が必要な場合があります。

前回の記事#19では、ポートフォリオ業種分散を FMEA(Failure Mode and Effects Analysis、故障モード影響解析)で設計し、応用編の SPC 4軸 + FMEA = 5層構成を整理しました。本記事は応用編シリーズ(#11〜#20、計10記事)の最終回として、これまで構築した高配当株スクリーニング自動化パイプラインのサンプルコードと手順を振り返り、発展編(#21〜#30、CAN-SLIM × 成長株分析)への接続点を提示します。

応用編シリーズで構築したものを、ひとことで言えば 「両学長スクリーニング基準を東証約3,900社に対して機械的に適用し、毎週の PASS 銘柄リストを LINE 通知で受け取る運用基盤の雛形」です。SPC(統計的工程管理)と FMEA という製造業 DX の品質保証作法を、投資データに応用した形で、サンプルコードを再現すれば自分のポートフォリオでも動かせる構造になっています。

本記事で扱う専門用語の予習

  • @step デコレータ: 関数の前後にログ出力を挟む Python のデコレータパターン。本記事の master_runner.py で各ステップの開始・完了を可視化
  • ARG_MAX(value, key) / ARG_MIN(value, key): DuckDB の集約関数。「key が最大のときの value」を返す(例: ARG_MAX(Close, Date) で「最新日の終値」)
  • CROSS JOIN: 2つのテーブルの全組合せを返す JOIN。本記事では「全銘柄 × TOPIX 1行」の組合せに使用
  • CAN-SLIM: オニール(William O’Neil)の成長株選定基準。Current EPS、Annual EPS、New product、Supply & demand、Leader、Institutional sponsorship、Market direction の7要素。発展編 #21 から本格的に扱う
  • TOPIX 相対変動率 -25%: 個別株変動率から TOPIX 変動率を引いた相対値。「市場全体に対して個別株が25%以上下落」を罠候補と判定(応用編 #17 の絶対値基準と区別)

本記事では、これまで先送りしてきた残課題を最後にまとめて整理します:

  • 残りの東証業種追加(応用編 #18/#19 で先送り): 証券・SI・陸運・空運・ガス・建設・サービス・倉庫・卸売・繊維、計25業種で東証主要部分(時価総額の概ね9割)をカバー。残8業種(鉱業・水産農林業・パルプ紙・ゴム・ガラス土石・精密機器・その他製品・その他金融)は今後の拡張対象
  • 市場ベースライン(TOPIX)併用(応用編 #17 で先送り): 個別株変動率から市場全体変動を引いた相対変動率で、市場全体ショック時の誤検知を低減(J-Quants の Premium プランで取得可能、Standard 以下では一般公開の TOPIX データを別ソースで補う運用)
  • portfolio_scores と v_screening_input の JOIN 仕様(応用編 #19 で先送り): ポートフォリオ単位スコアと個別銘柄評価を1ビューで参照可能に
  • パイプライン全体の起動スクリプト: 取得 → 統合 → 分析 → 罠検知 → 業種別補正 → 業種分散の11ステップ手順を順次実行

筆者は製造業の開発現場で、応用編シリーズが構造として再現している「品質保証システム集約プロジェクト」を実際に経験してきました。個別検査ライン × サプライチェーンFMEA × マスタデータ管理 × 自動化バッチを1プロジェクトに統合した経験は、応用編シリーズの構造と多くの部分で重なります。最後の本業エピソードでは、その同型対応を改めて整理します。

応用編シリーズで先送りした主要課題(発展編・運用フェーズで取り組む)

応用編シリーズの再現可能性を担保しつつ、以下の5課題は本記事の範囲を超えるため発展編・運用フェーズに送ります。読者は本記事の自動化パイプラインを動かしながら、課題ごとに実運用での検証と改善を進めるのが現実的です:

  • HHI 閾値の独禁法 vs 投資ポートフォリオ視点の切替: #19 で投資視点 (2000/3000) を default に、独禁法 (1500/2500) を引数で切替可能としたが、運用での最適閾値は実データで検証が必要
  • 業種間相関 0.7 / FMEA RPN スコアの根拠: #19 で導入した閾値・スコアは現状の標準作法をベースにしたもので、運用しながら自分の投資スタイルに合わせて調整する前提
  • 業種別閾値の出典精度: #18/#19/#20 で「業種別経営指標」「産業別経営動向調査」を出典としたが、四半期レビューでより精緻な数値に更新する運用
  • PASS から実際の購入までのギャップ: #15/#17 でも記述した通り、機械判定は暫定ラベル。事業内容・株価水準・ポートフォリオ全体との整合の定性調査が必須
  • マルコビッツ MVO(平均分散最適化)への先送り理由: 応用編は「両学長スクリーニング基準の機械化」を主題とし、MVO は別設計思想(過去リターン分布から最適配分を算出)。応用編の業種分散と組み合わせたい場合は、発展編 #29 のハイブリッド戦略で扱う

本記事で整う状態

  • 応用編 #11〜#19 のテーブル・ビュー・スクリプトすべてを master_runner.py 1本で起動する雛形が整う(実装の細部は各記事を参照する設計)
  • 東証主要25業種カバーで、未カバー業種による警告ログがほぼゼロに(残8業種は今後の拡張)
  • 市場ベースライン(TOPIX)併用で、コロナ・リーマンクラスのショック時にも罠検知の誤検知を低減
  • 1つのビュー v_full_screening(v5)で、個別 PASS 判定 + 業種別補正 + ポートフォリオスコアを統合参照
  • 応用編シリーズの自動化基盤の主要要素を網羅、発展編で CAN-SLIM × 成長株分析を載せる準備が整う

結論:応用編シリーズで構築した自動化パイプラインの雛形は「取得 × 統合 × 分析 × 罠検知 × 業種別補正 × 業種分散」の6フェーズ構成。SPC 4軸(個別品質管理)+ FMEA(ポートフォリオリスク管理)という製造業 DX の作法を投資データに応用することで、両学長スクリーニング基準の機械化と投資判断の品質保証を両立する設計が再現可能になる。発展編では、ここで作った基盤の上に CAN-SLIM × 成長株分析を載せ、配当株 × 成長株のハイブリッド戦略へ拡張する。

目次

応用編シリーズ #11〜#19 のサンプルコード振り返り

記事タイトルスタイル核心
#11なぜ高配当株か💭思想応用編の出発点。SPC 4軸 + FMEA を予告
#126基準のスペックシート💭思想USL/LSL 導入。両学長6基準をスペックシート化
#13J-Quants・EDINETでデータ取得🛠️実装取得層。3層分離アーキテクチャの宣言
#14DuckDB でデータ統合🛠️実装統合層。MDM × ELT パターンで4テーブル+2ビュー
#15全銘柄スクリーニング自動化🛠️実装判定層。multiprocessing + LINE通知 + cron/Actions
#16配当推移の安定性(時系列)🔬分析UCL/LCL 導入。連続非減少 / CV / rolling 移動平均
#17罠銘柄検知(IQR/Z/SPC)🔬分析第3軸 IQR/Z/SPC + WER。バリュートラップ候補フラグ
#18業種別財務健全性💭思想+🛠️実装第4軸 業種別補正テーブル(10業種、BIS/LTV/格付け 等)
#19業種分散の FMEA💭思想+🔬分析第5層 FMEA。HHI × 相関 × RPN(15業種に拡張)
#20応用編まとめ(本記事)💭+🛠️11ステップ手順 + 25業種カバー + TOPIX 併用 + 発展編接続

パイプライン全体像(6フェーズ構成)と11ステップ手順

┌────── 取得層(記事#13)──────┐
│  J-Quants → prices_daily       │
│             fins_statements    │
│  EDINET   → edinet_metrics     │
│  TOPIX    → topix_daily(#20追加)│
└──────────────┬─────────────────┘
               ▼
┌────── 統合層(記事#14)──────────┐
│  companies(マスタ、25業種)        │
│  industry_indicator_map(補正規則) │
│  v_latest_metrics(最新集約ビュー)  │
└──────────────┬───────────────────┘
               ▼
┌────── 判定層 SPC 4軸 ───────────────────────────┐
│  USL/LSL(規格限界、#12 両学長基準)              │
│  UCL/LCL(管理限界 ±3σ、#16 シューハート管理図)  │
│  IQR/Z(外れ値、#17 罠検知)                       │
│  業種別補正テーブル(#18 10業種→#20 25業種)       │
│  spec_sheet_judge_v2.py + screen_parallel.py     │
└──────────────┬──────────────────────────────────┘
               ▼
┌────── 通知層(記事#15)──────┐
│  LINE Messaging API + cron / GitHub Actions │
└──────────────┬─────────────────────────────┘
               ▼
┌────── ポートフォリオ層 FMEA(記事#19、#20で拡張)──────┐
│  HHI(業種集中度)                                       │
│  業種間相関(テールリスク連動)                          │
│  FMEA RPN(リスク優先順位)                              │
│  TOPIX 相対変動率(市場全体ショックへの対応、本記事追加) │
│  v_full_screening(v5、本記事の最終JOIN)                │
└─────────────────────────────────────────────────────────┘

11ステップ手順(master_runner.py で順次実行)

  1. データ取得: J-Quants(株価・財務サマリ)+ EDINET(XBRL)+ TOPIX(市場ベースライン)
  2. EDINET 正規化: XBRL → edinet_metrics の正規化スキーマに変換
  3. マスタテーブル更新: 25業種の industry_indicator_map をシード
  4. 統合ビュー更新: v_latest_metrics で銘柄ごとに最新値を集約
  5. 時系列指標計算: 連続非減少年数 / CV / rolling 移動平均(記事 #16)
  6. バリュートラップ候補検知: IQR/Z/SPC + WER(記事 #17)
  7. 記念配当検知: 過去中央値の1.5倍以上(記事 #18)
  8. 最終ビュー更新: v_full_screening v5 で全要素を1ビュー化
  9. スクリーニング判定: multiprocessing で並列判定(記事 #15)
  10. ポートフォリオスコア更新: HHI × 相関 × RPN(記事 #19)
  11. LINE 通知: PASS 銘柄を LINE Messaging API で送信(記事 #15)

エンジニア的に言い換えると(生産ライン起動シーケンス)

11ステップは、製造業 DX で言う 「生産ライン起動シーケンス」そのものです。検査機・搬送装置・梱包機の起動順序を1スクリプトで管理する仕組みと同型で、本記事の master_runner.py は cron / GitHub Actions の1行で起動できる設計です。11ステップが順序依存しているのは、製造業の検査ラインで「素材投入 → 加工 → 検査 → 梱包」が順序依存しているのと同じ。設計上の必然性です。

応用編シリーズで開発したコードファイル一覧(30本)

ファイル役割記事
jquants_auth.py / jquants_fetch.pyJ-Quants 認証・取得#13
edinet_fetch.py / normalize_edinet.pyEDINET XBRL 取得・正規化#13/#14
save_to_duckdb.py / ddl_setup.pyDuckDB 保存・スキーマ#13/#14
view_normalized.py / view_screening.pyv_latest_metrics / v_screening_input#14
industry_map_seed*.py業種別補正テーブル(10→15→25業種)#14/#18/#19/#20
spec_sheet_judge_v2.py業種補正対応の判定器#15
screen_parallel.py / notify_line.py並列判定 + LINE 通知#15
load_history.py / compute_persistence.py時系列指標#16
visualize_history.pymatplotlib 3パネル可視化#16
persistence_table.pypersistence_metrics + ビュー統合#16
detect_yield_outliers.py / detect_value_trap.pyIQR/Z + 動的検出#17
spc_control_limits.py / build_flags_df.pySPC 管理限界 + フラグ統合#17
trap_flags_table.py / industry_cv_threshold.py罠フラグ + 業種別CV閾値#17/#18
detect_special_dividend.py記念配当検知 + ビュー v4#18
industry_dashboard.py業種別箱ひげ図ダッシュボード#18
compute_hhi.py / compute_industry_correlation.pyHHI + 相関#19
fmea_rpn.py / portfolio_scores.pyFMEA RPN + ポートフォリオスコア#19
master_runner.py(本記事追加)パイプライン全体起動#20
topix_baseline.py(本記事追加)TOPIX 取得 + 相対変動率#20
final_view_v5.py(本記事追加)v_full_screening 最終JOINビュー#20

スニペット1:master_runner.py のサンプルコード(パイプライン1コマンド起動の雛形)

応用編 #13〜#19 の各スクリプトを順序通りに起動するマスターランナーの雛形を実装します。各ステップの実装は対応する記事を参照してください(本コードは「順序の枠組み」と「実装委譲先」を明示する設計です)。

# master_runner.py — 応用編パイプライン全体の起動スクリプト(雛形)
# 動作環境: Python 3.11+ / duckdb 1.0+ / 各依存パッケージ
import functools
import logging
import sys
from datetime import date

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger("master_runner")

def step(name: str):
    """ステップごとの開始・完了をログ出力するデコレータ(functools.wraps で関数情報保持)"""
    def decorator(fn):
        @functools.wraps(fn)
        def wrapper(*args, **kwargs):
            logger.info(f"=== START: {name} ===")
            try:
                result = fn(*args, **kwargs)
                logger.info(f"=== DONE:  {name} ===")
                return result
            except Exception as e:
                logger.exception(f"FAILED: {name} - {e}")
                raise
        return wrapper
    return decorator

@step("1. データ取得(J-Quants + EDINET + TOPIX)")
def step_fetch():
    """記事 #13 / #20 の各取得モジュールを順次呼び出す(実装は各記事参照)"""
    raise NotImplementedError(
        "実装は応用編 #13 の jquants_fetch.py / edinet_fetch.py + 本記事の topix_baseline.py を参照"
    )

@step("2. EDINET XBRL 正規化")
def step_normalize_edinet():
    """記事 #13/#14 の normalize_edinet.upsert_edinet_metrics を呼ぶ"""
    raise NotImplementedError("実装は応用編 #13/#14 の normalize_edinet.py を参照")

@step("3. マスタテーブル更新(25業種)")
def step_seed_master():
    """10業種 + 5業種拡張 + 残り10業種の SEED で計25業種"""
    from industry_map_seed_v2 import seed_industry_map_v2          # 10業種(#18)
    from portfolio_scores import add_additional_industries          # +5業種(#19)
    from industry_map_seed_full import seed_remaining_industries    # +10業種(#20)
    seed_industry_map_v2()
    add_additional_industries()
    seed_remaining_industries()
    logger.info("Industry map: 10 (#18) + 5 (#19) + 10 (#20) = 25 industries seeded")

@step("4. 統合ビュー更新(v_latest_metrics)")
def step_update_views():
    from view_normalized import create_latest_view
    create_latest_view()

@step("5. 時系列指標計算(連続非減少 / CV / rolling)")
def step_persistence():
    """記事 #16 の compute_persistence_metrics + persistence_table.upsert_persistence"""
    raise NotImplementedError("実装は応用編 #16 の load_history.py + compute_persistence.py を参照")

@step("6. バリュートラップ候補検知(IQR/Z/SPC + WER)")
def step_value_trap():
    from build_flags_df import build_value_trap_flags
    from trap_flags_table import upsert_trap_flags
    flags = build_value_trap_flags()
    upsert_trap_flags(flags)

@step("7. 記念配当検知")
def step_special_dividend():
    """記事 #18 の detect_special_dividend + upsert_special_dividend_flags"""
    raise NotImplementedError(
        "実装は応用編 #18 の detect_special_dividend.py(upsert_special_dividend_flags 関数)を参照"
    )

@step("8. 最終ビュー更新(v_full_screening v5)")
def step_final_view():
    from final_view_v5 import setup_final_view
    setup_final_view()

@step("9. スクリーニング判定(並列)")
def step_screening():
    from screen_parallel import run_screening_parallel
    run_screening_parallel()

@step("10. ポートフォリオスコア更新(HHI / 相関 / RPN)")
def step_portfolio_scores():
    """記事 #19 の compute_hhi + compute_correlation_matrix + fmea_rpn の統合"""
    raise NotImplementedError(
        "実装は応用編 #19 の compute_hhi.py + compute_industry_correlation.py + fmea_rpn.py を参照"
    )

@step("11. LINE 通知")
def step_notify():
    from notify_line import notify_today
    notify_today()

def main(skip_unimplemented: bool = False):
    today = date.today().isoformat()
    logger.info(f"=== Master Runner START ({today}) ===")
    steps = [step_fetch, step_normalize_edinet, step_seed_master, step_update_views,
             step_persistence, step_value_trap, step_special_dividend, step_final_view,
             step_screening, step_portfolio_scores, step_notify]
    try:
        for fn in steps:
            try:
                fn()
            except NotImplementedError as e:
                if skip_unimplemented:
                    logger.warning(f"SKIP (unimplemented): {fn.__name__} - {e}")
                    continue
                raise
        logger.info(f"=== Master Runner DONE ({today}) ===")
    except Exception as e:
        logger.exception(f"Master Runner FAILED: {e}")
        sys.exit(1)

if __name__ == "__main__":
    # 開発初期は --skip-unimplemented で動く部分だけ確認、本番運用前に全ステップ実装
    main(skip_unimplemented=("--skip-unimplemented" in sys.argv))

形式の罠:master_runner は「順序の枠組み」、実装は各記事に委譲

本コードは NotImplementedError明示的に実装委譲先を案内する設計です。すべてのステップを完成させてから動かすのではなく、動かせる部分(マスタ更新・統合ビュー・罠検知・最終ビュー・スクリーニング・通知)から順次起動して、未実装ステップは --skip-unimplemented でスキップする運用が現実的です。発展編 #21 以降で各ステップの実装を順次完成させていきます。

スニペット2:残り業種を追加して東証主要25業種カバー

応用編 #18 で10業種、#19 で15業種までカバーしていましたが、本記事で残り10業種(証券・SI・陸運・空運・ガス・建設・サービス・倉庫・卸売・繊維)を追加し、計25業種で東証主要部分(時価総額の概ね9割)をカバーします。残8業種(鉱業・水産農林業・パルプ紙・ゴム・ガラス土石・精密機器・その他製品・その他金融)は今後の拡張対象です。

# industry_map_seed_full.py — 残り10業種の SEED で計25業種にカバレッジ拡張
# 動作環境: Python 3.11+ / duckdb 1.0+
import duckdb
import pandas as pd
from pathlib import Path

DB_PATH = Path("data/stocks.duckdb")

REMAINING_INDUSTRIES = pd.DataFrame([
    {"industry_profile": "securities", "standard_indicator": "equity_ratio",
     "alt_indicator": "net_capital_ratio", "direction": "higher_better",
     "threshold_pass": 200.0, "threshold_caution": 120.0,
     "note": "証券業: 純資本規制比率 200%以上が健全(規制基準は120%)",
     "source": "金融庁 証券会社の自己資本規制比率(2026年5月)"},
    {"industry_profile": "system_integrator", "standard_indicator": "equity_ratio",
     "alt_indicator": "operating_margin", "direction": "higher_better",
     "threshold_pass": 8.0, "threshold_caution": 4.0,
     "note": "SI: 営業利益率 8%以上で健全、業界中央値は5-7%",
     "source": "業種別経営指標(情報サービス業、2026年5月)"},
    {"industry_profile": "land_transport", "standard_indicator": "equity_ratio",
     "alt_indicator": None, "direction": "higher_better",
     "threshold_pass": 35.0, "threshold_caution": 25.0,
     "note": "陸運: 設備投資が大きく自己資本比率35%以上で健全",
     "source": "業種別経営指標(陸運業、2026年5月)"},
    {"industry_profile": "air_transport", "standard_indicator": "equity_ratio",
     "alt_indicator": "debt_to_ebitda", "direction": "lower_better",
     "threshold_pass": 4.0, "threshold_caution": 6.0,
     "note": "空運: 大型航空機投資のレバレッジが高い、Debt/EBITDA 4倍以下で健全",
     "source": "業種別動向(航空運輸業、2026年5月)"},
    {"industry_profile": "gas_utility", "standard_indicator": "equity_ratio",
     "alt_indicator": "debt_to_ebitda", "direction": "lower_better",
     "threshold_pass": 5.0, "threshold_caution": 7.0,
     "note": "ガス: 装置産業、Debt/EBITDA 5倍以下で健全(電力・通信と同型)",
     "source": "業種別動向(ガス事業、2026年5月)"},
    {"industry_profile": "construction", "standard_indicator": "equity_ratio",
     "alt_indicator": None, "direction": "higher_better",
     "threshold_pass": 35.0, "threshold_caution": 25.0,
     "note": "建設業: 受注先行型、自己資本比率35%以上で健全",
     "source": "業種別経営指標(建設業、2026年5月)"},
    {"industry_profile": "services", "standard_indicator": "equity_ratio",
     "alt_indicator": None, "direction": "higher_better",
     "threshold_pass": 40.0, "threshold_caution": 30.0,
     "note": "サービス業: 設備依存が中程度、自己資本比率40%以上で健全(業界中央値 30-45%)",
     "source": "業種別経営指標(サービス業、2026年5月)"},
    {"industry_profile": "warehouse", "standard_indicator": "equity_ratio",
     "alt_indicator": "debt_to_ebitda", "direction": "lower_better",
     "threshold_pass": 5.0, "threshold_caution": 7.0,
     "note": "倉庫業: 不動産依存型、Debt/EBITDA 5倍以下で健全",
     "source": "業種別経営指標(倉庫・運輸業、2026年5月)"},
    {"industry_profile": "wholesale", "standard_indicator": "equity_ratio",
     "alt_indicator": None, "direction": "higher_better",
     "threshold_pass": 30.0, "threshold_caution": 20.0,
     "note": "卸売業: 商社系を除く一般卸、自己資本比率30%以上で健全",
     "source": "業種別経営指標(卸売業、2026年5月)"},
    {"industry_profile": "textile", "standard_indicator": "equity_ratio",
     "alt_indicator": None, "direction": "higher_better",
     "threshold_pass": 40.0, "threshold_caution": 30.0,
     "note": "繊維: 成熟産業、自己資本比率40%以上で安定",
     "source": "業種別経営指標(繊維業、2026年5月)"},
])

INSERT_COLUMNS = "(industry_profile, standard_indicator, alt_indicator, direction, threshold_pass, threshold_caution, note, source)"

def seed_remaining_industries() -> None:
    """残り10業種を industry_indicator_map に追加(既存15業種は変更しない)"""
    with duckdb.connect(str(DB_PATH)) as conn:
        conn.register("rem_df", REMAINING_INDUSTRIES)
        conn.execute("BEGIN")
        try:
            conn.execute("""
                DELETE FROM industry_indicator_map
                WHERE (industry_profile, standard_indicator) IN
                    (SELECT industry_profile, standard_indicator FROM rem_df)
            """)
            conn.execute(f"""
                INSERT INTO industry_indicator_map {INSERT_COLUMNS}
                SELECT industry_profile, standard_indicator, alt_indicator, direction,
                       threshold_pass, threshold_caution, note, source FROM rem_df
            """)
            conn.execute("COMMIT")
        except Exception:
            conn.execute("ROLLBACK")
            raise
        finally:
            conn.unregister("rem_df")
        n = conn.execute("SELECT COUNT(DISTINCT industry_profile) FROM industry_indicator_map").fetchone()[0]
        print(f"industry_profiles count: {n}")

if __name__ == "__main__":
    seed_remaining_industries()

エンジニア的に言い換えると(製品ファミリー追加プロセス)

残り10業種の追加は、製造業 DX で言う 「製品ファミリー追加プロセス」そのものです。既存ファミリーの検査閾値テーブルを破壊せずに新ファミリーを追加するパターンが、本コードの DELETE→INSERT の真の冪等性で再現されています。投資データでも、新業種を追加するたびにコードを書き換えるのではなく、SEED テーブルに行を追加するだけで運用できる設計です。

スニペット3:TOPIX 相対変動率で市場全体ショック時の罠検知を改善する手順

応用編 #17 で「市場全体ショック時(コロナ・リーマンクラス)には罠フラグが大量発生する」課題を指摘していました。本記事で TOPIX を市場ベースラインとして取り込み、個別株の絶対変動率ではなく「TOPIX に対する相対変動率」で罠検知することで、市場全体のショック影響を相殺します。

TOPIX -25% 閾値の根拠(相対変動率の分布特性)

  • 平常時の相対変動率: 個別株 vs TOPIX で ±10〜15% 程度の分布が一般的
  • 緩やかな下落局面: 個別株が市場以上に -15〜-25% 下落 → 業種固有の懸念材料の可能性
  • -25% 以下: 個別株が市場全体に対して構造的に下落 → 罠候補として要警戒
  • クライシス時: 市場全体が -30% 下落しても個別株の相対変動が ±5% 内なら、単純な絶対値判定より精度が高い

応用編 #17 の絶対値 -25% を「市場全体下落時には機能しない」と指摘していましたが、TOPIX 相対値 -25% を併用することで、市場全体ショック時にも個別株固有の問題を検出できる設計になります。

J-Quants プラン要件と TOPIX 取得方法

J-Quants の TOPIX エンドポイント(/indices/topix)は Premium プラン以上で利用可能。Standard 以下のプランの場合は、別ソース(公的統計 API・取引所公式 CSV)から TOPIX データを取得して topix_daily テーブルに投入する運用になります。本コードは取得元を抽象化(fetch_topix_daily 関数の実装で切替)する設計です。

# topix_baseline.py — TOPIX を市場ベースラインとして相対変動率を計算
# 動作環境: Python 3.11+ / duckdb 1.0+ / pandas 2.x / requests
import os
import duckdb
import pandas as pd
import requests
from datetime import date, timedelta
from pathlib import Path

DB_PATH = Path("data/stocks.duckdb")

DDL_TOPIX = """
CREATE TABLE IF NOT EXISTS topix_daily (
    date    DATE PRIMARY KEY,
    close   DOUBLE NOT NULL,
    fetched_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
"""

JQUANTS_TOPIX_URL = "https://api.jquants.com/v1/indices/topix"  # Premium プラン以上

def setup_topix_table() -> None:
    """TOPIX 日次データテーブルの作成"""
    with duckdb.connect(str(DB_PATH)) as conn:
        conn.execute(DDL_TOPIX)

def fetch_topix_daily(id_token: str, days: int = 365) -> pd.DataFrame:
    """J-Quants の TOPIX エンドポイントから過去 N 日分を取得(Premium プラン要)

    Premium プラン未契約の場合は、別ソース(取引所公式 CSV 等)からの取得関数に置換
    """
    headers = {"Authorization": f"Bearer {id_token}"}
    today = date.today().strftime("%Y%m%d")
    from_date = (date.today() - timedelta(days=days)).strftime("%Y%m%d")
    params = {"from": from_date, "to": today}
    resp = requests.get(JQUANTS_TOPIX_URL, headers=headers, params=params, timeout=60)
    resp.raise_for_status()
    rows = resp.json().get("topix", [])
    df = pd.DataFrame(rows)
    return df.rename(columns={"Date": "date", "Close": "close"})[["date", "close"]]

def upsert_topix_daily(df: pd.DataFrame) -> None:
    """TOPIX 日次データを idempotent に保存"""
    with duckdb.connect(str(DB_PATH)) as conn:
        conn.register("topix_df", df)
        conn.execute("BEGIN")
        try:
            conn.execute("DELETE FROM topix_daily WHERE date IN (SELECT date FROM topix_df)")
            conn.execute("INSERT INTO topix_daily (date, close) SELECT date, close FROM topix_df")
            conn.execute("COMMIT")
        except Exception:
            conn.execute("ROLLBACK")
            raise
        finally:
            conn.unregister("topix_df")

def fetch_relative_price_changes(lookback_days: int = 365) -> pd.DataFrame:
    """個別株 vs TOPIX の相対変動率(直近1年)を計算

    返却カラム:
    ticker_normalized / price_change_pct_1y / topix_change_pct_1y / relative_change_pct_1y

    relative = (個別株変動率) - (TOPIX変動率)
    relative <= -25% で「市場全体に対して個別株が大きく下落」と判定
    """
    sql = """
    WITH
      latest_close AS (
        SELECT
          CASE WHEN LENGTH(Code) = 5 THEN SUBSTRING(Code, 1, 4) ELSE Code END AS ticker_normalized,
          ARG_MAX(Close, Date) AS close_now,
          ARG_MIN(Close, Date) AS close_old
        FROM prices_daily
        WHERE Date >= CURRENT_DATE - CAST(? AS INTEGER) * INTERVAL '1' DAY
        GROUP BY (CASE WHEN LENGTH(Code) = 5 THEN SUBSTRING(Code, 1, 4) ELSE Code END)
      ),
      topix_range AS (
        SELECT
          ARG_MAX(close, date) AS topix_now,
          ARG_MIN(close, date) AS topix_old
        FROM topix_daily
        WHERE date >= CURRENT_DATE - CAST(? AS INTEGER) * INTERVAL '1' DAY
      )
    SELECT
      l.ticker_normalized,
      ((l.close_now - l.close_old) / NULLIF(l.close_old, 0)) * 100 AS price_change_pct_1y,
      ((t.topix_now - t.topix_old) / NULLIF(t.topix_old, 0)) * 100 AS topix_change_pct_1y,
      (((l.close_now - l.close_old) / NULLIF(l.close_old, 0)) -
       ((t.topix_now - t.topix_old) / NULLIF(t.topix_old, 0))) * 100 AS relative_change_pct_1y
    FROM latest_close l
    CROSS JOIN topix_range t
    """
    with duckdb.connect(str(DB_PATH)) as conn:
        return conn.execute(sql, [lookback_days, lookback_days]).fetchdf()

# 使用例
# setup_topix_table()
# df_topix = fetch_topix_daily(id_token=os.environ["JQUANTS_ID_TOKEN"])
# upsert_topix_daily(df_topix)
# changes = fetch_relative_price_changes(lookback_days=365)
# value_traps = changes[changes["relative_change_pct_1y"] <= -25]
# print(value_traps.head())

スニペット4:v_full_screening v5(応用編パイプラインの最終JOIN)

応用編 #19 で先送りしていた portfolio_scoresv_screening_input の JOIN 仕様を本記事で確定します。v_full_screening v5 として、個別銘柄評価 + 業種別補正 + ポートフォリオスコア + TOPIX相対変動率を1ビューで参照可能にします(v1 で記載した冗長な ROW_NUMBER パターンを簡略化)。

# final_view_v5.py — v_full_screening v5(応用編パイプラインの最終JOIN、v2: 簡略化)
# 動作環境: Python 3.11+ / duckdb 1.0+
import duckdb
from pathlib import Path

DB_PATH = Path("data/stocks.duckdb")

# relative_price_changes_view: TOPIX 相対変動率を ticker 単位で持つビュー
DDL_RELATIVE_VIEW = """
CREATE OR REPLACE VIEW relative_price_changes_view AS
WITH
  latest_close AS (
    SELECT
      CASE WHEN LENGTH(Code) = 5 THEN SUBSTRING(Code, 1, 4) ELSE Code END AS ticker_normalized,
      ARG_MAX(Close, Date) AS close_now,
      ARG_MIN(Close, Date) AS close_old
    FROM prices_daily
    WHERE Date >= CURRENT_DATE - 365 * INTERVAL '1' DAY
    GROUP BY (CASE WHEN LENGTH(Code) = 5 THEN SUBSTRING(Code, 1, 4) ELSE Code END)
  ),
  topix_range AS (
    SELECT ARG_MAX(close, date) AS topix_now, ARG_MIN(close, date) AS topix_old
    FROM topix_daily WHERE date >= CURRENT_DATE - 365 * INTERVAL '1' DAY
  )
SELECT
  l.ticker_normalized,
  ((l.close_now - l.close_old) / NULLIF(l.close_old, 0)) * 100 AS price_change_pct_1y,
  ((t.topix_now - t.topix_old) / NULLIF(t.topix_old, 0)) * 100 AS topix_change_pct_1y,
  (((l.close_now - l.close_old) / NULLIF(l.close_old, 0)) -
   ((t.topix_now - t.topix_old) / NULLIF(t.topix_old, 0))) * 100 AS relative_change_pct_1y
FROM latest_close l CROSS JOIN topix_range t
;
"""

# v_full_screening v5: 全要素を1ビューに集約(v1 の冗長 ROW_NUMBER を削除)
DDL_VIEW_V5 = """
CREATE OR REPLACE VIEW v_full_screening AS
SELECT
  s.ticker_normalized, s.name_jp, s.industry_profile,
  s.yield_pct, s.payout, s.equity_ratio,
  s.bis_ratio, s.ltv, s.credit_rating_score,
  s.eps_trend, s.consec_inc_years, s.ocf_positive_years,
  s.value_trap_flag, s.value_trap_severity,
  s.iqr_outlier, s.zscore_outlier, s.spc_outlier,
  s.special_dividend_flag,
  s.equity_ratio_pass_threshold, s.equity_ratio_alt_indicator, s.equity_ratio_direction,
  -- TOPIX 相対変動率(本記事追加、ticker 単位)
  rel.relative_change_pct_1y,
  rel.price_change_pct_1y,
  rel.topix_change_pct_1y,
  -- ポートフォリオスコア(記事 #19、score_id=1 をデフォルト保有ポートフォリオと仮定)
  ps.hhi, ps.weighted_rpn, ps.high_corr_pair_count, ps.score_summary AS portfolio_summary
FROM v_screening_input s
LEFT JOIN relative_price_changes_view rel ON s.ticker_normalized = rel.ticker_normalized
LEFT JOIN portfolio_scores ps ON ps.score_id = 1
;
"""

def setup_final_view() -> None:
    with duckdb.connect(str(DB_PATH)) as conn:
        conn.execute("BEGIN")
        try:
            conn.execute(DDL_RELATIVE_VIEW)
            conn.execute(DDL_VIEW_V5)
            conn.execute("COMMIT")
        except Exception:
            conn.execute("ROLLBACK")
            raise
        n = conn.execute("SELECT COUNT(*) FROM v_full_screening").fetchone()[0]
        print(f"v_full_screening rows: {n}")

if __name__ == "__main__":
    setup_final_view()

エンジニア的に言い換えると(製造業の最終出荷判定パネル)

v_full_screening v5 は、製造業 DX で言う 「最終出荷判定パネル」そのものです。複数の検査ライン(個別銘柄評価・業種補正・時系列・罠検知・ポートフォリオスコア)の結果を1画面に集約し、出荷可否を判断する装置と同型。投資データでも1つのビューですべての判定結果を参照できる構造があれば、運用判断の意思決定が大幅に楽になります。

設計判断の記録:応用編まとめ固有の4判断 + 応用編全体俯瞰表

判断0:応用編まとめ #20 で記録すべき4判断

本記事は応用編シリーズ最終回として、まとめ記事固有の設計判断を4つ記録します。判断1(master_runner 方式)は運用効率に直結、判断2(25業種カバレッジ)はカバレッジと精度のバランス、判断3(TOPIX 相対変動率)は罠検知の精度向上、判断4(v5 最終JOIN)はビュー統合の運用負荷を左右します。

判断1:master_runner 方式(NotImplementedError による委譲)か全実装統合か

  • 採用理由: 応用編まとめ記事の役割は「順序の枠組みと実装委譲先の明示」。各ステップの実装は対応する記事を参照し、本コードは雛形に留める
  • 採用したことで失うもの:
    • トリガー条件: 「コピペで全部動く」期待を持つ読者には不親切
    • 残るメリット: 各記事の独立性が保たれ、記事ごとに更新できる。NotImplementedError で実装委譲先を明示するため迷子にならない
    • 対処: --skip-unimplemented オプションで動く部分だけ起動可能
  • 本業 DX との同型対応: 製造業の生産ライン起動シーケンスでも「全装置完成してから起動」ではなく「ステージごとの段階稼働」が現実的

判断2:業種カバレッジを25業種にするか33業種完全カバーにするか

  • 採用理由: 25業種で東証時価総額の概ね9割をカバー。残8業種(鉱業・水産農林業・パルプ紙・ゴム・ガラス土石・精密機器・その他製品・その他金融)は規模が小さく優先度が低い
  • 採用したことで失うもの:
    • トリガー条件: 残8業種の銘柄を保有している場合、業種補正が manufacturing にデフォルト適用される
    • 残るメリット: 主要業種に集中することで、各業種の SEED データの品質を高く保てる
    • 対処: 必要に応じて発展編・運用フェーズで残8業種を追加(テンプレートは確立済み)
  • 本業 DX との同型対応: 製造業でも「全製品ファミリーカバー」より「主要ファミリー先行 + 後続追加」が標準

判断3:TOPIX 相対変動率を導入するか単純な絶対値を維持するか

  • 採用理由: 市場全体ショック時の罠検知の誤検知低減。応用編 #17 で指摘した課題への対応
  • 採用したことで失うもの:
    • トリガー条件: J-Quants Premium プラン未契約の場合、別ソースから TOPIX 取得が必要
    • 残るメリット: 市場全体下落時にも個別株固有の問題を検出可能
    • 対処: fetch_topix_daily を抽象化して、別ソースからの取得関数に切替可能
  • 本業 DX との同型対応: 製造業の品質管理でも「業界全体の不良率トレンドを差し引いた個別工程の異常」を見るのが標準

判断4:v_full_screening v5 を最終ビューにするか個別ビュー併用か

  • 採用理由: 1つのビューで全要素を参照可能。応用編 #15 のスクリーニング Runner が v_full_screening を読むだけで全判定材料が揃う
  • 採用したことで失うもの:
    • トリガー条件: 個別の指標だけ見たい場合(例: バリュートラップだけ抽出)でも全カラムが返る
    • 残るメリット: スクリーニング判定器のコードを変えずに新指標を追加可能
    • 対処: SELECT で必要カラムだけ取得することでオーバーヘッドを低減
  • 本業 DX との同型対応: 製造業でも「最終出荷判定パネル」で全検査結果を1画面で見るのが定石

応用編全体の判断俯瞰表(#13〜#20 の主要設計判断)

記事主要判断採用
#13データソース選定J-Quants + EDINET(公式 API 優先)
#14DB / アーキテクチャDuckDB + ELT パターン + マスタ駆動
#15並列化 / 通知 / スケジューラmultiprocessing + LINE + cron/Actions
#16連続増配判定連続非減少(同額据え置きOK)+ rolling 移動平均
#17異常値検知IQR + Z スコア + SPC 管理限界 + WER の3層フィルタ
#18業種別補正業種別代替指標テーブル(10業種)+ direction カラム
#19ポートフォリオ評価HHI + 業種間相関 + FMEA RPN(投資視点閾値)
#20パイプライン統合master_runner 委譲方式 + 25業種 + TOPIX + v5

応用編シリーズ「SPC 4軸 + FMEA = 5層構成」の整理

  • 第1層 USL/LSL(規格限界、両学長スクリーニング基準): 記事 #11/#12 — 配当利回り 4-8%、自己資本比率 40% 以上 等の合否ライン
  • 第2層 UCL/LCL(管理限界 ±3σ、SPC 異常値): 記事 #16 — シューハート管理図、業種内分布から ±3σ 逸脱を検出
  • 第3層 IQR / Z スコア / WER(外れ値・連続性): 記事 #17 — IQR 第1段、Z スコア第2段、WER 連続性で構造異常検出
  • 第4層 業種別補正テーブル(製品ファミリー別検査): 記事 #18 — 25業種の代替指標(BIS/LTV/格付け/ソルベンシー 等)
  • 第5層 FMEA(ポートフォリオ全体のリスク管理): 記事 #19 — HHI × 相関 × RPN でセクター集中リスク

SPC が「個別品質管理」、FMEA が「全体リスク管理」という役割分担で、両者を組み合わせることで応用編シリーズの自動化システムが品質保証の主要要素を網羅した構造になります。本記事で TOPIX 相対変動率と最終JOINビューが追加され、再現可能な雛形として運用可能な状態です。

発展編(CAN-SLIM × 成長株分析)への接続点

応用編シリーズで構築した自動化基盤は、そのまま発展編(記事 #21〜#30、CAN-SLIM × 成長株分析)の土台として活用できます。発展編で扱う内容と応用編との対応:

発展編記事テーマ応用編からの再利用
#21なぜ成長株か(オニール CAN-SLIM 概要)応用編 #11 と同型の導入回
#22CAN-SLIMの C(当期EPS)— Python実装spec_sheet_judge_v2 を成長株版に拡張
#23CAN-SLIMの A(年間EPS成長率)— 可視化matplotlib 3パネル可視化を再利用
#24C×A 複合スクリーニングscreen_parallel.py に CAN-SLIM 版判定器を追加
#25事業構造分析(製品アーキテクト視点)業種別補正テーブルに「成長フェーズ」追加
#26固有値分解で銘柄クラスタリング(PCA)業種間相関を PCA で次元削減
#27情報理論(エントロピー・相互情報量)「どの指標が銘柄選定に効くか」の定量化
#28CAN-SLIMの N(新製品)を NLP で分析EDINET XBRL に決算短信テキスト抽出を追加
#29高配当株 × 成長株のハイブリッド戦略応用編 + 発展編の判定器を1パイプラインで運用、マルコビッツ MVO もここで導入検討
#30シリーズ総括(30記事全体)3段階モデル(基礎→応用→発展)の集大成

発展編では、応用編の SPC 4軸 + FMEA に加えて、機械学習・統計学的手法(PCA、エントロピー、NLP) を組み合わせます。応用編が「両学長スクリーニングを Python で再現」だったのに対し、発展編は「CAN-SLIM をエンジニアリング視点で深化させる」フェーズで、Chelsea-Labs シリーズの DX 横展開の集大成になります。

本業の話:応用編シリーズの構造そのものが「品質保証システム集約プロジェクト」

筆者が製造業の開発部門で、新製品の品質保証システム集約プロジェクトを担当した経験があります。プロジェクトの構造が、応用編シリーズ #11〜#20 と多くの部分で重なっていました:

本業のフェーズ応用編対応記事現場の質的記述
製品スペックシート設計両学長基準 + USL/LSL#11/#12承認会議4回、設計部門・購買・QA の合意形成に2ヶ月
検査データ取得(複数ライン)J-Quants + EDINET#13各拠点5系統からのデータ統合、SCADA 連携に3ヶ月
検査データ統合(マスタDB)DuckDB データマート#14SQL Server 構築、初期データクレンジングに6ヶ月
並列検査ライン稼働multiprocessing スクリーニング#155並列ラインで1日500台、初期不良率0.3%(記事#15参照)
長期信頼性試験データ評価時系列分析(連続非減少 / CV / rolling)#1610,000時間連続稼働試験、240万データ点(記事#16参照)
SPC 管理図 + 異常値検知IQR/Z/SPC + バリュートラップ#17UCL 連続超過でロット停止、リコール回避(記事#17参照)
製品ファミリー別検査閾値業種別代替指標#18医療機器の撤退候補化を回避、3年後主力事業化(記事#18参照)
サプライチェーン FMEAポートフォリオ業種分散#19RPN 200以上15点をセカンドソース化、地震時出荷遅延ゼロ(記事#19参照)
生産ライン起動シーケンスmaster_runner.py#2011ステップを1コマンドで起動、夜間バッチ運用で品質保証作業 週20→週3時間

本業のプロジェクトでは、これらを2年がかりで設計・実装しました。具体的な業務インパクト:

  • 品質クレーム件数: 年間 100件 → 20件(5分の1)に削減
  • 品質保証担当の作業時間: データ集計・確認に週20時間 → 週3時間(85%削減)。残り時間で「本質的な品質改善活動」に集中可能になった
  • 新製品立ち上げ時のリードタイム: 品質保証フェーズが3ヶ月 → 1ヶ月に短縮
  • システム再利用: 5年後にも同じパイプラインが現役で稼働、新製品ファミリー追加時はマスタテーブル更新のみで対応可能

応用編シリーズが応用編 #11 → #20 と 10記事の連続体として読めるのは偶然ではなく、製造業 DX の品質保証システム設計が「個別品質管理 → 統合DB → 並列検査 → 時系列評価 → 異常値検知 → ファミリー別検査 → サプライチェーンFMEA → 生産ライン統合」という一筆書きの構造を持つからです。投資データの自動化も、製品品質保証も、根底のロジックは同じ。Chelsea-Labs シリーズが「製品開発DXエンジニアの投資術」と銘打つ理由は、ここにあります。

逆方向の転移の総括(運用構造の変化を含む)

応用編シリーズで「投資→本業」の逆方向転移を 全10記事のうち5記事で具体例として記録してきました:

記事投資側で開発した手法本業への逆輸入と運用構造の変化
#15multiprocessing 並列化本業の生産ライン並列化、Excel ベース → Python ベースに移行
#16pandas + 管理図本業の Excel ベース信頼性試験を pandas に置換、月次集計2-3日→数時間(運用シフトの大幅変化)
#17IQR 2段階フィルタ本業の品質管理に IQR 第1段フィルタを導入、SPC 単独運用 → 多段運用
#18DuckDB ベース業種別評価本業の事業ポートフォリオ評価が半日→30分、Excel → DuckDB 移行で月次レビューの所要時間が半分以下
#19HHI + 相関 + RPN本業のサプライチェーン FMEA レビュー3日→半日、HHI ベースのサプライヤー集中度評価が新規業務として定着

「投資のために学んだ技術が本業を改善する」という逆方向の流れは、知的好奇心を維持する強力な動機になります。応用編シリーズを通じて筆者自身が経験した最大の学びは、技術習得そのものより、この双方向の循環構造が成立することでした。

まとめ:応用編シリーズの整理と発展編への移行宣言

  • 応用編 #11〜#20 で「両学長スクリーニング基準を東証約3,900社に機械的に適用するパイプラインの雛形」が再現可能な状態に。SPC 4軸 + FMEA の5層構成で、個別銘柄評価とポートフォリオ評価を統合する設計を整理
  • master_runner.py 1コマンドで全パイプラインを起動できる雛形、cron / GitHub Actions に乗せれば毎週の運用が自動化。25業種カバー、TOPIX 相対変動率併用、最終JOINビュー v5 で先送り課題を整理(NotImplementedError による委譲設計で各記事と連動)
  • 製造業 DX の品質保証システム集約プロジェクトと多くの部分で重なる構造。投資データの自動化と製品品質保証の根底ロジックは同じで、双方向の知識循環が成立。発展編(#21〜#30)で CAN-SLIM × 成長株分析を載せる準備が整いました。次回 #21 から発展編に入ります

今日からできる3つのアクション

  1. 本記事の master_runner.py を作成し、応用編 #13〜#19 の各スクリプトを --skip-unimplemented で動く部分から起動できる状態を作る。cron / GitHub Actions に乗せて、毎週月曜朝6時に自動実行を試す
  2. スニペット2 で残り10業種を industry_indicator_map に投入し、計25業種カバーを完成させる。compute_portfolio_weighted_rpn の警告ログ(未カバー業種)が大幅に減ることを確認
  3. スニペット3-4 でTOPIX 相対変動率 + v_full_screening v5 を構築。SELECT * FROM v_full_screening WHERE value_trap_flag = TRUE AND relative_change_pct_1y > -25 のように、「市場全体ショックではなく個別株固有の罠」を抽出するクエリを試す

次回予告:発展編 #21 — オニール CAN-SLIM × 成長株分析の入口

次回(記事#21)からは 発展編に入ります。応用編が「両学長スクリーニング × 高配当株」だったのに対し、発展編は「オニール CAN-SLIM × 成長株分析」をテーマに、エンジニアリング視点で深化させます。

  • CAN-SLIM の概要(C/A/N/S/L/I/M の7要素)と、応用編で構築したパイプラインへの接続
  • 応用編との戦略的差別化(高配当株 = インカム重視 vs 成長株 = キャピタルゲイン重視)
  • 発展編シリーズ全体(#21〜#30)のロードマップ

「製品開発DXエンジニアの投資術」シリーズ全体像

本記事は 応用編(記事#11〜#20、計10記事)の最終回 です。シリーズ全体の進捗:

  • 基礎編(#01〜#10): 完了(インデックス投資 × DX思想)
  • 応用編(#11〜#20): 本記事で完了 ✅(高配当株 × データパイプライン)
  • 発展編(#21〜#30): 次回スタート(CAN-SLIM × 成長株分析)

応用編 DX フェーズマップ(全10回):

前回 #19 業種分散の FMEA本記事 #20 応用編まとめ | 次回 #21 発展編スタート(CAN-SLIM、公開予定)

関連記事(基礎編から): #03 複利のPython可視化#08 リスクとリターン#09 NISA・iDeCoの設計

免責事項(再掲)

本記事は投資助言を目的としたものではなく、技術・分析手法の紹介です。コード・パイプライン設計は教育目的であり、特定の銘柄・金融商品の売買を推奨するものではありません。投資判断はご自身の責任で行ってください。J-Quants API・EDINET API・LINE Messaging API・GitHub Actions の利用規約は変更される可能性があるため、実装時は各サービスの公式ドキュメント・利用規約を必ず確認してください。本記事中に J-Quants API から取得した実データは掲載していません(利用規約に基づく方針)。応用編 #18-#20 で扱った業種別閾値(BIS/LTV/格付け/CV閾値等)は2026年5月時点の参考値で、規制改定により変動します。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

CAPTCHA


目次