• #nvidia
  • #financial-quiz
  • #vue
  • #implementation
開発financial-data完了

NVIDIA EPS予測 Phase 8: 計算詳細テーブル追加

概要

ユーザーが設定したパラメータが最終的な株価予測にどのように反映されるかを、Excelのセルのように各計算ステップを可視化するテーブルを追加する。

完了ステータス

Phase 8-1: 事前準備
  [x] QoQオーバーライドテーブルを横向きに変更済み
  [x] QoQオーバーライドの表示範囲をFY28まで(4Q'26〜4Q'28)に制限済み
  [x] 予測期間をFY30まで(FY31削除)に変更済み
  [x] FY29〜FY30は内部計算で一律10.7% QoQを使用(UI非表示)

Phase 8-2: 基本テーブル作成
  [x] CalculationDetailTable.vue新規作成
  [x] index.tsにエクスポート追加
  [x] nvidia-eps-forecast.vueに統合
  [x] 累積計算行の追加(年度別累計売上、累計純利益、累計株式数)
  [x] 動作確認

Phase 8-3: QoQ継承ロジック修正
  [x] 4Q'28のQoQ値がFY29以降に継承されるように修正
  [x] useNvidiaForecast.tsのgetQoQRate()関数修正
  [x] CalculationDetailTable.vueのgetQoQRate()関数修正
  [x] 1Q'27〜3Q'28のデフォルトQoQを10%に変更

Phase 8-4: PER/P/S計算タブ追加
  [x] タブUI追加(PERベース/P/Sベース切り替え)
  [x] PERベース計算(現在の実装)
  [x] P/Sベース計算(Forward売上 × P/S倍率 = 時価総額)
  [x] $20T目標への到達状況表示(P/Sタブ)
  [x] P/S倍率スライダー追加(SensitivityPanel)
  [x] 動作確認

Phase 8-5: チャート修正
  [x] 年間売上チャートのY軸ラベル修正($1B → $1T)
  [x] 動作確認

Phase 8-6: P/S (LTM) 推移チャート追加
  [x] koyfin.dbからNVDA P/Sデータ取得(nvda-ps-data.ts作成)
  [x] P/S推移チャートコンポーネント作成(PSRatioChart.vue)
  [x] 実績P/S(FY2016A〜FY2025A)表示
  [x] 修正版P/S(計算詳細テーブルから算出)表示
  [x] 25x基準線の追加(psMultipleスライダー連動)
  [x] nvidia-eps-forecast.vueに統合
  [x] 動作確認

現在の状態

完了済み

  • QoQオーバーライドテーブルを横向きに変更済み
  • QoQオーバーライドの表示範囲をFY28まで(4Q'26〜4Q'28)に制限済み
  • 予測期間をFY30まで(FY31削除)に変更済み
  • FY29〜FY30は内部計算で一律10.7% QoQを使用(UI非表示)
  • CalculationDetailTable.vue作成済み
  • QoQ継承ロジック修正済み

関連ファイル

ファイル役割
useNvidiaForecast.tsビジネスロジック(composable)
SensitivityPanel.vue感応度パラメータ入力UI
nvidia-eps-forecast.vueメインページ

実装タスク

8-2. CalculationDetailTable.vueコンポーネント新規作成

ファイル: apps/web/app/components/financial-quiz/nvidia-eps-forecast/CalculationDetailTable.vue

表示内容(Excelライクなテーブル):

項目計算式備考
四半期-1Q'26, 2Q'26, ... 4Q'30
修正版売上前期売上 × (1 + QoQ%)四半期ごとのQoQ適用結果
修正版純利益売上 × 純利益率%パラメータ連動
希釈後株式数前年株式数 × (1 + 希釈率%)年度ごとに増加
EPS純利益 ÷ 株式数-
株価EPS × PERパラメータ連動

Props:

interface Props {
  quarterlyData: QuarterlyForecastItem[]
  netProfitMargin: number  // 純利益率パラメータ
  perMultiple: number      // PER倍率パラメータ
  dilutionRate: number     // 年間希釈率パラメータ
  baseShares: number       // 基準株式数 (24800M)
}

UI要件:

  • 横スクロール可能(四半期が多いため)
  • 左端の項目名列は固定(sticky)
  • 数値は適切にフォーマット(売上: XXB, EPS: X.XX, 株価: $XXX)
  • 実績期間と予測期間で背景色を分ける

