🚀 AI 一键生成 qmt 策略代码

如何在 QMT 中计算期权的 Delta、Gamma、Vega 等希腊字母指标?

qmt | 发布时间: 2025/12/5
以下内容由 EasyQuant 生成。

问题描述

请告诉我如何计算一个期权的 Delta 值。

解决方案

在 QMT (Quant Trader) 平台中,虽然 API 提供了计算期权理论价格 (bsm_price) 和隐含波动率 (bsm_iv) 的函数,但没有直接提供计算 Delta 等希腊字母(Greeks)的原生接口

因此,我们需要基于 Black-Scholes-Merton (BSM) 模型,利用 Python 的数学库(如 scipynumpy)自行编写计算逻辑。

计算 Delta 的核心逻辑

Delta ($\Delta$) 衡量的是期权价格相对于标的资产价格变动的敏感度。基于 BSM 模型,其计算公式如下:

  1. 计算 $d_1$:
    $$d_1 = \frac{\ln(S / K) + (r + \sigma^2 / 2)T}{\sigma \sqrt{T}}$$

  2. 计算 Delta:

    • 认购期权 (Call): $\Delta = N(d_1)$
    • 认沽期权 (Put): $\Delta = N(d_1) - 1$

其中:

  • $S$: 标的资产当前价格
  • $K$: 行权价
  • $r$: 无风险利率
  • $\sigma$: 波动率(通常使用隐含波动率 IV)
  • $T$: 距离到期时间(年化)
  • $N(x)$: 标准正态分布的累积分布函数

QMT 策略代码实现

以下是一个完整的 Python 策略示例,展示了如何获取 QMT 的行情数据、期权详情、隐含波动率,并计算 Delta 值。

# -*- coding: gbk -*-
import numpy as np
from scipy.stats import norm
import datetime

def init(ContextInfo):
    # 设置要计算 Delta 的期权代码 (示例:沪深300ETF期权)
    # 请确保在“数据管理”中下载了对应的期权和标的数据
    ContextInfo.option_code = '10006234.SHO' 
    
    # 设置标的代码 (示例:华泰柏瑞沪深300ETF)
    ContextInfo.underlying_code = '510300.SH'
    
    # 订阅行情
    ContextInfo.subscribe_quote(ContextInfo.option_code, 'tick', 'follow')
    ContextInfo.subscribe_quote(ContextInfo.underlying_code, 'tick', 'follow')

def handlebar(ContextInfo):
    # 仅在最后一根K线(实时行情)计算,避免回测时重复大量计算
    if not ContextInfo.is_last_bar():
        return

    # 1. 获取期权合约详细信息 (行权价 K, 到期日等)
    detail = ContextInfo.get_option_detail_data(ContextInfo.option_code)
    if not detail:
        print(f"未找到合约 {ContextInfo.option_code} 的详细信息")
        return
    
    strike_price = detail['OptExercisePrice']  # 行权价 K
    expire_date_str = str(detail['ExpireDate']) # 到期日 YYYYMMDD
    option_type = detail['optType'] # 'CALL' 或 'PUT'
    
    # 2. 获取标的资产当前价格 S
    # 使用 get_market_data_ex 获取最新 tick 数据
    tick_data = ContextInfo.get_market_data_ex(
        [], 
        [ContextInfo.underlying_code], 
        period='tick', 
        count=1, 
        subscribe=True
    )
    
    if ContextInfo.underlying_code not in tick_data or tick_data[ContextInfo.underlying_code].empty:
        return
        
    # 获取标的最新价
    S = tick_data[ContextInfo.underlying_code].iloc[-1]['lastPrice']
    
    # 3. 获取无风险利率 r
    # QMT 提供 get_risk_free_rate,通常返回百分比(如 3.0),需要除以 100
    # 这里取当前 bar 对应的利率
    r = ContextInfo.get_risk_free_rate(ContextInfo.barpos) / 100.0
    
    # 4. 获取隐含波动率 sigma
    # QMT 提供 get_option_iv 接口
    iv = ContextInfo.get_option_iv(ContextInfo.option_code)
    
    # 如果 IV 获取失败或为 0,可以使用历史波动率或固定值代替,这里做简单处理
    if iv <= 0.0001:
        # print("隐含波动率无效,跳过计算")
        return
    sigma = iv
    
    # 5. 计算剩余期限 T (年化)
    # 获取当前时间
    current_timetag = ContextInfo.get_tick_timetag()
    current_dt = datetime.datetime.fromtimestamp(current_timetag / 1000)
    
    # 解析到期日
    expire_dt = datetime.datetime.strptime(expire_date_str, '%Y%m%d')
    # 将到期日设置为当天的 15:00:00 收盘
    expire_dt = expire_dt.replace(hour=15, minute=0, second=0)
    
    # 计算剩余秒数并转换为年
    delta_seconds = (expire_dt - current_dt).total_seconds()
    if delta_seconds <= 0:
        print("期权已到期")
        return
    
    T = delta_seconds / (365 * 24 * 3600)
    
    # 6. 调用函数计算 Delta
    delta_val = calculate_bsm_delta(S, strike_price, T, r, sigma, option_type)
    
    print(f"时间: {current_dt} | 代码: {ContextInfo.option_code} | 类型: {option_type}")
    print(f"标的价(S): {S:.4f} | 行权价(K): {strike_price} | 剩余年(T): {T:.4f}")
    print(f"波动率(IV): {sigma:.4f} | 利率(r): {r:.4f}")
    print(f"==> Delta: {delta_val:.4f}")

