计算带下限和上限的 CPI 租金调整

按 CPI 调整租金的租约,会比较两个基准月份的指数,再把变化率限制在下限和上限之间应用。Narwhal 提供各国的月度 CPI 指数,其余由一个简短的脚本完成。

获取每个基准月份的指数

CPI 租金条款会比较两个基准月份的指数,通常是相隔一年的同一个日历月。本例使用 9 月和英国。一次请求就返回 2022 年 9 月到 2026 年 9 月每个月的指数,下面的响应只保留了第一个和最后一个。

curl,租约基准月份的 CPI
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
  "https://api.narwhalapi.com/v1/economics/GBR/cpi/observations?start=2022-09&end=2026-09&limit=100"
响应,已精简
{
  "country": "GBR",
  "as_of": "2026-10-21T00:00:00Z",
  "index_base": "2015=100",
  "observations": [
    {
      "period": "2022-09",
      "value": "123.8"
    },
    {
      "period": "2026-09",
      "value": "144.1"
    }
  ],
  "next_cursor": null
}

observations 按从旧到新的顺序列出每个 period 及其 value。英国的 index_base 是 2015=100,对百分比变化没有影响。as_of 是该序列所反映的日期。这个请求返回 49 个月度值,全部在一页之内,next_cursor 为 null。

用下限和上限计算调整幅度

一年的调整幅度等于新指数除以旧指数再减一。下限设定租金至少上涨多少,上限设定最多上涨多少。实际适用的比率是把调整幅度限制在两者之间的结果,新租金等于旧租金乘以一加适用比率。

python,带下限和上限的年度租金调整
import json
import os
import urllib.request
from decimal import Decimal, ROUND_HALF_UP

def get(path):
    req = urllib.request.Request(
        "https://api.narwhalapi.com" + path,
        headers={"Authorization": "Bearer " + os.environ["NARWHAL_API_KEY"]},
    )
    with urllib.request.urlopen(req, timeout=30) as r:
        return json.load(r)

def escalate(rent, cpi_old, cpi_new, floor, cap):
    change = cpi_new / cpi_old - 1
    applied = min(max(change, floor), cap)
    return (rent * (1 + applied)).quantize(Decimal("0.01"), ROUND_HALF_UP), change, applied

data = get("/v1/economics/GBR/cpi/observations?start=2022-09&end=2026-09&limit=100")
cpi = {o["period"]: Decimal(o["value"]) for o in data["observations"]}

rent, floor, cap = Decimal("2000.00"), Decimal("0.02"), Decimal("0.05")
for year in (2023, 2024, 2025, 2026):
    old, new = cpi[f"{year - 1}-09"], cpi[f"{year}-09"]
    rent, change, applied = escalate(rent, old, new, floor, cap)
    print(f"{year}: CPI {old} -> {new}, change {change:.2%}, applied {applied:.2%}, rent {rent}")

本例的租约起始租金为每月 2,000.00,下限为 2%,上限为 5%。每个周年日都用 9 月与上一年的 9 月比较。脚本每年打印一行,例如 2023: CPI 123.8 -> 132.0, change 6.62%, applied 5.00%, rent 2100.00。它全程使用 Decimal 计算,并且每年只把租金四舍五入到分一次,所以如果租约先对比率取整,或者用别的方式对租金取整,结果会相差几分。

年份指数变化适用比率租金
2023123.8 到 132.0,6.62%5.00%(触及上限)2,100.00
2024132.0 到 134.2,1.67%2.00%(触及下限)2,142.00
2025134.2 到 139.3,3.80%3.80%2,223.40
2026139.3 到 144.1,3.45%3.45%2,300.01

手工验证第一年。132.0 除以 123.8 等于 1.0662,所以指数上涨了 6.62%。这高于上限,因此适用比率是 5%,2,000.00 乘以 1.05 得 2,100.00。2024 年,134.2 除以 132.0 等于 1.0167,低于 2% 的下限,所以租金上涨 2%,变为 2,142.00。

2023 年触及上限,2024 年被下限抬高,后面两年则跟随指数。租金是复利增长的,因为每一年都从上一年的租金出发。如果租约把每年的比率都用于起始租金、不做复利,就需要把起始租金放在单独的变量里。

API 提供什么,租约规定什么

项目来源
每个月的指数值Narwhal 的 CPI 观测值
租约指定了哪个指数租约
基准月份租约
下限和上限租约
取整与复利租约

Narwhal 提供的是各国的总体居民消费价格指数。如果合同指定了其他指数,比如核心指数、地区指数或另一家发布机构的指数,这里的数据可能就不是合同所用的数字。运行脚本前请先读懂条款。

租金调整应该用哪个月的指数?

用租约指定的月份。本例用的是 9 月,因为这里的条款是把 9 月与上一年的 9 月比较,而且英国的最新指数是 2026 年 9 月的。用 start 和 end 请求这两个月,或者用 /v1/economics/{country}/cpi?period=YYYY-MM 读取过去的某一个月。

如果周年日时新的月份还没有公布怎么办?

请求一个尚无公布数值的月份,会返回代码为 series_not_found 的 404 问题响应。不带 period 的 CPI 端点返回最新的月份及其 released_on 日期。如果周年日早于基准月份的公布时间,请先保持租金不变,等该月份出来后再运行脚本,或者按租约规定的替代办法处理。

如果物价下降会怎样?

变化率为负时,结果由上下限的限制来决定。下限为 0% 时,适用比率为 0%,租金保持不变。像上面那样下限为 2% 时,租金仍然上涨 2%。没有下限的租约会让租金按变化率下降,同一个函数把下限设为 -1 就能处理这种情况。

其他国家也能做同样的检查吗?

改一下路径里的国家代码即可。端点返回该国的总体指数,所以条款也必须指定这个指数。start 和 end 接受 YYYY、YYYY-MM 或 YYYY-QN,响应中 period 字符串的格式会告诉你该序列是月度还是季度。百分比变化的更多细节见计算 CPI 同比的指南。

发布于。

后续步骤