模块一:风险管理基础框架与市场风险 (4学时)¶

M01H01 金融风险管理概述¶

金融危机影响可视化¶

In [63]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.dates import DateFormatter
import matplotlib.ticker as mtick

# 设置样式
plt.style.use('seaborn-v0_8-whitegrid')
sns.set_palette("deep")

# 创建金融危机前后的标普500指数数据
dates = pd.date_range(start='2007-01-01', end='2010-12-31', freq='B')
np.random.seed(42)  # 确保可重现性

# 模拟金融危机期间的股市走势
base_level = 1500
trend = np.linspace(0, 500, len(dates))
crisis_effect = np.zeros(len(dates))

# 添加危机效应 - 2008年9月雷曼破产后市场大幅下跌
lehman_date = pd.Timestamp('2008-09-15')
crisis_start_idx = np.where(dates >= lehman_date)[0][0]
crisis_duration = 250  # 约一年的交易日
crisis_effect[crisis_start_idx:crisis_start_idx+crisis_duration] = \
    -900 * (1 - np.exp(-np.linspace(0, 5, crisis_duration)))

# 创建指数数据
level = base_level + trend + crisis_effect
# 添加日波动
daily_returns = np.random.normal(0, 1, len(dates)) * (1 + crisis_effect/500).clip(1, 4)
# 提高危机期间的波动率
for i in range(1, len(level)):
    level[i] = level[i-1] * (1 + daily_returns[i]/100)

sp500 = pd.Series(level, index=dates)

# 创建数据框
df = pd.DataFrame({'S&P500': sp500})

# 计算滚动波动率(20天)
df['Volatility'] = df['S&P500'].pct_change().rolling(20).std() * np.sqrt(252) * 100

# 绘制图表
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10), sharex=True)

# 绘制标普500指数
ax1.plot(df.index, df['S&P500'], linewidth=2)
ax1.set_title('S&P 500 During Financial Crisis (2007-2010)', fontsize=15)
ax1.set_ylabel('Index Level', fontsize=12)
ax1.axvline(x=lehman_date, color='r', linestyle='--', alpha=0.7, 
           label='Lehman Bankruptcy (Sep 15, 2008)')
ax1.legend(fontsize=10)

# 绘制波动率
ax2.plot(df.index, df['Volatility'], color='darkred', linewidth=2)
ax2.set_title('Market Volatility (Annualized)', fontsize=15)
ax2.set_ylabel('Volatility (%)', fontsize=12)
ax2.set_xlabel('Date', fontsize=12)
ax2.axvline(x=lehman_date, color='r', linestyle='--', alpha=0.7)
ax2.axhline(y=20, color='orange', linestyle='-.', alpha=0.7, 
           label='High Volatility Threshold')
ax2.yaxis.set_major_formatter(mtick.PercentFormatter())
ax2.legend(fontsize=10)

# 格式化日期
date_form = DateFormatter("%Y-%m")
ax2.xaxis.set_major_formatter(date_form)
fig.autofmt_xdate()

plt.tight_layout()
plt.show()

风险事件时间序列分析¶

In [64]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.dates import DateFormatter
import matplotlib.patches as mpatches

# 设置样式
plt.style.use('seaborn-v0_8-whitegrid')

# 创建主要金融风险事件数据
events = [
    {'date': '2007-02-27', 'event': 'Shanghai Stock Market Crash', 'type': 'Market Risk', 'impact': 6},
    {'date': '2007-08-09', 'event': 'BNP Paribas Freezes Funds', 'type': 'Liquidity Risk', 'impact': 7},
    {'date': '2008-03-16', 'event': 'Bear Stearns Collapse', 'type': 'Credit Risk', 'impact': 8},
    {'date': '2008-09-15', 'event': 'Lehman Brothers Bankruptcy', 'type': 'Credit/Liquidity Risk', 'impact': 10},
    {'date': '2008-09-16', 'event': 'AIG Bailout', 'type': 'Credit Risk', 'impact': 9},
    {'date': '2008-10-03', 'event': 'TARP Enacted', 'type': 'Systemic Risk', 'impact': 7},
    {'date': '2010-05-06', 'event': 'Flash Crash', 'type': 'Market/Operational Risk', 'impact': 5},
    {'date': '2010-05-10', 'event': 'European Stability Mechanism', 'type': 'Sovereign Risk', 'impact': 8},
    {'date': '2011-08-05', 'event': 'US Credit Downgrade', 'type': 'Sovereign Risk', 'impact': 7},
    {'date': '2012-07-26', 'event': 'Draghi "Whatever it takes"', 'type': 'Systemic Risk', 'impact': 6},
    {'date': '2015-08-24', 'event': 'China Market Crash', 'type': 'Market Risk', 'impact': 6},
    {'date': '2016-06-23', 'event': 'Brexit Vote', 'type': 'Political Risk', 'impact': 7},
    {'date': '2020-03-16', 'event': 'COVID-19 Market Crash', 'type': 'Systemic Risk', 'impact': 9}
]

# 转换为DataFrame
df = pd.DataFrame(events)
df['date'] = pd.to_datetime(df['date'])
df = df.sort_values('date')

# 为不同风险类型分配颜色
risk_types = df['type'].unique()
colors = sns.color_palette("bright", len(risk_types))
color_map = dict(zip(risk_types, colors))

# 创建图表
plt.figure(figsize=(14, 8))

# 绘制事件时间线
for i, (_, event) in enumerate(df.iterrows()):
    plt.scatter(event['date'], i, s=event['impact']*50, color=color_map[event['type']], alpha=0.7)
    plt.plot([event['date'], event['date']], [i-0.1, i+0.1], color='black', linewidth=1)
    plt.text(event['date'], i+0.5, event['event'], ha='center', fontsize=11, 
             bbox=dict(facecolor='white', alpha=0.7, boxstyle='round,pad=0.3'))

# 添加Y轴标签
plt.yticks([])
plt.ylabel('Timeline')

# 格式化X轴日期
plt.gca().xaxis.set_major_formatter(DateFormatter('%Y'))
plt.gcf().autofmt_xdate()
plt.xlabel('Year')

