DCF 模型建構器
概述
此技能可建立符合機構品質的 DCF 模型用於股權估值,遵循投資銀行標準。每次分析都會產出一個詳細的 Excel 模型(在 DCF 工作表底部包含敏感度分析)。
工具
- 預設使用使用者提供的所有資訊以及可用的 MCP 伺服器進行資料來源擷取。
關鍵限制 - 請先閱讀
這些限制適用於所有 DCF 模型建構過程。請在開始前審閱:
環境:Office JS vs Python/openpyxl:
- 如果在 Excel 內部執行(Office 增益集 / Office JS 環境): 請直接使用 Office JS — 不要使用 Python/openpyxl。透過
range.formulas = [["=D19*(1+$B$8)"]]編寫公式。不需要單獨的重新計算步驟;Excel 會原生計算。使用range.format.*進行樣式設定。同樣適用的公式優先於硬編碼規則:對於衍生儲存格,請始終設定.formulas,切勿設定.values。 - 如果產生獨立的 .xlsx 檔案(無即時 Excel 工作階段): 使用如下的 Python/openpyxl,然後在交付前執行
recalc.py。 - 此技能的其餘部分使用 openpyxl 範例 — 在該環境中請轉換為 Office JS API 呼叫,但所有原則(公式字串、儲存格註解、區段檢查點、敏感度表格迴圈)都完全相同。
⚠️ Office JS 合併儲存格陷阱: 在建立合併儲存格的區段標題時,不要對合併範圍呼叫 .merge() 然後設定 .values — Office JS 仍會回報該範圍的原始維度,並拋出 InvalidArgument: The number of rows or columns in the input array doesn't match the size or dimensions of the range。應改為先將值寫入左上角儲存格,然後再合併並格式化整個範圍:
// 錯誤 — 會拋出 InvalidArgument:
const hdr = ws.getRange("A7:H7");
hdr.merge();
hdr.values = [["市場數據與關鍵輸入"]]; // 1×1 陣列 vs 1×8 範圍 → 失敗
// 正確 — 先在單一儲存格設定值,然後合併 + 格式化範圍:
ws.getRange("A7").values = [["市場數據與關鍵輸入"]];
const hdr = ws.getRange("A7:H7");
hdr.merge();
hdr.format.fill.color = "#1F4E79";
hdr.format.font.bold = true;
hdr.format.font.color = "#FFFFFF";
這適用於 DCF 中的每個合併區段標題(市場數據、情境區塊、現金流量預測、終值、估值摘要、敏感度表格).
公式優先於硬編碼(不可協商):
- 每個預測、邊際、折現因子、現值 (PV) 和敏感度儲存格都必須是即時的 Excel 公式 — 絕不能是在 Python 中計算後寫入的數值
- 使用 openpyxl 時:
ws["D20"] = "=D19*(1+$B$8)"是正確的;ws["D20"] = calculated_revenue是錯誤的 - 唯一允許的硬編碼數字是:(1) 原始歷史輸入,(2) 假設驅動因子(成長率、WACC 輸入、終值成長率 g),(3) 當前市場數據(股價、債務餘額)
- 如果你發現自己在 Python 中計算某個值並將結果寫入 — 立即停止。模型必須能夠在使用者更改假設時靈活調整。
與使用者逐步驗證(不要一口氣從頭做到尾):
- 資料檢索後 → 向使用者顯示原始輸入區塊(營收、利潤率、股數、淨債務),確認後再進行預測
- 營收預測後 → 顯示預測的營收和成長率,確認後再建立利潤率結構
- 自由現金流 (FCF) 建立後 → 顯示完整的 FCF 時間表,確認邏輯後再計算 WACC
- WACC 計算後 → 顯示計算過程和輸入,確認後再進行折現
- 終值 + 現值 (PV) 計算後 → 顯示權益橋樑(企業價值 EV → 權益價值 → 每股價值),確認後再建立敏感度表格
- 在每個階段捕捉錯誤 — 如果在敏感度表格建立後才發現錯誤的利潤率假設,則需要重建下游所有內容。
敏感度表格:
- 使用奇數行和奇數列(標準為 5×5,有時為 7×7)— 這可確保有一個真正的中心儲存格
- 中心儲存格 = 基準情境。 建構軸值,使中間的行標題和中間的欄標題與模型的實際假設完全相等(例如,如果基準 WACC = 9.0%,則中間行就是 9.0%;如果終值成長率 g = 3.0%,則中間欄就是 3.0%)。因此,中心儲存格的輸出必須等於模型實際的隱含股價 — 這是驗證表格建構是否正確的完整性檢查。
- 高亮中心儲存格,使用中藍色填滿 (
#BDD7EE) + 粗體字型,以便立即識別哪個儲存格是基準情境。 - 填滿所有儲存格(通常為 3 個表格 × 25 個儲存格 = 75 個)並使用完整的 DCF 重新計算公式
- 使用 openpyxl 迴圈(或 Office JS 迴圈)以程式化方式編寫公式
- 沒有預留位置文字,沒有線性近似,不需要手動步驟
- 每個儲存格必須針對該假設組合重新計算完整的 DCF
儲存格註解:
- 在建立每個硬編碼值時立即加入儲存格註解
- 格式:「來源:[系統/文件],[日期],[參考],[URL 若適用]」
- 在進入下一個區段之前,每個藍色輸入都必須有註解
- 不要延遲到最後才做,也不要寫「待辦:加入來源」
模型版面規劃:
- 在編寫任何公式之前,先定義所有區段的列位置
- 先編寫所有標題和標籤
- 其次編寫所有區段分隔線和空白列
- 然後使用固定的列位置編寫公式
- 建立後立即測試公式
公式重新計算:
- 在交付前執行
python recalc.py model.xlsx 30 - 修復所有錯誤,直到狀態為「success」
- 要求零公式錯誤(#REF!、#DIV/0!、#VALUE! 等)
情境區塊:
- 為熊市/基準/牛市案例建立單獨的區塊
- 在每個區塊中,將假設水平顯示在預測年份中
- 使用 IF 公式:
=IF($B$6=1,[熊市儲存格],IF($B$6=2,[基準儲存格],[牛市儲存格])) - 驗證公式是否參考了正確的情境區塊儲存格
DCF 處理流程
步驟 1:資料檢索與驗證
從 MCP 伺服器、使用者提供的資料以及網際網路擷取資料。
資料來源優先順序:
- MCP 伺服器(若已設定)— 來自 Daloopa 等提供者的結構化財務資料
- 使用者提供的資料 — 使用者研究中的歷史財務資料
- 網路搜尋/擷取 — 需要時的當前價格、Beta、債務和現金
驗證檢查清單:
- 驗證淨債務與淨現金(對估值至關重要)
- 確認稀釋後流通在外股數(檢查近期庫藏股買回/增發)
- 驗證歷史利潤率與商業模式一致
- 交叉比對營收成長率與行業基準
- 驗證稅率是否合理(通常為 21-28%)
步驟 2:歷史分析(3-5 年)
分析並記錄:
- 營收成長趨勢:計算年複合成長率 (CAGR),找出驅動因素
- 利潤率演變:追蹤毛利率、EBIT 利潤率、FCF 利潤率
- 資本密集度:折舊攤銷 (D&A) 和資本支出 (CapEx) 佔營收百分比
- 營運資金效率:淨營運資金 (NWC) 變動佔營收成長百分比
- 回報指標:ROIC、ROE 趨勢
建立摘要表格,顯示如下:
歷史指標(LTM):
營收:X 百萬美元
營收成長:X% CAGR
毛利率:X%
EBIT 利潤率:X%
D&A 佔營收百分比:X%
CapEx 佔營收百分比:X%
FCF 利潤率:X%
步驟 3:建立營收預測
方法論:
- 從最新實際營收開始(LTM 或最近會計年度)
- 為每個預測年度應用成長率
- 同時顯示金額和計算出的成長率百分比
成長率架構:
- 第 1-2 年:較高成長,反映近期能見度
- 第 3-4 年:逐步趨緩,朝行業平均水準邁進
- 第 5 年以後:接近終值成長率
公式結構:
- 營收(第 Y 年) = 營收(第 Y-1 年) × (1 + 成長率(第 Y 年))
- 成長率 = 使用者提供的或根據指導原則計算的百分比值