1000 块能变成什么

YaHan 有 1000 块现金。放在抽屉里。

过了一年,打开抽屉,还是 1000 块。数目没变。

数目没变,不等于价值没变——一年后的 1000 块和今天的 1000 块,能买的东西不一样。但我们先不管购买力。只管数目。数目不变这件事太显然了,显然到你不觉得它是一个"结论"。但它是一个起点:如果你希望一年后数目变多,你必须做点什么。

借钱给别人,就是一种"做点什么"。


钱放着不动,会发生什么?[Build]

YaHan 想试试看:如果他什么都不做,1000 块一年后还是 1000 块。这件事太简单了,简单到不值得写成公式。但把它写出来是有用的——它是一个参照系。后面所有"钱变多"的情况,都是在这个参照系上叠加了别的东西。

用 $P$ 表示今天的本金 (Principal),用 $A$ 表示未来的金额 (Amount)。什么交易都没发生的时候:

$$A = P$$

def future_amount_if_idle(principal):
    return principal

P = 1000
A = future_amount_if_idle(P)
Principal (Principal, P): 1000
Future amount (Amount, A): 1000

这么简单直白的事甚至都不值得写代码,但请提醒自己:钱自己不会繁殖。 任何偏离这个等式的变化,都需要解释。

钱不会自己变多。任何收益都来自你把钱交给了别人使用。闲置就是选择收益为零。


你开口借钱,YaHan 犹豫了一下*[Build]*

你对 YaHan 说:借我 1000 块,过段时间还你。

YaHan 犹豫了。不是不信任你——是他把 1000 块给你以后,有几样东西就没了:

  1. 他暂时不能用这笔钱。万一自己突然要用呢。
  2. 你未来可能还不上。这个概率不是零。
  3. 他可能错过别的机会——也许有人愿意出更高的利息。
  4. 一年后的 1000 块和今天的 1000 块,感觉上不太一样。

所以 YaHan 说:"你还我 1050 吧。"你同意了。

多出来的 50 块需要一个名字。叫利息 (Interest)。YaHan 并不知道"利息"这个词是不是已经被发明了——他只是本能地觉得:你占用了他的钱、他承担了风险、他就应该多收回一些。这个本能在公元前 1754 年就被写进了汉谟拉比法典。法典规定,借出白银的年利率不得超过 20%,借出粮食的年利率不得超过 33.3%——四千年前,人们已经懂得为"让别人使用自己的资源"定价。

$$I = A - P$$

def interest_amount(principal, repayment):
    return repayment - principal

P = 1000
A = 1050
I = interest_amount(P, A)
Principal (P): 1000
Repayment (A): 1050
Interest (Interest, I): 50

利息是"货币的时间价值"最原始的形态。后面的一切——债券、远期、互换、期权——都在这个公式上面搭积木。


一定是50元利息吗?[Build]

50 块是多还是少?

如果本金是 100 块,多还 50 块等于赚了 50%——很厉害。如果本金是 10000 块,多还 50 块等于只赚了 0.5%——不如存银行。所以光看利息的绝对数没有意义,需要把它和本金放在一起看。

多还的比例叫期间利率 (Period Rate):$r = (A - P) / P$。YaHan 这笔借款的期间利率是 5%。

def period_rate(principal, repayment):
    return (repayment - principal) / principal

r_T = period_rate(1000, 1050)
Period rate: 0.05
As percentage: 5.0%

但这 5% 是多长时间的 5%?一个月?半年?一年?YaHan 和你都没说清楚。2023 年美国一年期国债收益率大约是 5%——但那是一年 5%。如果 YaHan 的这笔借款是半年期的,那它的实际年回报远高于国债。如果是五年期的,那就远低于国债。

说"利率 5%"没有意义。必须同时说清楚是多长时间的 5%。
对于利率,你需要记住三件事:

  1. 利率就是"用别人钱的租金"。你借 1000 还 1050,那 50 块就是租金。租金除以本金,就是利率。
  2. 利率和秤砣一样——不知道时间长度,利率就是个空数字。年化利率就是把不同期限的利率都拉到"一年"这条线上比。
  3. 简单年化和复利年化算出来的数不一样。简单年化假装利息不会生利息,复利年化承认它会。现实中永远是复利。

