開発beat-monitoring

朝、BCU(Birmingham City University)が出しているテンバガー株の研究論文を見つけて読んだ。「結局フリーキャッシュフローが効いた」という主旨で、自分の /beat-monitoring/scatter ページが今は EPS NTM 成長率 vs フォワード PER の軸だけになっているのが急に物足りなく感じた。計画書を書いて Codex にレビューしてもらい、FCF データを Koyfin から引っ張るところまで進めた。ただ最後、「FCF Yield と FCF 成長率の2軸だけでは株価指標がどこにも入っていないのでは」という違和感が残り、軸の決め方を再検討中で止まっている。

論文を見つけた瞬間に既存ページが古く見えた

論文の URL は → BCU テンバガー論文。Claude Code に既存記事を grep してもらったが、「テンバガー × FCF」の組み合わせで書かれた記事はリポジトリに1本もなかった。過去にテンバガーをテーマにした記事は3本書いていたが、どれもストーリー寄りで、財務指標まで踏み込んだものはない。

論文をざっと読んだ印象は単純で、テンバガーの共通点を一つだけ挙げるならフリーキャッシュフローの伸びだ、というもの。EPS や売上ではなく、現金が増え続けたかどうか。

その瞬間、/beat-monitoring/scatter の2軸が EPS NTM 成長率と Forward PER だけになっているのが古く見えた。EPS は会計上の利益で、減価償却や運転資本の動きが見えない。論文が言っているテンバガーの条件と直接つながらない。

ドキュメントから先に書いた

いきなり実装に入らず、論文の要旨と既存ページの限界を整理する公開記事を先に書くことにした。doc-communication スキルの「結論先出し」と svg-diagram スキルの 720px / 8px ベースラインに沿って、SVG 図解を1枚作って記事1本にまとめた。

書きながら気づいたのは、自分の既存 scatter ページのガイドにも「PER だけでバリュエーションは決まらない、FCF が見えていない」と既に書いてあったこと。論文を読まなくても、自分で書いた文章の中に伏線があった。読み返すまで気づいていなかった。

計画書を Codex にレビューさせて3度修正した

記事を書き終えてから、scatter ページ拡張の実装計画書を別途作って Codex でレビューさせた。~/.claude/rules/plan-codex-review.md の手順通り「致命点だけ指摘して」と指示したが、それでも致命点が3つ返ってきた。

一番痛かったのは 「ADR 後の FCF 利回り式が逆」 という指摘。自分は price ÷ (ntm_fcfps × ratio) と書いていたが、これは Multiple であって Yield ではない。Yield なら逆数を取らないといけない。横で見ているとすぐ分かるはずなのに、自分で書いている時は気づけない。

3つ修正して再レビュー、また1点出てきて修正、3度目で「致命点なし」を取った。Codex を resume --last でつなぐのを忘れると最初の文脈が消えるので、ここは毎回気をつける。

Phase 0 のデータ確認で詰まる

実装は Phase 0(データ存在確認)→ Phase 1(DDL)→ Phase 2-3(generate スクリプト拡張)→ Phase 4(純粋関数追加)→ Phase 5(UI)→ Phase 6(ガイド更新)の6段で組んだ。

Phase 0 でいきなり詰まった。v_latest_valuation view の DDL は別リポジトリ turso-replicas で管理されているはずだったが、migrations を覗くと該当 SQL がない。Turso 上で直接管理されていたらしく、手元から DDL の追跡ができない。

.env の読み取りは自分で禁止しているため、Claude Code から直接 Turso を叩けない。「実行スクリプトを書いておくのでこれを走らせて結果を貼ってください」と言ってもらったが、その後 Phase 0 の結果を出すのを忘れていて、次のターンで「これ進んでますか?」と聞いた時に止まっていることに気づいた。

ここで方針を切り替えた。view を触らず、generate スクリプト側で consensus_estimates を直読みする方式に変える。view のロールバックリスクが消え、DDL 管理の所在を気にしなくて済む。Phase 4 の純粋関数追加(computeFcfYield, computeFcfGrowth, getYAxisDisplay)はデータが無くても安全に先行投入できるので、まずそこから入れた。Vitest を走らせて 38 件全パス。

FCF データは Koyfin から取れるか

Phase 5 まで UI を一気に進めた後、ブラウザで開いたら 「FCF 基準では 13 銘柄全件が除外」 と出た。UI は動いている。データが入っていないだけ。

ユーザーから「Koyfin でも取れないんでしたっけ?」と聞かれて、これは未確認だと気づいた。Koyfin に FCF コンセンサスがある可能性は十分高い。NVDA・MSFT・AAPL クラスなら普通に持っているはず。

調査を始めると、Koyfin の Earnings Matrix(Sales/EBITDA/EBIT/EPS タブ)には FCF タブが無く、ここからは取れない。一瞬「Case C 確定(データ源を変える方針判断が要る)」と判定しかけたが、別画面の EAC(Earnings Analytics Center)に FCF も CFO も CAPEX もコンセンサス付きで存在していた。

