mcpField
O
officecli-financial-model

officecli-financial-model

github.com/iofficeaiデータ・データベース32.7k97 回インストール今日更新
リポジトリ

officecli-financial-model について

officecli-financial-modelは、officecli-xlsxで数式駆動の財務モデルを構築するスキルです。三表、DCF、LBOモデルを作成するアナリスト向けに、入力・計算・出力の区分とシナリオ、感応度分析の手順を示します。

主な機能

  1. 01Inputs、Calc、Outputsの3区分構成
  2. 02三表、DCF、LBOモデルのレシピ
  3. 03シナリオ・感応度分析のパターン
  4. 04財務関数と循環参照のガイド
  5. 05モデル固有の検証ゲート

活用シーン

  1. 01連動する財務諸表の予測作成
  2. 02感応度グリッド付きDCF評価の作成
  3. 03LBOの債務スケジュールと投資リターンのモデル化

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/iofficeai/officecli --skill officecli-financial-model

インストール後、Claude Code で/officecli-financial-modelを入力して読み込まれたか確認します。

詳細

OfficeCLI 財務モデルスキル

このスキルは、officecli-xlsx の上に重ねるシーンレイヤーです。 xlsx のすべての基本ルール――シェルでの引用符の使い方、段階的な実行、Help-First ルール、ビジュアル納品の最低基準、CFO の4色コード(入力は青/数式は黒/シート間参照は緑/前提条件は黄色の塗りつぶし)、数値形式の標準(年はテキスト、ゼロは -、% は小数点以下1桁、負数は括弧で囲む)、前提条件セルの扱い、CSV の一括インポート、グラフのデータフィード形式(a/b/c)、5ゲートの納品サイクル、キャッシュのずれに関するガイダンス、既知の問題(シート間参照での ! の落とし穴、数式における一括処理+常駐の問題、レンダラーに関する注意事項)――は、ここで再説明するのではなく、すべて引き継がれます。このファイルで追加するのは、財務モデルに必要な要素のみです。具体的には、3ゾーンアーキテクチャ、モデルタイプ別のレシピ3種(3表モデル/DCF/LBO)、感応度分析とシナリオの手順、財務関数のパターン、循環参照の扱い、モデル固有の納品ゲート4~6です。

xlsx の基本ルールで扱っている内容については、ここでは → xlsx v2 §X を参照 と記載しています。まだ読んでいない場合は、先に skills/officecli-xlsx/SKILL.md を読んでください。

セットアップ

officecli が見つからない場合:

  • macOS / Linux:curl -fsSL https://d.officecli.ai/install.sh | bash
  • Windows(PowerShell):irm https://d.officecli.ai/install.ps1 | iex

officecli --version で確認してください(PATH に反映されていない場合は、新しいターミナルを開いてください)。インストールに失敗した場合は、https://github.com/iOfficeAI/OfficeCLI/releases からバイナリをダウンロードしてください。

Help-First ルール

このスキルでは、財務モデルに必要な内容を説明します。CLI のすべてのフラグを網羅するものではありません。プロパティ名、別名、列挙値が不明な場合は、推測する前にヘルプを確認してください:officecli help xlsx [element] [--json]。ヘルプはインストール済みバージョンに対する正式な情報です。このスキルの記述とヘルプが異なる場合は、ヘルプを優先してください。以下の --prop X= は、すべて officecli help xlsx <element> で確認済みです。

メンタルモデルと継承事項

xlsx v2 を継承します。 先に skills/officecli-xlsx/SKILL.md を読んでください。このスキルでは、create/open/close、値や数式を設定する set、シート間数式向けの batch ヒアドキュメント、/SheetName/A1 パス、名前付き範囲、5ゲートの納品サイクル、シート間参照での ! の落とし穴、および**シート間数式は非常駐で実行すること(一括処理または個別の set。常駐中の一括処理は不可)**を理解しているものとします。

シェルと実行の規律

