admin 发表于 昨天 15:25

飓风图代码

import numpy as np
import matplotlib.pyplot as plt

# ============================================================
# 1. 蒙特卡洛模拟函数(备用)
# ============================================================
def monte_carlo_simulation(S0, mu, sigma, T, n_sim=1000, n_steps=252):
    """
    几何布朗运动路径模拟。
    返回形状 (n_sim, n_steps+1) 的价格矩阵。
    """
    dt = T / n_steps
    drift = (mu - 0.5 * sigma**2) * dt
    vol = sigma * np.sqrt(dt)
    Z = np.random.standard_normal((n_sim, n_steps))
    log_returns = drift + vol * Z
    log_cumsum = np.cumsum(log_returns, axis=1)
    paths = np.zeros((n_sim, n_steps + 1))
    paths[:, 0] = S0
    paths[:, 1:] = S0 * np.exp(log_cumsum)
    return paths

# ============================================================
# 2. 目标函数(可替换为任何标量输出)
# ============================================================
def gbm_expected_final_price(params: dict) -> float:
    """
    解析计算 GBM 期末价格的数学期望:E = S0 * exp(mu * T)
    参数:
      params (dict): 包含 'S0', 'mu', 'sigma', 'T' 键的字典。
    返回:
      float: 期望期末价格。
    """
    return params['S0'] * np.exp(params['mu'] * params['T'])

# ---------- 如需模拟版本,取消下面注释即可 ----------
# def gbm_mean_simulation(params: dict, n_sim=2000, n_steps=252) -> float:
#   paths = monte_carlo_simulation(params['S0'], params['mu'], params['sigma'],
#                                    params['T'], n_sim, n_steps)
#   return paths[:, -1].mean()

# ============================================================
# 3. 飓风图绘制函数
# ============================================================
def plot_tornado(
    base_params: dict,
    param_ranges: dict,
    target_func,
    target_label: str = 'Expected Final Price',
    figsize=None
):
    """
    绘制飓风图,展示各参数独立变化时目标函数相对于基准的变化幅度。

    参数:
      base_params : dict
            基准参数值,如 {'S0':100, 'mu':0.05, 'sigma':0.2, 'T':1.0}
      param_ranges : dict
            参数变化比例范围,值为 (低值比例, 高值比例)。
            例如 {'S0': (-0.1, 0.1)} 表示 S0 在基准的 ±10% 之间变动。
      target_func : callable
            接收参数字典,返回标量数值。
      target_label : str
            目标函数的名称,用于轴标签。
      figsize : tuple, optional
            图形大小,默认自适应。

    返回:
      fig, ax : matplotlib 对象。
    """
    # 计算基准情景输出
    base_val = target_func(base_params)

    # 收集每个参数的低/高输出变化量
    data = []
    for param, (low_pct, high_pct) in param_ranges.items():
      # 低情景
      low_params = base_params.copy()
      low_params = base_params * (1 + low_pct)
      low_val = target_func(low_params)
      low_delta = low_val - base_val

      # 高情景
      high_params = base_params.copy()
      high_params = base_params * (1 + high_pct)
      high_val = target_func(high_params)
      high_delta = high_val - base_val

      data.append((param, low_delta, high_delta))

    # 按最大影响宽度排序(降序)
    data.sort(key=lambda x: max(abs(x), abs(x)), reverse=True)

    # 绘图
    if figsize is None:
      figsize = (max(8, len(data)*1.5), max(4, len(data)*0.5))
    fig, ax = plt.subplots(figsize=figsize)
    y_idx = np.arange(len(data))

    for i, (param, low_d, high_d) in enumerate(data):
      ax.barh(i, high_d - low_d, left=low_d, height=0.5,
                color='steelblue', alpha=0.8, edgecolor='black')

    # 基准线
    ax.axvline(x=0, color='black', linewidth=1)
    ax.set_yticks(y_idx)
    ax.set_yticklabels( for d in data])
    ax.set_xlabel(f'Change in {target_label}')
    ax.set_title(f'Sensitivity Tornado Chart\nBase value: {base_val:.2f}')
    ax.grid(axis='x', linestyle=':', alpha=0.6)
    ax.invert_yaxis()# 最宽的放在最上面

    fig.tight_layout()
    return fig, ax

# ============================================================
# 4. 主程序:示例运行
# ============================================================
if __name__ == '__main__':
    # 基准参数
    base = {
      'S0': 100.0,    # 初始价格
      'mu': 0.05,   # 预期收益率 5%
      'sigma': 0.2,   # 波动率 20%
      'T': 1.0      # 期限 1 年
    }

    # 各参数的变化范围(相对于基准的比例)
    ranges = {
      'S0':    (-0.10, 0.10),   # S0 在 90 ~ 110
      'mu':    (-0.50, 0.50),   # mu 在 2.5% ~ 7.5% (相对变化 ±50%)
      'sigma': (-0.20, 0.20),   # sigma 在 0.16 ~ 0.24
      'T':   (-0.20, 0.20),   # T 在 0.8 ~ 1.2 年
    }

    # 绘制飓风图(使用快速解析期望)
    # 若需要基于模拟的期末价格均值,将 target_func 换为 gbm_mean_simulation 即可
    fig, ax = plot_tornado(base, ranges, gbm_expected_final_price,
                           target_label='Expected Final Price')
    plt.show()

页: [1]
查看完整版本: 飓风图代码