AIエージェントで作る銘柄評価基盤①—全体設計と実装の流れ


AIエージェントで作る銘柄評価基盤①—全体設計と実装の流れ

匿名化した銘柄評価パイプラインの概念図

AIエージェントを使った仕組みを作るとき、最初に迷うのは「どこまでAIへ任せるか」です。株式の銘柄評価では、価格・財務データの集計、同業種内での比較、決算イベントの検知、企業の競争優位やカタリストの確認など、性質の異なる仕事が一つの流れに混ざります。すべてをAIへ渡すと再現性と費用が不安定になり、すべてを固定ロジックで書くと文章資料の読解や事業の質の判断が苦しくなります。

そこで今回の実装では、毎日同じ答えを返すべき処理をPythonとデータベースへ、公開資料を読んで根拠を整理する処理をAIエージェントへ分けました。Hermes Agentは、これらを毎営業日に起動し、実行状況を残す運用基盤として使っています。

この記事では、プロジェクト全体の設計と日次処理の流れを紹介します。個別企業名、証券コード、実際の通知先、認証情報、利用者名、ローカルの絶対パスは掲載しません。画面例や数値例も、実データではなく「銘柄A」「候補B」のような架空表現へ置き換えています。

> 本記事はシステム設計とAIエージェント活用の解説です。特定銘柄の推奨や投資助言ではありません。スコアは将来の利益を保証するものではなく、最終判断には一次資料の確認と人の判断が必要です。

この仕組みが解こうとした問題

対象市場には数千の銘柄があります。終値、出来高、売買代金、財務数値のような構造化データは、全銘柄を毎日計算できます。一方で、企業ごとに決算説明資料、中期経営計画、ニュース、競争環境まで調べる深掘り評価は、時間も推論コストも大きくなります。

つまり、次の非対称性があります。

  • 定量計算は、広く・速く・毎日できる
  • 事業の深掘りは、狭く・遅く・定期的にしかできない
  • 株価や流動性は毎日変わるが、事業の質はそれほど速く変わらない
  • 決算や急変など、予定外に優先して再確認したいイベントがある
  • 未評価銘柄を放置せず、一度は全体を見渡す必要がある

この問題へ、単純な「スコア上位だけを毎日AIへ渡す」という方法で対応すると、同じ人気銘柄ばかりが再評価されます。反対に、単純な順番待ちでは、重要な決算や急変を見逃します。必要だったのは、全体を毎日計算する層と、限られたAI評価枠を公平かつ優先度付きで配るローテーション層でした。

基本方針は「決定論の外側にAIを置く」

このプロジェクトで最も重要な設計判断は、AIエージェントをパイプライン全体の司令塔にしなかったことです。AIが毎朝、自由に「今日は何をするか」を考える構成ではありません。処理順、対象件数、保存形式、失敗時の挙動、再実行の条件はコード側で固定しています。

AIへ任せるのは、選定済みの対象について、固定ルーブリックに沿って公開情報を調べ、構造化された評価案を返す部分です。返ってきた点数の範囲検証、合計、グレード変換、保存は再びコード側が担当します。

“`mermaid
flowchart LR
A[構造化データ] –> B[決定論的な特徴量計算]
B –> C[定量スコアとフィルター]
C –> D[優先度付きローテーション]
D –> E[AIによる根拠確認とカテゴリ採点]
E –> F[コードによる検証・合成]
F –> G[履歴保存・レポート・通知]

classDef code fill:#dff3f1,stroke:#246b6b,color:#173d3d;
classDef ai fill:#fff0cf,stroke:#b7791f,color:#5b3a00;
classDef ops fill:#e7edf7,stroke:#334e68,color:#1f2937;
class B,C,D,F code;
class E ai;
class A,G ops;
“`

この境界にすると、AIの応答が一時的に失敗しても、全銘柄の定量計算やデータ保存まで失う必要がありません。また、AIモデルを変更しても、周囲のデータ処理やレポート形式は維持できます。

全体アーキテクチャ

日次処理は大きく10段階です。実装上は一つのエントリーポイントから呼び出しますが、それぞれを独立した責務のモジュールに分けています。