8-3. メインページに統合

nvidia-eps-forecast.vueの適切な位置にコンポーネントを追加:

<CalculationDetailTable
  :quarterlyData="quarterlyForecastData"
  :netProfitMargin="netProfitMargin"
  :perMultiple="perMultiple"
  :dilutionRate="dilutionRate"
  :baseShares="24800"
/>

8-4. 動作確認

Chrome DevTools MCPで以下を確認:

  • テーブルが正しく表示される
  • スライダー変更時にテーブルが更新される
  • 横スクロールが正常に動作する
  • モバイルでも見やすい

計算ロジック詳細

現在の計算方法(PERベース - useNvidiaForecast.tsより)

1. 修正版売上予測:
   - 四半期ごとにQoQ成長率を適用
   - QoQ率 = quarterlyQoQOverrides から取得(FY28まで)
   - FY29以降は 4Q'28のQoQ値を継承(デフォルト10%)

2. 修正版純利益:
   - 修正版売上 × 純利益率パラメータ (netProfitMargin / 100)

3. 希釈後株式数:
   - baseShares × (1 + dilutionRate/100) ^ yearsFromBase
   - yearsFromBase = 対象年度 - 2025

4. EPS:
   - 修正版純利益 ÷ 希釈後株式数

5. 株価(PERベース):
   - Forward EPS × PER倍率パラメータ (perMultiple)
   - Forward EPS = 4四半期先のEPS

P/Sベース計算方法(Phase 8-4で追加)

I/O Fund分析ドキュメント(nvidia_20t_analysis_complete.md)との整合性のために追加。

1. Forward売上:
   - 4四半期先の売上を合計(Forward 4Q Revenue)
   - 例: 現在1Q'26なら、2Q'26+3Q'26+4Q'26+1Q'27の合計

2. 時価総額(P/Sベース):
   - Forward売上 × P/S倍率(デフォルト25x)
   - 例: Forward売上 $400B × 25 = 時価総額 $10T

3. 株価(P/Sベース):
   - 時価総額 ÷ 希釈後株式数
   - 例: $10T ÷ 25.4B株 = $394

4. $20T目標到達状況:
   - 必要売上: $800B($20T ÷ 25x P/S)
   - 現在のForward売上との差額
   - 必要成長率の逆算

2つの計算方法の比較

項目PERベースP/Sベース
主要指標EPS(一株当たり利益)売上高
倍率PER 25xP/S 25x
計算式株価 = EPS × PER時価総額 = 売上 × P/S
強み利益重視、純利益率の影響大売上成長重視、赤字企業にも適用可
参照一般的な株式評価I/O Fund $20T分析

P/S倍率に関する注記(LTM vs NTM)

重要: P/S 25xはLTM(過去12ヶ月)ベースの前提。

NVIDIAの過去P/S倍率推移:

指標過去レンジ直近値25xの評価
P/S (LTM)3.0x〜27.3x23.5x妥当な範囲内
P/S (NTM)2.9x〜20.9x14.8xかなり楽観的(過去最高21x未満)

I/O Fund $20T分析の前提:

8% QoQ成長(≒36% CAGR)を1Q'27以降適用
  ↓
FY30末で年間売上 ≒ $800B
  ↓
LTM P/S 25x × $800B = $20T時価総額

NTMベースで25xを使うと、過去に一度も達したことがない水準となるため、 P/Sベースの計算ではLTM(実績売上)を前提としていることに留意。

パラメータのデフォルト値

パラメータデフォルト範囲
純利益率55%40-70%
PER倍率25x15-45x
P/S倍率25x15-45x(新規追加)
年間希釈率2.5%0-5%
基準株式数24,800M固定
デフォルトQoQ10%1Q'27〜3Q'28用
拡張期間QoQ4Q'28の値を継承FY29以降用

Phase 8-4: PER/P/S計算タブ追加 - 実装計画

概要

CalculationDetailTable.vueにタブ機能を追加し、2つの計算方法を切り替え可能にする:

  1. PERベース(現在の実装): Forward EPS × PER = 株価
  2. P/Sベース(新規追加): Forward売上 × P/S = 時価総額 → 株価

UI設計

