4. 希腊字母计算与风险暴露分析

任务目标

基于Black-Scholes模型,实现期权希腊字母(Delta、Gamma、Theta、Vega、Rho)的计算函数,并对一个由看涨期权与看跌期权构成的投资组合进行风险暴露分析,输出各风险因子的组合敞口及占比。

环境与依赖

仅需Python 3.8+及NumPy/SciPy(用于正态分布函数)。无需额外数据文件,所有输入参数在代码中直接给定。

关键完整代码

import numpy as np
from math import log, sqrt, exp
from scipy.stats import norm

def black_scholes_greeks(S, K, T, r, sigma, option_type='call'):
    """
    计算单个期权的希腊字母
    S: 标的价格, K: 行权价, T: 剩余期限(年), r: 无风险利率, sigma: 波动率
    option_type: 'call' 或 'put'
    返回: (delta, gamma, theta, vega, rho) —— theta为每日(除以365)
    """
    if T <= 0 or sigma <= 0:
        raise ValueError("T 和 sigma 必须为正")
    d1 = (log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * sqrt(T))
    d2 = d1 - sigma * sqrt(T)
    pdf_d1 = norm.pdf(d1)
    cdf_d1 = norm.cdf(d1)
    cdf_d2 = norm.cdf(d2)

    if option_type == 'call':
        delta = cdf_d1
        theta = (-S * pdf_d1 * sigma / (2 * sqrt(T))
                 - r * K * exp(-r * T) * cdf_d2) / 365
        rho = K * T * exp(-r * T) * cdf_d2 / 100  # 每1%利率变动
    elif option_type == 'put':
        delta = cdf_d1 - 1
        theta = (-S * pdf_d1 * sigma / (2 * sqrt(T))
                 + r * K * exp(-r * T) * norm.cdf(-d2)) / 365
        rho = -K * T * exp(-r * T) * norm.cdf(-d2) / 100
    else:
        raise ValueError("option_type 必须为 'call' 或 'put'")

    gamma = pdf_d1 / (S * sigma * sqrt(T))
    vega = S * pdf_d1 * sqrt(T) / 100  # 每1%波动率变动
    return delta, gamma, theta, vega, rho

# ========== 组合定义与风险暴露分析 ==========
# 组合持仓: (数量, S, K, T, r, sigma, 类型)
# 正数=多头, 负数=空头
positions = [
    (100, 100.0, 100.0, 0.5, 0.03, 0.20, 'call'),   # 多100张平值看涨
    (-50, 100.0, 105.0, 0.5, 0.03, 0.20, 'call'),   # 空50张虚值看涨
    (80,  100.0, 95.0,  0.5, 0.03, 0.20, 'put'),    # 多80张实值看跌
]

greeks_names = ['Delta', 'Gamma', 'Theta(每日)', 'Vega(每1%)', 'Rho(每1%)']
portfolio_greeks = np.zeros(5)

print("单腿希腊字母明细:")
print(f"{'腿':<4} {'数量':>6} {'Delta':>8} {'Gamma':>8} {'Theta':>8} {'Vega':>8} {'Rho':>8}")
for i, (qty, S, K, T, r, sigma, typ) in enumerate(positions):
    g = black_scholes_greeks(S, K, T, r, sigma, typ)
    leg_greeks = np.array(g) * qty
    portfolio_greeks += leg_greeks
    print(f"腿{i+1} {qty:>6} " + " ".join(f"{v:>8.4f}" for v in g))

print("\n组合总风险暴露:")
for name, val in zip(greeks_names, portfolio_greeks):
    print(f"{name:<12}: {val:>10.4f}")

# 风险占比分析(以值衡量各因子相对重要性)
abs_vals = np.abs(portfolio_greeks)
total_abs = abs_vals.sum()
print("\n风险因子暴露占比(值):")
for name, val in zip(greeks_names, abs_vals):
    print(f"{name:<12}: {val/total_abs*100:>6.2f}%")

运行方式

将上述代码保存为 greeks_analysis.py,在已安装 numpy 和 scipy 的环境中执行:

pip install numpy scipy
python greeks_analysis.py

验证方法与判定标准

程序运行后应输出三部分内容:

  1. 单腿希腊字母明细:共3行,每行包含该腿的Delta、Gamma、Theta、Vega、Rho值。可通过以下数值特征快速验证正确性:
    • 平值看涨期权(腿1)的Delta应接近0.5~0.55(因利率为正略高于0.5);
    • 虚值看涨期权(腿2)的Delta应小于0.5;
    • 实值看跌期权(腿3)的Delta应为负值(约-0.6~-0.7);
    • 所有Gamma均为正值,平值期权Gamma最大。
  2. 组合总风险暴露:5个数值,等于各腿希腊字母乘以数量后的代数和。例如组合Delta = 100×Δ₁ − 50×Δ₂ + 80×Δ₃。
  3. 风险因子暴露占比:5个百分比,各因子值之和为100%。

通过条件:程序无异常退出;单腿希腊字母满足上述数值方向性特征;组合总暴露与手工按公式加权计算结果一致(误差<1e-6);占比合计为100%。

常见问题

  • Theta与Rho的量纲:代码中Theta已除以365转换为每日损耗,Rho除以100表示利率变动1个百分点(即100个基点)的影响。若需原始年度值,去掉对应除法即可。
  • 空头持仓的希腊字母:空头(数量为负)时,组合希腊字母为负值,表示反向风险暴露。例如空头看涨期权的Delta为负,意味着标的价格上涨时组合价值下降。
  • 边界条件:当T接近0时,d1计算会溢出。实际交易中临近到期期权需改用二叉树或数值方法,本案例适用于T>0.01的常规场景。