问题描述
解决方案
在 QMT 量化交易平台中,计算期权的理论价格和隐含波动率主要基于 Black-Scholes-Merton (BSM) 模型。QMT 的 ContextInfo 对象提供了内置的 API 函数来直接完成这些计算,无需手动编写复杂的数学公式。
以下是具体的计算方法和代码示例。
1. 核心 API 函数
(1) 计算理论价格:ContextInfo.bsm_price
该函数用于根据标的价格、行权价、无风险利率、波动率等参数计算期权的理论价格。
- 语法:
ContextInfo.bsm_price(optionType, objectPrices, strikePrice, riskFree, sigma, days, dividend) - 参数说明:
optionType: 期权类型,'C' 代表认购 (Call),'P' 代表认沽 (Put)。objectPrices: 标的资产当前价格 ($S$)。strikePrice: 期权行权价 ($K$)。riskFree: 无风险利率 ($r$),例如 0.03 代表 3%。sigma: 标的年化波动率 ($\sigma$),例如 0.23 代表 23%。days: 距离到期日的剩余天数 ($T$)。dividend: 标的分红率 ($q$),通常设为 0。
(2) 计算隐含波动率:ContextInfo.bsm_iv
该函数用于根据期权的当前市场价格反推隐含波动率。
- 语法:
ContextInfo.bsm_iv(optionType, objectPrices, strikePrice, optionPrice, riskFree, days, dividend) - 参数说明:
- 大部分参数与
bsm_price相同。 optionPrice: 期权的当前市场价格(用于反推波动率)。
- 大部分参数与
(3) 获取实时隐含波动率:ContextInfo.get_option_iv
如果你不需要自己根据模型计算,而是想直接获取交易所或系统计算好的实时隐含波动率,可以使用此函数。
- 语法:
ContextInfo.get_option_iv(optioncode)
2. 策略代码示例
以下代码展示了如何在 QMT 策略中计算一个假设场景下的期权理论价格,并验证反推隐含波动率。
# -*- coding: gbk -*-
def init(ContextInfo):
# 在初始化中可以做一些设置,这里暂时不需要
pass
def handlebar(ContextInfo):
# 为了演示,我们只在最后一根K线(最新时刻)运行计算
if not ContextInfo.is_last_bar():
return
# ==========================================
# 场景假设:
# 标的:50ETF
# 标的价格:3.51 元
# 行权价:3.50 元
# 无风险利率:3% (0.03)
# 假设波动率:23% (0.23)
# 剩余天数:15 天
# 分红率:0
# ==========================================
# 1. 定义参数
option_type = 'C' # 认购期权
obj_price = 3.51 # 标的价格
strike_price = 3.50 # 行权价
risk_free = 0.03 # 无风险利率
sigma = 0.23 # 年化波动率
days = 15 # 剩余天数
dividend = 0 # 分红率
# 2. 计算理论价格 (Theoretical Price)
# 使用 bsm_price 计算
theo_price = ContextInfo.bsm_price(option_type, obj_price, strike_price, risk_free, sigma, days, dividend)
print("=" * 30)
print(f"【参数输入】标的价:{obj_price}, 行权价:{strike_price}, 波动率:{sigma}, 剩余天数:{days}")
print(f"【计算结果】BSM模型理论价格: {theo_price:.4f}")
# 3. 计算隐含波动率 (Implied Volatility)
# 假设我们观察到市场上的期权价格就是上面算出来的 theo_price,我们反推一下波动率
# 理论上反推出来的结果应该非常接近输入的 sigma (0.23)
market_price = theo_price
calc_iv = ContextInfo.bsm_iv(option_type, obj_price, strike_price, market_price, risk_free, days, dividend)
print(f"【反推验证】基于价格 {market_price:.4f} 反推的隐含波动率: {calc_iv:.4f}")
# 4. 获取指定合约的实时隐含波动率 (Real-time IV)
# 假设获取 '10003280.SHO' 这个期权合约的实时IV
# 注意:需要确保有期权行情权限且在交易时段或有历史数据
target_option = '10003280.SHO'
real_time_iv = ContextInfo.get_option_iv(target_option)
print(f"【实时数据】合约 {target_option} 的系统实时隐含波动率: {real_time_iv}")
print("=" * 30)
3. 注意事项
- 参数单位:
- 利率和波动率通常使用小数表示(如 0.03 表示 3%)。
days参数直接传入剩余天数的数值(如 15),不需要转换为年化时间,API 内部会处理。
- 数据获取:
- 在实盘中,
objectPrices(标的价格)通常通过ContextInfo.get_market_data_ex获取标的资产的最新close价格。 days(剩余天数)可以通过ContextInfo.get_contract_expire_date获取到期日后,与当前日期相减计算得出。
- 在实盘中,
- 异常值处理:
- 如果输入的参数不合法(例如期权价格为负数,或者无法通过模型收敛计算出 IV),
bsm_iv可能会返回nan或异常值,建议在代码中加入判断逻辑。
- 如果输入的参数不合法(例如期权价格为负数,或者无法通过模型收敛计算出 IV),
Q&A
Q: bsm_price 函数支持美式期权吗?
A: 不支持。QMT 的 bsm_price 基于 Black-Scholes-Merton 模型,该模型专门用于计算欧式期权(European Options)的理论价格。对于美式期权,通常需要使用二叉树等数值方法,但 BSM 模型常被用作近似参考。
Q: 如何获取期权的剩余天数 days?
A: 可以通过 ContextInfo.get_instrumentdetail(option_code) 获取期权的详细信息,其中包含 ExpireDate(到期日)。然后使用 Python 的 datetime 模块将到期日与当前日期相减,获取天数差。
Q: 为什么 get_option_iv 返回 0 或空值?
A: 这通常是因为:1. 当前账号没有期权行情权限;2. 该合约已经过期或未上市;3. 处于非交易时间且本地没有历史数据缓存。建议先检查行情订阅状态。