没有时间坐标,一切利率都是空话*[Build]*

金融里的大多数错误都来自省略了时间。YaHan 决定从这一秒开始,以后每一笔钱都标注"发生在什么时候"。

用 $t = 0$ 表示现在。$t = 1$ 表示一年后。$t = 0.5$ 是半年后。画出来是一条轴:

0      0.5      1.0      1.5      2.0
|-------|--------|--------|--------|
现在    半年后    一年后    一年半后   两年后

把这条轴生成出来——以后任何金融产品都要回答一个问题:它在哪些时间点产生现金流?

def make_time_grid(start, end, step):
    points = []
    t = start
    eps = 0.000000001
    while t <= end + eps:
        points.append(round(t, 10))
        t += step
    return points

time_grid = make_time_grid(0, 2, 0.5)
Time grid: [0, 0.5, 1.0, 1.5, 2.0]

有了这条轴,YaHan 的借款就可以精确描述了:$t=0$ 时借出 1000,$t=1$ 时收回 1050。


怎么记录一笔"钱要发生"?[Build]

YaHan 决定用一个简单的记账法:流入记正,流出记负。

他的借款就是两笔记录:$t=0$ 时 $-1000$,$t=1$ 时 $+1050$。每笔记录有三个要素:时间、金额、说明。在代码里就是三个字段:

class CashFlow:
    def __init__(self, time, amount, label=""):
        self.time = time
        self.amount = amount
        self.label = label
CashFlow(time=0, amount=-1000, label='lend money to you')
CashFlow(time=1, amount=1050, label='you repay')

YaHan 发现,他用这个东西可以表示任何一笔"钱在某时发生"的事件。银行房贷的月供、公司债的利息支付、VC 投给创业公司的那笔钱——全是 CashFlow,只是时间和金额不同。


一笔交易里藏着不止一笔现金流*[Build]*

YaHan 的借款有两笔现金流。但如果是一笔分期贷款呢?或者一张每年付息的债券呢?会有很多笔。

他把一组现金流装进一个表——现金流表 (CashFlowSchedule)。这个表可以做两件事:把所有金额直接加起来(名义总和),或者把未来每一笔都贴现到现在再加起来(净现值)。后者比前者有用得多——但目前他还不知道"贴现"这个词。

class CashFlowSchedule:
    def __init__(self, cashflows):
        self.cashflows = cashflows

    def total_amount(self):
        total = 0
        for cf in self.cashflows:
            total += cf.amount
        return total

把 YaHan 的借款装进去:

time    amount  label
0       -1000   YaHan lends money to you
1       1050    you repay
Nominal sum: 50

名义总和是 50——但这 50 不是"今天的 50"。1050 发生在一年后,不能和今天的 -1000 直接加。YaHan 隐约觉得这里有个问题,但暂时搁置——先处理另一个更紧急的麻烦。


你给了 YaHan 三种还款方案*[Verify]*

你又来了,给了 YaHan 三个选择:

直觉上,C 最诱人——多还 120 块。但 C 占用了 YaHan 的钱整整两年。如果他半年后就把 A 的本息收回来,再把 1030 借出去半年,第二笔又能赚一点。连续做下去——半年一滚——两年后可能比 C 的 1120 还多。

YaHan 需要把不同期限的收益率放在同一条线上比较。各地的银行、债券交易员、抵押贷款经纪人天天都在做这件事。2022 年美联储开始加息的时候,市场上所有不同期限的债券收益率一起上升——2 年期从 0.7% 飙升到 4.7%,10 年期从 1.5% 升到 4.2%。不同期限的利率不是独立运动的,但运动的幅度不一样。

用期间利率分别算:

Deal A: T=0.5yr, period rate=0.0300 (3.0%)
Deal B: T=1.0yr, period rate=0.0600 (6.0%)
Deal C: T=2.0yr, period rate=0.1200 (12.0%)

A 半年赚 3%,B 一年赚 6%,C 两年赚 12%——但时间长度不一样,没法直接说"哪个利率更高"。


如何比较三个收益率呢?[Build]

最简单的换算:假设收益按时间线性增长。半年 3%,那一年就是 2 × 3% = 6%。这叫简单年化 (Simple Annualised Rate)

YaHan 用这个公式把三笔借款都换算成一年:

Deal A: simple annual rate = 0.060000 (6.0000%)
Deal B: simple annual rate = 0.060000 (6.0000%)
Deal C: simple annual rate = 0.060000 (6.0000%)

三笔一模一样——都是年化 6%。有那么一瞬间,YaHan 觉得问题解决了。

但事情似乎没这么简单。如果选 A(半年 3%),到期后把本息 1030 再借出去半年,第二期的利率如果也是 3%,一年后的总额是 $1030 \times 1.03 = 1060.9$,比 B 的 1060 多出 0.9。连续做四次 A(两年),本息是 $1000 \times 1.03^4 \approx 1125.5$,比 C 的 1120 多出 5.5。

简单年化把"利息本身也能生利息"这件事忽略了。YaHan 想了想:"半年赚到的 30 块,下半年也可以继续借给别人啊。"

这个想法有一个名字。叫复利 (Compounding)


半年赚 3% 等于一年 6% ?[Verify]

如果每一期赚到的利息都能加入本金继续赚钱,年化的公式就变了。不再是简单的除以时间,而是开方:

$$r_{\text{compound}} = \left(\frac{A}{P}\right)^{1/T} - 1$$

用这个重新算:

Deal A: compound annual rate = 0.060900 (6.0900%)
Deal B: compound annual rate = 0.060000 (6.0000%)
Deal C: compound annual rate = 0.058301 (5.8301%)

A 最高(6.09%),B 居中(6.00%),C 最低(5.83%)。YaHan 盯着这三个数看了一会儿。期限越长,同样的"多还多少钱"摊到每年反而越薄。不是因为长期借款不好——是因为锁死的时间更长,复利效果被拉平。如果你想要两年期的借款也能给到 6.09% 的年化,C 需要还的不该是 1120,而是 $1000 \times 1.0609^2 \approx 1125.5$。

这里有一个普遍的规律:在正常市场里,长期利率通常高于短期利率。 2023 年 10 月,美国 3 个月期国债收益率 5.5%,10 年期只有 4.8%——短高长低,这叫收益率曲线倒挂,通常被视为衰退信号。但在 2021 年,3 个月期接近 0%,10 年期 1.5%——正常的向上倾斜。YaHan 还不知道"收益率曲线"这个词,但他已经在做这个计算了。

到这里,YaHan 手上有了四个可以反复用的东西:时间轴、单笔现金流、现金流表、利率(期间和年化)。这些是最小的积木。但他还有一个问题悬着——一年后的 1050,今天值多少?


把明年的 1050 搬回今天*[Build]*

YaHan 现在能比较不同期限的利率了。但他还有一个问题悬着。他手里有一张借条——一年后收回1050。这张借条是一张纸,但纸上的"1050"不是今天的1050。要确定它今天的价值,需要回答一个问题:在今天的环境里,用今天的利率,让一年后恰好变成1050,今天需要多少钱。

市场上有一个稳妥的投资机会:今天投入 1000,一年后拿回 1100。年回报 10%。

那如果一年后有人承诺给你 1100 元,这个承诺今天值多少?答案是 1000——因为你可以用同样的 1000 元复制出这个结果。

YaHan 把这个动作叫贴现 (Discounting)。它不是在说"未来的钱变少了"。它问的是:未来的一笔钱,今天值多少?

一年期:$PV = \frac{FV}{1+r}$。T 年期(复利):$PV = \frac{FV}{(1+r)^T}$。

def present_value(future_value, rate, T):
    return future_value / ((1 + rate) ** T)