| 段階 | 主な処理 | AIの関与 | 失敗時の考え方 |
|—|—|—:|—|
| 1 | 対象営業日の確定、価格・財務・銘柄マスター取得 | なし | データがなければ停止 |
| 2 | 特徴量計算、定量スコア、ハードフィルター | なし | 入力欠損は中立化または除外 |
| 3 | 決算・価格急変・売買代金急増のイベント検知 | なし | 対象イベントだけ省略可能 |
| 4 | Tierと期限に基づく当日対象の選定 | なし | 重複を防ぎ、枠不足は補充 |
| 5 | 公開情報を使った事業の深掘り評価 | あり | 銘柄単位で失敗を隔離 |
| 6 | 事業・割安度・モメンタムの統合 | なし | AI評価がなければ未採点のまま |
| 7 | Tier更新と次回評価日の計算 | なし | 連続条件で急変を抑制 |
| 8 | Markdown・HTMLレポートと通知 | なし | 通知先ごとに失敗を分離 |
| 9 | テーマ・競合関係の補助抽出 | 一部あり | 本流完了後に実行 |
| 10 | 再取得困難な評価データの世代バックアップ | なし | 本流を止めず警告を残す |

処理の中心は `daily` モジュールです。ただし、そこへ計算式や通知処理を直接詰め込まず、データ取得、特徴量、スコア、ローテーション、AI評価、学習、レポート、保存を分離しています。

実装フォルダの役割

公開時にローカルの絶対パスを出す必要はありません。プロジェクト内の相対的な役割だけを示すと、次のようになります。

“`text
stock_brand_eval_agent/
├── clients/ 外部データAPIとの通信
├── screener/ 特徴量、定量スコア、補助シグナル、統合スコア
├── rotation/ イベント検知、Tier、当日対象の選定
├── evaluator/ AIバックエンド、評価パッケージ、ルーブリック検証
├── ontology/ テーマ・競合の関係抽出と波及候補
├── learning/ 事後成績、shadow比較、重み更新
├── reporting/ Markdown、HTML、要約、通知
├── storage/ SQLite、Parquet、バックアップ
├── config.py 閾値、重み、機能フラグ
└── daily.py 日次処理のオーケストレーション

scripts/hermes/
└── stock_eval_daily.sh Hermes Agentから起動する薄いラッパー
“`

この分け方には、AIエージェント活用で起こりやすい変更を局所化する狙いがあります。モデルやプロンプトを変えるなら `evaluator`、評価枠を変えるなら `rotation`、データの見せ方を変えるなら `reporting` を確認すればよく、日次処理全体を書き換える必要はありません。

ステップ1:対象営業日を確定する

日次バッチでは「今日の日付」をそのまま評価日にできません。土日・祝日があり、データ提供プランによって遅延があり、API更新時刻との境界もあります。そのため、基準日から過去へ遡り、実際に価格データが存在する最新営業日を採用します。

ここで重要なのは、カレンダーではなく取得できた市場データを基準にすることです。休日に定期実行されても、直近営業日がすでに処理済みなら安全にスキップできます。スキップも正常系として通知し、「実行されなかった」のか「実行した結果、処理不要だった」のかを区別します。

ステップ2:入力データを保存してから計算する

外部APIの応答をそのままAIへ渡すのではなく、まずローカルの状態へ保存します。主なデータは次の3種類です。

  • 銘柄マスター:対象市場、業種、銘柄の有効状態
  • 日次価格:調整後価格、出来高、売買代金、高値・安値
  • 財務開示:売上、利益、資産、自己資本、会社予想、開示日時

運用参照にはSQLite、長期の定量履歴にはParquetを使い分けています。毎朝参照する直近状態と、後から検証する時系列を同じ形で抱え続けると、データベースが不必要に大きくなるためです。

保存を先にする利点は、外部APIへ再度アクセスしなくても、取得済みデータだけで計算を再現できることです。AIの評価結果も一件ずつ保存するため、途中で失敗しても成功分は残ります。

ステップ3:全銘柄を機械計算する

定量層では、価格・財務データから次のような特徴量を作ります。

  • 20日中央値の売買代金と出来高
  • 60日間の無商い率
  • 売買代金に対する価格変動の大きさ
  • 20日実現ボラティリティと60日最大ドローダウン
  • 3年成長率、前年同期比、会社予想の成長率
  • ROE、ROA、営業利益率、自己資本比率
  • 20日平均株価を使ったPBR

これらを「割安」「成長」「質」「流動性」「リスク」の5本柱へまとめ、0〜100の定量スコアへ変換します。異なる業種のPBRや利益率を直接比べないよう、市場と業種の組み合わせごとに相対化します。外れ値の影響を抑えるため、平均と標準偏差ではなく中央値とMADを使うロバストな正規化です。

この段階はAIを使いません。同じ入力なら同じ結果になること、計算根拠をテストできること、数千件でも費用を予測できることを優先しています。

ステップ4:売買可能性を先に確認する

計算上の魅力が高くても、極端に流動性が低い銘柄や、長期間売買が成立していない銘柄を上位候補として扱うと、運用上の意味が変わります。そのため、順位付けの前にハードフィルターを置きます。

