| Overall Statistics |
|
Total Trades 2 Average Win 17.20% Average Loss 0% Compounding Annual Return 2.024% Drawdown 4.600% Expectancy 0 Net Profit 17.190% Sharpe Ratio 0.451 Probabilistic Sharpe Ratio 1.329% Loss Rate 0% Win Rate 100% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0.032 Annual Variance 0.001 Information Ratio 0.451 Tracking Error 0.032 Treynor Ratio 0 Total Fees $10.00 Estimated Strategy Capacity $5000.00 Lowest Capacity Asset UVXY 2ZWLGYQK5YDEU|UVXY V0H08FY38ZFP |
# region imports
from AlgorithmImports import *
from scipy import stats
# endregion
class WellDressedTanLemur(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2015, 1, 1) # Set Start Date
self.SetEndDate(datetime.now())
self.SetCash(100000) # Set Strategy Cash
self.SetWarmup(timedelta(50))
self.equity = self.AddEquity("UVXY", Resolution.Hour)
self.VIX = self.AddIndex("VIX", Resolution.Hour).Symbol
self.symbol = self.equity.Symbol
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.contractsAdded = set()
self.percentileThreshold = 50
self.lookback = 50
self.DTEput = 20
self.DaysBeforeExp = 3
self.putcontract = str()
self.current_VIX_percentile = 0
self.VIXwindow = RollingWindow[Tick](self.lookback)
def OnData(self, data):
if(self.IsWarmingUp):
return
self.VIXwindow.Add(data["VIX"])
current_VIX = self.Securities[self.VIX].Price
self.current_VIX_percentile = stats.percentileofscore(self.VIXwindow, current_VIX)
self.Log(self.current_VIX_percentile)
option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type==SecurityType.Option]
for option in option_invested:
if option.IsShort:
if (self.putcontract.ID.Date - self.Time) <= timedelta(self.DaysBeforeExp):
self.Liquidate(self.putcontract)
self.Log("Closed: too close to expiration")
self.putcontract = str()
if self.Portfolio.UnrealizedProfitPercent < -1:
self.Liquidate(self.putcontract)
self.putcontract = str()
if self.Portfolio.UnrealizedProfitPercent >= 0.75:
self.Liquidate(self.putcontract)
self.putcontract = str()
if self.current_VIX_percentile < self.percentileThreshold:
self.SellPut(data)
def SellPut(self, data):
if self.putcontract == str():
self.putcontract = self.OptionsFilter(data)
return
elif not self.Portfolio[self.putcontract].Invested and data.ContainsKey(self.putcontract):
self.underlyingPrice = self.Securities[self.symbol].Price
positionSize = self.Portfolio.Cash / (self.putcontract.ID.StrikePrice * 100)
self.Sell(self.putcontract, positionSize)
# Allocation sizing goes here
def OptionsFilter(self, data):
contracts = self.OptionChainProvider.GetOptionContractList(self.symbol, data.Time)
self.underlyingPrice = self.Securities[self.symbol].Price
# self.underlyingPrice can later be replaced with projected UVXY price
otm_puts = [i for i in contracts if i.ID.OptionRight == OptionRight.Put and i.ID.StrikePrice < self.underlyingPrice]
if len(otm_puts) > 0:
putcontract = sorted(sorted(otm_puts, key = lambda x: abs((x.ID.Date - self.Time).days - self.DTEput)), key = lambda x: self.underlyingPrice - x.ID.StrikePrice)[0]
if putcontract not in self.contractsAdded:
self.contractsAdded.add(putcontract)
self.AddOptionContract(putcontract, Resolution.Hour)
return putcontract
else:
return str()
def OnOrderEvent(self, orderEvent):
# log order events
self.Log(str(orderEvent))
# QC appears to support daily resolution for options now