• #決算モニタリング
  • #半導体
  • #バリュエーション
  • #Vue
  • #Koyfin
開発financial-data

決算モニタリング(beat-monitoring)ページに、半導体・メモリー銘柄を一気に積み増した1日。GLW(Corning)の積み残しを片付け、Broadcomにはギャップ会計ベースのフォワードPERを併記し、Credo(CRDO)の本決算を取り込み、SK HynixとSamsungの韓国メモリ2社を追加してウォン建て対応まで通した。最後に散布図ページの表示バグを画面で見つけたが、その場で直さず翌日のメモに回した。

朝イチ:GLWのバリュエーションカード(積み残し)

前日のハンドオフメモを開いて、途中で止まっている作業を洗い出させた。GLW(Corning)のバリュエーションカードが未登録のまま残っていた。

実ファイルを確認させると、valuation.ts は21銘柄でGLWがない。gaapValuation.ts にもない。未登録は事実だった。

Koyfin内部APIで取り直したところで足が止まった。ハンドオフメモに書かれたKID f6-Pk6Zsn で株価を叩くと404が返る。「Unknown KID in graph request」。検索APIでGLWを引き直させると、正しいKIDは eq-mb62wh だった。メモに残したKIDが間違っていたわけだ。しかも誤KIDでもestimatesのkeysエンドポイントはHTTPエラーを返さず、空データを黙って返していた。前日に「periods=0」で詰まった真因はこれだったと腑に落ちた。

正しいKIDで取り直すと一発で通った。

GLW price=176.70 / NTM EPS=3.373 / フォワードPER=52.39x

再生成時はMU/NVDA/SNDKのpriceがnull落ちする罠(add-ticker Step5-5)に注意させ、ログで全銘柄のpriceが生きているか確認した。MU=971、NVDA=211.14、SNDK=1694.98、すべて健在。GLWカードが /beat-monitoring のindexに表示された。

将来のためにTursoに残っていた誤KIDも eq-mb62wh に直させ、pitfalls issueに「真因はKID誤り」と書き足した。

Broadcom:GAAPベースのフォワードPERを併記する

beat-monitoringのページを開いて、Broadcom(AVGO)のフォワードPERが気になった。non-GAAP EPSベースで計算されている。GAAP EPSを使った場合のフォワードPERも並べて出したい、と頼んだ。

ここで会計の壁にぶつかった。直近4QのGAAP EPS実績はSECの8-Kから確定できた(LTM GAAP合計 $5.12)。だがAVGOは会社としてGAAPガイダンスを出さないため、前方(フォワード)のGAAPコンセンサスが公開ソースに存在しない。前方GAAP PERは厳密には出せない。

そこで「前方GAAP PER(推計)」として載せる方針にした。直近実績のGAAP/non-GAAP比(Q1 FY26で約0.73)を非GAAP予想に掛けるブリッジ推計で、その旨を gaapValuation.ts のnotesに明記させた。

AVGO フォワードPER(非GAAP): 33.4x
AVGO フォワードPER(GAAP):   45.7x  ← 約1.4倍

GAAPデータが揃う全11銘柄(AVGO+構造転換済み10銘柄)に同じGAAP行を出し、既存のPERには「(非GAAP)」と明示した。データ層→表示層の2コミットに分割してコミット。作業ツリーには別作業の未コミット変更が散らばっていたので、対象2ファイルだけを明示ステージして、他の作業を巻き込まないようにさせた。

Credo(CRDO):Q4 FY2026決算を取り込む

CRDOがQ4 FY2026決算を出した。x-searchで決算サマリを拾わせると、ユーザー提供の数字と整合した。

  • 売上 $437M(+157% YoY、+7.4% QoQ)
  • 非GAAP EPS 1.16 vs コンセンサス 1.03
  • 通期 $1.335B(+206%)
  • Q1 FY27ガイド $465〜475M
  • 時間外で11〜14%下落(顧客集中:上位4社で約87%)

CRDO.json に通期FY2026を含む FY26Q4(6/1発表)を追加し、summaries.tstickerMeta.ts を更新した。