実装では、売買代金、無商い率、株価、PBR、自己資本などを確認します。閾値は設定ファイルに集約し、市場ごとに変更できる構造です。フィルターを通過しない銘柄を「悪い会社」と判定しているわけではありません。「この評価パイプラインの通常候補として扱う条件を満たさない」と区別しています。

ステップ5:その日にAIが見る対象を選ぶ

全銘柄を毎日深掘りできないため、ローテーターが当日枠を配ります。優先度は一種類ではありません。

1. 決算や大きな価格・売買代金変化が起きたイベント枠
2. 高評価企業の競合として見つかった未評価候補の発掘枠
3. 前回評価から所定期間を過ぎた期限超過枠
4. 低いTierにいるが定量順位が急上昇した敗者復活枠

空きが出た場合は期限超過候補から補充します。一つの銘柄が複数条件に当てはまっても、当日の選定は一度だけです。対象市場ごとに枠と順位を分けるため、規模や流動性の違う市場を一つの順位表へ無理に混ぜません。

Tierは再評価頻度を表します。上位Tierほど短い間隔で再確認し、低いTierは長い周期にします。新規銘柄は未評価として早めに一周させます。Tierを一日ごとの株価変化で頻繁に上下させないよう、確定後の変更には同じ方向の条件が連続することを求めます。

ステップ6:AIへ渡す情報を絞る

AIへデータベース全体を見せるのではなく、対象銘柄の評価パッケージを作ります。パッケージには、対象日、対象市場、業種、最新財務、定量指標、前回評価の要約など、判断に必要な範囲だけを含めます。

AIは、必要に応じて公開されたIR資料やニュースを検索し、収益力、成長性、競争優位、カタリスト、経営・資本政策、リスクを採点します。価格水準やPBRの割安判断は、AI側の採点から明示的に外します。定量層と同じことをAIにも採点させると、二重計上になるからです。

AIの出力は自由文で終わらせず、JSON形式に限定します。カテゴリごとの点数、要約、カタリスト、リスク、確信度が必須です。コード側は型、点数範囲、必須項目を検証し、不正な出力なら修正要求を付けて再試行します。

ステップ7:AIの点数をコードで確定する

AIはカテゴリ別の採点案を返しますが、最終的な事業スコアとグレードはコードが計算します。これにより、合計式や境界値がモデルの文章表現に左右されません。

また、評価日、使用したバックエンド、プロンプト版、市場別キャリブレーション、カテゴリ点、再試行回数、確信度を履歴として保存します。後からモデルやプロンプトを変えた場合も、異なる条件の評価を混同せず比較できます。

AI評価が利用できない日は、事業スコアを0点にしません。「未評価」と「低評価」は別の状態です。定量層、レポート、通知は継続し、統合スコアだけを未付与にします。これは劣化運転の重要な原則です。

ステップ8:時間軸の違うスコアを統合する

毎日変わる割安度・モメンタムと、数週間から数か月有効な事業評価を組み合わせて統合スコアを作ります。実装の初期重みは、事業評価を中心に、割安度とモメンタムを補助として加える形です。

ここでも、有効な事業評価がある銘柄だけを統合対象にします。未評価を0点として合成すると、AIがまだ見ていないだけの銘柄が不当に最下位へ落ちるためです。欠損は欠損のまま扱い、評価の有無を利用者が区別できるようにします。

ステップ9:結果を人が読める形へ戻す

日次処理の成果物は、ランキングだけではありません。MarkdownとHTMLのレポートへ、次の情報をまとめます。

  • 対象ユニバースとフィルター通過件数
  • Tier分布
  • 当日の深掘り対象と選定理由
  • 市場別の定量スコア上位
  • 有効評価がある銘柄の統合スコア上位
  • 当日のAI事業評価要約
  • イベントとTier変更
  • 検証中の補助シグナルや学習状態

通知はレポート全文ではなく、開始、スキップ、完了、失敗、検証結果などを短く送ります。複数の通知先へ同じ内容を送れるようにし、一方の障害がもう一方を妨げない設計です。

ステップ10:後処理を本流から分離する

テーマ・競合関係の抽出や、学習用の事後成績、再取得しにくいAI評価のバックアップは重要ですが、朝の基本レポートを遅らせる理由にはしたくありません。そのため、利用者へ主要結果を通知した後に実行します。

後処理が失敗しても、定量計算・AI評価・レポートが成功していれば本流は完了として扱います。ログには後処理の失敗を残し、次回以降に修復できます。「すべて成功するまで何も出さない」より、どこまで成功したかを明確にする設計です。

AIエージェントを使う場所、使わない場所