def calculate_bsm_delta(S, K, T, r, sigma, option_type):
    """
    计算 BSM 模型下的 Delta 值
    """
    try:
        d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
        
        if option_type.upper() == 'CALL':
            delta = norm.cdf(d1)
        elif option_type.upper() == 'PUT':
            delta = norm.cdf(d1) - 1
        else:
            delta = 0
            
        return delta
    except Exception as e:
        print(f"计算 Delta 出错: {e}")
        return 0

代码关键点解析

  1. 数据获取 (handlebar 函数内):

    • 标的价格 ($S$): 使用 ContextInfo.get_market_data_ex 获取标的(如 510300.SH)的最新 Tick 数据。
    • 行权价 ($K$) & 到期日: 使用 ContextInfo.get_option_detail_data 获取合约的静态数据。
    • 隐含波动率 ($\sigma$): 直接调用 QMT 的 ContextInfo.get_option_iv。这是计算 Delta 最关键的动态参数。
    • 无风险利率 ($r$): 使用 ContextInfo.get_risk_free_rate,注意单位转换。
  2. 时间处理 ($T$):

    • BSM 模型中的 $T$ 单位为“年”。
    • 代码中通过 (到期时间 - 当前时间).total_seconds() / (365 * 24 * 3600) 将剩余时间精确转换为年化数值。
  3. 数学计算 (calculate_bsm_delta 函数):

    • 使用 numpy 进行对数和平方根运算。
    • 使用 scipy.stats.norm.cdf 计算标准正态分布的累积概率 $N(x)$。

注意事项

  • 第三方库: 代码依赖 scipy 库。QMT 内置的 Python 环境通常包含此库。如果报错提示缺少库,请参考 QMT 文档中关于“用户自行安装 Python 三方库”的章节进行安装(通常使用 pip install scipy)。
  • 数据补充: 在运行策略前,请务必在 QMT 客户端的【数据管理】中补充相关的期权和标的的历史数据,以确保 get_option_iv 等函数能正常返回数据。
  • 异常处理: 期权临近到期或深度虚值/实值时,IV 可能计算异常或缺失,代码中应加入适当的判断逻辑(如示例中的 if iv <= 0.0001)。

Q&A

Q: 为什么 QMT 不直接提供 Delta 接口?
A: QMT 的 API 设计更侧重于交易执行和基础数据获取。Greeks(希腊字母)属于衍生品分析的高级指标,通常由量化开发者根据自己的定价模型(如 BSM、二叉树等)自行计算,以便拥有更高的灵活性。

Q: 代码中的 ContextInfo.get_option_iv 返回的是什么?
A: 它返回的是交易所或数据商提供的实时隐含波动率。如果该数据缺失,你可以使用标的资产的历史波动率作为替代,或者自行编写算法反推 IV。

Q: 如何计算 Gamma 或 Vega?
A: 逻辑与 Delta 类似,只需将 calculate_bsm_delta 函数中的公式替换为 Gamma 或 Vega 的 BSM 公式即可。所有需要的基础输入参数(S, K, T, r, sigma)在上述代码中都已经获取到了。