Claude APIで日米株スクリーナーを個人で作った話
はじめに
個人投資の銘柄選びを自動化したくて、Streamlit + yfinance + Claude API で日米株スクリーナーを作りました。「どの銘柄を見ればいいか」を絞り込む部分と、「その銘柄がなぜ良いか」を説明する部分の両方を一つのツールにまとめています。
何ができるか
- スクリーニング: US/JP 計 200 銘柄を対象に PER・PBR・RSI・売上成長率などの条件で絞り込み
- スコアリング: バリュー・グロース・テクニカルの3軸を重み付けして 0〜100 点でランキング
- AI コメント: Claude Haiku が各銘柄に短評を自動生成
- 深掘り分析: Claude Sonnet がボタン1つで詳細な投資分析を出力
- チャット: スクリーニング結果を文脈に乗せて Claude と相談
技術スタック
| レイヤー | 採用技術 |
|---|---|
| UI | Streamlit + Plotly |
| データ取得 | yfinance |
| テクニカル指標 | pandas-ta-classic |
| AI | Claude API (Haiku / Sonnet) |
| キャッシュ | SQLite |
設計のポイント
Haiku と Sonnet を使い分けてコストを抑える
一番こだわったのがモデルの使い分けです。
# 一括コメント生成(20銘柄 → 4回の API 呼び出し)→ Haiku
response = self.client.complete(
prompt=prompt,
model=CLAUDE_HAIKU, # $1.00 / 1M input tokens
max_tokens=1024,
)
# 深掘り分析(1銘柄、詳細な投資分析)→ Sonnet
analysis = self.client.complete(
prompt=prompt,
model=CLAUDE_SONNET, # $3.00 / 1M input tokens
max_tokens=2048,
)
スクリーニングの一覧コメントは「短くて速くて安い」Haiku、1銘柄を深く掘り下げる場合は Sonnet、という分け方です。体感の品質差がほとんど出ない部分は Haiku に任せることで、1回のスクリーニング実行が 〜$0.01 程度に収まります。
5銘柄まとめて1回のプロンプトに
Haiku へのリクエストを1銘柄ずつ送るとレイテンシとコストが積み上がります。そこで5銘柄分のデータをまとめて1プロンプトに入れ、JSON で返させています。
BATCH_SIZE = 5
for i in range(0, len(uncached), BATCH_SIZE):
batch = uncached[i:i + BATCH_SIZE]
comments = self._batch_comment(batch, style) # 1 API call for 5 stocks
20銘柄なら4回の API 呼び出しで済む計算です。
SQLite キャッシュで API 費用を節約
同じ銘柄の分析を何度もリクエストすると費用がかさみます。コメントは 48 時間、深掘り分析は 24 時間 SQLite にキャッシュしています。
# 先にキャッシュを確認
cached = self.cache.get_claude_analysis(result.symbol, "screening_comment")
if cached:
result = result.model_copy(update={"claude_comment": cached})
continue # API 呼び出しをスキップ
# キャッシュになければ API を呼んで保存
self.cache.store_claude_analysis(
result.symbol, "screening_comment", CLAUDE_HAIKU, comment,
ttl_seconds=172800 # 48 hours
)
毎日同じ銘柄を見ている場合、2回目以降は API コスト ゼロです。
パーセンタイルランキングで複合スコアを計算
「PER が低い = バリュー株」を単純な絶対値で評価すると、業種間の比較がおかしくなります。そこでユニバース内での相対的な順位(パーセンタイル)をスコアに変換しています。
def _normalize_inverse(value, values):
"""低いほど良い指標 (PER, PBR) を 0-100 に変換"""
clean = [v for v in values if v is not None]
n = len(clean)
rank = sum(1 for v in clean if v > value)
return ((rank + 0.5) / n) * 100 # 中点パーセンタイル
このスコアに分析スタイル別の重みをかけて合算します。
STYLE_WEIGHTS = {
AnalysisStyle.VALUE: (0.6, 0.2, 0.2), # バリュー重視
AnalysisStyle.GROWTH: (0.1, 0.6, 0.3), # グロース重視
AnalysisStyle.TECHNICAL: (0.1, 0.1, 0.8), # テクニカル重視
}
composite = value_score * vw + growth_score * gw + technical_score * tw
日次予算上限(ただし制限あり)
暴走を防ぐため、1日あたりの API 費用に上限を設けています。
if self._daily_spend() >= self.daily_budget:
raise RuntimeError(f"Daily budget ${self.daily_budget:.2f} reached.")
ただし、これはメモリ内管理なので Streamlit を再起動するとリセットされます。本当に厳密に制限したいなら SQLite に永続化すべきですが、個人ツールとして実害がないのでそのままにしています。
実際の Claude 出力例
プロンプトは「2文で評価、数値を具体的に、免責事項不要」と指示しています。実際に出てくるコメントはこんな感じです。
スクリーニング一覧コメント(Haiku)
AAPL: Revenue growth of 9% YoY with a 30% operating margin signals durable earnings power, justifying the premium PER of 28x. MACD bullish crossover and RSI at 58 suggest near-term momentum without overbought conditions.
7203.T(トヨタ): PER 8.2倍・PBR 0.9倍と同業他社比で割安水準にあり、配当利回り3.1%は日本株平均を上回る。RSI 52で中立圏かつMACDが上昇トレンドにあり、バリュー投資の観点からエントリーを検討できる。
深掘り分析(Sonnet)の構成
Sonnet に切り替えると、以下の5セクション構成で出力されます。
1. ビジネス品質(2〜3文)
2. バリュエーション評価(2〜3文)
3. 主要な成長カタリスト(箇条書き)
4. 主要リスク(箇条書き)
5. 総合評価: Strong Buy / Buy / Hold / Sell / Strong Sell + 根拠
Haiku との文字数・精度の差は明確で、一覧コメントには Haiku で十分、1銘柄を掘り下げるときだけ Sonnet を使う、という使い分けがうまく機能しています。
プリセット戦略
3つのプリセットをワンクリックで適用できます。
| プリセット | 条件 | 重み |
|---|---|---|
| 割安バリュー | PER < 15、PBR < 1.5 | バリュー 60% |
| 成長グロース | 売上成長 > 15%、営業利益率 > 10% | グロース 60% |
| テクニカル突破 | RSI 40〜65、MACD ヒストグラム > 0 | テクニカル 80% |
コスト感
実際の運用でかかっているコストの目安です。
| 操作 | モデル | 目安コスト |
|---|---|---|
| スクリーニング(20銘柄) | Haiku | 〜$0.01 |
| 深掘り分析(1銘柄) | Sonnet | 〜$0.02 |
| チャット(1往復) | Haiku | 〜$0.001 |
仕事終わりにスクリーニングを回して、気になる銘柄を2〜3個深掘りする。そんな使い方をしていますが、月の API 代は缶コーヒー1本分($1〜2)程度です。
まとめ
- Haiku / Sonnet の使い分けとバッチ処理でコストを最小化
- SQLiteキャッシュで同じ銘柄の再分析を回避
- スコアリングは絶対値ではなくパーセンタイル相対評価
- 個人ツールは「完璧」より「動く」を優先してよい
免責事項: 本ツールは個人の学習・情報収集を目的として作成したものです。AI の出力を含むすべての情報は投資助言ではありません。投資の最終判断はご自身の責任で行ってください。また yfinance は Yahoo Finance の非公式 API であり、個人利用の範囲でご使用ください。