ここで時刻の罠があった。作業時点は日本時間6/2の午前で、米国市場6/2はまだ開いていない。Koyfinの p_candle_range が返す最新ローソクは6/1終値=**発表前の226.10**になる。発表後の時間外193.6もFY27予想改定もKoyfinにはまだ乗っていない。実データを見たら案の定そうだったので、その事実を正直に報告させた。再生成は巻き添えnull化を避けるため、CRDO/MU/NVDA/SNDKをprice込みでまとめて取り込んだ。

/add-ticker:MRVLは登録済みだった

MRVL(Marvell)を /add-ticker で追加しようとしたら、4ファイルすべてに登録済みでコミット済み、しかも新鮮だった。新規追加の必要はなく、状態確認だけで終了。空振りだが、無駄に上書きしないのが正解だ。

/add-ticker:SK Hynix(000660)を追加する

ここが今日の本丸だった。SK Hynixは韓国上場(KRX 000660)。beat-monitoringが前提とする「米国上場・SEC 8-K・Koyfin ・USD」と折り合うのか、最初に見極める必要があった。

既存の tickerMeta.ts4062(イビデン=日本・東証)が居た。非米国銘柄を扱える前例だ。4062はKoyfin非対応でカード上段の株価/PERは「—」、YoYと翌日株価反応で代替している。SK Hynixも同じ構造でいける、と当たりをつけた。

x-searchで直近4四半期からデータを集めさせた。SK Hynixは寄り前(午前)発表なので、株価反応は「前営業日終値→発表当日終値」で取る。2025 Q3は10/28の521,000→10/29の558,000で+7.10%、ポストの数値と完全一致した。全9四半期の実績・コンセンサス・発表日・株価3値が揃った。

ウォン建てでチャートが壊れた

JSONを組んでチャートを描かせたら、線が引けない。原因は parseCurrencyToNumber がUSD($,M/B/K)とJPY(兆/億/万+円)しか解釈できず、ウォンがnullに落ちていたこと。関数名どおりの責務拡張として、KRW対応(兆/億/万 + W/ウォン/₩、素のウォン)を追加してテストも足した。

次にEPS(営業利益)チャートの軸が X0000000000.0、データラベルが 5470000000000.00 と潰れた。営業利益を絶対ウォン額(兆W=e12)のままバーラベルにしていたためだ。桁の大きい値を兆/億/万に圧縮表示するロジックに変えると、表と同じ「9.21兆」「22.23兆」表記に揃った。副次的に4062(億円)のEPSも「95億」と読めるようになった。共有コンポーネントなので、USD銘柄(NVDA)で兆/億の誤混入がゼロか回帰確認した。

発表日時を全部入れる、通過判定も入れる

スクショとともに「各決算の発表日時を全部拾って、他の銘柄と同じようにここにも日付を入れて。株価は入ってたっけ?」と頼まれた。確認すると、株価も発表日も全9四半期に入っていた。グラフが空っぽに見えたのは、開いていたタブが韓国ウォン対応前のパーサーのままで、ハードリロードしていなかっただけだった。

Samsungとの並走、そして韓国はKoyfin対応だった

作業中に、ユーザーが 005930(Samsung)をメモリセクターに並行追加していた。韓国メモリ勢を2社まとめて入れていたわけだ。

そこで重要な発見があった。Samsungが既にKoyfin/Turso経由で valuation.ts に入っていた(price 349,000・NTM EPS 53585・PER 6.5x・currency: KRW)。つまりKoyfinは韓国銘柄に対応している。SK Hynixを4062扱い(Koyfin非対応)と誤判断していたわけだ。同じパイプラインで取り込めばカードの「—」が埋まり、構造転換済みのGAAPも組める。

SK HynixのKRX KIDは eq-7326uw(identifier A000660:KR)。Samsungと同形式で tickers に登録し(exchange=KOSE、12月決算)、estimatesとpriceをKRW建てで取り込んだ。

SK Hynix price=2,363,000 / NTM EPS=335,242 / NTM PE=7.05x(KRW)