シェルでの引用符の使い方、段階的な実行、$FILE の規則については、xlsx v2 §Shell & Execution Discipline を参照してください。同じルールが適用されます。すべての [N] パスを引用符で囲むこと、$ を含むプロパティはシングルクォートで囲むこと(ここで使用するすべての数値形式――$#,##0;($#,##0);"-"――にはシングルクォートが必要です)、手書きの \$/\t/\n は使用しないこと、コマンドは一度に1つだけ実行すること。以下の例では $FILE を使用します(FILE="model.xlsx")。

コア原則(アイデンティティ)

財務モデルとは、意思決定に耐える数式駆動型のレイヤーを備えた xlsx です。すべての出力が青字の前提条件まで途切れない連鎖をたどり、すべての財務諸表が各期間で貸借一致し、すべての評価を再監査できます。一般的な xlsx に加わる 8 つの差分は次のとおりです。

  1. 3 ゾーンのアーキテクチャが必須です。 Inputs → Calc → Outputs。ゾーンを統合すると監査不能になります。
  2. 前提条件はセルに置き、数式の中には入れません。 =B5*(1+Assumptions!GrowthRate) とし、=B5*1.05 とはしません。
  3. 財務諸表は各期間で貸借一致させます。 Assets − Liab − Equity = 0、CF.EndingCash = BS.Cash。IMBALANCED の場合、Gate 4 は失敗します。
  4. ハードコード値を監査します。 Calc シートにハードコードされた数値はゼロです。Gate 6 でカウントします。
  5. 感度分析/シナリオ分析は第一級の機能です。 2 軸グリッド、ドロップダウンによる INDEX/MATCH 切り替え、または Base/Upside/Downside 列を使います。Excel Data Tables は安定してサポートされていないため、手動グリッドのみを使用します。
  6. 評価セルのキャッシュ値は重要です。 キャッシュ結果がない(または #OCLI_NOTEVAL! センチネルを含む)評価セルをそのまま渡すと、再計算しないリーダーには空白または誤った数値が表示されます。評価器は NPV / XNPV / IRR / XIRR を計算するようになりました。読み戻してキャッシュ値を確認してください。Gate 5 ではスポットチェックを行います。
  7. 循環参照は設計上の選択です。 正当な循環(利息 ↔ 現金、リボルバー・プラグ ↔ 期末現金)には calc.iterate=true を使用します。意図しない循環参照は数式の誤りです。決して iterate で覆い隠してはいけません。
  8. 3 回以上使う前提条件には名前付き範囲を使います。 WACC、TaxRate、TerminalGrowth、ExitMultiple、ChurnRate。宣言したまま未使用の名前は無意味な装飾です。Gate 6 で検出します。
逆方向への引き継ぎ — xlsx ベースに戻す場合

予算管理表、CSV からレポートへの出力、運用 KPI シート、単純なテンプレート、予測ロジックのない資本政策表では、xlsx ベースを使います。このスキルを使うのは、依頼に 3 表モデル / DCF / WACC / NPV / TV / LBO / 債務スケジュール / MOIC / IRR / ユニットエコノミクス / ARR ロールフォワード / 感度分析グリッド / シナリオ切り替え / プロフォーマが含まれる場合に限ります。

3 ゾーンのアーキテクチャ(絶対ルール)

このスキルで作成するすべてのモデルは、3 つのゾーンを基盤とします。ゾーンに名前を付け、タブに色を付け、実行可能な監査で徹底してください。 ゾーンのルールを破ることは、監査不能なモデルを生む最も一般的な原因です。

ゾーンシート名(慣例)タブの色内容ハードコード数式
InputsAssumptions、Inputs、Drivers黄色 FFC000生のドライバー:成長率、利益率、税率、WACC、FTE、価格設定、運転資本日数すべてのセルを青 0000FF派生前提条件(例:=MonthlyARPU*12)に限り許可
CalcP&L、Balance Sheet、Cash Flow、DCF、Debt、ARR青 4472C4すべての派生計算と財務諸表ゼロ(Gate 6 で徹底)同一シート内は黒 000000、シート間参照は緑 008000
OutputsSummary、Dashboard、Sensitivity、Returns緑 70AD47KPI、感度分析グリッド、チャート、リターン・ウォーターフォールラベル(数値以外)のみ。Gate 6 では数値のハードコードをカウント → 0上記に従い黒/緑

作成順序ではゾーン間の依存関係を考慮します。 まず Assumptions を作成し、次に依存関係に沿って下から Calc を作成し(3 表モデルでは IS → BS → CF、DCF では FCF → WACC → NPV)、最後に Outputs を作成します。Outputs を先に作成すると、すべての箇所が 0 でキャッシュされ、下流にもゼロが引き継がれます。

実行可能なゾーン監査(Gate 4 の前に実行):

# Calc zone: zero numeric hardcodes allowed. `cell:not(:has(formula))` selects the literal (non-formula) cells; `cell:has(formula)` selects the formula cells.
HARDCODE=$(officecli query "$FILE" 'cell[type=Number]' --json | jq '[.data.results[] | select(.format.formula == null) | select(.path | test("/(P&L|Balance Sheet|Cash Flow|DCF|Debt|ARR)/"))] | length')
[ "$HARDCODE" -eq 0 ] && echo "Zone audit OK" || { echo "REJECT: $HARDCODE hardcoded numeric cells on Calc sheets — move to Assumptions"; exit 1; }
# Assumptions zone: should be non-zero.
INPUTS=$(officecli query "$FILE" '/Assumptions/cell[type=Number]' --json | jq '[.data.results[] | select(.format.formula == null)] | length')
[ "$INPUTS" -ge 5 ] && echo "Assumptions has $INPUTS hardcoded drivers" || echo "WARN: Assumptions has only $INPUTS inputs"

印刷用出力(取締役会/IC/LP)

依頼に「print」/「一页」/「董事会」/「投资人」/「IC memo」/「LP update」が含まれる場合、印刷パイプラインは Outputs ゾーンのみを出力する必要があります。成果物は 2 つです。

# 1. Print_Area scoped to the Outputs sheet (Summary or Dashboard).
officecli add "$FILE" / --type namedrange --prop name=_xlnm.Print_Area --prop scope=Summary --prop 'refersTo=Summary!$A$1:$H$40'
# 2. Hide every non-Outputs sheet — Print_Area scope alone does NOT stop the print pipeline from emitting every visible sheet.
for S in Assumptions 'P&L' 'Balance Sheet' 'Cash Flow' DCF WACC Debt FCF 'S&U' Exit Returns; do
  officecli raw-set "$FILE" /workbook --xpath "//x:sheet[@name='$S']" --action setattr --xml "state=hidden" || true
done
# 3. fit-to-page landscape on Outputs sheet.
officecli raw-set "$FILE" /Summary --xpath "//x:worksheet" --action prepend --xml '<sheetPr xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><pageSetUpPr fitToPage="1"/></sheetPr>'

Calc シートに設定された Print_Area はすべて削除してください。範囲が競合すると複数ページの出力が生成され、Assumptions/財務諸表シートが混入します。

構築順序とキャッシュのずれに関するルール(3ステートメントモデルでは重要)

3つの事実が、気付かないうちに誤った数値を生みます。(1)新しい数式にキャッシュ値が設定されない場合、Excelは開いたときに再計算しますが、HTMLプレビューや古いビューアーでは再計算されません。(2)下流の項目を上流と同じ順序で書き込むと、上流のキャッシュが更新される前の状態から 0 を取得します。(3)レジデントが開いている状態でシートをまたぐ batch を実行すると、3~5件の操作でデッドロックが発生します。

手順(すべてのレシピで適用):

  • 構築順序はデータの流れに従います。3ステートメントモデルでは P&L → BS → CF、DCFでは FCF → WACC → NPV → Sensitivity、LBOでは S&U → Debt → P&L → CF → Returns です。
  • シートをまたぐ一連の処理の後に、キャッシュ更新パスを実行します。レジデントではない状態で、すべてのサマリー/バリュエーション/バランスチェックのセルに対して set を再実行します。
  • スポットチェック:officecli get "$FILE" /Summary/B2 --json | jq '.data.results[0].format.cachedValue' が、妥当な null 以外の値を返すことを確認します。null は、Excelを開いたときに計算されることを意味します(納品時には問題ありません)。セルに #OCLI_NOTEVAL! のセンチネルが表示される場合は、レジデントを閉じて再設定します。それでも未評価の場合は、キャッシュフォールバック(§財務関数のパターン)を使用します。

レシピ — 3種類のモデル

以下の各レシピは、実行可能な骨組みであり、財務理論の説明ではありません。数値を置き換え、構成は変更しないでください。すべてのレシピでは、FILE="model.xlsx" が設定されており、officecli create "$FILE" と officecli open "$FILE" を実行済みであることを前提とします。最後に officecli close "$FILE" を実行して閉じてください。

レシピ A — 3ステートメントモデル(P&L + BS + CF)

このレシピで作成されるもの。 4つのシート:Assumptions、P&L、Balance Sheet、Cash Flow、および Summary。年次列は2024A・2025E・2026E・2027Eです。BSにバランスチェック行、CFにキャッシュ照合行を設けます。各ステートメントの行はすべて、数式からAssumptionsを参照します。

構築順序(必須)。 Assumptions → P&L → Balance Sheet → Cash Flow → Summary。P&Lより先にBSを構築しないでください。RetainedEarnings は NI に依存します。BSより先にCFを構築しないでください。CF.OpeningCash = prior period CF.EndingCash の自己連鎖では、Y1の現金をBSで確定しておく必要があります。構築順序が誤っていると、このスキルのゲート4のバランスチェックはエラーを表示せずに失敗します。

ステップ1 — シート、タブの色、ウィンドウ枠の固定。

officecli add "$FILE" / --type sheet --prop name=Assumptions --prop tabColor=FFC000
officecli add "$FILE" / --type sheet --prop name=P&L --prop tabColor=4472C4
officecli add "$FILE" / --type sheet --prop name='Balance Sheet' --prop tabColor=4472C4
officecli add "$FILE" / --type sheet --prop name='Cash Flow' --prop tabColor=4472C4
officecli add "$FILE" / --type sheet --prop name=Summary --prop tabColor=70AD47
officecli set "$FILE" /Assumptions --prop freeze=B2
officecli set "$FILE" /P&L --prop freeze=B3
officecli set "$FILE" "/Balance Sheet" --prop freeze=B3
officecli set "$FILE" "/Cash Flow" --prop freeze=B3

ステップ2 — 前提条件(青字、主要ドライバーは黄色の塗りつぶし)。 2行目に年次ヘッダー、A列にラベル、B:Eに青字の数値入力を配置します。ドライバー:RevenueGrowth、GrossMargin、OpExRatio、TaxRate、DaysReceivable/Inventory/Payable、CapExRatio、DepreciationYears。B:Eには font.color=0000FF を設定します。シナリオ切り替えに使う3~5個のドライバーを黄色で塗りつぶします(fill=FFFF00)。

3回以上使用するドライバーには名前付き範囲を定義して参照します(StartingARR、TaxRate、OpeningCash、GrowthRate、GrossMargin)。数式には =Assumptions!B4 ではなく =StartingARR、=EBT*Assumptions!B8 ではなく =EBT*TaxRate を使用します。宣言した名前を使用しない場合は、飾りにすぎないものとしてゲート6で却下されます。

ステップ3 — P&Lの行(すべて数式)。 行:Revenue / COGS / Gross Profit / OpEx / EBITDA / D&A / EBIT / Interest / EBT / Tax / Net Income。各行は、Assumptions または前の行のセルを参照する数式にします。以下は売上側のブロック例です。行番号は適宜置き換えてください。この例の行マップ:B3=Revenue, B4=COGS, B5=Gross Profit, B7=OpEx, B9=EBITDA, B10=EBIT, B15=Net Income。レジデントではない状態で、単一のバッチとして送信します。

cat <<'EOF' | officecli batch "$FILE"
[
  {"command":"set","path":"/P&L/B3","props":{"formula":"Assumptions!B5","font.color":"008000"}},
  {"command":"set","path":"/P&L/C3","props":{"formula":"B3*(1+Assumptions!C6)"}},
  {"command":"set","path":"/P&L/D3","props":{"formula":"C3*(1+Assumptions!D6)"}},
  {"command":"set","path":"/P&L/E3","props":{"formula":"D3*(1+Assumptions!E6)"}},
  {"command":"set","path":"/P&L/B4","props":{"formula":"-B3*(1-Assumptions!B7)"}},
  {"command":"set","path":"/P&L/B5","props":{"formula":"B3+B4"}}
]
EOF

Assumptionsの参照先(B5、C6、B7)も仮の行です。より適切な方法は、各ドライバーに名前付き範囲を定義すること(ステップ2)です。そうすれば、行の配置にかかわらず、数式を =StartingRevenue*(1+RevenueGrowth_Y2) のように記述できます。OpEx/D&A/Interest/Tax/NI についても同様に繰り返します。シート間参照を含むすべてのセルに font.color=008000 を設定します。同一シート内のセルは既定で 000000 です。すべてのドル建て行に numFmt='$#,##0;($#,##0);"-"' を設定します。

ステップ4 — Balance Sheetの行(すべて数式)。 資産 = Cash + AR + Inventory + Net PP&E。負債 = AP + Debt。純資産 = OpeningEquity + RetainedEarnings。運転資本の行では日数の前提条件を使用します:AR = Revenue × DaysReceivable / 365。Net PP&E は次のように繰り越します:Beg + CapEx − Depreciation。BS.Cash は独立した調整項目ではありません。ステップ5で設定する 'Cash Flow'!B<ending-cash-row> と必ず一致させます。 利益剰余金 — 各期間で有効な数式です。 BS.RE(t) = BS.RE(t-1) + 'P&L'!NI(t) − Dividends(t)。利益剰余金をハードコードすると、1ドル単位に丸められ、各期間のBSに±$1のずれが生じます(CFOは「モデルが一致していない」と判断します)。Y1の過年度利益剰余金(前期のNIがない場合)は、BSの恒等式を使って有効な数式として計算します:BS!RE_Y1 = TotalAssets − TotalLiabilities − PaidInCapital。Y1のセルには青いフォントと従来形式のコメントを付け、Y2~Y5はNIに基づく計算のままにします。

ステップ 5 — キャッシュフローの行(すべて数式)。 営業活動:NI + D&A − ΔWorkingCapital。投資活動:−CapEx。財務活動:ΔDebt − Dividends。期末現金 = Opening + Operating + Investing + Financing。Y2以降の期首現金 = 前期の期末現金 — 同じシート内で自己参照します:C17 = B19、D17 = C19、E17 = D19。Y1のOpeningCashはAssumptionsの入力値です。

ステップ 6 — 貸借対照表チェックと現金照合の行(納品時の必須チェック)。 この例の行マッピング:Balance Sheet: B10=Total Assets, B15=Total Liab, B17=Total Equity, B18=Balance Check;Cash Flow: B5=BS.Cash (cross-sheet anchor), B19=CF.Ending Cash, B21=CF-BS Cash Recon。レイアウトに合わせて行を置き換えてください。重要なのはチェックのロジックであり、セルのアドレスではありません。

cat <<'EOF' | officecli batch "$FILE"
[
  {"command":"set","path":"/Balance Sheet/B18","props":{"formula":"IF(ABS(B10-B15-B17)<0.01,\"OK\",\"IMBALANCED: \"&ROUND(B10-B15-B17,0))","bold":"true","font.color":"000000"}},
  {"command":"set","path":"/Cash Flow/B21","props":{"formula":"IF(ABS(B19-'Balance Sheet'!B5)<0.01,\"OK\",\"CF != BS CASH: \"&ROUND(B19-'Balance Sheet'!B5,0))","bold":"true"}}
]
EOF

列C/D/Eにも同様に適用します。条件付きで赤い塗りつぶし(fill=FFC7CE)を適用します。type=containsText --prop text=IMBALANCEDまたはtext="CF !="を使用してください。ゲート4はこれらの行を照会し、IMBALANCEDがあれば納品を拒否します。

ステップ 7 — キャッシュの更新と書式設定。 Summaryのすべてのサマリーセル、すべての貸借対照表チェック/照合セル、およびBS/CFのすべてのシート間参照(非常駐、シートごとに1バッチ)を再設定します。列幅(col[A]=28、col[B:E]=15)、すべての金額行のnumberformat='$#,##0;($#,##0);"-"'、セクション見出し行(REVENUE / COGS / ASSETS / LIABILITIES)の見出しの塗りつぶし(fill=1F3864、font.color=FFFFFF、bold=true)を適用します。見出しの塗りつぶしはラベルのセルだけでなく、A:E全体に適用してください(→ xlsx v2 §visual floor)。

ステップ 8 — サマリー/ダッシュボードのKPIとグラフ。 KPIは最低4つ:Revenue 27E、EBITDA Margin 27E、Ending Cash 27E、Net Income CAGR — それぞれ財務諸表のセルを参照する数式とし、緑のフォントを適用します。

取締役会/経営幹部向けに納品するダッシュボードには、グラフを最低3つ含めてください — グラフ1つではドラフト、3つで納品可能な成果物です。マージングラフを追加する前に、Gross Margin/EBITDA Margin/NI Marginの比率行をSummary!A10:E13にあらかじめ入力します(P&Lを参照する数式を使用)。

# (1) Top-line trend (Revenue + EBITDA).
officecli add "$FILE" /Summary --type chart --prop chartType=column --prop dataRange='P&L!A2:E5' --prop title='Revenue & EBITDA' --prop width=14cm --prop height=8cm
# (2) Margin trend (Gross / EBITDA / NI margin).
officecli add "$FILE" /Summary --type chart --prop chartType=line --prop dataRange='Summary!A10:E13' --prop title='Margin trend' --prop width=14cm --prop height=8cm
# (3) Cash trajectory (Ending Cash ± Runway).
officecli add "$FILE" /Summary --type chart --prop chartType=area --prop dataRange='Cash Flow!A19:E19' --prop title='Ending cash' --prop width=14cm --prop height=8cm

検証(以下の3つをすべて実行してください):

# Balance check every period must say OK (range get → cells under .data.results[0].children[])
officecli get "$FILE" "/Balance Sheet/B18:E18" --json | jq '.data.results[0].children[] | .format.cachedValue // .text'
# Cash recon every period must say OK
officecli get "$FILE" "/Cash Flow/B21:E21" --json | jq '.data.results[0].children[] | .format.cachedValue // .text'
# Summary KPIs are plausible numbers, not null
officecli get "$FILE" "/Summary/B2:B5" --json | jq '.data.results[0].children[].format.cachedValue'
レシピ B — DCF 評価

このレシピで作成するもの。 シート:Assumptions、FCF(10年間の予測)、WACC(パネル)、DCF(NPV + TV + 株主価値へのブリッジ)、Sensitivity(2軸グリッド)。出力:Implied Equity Value + Implied Per-Share、および WACC × g の感応度分析。

作成順。 Assumptions → FCF → WACC → DCF → Sensitivity。

ステップ 1 — 主要ドライバーの名前付き範囲。 DCF の読みやすさは名前に左右されます。以下の数式ではすべて、$B$6 ではなく WACC、TaxRate、g を使用します。

cat <<'EOF' | officecli batch "$FILE"
[
  {"command":"add","parent":"/","type":"namedrange","props":{"name":"WACC","ref":"WACC!$B$12"}},
  {"command":"add","parent":"/","type":"namedrange","props":{"name":"TaxRate","ref":"Assumptions!$B$8"}},
  {"command":"add","parent":"/","type":"namedrange","props":{"name":"TerminalGrowth","ref":"Assumptions!$B$15"}},
  {"command":"add","parent":"/","type":"namedrange","props":{"name":"NetDebt","ref":"Assumptions!$B$20"}},
  {"command":"add","parent":"/","type":"namedrange","props":{"name":"SharesOut","ref":"Assumptions!$B$21"}}
]
EOF

ステップ 2 — FCF の作成(10 年間)。 列 B:K = Y1..Y10。行:Revenue(成長率から算出)/EBIT(売上高 × マージン)/EBIT × (1 − TaxRate)(NOPAT)/+ D&A/− CapEx/− ΔNWC/= FCF。Assumptions に基づく比率を使用します(CapEx = Revenue × CapExRatio)。すべてのセルを数式にし、フォント色は黒、numFmt='$#,##0;($#,##0);"-"' にします。

ステップ 3 — WACC パネル。 WACC シートに 8 行のパネルを作成します:Risk-free rate/Equity risk premium/Beta/Cost of equity(=Rf + β×ERP)/Pre-tax debt cost/After-tax debt cost(=×(1−TaxRate))/Equity weight/Debt weight/WACC(=We×Re + Wd×Rd_after_tax)。入力値は青、計算結果の行は黒にします。

ステップ 4 — ターミナルバリュー + NPV + 株主価値へのブリッジ。 行の対応:DCF: B/C 3=TV, 4=PV explicit FCF, 5=PV terminal, 6=EV, 7=Net Debt, 8=Equity Value, 9=Per-Share;FCF: row 2 = periods (1..10), row 11 = FCF, B:K = Y1..Y10。実際の行に置き換えてください。注記列のセルには {"value":"text"} を使用し、{"formula":"..."} は使用しないでください。数式形式の文章は、ファイルを開いたときに #NAME? を引き起こします(レシピ C のステップ 5 の後にあるコールアウトを参照)。DCF シートで以下を実行します。

cat <<'EOF' | officecli batch "$FILE"
[
  {"command":"set","path":"/DCF/B3","props":{"value":"Terminal value (Gordon growth)"}},
  {"command":"set","path":"/DCF/C3","props":{"formula":"FCF!K11*(1+TerminalGrowth)/(WACC-TerminalGrowth)","font.color":"008000","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/DCF/B4","props":{"value":"PV of explicit-period FCF (10 yr)"}},
  {"command":"set","path":"/DCF/C4","props":{"formula":"SUMPRODUCT(FCF!B11:K11/(1+WACC)^FCF!B2:K2)","font.color":"008000","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/DCF/B5","props":{"value":"PV of terminal value"}},
  {"command":"set","path":"/DCF/C5","props":{"formula":"C3/(1+WACC)^10","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/DCF/B6","props":{"value":"Enterprise value"}},
  {"command":"set","path":"/DCF/C6","props":{"formula":"C4+C5","bold":"true","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/DCF/B7","props":{"value":"Less: Net debt"}},
  {"command":"set","path":"/DCF/C7","props":{"formula":"-NetDebt","font.color":"008000","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/DCF/B8","props":{"value":"Equity value"}},
  {"command":"set","path":"/DCF/C8","props":{"formula":"C6+C7","bold":"true","font.color":"000000","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/DCF/B9","props":{"value":"Implied per-share"}},
  {"command":"set","path":"/DCF/C9","props":{"formula":"C8/SharesOut","bold":"true","numberformat":"$0.00"}}
]
EOF

NPV と SUMPRODUCT — どちらもキャッシュが正しく保存されます。 評価エンジンは NPV(rate, cross_sheet_range) を計算し、正しい値をキャッシュします(読み戻して確認してください)。SUMPRODUCT(values/(1+rate)^periods) は代数的に同等です(期間行 FCF!B2:K2 = 1..10 は初回のみ設定)。ここでは、監査時の読みやすさを優先する場合の任意の選択肢として示しています。明示的な割引計算の系列は、レビュー担当者が追跡しやすい場合があります。キャッシュ回避策ではありません。どちらの形式でも問題ありません。不規則な日付の場合も、XNPV(rate, values, dates) は同様にキャッシュされます。同等の SUMPRODUCT 式は SUMPRODUCT(values/(1+rate)^((dates-base_date)/365)) です。

ステップ 5 — 2 軸の感応度グリッド(WACC × g)。 5×5 のグリッドです。行 = WACC の値 7.5% ... 11.5%、列 = g の値 1.5% ... 3.5%。各セルには、グリッドの WACC と g を代入して DCF を再計算する、単独で完結した数式を 1 つ入力します。テンプレート:

# Cell D14 (first data cell, grid anchor at C14 = WACC label, C15 = first WACC value)
# Substitute $D$13 (this cell's g) and $C15 (this cell's WACC) into a replicated EV + equity formula.
cat <<'EOF' | officecli batch "$FILE"
[
  {"command":"set","path":"/Sensitivity/D15","props":{"formula":"(NPV($C15,FCF!$B$11:$K$11)+(FCF!$K$11*(1+D$14)/($C15-D$14))/(1+$C15)^10+(-NetDebt))/SharesOut","numberformat":"$0.00"}}
]
EOF

数式を D15:H19(5×5 のグリッド)にコピーします。行 14 には g の値(青の入力値)を置き、列 C には WACC の値(青の入力値)を置きます。行 13 と列 B にはラベルを置きます。すばやく把握できるよう、3 色のグラデーションによる CF を適用します(緑 = 上振れ、赤 = 下振れ)。

officecli add "$FILE" /Sensitivity --type conditionalformatting \
  --prop type=colorScale --prop ref=D15:H19

Excel のデータテーブルは使用しないでください。 Excel のネイティブな /Data/Table 2 変数テーブルは CLI 経由では安定してサポートされません。各グリッドセルには必ず明示的な数式を入力してください。テンプレートをコピーし、Data Table の入力セルは使用しないでください。

検証。

officecli get "$FILE" "/DCF/C8" --json | jq '.data.results[0].format.cachedValue'   # equity value, plausible $
officecli get "$FILE" "/DCF/C9" --json | jq '.data.results[0].format.cachedValue'   # per-share, in $XX.XX range
officecli get "$FILE" "/Sensitivity/F17" --json | jq '.data.results[0].format.cachedValue'   # grid center cell, plausible

C8 または C9 が null を返すか、#OCLI_NOTEVAL! のセンチネル値を表示する場合は、再設定してください(非常駐)。§Build-order & cache-drift を参照してください。

レシピ C — LBO モデル

このレシピで作成するもの。 シート:Assumptions、S&U(資金調達と資金使途)、Debt(複数トランシェのスケジュール)、P&L(5 年間)、CF、Exit/Returns。出力:MOIC、IRR、および 4 層のリターンウォーターフォール。LBO はストレステストです。循環参照(利息 ↔ 現金)、最も深いシート間の参照チェーン、そして名前付き範囲の多用を想定してください。

作成順。 Assumptions → S&U → P&L → Debt → CF → Exit → Returns。債務の利息はカバレッジチェックで P&L の EBIT に依存するため、Debt の前に P&L を作成します。CF は利息と元本償還を使用するため、CF の前に Debt を作成します。ステップ 5 の前に calc.iterate を有効にしてください。

ステップ 1 — 資金調達と資金使途(残高を一致させ、すべての手数料項目を個別に明記)。

Uses    = Purchase_EV (EntryEBITDA × EntryMultiple) + Transaction_fees (Purchase_EV × TxnFeePct, typ 1.5–2.5%)
        + Financing_fees ((Senior + Mezz) × FinFeePct, typ 1–3%) + Refinanced_debt
Sources = Senior_TLB + Mezz + Revolver_drawn + Sponsor_equity

スポンサー出資額 — どちらか一方を選び、両方は使わないでください。 (a) 指定方式: Sponsor_equity = Assumptions!SponsorEquity とし、Sources = Uses となるようシニア/メザニンを調整します(手数料は負債に吸収させ、暗黙の差額調整は行いません)。(b) 算出方式: Sponsor_equity = Uses − Senior − Mezz − Revolver − Refinanced とし、「スポンサー出資額(算出)」とラベル付けし、Assumptions への直接参照は設けません。ハードコードされた SponsorEquity に加えて =Uses − Senior − Mezz の差額調整を行うと、手数料は必ず暗黙に吸収されます。指定額の $140M に対して差額調整額が $194.67M となり、未計上の手数料が $54.67M 発生するため、CFO は一目で却下します。

# Sources = Uses hard check.
officecli set "$FILE" /S&U/B12 --prop formula='IF(ABS(SUM(B4:B7)-SUM(B9:B11))<1,"BALANCED","S&U IMBALANCE: "&ROUND(SUM(B4:B7)-SUM(B9:B11),0))' --prop bold=true

# Stated-vs-plug consistency (Gate 4 addendum; only run if you chose pattern (a)).
STATED=$(officecli get "$FILE" /Assumptions/B12 --json | jq -r '.data.results[0].format.cachedValue // "null"')
PLUGGED=$(officecli get "$FILE" /S&U/B10 --json | jq -r '.data.results[0].format.cachedValue // "null"')   # B10 = sponsor-equity row on S&U
DELTA=$(python3 -c "print(abs(float('$STATED') - float('$PLUGGED')))" 2>/dev/null || echo 99999)
python3 -c "import sys; sys.exit(0 if float('$DELTA') <= 1 else 1)" && echo "S&U sponsor OK (stated=$STATED plug=$PLUGGED)" || { echo "REJECT Gate 4 S&U: stated $STATED ≠ plug $PLUGGED (Δ=$DELTA) — fees silently absorbed"; exit 1; }

S&U のスポンサー以外のすべての項目は、Assumptions の青色の入力値(対象 EBITDA、エントリーマルチプル、手数料率など)か、導出式にします。Uses / Sources の数値をハードコードしないでください。

ステップ 2 — 負債スケジュール(複数トランシェ)。 トランシェごと、年度ごとに 1 行を設けます。列:BeginningBalance / Mandatory amortization / Cash sweep / EndingBalance / AverageBalance / InterestExpense。シニア TLB:強制償還 1% + 余剰キャッシュ全額をキャッシュスイープに充当します。メザニン:償還 0%、キャッシュ払いの利息のみです。この例の行マップ(シニア TLB トランシェ、2 年目の列 C):C4=Beginning Balance, C5=Mandatory Amort, C6=Ending Balance, C7=Cash Sweep, C8=Average Balance, C9=Interest Expense。CF!C20 = キャッシュスイープに利用できるフリーキャッシュ(CF シートの 2 年目の期末現金、スイープ前)。レイアウトに応じて、使用するトランシェの行ブロックを置き換えてください。

# year 2 senior TLB
cat <<'EOF' | officecli batch "$FILE"
[
  {"command":"set","path":"/Debt/C4","props":{"formula":"B6"}},
  {"command":"set","path":"/Debt/C5","props":{"formula":"-C4*Assumptions!$B$30","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/Debt/C6","props":{"formula":"C4+C5+C7","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/Debt/C7","props":{"formula":"-MIN(-CF!C20,C4+C5)"}},
  {"command":"set","path":"/Debt/C8","props":{"formula":"(C4+C6)/2","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/Debt/C9","props":{"formula":"-C8*Assumptions!$B$31","numberformat":"$#,##0;($#,##0);\"-\""}}
]
EOF
# Add the sweep-rule comment as a classic comment (comment is NOT a cell prop — separate --type comment).
officecli add "$FILE" /Debt --type comment --prop ref=C7 --prop text='cash sweep capped at available cash and remaining tranche balance'

リボルバーの上限。 取引にリボルバー・トランシェを使う場合、各期間のリボルバー残高はコミットメント上限以下に制限します。

Revolver_Balance = MIN(Assumptions!RevolverCapacity, MAX(0, prior_revolver + draw − paydown))

外側の MIN(capacity, ...) がないと、資金不足の四半期に融資枠を超過しても、気付かないままになります。

行番号はレイアウトに合わせて調整してください。各トランシェ(シニア/メザニン/リボルバー)および各年度について繰り返します。

ステップ 3 — 損益計算書(5 年間)+負債からの利息。 損益計算書の利息行は、Debt から参照します:Interest = 'Debt'!TotalInterestRowY<N>。これにより循環参照が発生します:利息 → 純利益 → CF → キャッシュスイープ → 負債残高 → 利息。

書き込み順序に関する警告。 calc.iterate=true が制御するのは 再計算 であり、書き込みフェーズではありません。すでに循環参照が含まれているファイルに、シート間の循環参照を閉じる式を追加すると、iterate の設定にかかわらず、エンジンが CPU を 100% 使用したままデッドロックします。複雑な循環参照(複数トランシェの LBO、リボルバー + TLB + メザニン)では、後述の「書き込み順序の修正」を使ってください(循環を解除 → 下流を書き込み → 再び循環を設定)。循環参照の式を書き込む前に calc.iterate=true を有効にします。

officecli set "$FILE" / --prop calc.iterate=true --prop calc.iterateCount=100 --prop calc.iterateDelta=0.001

iterate は、自然に減衰するループ(利息の増加 → キャッシュの減少 → スイープ額の減少 → 残高の増加、EBIT による上限あり)について、逐次近似で収束させます。#REF! または発散する値が表示された場合は、一旦停止してください。代数式を修正し、iterateCount を 1000 に引き上げないでください。

ステップ 4 — CF + キャッシュスイープ。 期末現金 = 期首現金 + CFO − CapEx − 強制償還 − キャッシュスイープ。キャッシュスイープ = MIN(freeCashAfterCapEx, seniorDebtBalance + seniorMandatoryAmort)。MIN の上限により、スイープ後の現金がマイナスになるのを防ぎます。

ステップ 5 — エグジット + リターン。 行マップ:Exit: B3=Exit EV, B4=Less: remaining debt, B5=Exit equity to sponsor;Returns: B3=MOIC, B4=IRR。

# Values/formulas — single non-resident batch.
cat <<'EOF' | officecli batch "$FILE"
[
  {"command":"set","path":"/Exit/B3","props":{"formula":"'P&L'!F8*Assumptions!$B$25","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/Exit/B4","props":{"formula":"-('Debt'!F6+'Debt'!F13)","font.color":"008000","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/Exit/B5","props":{"formula":"B3+B4","bold":"true","numberformat":"$#,##0;($#,##0);\"-\""}},
  {"command":"set","path":"/Returns/B3","props":{"formula":"'Exit'!B5/('S&U'!B9)","numberformat":"0.00\"x\""}},
  {"command":"set","path":"/Returns/B4","props":{"formula":"IRR({-'S&U'!B9,0,0,0,0,'Exit'!B5})","numberformat":"0.0%"}}
]
EOF
# Classic comments — one --type comment per anchor cell.
officecli add "$FILE" /Exit --type comment --prop ref=B3 --prop text='Exit EV = Y5 EBITDA × exit multiple'
officecli add "$FILE" /Returns --type comment --prop ref=B3 --prop text='MOIC = exit equity / sponsor equity'
officecli add "$FILE" /Returns --type comment --prop ref=B4 --prop text='IRR — 5-yr, entry + exit only; use XIRR for mid-year dividends'

補足 — ラベル:comment 要素、Notes 列、formula(それぞれ異なる仕組みです)。

  • ホバー時のツールチップ → officecli add ... --type comment --prop ref=<cell> --prop text='...'。comment キーは set cell で有効な prop ではありません(officecli help xlsx cell に記載されていません)。set cell の props 辞書内に含めると、通知なく破棄されます。専用の要素を使ってください。
  • 隣接する Notes 列に表示するテキスト → {"command":"set","path":"/DCF/D3","props":{"value":"TV = FCF × (1+g) / (WACC−g)"}} — formula ではなく value を使い、引用符で囲んだプレーンテキストを指定します。
  • 実際の数式として記述する数式風の説明文 → 絶対に使用しないでください。{"formula":"FCF10*(1+g)/(WACC-g)"} は Excel で #NAME? を返します(FCF10、g、WACC はそのセルのコンテキストで未バインドの識別子です)。

期中配当または部分エグジットには、IRR ではなく XIRR({cashflows}, {dates}) を使用してください。 ステップ 6 — リターンのウォーターフォール(任意、LP/GP の4段階)。 段階:(1)LP の優先リターン 8%、(2)GP のキャッチアップ 20%まで、(3)ハードル超過分を 80/20 で分配、(4)損失時は 100%を LP に分配します。各段階は MAX(0, MIN(...)) でクランプします。一般的なグリッドパターンについては、§Sensitivity & scenarios を参照してください。

検証。

officecli get "$FILE" /S&U/B12 --json | jq '.data.results[0].format.cachedValue // .data.results[0].text'   # must say BALANCED
officecli get "$FILE" /Returns/B3 --json | jq '.data.results[0].format.cachedValue'                # MOIC, expect 2.0x-4.0x typical
officecli get "$FILE" /Returns/B4 --json | jq '.data.results[0].format.cachedValue'                # IRR, expect 0.15-0.30 typical
# Iterate converged?
officecli query "$FILE" 'cell:contains("#REF!")' --json | jq '.data.results | length'   # must be 0

感度分析とシナリオ

3つのパターンから1つを選択します:

  • (a) Assumptions の Base/Upside/Downside 列 — シナリオを横並びにし、ドロップダウンを使わずに「Active」列と INDEX/MATCH で切り替えます。
  • (b) ドロップダウン + INDEX/MATCH による切り替え — Summary の検証用ドロップダウン1つで、すべてのドライバーを INDEX(Base:Downside, MATCH(Dropdown, ScenLabels, 0)) 経由で制御します。
  • (c) 2軸感度分析グリッド — 5×5 または 7×7 のグリッドを使い、各セルに自己完結型の数式を1つ配置します。行と列のヘッダーが2つのドライバーになります。WACC × g については、レシピ B のステップ 5 を参照してください。

(a) と (b) を組み合わせると、ドロップダウンで選択したシナリオが Active 列によって上書きされ、入力が循環します。どちらか1つを選択してください。

グリッドのルール: 各セルでは、出力数式の自己完結型のコピーに、行のドライバーと列のドライバーを代入します。WACC という名前付き範囲は参照できません(これはパネルです)。グリッドの軸セルを参照してください。

ドロップダウンによるシナリオ切り替え。 Summary の validation ドロップダウン1つで、すべての Assumptions 行を制御します。

cat <<'EOF' | officecli batch "$FILE"
[
  {"command":"add","parent":"/Summary","type":"validation","props":{"sqref":"B1","type":"list","formula1":"Base,Upside,Downside"}},
  {"command":"set","path":"/Assumptions/B5","props":{"formula":"INDEX(C5:E5,MATCH(Summary!$B$1,$C$4:$E$4,0))"}}
]
EOF
# If you want a hover tooltip on B5, add it separately:
officecli add "$FILE" /Assumptions --type comment --prop ref=B5 --prop text='Revenue growth — picked by Summary!B1 scenario dropdown'

Assumptions のドライバー行には、すべて同じ INDEX/MATCH を設定します。C:E の Base/Upside/Downside 列は青色のままにします(シナリオ入力をハードコード)。

フットボールフィールドチャートのパターン(DCF 評価サマリー)。 3〜5種類の評価手法(DCF base、DCF bear、Trading comps、Precedent txns、LBO floor)を縦に並べ、横方向に Low→High のバーを表示します。Football シートでは、A列 = 手法ラベル、B列 = Low $、C列 = High $、D列 = =C−B(幅)とします。B列を非表示の第1系列(白/塗りつぶしなし)、D列を表示系列として、積み上げ横棒グラフを作成します。dataRange=Football!A3:D7、chartType=bar を指定します。Excel では各手法のバーが浮動バーとして表示されます。

財務関数のパターン

簡潔なリファレンスです。財務の教科書ではありません。以下の関数の用途がわからない場合は、いったん停止してユーザーに確認してください。

関数こちらを優先する対象理由
XNPV(rate, values, dates)NPVキャッシュフローの日付が不規則な場合(M&A のクロージングが年度途中、トランシェの実行が段階的など)
XIRR(values, dates)IRR日付が不規則な場合に対応し、符号の複数回の変化もより適切に処理します
INDEX(range, MATCH(lookup, key, 0))VLOOKUP列の挿入に強い(ソース範囲に列を挿入すると VLOOKUP は機能しなくなります)
IFERROR(x/y, 0) または IF(y=0, 0, x/y)そのままの除算財務モデルの / はすべて保護してください。#DIV/0! を含む状態で納品することは、納品失敗を意味します
MIRR(values, financeRate, reinvestRate)符号が反転する場合の IRRキャッシュフローのパターンで符号が2回以上変化する場合に使用します
SUMIFS(sumRange, criteriaRange1, criterion1, ...)SUMPRODUCT((...)) 配列条件付き合計の意図がより明確です。どちらも正しく評価されます

評価機能の対応状況 — 先回りしてハードコードせず、検証してください。 CLI 評価機能は、このスキルで使用する財務関数 — NPV/XNPV/IRR/XIRR、配列リテラル数式(IRR({...}))、および SUMPRODUCT(1/COUNTIF(range,range)) による個別の値のカウント — を計算し、正しい値を evaluated:true とともにキャッシュします。NPV→0 に書き換える必要も、個別の値をカウントする際の 1/N の落とし穴もありません。正しい手順は、意図した数式を作成し、読み戻しでキャッシュ値を検証することです(get ... --json | jq '.data.results[0].format.cachedValue')。特定のセルが実際に #OCLI_NOTEVAL! センチネルを返す場合(入力より先に数式が書き込まれた場合、または未対応の関数の場合)に限り、代替手段を使ってください。まず close の後に非常駐として再設定します。それでも評価されない場合は、計算済みの値を青色のフォントでハードコードし、officecli add "$FILE" /Sheet --type comment --prop ref=<cell> --prop text='cached valuation; refreshes on open in Excel — do not edit' で標準形式のコメントを追加し、納品メモにその旨を記載してください。

循環参照と反復計算

循環性が代数的に正当化される場合にのみ、calc.iterateを有効にしてください: 利息 ↔ 現金(LBOのリボルバー/キャッシュスイープ)、税額控除 ↔ NI(まれです。ほとんどの3ステートメントモデルでは税引前に利息を計算して回避します)、リボルバーのプラグ ↔ 期末現金(最低現金残高を設定する企業のキャッシュウォーターフォール)。

officecli set "$FILE" / --prop calc.iterate=true --prop calc.iterateCount=100 --prop calc.iterateDelta=0.001

iterateCount=100 / iterateDelta=0.001はExcelのデフォルト値で、自然に減衰するループには問題ありません。

書き込み順序の調整(循環を解消 → 下流を書き込み → 再び循環を閉じる)

calc.iterateが制御するのは再計算であり、書き込みフェーズではありません。すでに接続されているシート間の循環(Debt.Interest ↔ CF.Cash ↔ Debt.CashSweep)を閉じる最後の部分を書き込むと、CPU使用率が100%のままデッドロックします。収束していない循環があると、view html / getもハングします。

3ステップの手順:

  1. 循環を解消する — Debtを書き込む際、循環に関わる10~20個のセルをリテラルの0にします(例:C7=0。=-MIN(...)ではありません)。これで循環が解消されます。
  2. 下流を書き込む — 循環しないチェーン(P&L、CF、Exit、Returns、Summary、grid)をすべて非residentで構築します。シートごとにheredocを1つ使います。すべてゼロ化したセルを基にキャッシュされます。
  3. 再び循環を閉じる — すべてのresidentを閉じ、各循環セルを実際の数式に戻します。各セルに対して個別にsetを実行し、非residentにします。

合格条件。 get /Debt/C7 --json | jq '.data.results[0].format.cachedValue'が、nullではないゼロ以外の値を返すこと。セルがまだデッドロックする場合は、=0のままにして、従来型のコメント"circular; recalculates in Excel on F9"を付け、納品時にその旨を明記してください。iterateCount=1000でごまかしてはいけません。

#REF! / 発散値へのその場しのぎとしてiterateを使わないでください。 iterateCountを1000に増やすとバグが隠れ、もっともらしい誤った値を納品することになります。validateでも検出できません。ループは代数的に解消してください(例:平均残高ではなく期首残高に対する利息を使う)。

収束を検証する。 ループセルを読み取り、入力となる前提を変更して元に戻し、再度読み取ります。値が一致しなければなりません:

V1=$(officecli get "$FILE" /Debt/C9 --json | jq '.data.results[0].format.cachedValue')
officecli set "$FILE" /Assumptions/B31 --prop value=0.085
officecli set "$FILE" /Assumptions/B31 --prop value=0.0845
V2=$(officecli get "$FILE" /Debt/C9 --json | jq '.data.results[0].format.cachedValue')
[ "$V1" = "$V2" ] && echo "Iterate converged" || echo "WARN: drift V1=$V1 V2=$V2 — tighten iterateDelta or check algebra"

監査と納品ゲート

問題があることを前提にしてください。 最初の構築が正しいことはほとんどありません。以下のゲートをすべて実行し、各チェックで成功行が出力されることを確認してください。validateに合格しても納品できるとは限りません。スキーマに合格していても、モデルが10倍ずれている場合があります。

ゲート1~3 — xlsx v2からそのまま継承

→ xlsx v2 §QA minimum cycleを参照してください(ゲート1~3ではview issues、エラーセルのクエリ、クローズ後のvalidateを確認します)。まず、xlsx v2に記載されたとおりに実行してください。財務モデル固有の変更は不要です。

ゲート4 — 財務諸表の整合性(3ステートメントとLBO)

Recipe A / Cで作成した貸借一致チェック行と現金照合行が、すべての期間でOK / BALANCEDを示す必要があります。チェック行をqueryし、IMBALANCED / CF !=が1つでもあれば作業を中止してください:

BS_FAIL=$(officecli query "$FILE" 'cell:contains("IMBALANCED")' --json | jq '.data.results | length')
CF_FAIL=$(officecli query "$FILE" 'cell:contains("CF !=")' --json | jq '.data.results | length')
SU_FAIL=$(officecli query "$FILE" 'cell:contains("S&U IMBALANCE")' --json | jq '.data.results | length')
if [ "$BS_FAIL" -eq 0 ] && [ "$CF_FAIL" -eq 0 ] && [ "$SU_FAIL" -eq 0 ]; then
  echo "Gate 4 OK (balance + recon + S&U all pass)"
else
  echo "REJECT Gate 4: BS=$BS_FAIL CF=$CF_FAIL S&U=$SU_FAIL"; exit 1
fi

1つでも失敗した場合、モデルは気づかないまま誤っています。納品前に上流のチェーンを修正してください。最も多い原因は、シート間の数式が\!として保存されていること(シェルによる破損)です。officecli query "$FILE" 'cell:contains("\\\\!")'を実行し、バッチheredocで再入力してください。

ゲート5 — バリュエーションセルのキャッシュ値の妥当性

NPV / IRR / XIRR / equity-bridge / MOIC / summary KPIのセルが未評価のまま納品されると(通常、入力値より先に数式を書き込んだために#OCLI_NOTEVAL!センチネルが表示されます)、ファイルを開いたときに再計算しない読者には空欄または誤った数値が表示されます。バリュエーションセルをすべて列挙し、キャッシュ値があることを確認してください:

# Customize the path list per recipe — this is the DCF example
for P in "/DCF/C4" "/DCF/C5" "/DCF/C6" "/DCF/C8" "/DCF/C9"; do
  V=$(officecli get "$FILE" "$P" --json | jq -r '.data.results[0].format.cachedValue // "null"')
  if [ "$V" = "null" ] || [ "${V#\#OCLI_NOTEVAL}" != "$V" ]; then
    echo "REJECT Gate 5: $P unevaluated (cached=$V) — re-set after close (see §Build-order & cache-drift)"; exit 1
  fi
  echo "Gate 5 $P: cached=$V OK"
done

LBOの場合は、リストに/Exit/B5、/Returns/B3、/Returns/B4を追加してください。3ステートメントの場合は、/Summary/B2:B5も追加してください。

ゲート6 — ハードコードとゾーンの規律

すべてのCalcシートで、数値のハードコードがゼロであること。実行コマンド:

# `cell:not(:has(formula))` selects the literal cells (and `cell:has(formula)` the formula cells).
HARDCODE=$(officecli query "$FILE" 'cell[type=Number]' --json \
  | jq '[.data.results[] | select(.format.formula == null) | select(.path | test("/(P&L|Balance Sheet|Cash Flow|DCF|Debt|FCF|WACC|Exit|Returns)/"))] | length')
[ "$HARDCODE" -eq 0 ] && echo "Gate 6 OK (no hardcodes on Calc sheets)" || { echo "REJECT Gate 6: $HARDCODE hardcoded numeric cells on Calc zone — move to Assumptions"; exit 1; }

# Named-range coverage + dead-decoration audit: ≥3 ranges declared AND each referenced by ≥1 formula.
NR=$(officecli query "$FILE" namedrange --json | jq '.data.results | length')
[ "$NR" -ge 3 ] && echo "Gate 6 OK ($NR named ranges)" || echo "WARN Gate 6: only $NR named ranges"
DEAD=0
for NR_NAME in $(officecli query "$FILE" namedrange --json | jq -r '.data.results[].format.name'); do
  # Match the formula SOURCE (`formula~=`), not the cached/displayed RESULT — `:contains` would scan
  # the computed value and report every name as dead (false reject).
  USES=$(officecli query "$FILE" "cell[formula~=$NR_NAME]" --json | jq '.data.results | length')
  [ "$USES" -ge 1 ] && echo "  $NR_NAME: $USES uses OK" || { echo "  WARN: $NR_NAME unused"; DEAD=$((DEAD+1)); }
done
[ "$DEAD" -eq 0 ] && echo "Gate 6 named-range audit OK" || { echo "REJECT Gate 6: $DEAD dead-decoration name(s)"; exit 1; }
ゲート 5b — HTML プレビューによる目視監査(必須)

ゲート 1~4/6 は grep による防御です。レンダリングされたシートを確認できません。officecli view "$FILE" html を実行し、返された HTML を読み取ってください。各シートをすべて確認します(xlsx v2 のビジュアル基準を継承します)。

  • 数値セルに ### がないこと(列幅を広げます)。
  • ラベルやセクション見出しが途中で切れていないこと(列幅を広げるか、alignment.wrapText=true を設定します)。
  • プレースホルダートークン(TBD、{var}、xxxx)がないこと。下記のゲート 6.1 の grep を参照してください。
  • 残高チェック/照合行で、各期間の列に OK/BALANCED と表示されていること。
  • ダッシュボードのグラフが表示され、ARR/収益の線の y 軸が 0 で、参照元データが財務諸表シートと一致していること。
  • 感度分析グリッドの色が緑(上振れ)から赤(下振れ)に変化していること(カラースケールの条件付き書式が適用済みであること)。
  • サマリー KPI に古いキャッシュ値 0 が残っていないこと。残っている場合は、キャッシュ更新のパスを実行します。

不具合があれば却下してください。人によるプレビュー: officecli watch "$FILE" を実行するか、Excel/WPS/Numbers で開いてください。最終的な色とグラフの表示品質を完全に確認できるのは、対象のビューアーだけです。

ゲート 6.1 — トークン/プレースホルダーの一括チェック
LEAK=$(officecli view "$FILE" text | grep -niE 'TBD|\(fill in\)|xxxx|lorem|\{\{|placeholder|coming soon')
[ -z "$LEAK" ] && echo "Gate 6.1 OK (no placeholder tokens)" || { echo "REJECT Gate 6.1:"; echo "$LEAK"; exit 1; }
正直な限界

validate で検出できるのはスキーマエラーであり、財務上のエラーではありません。BS.Cash をハードコードして貸借を一致させたモデル、NPV のキャッシュ値が 0 のモデル、FCF の作成前に生成されたため全値がゼロの感度分析グリッド、参照を引用符で囲まないまま P&L という名前のシートで実行時に #NAME? が発生するモデルでも、validate を通過します。スキーマレベルの validate ではこうした問題を検出できないため、ゲート 4/5/6/5b が設けられています。

既知の問題と落とし穴

→ 基本的な落とし穴(シートをまたぐ ! の罠、バッチ JSON のドット付き名前のルール、レンダラーの注意点)については、xlsx v2 §既知の問題と落とし穴を参照してください。すべて当てはまります。

財務モデル固有の注意点:

  • 売上原価の符号と買掛金。 損益計算書で売上原価がマイナスとして記録されている場合、買掛金の数式では符号を反転する必要があります — =-COGS*DaysPayable/365。符号が誤っていると、NWC が過大になり、キャッシュフローの方向が逆になります。エラーは表示されず、validate も通過します。
  • query / validate では #NAME? を検出できません。 シート名に特殊文字 & が含まれているため、シート名を引用符で囲まずに P&L!B3 を参照する別シート数式は、実行時に #NAME? になります。シート名に &、スペース、(、) などが含まれる場合は、必ずシート名を単一引用符で囲み、シート間参照を 'P&L'!B3 のように記述してください。検出できるのは Gate 5b の目視確認だけです。
  • 反復計算が収束しなくても通知されません。 calc.iterate=true iterateCount=100 は、上限に達した時点の値に収束します — 真の答えがその 2 倍であっても同様です。必ず収束を検証してください(§循環参照)。複雑な LBO の循環(複数トランシェの負債+余剰資金の返済+タックスシールド)は収束しない場合があります。循環セルの cachedValue=0 の場合は、§書き込み順序の修正を使用してください。
  • 常駐状態で循環参照を書き込むと、バッチ処理がデッドロックします。 常駐プロセスを開いたまま batch でシートをまたぐ循環参照の最後のリンクを書き込むと、CPU 使用率 100% でデッドロックします。循環セルへの単一の set でもハングする場合があります。対処法:常駐プロセスを終了し、§書き込み順序の修正に従って、循環参照を 2 回に分けて書き込みます。安全なのは、常駐プロセスを使わない単一の heredoc 形式だけです。
  • view html ではシート間のキャッシュ値が古くなります。 上流と同じ一連の処理内で下流を書き込むと、キャッシュ値は 0 になります。Excel はファイルを開いたときに解決しますが、HTML プレビューでは解決しません。チェーンの後、常駐プロセスを使わずに、下流の各項目を再設定してください(§構築順序とキャッシュのずれ)。
  • NPV() / XNPV() は正しく評価され、キャッシュされます。 評価器は(同一シート内とシート間の両方で)どちらも計算します。書き換えは不要です。SUMPRODUCT(values/(1+rate)^periods) は、監査時の読みやすさを高める任意の代替手段であり、キャッシュ回避策ではありません。
  • 感度分析グリッドでは、引き続き構築順序が重要です。 FCF / WACC の入力値が存在する前にグリッドセルを書き込むと、空の入力値で評価され、誤った値または空白値がキャッシュされる場合があります。まず FCF、WACC、DCF を構築し、その後、常駐プロセスを使わない別のバッチでグリッドを構築して、検証してください(jq '.data.results[0].format.cachedValue')。これは順序を守るためのルールであり、評価器の制限ではありません。
  • BS.Cash は常に CF の期末現金残高です(Y1 も同様:BS.Cash = 'Cash Flow'!B19)。独立した調整項目や Assumptions 参照にはしないでください — BS.Cash を調整項目として使うと、貸借対照表の不整合が隠れてしまいます。
  • Y2 以降の Opening Cash は、前期の Ending Cash です(C17=B19、D17=C19)。Y2 以降の期首現金を独立して入力すると、貸借対照表とのずれが通知なく生じます。
  • ウォーターフォールチャートの「合計」バー。 chartType=waterfall では、プログラムから合計を指定できません。colors= の慣例(暗色=合計、中間色=正、赤=負)を使用してください。help xlsx chart を参照してください。
  • SharesOut が数式の場合の DCF の 1 株当たり価値。 =BasicShares + OptionPool × ExerciseAssumption → 青字の前提セルを追加し、SharesOut の名前付き範囲は生の入力値ではなく、計算済みセルを参照するようにしてください。

ヘルプの参照先

迷ったときは、officecli help xlsx [element] [--json] を使用してください。ヘルプが正式なスキーマであり、このスキルガイドは財務モデル作成における差分の判断基準です。

コメント