Quant Buffet放轻松,别过度思虑

在债券ETF上卖出期权

登录后收藏

学术论文

An Examination of Long-Term Bond iShare Option Selling Strategies

作者Simon

论文摘要

本文研究了2003年7月到2007年5月期间,关于雷曼兄弟20年期美国国债指数iShare(TLT)期权的波动率交易。研究结果表明,隐含波动率持续高于实际波动率,且在扣除交易成本后,前合约的跨式期权和铁头策略的卖出策略在持有一个月后非常有利可图。本文还表明,当隐含波动率相对于样本外时间序列波动率预测较高时,卖出跨式期权和铁头策略的短期策略的盈利能力会得到增强。盈利能力的来源既在于盈利交易的数量远超亏损交易(约为2:1),也在于盈利交易的利润大于亏损交易的损失,尽管短期期权策略具有有限的回报和无限的风险。结果的分解显示,大部分盈利来自于theta的收益超越gamma的损失。风险管理策略,如止损策略,会减少短期期权卖出策略的盈利性,而止盈订单对结果的影响相对温和。总体而言,结果表明,在样本期间,TLT期权卖出策略提供了有吸引力的风险收益权衡。

策略概要

该策略使用TLT ETF进行期权卖出,形成每月的delta中性strangle,选择第一个价外的看涨和看跌期权。每日进行delta对冲,当delta超过±500股时,通过TLT股票重新平衡。期权交易在买卖价中点执行,每份合同的交易成本为1美元。TLT股票交易的经纪费用为5美元,每次交易有1美分的买卖差价。卖空期权和TLT股票的收益,或用于购买TLT股票的资金,按3个月国库券利率赚取。该方法旨在通过期权溢价获利,同时管理风险和交易成本。

策略合理性

大多数研究人员推测,波动率溢价是由于投资者极度讨厌负资产回报,因此愿意为期权提供的组合保险支付溢价。

回测表现

波动率18.41%
夏普比率0.73
索提诺比率-0.271
胜率45%

完整 Python 代码

from AlgorithmImports import *
class SellingOptionsonBondETFs(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)

data = self.AddEquity("BIL", Resolution.Minute)
self.bills = data.Symbol
data.SetLeverage(5)

data = self.AddEquity("TLT", Resolution.Minute)
self.symbol = data.Symbol
data.SetLeverage(5)

option = self.AddOption("TLT", Resolution.Minute)
option.SetFilter(-20, 20, 25, 35)

self.last_day = -1

def OnData(self,slice):
# Check once a day.
if self.Time.day == self.last_day:
    return
self.last_day = self.Time.day

for i in slice.OptionChains:
    chains = i.Value
    # Only bill position is opened.
    invested = [x.Key for x in self.Portfolio if x.Value.Invested]
    if len(invested) <= 1:
        calls = list(filter(lambda x: x.Right == OptionRight.Call, chains))
        puts = list(filter(lambda x: x.Right == OptionRight.Put, chains))
        
        if not calls or 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_call = [i for i in calls if i.Expiry == expiry and i.Strike == strike]
        atm_put = [i for i in puts if i.Expiry == expiry and i.Strike == strike]

        if atm_call and atm_put:
            options_q = int(self.Portfolio.MarginRemaining / (underlying_price * 100))
            # Set max leverage.
            self.Securities[atm_call[0].Symbol].MarginModel = BuyingPowerModel(5)
            self.Securities[atm_put[0].Symbol].MarginModel = BuyingPowerModel(5)
            
            # Sell at-the-money straddle.
            self.Sell(atm_call[0].Symbol, options_q)
            self.Sell(atm_put[0].Symbol, options_q)
            
            # Buy treasury bill.
            self.SetHoldings(self.bills, 1)

    if self.Portfolio.Invested:
        self.Liquidate(self.symbol)