┌─────────────────────────────────────────────────────────────┐
│ 計算詳細                                                     │
├─────────────────────────────────────────────────────────────┤
│ [PER × Forward EPS] [P/S × Forward売上]  ← タブ切り替え      │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│ 計算方法: Forward EPS ($X.XX) × PER (25x) = 株価 ($XXX)     │
│                                                              │
│ ┌──────────┬─────────┬─────────┬─────────┬───┐             │
│ │  項目    │ 1Q'26   │ 2Q'26   │ 3Q'26   │...│             │
│ ├──────────┼─────────┼─────────┼─────────┼───┤             │
│ │ QoQ成長率│ 14.9%   │  8.2%   │  5.1%   │   │             │
│ │ 売上($B) │  45.2   │  48.9   │  51.4   │   │             │
│ │ ...      │         │         │         │   │             │
│ └──────────┴─────────┴─────────┴─────────┴───┘             │
│                                                              │
│ ※ P/Sタブ時は$20T目標への進捗バーを表示                     │
└─────────────────────────────────────────────────────────────┘

Props追加

interface Props {
  quarterlyData: QuarterlyForecastItem[]
  netProfitMargin: number
  perMultiple: number
  psMultiple: number      // 新規追加: P/S倍率
  dilutionRate: number
  baseShares: number
}

コード実装

1. タブ状態管理

// タブタイプ
type CalculationMethod = 'per' | 'ps'

// 現在のタブ
const activeTab = ref<CalculationMethod>('per')

2. P/S計算ロジック

// Forward売上(4四半期先の合計)
const forwardRevenue = computed(() => {
  const currentQuarterIndex = 0 // 現在の四半期インデックス
  const forwardQuarters = props.quarterlyData.slice(
    currentQuarterIndex + 1,
    currentQuarterIndex + 5
  )
  return forwardQuarters.reduce((sum, q) => sum + q.modifiedRevenue, 0)
})

// P/S方式での時価総額(百万ドル単位)
const marketCapPS = computed(() => {
  return forwardRevenue.value * props.psMultiple
})

// P/S方式での株価
const stockPricePS = computed(() => {
  const shares = getDilutedShares(/* 対象年度 */)
  return marketCapPS.value / shares
})

// $20T目標への進捗
const targetMarketCap = 20_000_000 // $20T = 20,000,000百万ドル
const progressTo20T = computed(() => {
  return (marketCapPS.value / targetMarketCap) * 100
})

3. テーブル表示切り替え

<template>
  <!-- タブボタン -->
  <div class="tabs">
    <button
      :class="{ active: activeTab === 'per' }"
      @click="activeTab = 'per'"
    >
      PER × Forward EPS
    </button>
    <button
      :class="{ active: activeTab === 'ps' }"
      @click="activeTab = 'ps'"
    >
      P/S × Forward売上
    </button>
  </div>

  <!-- 計算方法の説明 -->
  <div v-if="activeTab === 'per'" class="method-description">
    計算方法: Forward EPS (${{ forwardEps.toFixed(2) }}) × PER ({{ perMultiple }}x) = 株価 (${{ stockPricePER.toFixed(0) }})
  </div>
  <div v-else class="method-description">
    計算方法: Forward売上 (${{ (forwardRevenue / 1000).toFixed(0) }}B) × P/S ({{ psMultiple }}x) = 時価総額 (${{ (marketCapPS / 1_000_000).toFixed(1) }}T)
    <div class="target-progress">
      $20T目標: {{ progressTo20T.toFixed(1) }}% 到達
      <progress :value="progressTo20T" max="100" />
    </div>
  </div>

  <!-- テーブル本体(共通) -->
  <!-- ... 既存のテーブル ... -->

  <!-- 結果行(タブによって表示内容切り替え) -->
  <tr v-if="activeTab === 'per'">
    <td class="row-label">Forward EPS ($)</td>
    <!-- ... PERベースの結果 ... -->
  </tr>
  <tr v-if="activeTab === 'ps'">
    <td class="row-label">Forward売上 ($B)</td>
    <!-- ... P/Sベースの結果 ... -->
  </tr>
</template>

nvidia-eps-forecast.vue変更

P/S倍率パラメータの追加が必要:

// useNvidiaForecast.ts に追加
const psMultiple = ref(25)  // P/S倍率、デフォルト25x

// nvidia-eps-forecast.vue でのprops渡し
<CalculationDetailTable
  :quarterlyData="quarterlyForecastData"
  :netProfitMargin="netProfitMargin"
  :perMultiple="perMultiple"
  :psMultiple="psMultiple"        // 新規追加
  :dilutionRate="dilutionRate"
  :baseShares="24800"
