基于期权偏度(Options Skewness)的量化交易策略详解:捕捉市场情绪的关键|附回测代码
在金融市场中,交易策略的设计往往需要结合市场的情绪和行为模式,以实现更好的投资回报。本文将介绍一种基于期权偏度(Skewness)的量化交易策略,详细解读该策略的核心原理、计算方法及其在实际市场中的应用。
什么是期权偏度?
期权偏度是指同一标的资产、相同到期日的不同期权(通常为看涨期权和看跌期权)之间隐含波动率(IV)的差异。隐含波动率反映了市场对标的资产未来价格波动的预期,因此偏度成为投资者解读市场情绪的重要工具。
根据市场普遍的风险偏好,投资者通常更担心下行风险,因此虚值看跌期权的需求较高,这往往会推高这些期权的隐含波动率,从而形成负偏度。在这样的情况下,负偏度表明市场预期价格可能下跌,投资者可以通过卖出看跌期权或采取其他保护性策略进行对冲。
深度解析:如何解读期权偏度的形态
根据期权偏度的不同形态,投资者可以解读出市场对未来价格走势的预期:
• 正偏度(Positive Skew):当期权偏度为正时,通常意味着市场预期标的资产价格将上涨。这在大宗商品市场中较为常见,尤其是在供应紧张的情况下,投资者可能会大幅推高看涨期权的隐含波动率。
• 负偏度(Negative Skew):负偏度则表明市场对标的资产价格下跌的担忧。这种形态在股票市场中最为常见,尤其是在投资者寻求保护性看跌期权以规避市场下行风险时。
• 波动率微笑(Volatility Smile):当虚值看涨期权和看跌期权的隐含波动率均高于平值期权时,形成所谓的“波动率微笑”形态。这种形态通常出现在市场对未来价格波动的预期较大,且方向不确定的情况下。
• 波动率怪异形态(Volatility Smirk):有时,市场可能形成一种不对称的波动率形态,通常表现为虚值看跌期权的隐含波动率显著高于平值期权,这反映了市场对下行风险的高度担忧。
期权偏度在市场中的实际应用
期权偏度不仅仅是一个反映市场情绪的指标,它还可以帮助投资者识别潜在的市场异常波动。例如,当偏度显著扩大时,可能预示着市场参与者对未来大幅下跌的担忧加剧。通过与历史数据进行对比,投资者还可以判断当前的市场情绪是否异常,从而做出相应的交易决策。
此外,期权偏度的分析可以与其他市场指标结合使用,如经济数据发布、企业财报公告等,进一步增强策略的有效性。需要注意的是,虽然期权偏度提供了重要的市场洞察,但它不应被单独使用,而应结合其他技术分析工具和市场信息,以全面评估市场状况。
策略框架:从偏度计算到投资组合
本策略的核心思想是通过计算每日的期权偏度来预测股票的未来收益,并基于这些预测构建每周的多空投资组合。以下是策略的主要步骤:
1. 投资标的选择:
• 筛选市场上流动性较好的前50只美国股票,且股价高于5美元。
2. 期权偏度计算:
• 策略中关注的期权包括:
• 虚值看跌期权(OTM Put):行权价与标的股票现价比率最接近0.95但低于0.95的看跌期权。
• 平值看涨期权(ATM Call):行权价与标的股票现价比率最接近1的看涨期权。
• 每日计算这些期权的隐含波动率,得到当日的期权偏度值。偏度的计算方法为:偏度 = 虚值看跌期权的隐含波动率 - 平值看涨期权的隐含波动率
3. 投资组合构建:
• 每周,根据前一周的平均偏度值对所有样本股票进行排序,并将其分为五个等权重投资组合:
• 组合1:包含偏度最低的股票。
• 组合5:包含偏度最高的股票。
• 投资者每周初调整投资组合,对低偏度组合建立多头头寸(买入),对高偏度组合建立空头头寸(卖出)。
4. 策略执行:
• 策略每周执行一次,再根据当周的市场数据进行更新和再平衡。
结论:基于期权偏度的策略优势
基于期权偏度的量化交易策略通过捕捉市场情绪的变化,提供了一个独特且有效的市场分析工具。通过系统化的偏度计算,投资者可以更准确地预测市场走势并构建适应不同市场环境的投资组合。虽然该策略在历史数据上表现优异,但投资者在应用时仍需考虑市场环境的变化及潜在的交易成本。
这种策略的优势在于其系统化的风险管理和灵活的投资组合构建方法,尤其适合那些希望在市场中获取稳健回报的投资者。通过深入理解期权偏度及其市场影响,投资者可以在复杂的市场环境中做出更加明智的投资决策。
策略实现代码基于QuantConnect平台,详细完整代码和策略原文请见知识星球
#region imports
from AlgorithmImports import *
#endregion
#
# Stocks with liquid options are used as the investment universe.
# Skewness is calculated as the difference between the implied volatilities of OTM puts and ATM calls.
# A put option is defined as OTM when the ratio of strike price to the stock price is closest to 0.95 (but lower than 0.95),
# and a call option is defined as ATM when the ratio of strike price to the stock price is closest to 1.
# Only options with a time to expiration between 10 and 60 days are included.
# Weekly SKEW is calculated by averaging the daily SKEW over a week.
# Every week the investors sort all sample firms into quintile portfolios based on the previous week’s average skew (Tuesday close to Tuesday close).
# Portfolio 1 includes firms with the lowest skew, and portfolio 5 includes firms with the highest skew.
# He/she then goes long on portfolio one and short on portfolio 5 (value-weighted portfolios) and rebalances the portfolios weekly.
#
# QC Implementation:
# - Investment universe consists of options of top 50 liquid US stocks with price > 5$.
import numpy as np
class OptionsSkewnessPredictsConsecutiveStocksReturns(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(100000)
self.min_expiry = 40
self.max_expiry = 60
self.period = 5 # need n of daily implied volatility
self.data = {} # storing daily SKEW
self.contracts = {} # storing option contracts
self.tickers_symbols = {} # storing symbols under their tickers
self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol
self.day = -1
self.coarse_count = 50
self.selection_flag = False
self.UniverseSettings.Resolution = Resolution.Minute
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
self.SetSecurityInitializer(lambda x: x.SetDataNormalizationMode(DataNormalizationMode.Raw))
self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw
# rebalance on each Wednesday at 00:00 so it takes prices from Tuesday close
self.Schedule.On(self.DateRules.WeekStart(self.symbol, 1), self.TimeRules.BeforeMarketClose(self.symbol), self.Selection)
def OnSecuritiesChanged(self, changes):
for security in changes.AddedSecurities:
security.SetFeeModel(CustomFeeModel(self))
security.SetLeverage(5)
def OnData(self, data):
# each day store implied volatility for selected stocks
# if this is too slow, then add self.Time.minute == 31 to condition,
# because ~99% of subscribed options get implied volatility in this time each day
# get option ticker from option symbol
# based on option ticker get stock symbol
# make sure, SKEW is updated once in a day
# make sure, there are enough contracts for stock
# get atm call and otm put contract
# check if there are both contracts
# calculate stock's SKEW
# update RollingWindow for stock's SKEW values
# execute once a day
# check expiry of contracts
# remove contract, when it is 10 days to expiry
# subscribe to contracts, if stock symbol doesn't have any
# get new contracts after expiration
# rebalance weekly
# go through each stock in self.data and trade calculate mean of SKEW values
# get SKEW values from RollingWindow and calculate their mean
# store stock's mean SKEW
# make sure, there are enough stocks for quintile selection
# sort stocks by mean SKEW value and perform quintile selection
# long stocks with lowest mean SKEW
# go short stocks with highest mean SKEW
# perform value weight calculation
# trade execution
# data error handling
关于LLMQuant
🌟🌟 起源于剑桥大学的知识分享社区,每日更新大语言模型与量化金融的最新资讯 🌍📊 www.llmquant.com 🌟🌟
加入知识星球,你将获得:
📰 每日最新资讯:人工智能与量化金融的前沿动态,附中英文原文,助你紧跟行业发展。
💻 量化策略详解:获取量化策略的完整代码,支持多平台回测,提升你的实战能力。
❓ 免费答疑:每日解答社区成员问题,高效提升你的知识水平。
🌐 线上交流活动:与国内外量化从业者互动,参与深度知识分享,拓展你的专业网络。
欢迎加入我们的知识星球,和全球精英一起探索人工智能与量化金融的无限可能!🚀✨
搜索 LLMQuant
关注我们