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
验证方法与判定标准
程序运行后应输出三部分内容:
- 单腿希腊字母明细:共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最大。
- 组合总风险暴露:5个数值,等于各腿希腊字母乘以数量后的代数和。例如组合Delta = 100×Δ₁ − 50×Δ₂ + 80×Δ₃。
- 风险因子暴露占比:5个百分比,各因子值之和为100%。
通过条件:程序无异常退出;单腿希腊字母满足上述数值方向性特征;组合总暴露与手工按公式加权计算结果一致(误差<1e-6);占比合计为100%。
常见问题
- Theta与Rho的量纲:代码中Theta已除以365转换为每日损耗,Rho除以100表示利率变动1个百分点(即100个基点)的影响。若需原始年度值,去掉对应除法即可。
- 空头持仓的希腊字母:空头(数量为负)时,组合希腊字母为负值,表示反向风险暴露。例如空头看涨期权的Delta为负,意味着标的价格上涨时组合价值下降。
- 边界条件:当T接近0时,d1计算会溢出。实际交易中临近到期期权需改用二叉树或数值方法,本案例适用于T>0.01的常规场景。