# 添加图例
patches = [mpatches.Patch(color=color_map[risk], label=risk) for risk in color_map]
plt.legend(handles=patches, title='Risk Type', loc='upper left')

plt.title('Major Financial Risk Events (2007-2020)', fontsize=16)
plt.tight_layout()
plt.grid(True, alpha=0.3)
plt.show()

M01H02 风险度量基础方法¶

VaR基础实现 (1/4)¶

In [65]:
# import numpy as np
# import pandas as pd
# import matplotlib.pyplot as plt
# import yfinance as yf
# from scipy.stats import norm

# ### 下载股票数据
# tickers = ['AAPL', 'MSFT', 'AMZN', 'GOOGL']
# weights = np.array([0.3, 0.3, 0.2, 0.2])
# start_date = '2021-01-01'
# end_date = '2023-01-01'

# ### 获取历史数据
# data = yf.download(tickers, start=start_date, end=end_date)['Adj Close']
# returns = data.pct_change().dropna()

# ### 计算组合收益
# portfolio_returns = returns.dot(weights)

# ### 设置参数
# confidence_level = 0.95
# investment_value = 1000000  ### 100万投资
In [66]:
# %pip install akshare
In [67]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import akshare as ak
from scipy.stats import norm
from datetime import datetime

### 下载股票数据
tickers = ['AAPL', 'MSFT', 'AMZN', 'GOOGL']
weights = np.array([0.3, 0.3, 0.2, 0.2])
start_date = '2021-01-01'
end_date = '2023-01-01'

### 获取历史数据
# 创建一个空的DataFrame来存储调整后收盘价
data = pd.DataFrame()

# 使用akshare分别获取每只股票的历史数据
for ticker in tickers:
    # 获取美股日线数据(qfq表示前复权,相当于Adj Close)
    stock_data = ak.stock_us_daily(symbol=ticker, adjust="qfq")
    
    # 过滤日期范围
    stock_data['date'] = pd.to_datetime(stock_data['date'])
    mask = (stock_data['date'] >= start_date) & (stock_data['date'] <= end_date)
    filtered_data = stock_data.loc[mask]
    
    # 设置日期为索引
    filtered_data.set_index('date', inplace=True)
    filtered_data.sort_index(inplace=True)
    
    # 添加到主数据框
    data[ticker] = filtered_data['close']

# 计算收益率
returns = data.pct_change().dropna()

### 计算组合收益
portfolio_returns = returns.dot(weights)

### 设置参数
confidence_level = 0.95
investment_value = 1000000  # 100万投资

# 打印结果确认
print(f"数据范围: {data.index.min()} 至 {data.index.max()}")
print(f"数据样本数: {len(returns)}")
print(f"前5个交易日组合收益率:\n{portfolio_returns.head()}")
数据范围: 2021-01-04 00:00:00 至 2022-12-30 00:00:00
数据样本数: 502
前5个交易日组合收益率:
date
2021-01-05    $0.01
2021-01-06   $-0.03
2021-01-07    $0.03
2021-01-08    $0.01
2021-01-11   $-0.02
dtype: float64

VaR基础实现 (2/4)¶

In [68]:
### 计算历史模拟法VaR
historical_var = -np.percentile(portfolio_returns, (1-confidence_level)*100)
historical_var_value = historical_var * investment_value
print(f"95% 历史模拟法VaR: {historical_var:.4f} ({historical_var_value:.2f}元)")

### 计算参数法VaR
mean = np.mean(portfolio_returns)
std = np.std(portfolio_returns)
parametric_var = -(mean + std * norm.ppf(1-confidence_level))
parametric_var_value = parametric_var * investment_value
print(f"95% 参数法VaR: {parametric_var:.4f} ({parametric_var_value:.2f}元)")

### 蒙特卡洛模拟法VaR
np.random.seed(42)  ### 设置随机种子以确保结果可重复
n_simulations = 10000  ### 模拟次数
### 使用历史均值和标准差生成随机收益率
mc_returns = np.random.normal(mean, std, n_simulations)
mc_var = -np.percentile(mc_returns, (1-confidence_level)*100)
mc_var_value = mc_var * investment_value
print(f"95% 蒙特卡洛模拟法VaR: {mc_var:.4f} ({mc_var_value:.2f}元)")
95% 历史模拟法VaR: 0.0305 (30536.88元)
95% 参数法VaR: 0.0304 (30374.36元)
95% 蒙特卡洛模拟法VaR: 0.0306 (30559.44元)

VaR基础实现 (3/4)¶

In [69]:
### 可视化收益率分布与VaR
plt.figure(figsize=(12, 8))

### 绘制收益率分布直方图
plt.hist(portfolio_returns, bins=50, alpha=0.5, density=True, 
         label='历史收益率分布')

### 添加VaR线
plt.axvline(-historical_var, color='r', linestyle='--', 
           label=f'历史模拟法VaR (95%): {historical_var:.4f}')
plt.axvline(-parametric_var, color='g', linestyle='--', 
           label=f'参数法VaR (95%): {parametric_var:.4f}')
plt.axvline(-mc_var, color='b', linestyle='--', 
           label=f'蒙特卡洛模拟法VaR (95%): {mc_var:.4f}')

### 添加正态分布曲线
x = np.linspace(min(portfolio_returns), max(portfolio_returns), 1000)
plt.plot(x, norm.pdf(x, mean, std), 'k-', lw=2, 
         label='正态分布拟合')