/>

スタイル

.tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.tabs button {
  padding: 0.5rem 1rem;
  border: 1px solid #ddd;
  background: #f5f5f5;
  cursor: pointer;
  border-radius: 4px 4px 0 0;
}

.tabs button.active {
  background: white;
  border-bottom-color: white;
  font-weight: bold;
}

.method-description {
  background: #f0f8ff;
  padding: 0.75rem;
  border-radius: 4px;
  margin-bottom: 1rem;
  font-size: 0.9rem;
}

.target-progress {
  margin-top: 0.5rem;
}

.target-progress progress {
  width: 100%;
  height: 8px;
}

Phase 8-5: チャート修正 - 実装計画

問題

年間売上チャートのY軸ラベルが「1B」と表示されているが、実際の値は100B〜800Bなので「1T」表示が適切。

修正箇所

DualSeriesChart.vue のY軸ラベルフォーマット処理

現在のコード(推定)

// Y軸ラベルのフォーマット
const formatYAxisLabel = (value: number) => {
  if (isEps) {
    return `$${value.toFixed(2)}`
  } else {
    return `$${value}B`  // ← ここが問題
  }
}

修正後

const formatYAxisLabel = (value: number) => {
  if (isEps) {
    return `$${value.toFixed(2)}`
  } else {
    // 売上高: 1000B以上は$XT表示、それ以下は$XB表示
    if (value >= 1000) {
      return `$${(value / 1000).toFixed(1)}T`
    }
    return `$${value}B`
  }
}

確認ポイント

  1. 年間売上チャートのY軸が0.1T〜0.8T程度で表示される
  2. 四半期売上チャートは30B〜200B程度なので$XB表示のまま
  3. チャートのデータポイントラベルも同様に修正が必要か確認

Phase 8-6: P/S (LTM) 推移チャート追加 - 実装計画

目的

P/S 25xの妥当性を過去の推移から視覚的に確認できるようにする。 ユーザーがQoQ成長率を変更すると、将来のP/Sがどう変化するかをリアルタイムで確認可能。

データソース

koyfin.db から取得可能なNVDA P/S (LTM) データ:

SELECT p.period_label, e.metric_value, p.is_actual
FROM eac_annual e
JOIN eac_periods p ON e.period_id = p.id
JOIN companies c ON e.company_id = c.id
WHERE c.ticker = 'NVDA'
AND e.metric_name = 'Price-/-Sales'
ORDER BY p.fiscal_year;

結果:

年度P/S (LTM)区分
FY 2016A3.1x実績
FY 2017A8.5x実績
FY 2018A15.3x実績
FY 2019A7.5x実績
FY 2020A13.3x実績
FY 2021A19.3x実績
FY 2022A22.7x実績
FY 2023A17.8x実績
FY 2024A24.9x実績
FY 2025A22.5x実績
FY 2026E20.0x予測
FY 2027E13.5x予測
FY 2028E10.5x予測
FY 2029E10.0x予測

修正版P/Sの計算方法

計算詳細テーブルから算出:

// 年度ごとの修正版P/S (LTM)
const modifiedPS = computed(() => {
  // 各年度の年間売上を取得(累計行から)
  const annualRevenue = getAnnualRevenue(fiscalYear) // 例: FY26 = $212B

  // 時価総額 = 現在株価 × 株式数
  // または計算されたmarketCap(PERベースまたはP/Sベース)
  const marketCap = stockPrice * dilutedShares

  // P/S (LTM) = 時価総額 / 年間売上
  return marketCap / annualRevenue
})

チャート設計

P/S (LTM) 推移チャート
┌────────────────────────────────────────────────────────────┐
│  30x ┼                                                     │
│      │                              ●                      │
│  25x ┼─────────────────────────────────────────────25x基準─│
│      │                           ●  ●                      │
│  20x ┼                        ●        ○─○                │
│      │                     ●                 ○             │
│  15x ┼                  ●                       ○─○─○     │
│      │               ●                                     │
│  10x ┼            ●                                        │
│      │                                                     │
│   5x ┼   ●                                                 │
│      │●                                                    │
│   0x ┼──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──────────│
│      FY16 17 18 19 20 21 22 23 24 25 26 27 28 29 30       │
│                                                            │
│  ● 実績P/S   ○ アナリスト予測P/S   ─ 修正版P/S(QoQ連動) │
└────────────────────────────────────────────────────────────┘