この実装の境界を、もう一度まとめます。

| 作業 | AIを使うか | 理由 |
|—|—:|—|
| API取得、営業日判定、保存 | 使わない | 再現性と失敗検知が必要 |
| 財務の累計値変換、指標計算 | 使わない | 数式を固定しテストしたい |
| 全銘柄の相対順位 | 使わない | 大量処理と比較可能性を優先 |
| 当日対象の枠配分 | 使わない | 公平性、上限、重複防止が必要 |
| IR資料・中計・ニュースの根拠整理 | 使う | 非構造化文書の読解が得意 |
| 競争優位やカタリストのカテゴリ採点 | 使う | 根拠を伴う言語判断が必要 |
| 点数範囲、合計、グレード | 使わない | 境界値を決定論的に保つ |
| 定期起動と実行監視 | Hermes Agentを使う | 継続運用と実行証跡が必要 |

AIを使うこと自体が目的ではありません。従来は人が毎回資料を探し、同じ観点で読み直していた部分を、固定ルーブリックと構造化出力で再利用可能にすることが目的です。

他のAIエージェント案件へ応用する手順

この構成は、銘柄評価以外にも応用できます。たとえば、競合調査、仕入先評価、論文ウォッチ、顧客要望の優先付けでも、次の順番が使えます。

1. 全件に安く適用できる機械的な前処理を決める
2. AIが必要な少数対象を選ぶルールを作る
3. AIへ渡す情報を最小の評価パッケージにする
4. 自由文ではなく、検証可能な構造化出力を求める
5. AIの出力をコードで検証し、最終計算はコード側で行う
6. 対象単位で保存し、途中失敗から再開できるようにする
7. 定期実行、スキップ、失敗、復旧の証跡を残す

特に、AIへ渡す前の「対象選定」が重要です。エージェントの能力を高めるだけでなく、何を見せるか、何件まで使うか、再評価の周期をどうするかが、品質と費用を左右します。

公開時のマスキング方針

AIエージェントの実装記事では、コードよりもスクリーンショットやログに個人情報が残りやすくなります。この連載では次の情報を公開しません。

  • 実在する個別銘柄名、証券コード、実スコア、実順位
  • APIキー、Webhook URL、認証トークン、環境変数の値
  • 利用者名、ホームディレクトリ、外付けストレージ名を含む絶対パス
  • 通知チャンネルID、ジョブID、実行ID
  • AIの検索履歴に含まれる個人的なメモや未公開資料
  • 実データのダッシュボードや日次レポートの画面

コード例では、パスを `/path/to/project`、通知先を `channel:example`、銘柄を `銘柄A` のように置き換えます。画像は実画面のスクリーンショットではなく、処理の概念図を使います。マスキングは文字列だけでなく、ウィンドウのタイトル、サイドバー、通知バッジ、画像メタデータも対象です。

実装して分かったこと

第一に、AIエージェントの導入効果は、判断そのものより「判断の入口と出口を固定すること」で大きくなります。固定ルーブリック、評価パッケージ、JSON検証、履歴保存があることで、AIの回答が運用可能なデータになります。

第二に、低頻度の深掘りと高頻度の数値更新を分けると、費用だけでなく説明もしやすくなります。「会社の質が変わった」のか、「価格が変わって割安度が変わった」のかを別々に見られます。

第三に、成功時の結果だけでなく、スキップ、部分成功、失敗、再実行を最初から設計する必要があります。毎朝動く仕組みでは、休日やAPI遅延は例外ではなく通常運用の一部です。

まとめ

この銘柄評価基盤は、全銘柄を毎日計算する決定論的な層と、限られた対象を公開情報から深掘りするAI層を分けています。ローテーションがAIの利用枠を配り、コードがAI出力を検証し、Hermes Agentが定期起動と実行証跡を支えます。

重要なのは、AIへ全権を渡すことではありません。AIが得意な非構造化情報の読解だけを、再現可能なパイプラインの中へ狭く組み込むことです。

次回は、定量スコア、事業スコア、統合スコア、Tierがどのように役割分担しているかを、匿名化した計算例とともに詳しく説明します。

実装確認に使った主なファイル

  • `stock_brand_eval_agent/daily.py`
  • `stock_brand_eval_agent/config.py`
  • `stock_brand_eval_agent/screener/features.py`
  • `stock_brand_eval_agent/screener/quant_score.py`
  • `stock_brand_eval_agent/rotation/scheduler.py`
  • `stock_brand_eval_agent/evaluator/rubric.py`
  • `stock_brand_eval_agent/reporting/daily_report.py`
  • `scripts/hermes/stock_brand_eval_daily.sh`

Back to top