
“该策略每月做空标普500指数的虚值看跌期权,应用2.0倍杠杆,将多余保证金投资于无风险资产,并每月进行再平衡,以保持一致的敞口并优化回报。”
资产类别: 期权 | 地区: 美国 | 周期: 每月 | 市场: 股票 | 关键词: 对冲,指数
I. 策略概要
每个月,该策略都涉及做空标普500指数的虚值看跌期权,其行权价设置为指数月度标准差的1.0倍。投资组合应用2.0倍的恒定杠杆,将未使用的保证金资本投资于无风险利率以提高回报。投资组合每月进行再平衡,编写新的看跌期权以维持策略的结构和一致的敞口。这种方法旨在通过杠杆和将多余资本分配给无风险投资来利用期权溢价,同时管理风险。
II. 策略合理性
学术研究表明,对冲基金可能因获得跳跃和波动性风险溢价的补偿。因此,使用简单的期权卖出策略进行非线性复制,理论上可以很好地克隆对冲基金指数。
III. 来源论文
另类投资的资本成本 [点击查看论文]
- 雅库布·W·尤雷克 和 埃里克·斯塔福德。宾夕法尼亚大学 – 金融系;国家经济研究局(NBER)。哈佛商学院 – 金融部门。
<摘要>
传统的风险因素模型表明,在1996年至2012年期间,对冲基金获得了每年6%至10%的扣费前阿尔法。与此同时,对冲基金的回报序列与机械标普500看跌期权卖出策略的回报没有可靠的区别。我们表明,对冲基金和看跌期权卖出的高超额回报与这样一种均衡状态相符:一小部分投资者专门承担下行市场风险。在这种均衡状态下,要求的收益率可以显著超过传统模型所建议的收益率,从而影响对这些投资吸引力的推断。


IV. 回测表现
| 年化回报 | 10.3% |
| 波动率 | 7.7% |
| β值 | 1.196 |
| 夏普比率 | 1.34 |
| 索提诺比率 | 0.394 |
| 最大回撤 | -21.8% |
| 胜率 | 61% |
V. 完整的 Python 代码
import numpy as np
from AlgorithmImports import *
from math import floor
from datetime import datetime
class CloningHedgeFundIndexes(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2013, 1, 1)
self.SetCash(100000)
self.symbol = self.AddEquity("SPY", Resolution.Minute).Symbol
self.leverage:float = 2.
# spy consolidator
self.consolidator:TradeBarConsolidator = TradeBarConsolidator(timedelta(days=1))
self.consolidator.DataConsolidated += self.CustomHandler
self.SubscriptionManager.AddConsolidator(self.symbol, self.consolidator)
self.period:int = 21
# Daily price data.
self.data:RollingWindow = RollingWindow[float](self.period)
option:Option = self.AddOption("SPY", Resolution.Minute)
def CustomHandler(self, sender: object, consolidated_bar: TradeBar) -> None:
self.data.Add(consolidated_bar.Close)
def OnData(self, slice:Slice) -> None:
for i in slice.OptionChains:
chains:OptionChain = i.Value
if self.Portfolio[self.symbol].Invested:
self.Liquidate(self.symbol)
if not self.Portfolio.Invested:
# Market data is ready.
if self.data.IsReady:
market_closes:np.ndarray = np.array(list(self.data))
market_returns:np.ndarray = market_closes[:-1] / market_closes[1:] - 1
market_std:float = np.std(market_returns)
# Divide option chains into put options
puts:List = list(filter(lambda x: x.Right == OptionRight.Put, chains))
if not puts: return
underlying_price:float = self.Securities[self.symbol].Price
expiries:List[datetime] = list(map(lambda x: x.Expiry, puts))
# Determine expiration date nearly one month.
expiry:datetime = min(expiries, key=lambda x: abs((x.date() - self.Time.date()).days - 30))
strikes:List[float] = list(map(lambda x: x.Strike, puts))
# Determine out-of-the-money strike.
otm_strike:float = min(strikes, key = lambda x:abs(x - float(1 - market_std) * underlying_price))
# Leverage calc.
otm_put:OptionContract = [i for i in puts if i.Expiry == expiry and i.Strike == otm_strike]
q:float = floor(float(self.Portfolio.MarginRemaining / (underlying_price * 100)) * self.leverage)
if otm_put:
# Sell with 2x leverage.
self.Sell(otm_put[0].Symbol, q)