以下情境为教学假设,人物与数字不代表经核实的真实案例。
交易不是签字那一刻,而是一段有阶段、有费用、有等待的项目。买方从接触、意向书、尽调、签约到交割,每一步都在消耗卖家的时间;律师、会计师、顾问和托管方则在每一步寄来账单。对一笔 768,768 美元的交易,这些费用可能只占 4%;对一笔 102,960 美元的交易,同样的流程可能吃掉 30% 以上。交易成本不是按价格比例发生的,而是按流程固定发生的,这个差别决定了小生意该不该卖、什么时候卖、卖给谁。
这一节用三个案例做同一张时间表:Tidecast 的锚是 1.8× 收入 = 248,708 美元,LedgerLite 的锚是 3.2× ARR = 768,768 美元,Nord 的锚是 3.0× SDE = 102,960 美元。三个案例走的是同一套五阶段流程,外部费用按同一组教学假设估算。差别只在分母:价格越小,固定成本占比越高。最后把「拖 6 个月」拆成时间价值与团队分心成本,算清楚等待本身值多少钱。
时间表不是承诺。真实交易可能因为买方内部审批、融资安排、关键客户访谈或监管问询而延长;也可能因为买方已经有现成团队而缩短。下面的周数和费用是教学假设,用来建立量级,不是行业标准。卖方能用的是把每个阶段的工作提前准备好,让流程在自己的控制范围内尽量短。
五个阶段:时间与外部费用
| 阶段 | 主要工作 | 最短–最长周数 | 外部费用(教学假设) |
|---|---|---|---|
| 接触与筛选 | 买方名单、NDA、teaser、初次电话 | 2–4 周 | 1,000–3,000 美元 |
| 意向书 | 估值、结构、排他期、费用分担 | 2–3 周 | 2,000–5,000 美元 |
| 尽职调查 | 财务、客户、技术/IP、法务、数据室 | 6–10 周 | 8,000–20,000 美元 |
| 签约 | definitive agreement、陈述保证、托管、竞业 | 2–4 周 | 4,000–10,000 美元 |
| 交割 | 账号、合同、代码、数据迁移 | 2–4 周 | 2,000–6,000 美元 |
| 合计 | 14–25 周 | 17,000–44,000 美元 |
接触与筛选阶段花的是「找对人」的钱。卖方要准备一份不含敏感信息的 teaser、一份买方名单、一份 NDA 模板,然后和潜在买方做初次电话。这个阶段通常 2–4 周,外部费用 1,000–3,000 美元,主要是顾问或平台的服务费、差旅和初步法律咨询。它的目的不是谈价格,而是确认对方有没有钱、有没有战略意图、能不能在合理时间内做决定。找错买方,后面所有阶段都会白做。
意向书阶段花的是「把交易写成条款」的钱。一份 LOI 会写估值区间、现金与 earn-out 比例、托管、排他期、费用分担和大致时间表。它通常 2–3 周,外部费用 2,000–5,000 美元,主要是律师审阅和谈判。LOI 不是合同,但它决定了后面尽调的方向:如果 LOI 写的是资产收购,尽调会围绕资产的可转让性;如果写的是股权收购,尽调会围绕公司的负债和合规。第 7 章会展开资产收购与股权收购的区别。
尽职调查阶段花的是「验证」的钱,也是整个流程最长的部分。买方会查财务、客户、技术、IP、合同、税务和合规;卖方要准备数据室、回答问卷、安排客户访谈、配合代码审计。这个阶段通常 6–10 周,外部费用 8,000–20,000 美元,主要是会计师、律师、技术顾问和数据室服务。尽调不是买方故意拖时间,而是他要在付款前确认 LOI 里的假设;卖方能做的是提前把材料准备好,让问题在一轮内回答完。
签约阶段花的是「把条款写成可执行文件」的钱。definitive agreement 会把陈述保证、赔偿上限、托管、竞业、过渡服务和交割条件写清楚;双方律师会来回修改,卖方还要准备披露函。这个阶段通常 2–4 周,外部费用 4,000–10,000 美元。签约不是终点,它只是把交割条件固定下来;如果签约后发现披露不实,买方仍可以在交割前退出或要求调整价格。
交割阶段花的是「把资产真的交出去」的钱。账号、域名、合同、代码、数据、客户通知和员工安排都要在这一阶段完成;托管方要放款,银行要处理跨境付款,平台要审核账号转让。这个阶段通常 2–4 周,外部费用 2,000–6,000 美元,主要是托管费、迁移工具和最后的法律文件。交割完成后还有过渡期,通常是 1–6 个月,卖方要回答买方的问题、协助客户迁移、处理遗留工单。过渡期的成本通常不计入上表,但它会占用卖方的时间,第 8 章会把迁移清单展开。
五个阶段合计 14–25 周,中位 19.5 周,约 4.5 个月;外部费用 17,000–44,000 美元,中位 30,500 美元。这个中位数是后面所有比例的分母。它不是「一定会花这么多」,而是「如果每个阶段都落在区间中间,交易的外部 friction 是多少」。卖方可以用自己的报价替换区间,但阶段数量和顺序不变。
交易成本占价格的比例
| 案例 | 价格锚 | 阶段中位成本 | 占价格 | 读法 |
|---|---|---|---|---|
| Tidecast | 248,708 | 30,500 | 12.3% | 小交易,固定成本占比高 |
| LedgerLite | 768,768 | 30,500 | 4.0% | 大交易,固定成本被摊薄 |
| Nord | 102,960 | 30,500 | 29.6% | 更小的交易,流程成本接近三分之一 |
同样的 30,500 美元,在 LedgerLite 身上是 4.0%,在 Tidecast 身上是 12.3%,在 Nord 身上是 29.6%。这不是因为 Nord 的律师更贵,而是因为分母更小。交易成本的大部分是固定的:一份 definitive agreement 不会因为交易金额小就少写几页,一次尽调不会因为收入低就少查几项,托管和跨境付款也不会按比例打折。小生意的卖方常常只算「卖多少钱」,不算「卖完还剩多少」,结果发现流程费用和创始人时间把收益吃掉了一大块。
29.6% 还只是阶段成本,不含延迟、不含税、不含卖方自己在交易期间少做的业务。如果把「拖 6 个月」的机会成本加进去,Nord 的摩擦会超过 40%。这也是为什么很多小服务工作室最后没有卖:不是没人买,而是交易成本相对于价格太高,卖方宁愿继续经营或关停。第 11 章会把关停成本拆开,和出售的净收益做对照。
对 LedgerLite,4.0% 的阶段成本是可以接受的:一笔 768,768 美元的交易,花 30,500 美元把结构、尽调和交割做干净,换来的是更高的成交确定性和更少的交割后争议。对 Tidecast,12.3% 已经需要认真考虑:如果买方要求 6 个月排他期,卖方在这 6 个月里不能找其他买方,机会成本会进一步上升。对 Nord,29.6% 意味着卖方要先问「这笔交易的非现金收益是什么」:是合伙人退出、是客户延续、还是品牌保留?如果答案只是「拿一笔钱」,交易成本可能高于它带来的自由。
拖 6 个月的机会成本
交易延迟的成本有两块。第一块是时间价值:钱晚到 6 个月,按教学假设 12% 的年折现率,等于价格少了 6%。第二块是团队分心:创始人和团队在交易期间要回答尽调、准备材料、开会、改合同,能用在产品、销售和支持上的时间变少。分心成本按「少掉的 SDE」和「继续支付的工资」两者取大:一人公司没有工资,分心损失的是利润;两人公司继续发工资,分心损失至少是工资。
| 案例 | 价格 | 6 个月时间价值 | 分心成本 | 合计 | 占价格 |
|---|---|---|---|---|---|
| Tidecast | 248,708 | 14,922 | 12,117 | 27,040 | 10.9% |
| LedgerLite | 768,768 | 46,126 | 13,024 | 59,150 | 7.7% |
| Nord | 102,960 | 6,178 | 9,600 | 15,778 | 15.3% |
时间价值的算法是价格 × 12% × 6/12。Tidecast 的 248,708 × 6% = 14,922 美元;LedgerLite 的 768,768 × 6% = 46,126 美元;Nord 的 102,960 × 6% = 6,178 美元。12% 是教学假设,不是无风险利率,也不是任何买方的资金成本;它只是把「晚拿到钱」换算成一个可比较的数字。如果卖方自己的再投资回报更高,时间价值应该更高;如果钱到账后只是放在账上,时间价值可以更低。
分心成本的算法是「年 SDE 或年工资 × 20% × 6/12」。Tidecast 是一人公司,没有单独工资,按 SDE 121,171 × 20% × 0.5 = 12,117 美元;LedgerLite 的 SDE 是 130,240,按 20% 算是 13,024 美元,比创始人工资 60,000 的 20% 算出的 6,000 美元大,所以取 13,024 美元;Nord 有两位合伙人,年工资合计 96,000 美元,按 20% 算是 9,600 美元,比 SDE 34,320 的 20% 算出的 3,432 美元大,所以取 9,600 美元。取大的原因是:分心既让利润变少,也让工资继续烧;对现金流紧的团队,工资口径更接近真实压力。
Nord 的数字值得单独看。它的 SDE 只有 34,320 美元,6 个月分心按 SDE 算只有 3,432 美元,看起来不痛;但两位合伙人继续领工资,96,000 美元的年工资在 6 个月里是 48,000 美元,20% 的分心就是 9,600 美元。如果交易拖到 9 个月,分心成本按工资口径是 14,400 美元,加上时间价值 9,266 美元,合计 23,666 美元,已经接近价格的 23%。对小团队,交易拖延不是「晚一点拿钱」,而是「一边烧工资一边等钱」。
Tidecast 的时间价值占比高,是因为价格相对 SDE 不算低,6% 的折现就是 14,922 美元;它的分心成本 12,117 美元约等于 1.2 个月 SDE。两者相加 27,040 美元,相当于价格的 10.9%。如果交易拖到 9 个月,时间价值 22,383 美元、分心 18,176 美元,合计 40,559 美元,占价格 16.3%。对一笔 248,708 美元的交易,这是卖方在谈判桌上应该要求的补偿,或者至少应该写进排他期的例外条款。
阶段成本加延迟成本:总摩擦
| 案例 | 阶段成本 | 6 个月延迟成本 | 总摩擦 | 占价格 | 税前净得 |
|---|---|---|---|---|---|
| Tidecast | 30,500 | 27,040 | 57,540 | 23.1% | 191,168 |
| LedgerLite | 30,500 | 59,150 | 89,650 | 11.7% | 679,118 |
| Nord | 30,500 | 15,778 | 46,278 | 44.9% | 56,682 |
总摩擦是阶段成本加 6 个月延迟成本。Tidecast 的 57,540 美元占价格 23.1%,税前净得 191,168 美元;LedgerLite 的 89,650 美元占 11.7%,税前净得 679,118 美元;Nord 的 46,278 美元占 44.9%,税前净得 56,682 美元。这里的「税前净得」只扣了交易摩擦,没有扣税、没有扣债务、没有扣卖方在交易期间少做的业务;第 10 章会把税后所得算完整。
这张表最重要的不是具体数字,而是排序:LedgerLite 的总摩擦金额最大,但占比最低;Nord 的总摩擦金额最小,但占比最高;Tidecast 在中间。卖方在决定「卖不卖」时,应该看占比,而不是只看金额。一笔 102,960 美元的交易,摩擦 46,278 美元,税前只剩 56,682 美元;如果卖方还要承担交割后的过渡支持、竞业限制和客户流失风险,这笔交易的吸引力会进一步下降。反过来,一笔 768,768 美元的交易,摩擦 89,650 美元,税前仍有 679,118 美元,流程的绝对成本高,但相对收益仍然成立。
这也是为什么「交易时间表」不是行政细节,而是估值的一部分。买方在报价时会考虑交割确定性,卖方在还价时也应该把摩擦算进去。如果买方要求 6 个月排他期,卖方可以把这段时间的机会成本折成价格让步,或者要求买方承担部分尽调费用、缩短排他期、设置分手费。交易条款里的排他期、费用分担和分手费,本质上都是在分配这 57,540、89,650 或 46,278 美元的摩擦。
写成代码:deal-timeline.ts
下面的 deal-timeline.ts 把五个阶段和延迟成本写成两个函数。summarizeTimeline 要求恰好五个阶段,每个阶段有最短/最长周数和最低/最高外部费用;它把区间加总,取中位,再算中位成本占价格的比例。estimateDelayCost 把延迟拆成时间价值、SDE 分心、工资分心和总成本;分心成本取 SDE 与工资两者中的较大值,避免把同一段时间重复计算两次。
代码不判断交易该不该做,也不预测真实买方的时间表。它只保证三件事:阶段必须齐全、区间必须有效、延迟成本必须能拆开。阶段齐全意味着卖方不会漏掉交割后的迁移;区间有效意味着最低费用不能高于最高费用;延迟成本能拆开意味着卖方可以和买方讨论「这段时间谁承担」。这三件事都能在谈判前准备好,不需要等到律师发来第一版合同。
// file: src/capital/deal-timeline.ts
// tier: L1
// verify: node --test test/capital/deal-timeline.test.ts
import { type Cents } from "../core/money.ts";
import { type Bps, divide } from "../core/rate.ts";
import { type Result, fail, ok } from "../core/result.ts";
export type DealStageKey =
| "outreach"
| "loi"
| "diligence"
| "signing"
| "closing";
export const STAGE_ORDER: DealStageKey[] = [
"outreach",
"loi",
"diligence",
"signing",
"closing",
];
export const STAGE_LABELS: Record<DealStageKey, string> = {
outreach: "接触与筛选",
loi: "意向书",
diligence: "尽职调查",
signing: "签约",
closing: "交割",
};
export type DealStage = {
key: DealStageKey;
minWeeks: number;
maxWeeks: number;
minCostCents: Cents;
maxCostCents: Cents;
};
export type TimelineInput = {
priceCents: Cents;
stages: DealStage[];
};
export type Timeline = {
minWeeks: number;
maxWeeks: number;
midWeeks: number;
minCostCents: Cents;
maxCostCents: Cents;
midCostCents: Cents;
costBpsOfPrice: Bps;
};
export type DelayInput = {
priceCents: Cents;
annualSdeCents: Cents;
annualPayrollCents: Cents;
delayMonths: number;
discountRateBps: Bps;
distractionBps: Bps;
};
export type DelayCost = {
timeValueCents: Cents;
sdeDistractionCents: Cents;
payrollDistractionCents: Cents;
distractionCents: Cents;
totalCents: Cents;
totalBpsOfPrice: Bps;
};
function isStageKey(value: string): value is DealStageKey {
return (STAGE_ORDER as string[]).includes(value);
}
/**
* External costs only: legal, accounting, advisory, data room and escrow
* fees. Founder time is not included here because it is priced separately in
* estimateDelayCost, where a month of delay has both a time-value and a
* distraction component.
*/
export function summarizeTimeline(input: TimelineInput): Result<Timeline> {
if (!Number.isInteger(input.priceCents) || input.priceCents <= 0) {
return fail("price must be a positive integer amount in cents");
}
if (input.stages.length !== STAGE_ORDER.length) {
return fail(`expected ${STAGE_ORDER.length} stages, got ${input.stages.length}`);
}
const seen = new Set<DealStageKey>();
let minWeeks = 0;
let maxWeeks = 0;
let minCostCents = 0;
let maxCostCents = 0;
for (const stage of input.stages) {
if (!isStageKey(stage.key)) {
return fail(`unknown stage ${stage.key}`);
}
if (seen.has(stage.key)) {
return fail(`duplicate stage ${stage.key}`);
}
seen.add(stage.key);
if (
!Number.isFinite(stage.minWeeks) ||
!Number.isFinite(stage.maxWeeks) ||
stage.minWeeks < 0 ||
stage.maxWeeks < stage.minWeeks
) {
return fail(`stage ${stage.key} weeks must be a valid range`);
}
if (
!Number.isInteger(stage.minCostCents) ||
!Number.isInteger(stage.maxCostCents) ||
stage.minCostCents < 0 ||
stage.maxCostCents < stage.minCostCents
) {
return fail(`stage ${stage.key} costs must be a valid integer range`);
}
minWeeks += stage.minWeeks;
maxWeeks += stage.maxWeeks;
minCostCents += stage.minCostCents;
maxCostCents += stage.maxCostCents;
}
for (const key of STAGE_ORDER) {
if (!seen.has(key)) {
return fail(`missing stage ${key}`);
}
}
const midCostCents = Math.round((minCostCents + maxCostCents) / 2);
return ok({
minWeeks,
maxWeeks,
midWeeks: (minWeeks + maxWeeks) / 2,
minCostCents,
maxCostCents,
midCostCents,
costBpsOfPrice: divide(midCostCents, input.priceCents),
});
}
/**
* Six months of delay costs money twice. The buyer's price sits in the future,
* so every month loses time value; and the founder spends part of the month on
* diligence instead of on the business. Distraction is the larger of the SDE
* forgone and the payroll still being paid, because a salaried team can burn
* cash even when profit is thin.
*/
export function estimateDelayCost(input: DelayInput): Result<DelayCost> {
if (!Number.isInteger(input.priceCents) || input.priceCents <= 0) {
return fail("price must be a positive integer amount in cents");
}
if (!Number.isInteger(input.annualSdeCents) || input.annualSdeCents < 0) {
return fail("annual SDE must be a non-negative integer amount in cents");
}
if (
!Number.isInteger(input.annualPayrollCents) ||
input.annualPayrollCents < 0
) {
return fail("annual payroll must be a non-negative integer amount in cents");
}
if (!Number.isFinite(input.delayMonths) || input.delayMonths < 0) {
return fail("delay months must be a non-negative number");
}
if (
!Number.isInteger(input.discountRateBps) ||
input.discountRateBps < 0 ||
input.discountRateBps > 10000
) {
return fail("discount rate must be between 0 and 100%");
}
if (
!Number.isInteger(input.distractionBps) ||
input.distractionBps < 0 ||
input.distractionBps > 10000
) {
return fail("distraction share must be between 0 and 100%");
}
// Basis points and twelve months share the same denominator: 10000 × 12.
const timeValueCents = Math.round(
(input.priceCents * input.discountRateBps * input.delayMonths) / 120000,
);
const sdeDistractionCents = Math.round(
(input.annualSdeCents * input.distractionBps * input.delayMonths) / 120000,
);
const payrollDistractionCents = Math.round(
(input.annualPayrollCents * input.distractionBps * input.delayMonths) /
120000,
);
const distractionCents = Math.max(
sdeDistractionCents,
payrollDistractionCents,
);
const totalCents = timeValueCents + distractionCents;
return ok({
timeValueCents,
sdeDistractionCents,
payrollDistractionCents,
distractionCents,
totalCents,
totalBpsOfPrice: divide(totalCents, input.priceCents),
});
}
把 Tidecast 代进去:五个阶段合计 14–25 周,中位 19.5 周,外部费用 17,000–44,000 美元,中位 30,500 美元,占 248,708 美元的 12.3%;拖 6 个月的时间价值 14,922 美元,分心成本 12,117 美元,合计 27,040 美元。LedgerLite 的阶段成本占比 4.0%,6 个月延迟成本 59,150 美元,其中时间价值 46,126 美元、分心 13,024 美元。Nord 的阶段成本占比 29.6%,6 个月延迟成本 15,778 美元,其中时间价值 6,178 美元、工资口径分心 9,600 美元。代码返回的阶段成本 costBpsOfPrice 分别是 1226、397、2962,和正文的 12.3%、4.0%、29.6% 一致;延迟成本 totalBpsOfPrice 分别是 1087、769、1532,对应 10.9%、7.7%、15.3%。
代码的边界是「外部费用与创始人时间」。它不包含税、债务、过渡期工资、客户流失和交割后诉讼;这些要分别放进第 10 章、第 8 章和第 7 章。它也不包含买方的时间成本,因为那部分通常已经体现在报价里。卖方要算的是自己的净得,不是双方的共同成本;把买方的尽调成本也算进来,只会让自己的模型变复杂,不会让谈判更有力。
小结
- 交易流程分五个阶段:接触与筛选、意向书、尽职调查、签约、交割;教学假设下合计 14–25 周,外部费用 17,000–44,000 美元。
- 阶段中位成本约 30,500 美元;占价格的比例:Tidecast 12.3%、LedgerLite 4.0%、Nord 29.6%。
- 交易成本大部分是固定的,小生意的占比更高;Nord 的流程成本接近价格的三分之一,还没算延迟和税。
- 拖 6 个月的机会成本 = 时间价值 + 分心成本;时间价值按价格 × 12% × 0.5 计,分心成本取 SDE 与工资两者中的较大值。
- 6 个月延迟成本:Tidecast 27,040 美元(10.9%)、LedgerLite 59,150 美元(7.7%)、Nord 15,778 美元(15.3%)。
- 阶段成本加延迟成本:Tidecast 57,540 美元(23.1%)、LedgerLite 89,650 美元(11.7%)、Nord 46,278 美元(44.9%)。
- 税前净得:Tidecast 191,168 美元、LedgerLite 679,118 美元、Nord 56,682 美元;税、债务和过渡期成本尚未扣除。
- 排他期、费用分担和分手费不是行政条款,它们是在分配交易摩擦;卖方应该把摩擦算进还价。
阅读导航:上一节:4.2 买方如何看独立开发者资产 · 下一节:5.1 ARR/SDE/EBITDA 倍数 。
常见错误与边界
- 只算律师费,不算创始人时间。 外部费用只是交易摩擦的一半;拖 6 个月的分心成本可能和律师费一样大,Nord 的工资口径分心就是 9,600 美元。
- 用大交易的费率套小交易。 30,500 美元对 768,768 美元是 4.0%,对 102,960 美元是 29.6%;小生意要按固定成本算,不能按比例算。
- 忽略排他期的机会成本。 排他期内不能找其他买方,等于放弃了竞争;6 个月排他期的成本至少是时间价值加分心,谈判时要换条件。
- 把 LOI 当合同。 LOI 不约束交割,但排他期和费用分担可能约束;签字前要看清哪些条款有约束力。
- 把尽调当成买方单方面的事。 卖方要准备数据室、安排访谈、回答问卷;准备不足会让尽调延长,延长就是成本。
- 把交割当成终点。 交割后还有 1–6 个月过渡期,账号迁移、客户通知、遗留工单都要人;过渡期成本通常不在阶段费用表里。
- 只算税前价格。 交易摩擦、税、债务和过渡成本都要从价格里扣;第 10 章会算税后所得,本节只算到税前净得。
- 把 12% 折现率当成唯一答案。 12% 是教学假设;如果卖方能把钱再投资到更高回报的地方,时间价值更高,延迟更贵。
- 用 SDE 口径算两人团队的分心。 两位合伙人继续领工资时,工资口径可能比 SDE 口径大;Nord 的 9,600 美元对 3,432 美元就是例子。
- 忽略交易失败的概率。 拖 6 个月不只是晚拿钱,还可能最后不成交;时间价值加 distraction 是「成交的延迟成本」,失败时还要加上全部沉没成本。
本节的边界是「交易流程、时间与摩擦成本」:只拆接触、意向书、尽调、签约、交割五个阶段,以及 6 个月延迟的时间价值与分心成本,不展开尽调清单、交易结构、税务和交割后的客户迁移。所有周数、费用、折现率、分心比例和案例数字都是教学假设,不构成投资、税务或法律建议;真实交易的时间表与费用应由专业人员评估。资产收购与股权收购的选择见 7.1 资产收购与股权收购 ,交割清单见 8.1 交割清单与资金流 ,知识转移见 9.3 交接期与知识转移 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。