VeighNa社区【OptionStrategy期权策略分享】系列第2场,将于8月3日(周六)在深圳举办,本次活动将会深入剖析期权策略模板开发和回测引擎细节,并分享针对ETF期权市场的AdvancedSpreadStrategy策略源码,感兴趣的同学可以点击这里查看活动大纲或者直接扫描下方二维码报名:本文是《聊聊期权量化》系列的第三篇,还是先来回顾一下本系列计划探讨的主题:
在上一篇文章中,我们分享了基于迅投研数据服务搭建本地化期权数据库的代码脚本,以及增量化的每日期权数据更新方案。对于数据管理这块感到头疼不想折腾的同学,也可以直接使用VeighNa Elite版的DataManager数据管理模块中提供的期权数据自动更新功能:- 在【交易所】下拉框中选择需要更新下载期权数据的交易所,在【开始时间】编辑框中修改要下载期权数据的开始时间点;
- 点击【更新期权数据】按钮,即可启动后台的数据下载更新任务进程,任务进程会以交易所为范围更新期权合约数据和历史K线数据;
- 点击【停止数据更新】按钮,等待若干秒后台进程就会安全停止退出;在更新过程中不能关闭DataManager窗口,否则会中断更新任务。
和VeighNa平台上的其他策略模块(CtaStrategy、PortfolioStrategy等)类似,OptionStrategy模块在开发策略时同样采用继承策略模板的方式来实现,整体的开发流程如下:- 继承策略模板StrategyTemplate实现策略类
- 定义策略的外部入参Parameter和内部变量Variable
相信接触过一定期权知识的同学,都有听到过所谓【新手买期权,老手卖期权】的说法。但某些传闻中效果拔群的期权交易策略到底绩效如何,这些传闻又没有给出任何数量化的结论。那么接下来我们就借助OptionStrategy的精准回测功能,来看看一个经典的卖出期权跨式价差策略,在历史回测中的绩效到底如何:策略的代码实现并不复杂。首先导入相关的模块,并且继承实现策略类:
from vnpy.trader.object import TickData, BarData
from elite_optionstrategy import (
StrategyTemplate,
Parameter, Variable,
PortfolioData, ChainData, OptionData
)
class ShortStraddleStrategy(StrategyTemplate):
"""持续做空跨式价差的策略"""
author: str = "用Python的交易员"
option_portfolio: str = Parameter("IO")
fixed_size: int = Parameter(1)
percent_add: float = Parameter(0.02)
atm_strike: float = Variable(0)
然后实现策略状态控制相关的回调函数。主要注意在on_init初始化回调函数下,需要调用self.subscribe_options来订阅策略交易的期权产品组合: def on_init(self):
"""策略初始化"""
self.write_log("策略初始化")
self.subscribe_options(self.option_portfolio)
def on_start(self):
"""策略启动"""
self.write_log("策略启动")
def on_stop(self):
"""策略停止"""
self.write_log("策略停止")
接下来在行情数据回调函数下实现策略的交易逻辑部分。由于本篇文章只涉及历史回测,所以跳过on_tick回调函数(实盘Tick推送): def on_tick(self, tick: TickData):
"""Tick推送"""
pass
def on_bars(self, bars: dict[str, BarData]):
"""K线推送"""
if self.pos_data:
return
portfolio: PortfolioData = self.get_portfolio(self.option_portfolio)
price_data: dict[str, float] = {}
for bar in bars.values():
price_data[bar.vt_symbol] = bar.close_price
portfolio.update_price(price_data)
front_chain: ChainData = portfolio.get_chain_by_level(0)
if not front_chain:
self.write_log("无法获取当月期权链,请检查是否正确添加了期权合约")
return
front_chain.calculate_atm()
self.atm_strike = front_chain.atm_strike
atm_call: OptionData = front_chain.get_option_by_level(cp=1, level=0)
atm_put: OptionData = front_chain.get_option_by_level(cp=-1, level=0)
self.set_target(atm_call.vt_symbol, -self.fixed_size)
self.set_target(atm_put.vt_symbol, -self.fixed_size)
self.execute_trading(price_data, self.percent_add)
- PortfolioData对象提供了期权策略中常用的期权合约动态查询功能,包括根据到期月份顺序筛选期权链、在期权链上根据虚值档位筛选指定行权价的期权合约等功能,详细说明可以参考官方文档中的章节。
- OptionStrategy的交易执行,采用了类似PortfolioStrategy的目标仓位执行模式,用户无需直接执行挂撤单操作,而是通过set_target函数设置下一时刻在每个合约上希望持有的目标仓位后,调用execute_trading函数由策略引擎自动生成对应的买卖委托并发送,大幅简化多合约交易场景下的委托逻辑开发难度。
将上述策略代码保存为short_straddle_strategy.py文件后,即可通过Elite Lab交互式投研环境来执行回测,回测相关的代码如下(粘贴到Jupyeter单元格中执行):
from datetime import datetime
from vnpy.trader.constant import Interval
from elite_optionstrategy import BacktestingEngine
from short_straddle_strategy import ShortStraddleStrategy
engine = BacktestingEngine()
engine.set_parameters(
interval=Interval.MINUTE,
start=datetime(2021, 1, 1),
end=datetime(2022, 12, 31),
rate=0,
slippage=0.6 + (16 / 100),
)
engine.add_strategy(ShortStraddleStrategy, {})
engine.run_backtesting()
engine.calculate_result()
result = engine.calculate_statistics()
engine.show_chart()
使用2021-2022这两年时间的IO期权数据,回测结果的绩效图表如下:可以看到作为一个大方向上卖出波动率的期权策略,在回测周期的两年间实现了整体的盈利,且大部分交易时间中都能够通过收Theta的方式在不断积累微小但稳定的收入。但由于策略简单的无脑做空,几乎全程持有跨式价差的空头仓位,在市场出现巨幅波动的2021年2-3月和2022年的2-3月也都遭遇了巨大的回撤,导致策略的收益和Sharpe并不理想。当然策略的改进空间还有很多,通过结合标的物趋势预测、复合期权价差、动态风险调仓等技术后优化完成的AdvancedSpreadStrategy绩效如下:
你对于期权回测数据的准备策略的开发有什么疑问,或者希望在后续文章中看到的内容?欢迎在评论区留言告诉我们!!!文章中的信息或观点仅供参考,作者不对其准确性或完整性做出任何保证。读者应以其独立判断做出投资决策,作者不对因使用本报告的内容而引致的损失承担任何责任。