以下情境为教学假设,人物与数字不代表经核实的真实案例。
5.1 和 5.2 算出来的都是企业价值:3.2× ARR = $768,768,或者 DCF 的 $837,005。企业价值是「这门生意值多少」,不是「卖方到手多少」。从企业价值到股权价值,中间隔着一串调整项:现金、债务类负债、营运资金、一次性费用和资本开支欠账。同一笔交易,调整项的定义不同,最终价格可以差出几万美元。
LedgerLite 的案例给了三个关键数字:现金 $95,000、应收 $12,000、递延收入 $22,000;营运资金目标是 $15,000,实际是 $12,000,调整 −$3,000。这一节用这三个数字把桥搭出来,再讨论另外两类调整:一次性费用加回和资本开支欠账。
从企业价值到股权价值:一张桥
先看公式:
股权价值 = 企业价值 + 现金 − 债务类负债 ± 营运资金调整
营运资金调整 = 实际营运资金 − 目标营运资金
LedgerLite 的桥如下。企业价值取 3.2× ARR = $768,768;现金 $95,000 归买方;递延收入 $22,000 是尚未履行的服务义务,按债务类负债扣除;营运资金目标 $15,000、实际应收 $12,000,短少 $3,000,下调价格。
| 项 | 金额 | 说明 |
|---|---|---|
| 企业价值 | $768,768 | 3.2× ARR |
| 加:现金 | +$95,000 | 买方接手后的可用现金 |
| 减:递延收入 | −$22,000 | 已收钱但尚未履约 |
| 营运资金调整 | −$3,000 | 目标 $15,000,实际 $12,000 |
| 股权价值 | $838,768 | 768,768 + 95,000 − 22,000 − 3,000 |
用净债务的口径复算:净债务 = 债务类负债 − 现金 = 22,000 − 95,000 = −$73,000,也就是净现金 $73,000;股权价值 = 企业价值 − 净债务 + 营运资金调整 = 768,768 + 73,000 − 3,000 = $838,768。两种写法结果相同,但第一种更容易逐项核对,第二种更容易和买方的净债务表对齐。5.2 的 DCF 给出的也是企业价值;同一个桥可以套在 DCF 的 $837,005 上,起点变高,加减项不变。本节用倍数锚 $768,768 演示,是因为它和案例的交易结构直接对应。
这里最容易出错的是「现金」和「递延收入」的方向。现金是资产,加;递延收入是负债,减。如果只加现金不扣递延收入,会高估 $22,000;如果只扣递延收入不加现金,会低估 $95,000。两个错误方向相反,但都会让谈判在一个错误的锚上开始。
三种口径,三个价格
「股权价值」不是唯一的口径。资产收购和股权收购对现金、负债的归属不同,同一组数字会得到不同价格。下面三种口径都用同一个企业价值 $768,768、同一笔营运资金调整 −$3,000:
| 口径 | 公式 | 结果 | 与主口径的差 |
|---|---|---|---|
| 含现金,只扣递延收入 | 768,768 + 95,000 − 22,000 − 3,000 | $838,768 | $0 |
| 含现金,再扣应付 | 768,768 + 95,000 − 22,000 − 8,000 − 3,000 | $830,768 | −$8,000 |
| 不含现金(资产收购常见) | 768,768 − 22,000 − 3,000 | $743,768 | −$95,000 |
应付账款 $8,000 是否进入调整,取决于合同怎么写。如果买方承接应付,它应该像递延收入一样被扣除;如果卖方在交割前付清,它就不进入价格。案例的简化口径只列了现金、应收和递延收入,所以主口径是 $838,768;把应付也扣掉,得到 $830,768。两种都不是错,错的是没有在合同里写清楚用哪一种。
现金是否留下,影响更大。资产收购中,买方可能只买代码、客户合同和商标,不买公司账户里的现金;这时价格里不加 $95,000,股权价值变成 $743,768。股权收购中,买方买的是整个主体,现金通常留在公司里,所以加 $95,000。案例的结构是资产收购,但交易双方仍可以约定现金归属;$95,000 的差额必须在意向书阶段就说清楚。
递延收入还有一个重复计算的陷阱。可以把它当债务类负债单独扣,也可以把它放进营运资金一起算,但不能两边都扣。两种正确的算法得到同一个 $838,768:
算法 A:768,768 + 95,000 − 22,000 − 3,000 = 838,768
算法 B:768,768 + 95,000 + (12,000 − 22,000 − 15,000) = 838,768
算法 B 把实际营运资金定义为「应收 − 递延收入 = −$10,000」,目标仍是 $15,000,调整是 −$25,000。两种算法的调整项不同,但合计一样。如果既单独扣 $22,000,又在营运资金里扣一次,结果会变成 $816,768,凭空少掉 $22,000。
营运资金正常化
营运资金调整的目的,是让买方接手时拿到一个「正常水平」的营运资金,而不是拿到一个被交割前操作过的数字。LedgerLite 的目标是 $15,000,实际应收是 $12,000,短少 $3,000,所以价格下调 $3,000。
目标 $15,000 不是去年实际值的复制,而是双方对「正常经营需要多少营运资金」的约定。LedgerLite 的平均账期是 Net 15,年末应收 $12,000 约等于 18 天收入;如果买方要求 20 天左右的缓冲,目标就会高于 $12,000。反过来,如果卖方在交割前加速收款,实际应收可能低于 $12,000,调整会更大。
| 实际营运资金 | 目标营运资金 | 调整 | 对价格的影响 |
|---|---|---|---|
| $12,000 | $15,000 | −$3,000 | 下调 |
| $15,000 | $15,000 | $0 | 不变 |
| 高于目标 | $15,000 | 正数 | 仅在合同约定买方支付盈余时上调 |
第三行没有写具体金额,因为盈余是否支付取决于合同。很多交易只向下调整,不向上调整:实际低于目标,卖方补;实际高于目标,多出来的部分留給买方作为缓冲。这不是数学问题,是谈判条款。
营运资金调整还会和交易结构叠加。LedgerLite 的结构是现金 70% + earn-out 30%,另有 10% 托管;如果 −$3,000 从 headline 里扣,现金部分少 $2,100,earn-out 少 $900,托管也按比例少 $300。调整金额不大,但它会沿着结构传导,所以谈判时要把调整放在 headline 之前还是之后说清楚。结构条款见 7.2 现金、票据与 earn-out 。
一次性费用加回与资本开支欠账
第三类调整是利润质量。SDE 已经把创始人薪酬 $60,000 加回,因为买方接手后要自己决定给管理者开多少工资;除此之外,任何一次性费用加回都必须有凭证。一次性的法律费、搬迁费、旧系统迁移费,如果确实不会再发生,可以从运营费用中加回;如果只是卖方想把价格抬高,买方会在尽调中把它删掉。
加回对价格的影响,取决于交易用哪个基数。在 SDE 倍数交易里,每加回 $1,价格就按倍数增加;在 ARR 倍数交易里,加回不直接乘倍数,它改变买方对 SDE 质量的判断,从而影响倍数是 3.2× 还是 3.0×。LedgerLite 的价格锚是 ARR,所以一次性费用加回不会直接改变 $768,768;它影响的是买方愿不愿意接受 3.2×。
资本开支欠账是另一类。案例的年度投资是 $3,000,固定资产也是 $3,000;如果这 $3,000 正好覆盖维持性资本开支,欠账为零。如果买方认为维持性资本开支应该是 $3,000,而过去一年实际投入是 $0,欠账就是 $3,000,价格要相应下调。资本开支欠账和营运资金短少都会减少价格,但原因不同:前者是长期资产需要补投入,后者是短期周转需要补现金。
把调整项写成代码
下面的 adjustments.ts 把三类调整写成四个函数。bridgeToEquity 做企业价值到股权价值的桥;workingCapitalAdjustment 单独算实际减目标;applyAddBacks 只接受带 verified: true 的加回,未验证的加回会被列出来但不会进入调整后利润;capexArrears 只在实际资本开支低于维持性资本开支时产生欠账,过度投资不会变成价格抵扣。
// file: src/capital/adjustments.ts
// tier: L1
// verify: node --test test/capital/adjustments.test.ts
import { type Cents } from "../core/money.ts";
import { type Result, fail, ok } from "../core/result.ts";
export type BridgeInput = {
enterpriseValueCents: Cents;
cashCents: Cents;
debtCents: Cents;
workingCapitalActualCents: Cents;
workingCapitalTargetCents: Cents;
};
export type BridgeResult = {
enterpriseValueCents: Cents;
cashCents: Cents;
debtCents: Cents;
netDebtCents: Cents;
workingCapitalAdjustmentCents: Cents;
equityValueCents: Cents;
negativeEquity: boolean;
};
export type AddBack = {
label: string;
amountCents: Cents;
verified: boolean;
};
export type AddBackResult = {
startingCents: Cents;
acceptedCents: Cents;
rejectedCents: Cents;
adjustedCents: Cents;
acceptedLabels: string[];
rejectedLabels: string[];
};
export type CapexArrears = {
maintenanceCents: Cents;
actualCents: Cents;
arrearsCents: Cents;
overInvestedCents: Cents;
};
function checkNonNegative(value: Cents, label: string): string | null {
if (!Number.isInteger(value) || value < 0) {
return `${label} must be a non-negative integer amount in cents`;
}
return null;
}
/**
* Working capital adjustment = actual minus target. A shortfall produces a
* negative adjustment and reduces the price; a surplus produces a positive
* adjustment only if the contract says the buyer pays for it.
*/
export function workingCapitalAdjustment(
actualCents: Cents,
targetCents: Cents,
): Result<Cents> {
const actualError = checkNonNegative(actualCents, "actual working capital");
if (actualError) {
return fail(actualError);
}
const targetError = checkNonNegative(targetCents, "target working capital");
if (targetError) {
return fail(targetError);
}
return ok(actualCents - targetCents);
}
/**
* Equity value bridge: start from enterprise value, add cash, subtract
* debt-like liabilities, then apply the working capital adjustment. Cash and
* debt must be defined before signing; a dollar counted in both places moves
* the price twice.
*/
export function bridgeToEquity(
input: BridgeInput,
): Result<BridgeResult> {
if (
!Number.isInteger(input.enterpriseValueCents) ||
input.enterpriseValueCents <= 0
) {
return fail("enterprise value must be a positive integer amount in cents");
}
const cashError = checkNonNegative(input.cashCents, "cash");
if (cashError) {
return fail(cashError);
}
const debtError = checkNonNegative(input.debtCents, "debt");
if (debtError) {
return fail(debtError);
}
const adjustment = workingCapitalAdjustment(
input.workingCapitalActualCents,
input.workingCapitalTargetCents,
);
if (!adjustment.ok) {
return adjustment;
}
const netDebtCents = input.debtCents - input.cashCents;
const equityValueCents =
input.enterpriseValueCents - netDebtCents + adjustment.value;
return ok({
enterpriseValueCents: input.enterpriseValueCents,
cashCents: input.cashCents,
debtCents: input.debtCents,
netDebtCents,
workingCapitalAdjustmentCents: adjustment.value,
equityValueCents,
negativeEquity: equityValueCents < 0,
});
}
/**
* Add-backs increase the earnings base only when they are documented. The
* function keeps rejected claims visible instead of silently dropping them,
* because an unverified add-back is usually the first thing a buyer removes.
*/
export function applyAddBacks(
startingCents: Cents,
addBacks: AddBack[],
): Result<AddBackResult> {
if (!Number.isInteger(startingCents) || startingCents <= 0) {
return fail("starting earnings must be a positive integer amount in cents");
}
const seen = new Set<string>();
let acceptedCents = 0;
let rejectedCents = 0;
const acceptedLabels: string[] = [];
const rejectedLabels: string[] = [];
for (const addBack of addBacks) {
if (
typeof addBack.label !== "string" ||
addBack.label.trim() === ""
) {
return fail("add-back label must be a non-empty string");
}
if (seen.has(addBack.label)) {
return fail(`duplicate add-back label ${addBack.label}`);
}
seen.add(addBack.label);
if (
!Number.isInteger(addBack.amountCents) ||
addBack.amountCents <= 0
) {
return fail(
`add-back ${addBack.label} must be a positive integer amount in cents`,
);
}
if (typeof addBack.verified !== "boolean") {
return fail(`add-back ${addBack.label} must state verified true or false`);
}
if (addBack.verified) {
acceptedCents += addBack.amountCents;
acceptedLabels.push(addBack.label);
} else {
rejectedCents += addBack.amountCents;
rejectedLabels.push(addBack.label);
}
}
return ok({
startingCents,
acceptedCents,
rejectedCents,
adjustedCents: startingCents + acceptedCents,
acceptedLabels,
rejectedLabels,
});
}
/**
* Deferred maintenance is a price adjustment, not a financing item. If actual
* capex is below the maintenance level, the shortfall is an arrears the buyer
* will eventually pay; over-investment does not create a credit.
*/
export function capexArrears(
maintenanceCents: Cents,
actualCents: Cents,
): Result<CapexArrears> {
const maintenanceError = checkNonNegative(
maintenanceCents,
"maintenance capex",
);
if (maintenanceError) {
return fail(maintenanceError);
}
const actualError = checkNonNegative(actualCents, "actual capex");
if (actualError) {
return fail(actualError);
}
const difference = maintenanceCents - actualCents;
return ok({
maintenanceCents,
actualCents,
arrearsCents: difference > 0 ? difference : 0,
overInvestedCents: difference < 0 ? -difference : 0,
});
}
代进 LedgerLite:bridgeToEquity 返回股权价值 $838,768、净债务 −$73,000、营运资金调整 −$3,000。把应付 $8,000 也放进债务,结果是 $830,768;把现金留给卖方,结果是 $743,768。applyAddBacks 对已验证和未验证的加回分开计数;capexArrears 对 $3,000 的维持性资本开支与 $3,000 的实际投入返回欠账 $0,因为案例的投资正好等于固定资产。
代码不判断哪个口径「正确」,只保证每个口径都能被复算。谈判时要做的,是先选一个口径,再把选择写进合同;不是先谈价格,再回头解释为什么价格和报表对不上。
小结
- 企业价值不等于股权价值;股权价值 = 企业价值 + 现金 − 债务类负债 ± 营运资金调整。
- LedgerLite 的主口径:768,768 + 95,000 − 22,000 − 3,000 = $838,768;净债务是 −$73,000。
- 把应付 $8,000 也扣掉,得到 $830,768;把现金留给卖方,得到 $743,768;三个价格都来自同一组数字,差别在口径。
- 递延收入可以单独扣,也可以放进营运资金,但不能两边都扣;重复计算会让价格少 $22,000。
- 营运资金目标是 $15,000,实际是 $12,000,调整 −$3,000;目标不是去年实际值,而是双方约定的正常水平。
- 一次性费用加回必须有凭证;在 ARR 倍数交易里,它影响倍数选择,不直接乘价格;在 SDE 倍数交易里,它按倍数进入价格。
- 资本开支欠账只在实际投入低于维持性资本开支时产生;案例的 $3,000 投资正好覆盖 $3,000 固定资产,欠账为零。
阅读导航:上一节:5.2 DCF 与情景加权 · 下一节:6.1 财务尽调 。
常见错误与边界
- 把企业价值当股权价值。 3.2× ARR = $768,768 是企业价值;加上现金、减去递延收入和营运资金短少后,才是 $838,768。
- 只加现金不扣负债。 只加 $95,000 不扣 $22,000 递延收入,会高估 $22,000;反过来只扣负债不加现金,会低估 $95,000。
- 重复扣递延收入。 单独扣一次、又在营运资金里扣一次,会把 $838,768 算成 $816,768,凭空少掉 $22,000。
- 不约定现金归属。 资产收购中现金可能留给卖方;加不加 $95,000,价格差一倍多。
- 不约定应付账款是否承接。 承接应付就扣 $8,000,不承接就不扣;合同没写清楚,交割时一定争论。
- 把营运资金目标当成去年实际值。 目标是双方约定的正常水平;实际 $12,000 低于目标 $15,000,才有 −$3,000 的调整。
- 只向下调整,不写向上调整。 实际高于目标时是否调增,取决于合同;不写就等于默认不调增,卖方会吃亏。
- 无凭证的一次性费用也加回。 加回必须有凭证;没有凭证的加回,买方在尽调中会删掉,还会怀疑其他数字。
- 把资本开支欠账和营运资金短少混为一谈。 前者是长期资产补投入,后者是短期周转补现金;两者都会减价,但原因和谈判逻辑不同。
- 忽略调整项对交易结构的传导。 −$3,000 的调整会按 70/30 分成,并影响 10% 托管;只看 headline 会漏掉现金和 earn-out 的变化。
5.3 把企业价值桥到股权价值,但价格还不是到手金额。第 7 章会继续拆资产收购与股权收购、earn-out 和托管;第 10 章会算税后所得。本节的所有调整都是税前口径,税后结果见 10.1 税后所得与分期 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。