UI が裏で叩いている API を Network タブで覗くと、/api/v3/fa/estimate-data という別エンドポイントが見つかり、body は {"id":"eq-212q1o","currency":"USD","periodTypeId":2,"startYear":2023,"endYear":2030} だけ。レスポンスに fest_estfcf(FCF estimate, 12 期分)と fest_actfcf(FCF actual)が揃っていた。しかも Free プランで叩けている

NVDA で PoC を組む。LTM 4Q(actual の末尾)と NTM 4Q(estimate の先頭)を分離して合計したら、LTM FCF 119.1B / NTM FCF 231.1B が出た。1株あたりに直すと LTM FCF/株 4.90、NTM FCF/株 9.54。dev で開くと NVDA 1 点だけがプロット された。データ経路が動いている証拠が画面に出た。

13 銘柄に拡大する

「全部取って」と指示が来たので、TICKER_META から構造転換済み tier の銘柄を抽出し、KID(Koyfin 内部 ID)を解決して回った。

途中で気づいた制約:

  • Samsung / SK hynix は私の Koyfin プランの検索結果が0で取れない
  • キオクシア(285A)は米国 ADR KXIAY:US として存在するが、valuation.ts285A キーが日本上場(円価格)なので単位ミスマッチを避けるため除外

結局、米国上場の10銘柄で batch 注入することになった。

batch 投入後の検証で、NVDA に ALAB の値が、SNDK に RDDT の値が混ざるバグが出た。原因は regex の lazy match が 行を跨いで別 ticker の ntmFcfps: まで貫通 していたこと。1 ticker = 1 行なので、行単位で処理に書き換えて再注入したら、10銘柄全件に正値が入った。dev で開くと10点プロットされた。

ティッカーLTM FCF/株NTM FCF/株成長率利回り
NVDA$4.90$9.54+94.9%4.36%

(他9銘柄も同様に取得できたが詳細は割愛)

ここで違和感: 株価指標が軸にない

ここで「ちょっと待って」が入った。

これフリーキャッシュフロー利回りと、LTM フリーキャッシュフロー成長率の2軸でいいんでしたっけ? 株価の指標がどっちかにないと、イマイチなような気がするんですけど。

確かに。EPS 基準の方は「NTM EPS 成長率 × Forward PER」で、PER に株価がしっかり入っている。一方 FCF 基準は「FCF Yield × FCF 成長率」だと両方とも fundamental の話で、PER に相当する株価指標が軸に乗っていない。

正確には FCF Yield の分母は株価なので、Yield の中に株価は埋め込まれている。ただ、軸を見ただけで「Multiple ベース(PER 系)か Yield ベース(利回り系)か」が一目で読めない。これは scatter 上で EPS 基準と FCF 基準を頭の中で並べて比較するときに、認知コストが跳ね上がる。

そこで、Yield ではなく Multiple(Price/FCF) に切り替える方向で再実装した。x 表記(PER と同じ単位記号)にして、軸方向も lower-is-better で統一すると、PER の隣に並べた時の解釈が完全に揃う。Multiple なら反転トリックも要らなくなる。

scatterSplit.tscomputeFcfMultiple を追加して getYAxisDisplay('fcf') の戻り値を Multiple 仕様に書き換え、scatter.vue から軸反転トリックを撤去。Vitest 43 件 pass。ブラウザで確認すると「フォワード FCF Multiple」の表示で10銘柄プロットが維持されている。NVDA 22.9x / MU 16.6x / SNDK 13.4x。PER と直接比較できる体裁になった。

ただし「Multiple 1本でいいのか、Yield と切替トグルにするか、それとも別軸として PER を残したまま FCF を第2軸として並列表示するか」はまだ決めきれていない。明日以降、論文が言うテンバガーの定義に立ち戻って軸の意味を考え直す。

明日以降に持ち越す論点

  • BCU 論文をもう一度精読して、テンバガー判定に「Multiple」を使っているか「Yield」を使っているか確認する
  • FCF Multiple と Forward PER の2銘柄並列散布図を一度試作してみる(軸の意味を揃えた状態で目視比較する)
  • Samsung / SK hynix / キオクシア(日本上場)の FCF データ取得経路を別途検討する(Koyfin 以外)
  • MU / SNDK の NTM FCF が急増している件、半導体サイクル底→ピーク移行 + SNDK 分社直後の特殊性を分けて精査する

論文を読んで「自分のページが古い」と感じた瞬間から、ドキュメント → 計画 → Codex レビュー → 実装 → ブラウザ確認 → データ取得経路の切替 → 軸の意味の再検討、まで一日で動けたのは、各フェーズを Claude Code に並行して回させた構図の効果が大きい。判断する係は自分、実行する係は AI、という分担がはっきりしてくると、こういう「論文1本から実装1段」のサイクルが半日で1周する。