plt.legend(fontsize=10)
plt.title('投资组合收益率分布与VaR比较', fontsize=15)
plt.xlabel('日收益率', fontsize=12)
plt.ylabel('概率密度', fontsize=12)
plt.grid(True, alpha=0.3)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 26085 (\N{CJK UNIFIED IDEOGRAPH-65E5}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 25910 (\N{CJK UNIFIED IDEOGRAPH-6536}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 30410 (\N{CJK UNIFIED IDEOGRAPH-76CA}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 29575 (\N{CJK UNIFIED IDEOGRAPH-7387}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 27010 (\N{CJK UNIFIED IDEOGRAPH-6982}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 23494 (\N{CJK UNIFIED IDEOGRAPH-5BC6}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 24230 (\N{CJK UNIFIED IDEOGRAPH-5EA6}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 25237 (\N{CJK UNIFIED IDEOGRAPH-6295}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 36164 (\N{CJK UNIFIED IDEOGRAPH-8D44}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 32452 (\N{CJK UNIFIED IDEOGRAPH-7EC4}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 21512 (\N{CJK UNIFIED IDEOGRAPH-5408}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 20998 (\N{CJK UNIFIED IDEOGRAPH-5206}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 24067 (\N{CJK UNIFIED IDEOGRAPH-5E03}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 19982 (\N{CJK UNIFIED IDEOGRAPH-4E0E}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 27604 (\N{CJK UNIFIED IDEOGRAPH-6BD4}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 36739 (\N{CJK UNIFIED IDEOGRAPH-8F83}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 21382 (\N{CJK UNIFIED IDEOGRAPH-5386}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 21490 (\N{CJK UNIFIED IDEOGRAPH-53F2}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 27169 (\N{CJK UNIFIED IDEOGRAPH-6A21}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 25311 (\N{CJK UNIFIED IDEOGRAPH-62DF}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 27861 (\N{CJK UNIFIED IDEOGRAPH-6CD5}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 21442 (\N{CJK UNIFIED IDEOGRAPH-53C2}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 25968 (\N{CJK UNIFIED IDEOGRAPH-6570}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 33945 (\N{CJK UNIFIED IDEOGRAPH-8499}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 29305 (\N{CJK UNIFIED IDEOGRAPH-7279}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 21345 (\N{CJK UNIFIED IDEOGRAPH-5361}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 27931 (\N{CJK UNIFIED IDEOGRAPH-6D1B}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 27491 (\N{CJK UNIFIED IDEOGRAPH-6B63}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\events.py:82: UserWarning: Glyph 24577 (\N{CJK UNIFIED IDEOGRAPH-6001}) missing from current font.
  func(*args, **kwargs)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 26085 (\N{CJK UNIFIED IDEOGRAPH-65E5}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 25910 (\N{CJK UNIFIED IDEOGRAPH-6536}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 30410 (\N{CJK UNIFIED IDEOGRAPH-76CA}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 29575 (\N{CJK UNIFIED IDEOGRAPH-7387}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27010 (\N{CJK UNIFIED IDEOGRAPH-6982}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 23494 (\N{CJK UNIFIED IDEOGRAPH-5BC6}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 24230 (\N{CJK UNIFIED IDEOGRAPH-5EA6}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 25237 (\N{CJK UNIFIED IDEOGRAPH-6295}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 36164 (\N{CJK UNIFIED IDEOGRAPH-8D44}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 32452 (\N{CJK UNIFIED IDEOGRAPH-7EC4}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21512 (\N{CJK UNIFIED IDEOGRAPH-5408}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 20998 (\N{CJK UNIFIED IDEOGRAPH-5206}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 24067 (\N{CJK UNIFIED IDEOGRAPH-5E03}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 19982 (\N{CJK UNIFIED IDEOGRAPH-4E0E}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27604 (\N{CJK UNIFIED IDEOGRAPH-6BD4}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 36739 (\N{CJK UNIFIED IDEOGRAPH-8F83}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21382 (\N{CJK UNIFIED IDEOGRAPH-5386}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21490 (\N{CJK UNIFIED IDEOGRAPH-53F2}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27169 (\N{CJK UNIFIED IDEOGRAPH-6A21}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 25311 (\N{CJK UNIFIED IDEOGRAPH-62DF}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27861 (\N{CJK UNIFIED IDEOGRAPH-6CD5}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21442 (\N{CJK UNIFIED IDEOGRAPH-53C2}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 25968 (\N{CJK UNIFIED IDEOGRAPH-6570}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 33945 (\N{CJK UNIFIED IDEOGRAPH-8499}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 29305 (\N{CJK UNIFIED IDEOGRAPH-7279}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21345 (\N{CJK UNIFIED IDEOGRAPH-5361}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27931 (\N{CJK UNIFIED IDEOGRAPH-6D1B}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27491 (\N{CJK UNIFIED IDEOGRAPH-6B63}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 24577 (\N{CJK UNIFIED IDEOGRAPH-6001}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)

VaR基础实现 (4/4)¶

In [70]:
### 计算10天VaR (使用平方根法则)
time_horizon = 10  ### 10天持有期
historical_var_10d = historical_var * np.sqrt(time_horizon)
parametric_var_10d = parametric_var * np.sqrt(time_horizon)
mc_var_10d = mc_var * np.sqrt(time_horizon)

print("\n10天持有期VaR (平方根法则):")
print(f"历史模拟法VaR (10天): {historical_var_10d:.4f} ({historical_var_10d*investment_value:.2f}元)")
print(f"参数法VaR (10天): {parametric_var_10d:.4f} ({parametric_var_10d*investment_value:.2f}元)")
print(f"蒙特卡洛模拟法VaR (10天): {mc_var_10d:.4f} ({mc_var_10d*investment_value:.2f}元)")

### 计算各资产对组合VaR的贡献
cov_matrix = returns.cov()
portfolio_variance = weights.T @ cov_matrix @ weights
portfolio_std = np.sqrt(portfolio_variance)

### 边际贡献
marginal_contrib = (cov_matrix @ weights) / portfolio_std
component_var = weights * marginal_contrib * norm.ppf(confidence_level)
percent_contrib = component_var / np.sum(component_var) * 100

var_contrib = pd.DataFrame({
    'Asset': tickers,
    'Weight': weights * 100,
    'VaR Contribution': component_var,
    'Contribution %': percent_contrib
})

print("\n各资产VaR贡献:")
print(var_contrib)
10天持有期VaR (平方根法则):
历史模拟法VaR (10天): 0.0966 (96566.08元)
参数法VaR (10天): 0.0961 (96052.15元)
蒙特卡洛模拟法VaR (10天): 0.0966 (96637.43元)

各资产VaR贡献:
       Asset  Weight  VaR Contribution  Contribution %
AAPL    AAPL  $30.00             $0.01          $28.99
MSFT    MSFT  $30.00             $0.01          $28.57
AMZN    AMZN  $20.00             $0.01          $22.69
GOOGL  GOOGL  $20.00             $0.01          $19.75

条件风险价值的计算方法(Monte-Carlo)¶

In [71]:
### 历史模拟法ES
def calculate_historical_es(returns, alpha=0.95):
    var = -np.percentile(returns, (1-alpha)*100)
    es = -np.mean(returns[returns <= -var])
    return es

### 参数法ES (正态分布假设)
def calculate_parametric_es(mu, sigma, alpha=0.95):
    z_score = norm.ppf(1-alpha)
    es = -(mu + sigma * norm.pdf(z_score)/(1-alpha))
    return es

### 计算实例
hist_es = calculate_historical_es(portfolio_returns)
para_es = calculate_parametric_es(
    np.mean(portfolio_returns), 
    np.std(portfolio_returns))

M01H03 市场风险模型¶

模型比较代码 (1/5)¶

In [72]:
# import numpy as np
# import pandas as pd
# import matplotlib.pyplot as plt
# from scipy.stats import norm, t
# import yfinance as yf

# # 下载数据
# symbol = 'SPY'  # 标普500ETF
# data = yf.download(symbol, start='2018-01-01', end='2023-01-01')
# returns = data['Adj Close'].pct_change().dropna()

# print(f"数据点数: {len(returns)}")
# print(f"平均收益率: {np.mean(returns)*100:.4f}%")
# print(f"收益率标准差: {np.std(returns)*100:.4f}%")
# print(f"最小收益率: {min(returns)*100:.4f}%")
# print(f"最大收益率: {max(returns)*100:.4f}%")
# print(f"偏度: {returns.skew():.4f}")
# print(f"峰度: {returns.kurtosis():.4f}")

# # 检查是否存在异常值
# plt.figure(figsize=(12, 5))
# plt.subplot(1, 2, 1)
# plt.plot(returns.index, returns, linewidth=1)
# plt.title('SPY每日收益率')
# plt.grid(True)

# plt.subplot(1, 2, 2)
# plt.hist(returns, bins=50, alpha=0.75)
# plt.title('收益率分布')
# plt.grid(True)
# plt.tight_layout()
# plt.show()
In [73]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import norm, t
import akshare as ak

# 下载数据
symbol = 'SPY'  # 标普500ETF
stock_data = ak.stock_us_daily(symbol=symbol, adjust="qfq")  # qfq表示前复权数据

# 处理日期范围
stock_data['date'] = pd.to_datetime(stock_data['date'])
mask = (stock_data['date'] >= '2018-01-01') & (stock_data['date'] <= '2023-01-01')
data = stock_data.loc[mask].copy()

# 按日期排序
data.sort_values('date', inplace=True)
data.set_index('date', inplace=True)

# 计算收益率
returns = data['close'].pct_change().dropna()

# 打印统计信息
print(f"数据点数: {len(returns)}")
print(f"平均收益率: {np.mean(returns)*100:.4f}%")
print(f"收益率标准差: {np.std(returns)*100:.4f}%")
print(f"最小收益率: {min(returns)*100:.4f}%")
print(f"最大收益率: {max(returns)*100:.4f}%")
print(f"偏度: {returns.skew():.4f}")
print(f"峰度: {returns.kurtosis():.4f}")

# 检查是否存在异常值
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.plot(returns.index, returns, linewidth=1)
plt.title('SPY每日收益率')
plt.grid(True)

plt.subplot(1, 2, 2)
plt.hist(returns, bins=50, alpha=0.75)
plt.title('收益率分布')
plt.grid(True)
plt.tight_layout()
plt.show()
数据点数: 1258
平均收益率: 0.0505%
收益率标准差: 1.5136%
最小收益率: -12.4769%
最大收益率: 10.5631%
偏度: -0.5074
峰度: 11.5832
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1861880576.py:43: UserWarning: Glyph 27599 (\N{CJK UNIFIED IDEOGRAPH-6BCF}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1861880576.py:43: UserWarning: Glyph 26085 (\N{CJK UNIFIED IDEOGRAPH-65E5}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1861880576.py:43: UserWarning: Glyph 25910 (\N{CJK UNIFIED IDEOGRAPH-6536}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1861880576.py:43: UserWarning: Glyph 30410 (\N{CJK UNIFIED IDEOGRAPH-76CA}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1861880576.py:43: UserWarning: Glyph 29575 (\N{CJK UNIFIED IDEOGRAPH-7387}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1861880576.py:43: UserWarning: Glyph 20998 (\N{CJK UNIFIED IDEOGRAPH-5206}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1861880576.py:43: UserWarning: Glyph 24067 (\N{CJK UNIFIED IDEOGRAPH-5E03}) missing from current font.
  plt.tight_layout()
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27599 (\N{CJK UNIFIED IDEOGRAPH-6BCF}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 26085 (\N{CJK UNIFIED IDEOGRAPH-65E5}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 25910 (\N{CJK UNIFIED IDEOGRAPH-6536}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 30410 (\N{CJK UNIFIED IDEOGRAPH-76CA}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 29575 (\N{CJK UNIFIED IDEOGRAPH-7387}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 20998 (\N{CJK UNIFIED IDEOGRAPH-5206}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 24067 (\N{CJK UNIFIED IDEOGRAPH-5E03}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)

模型比较代码 (2/5)¶

In [74]:
# 设置参数
confidence_level = 0.99  # 使用99%置信水平
position = 1000000  # 100万美元仓位
n_simulations = 10000  # 蒙特卡洛模拟次数

# 1. 参数法VaR - 正态分布
mu = np.mean(returns)
sigma = np.std(returns)
var_normal = -position * (mu + sigma * norm.ppf(1-confidence_level))

# 同时计算95%的VaR
var_normal_95 = -position * (mu + sigma * norm.ppf(1-0.95))

# 2. 参数法VaR - t分布
# 使用t分布拟合数据
params = t.fit(returns)
df, loc, scale = params  # 得到自由度、位置和尺度参数
var_t = -position * (loc + scale * t.ppf(1-confidence_level, df))
var_t_95 = -position * (loc + scale * t.ppf(1-0.95, df))

print(f"t分布拟合参数: 自由度={df:.2f}, 位置={loc:.6f}, 尺度={scale:.6f}")

# 3. 历史模拟法
var_hist = -position * np.percentile(returns, (1-confidence_level)*100)
var_hist_95 = -position * np.percentile(returns, (1-0.95)*100)

# 计算条件尾部期望(Expected Shortfall)
es_hist = -position * returns[returns <= -var_hist/position].mean()
t分布拟合参数: 自由度=2.65, 位置=0.001154, 尺度=0.008563

模型比较代码 (3/5)¶

In [75]:
# 4. 蒙特卡洛模拟 - 正态分布
np.random.seed(42)  # 设置随机种子确保结果可重复
sim_returns_normal = np.random.normal(mu, sigma, n_simulations)
var_mc_normal = -position * np.percentile(sim_returns_normal, (1-confidence_level)*100)
var_mc_normal_95 = -position * np.percentile(sim_returns_normal, (1-0.95)*100)

# 5. 蒙特卡洛模拟 - t分布
sim_returns_t = t.rvs(df, loc=loc, scale=scale, size=n_simulations)
var_mc_t = -position * np.percentile(sim_returns_t, (1-confidence_level)*100)
var_mc_t_95 = -position * np.percentile(sim_returns_t, (1-0.95)*100)

# 6. 加权历史模拟法
# 使用指数衰减权重使最近数据权重更高
lambda_factor = 0.94  # BRW方法中常用的衰减因子
weights = np.array([(1-lambda_factor) * lambda_factor**(len(returns)-i-1) 
                    for i in range(len(returns))])
weights = weights / sum(weights)  # 标准化权重

# 按权重排序收益率
sorted_indices = np.argsort(returns)
sorted_returns = returns.iloc[sorted_indices]
cumulative_weights = np.cumsum(weights[sorted_indices])

# 找到对应置信水平的收益率
var_weight_index = np.searchsorted(cumulative_weights, 1-confidence_level)
var_weighted = -position * sorted_returns.iloc[var_weight_index]
var_weight_index_95 = np.searchsorted(cumulative_weights, 1-0.95)
var_weighted_95 = -position * sorted_returns.iloc[var_weight_index_95]

模型比较代码 (4/5)¶

In [76]:
# 结果对比
results = pd.DataFrame({
    'Method': ['正态分布参数法', 't分布参数法', '历史模拟法', 
             '蒙特卡洛(正态)', '蒙特卡洛(t分布)', '加权历史模拟法'],
    'VaR_99%': [var_normal, var_t, var_hist, 
                var_mc_normal, var_mc_t, var_weighted],
    'VaR_95%': [var_normal_95, var_t_95, var_hist_95, 
               var_mc_normal_95, var_mc_t_95, var_weighted_95]
})

# 计算方法间的差异百分比
base_method = '历史模拟法'  # 使用历史模拟法作为基准
base_var_99 = results.loc[results['Method'] == base_method, 'VaR_99%'].values[0]
base_var_95 = results.loc[results['Method'] == base_method, 'VaR_95%'].values[0]

results['Diff_99%'] = (results['VaR_99%'] - base_var_99) / base_var_99 * 100
results['Diff_95%'] = (results['VaR_95%'] - base_var_95) / base_var_95 * 100

# 格式化输出
pd.set_option('display.float_format', '${:.2f}'.format)
print("\n不同VaR计算方法比较(99%置信水平):")
print(results[['Method', 'VaR_99%', 'Diff_99%', 'VaR_95%', 'Diff_95%']])

# 可视化VaR比较
plt.figure(figsize=(14, 6))
plt.bar(results['Method'], results['VaR_99%'], alpha=0.7)
plt.title('不同方法99% VaR比较 (100万美元头寸)', fontsize=15)
plt.xticks(rotation=45, ha='right')
plt.ylabel('VaR (美元)', fontsize=12)
plt.grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.show()
不同VaR计算方法比较(99%置信水平):
      Method   VaR_99%  Diff_99%   VaR_95%  Diff_95%
0    正态分布参数法 $34707.89   $-15.51 $24392.53     $3.64
1     t分布参数法 $42126.53     $2.56 $20124.76   $-14.50
2      历史模拟法 $41077.01     $0.00 $23536.72     $0.00
3   蒙特卡洛(正态) $34620.02   $-15.72 $24543.96     $4.28
4  蒙特卡洛(t分布) $41131.40     $0.13 $19303.71   $-17.98
5    加权历史模拟法 $25560.91   $-37.77 $21572.03    $-8.35
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 27491 (\N{CJK UNIFIED IDEOGRAPH-6B63}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 24577 (\N{CJK UNIFIED IDEOGRAPH-6001}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 20998 (\N{CJK UNIFIED IDEOGRAPH-5206}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 24067 (\N{CJK UNIFIED IDEOGRAPH-5E03}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 21442 (\N{CJK UNIFIED IDEOGRAPH-53C2}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 25968 (\N{CJK UNIFIED IDEOGRAPH-6570}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 27861 (\N{CJK UNIFIED IDEOGRAPH-6CD5}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 21382 (\N{CJK UNIFIED IDEOGRAPH-5386}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 21490 (\N{CJK UNIFIED IDEOGRAPH-53F2}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 27169 (\N{CJK UNIFIED IDEOGRAPH-6A21}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 25311 (\N{CJK UNIFIED IDEOGRAPH-62DF}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 33945 (\N{CJK UNIFIED IDEOGRAPH-8499}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 29305 (\N{CJK UNIFIED IDEOGRAPH-7279}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 21345 (\N{CJK UNIFIED IDEOGRAPH-5361}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 27931 (\N{CJK UNIFIED IDEOGRAPH-6D1B}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 21152 (\N{CJK UNIFIED IDEOGRAPH-52A0}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 26435 (\N{CJK UNIFIED IDEOGRAPH-6743}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 32654 (\N{CJK UNIFIED IDEOGRAPH-7F8E}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 20803 (\N{CJK UNIFIED IDEOGRAPH-5143}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 19981 (\N{CJK UNIFIED IDEOGRAPH-4E0D}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 21516 (\N{CJK UNIFIED IDEOGRAPH-540C}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 26041 (\N{CJK UNIFIED IDEOGRAPH-65B9}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 27604 (\N{CJK UNIFIED IDEOGRAPH-6BD4}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 36739 (\N{CJK UNIFIED IDEOGRAPH-8F83}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 19975 (\N{CJK UNIFIED IDEOGRAPH-4E07}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 22836 (\N{CJK UNIFIED IDEOGRAPH-5934}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\1847955310.py:31: UserWarning: Glyph 23544 (\N{CJK UNIFIED IDEOGRAPH-5BF8}) missing from current font.
  plt.tight_layout()
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27491 (\N{CJK UNIFIED IDEOGRAPH-6B63}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 24577 (\N{CJK UNIFIED IDEOGRAPH-6001}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 20998 (\N{CJK UNIFIED IDEOGRAPH-5206}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 24067 (\N{CJK UNIFIED IDEOGRAPH-5E03}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21442 (\N{CJK UNIFIED IDEOGRAPH-53C2}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 25968 (\N{CJK UNIFIED IDEOGRAPH-6570}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27861 (\N{CJK UNIFIED IDEOGRAPH-6CD5}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21382 (\N{CJK UNIFIED IDEOGRAPH-5386}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21490 (\N{CJK UNIFIED IDEOGRAPH-53F2}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27169 (\N{CJK UNIFIED IDEOGRAPH-6A21}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 25311 (\N{CJK UNIFIED IDEOGRAPH-62DF}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 33945 (\N{CJK UNIFIED IDEOGRAPH-8499}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 29305 (\N{CJK UNIFIED IDEOGRAPH-7279}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21345 (\N{CJK UNIFIED IDEOGRAPH-5361}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27931 (\N{CJK UNIFIED IDEOGRAPH-6D1B}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21152 (\N{CJK UNIFIED IDEOGRAPH-52A0}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 26435 (\N{CJK UNIFIED IDEOGRAPH-6743}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 32654 (\N{CJK UNIFIED IDEOGRAPH-7F8E}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 20803 (\N{CJK UNIFIED IDEOGRAPH-5143}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 19981 (\N{CJK UNIFIED IDEOGRAPH-4E0D}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21516 (\N{CJK UNIFIED IDEOGRAPH-540C}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 26041 (\N{CJK UNIFIED IDEOGRAPH-65B9}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27604 (\N{CJK UNIFIED IDEOGRAPH-6BD4}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 36739 (\N{CJK UNIFIED IDEOGRAPH-8F83}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 19975 (\N{CJK UNIFIED IDEOGRAPH-4E07}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 22836 (\N{CJK UNIFIED IDEOGRAPH-5934}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 23544 (\N{CJK UNIFIED IDEOGRAPH-5BF8}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)

模型比较代码 (5/5)¶

In [77]:
# 可视化分布对比
plt.figure(figsize=(12, 6))
plt.hist(returns, bins=50, density=True, alpha=0.5, label='实际收益率')

# 拟合分布
x = np.linspace(min(returns), max(returns), 1000)
plt.plot(x, norm.pdf(x, mu, sigma), 'r-', lw=2, label='正态分布')
plt.plot(x, t.pdf(x, df, loc, scale), 'g-', lw=2, label='t分布')

# 添加VaR标记线
plt.axvline(x=-var_normal/position, color='r', linestyle='--', 
           label=f'正态分布99% VaR: ${var_normal:.0f}')
plt.axvline(x=-var_t/position, color='g', linestyle='--', 
           label=f't分布99% VaR: ${var_t:.0f}')
plt.axvline(x=-var_hist/position, color='b', linestyle='--', 
           label=f'历史模拟99% VaR: ${var_hist:.0f}')

plt.legend()
plt.title('收益率分布拟合与VaR比较', fontsize=15)
plt.xlabel('收益率', fontsize=12)
plt.ylabel('概率密度', fontsize=12)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

# 回测分析(简化版)
exceed_normal = sum(returns < -var_normal_95/position)
exceed_t = sum(returns < -var_t_95/position)
exceed_hist = sum(returns < -var_hist_95/position)

expected_exceeds = len(returns) * (1-0.95)  # 期望违例数
print(f"\n95%置信水平回测结果:")
print(f"样本数量: {len(returns)}")
print(f"期望违例数: {expected_exceeds:.1f}")
print(f"正态分布违例数: {exceed_normal} ({exceed_normal/len(returns)*100:.2f}%)")
print(f"t分布违例数: {exceed_t} ({exceed_t/len(returns)*100:.2f}%)")
print(f"历史模拟违例数: {exceed_hist} ({exceed_hist/len(returns)*100:.2f}%)")
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 25910 (\N{CJK UNIFIED IDEOGRAPH-6536}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 30410 (\N{CJK UNIFIED IDEOGRAPH-76CA}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 29575 (\N{CJK UNIFIED IDEOGRAPH-7387}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 27010 (\N{CJK UNIFIED IDEOGRAPH-6982}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 23494 (\N{CJK UNIFIED IDEOGRAPH-5BC6}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 24230 (\N{CJK UNIFIED IDEOGRAPH-5EA6}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 20998 (\N{CJK UNIFIED IDEOGRAPH-5206}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 24067 (\N{CJK UNIFIED IDEOGRAPH-5E03}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 25311 (\N{CJK UNIFIED IDEOGRAPH-62DF}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 21512 (\N{CJK UNIFIED IDEOGRAPH-5408}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 19982 (\N{CJK UNIFIED IDEOGRAPH-4E0E}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 27604 (\N{CJK UNIFIED IDEOGRAPH-6BD4}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 36739 (\N{CJK UNIFIED IDEOGRAPH-8F83}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 23454 (\N{CJK UNIFIED IDEOGRAPH-5B9E}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 38469 (\N{CJK UNIFIED IDEOGRAPH-9645}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 27491 (\N{CJK UNIFIED IDEOGRAPH-6B63}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 24577 (\N{CJK UNIFIED IDEOGRAPH-6001}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 21382 (\N{CJK UNIFIED IDEOGRAPH-5386}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 21490 (\N{CJK UNIFIED IDEOGRAPH-53F2}) missing from current font.
  plt.tight_layout()
C:\Users\wukek\AppData\Local\Temp\ipykernel_178052\2517428418.py:23: UserWarning: Glyph 27169 (\N{CJK UNIFIED IDEOGRAPH-6A21}) missing from current font.
  plt.tight_layout()
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 25910 (\N{CJK UNIFIED IDEOGRAPH-6536}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 30410 (\N{CJK UNIFIED IDEOGRAPH-76CA}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 29575 (\N{CJK UNIFIED IDEOGRAPH-7387}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 27010 (\N{CJK UNIFIED IDEOGRAPH-6982}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 23494 (\N{CJK UNIFIED IDEOGRAPH-5BC6}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 24230 (\N{CJK UNIFIED IDEOGRAPH-5EA6}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 21512 (\N{CJK UNIFIED IDEOGRAPH-5408}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 19982 (\N{CJK UNIFIED IDEOGRAPH-4E0E}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 23454 (\N{CJK UNIFIED IDEOGRAPH-5B9E}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
d:\Users\wukek\anaconda3\Lib\site-packages\IPython\core\pylabtools.py:152: UserWarning: Glyph 38469 (\N{CJK UNIFIED IDEOGRAPH-9645}) missing from current font.
  fig.canvas.print_figure(bytes_io, **kw)
95%置信水平回测结果:
样本数量: 1258
期望违例数: 62.9
正态分布违例数: 60 (4.77%)
t分布违例数: 85 (6.76%)
历史模拟违例数: 63 (5.01%)

M01H04 市场风险高级模型¶

期权Greeks计算代码 (1/5)¶

In [78]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import norm

# Black-Scholes期权定价模型
def bs_call_price(S, K, T, r, sigma):
    """
    计算欧式看涨期权价格
    
    参数:
    S: 标的资产价格
    K: 行权价
    T: 到期时间(年)
    r: 无风险利率
    sigma: 波动率
    
    返回:
    看涨期权价格
    """
    d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
    d2 = d1 - sigma*np.sqrt(T)
    return S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)

def bs_put_price(S, K, T, r, sigma):
    """
    计算欧式看跌期权价格
    
    参数与看涨期权相同
    """
    d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
    d2 = d1 - sigma*np.sqrt(T)
    return K*np.exp(-r*T)*norm.cdf(-d2) - S*norm.cdf(-d1)

期权Greeks计算代码 (2/5)¶

In [79]:
# 计算希腊字母
def bs_greeks(S, K, T, r, sigma, option_type='call'):
    """
    计算欧式期权的希腊字母
    
    参数:
    S: 标的资产价格
    K: 行权价
    T: 到期时间(年)
    r: 无风险利率
    sigma: 波动率
    option_type: 'call'表示看涨期权,'put'表示看跌期权
    
    返回:
    包含期权价格和希腊字母的字典
    """
    d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
    d2 = d1 - sigma*np.sqrt(T)
    
    if option_type == 'call':
        price = bs_call_price(S, K, T, r, sigma)
        delta = norm.cdf(d1)
        theta = -(S*norm.pdf(d1)*sigma)/(2*np.sqrt(T)) - r*K*np.exp(-r*T)*norm.cdf(d2)
    else:  # 'put'
        price = bs_put_price(S, K, T, r, sigma)
        delta = norm.cdf(d1) - 1
        theta = -(S*norm.pdf(d1)*sigma)/(2*np.sqrt(T)) + r*K*np.exp(-r*T)*norm.cdf(-d2)
    
    gamma = norm.pdf(d1) / (S*sigma*np.sqrt(T))
    vega = S * norm.pdf(d1) * np.sqrt(T) / 100  # 对应波动率变动1%
    rho = K * T * np.exp(-r*T) * (norm.cdf(d2) if option_type=='call' else -norm.cdf(-d2)) / 100  # 对应利率变动1%
    
    return {'price': price, 'delta': delta, 'gamma': gamma, 
            'vega': vega, 'theta': theta, 'rho': rho}

期权Greeks计算代码 (3/5)¶

In [80]:
# 参数设置
S = 100    # 标的价格
K = 100    # 行权价
T = 0.5    # 到期时间(年)
r = 0.05   # 无风险利率
sigma = 0.2 # 波动率

# 计算期权价格和希腊字母
call_greeks = bs_greeks(S, K, T, r, sigma, 'call')
put_greeks = bs_greeks(S, K, T, r, sigma, 'put')

print("看涨期权:")
for greek, value in call_greeks.items():
    print(f"{greek}: {value:.6f}")

print("\n看跌期权:")
for greek, value in put_greeks.items():
    print(f"{greek}: {value:.6f}")

# 创建Greeks变化表
print("\nGreeks随标的价格变化表:")
prices = np.linspace(80, 120, 9)
greeks_data = []

for price in prices:
    call_greeks = bs_greeks(price, K, T, r, sigma, 'call')
    greeks_data.append({
        'S': price,
        'Call_Price': call_greeks['price'],
        'Call_Delta': call_greeks['delta'],
        'Call_Gamma': call_greeks['gamma'],
        'Call_Vega': call_greeks['vega'],
        'Call_Theta': call_greeks['theta']
    })

greeks_df = pd.DataFrame(greeks_data)
print(greeks_df.round(4))
看涨期权:
price: 6.888729
delta: 0.597734
gamma: 0.027359
vega: 0.273587
theta: -8.115968
rho: 0.264424

看跌期权:
price: 4.419720
delta: -0.402266
gamma: 0.027359
vega: 0.273587
theta: -3.239418
rho: -0.223231

Greeks随标的价格变化表:
        S  Call_Price  Call_Delta  Call_Gamma  Call_Vega  Call_Theta
0  $80.00       $0.46       $0.09       $0.01      $0.09      $-2.21
1  $85.00       $1.13       $0.18       $0.02      $0.16      $-3.92
2  $90.00       $2.35       $0.31       $0.03      $0.22      $-5.76
3  $95.00       $4.25       $0.45       $0.03      $0.27      $-7.27
4 $100.00       $6.89       $0.60       $0.03      $0.27      $-8.12
5 $105.00      $10.20       $0.72       $0.02      $0.25      $-8.26
6 $110.00      $14.08       $0.82       $0.02      $0.20      $-7.87
7 $115.00      $18.37       $0.89       $0.01      $0.15      $-7.23
8 $120.00      $22.95       $0.94       $0.01      $0.10      $-6.56

期权Greeks计算代码 (4/5)¶

In [81]:
# Delta中性对冲
stock_position = 100  # 持有100股标的
call_contracts = 2    # 持有2张看涨期权合约(每张控制100股)
shares_per_contract = 100  # 每张期权合约对应的股数

portfolio_delta = stock_position + call_contracts * shares_per_contract * call_greeks['delta']
hedge_contracts = -portfolio_delta / (shares_per_contract * put_greeks['delta'])

print(f"\n当前组合Delta: {portfolio_delta:.2f}")
print(f"实现Delta中性需要: {hedge_contracts:.2f} 份看跌期权合约")

# 模拟Delta对冲P&L
def simulate_delta_hedge(S, K, T, r, sigma, days, price_path=None, hedge_freq=1):
    """
    模拟Delta对冲策略的损益
    
    参数:
    S, K, T, r, sigma: 与前面相同
    days: 模拟天数
    price_path: 预定义价格路径,如果为None则生成随机路径
    hedge_freq: 调整对冲头寸的频率(天)
    
    返回:
    对冲损益结果
    """
    dt = 1/252  # 一个交易日
    n_steps = days
    
    # 生成或使用价格路径
    if price_path is None:
        np.random.seed(42)
        price_path = [S]
        for i in range(n_steps):
            price_path.append(price_path[-1] * np.exp((r - 0.5*sigma**2)*dt + 
                                                    sigma*np.sqrt(dt)*np.random.normal()))
    
    # 初始化
    option_price = bs_call_price(S, K, T, r, sigma)
    cash = -option_price  # 卖出看涨期权
    delta = bs_greeks(S, K, T, r, sigma, 'call')['delta']
    stock = delta * S  # 买入Delta数量的标的
    cash -= stock  # 支付标的购买成本
    
    prices = []
    portfolio_values = []
    deltas = []
    
    # 模拟对冲过程
    for day in range(1, n_steps+1):
        # 更新价格和时间
        current_price = price_path[day]
        current_T = T - day*dt
        
        # 记录当前状态
        prices.append(current_price)
        current_option_price = bs_call_price(current_price, K, current_T, r, sigma)
        stock_value = delta * current_price
        portfolio_value = cash + stock_value - current_option_price
        portfolio_values.append(portfolio_value)
        deltas.append(delta)
        
        # 根据频率调整对冲
        if day % hedge_freq == 0 and current_T > dt:
            # 计算新的Delta
            new_delta = bs_greeks(current_price, K, current_T, r, sigma, 'call')['delta']
            
            # 调整股票头寸
            adjustment = new_delta - delta
            cash -= adjustment * current_price  # 买入更多股票需要支付现金
            delta = new_delta
    
    return {
        'prices': prices,
        'portfolio_values': portfolio_values,
        'deltas': deltas
    }
当前组合Delta: 287.56
实现Delta中性需要: 7.15 份看跌期权合约

期权Greeks计算代码 (5/5)¶

In [82]:
# 可视化Delta曲线
spot_range = np.linspace(80, 120, 100)
call_deltas = [bs_greeks(s, K, T, r, sigma, 'call')['delta'] for s in spot_range]
put_deltas = [bs_greeks(s, K, T, r, sigma, 'put')['delta'] for s in spot_range]

plt.figure(figsize=(12, 6))
plt.plot(spot_range, call_deltas, 'b-', label='Call Delta')
plt.plot(spot_range, put_deltas, 'r-', label='Put Delta')
plt.axvline(x=K, color='g', linestyle='--', label='Strike Price')
plt.axhline(y=0, color='k', linestyle='-')
plt.grid(True)
plt.legend()
plt.title('Option Delta vs. Underlying Price')
plt.xlabel('Underlying Price')
plt.ylabel('Delta')

# 可视化Delta对冲P&L
days_to_simulate = 30
price_move = 0.005  # 每日0.5%的价格变动

# 生成价格路径
price_path = [S]
for i in range(days_to_simulate):
    price_path.append(price_path[-1] * (1 + np.random.normal(0, price_move)))

# 模拟不同对冲频率
daily_hedge = simulate_delta_hedge(S, K, T, r, sigma, days_to_simulate, price_path, hedge_freq=1)
weekly_hedge = simulate_delta_hedge(S, K, T, r, sigma, days_to_simulate, price_path, hedge_freq=5)

plt.figure(figsize=(12, 8))
plt.subplot(2, 1, 1)
plt.plot(range(days_to_simulate), daily_hedge['portfolio_values'], 'b-', label='Daily Hedging')
plt.plot(range(days_to_simulate), weekly_hedge['portfolio_values'], 'r-', label='Weekly Hedging')
plt.legend()
plt.title('Delta Hedging P&L')
plt.ylabel('P&L')
plt.grid(True)

plt.subplot(2, 1, 2)
plt.plot(range(days_to_simulate+1), price_path, 'g-')
plt.title('Underlying Price Path')
plt.xlabel('Days')
plt.ylabel('Price')
plt.grid(True)

plt.tight_layout()
plt.show()