ところがインポート直後、000660 のcurrencyがUSDになっていた(値はKRWなのに)。これだとカードが「$2,363,000」と誤表示される。importスクリプトのcurrencyがデフォルトUSDで、Samsungは別途設定されていたのが原因。valuation_snapshots の000660をKRWに直して再生成し、カードに₩建ての実値が出た。

構造転換済みへ移動、GAAPデータの差異

両韓国銘柄を「ビート継続」から「構造転換済み」へ移した。ここで gaapValuation.test.ts が「構造転換済み銘柄はGAAP散布図データ+株価必須」を強制してくる。

GAAPデータを抽出させると、Koyfinの eps_gaapNTM forwardはあるがLTM実績が2四半期分しかない(4四半期に足りない)。米国型と違い、韓国IFRS開示は非GAAP調整(SBC加算等)が小さく、GAAP(IFRS純利益EPS)≒調整後EPSになる。そこで両韓国銘柄は調整後のNTM/LTM四半期値をGAAP基準として転用し、その旨を注記した。構造転換済みの件数を10→12に更新(テスト件数も)、散布図のハードコード「9銘柄」表記が古いことに気づいて12に直した。全106テストpass。

通貨判定をimportスクリプトに恒久化、コミット

「通過判定(通貨判定)入れといて」と頼まれた。importの2経路(json_stdin / API直叩き)が両方 _persist_rows_and_valuation を通るので、そこで tickers.exchange から通貨を判定すれば、価格無しの日次取込まで全経路をカバーできる。000660005930 → KRW、米国銘柄 → USD、未登録 → USD(安全側)と判定されることを検証した。

関連ファイルだけをステージして両リポジトリにコミット・push。enfabrica研究・memory-makers・issue類の無関係WIPは混ぜなかった。

散布図の表示バグ:その場で直さず明日に回す

最後に http://localhost:3001/beat-monitoring/scatter の画面を見て、表示バグに気づいた。銘柄を切り替えてもチャートのタイトルが全部「MU Micron Technology」のまま、数字もMUのまま動かない。特に韓国2社の数字が合っていない。それにティッカー番号(005930 / 000660)だと分かりづらいので、表記を銘柄名にしたい。

原因の当たりはつけさせた。selected.ticker は正しく切り替わっている(ナビは「005930」と正しい)のに、useTripleBeatData が返す data がMU固定。loader.ts とJSONは正常で、JSONには name: "Samsung Electronics" がちゃんと入っている。[ticker].vue(1ページ1銘柄)では起きず、scatter.vueが単一の BeatExpectationsChart インスタンスで :ticker を動的に切り替えるため、ここで初めて露見した。最有力は useAsyncData の動的キー+watchが同一インスタンスのprop切替に追従していない疑い。

ただし、ここでコードに手を入れずに止めた。今日はもう銘柄追加で頭が一杯で、調査と修正を続けると半端に終わるリスクが高い。症状・原因の当たり・修正候補・関連ファイルを memo/2026-06-02/beat-monitoring-scatter-display-bug.md に書き出して、翌日の実装メモに回した

修正候補も2案メモした。

  • A(即効): scatter.vue<BeatExpectationsChart :key="selected.ticker" ... />:key を付けて、ticker変更時にコンポーネントごと再マウントさせる
  • B(根本): useTripleBeatDatawatchEffect + 手動ロードに置き換え、または useAsyncData の動的キー運用を直す([ticker].vue / TripleBeatTable / BeatStockChart のdedupを壊さないこと)

振り返り

  • KIDの誤りは静かに事故る。estimatesのkeysエンドポイントが誤KIDでもエラーを返さず空を返す挙動を、もう一度肌で確認した
  • non-GAAP/GAAPの使い分けは会社のガイダンス方針に依存する。AVGOのようにGAAPガイダンスを出さない会社では前方GAAP PERは推計にしかならない、と明記する判断
  • 韓国銘柄は「Koyfin非対応の4062型」と思い込んだが、Samsungの既存データを見てKoyfin対応だと気づき直した。思い込みは既存データで検証する
  • 画面の数字の違和感は自分が拾う係。scatterのMU固定バグは画面を切り替えて初めて見えた。ただし疲れている時の見切り発車を避け、メモに回して翌日に持ち越す判断もした