Future value (Future Value, FV): 1100
Rate (r): 0.1
Time (T): 1 years
Present value (Present Value, PV): 1000.0

利率越高 → 现值越低。时间越长 → 现值越低。拉一张表:

FV=1000, r=0.01, T=1yr -> PV=990.10
FV=1000, r=0.01, T=5yr -> PV=951.47
FV=1000, r=0.10, T=1yr -> PV=909.09
FV=1000, r=0.10, T=5yr -> PV=620.92

5 年后的 1000 元,在 10% 的利率下,今天只值 620。因为 620 存五年按 10% 复利刚好变成 1000。

这个逻辑在现实中每天都在发生。2023 年,一家初创公司以 10 亿美元估值融资——投资者投的不是"今天值 10 亿",而是"5 年后这家公司值 50 亿,贴现回来今天值 10 亿"。VC 的整个定价模型就是一个高级版的 present_value 函数,只是参数不是利率,而是风险调整后的预期回报。


YaHan 把你的借款每条线都折回今天*[Verify]*

回到你借 YaHan 1000 元、一年后还 1050 的交易。它有两笔现金流。把每一笔都贴现到 $t=0$ 再加起来——叫净现值 (Net Present Value, NPV)

def npv(cashflow_schedule, rate):
    total = 0.0
    for cf in cashflow_schedule.cashflows:
        total += present_value(cf.amount, rate, cf.time)
    return total

用不同的贴现率跑一下:

Discount rate 0.0: NPV = 50.0000
Discount rate 0.03: NPV = 19.4175
Discount rate 0.05: NPV = 0.0000
Discount rate 0.1: NPV = -45.4545

贴现率 0%:1050 不打折,净现值等于名义差额 50。贴现率 5%:1050 折回今天恰好 1000,NPV = 0——借出和收回在现值上打平。贴现率 10%:1050 折回不到 1000,NPV 为负——按 10% 的标准,这笔借款亏了。

YaHan 意识到一件事:同一笔现金流,贴现率不同,结论完全不同。 2022 年美联储开始加息时,市场上所有风险资产的"贴现率"都在上调——同样的未来现金流,现值全部缩水。科技股跌得最惨,因为它们的现金流大部分在遥远的未来,对贴现率最敏感。

对于净现值,你需要记住三件事:

  1. 净现值就是把一个项目所有未来的现金流入和流出全部折到现在、加在一起。正的说明赚钱,负的说明亏钱。
  2. 同一笔现金流,换一个贴现率,NPV 可能从正变负。贴现率不是客观数字——它取决于你跟什么比。
  3. 公司做投资决策、VC 给创业公司估值、银行审批房贷——本质上都在算 NPV。公式可能包装得很复杂,内核就是贴现加总。

一年后的 100 块不等于今天的 100 块。差额就是利率。时间越长、利率越高,未来的钱今天就越不值钱。


如果定价的对象不是"钱",而是"别的东西"?[Build]

YaHan 发现他一直在处理"钱本身"——借出 1000、收回 1050。但市场上有太多东西不是钱:苹果公司的股票、德州的原油、芝加哥的玉米、加密交易所里的比特币。

它们有一个共同点:在某个时间点有一个价格。 YaHan 只需要一个最简单的类:

class AssetPrice:
    def __init__(self, asset_name, time, price):
        self.asset_name = asset_name
        self.time = time
        self.price = price
AssetPrice(asset_name='Apple Stock', time=0, price=100)

YaHan 现在不研究股票为什么涨跌。他只确定一件事:后面要讲的期货、期权、远期——所有这些衍生品——都是基于某个标的物 (Underlying Asset) 在未来某个时间的价格来设计合约的。2020 年 4 月 20 日,WTI 原油期货价格跌到 -$37.63——人类历史上第一次出现负油价。这个价格荒诞到像是一个 bug,但它恰好说明了一件事:衍生品合约的价值完全依赖标的物在特定时间点的价格。标的物价格可以变成负数,衍生品的 payoff 就跟着变成负数。


