年金计算:普通年金、预付年金、永续年金的现值与终值公式,以及Python函数封装

年金,说白了就是一系列等额、定期的现金流。你每个月还房贷、每年交保费、甚至领养老金,本质上都是年金。我个人做量化策略回测时,经常需要把未来一串现金流折现到今天,或者反过来算终值。这块搞不清楚,后面很多定价模型都站不住脚。

今天咱们就把三种最基础的年金——普通年金、预付年金、永续年金——的现值与终值公式彻底拆解一遍,最后我会给出封装好的Python函数,你直接拿去用就行。

一、普通年金:最标准的现金流模式

普通年金,也叫后付年金。它的特点是:现金流发生在每期期末。比如你每个月月底还房贷,这就是普通年金。

我刚开始做债券定价时,经常把普通年金和预付年金搞混。后来养成一个习惯:画时间轴。你想想看,现金流在时间轴上的位置不同,公式就差一个(1+r)的因子。

1. 普通年金现值公式

把未来每一期的现金流都折现到今天,然后加总。公式是:

PV = PMT × [1 - (1 + r)^(-n)] / r

其中:

  • PMT:每期支付金额
  • r:每期利率
  • n:期数

举个例子:你打算每年末存1万块,存5年,年利率5%。那么这笔年金的现值是多少?

PV = 10000 × [1 - (1.05)^(-5)] / 0.05
   = 10000 × 4.3295
   = 43295 元

嗯,43295元。也就是说,你现在一次性拿出43295元,按5%利率投资,效果等同于每年末拿1万、连续拿5年。

2. 普通年金终值公式

终值就是算最后一期结束时,这些钱一共值多少。公式是:

FV = PMT × [(1 + r)^n - 1] / r

还是上面那个例子:

FV = 10000 × [(1.05)^5 - 1] / 0.05
   = 10000 × 5.5256
   = 55256 元

你每年存1万,5年后连本带利一共55256元。这个数字比5万多了5256元,这就是复利的力量。

核心记忆点:普通年金的现值公式分母是r,终值公式分母也是r。两个公式就差一个(1+r)^n的因子。

二、预付年金:现金流提前一期

预付年金,也叫先付年金。它的特点是:现金流发生在每期期初。比如你每年年初交房租,这就是预付年金。

为什么会这样?因为期初付款比期末付款早了一期,所以每一笔钱都多赚了一期利息。说白了,预付年金的现值或终值,就是在普通年金的基础上乘以(1+r)。

1. 预付年金现值公式

PV_due = PMT × [1 - (1 + r)^(-n)] / r × (1 + r)

或者写成:

PV_due = PMT × [1 - (1 + r)^(-n+1)] / r + PMT

我个人更喜欢第一种写法,逻辑清晰:先算普通年金现值,再乘以(1+r)。

2. 预付年金终值公式

FV_due = PMT × [(1 + r)^n - 1] / r × (1 + r)

同样,先算普通年金终值,再乘以(1+r)。

我曾经在做一个租赁定价项目时,客户给的现金流是期初付款,我直接用普通年金公式算,结果差了整整一期利息。嗯,这个坑我踩过,你别再踩了。

小技巧:如果你记不住预付年金的公式,就记住一句话——预付年金 = 普通年金 × (1 + r)。考试或写代码时,先算普通年金,再乘(1+r),绝对不会错。

三、永续年金:没有终点的现金流

永续年金,就是永远持续下去的年金。现实中典型的例子是优先股股息——只要公司不倒闭,你就一直拿股息。

永续年金只有现值,没有终值。为什么?因为期数n趋向无穷大,终值也趋向无穷大,没有实际意义。

永续年金现值公式

PV_perp = PMT / r

这个公式简单到让人怀疑。但你别小看它,很多资产定价模型都基于这个公式。

举个例子:某优先股每年派息5元,市场利率4%,那么它的理论价格就是:

PV = 5 / 0.04 = 125 元

你想想看,125元存银行按4%利率,每年利息正好5元。所以这个定价是合理的。

注意:永续年金公式成立的前提是利率r > 0。如果r = 0,现值就是无穷大。现实中利率不可能长期为0,但接近0时,永续年金的现值会变得非常大,估值时要格外小心。

四、Python函数封装:拿来即用

理论讲完了,咱们上代码。我习惯把这些公式封装成一个类,方便调用。你直接复制到你的项目里就行。

class Annuity:
    """年金计算工具类"""
    
    @staticmethod
    def pv_ordinary(pmt, r, n):
        """普通年金现值"""
        return pmt * (1 - (1 + r) ** (-n)) / r
    
    @staticmethod
    def fv_ordinary(pmt, r, n):
        """普通年金终值"""
        return pmt * ((1 + r) ** n - 1) / r
    
    @staticmethod
    def pv_due(pmt, r, n):
        """预付年金现值"""
        return Annuity.pv_ordinary(pmt, r, n) * (1 + r)
    
    @staticmethod
    def fv_due(pmt, r, n):
        """预付年金终值"""
        return Annuity.fv_ordinary(pmt, r, n) * (1 + r)
    
    @staticmethod
    def pv_perpetuity(pmt, r):
        """永续年金现值"""
        if r <= 0:
            raise ValueError("利率必须大于0")
        return pmt / r

使用示例:

# 普通年金:每年末存1万,5年,利率5%
pv = Annuity.pv_ordinary(10000, 0.05, 5)
fv = Annuity.fv_ordinary(10000, 0.05, 5)
print(f"普通年金现值: {pv:.2f}")  # 43294.77
print(f"普通年金终值: {fv:.2f}")  # 55256.31

# 预付年金:每年初存1万,5年,利率5%
pv_due = Annuity.pv_due(10000, 0.05, 5)
fv_due = Annuity.fv_due(10000, 0.05, 5)
print(f"预付年金现值: {pv_due:.2f}")  # 45459.50
print(f"预付年金终值: {fv_due:.2f}")  # 58019.13

# 永续年金:每年末拿5元,利率4%
perp = Annuity.pv_perpetuity(5, 0.04)
print(f"永续年金现值: {perp:.2f}")  # 125.00
封装建议:我习惯把利率和期数都作为参数传入,而不是在类初始化时设置。这样每个方法都是纯函数,测试和调试都方便。如果你经常用同一组参数,可以初始化时设置默认值。

五、知识体系总览

下面这张图把三种年金的逻辑关系画清楚了。你看一眼就能明白它们之间的区别和联系。

年金计算知识体系 年金 普通年金(期末) 预付年金(期初) 永续年金(∞) 现值公式 终值公式 现值公式 终值公式 现值公式 核心关系:预付年金 = 普通年金 × (1 + r) 永续年金是普通年金当 n → ∞ 时的特例

这张图把三种年金的关系讲得很清楚。普通年金是基础,预付年金就是在普通年金基础上乘(1+r),永续年金则是普通年金在期数无穷大时的极限情况。

我个人建议你把这个图保存下来,每次用年金公式前看一眼,能避免很多低级错误。


公众号:蓝海资料掘金营,微信deep3321