| Overall Statistics |
|
Total Trades 4 Average Win 0% Average Loss -0.56% Compounding Annual Return 14.820% Drawdown 8.000% Expectancy -1 Net Profit 3.530% Sharpe Ratio 1.035 Probabilistic Sharpe Ratio 49.409% Loss Rate 100% Win Rate 0% Profit-Loss Ratio 0 Alpha 0.029 Beta -0.19 Annual Standard Deviation 0.126 Annual Variance 0.016 Information Ratio 1.075 Tracking Error 0.62 Treynor Ratio -0.688 Total Fees $4.00 |
from QuantConnect.Data.Custom.CBOE import CBOE
from math import sqrt,floor
class ModifiedCollar(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 1, 2) # Set Start Date
self.SetEndDate(2020, 4, 1)
self.SetCash(100000) # Set Strategy Cash
self.SetBenchmark("SPY")
self.stock = self.AddEquity("SPY", Resolution.Minute)
self.stockSymbol = self.stock.Symbol
self.stock.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.vixSymbol = self.AddData(CBOE, "VIX").Symbol
self.vix = 0
self.simpleMoving = SimpleMovingAverage(60)
self.vixSMA = self.SMA(self.vixSymbol, 60, Resolution.Daily)
self.simpleMoving.Updated += self.OnVixSMA
self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))
self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 10), self.LogData)
self.length = None
self.callContract = self.putContract = None
self.maxPutPrice = self.callPrice = 0
self.callTicket = self.putTicket = None
self.optionPercent = .04
self.optionPercentOfStock = self.optionPercent / (1 - self.optionPercent)
self.putsPerHundred, self.protectionNumber = 2, 1
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.SetWarmUp(timedelta(days=60))
def OnVixSMA(self, sender, updated):
return
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
Argumen
data: Slice object keyed by symbol containing the stock data
'''
self.Log("hello")
for volatility in data.Get(CBOE).Values:
self.vix = volatility.Value
self.simpleMoving.Update(self.Time, self.vix)
if self.IsWarmingUp:
return
if (not self.Portfolio[self.stockSymbol].Invested):
number = self.CalculateOrderQuantity(self.stockSymbol, 1-self.optionPercent)
self.protectionNumber = number // 100
number = self.protectionNumber * 100
self.ticket = self.MarketOrder(self.stockSymbol, number)
if (self.putContract is None):
self.putContract = self.GetPutContract()
# if (self.callContract is None):
# self.callContract = self.GetCallContract()
if (self.putContract is not None and not self.Portfolio[self.putContract.Symbol].Invested):
self.putTicket = self.MarketOrder(self.putContract.Symbol, self.protectionNumber * self.putsPerHundred)
self.Debug("bought")
self.maxPutPrice = self.putTicket.AverageFillPrice
# self.Debug("bought price: {}".format(self.maxPutPrice))
# if (self.callContract is not None and not self.Portfolio[self.callContract.Symbol].Invested):
# self.callTicket = self.MarketOrder(self.callContract.Symbol, -self.protectionNumber)
# self.callPrice = self.callTicket.AverageFillPrice
# if (self.callContract.AskPrice * 2 > self.callPrice):
# self.Liquidate(self.callContract.Symbol)
# self.callContract = None
if (self.putContract.BidPrice > self.maxPutPrice):
self.maxPutPrice = self.putContract.BidPrice
if (self.maxPutPrice * .8 >= self.putContract.AskPrice):
self.putTicket = self.MarketOrder(self.putContract.Symbol, -self.protectionNumber * self.putsPerHundred)
self.Debug("sold")
# self.Debug("sold price: {}".format(self.putTicket.AverageFillPrice))
self.RemoveSecurity(self.putContract.Symbol)
self.maxPutPrice = 0
self.putContract = None
def GetPutContract(self):
max_price = self.Portfolio.TotalPortfolioValue * self.optionPercent/ 100 / (self.protectionNumber * self.putsPerHundred)
contracts = self.OptionChainProvider.GetOptionContractList(self.stock.Symbol, self.Time)
x = 1
contracts = [x for x in contracts if 330 <= (x.ID.Date - self.Time).days <= 400]
x = 2
contracts = [x for x in contracts if x.ID.StrikePrice < self.stock.Price]
contracts = [x for x in contracts if x.ID.OptionRight == OptionRight.Put]
contracts = sorted(sorted(contracts, key = lambda x: x.ID.StrikePrice, reverse = True), key = lambda x: abs(x.ID.Date - self.Time))
for i in contracts:
contract = self.AddOptionContract(i)
if contract.AskPrice < max_price:
return contract
else:
self.RemoveSecurity(i)
return None
def GetCallContract(self):
# if (self.vix >= self.vixSMA.Current.Value * 1.5):
# return None
max_price = floor((1 + (self.vix/100 / sqrt(52) )) * self.Securities[self.stockSymbol].Price)
contracts = self.OptionChainProvider.GetOptionContractList(self.stock.Symbol, self.Time)
contracts = [x for x in contracts if 5 <= (x.ID.Date - self.Time).days <= 7]
contracts = [x for x in contracts if x.ID.StrikePrice > self.stock.Price]
contracts = [x for x in contracts if x.ID.OptionRight == OptionRight.Call]
contracts = sorted(sorted(contracts, key = lambda x: x.ID.StrikePrice, reverse = False), key = lambda x: x.ID.Date)
for i in contracts:
call = self.AddOptionContract(i)
if i.ID.StrikePrice >= max_price:
call = self.AddOptionContract(i)
return call
return None
def LogData(self):
if self.putContract is not None:
self.Debug("time: {}, stock price: {}, ask price: {}, bid price: {}, max price: {}, percentage different: {}".format(self.Time, self.stock.Price, self.putContract.AskPrice, self.putContract.BidPrice, self.maxPutPrice, (self.maxPutPrice - self.putContract.AskPrice)/self.maxPutPrice))