你一定会还钱吗?[Build]

一直到现在,YaHan 都假设你一定会履行承诺——到时必定还 1050。

这次不一样。你说你要拿这 1000 块去做生意。一年后结果取决于生意的好坏:

YaHan 意识到他之前处理的都是"确定"的现金流。这一次,未来还款金额是一个随机变量 (Random Variable)——现在不知道具体是多少,但知道可能有哪些结果,每种结果的概率是多少。

这不是一个奇怪的例外。每一次借钱、每一次投资、每一次签合约,未来都不完全确定。 2020 年 3 月,新冠疫情爆发时,全球市场在一个月内蒸发了 30% 的市值。没人能预测这个——但所有人都知道"有时候会发生这种事"。不确定性是金融的默认状态,确定性才是特例。真实的未来比三种可能结果复杂得多。股价不是只涨到120或跌到80——它可以在中间任何一个位置停下来,每天的涨跌互相影响。完整的"连续不确定性"需要随机微积分来刻画,那是后面章节的事。现在,YaHan 只需要一个最朴素的起点:在已知可能结果和概率的前提下,算一个平均。


"平均下来"能还多少?[Verify]

三种结果,概率分别 20%、60%、20%。加权平均——期望值 (Expected Value)

$$E[X] = 0.2 \times 800 + 0.6 \times 1050 + 0.2 \times 1300 = 1050$$

Expected repayment: 1050.0
Expected return vs principal: 0.0500

期望还款恰好也是 1050——跟确定还款一样。但 YaHan 注意到了区别:确定还 1050 没有坏情况。随机还 1050 有 20% 的概率只还 800。 期望值相同,风险不同。这件事在整个金融工程里反复出现——价格是一个数,风险是一整个分布。只盯着期望值不看分布,就跟只看平均水位不过问洪水概率一样。


怎么模拟"不知道的未来"?一颗骰子*[Build]*

YaHan 想模拟那个不确定的未来。他需要随机数——但不想用 Python 自带的 random

他手搓了一个最简单的线性同余发生器 (Linear Congruential Generator)。原理是递推:$x_{n+1} = (a \cdot x_n + c) \bmod m$。除以 m 就得到一个 0 到 1 之间的数。这不是高质量随机数——但在 1960 年代,兰德公司就是用类似的方法生成随机数来做核战争模拟的。对 YaHan 的目的来说够用了。

class LinearCongruentialGenerator:
    def __init__(self, seed=1):
        self.state = seed
        self.a = 1103515245
        self.c = 12345
        self.m = 2 ** 31

    def next_float(self):
        self.state = (self.a * self.state + self.c) % self.m
        return self.state / self.m
0.582308
0.519819
0.465976

YaHan 丢了十次骰子*[Verify]*

规则:随机数小于 0.2 → 还 800;0.2 到 0.8 之间 → 还 1050;大于 0.8 → 还 1300。连续抽十次:

Trial 1: 1050
Trial 2: 1050
Trial 3: 1050
Trial 4: 1050
Trial 5: 1300
Trial 6: 800
Trial 7: 1300
Trial 8: 1300
Trial 9: 1050
Trial 10: 1050

十次里有三次偏离了 1050——两次偏高(1300)、一次偏低(800)。单次看,什么都有可能。但 YaHan 想知道的是抽很多次以后的行为。


抽一次靠运气,抽一万次靠数学——蒙特卡洛*[Verify]*

10 次、100 次、1000 次、10000 次——每次重新播种、独立抽样,取平均值:

Trials:    10, average repayment: 1000.00
Trials:   100, average repayment: 1050.00
Trials:  1000, average repayment: 1051.25
Trials: 10000, average repayment: 1049.38

10 次时偏离明显(1000),100 次接近(1050),10000 次收敛到 1049.38——离理论值 1050 只差 0.62。这就是蒙特卡洛方法 (Monte Carlo Method) 的最小版本:用大量随机样本逼近真实期望。

