Excel Author
使用 openpyxl 以無頭模式構建可審計的 Excel 工作簿 — 採用藍/黑/綠單元格約定、公式優於硬編碼、命名範圍、平衡檢查和敏感性表。適用於財務模型、審計輸出和對賬。
技能元數據
| 來源 | 可選 — 使用 hermes skills install official/finance/excel-author 安裝 |
| 路徑 | optional-skills/finance/excel-author |
| 版本 | 1.0.0 |
| 作者 | Anthropic(由 Nous Research 改編) |
| 許可證 | Apache-2.0 |
| 平臺 | linux, macos, windows |
| 標籤 | excel, openpyxl, finance, spreadsheet, modeling |
| 相關技能 | pptx-author, dcf-model, comps-analysis, lbo-model, 3-statement-model |
參考:完整 SKILL.md
以下是 Hermes 在觸發此技能時加載的完整技能定義。這是技能激活時代理看到的指令。
excel-author
使用 openpyxl 在磁盤上生成 .xlsx 文件。遵循以下銀行級約定,以確保模型可審計、靈活,並可由構建者以外的人員審查。
改編自 anthropics/financial-services 倉庫中 Anthropic 的 xlsx-author 和 audit-xls 技能。原始技能中特定於 MCP / Office-JS / Cowork 的分支已被移除 — 此技能假定使用無頭 Python。
輸出契約
- 寫入
./out/<name>.xlsx。如果./out/不存在則創建它。 - 在最終消息中返回相對路徑,以便下游工具可以獲取它。
- 每個文件對應一個邏輯模型。除非明確要求,否則不要追加到現有工作簿中。
設置
pip install "openpyxl>=3.0"
核心約定(不可協商)
藍/黑/綠單元格顏色
- 藍色 (
Font(color="0000FF")) — 人類輸入的硬編碼輸入。收入驅動因素、WACC 輸入、永續增長率、市場數據。 - 黑色(默認)— 公式。每個派生單元格都是實時的 Excel 公式。
- 綠色 (
Font(color="006100")) — 鏈接到另一個工作表或外部文件。
審查者隨後可以掃描工作表,並立即區分哪些是假設,哪些是計算得出的。
公式優於硬編碼
每個計算單元格必須是公式字符串,絕不能是在 Python 中計算後作為值粘貼的數字。
# WRONG — silent bug waiting to happen
ws["D20"] = revenue_prior_year * (1 + growth)
# CORRECT — flexes when the user changes the assumption
ws["D20"] = "=D19*(1+$B$8)"
唯一允許的硬編碼數字:
- 原始歷史輸入(實際收入、報告的 EBITDA 等)
- 用戶旨在調整假設的驅動因素(增長率、WACC 輸入、永續增長率 g)
- 當前市場數據(股價、債務餘額)— 附帶單元格註釋記錄來源 + 日期
如果你發現自己在 Python 中計算一個值並寫入結果,請立即停止。
用於跨工作表引用的命名範圍
對於從另一個工作表、演示文稿或備忘錄中引用的任何數據,使用命名範圍。
from openpyxl.workbook.defined_name import DefinedName
wb.defined_names["WACC"] = DefinedName("WACC", attr_text="Inputs!$C$8")
# then elsewhere:
calc["D30"] = "=D29/WACC"
平衡檢查標籤頁
包含一個 Checks 標籤頁,用於關聯所有內容並顯示 TRUE/FALSE:
- 資產負債表平衡(資產 = 負債 + 權益)
- 現金流量與資產負債表中期間現金變動的關聯
- 分部之和與合併總額的關聯
- 計算範圍內沒有 rogue 硬編碼
示例:
checks = wb.create_sheet("Checks")
checks["A2"] = "BS balances"
checks["B2"] = "=IS!D20-IS!D21-IS!D22"
checks["C2"] = "=ABS(B2)<0.01" # TRUE/FALSE
每個硬編碼輸入都添加單元格註釋
在創建單元格時添加註釋,而不是稍後添加。
from openpyxl.comments import Comment
ws["C2"] = 1_250_000_000
ws["C2"].font = Font(color="0000FF")
ws["C2"].comment = Comment("Source: 10-K FY2024, p.47, revenue line", "analyst")
格式:Source: [System/Document], [Date], [Reference], [URL if applicable]。
切勿推遲記錄來源。切勿編寫 TODO: add source。
骨架:典型財務模型
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.comments import Comment
from openpyxl.utils import get_column_letter
from pathlib import Path
BLUE = Font(color="0000FF")
BLACK = Font(color="000000")
GREEN = Font(color="006100")
BOLD = Font(bold=True)
HEADER_FILL = PatternFill("solid", fgColor="1F4E79")
HEADER_FONT = Font(color="FFFFFF", bold=True)
wb = Workbook()
# --- Inputs tab ---
inp = wb.active
inp.title = "Inputs"
inp["A1"] = "MARKET DATA & KEY INPUTS"
inp["A1"].font = HEADER_FONT
inp["A1"].fill = HEADER_FILL
inp.merge_cells("A1:C1")
inp["B3"] = "Revenue FY2024"
inp["C3"] = 1_250_000_000
inp["C3"].font = BLUE
inp["C3"].comment = Comment("Source: 10-K FY2024 p.47", "model")
inp["B4"] = "Growth Rate"
inp["C4"] = 0.12
inp["C4"].font = BLUE
# --- Calc tab ---
calc = wb.create_sheet("DCF")
calc["B2"] = "Projected Revenue"
calc["C2"] = "=Inputs!C3*(1+Inputs!C4)" # formula, black
# --- Checks tab ---
chk = wb.create_sheet("Checks")
chk["A2"] = "BS balances"
chk["B2"] = "=ABS(BS!D20-BS!D21-BS!D22)<0.01"
Path("./out").mkdir(exist_ok=True)
wb.save("./out/model.xlsx")
帶有合併單元格的章節標題
openpyxl 特性:合併單元格時,在左上角單元格設置值,並單獨設置整個範圍的樣式。
ws["A7"] = "CASH FLOW PROJECTION"
ws["A7"].font = HEADER_FONT
ws.merge_cells("A7:H7")
for col in range(1, 9): # A..H
ws.cell(row=7, column=col).fill = HEADER_FILL
敏感性表
使用循環構建,而不是為每個單元格硬編碼公式。規則:
- 奇數行/列(5×5 或 7×7)— 保證有一個真正的中心單元格。
- 中心單元格 = 基準情形。 中間行/列標題必須等於模型的實際 WACC 和永續增長率 g,以便中心輸出等於基準情形隱含的股價。這是健全性檢查。
- 高亮顯示中心單元格,使用中藍色填充 (
"BDD7EE") 並加粗。 - 用完整的重計算公式填充每個單元格 — 絕不使用近似值。
# 5x5 WACC (rows) x terminal growth (cols) sensitivity
wacc_axis = [0.08, 0.085, 0.09, 0.095, 0.10] # center row = base 9.0%
term_axis = [0.02, 0.025, 0.03, 0.035, 0.04] # center col = base 3.0%
start_row = 40
ws.cell(row=start_row, column=1).value = "Implied Share Price ($)"
ws.cell(row=start_row, column=1).font = BOLD
for j, g in enumerate(term_axis):
ws.cell(row=start_row+1, column=2+j).value = g
ws.cell(row=start_row+1, column=2+j).font = BLUE
for i, w in enumerate(wacc_axis):
r = start_row + 2 + i
ws.cell(row=r, column=1).value = w
ws.cell(row=r, column=1).font = BLUE
for j, g in enumerate(term_axis):
c = 2 + j
# Full DCF recalc formula (simplified for illustration).
# In a real model this references the full projection block.
ws.cell(row=r, column=c).value = (
f"=SUMPRODUCT(FCF_range,1/(1+{w})^year_offset) + "
f"FCF_terminal*(1+{g})/({w}-{g})/(1+{w})^terminal_year"
)
# Highlight center cell (base case)
center = ws.cell(row=start_row+2+len(wacc_axis)//2,
column=2+len(term_axis)//2)
center.fill = PatternFill("solid", fgColor="BDD7EE")
center.font = BOLD
交付前重新計算
openpyxl 寫入公式字符串但不計算它們。Excel 會在打開時重新計算,但下游消費者(自動檢查腳本、CI)需要計算後的值。
在交付前運行 LibreOffice 或專用的重計算步驟:
# LibreOffice headless recalc
libreoffice --headless --calc --convert-to xlsx ./out/model.xlsx --outdir ./out/
或者使用 Python 重計算輔助工具(參見此技能中的 scripts/recalc.py)。
模型佈局規劃
在編寫任何公式之前:
- 定義所有部分行的位置
- 編寫所有標題和標籤
- 編寫所有部分分隔符和空行
- 然後使用鎖定的行位置編寫公式
這可以防止“級聯公式破壞”模式,即在編寫公式後插入標題行會導致所有下游引用發生偏移。
與用戶逐步驗證
對於大型模型(DCF、三張報表、LBO),請在繼續之前暫停並向用戶展示中間產物。在構建下游敏感性表之前發現錯誤的利潤率假設,可以節省一小時的時間。
檢查點模式:
- 輸入塊(Inputs block)完成後 → 展示原始輸入,在預測前確認
- 收入預測完成後 → 確認頂層收入(top line)及增長率
- 自由現金流(FCF)構建完成後 → 確認完整時間表
- WACC 完成後 → 確認輸入項
- 估值完成後 → 確認股權橋(equity bridge)
- 然後構建敏感性表
何時不使用此技能
- 用戶在擁有 Office MCP 的實時 Excel 會話中 — 應直接操作其實時工作簿。
- 純表格數據導出且無公式 — 使用
csv或pandas.to_excel更簡單。 - 具有高度交互性的儀表盤/圖表 — 請使用專業的 BI 工具。
歸屬
約定(藍色/黑色/綠色、公式優於硬編碼、命名範圍、敏感性規則)改編自 Anthropic 的 Claude for Financial Services 插件套件,採用 Apache-2.0 許可證。原文:https://github.com/anthropics/financial-services/tree/main/plugins/vertical-plugins/financial-analysis/skills/xlsx-author