σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academy学习路线
Ctrl K
AO
+1.2k 位学习者
登录加入 ↗
学习路线
AO
+1.2k 位学习者
登录
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python 学习路线›模块 2 · 用于市场数据的 NumPy 与 pandas›主题 2.11·~35分钟中级

对数收益率

路线进度模块 2/11 · 主题 11/20
2.11 对数收益率
—实验得分— / 100总 XP—连续天数—

价格比值的对数

对数收益率是两个价格之比的自然对数。不再计算 P_t / P_{t-1} - 1,而是计算 ln(P_t / P_{t-1})。对于小幅波动两者几乎相等(上涨 2% 的对数值是 0.0198),但对数形式具有一些性质,使它成为统计与建模的标准选择。在 pandas 中,先用 np.log 对整个价格 Series 取对数,再 diff:对数相减就是价格相除。

r_t = ln(P_t / P_{t-1}) = ln(P_t) - ln(P_{t-1})
import numpy as np
import pandas as pd

prices = pd.Series([100.0, 102.0, 100.98, 103.0], index=["Mon", "Tue", "Wed", "Thu"])

log_ret = np.log(prices).diff()
print(log_ret.round(4))
# Mon       NaN
# Tue    0.0198
# Wed   -0.0101
# Thu    0.0198
# dtype: float64

print(prices.pct_change().round(4).tolist())   # [nan, 0.02, -0.01, 0.02]   the simple returns, for comparison

对数收益率在时间上可以相加

这是使用它的主要原因。因为 ln(a) - ln(c) = (ln(a) - ln(b)) + (ln(b) - ln(c)),多期的对数收益率就是各期对数收益率的总和,无需复合。两天的收益率是两个单日收益率之和,月收益率是各日之和,再用 exp(total) - 1 就能还原成简单收益率。对数收益率还是对称的:价格翻倍后再减半,对数收益率为 +0.6931 与 -0.6931,正好抵消,而简单收益率是 +100% 和 -50%。

# The sum of the daily log returns is the log return over the whole period
print(round(log_ret.sum(), 6))                         # 0.029559
print(round(np.log(prices.iloc[-1] / prices.iloc[0]), 6))   # 0.029559   end price over start price

# exp(total) - 1 is the simple return of the whole period
print(round(np.exp(log_ret.sum()) - 1, 6))             # 0.03
# Symmetry: the price doubles, then halves
doubling = pd.Series([100.0, 200.0, 100.0])
print(doubling.pct_change().tolist())               # [nan, 1.0, -0.5]
print(np.log(doubling).diff().round(4).tolist())    # [nan, 0.6931, -0.6931]

转换与多日涨跌

要还原为简单收益率,用 np.exp(r) - 1(对很小的数值 np.expm1(r) 更精确)。小幅波动时两者很接近,大幅波动时会拉开差距:简单收益率 +50% 的对数值是 0.4055。np.log 与 np.exp 直接作用于整个 Series,所以不需要循环。要衡量多日涨跌,diff 可以接收期数:np.log(prices).diff(5) 就是五日对数收益率,等于五个单日对数收益率之和。

# Small moves agree with the simple return, big moves do not
for simple in [0.01, 0.1, 0.5, -0.5]:
    print(simple, round(np.log1p(simple), 4))   # log1p(r) is ln(1 + r)
# 0.01 0.01
# 0.1 0.0953
# 0.5 0.4055
# -0.5 -0.6931

# Back to simple returns, on the whole Series at once
print((np.exp(log_ret) - 1).round(4).tolist())   # [nan, 0.02, -0.01, 0.02]

# The log return over 2 days: diff takes a number of periods
print(np.log(prices).diff(2).round(4).tolist())   # [nan, nan, 0.0098, 0.0098]
按时间相加,而不是跨资产相加对数收益率可以跨期相加,但组合的收益率是各资产简单收益率的加权和。两个等额持仓的对数收益率为 +10% 和 -10%,组合并不是 0%:按简单收益率它们是 +10.5% 和 -9.5%,所以组合赚 +0.5%。先转换成简单收益率再加权,需要对数时再转换回去。
  • 对数收益率是 ln(价格 / 前一期价格):np.log(prices).diff();第一个元素是 NaN。
  • 在时间上直接相加:log_ret.sum(),np.exp(total) - 1 得到简单收益率。
  • diff(k) 给出 k 期的涨跌;跨资产加权时用简单收益率,而不是对数收益率。

下一节:DatetimeIndex 与基于时间的索引,为价格序列加上真实日期,按月份或星期切片。

实验:评分内容

  • 用 log_returns 把价格转换为对数收益率25 分
  • 用 simple_from_log 把对数收益率转换回简单收益率25 分
  • 用 total_log_return 把各期对数收益率相加25 分
  • 用 multi_day_log_return 衡量多日的涨跌25 分
资源管理器 · lab-44-1
▾ lab-44-1
…
bash · 浏览器内
learner@quantcraft:~/lab-44-1$
Python 尚未加载PythonLn 1, Col 1Spaces: 4UTF-8

要重置此主题吗?

lab-44-1 中的所有内容将恢复为初始文件,终端也会被清空。你当前的解答将丢失,且无法撤销。

将被重置
  • main.py → 初始代码
  • 终端历史与测试输出
  • 未提交的更改
将被保留
  • 实验最高得分
  • 你的 XP 与连续天数
  • 讲解进度与笔记

登录后即可运行你的代码。

所有讲解均可免费阅读。创建账户或登录后,即可运行代码、运行测试并提交此实验。

  • 浏览器内 IDE 与 bash 终端,无需安装
  • 即时评分、XP 以及你在学习路线中的位置
创建账户登录
或
使用 GitHub 继续