这个名字是 1940 年代在洛斯阿拉莫斯实验室起的——物理学家用这种方法模拟中子在原子弹里的扩散路径。2020 年新冠疫情期间,流行病学家又用蒙特卡洛模拟了不同封锁策略下的感染曲线。YaHan 用同一套逻辑模拟的是"你还钱"——标的不同,算法一样。

期望值相同的两个投资,风险可以完全不同。做决策的时候,分布比均值重要。


复利次数越多越好吗?[Build]

回来后利息。年利率 10%、本金 1000、一年到期。一年结一次:拿 1100。半年结一次(每半年利率 5%):$1000 \times 1.05^2 = 1102.5$。多出 2.5 块。如果按月结?按天结?

Compounds/yr:    1, future value: 1100.000000
Compounds/yr:    2, future value: 1102.500000
Compounds/yr:   12, future value: 1104.713067
Compounds/yr:  365, future value: 1105.155782

结算次数越多,最终拿的越多——但增长在减速。一年结 365 次(每天)和一年结 2 次(每半年)差 2.66 块;一年结 10000 次和连续复利几乎没差别。它似乎逼近了一个极限。


如果结算次数无穷多会怎样?[Build]

当结算次数趋向无穷,公式收敛到一个数学常数 $e$:

$$FV_{\text{continuous}} = P \cdot e^{rT}$$

YaHan 不用 math.exp。他用泰勒级数自己搓了 $e^x$——取 30 项已经非常准。1000 块、10% 利率、一年,连续复利 = 1105.1709。比每天结算只多 0.000015 元。

Compounds/yr    Future Value
--------------- ---------------
1               1100.000000
365             1105.155782
10000           1105.170365
continuous      1105.170918

现实中没有任何银行用连续复利结算。但它作为数学工具很好用——后面处理随机价格过程和衍生品定价时,连续复利的公式是最简洁的。在利率很低的时候——比如 r = 1%——连续复利和单利的结果几乎一样。e^0.01 ≈ 1.01005,而 1+0.01 = 1.01,只差十万分之五。这就是为什么低利率环境下很多人直接用单利近似:误差小到可以忽略。但利率一旦超过 5%,复利和单利的差距就肉眼可见了。

连续复利是一个数学极限,不是现实。它存在是因为公式简洁,不是因为真实。


小试牛刀*[Challenge]*

你把 YaHan 的 1000 元拿去做生意,一年后还款不确定:

市场上一年期无风险利率是 5%。

  1. 期望还款是多少?贴现到今天值多少?
  2. 净现值是多少?YaHan 该不该借?
Expected repayment: 1050.0
PV of expected repayment (r=0.05): 1000.0000
Expected NPV: 0.0000

期望还款 1050,按 5% 折现后恰好等于借出的 1000——净现值为零。在平均意义上,借和不借一样。但 NPV = 0 不代表没有风险:20% 的概率只还 800,YaHan 净亏 200 的现值。这件事提醒了一个区分:均值告诉你平均结果,分布告诉你有多大的概率偏离平均。 金融危机、创业失败、自然灾害——都是分布的尾部在起作用。只看均值不管分布的人,在 2008 年之前以为房价只涨不跌。


本章回顾*[Recap]*

YaHan 手里现在有这些可以反复调用的积木:

时间轴、单笔现金流、现金流表、期间利率、简单年化、复利年化、贴现因子、现值、净现值、标的物价格、不确定性和期望值、随机数发生器、还款抽样、蒙特卡洛模拟、离散复利、连续复利。

这些就是后面所有章节的"原语"。它们单独看什么都不是,但它们拼在一起就是债券、远期、互换、期权。

如果非要找一个类比的话——有点像乐高。没有一个单独的原语是"有用的"。它们的存在只是为了被组合。下一章开始的每一件事——债券、远期、FRA、互换——都是把已有的积木换个方式拼在一起。

问题是:拼出来的是什么?

后面所有的章节都在做同一件事:把第一章这些原语换个方式拼在一起。债券、远期、互换、期权——没有新原理,只有新拼法。