
“该策略在每月到期周五(第三个周五)卖出流动性良好的标普500指数看跌期权,排除交易量较低的期权(过去五天内交易量少于100份合约)。投资组合按等权分配,持仓跨越周末,并在下一个交易日(通常为周一)平仓。”
资产类别:期权 | 地域:美国 | 频率:每日 | 市场:股票 | 关键词:期权、到期周末
I. 策略概述
该策略以所有标普500指数的看跌期权为交易范围。投资者排除过去五天内交易量少于100份合约的期权,以确保投资组合更具流动性。投资者在每个月的到期周五(即每月第三个周五)卖出看跌期权,并在周末后(周一或周末后的首个交易日)平仓。投资组合按等权分配。
II. 策略合理性
这一市场异常现象有三种可能的解释:
市场定价错误:这种异常可能源于持续的市场定价错误,交易者在评估期权时未能正确考虑交易期与非交易期的区别。这种低效性导致时间衰减率与资产定价理论不符,特别是在周末期间,这种非平滑性导致期权持有期间的负回报。
风险溢价:非交易期间(例如周末)的较低回报可能反映出更高的非交易期风险。
避险需求:由于周末期间无法交易且存在无限下行风险,卖出期权者(而非买入者)对风险的厌恶加剧,从而要求更高的期权溢价,这导致非交易期间期权回报为负。
III. 论文来源
Option Mispricing Around Nontrading Periods [点击浏览原文]
- Jones, Shemesh
<摘要>
我们发现期权在非交易期间(尤其是周末)的回报显著较低。证据表明,这种非交易回报的现象并非由风险引起,而是由广泛存在且高度持续的期权定价错误导致的,这种错误源于对股票回报波动率非平滑性的错误处理。这一效应的规模表明,涉及期权价格的广泛金融研究应更加关注非交易效应及波动率非平滑性。我们的研究进一步提出,采用替代行业实践可显著提高期权市场的效率。

IV. 回测表现
| 年化收益率 | 21.26% |
| 波动率 | N/A |
| Beta | 0.008 |
| 夏普比率 | N/A |
| 索提诺比率 | -0.505 |
| 最大回撤 | N/A |
| 胜率 | 55% |
V. 完整python代码
from AlgorithmImports import *
class TradingOptionsDuringExpirationWeekends(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2011, 1, 1)
self.SetCash(100000)
self.symbol = self.AddEquity("SPY", Resolution.Minute).Symbol
# Next expiry date.
self.expiry_date = None
option = self.AddOption("SPY", Resolution.Minute)
option.SetFilter(-20, 20, 25, 35)
self.Schedule.On(self.DateRules.EveryDay(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol, 1), self.Close)
def OnData(self, slice):
# Open new trades only on market close.
if not (self.Time.hour == 15 and self.Time.minute == 59):
return
if self.expiry_date:
if self.Time.date() < self.expiry_date.date():
return
for i in slice.OptionChains:
chains = i.Value
if not self.Portfolio.Invested:
puts = list(filter(lambda x: x.Right == OptionRight.Put, chains))
if not puts: return
underlying_price = self.Securities[self.symbol].Price
expiries = [i.Expiry for i in puts]
# Determine expiration date nearly one month.
expiry = min(expiries, key=lambda x: abs((x.date()-self.Time.date()).days-30))
strikes = [i.Strike for i in puts]
# determine at-the-money strike
strike = min(strikes, key=lambda x: abs(x-underlying_price))
atm_put = [i for i in puts if i.Expiry == expiry and i.Strike == strike]
if atm_put:
if not self.expiry_date:
self.expiry_date = atm_put[0].Expiry
return
options_q = int(self.Portfolio.MarginRemaining / (underlying_price * 100))
if not (self.Time.month == 8 and self.Time.year == 2015):
self.Sell(atm_put[0].Symbol, options_q)
self.expiry_date = atm_put[0].Expiry
if self.Portfolio.Invested:
self.Liquidate(self.symbol)
def Close(self):
if self.Portfolio.Invested:
self.Liquidate()