コンポーネント設計

新規ファイル: PSRatioChart.vue

interface Props {
  historicalPS: Array<{ year: string; ps: number; isActual: boolean }>
  modifiedAnnualRevenue: Array<{ year: string; revenue: number }>
  currentMarketCap: number  // または株価 × 株式数
  psMultiple: number        // 基準線用(25x)
}

データ生成スクリプト

scripts/generate-nvda-ps-data.mjs を作成:

// koyfin.db から NVDA の P/S データを抽出
// → apps/web/app/composables/nvda-ps-data.ts に出力

export const nvdaPSData = [
  { year: 'FY16', ps: 3.1, isActual: true },
  { year: 'FY17', ps: 8.5, isActual: true },
  // ...
]

実装手順

  1. スクリプト作成: generate-nvda-ps-data.mjs
  2. データ生成: node scripts/generate-nvda-ps-data.mjs
  3. チャートコンポーネント作成: PSRatioChart.vue
  4. 統合: nvidia-eps-forecast.vue に追加
  5. 動作確認: QoQ変更時にP/Sラインが動くことを確認

表示位置

計算詳細テーブルの下、または別タブとして追加:

<!-- オプション1: 計算詳細テーブルの下 -->
<CalculationDetailTable ... />
<PSRatioChart
  :historicalPS="nvdaPSData"
  :modifiedAnnualRevenue="annualRevenueFromTable"
  :currentMarketCap="marketCap"
  :psMultiple="25"
/>

<!-- オプション2: P/Sタブ内に統合 -->
<div v-if="activeTab === 'ps'">
  <!-- テーブル -->
  <!-- P/Sチャート -->
</div>

テーブルデザイン案

┌────────────┬─────────┬─────────┬─────────┬─────────┬───┐
│  項目      │ 1Q'26   │ 2Q'26   │ 3Q'26   │ 4Q'26   │...│
├────────────┼─────────┼─────────┼─────────┼─────────┼───┤
│ QoQ成長率  │ 14.9%   │  8.2%   │  5.1%   │  3.5%   │   │
│ 売上 ($B)  │  45.2   │  48.9   │  51.4   │  53.2   │   │
│ 純利益($B) │  24.9   │  26.9   │  28.3   │  29.3   │   │
│ 株式数(B)  │  24.8   │  24.8   │  24.8   │  24.8   │   │
│ EPS ($)    │  1.00   │  1.08   │  1.14   │  1.18   │   │
│ 株価 ($)   │   25    │   27    │   29    │   30    │   │
└────────────┴─────────┴─────────┴─────────┴─────────┴───┘

※ 実績期間: 背景色薄いグレー
※ 予測期間: 背景色白
※ 項目列: sticky(横スクロール時固定)

作業開始コマンド

cd apps/web
pnpm dev

開発サーバー起動後、http://localhost:3000/financial-quiz/nvidia-eps-forecast で動作確認。

次セッションへの指示

  1. このドキュメントを読む
  2. 「完了ステータス」セクションで未完了のPhaseを確認
  3. Phase 8-4から順に実装を開始
  4. Chrome DevTools MCPで動作確認

次に実装すべきタスク(優先順)

  1. Phase 8-4: CalculationDetailTableにPER/P/Sタブ追加
    • タブUI追加
    • P/S計算ロジック実装
    • $20T目標進捗表示
  2. Phase 8-5: 年間売上チャートの1B→1T修正
    • DualSeriesChart.vueのY軸ラベルフォーマット修正
  3. Phase 8-6: P/S (LTM) 推移チャート追加
    • generate-nvda-ps-data.mjsスクリプト作成
    • PSRatioChart.vueコンポーネント作成
    • nvidia-eps-forecast.vueに統合

関連ファイル

ファイル役割
CalculationDetailTable.vue計算詳細テーブル(タブ追加対象)
useNvidiaForecast.tsビジネスロジック
DualSeriesChart.vueチャートコンポーネント(Y軸修正対象)
koyfin.dbP/Sデータソース

新規セッション用プロンプト

nvidia-eps-forecast.vueの実装を続けてください。

計画ドキュメント:
apps/web/content/2025-12-18/nvidia-eps-forecast-phase8-calculation-table.md

このドキュメントを読んで、「完了ステータス」を確認し、
Phase 8-4から実装を再開してください。