AI使用蒙特卡洛模拟对欧洲期权定价
编辑
0
2025-06-29

提示词
需要演示使用模拟方法对欧洲期权进行定价,请给出示例代码。
答案
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import norm
from tqdm import tqdm
class OptionPricing:
"""
欧洲期权定价工具类
支持蒙特卡洛模拟、Black-Scholes解析解和二叉树模型
"""
def __init__(self, S0, K, T, r, sigma, option_type='call'):
"""
初始化期权参数
S0: 标的资产现价
K: 行权价
T: 到期时间(年)
r: 无风险利率
sigma: 年化波动率
option_type: 'call'或'put'
"""
self.S0 = S0
self.K = K
self.T = T
self.r = r
self.sigma = sigma
self.option_type = option_type.lower()
# 验证期权类型
if self.option_type not in ['call', 'put']:
raise ValueError("期权类型必须是'call'或'put'")
def black_scholes(self):
"""计算Black-Scholes期权价格"""
d1 = (np.log(self.S0 / self.K) + (self.r + 0.5 * self.sigma**2) * self.T) / (self.sigma * np.sqrt(self.T))
d2 = d1 - self.sigma * np.sqrt(self.T)
if self.option_type == 'call':
price = self.S0 * norm.cdf(d1) - self.K * np.exp(-self.r * self.T) * norm.cdf(d2)
else: # put
price = self.K * np.exp(-self.r * self.T) * norm.cdf(-d2) - self.S0 * norm.cdf(-d1)
return price
def monte_carlo(self, n_simulations=10000, n_steps=252):
"""
蒙特卡洛模拟期权定价
n_simulations: 模拟路径数量
n_steps: 路径步数
"""
dt = self.T / n_steps
price_paths = np.zeros((n_simulations, n_steps + 1))
price_paths[:, 0] = self.S0
# 生成布朗运动
rv = np.random.normal(size=(n_simulations, n_steps))
# 模拟价格路径
for t in range(1, n_steps + 1):
z = rv[:, t-1]
price_paths[:, t] = price_paths[:, t-1] * np.exp(
(self.r - 0.5 * self.sigma**2) * dt +
self.sigma * np.sqrt(dt) * z
)
# 计算到期日收益
if self.option_type == 'call':
payoffs = np.maximum(price_paths[:, -1] - self.K, 0)
else: # put
payoffs = np.maximum(self.K - price_paths[:, -1], 0)
# 贴现收益
option_price = np.exp(-self.r * self.T) * np.mean(payoffs)
stderr = np.exp(-self.r * self.T) * np.std(payoffs) / np.sqrt(n_simulations)
# 保存模拟路径供可视化使用
self.price_paths = price_paths
self.payoffs = payoffs
self.mc_price = option_price
return option_price, stderr
def binomial_tree(self, n_steps=100):
"""
二叉树模型期权定价
n_steps: 二叉树步数
"""
dt = self.T / n_steps
u = np.exp(self.sigma * np.sqrt(dt)) # 上涨因子
d = 1 / u # 下跌因子
p = (np.exp(self.r * dt) - d) / (u - d) # 风险中性概率
# 初始化到期收益
stock_prices = np.zeros(n_steps + 1)
option_values = np.zeros(n_steps + 1)
# 计算到期时的股票价格和期权价值
for j in range(n_steps + 1):
stock_prices[j] = self.S0 * (u ** j) * (d ** (n_steps - j))
if self.option_type == 'call':
option_values[j] = max(stock_prices[j] - self.K, 0)
else: # put
option_values[j] = max(self.K - stock_prices[j], 0)
# 向后推导期权当前价值
for i in range(n_steps - 1, -1, -1):
for j in range(i + 1):
option_values[j] = np.exp(-self.r * dt) * (p * option_values[j + 1] + (1 - p) * option_values[j])
return option_values[0]
def visualize(self):
"""可视化蒙特卡洛模拟结果"""
if not hasattr(self, 'price_paths') or not hasattr(self, 'payoffs'):
raise RuntimeError("请先运行蒙特卡洛模拟")
# 创建画布
plt.figure(figsize=(15, 10))
# 1. 模拟价格路径
plt.subplot(2, 2, 1)
for i in range(min(100, len(self.price_paths))):
plt.plot(self.price_paths[i], lw=1, alpha=0.3, color='blue')
plt.axhline(self.K, color='red', linestyle='--', label='行权价 (K)')
plt.title(f'蒙特卡洛模拟路径 ({len(self.price_paths)}条路径)')
plt.xlabel('时间步')
plt.ylabel('价格')
plt.legend()
plt.grid(alpha=0.2)
# 2. 到期价格分布
plt.subplot(2, 2, 2)
plt.hist(self.price_paths[:, -1], bins=50, color='skyblue', edgecolor='black', alpha=0.8)
plt.axvline(self.K, color='red', linestyle='--', label='行权价 (K)')
plt.title('到期价格分布')
plt.xlabel('到期价格')
plt.ylabel('频数')
plt.legend()
plt.grid(alpha=0.2)
# 3. 收益分布
plt.subplot(2, 2, 3)
plt.hist(self.payoffs, bins=50, color='lightgreen', edgecolor='black', alpha=0.8)
plt.title('期权收益分布')
plt.xlabel('收益')
plt.ylabel('频数')
plt.grid(alpha=0.2)
# 4. 收敛分析
plt.subplot(2, 2, 4)
cum_avg_payoffs = np.cumsum(self.payoffs) / np.arange(1, len(self.payoffs) + 1)
discount_factor = np.exp(-self.r * self.T)
cumulative_price = discount_factor * cum_avg_payoffs
bs_price = self.black_scholes()
plt.plot(cumulative_price, label='蒙特卡洛价格')
plt.axhline(bs_price, color='red', linestyle='--', label='Black-Scholes价格')
plt.axhline(self.mc_price, color='purple', linestyle='-', label='最终蒙特卡洛价格')
plt.title(f'蒙特卡洛收敛性 (N={len(self.payoffs)})')
plt.xlabel('模拟次数')
plt.ylabel('期权价格')
plt.legend()
plt.grid(alpha=0.2)
plt.tight_layout()
plt.savefig('option_pricing_monte_carlo.png', dpi=300)
plt.show()
# ==========================================
# 测试与比较
# ==========================================
# 设置参数
params = {
'S0': 100, # 当前股票价格
'K': 105, # 行权价
'T': 1, # 到期时间(年)
'r': 0.05, # 无风险利率
'sigma': 0.2, # 年化波动率
'option_type': 'call' # 期权类型: call或put
}
# 创建定价器
option_pricer = OptionPricing(**params)
# 计算Black-Scholes价格
bs_price = option_pricer.black_scholes()
print(f"Black-Scholes价格: {bs_price:.4f}")
# 蒙特卡洛模拟
mc_price, stderr = option_pricer.monte_carlo(n_simulations=10000)
print(f"蒙特卡洛价格: {mc_price:.4f} (标准差: {stderr:.4f})")
print(f"与BS模型的差异: {abs(bs_price - mc_price):.4f} ({abs(bs_price - mc_price)/bs_price*100:.2f}%)")
# 二叉树模型
binomial_price = option_pricer.binomial_tree(n_steps=500)
print(f"二叉树价格(500步): {binomial_price:.4f}")
# 可视化蒙特卡洛结果
option_pricer.visualize()
# ==========================================
# 高级分析: 不同方法收敛性对比
# ==========================================
# 1. 不同模拟次数下的蒙特卡洛价格
simulations = np.arange(100, 100001, 1000)
mc_prices = []
bs_price = option_pricer.black_scholes()
print("\n蒙特卡洛收敛分析...")
for n in tqdm(simulations):
price, _ = option_pricer.monte_carlo(n_simulations=n)
mc_prices.append(price)
# 2. 不同步数下的二叉树价格
steps = np.arange(10, 1001, 10)
binomial_prices = []
print("\n二叉树收敛分析...")
for n in tqdm(steps):
price = option_pricer.binomial_tree(n_steps=n)
binomial_prices.append(price)
# 3. 可视化收敛性比较
plt.figure(figsize=(14, 10))
# 蒙特卡洛收敛
plt.subplot(2, 1, 1)
plt.plot(simulations, mc_prices, 'b-', label='蒙特卡洛价格')
plt.axhline(bs_price, color='r', linestyle='--', label='Black-Scholes')
plt.title('蒙特卡洛模拟收敛性')
plt.xlabel('模拟路径数量')
plt.ylabel('期权价格')
plt.legend()
plt.grid(alpha=0.2)
# 二叉树收敛
plt.subplot(2, 1, 2)
plt.plot(steps, binomial_prices, 'g-', label='二叉树价格')
plt.axhline(bs_price, color='r', linestyle='--', label='Black-Scholes')
plt.title('二叉树模型收敛性')
plt.xlabel('二叉树步数')
plt.ylabel('期权价格')
plt.legend()
plt.grid(alpha=0.2)
plt.tight_layout()
plt.savefig('option_pricing_convergence.png', dpi=300)
plt.show()
# ==========================================
# 希腊字母计算
# ==========================================
def calculate_greeks(option, epsilon=0.01):
"""计算期权的Delta和Gamma"""
# 原始价格
price = option.black_scholes()
# Delta计算
opt_up = OptionPricing(
S0=option.S0 * (1 + epsilon),
K=option.K,
T=option.T,
r=option.r,
sigma=option.sigma,
option_type=option.option_type
)
price_up = opt_up.black_scholes()
opt_down = OptionPricing(
S0=option.S0 * (1 - epsilon),
K=option.K,
T=option.T,
r=option.r,
sigma=option.sigma,
option_type=option.option_type
)
price_down = opt_down.black_scholes()
delta = (price_up - price_down) / (2 * epsilon * option.S0)
# Gamma计算
gamma = (price_up - 2 * price + price_down) / (epsilon**2 * option.S0**2)
return {'Delta': delta, 'Gamma': gamma}
# 计算示例希腊字母
greeks = calculate_greeks(option_pricer)
print(f"\n期权希腊字母:")
print(f"Delta: {greeks['Delta']:.4f}")
print(f"Gamma: {greeks['Gamma']:.4f}")
# ==========================================
# 参数敏感性分析
# ==========================================
def sensitivity_analysis(option, param, values):
"""计算不同参数下的期权价格"""
prices = []
orig_value = getattr(option, param)
for val in values:
setattr(option, param, val)
prices.append(option.black_scholes())
# 恢复原始值
setattr(option, param, orig_value)
return prices
# 波动率敏感性分析
vols = np.linspace(0.1, 0.5, 50)
vol_prices = sensitivity_analysis(option_pricer, 'sigma', vols)
# 到期时间敏感性分析
times = np.linspace(0.1, 2, 50)
time_prices = sensitivity_analysis(option_pricer, 'T', times)
# 可视化
plt.figure(figsize=(14, 6))
plt.subplot(1, 2, 1)
plt.plot(vols, vol_prices, 'b-')
plt.title('波动率敏感性')
plt.xlabel('波动率(σ)')
plt.ylabel('期权价格')
plt.grid(alpha=0.3)
plt.subplot(1, 2, 2)
plt.plot(times, time_prices, 'g-')
plt.title('到期时间敏感性')
plt.xlabel('到期时间(年)')
plt.ylabel('期权价格')
plt.grid(alpha=0.3)
plt.tight_layout()
plt.savefig('option_sensitivity.png', dpi=300)
plt.show()
结果:
提示词没有写模拟方法,好家伙,3种方法。不错。
- 0
- 0
-
赞助
支付宝
微信
-
分享