| Overall Statistics |
|
Total Trades 204 Average Win 1.67% Average Loss -1.30% Compounding Annual Return 26.661% Drawdown 10.600% Expectancy 0.745 Net Profit 157.545% Sharpe Ratio 1.55 Probabilistic Sharpe Ratio 83.848% Loss Rate 24% Win Rate 76% Profit-Loss Ratio 1.29 Alpha 0.11 Beta 0.69 Annual Standard Deviation 0.12 Annual Variance 0.014 Information Ratio 0.756 Tracking Error 0.1 Treynor Ratio 0.27 Total Fees $2205.00 Estimated Strategy Capacity $16000000.00 Lowest Capacity Asset SPY W7FVJCNHA4BQ|SPY R735QTJ8XC9X |
#region imports
from AlgorithmImports import *
#endregion
class IBOptionMarginModel(OptionMarginModel):
def __init__(self, algorithm):
self.algorithm = algorithm
def GetMarginRequirement(self, security, value):
OptionMarginRequirement=1
option = security
if (value == 0 or option.Close == 0 or option.StrikePrice == 0 or option.Underlying == None or option.Underlying.Close == 0):
return 0
if (value > 0):
return OptionMarginRequirement
absValue = -value
optionProperties = option.SymbolProperties
underlying = option.Underlying
multiplierRatio = underlying.SymbolProperties.ContractMultiplier / optionProperties.ContractMultiplier
quantityRatio = optionProperties.ContractUnitOfTrade
priceRatio = underlying.Close / (absValue / quantityRatio)
underlyingValueRatio = multiplierRatio * quantityRatio * priceRatio
if option.Right == OptionRight.Call:
amountOTM = max(0, option.StrikePrice - underlying.Close)
else:
amountOTM= max(0, underlying.Close - option.StrikePrice)
priceRatioOTM = amountOTM / (absValue / quantityRatio)
underlyingValueRatioOTM = multiplierRatio * quantityRatio * priceRatioOTM
result = OptionMarginRequirement +\
option.Holdings.AbsoluteQuantity * max(NakedPositionMarginRequirement * underlyingValueRatio,
NakedPositionMarginRequirementOtm * underlyingValueRatio - underlyingValueRatioOTM)
self.algorithm.Log("OPTION MARGIN MODEL, RESULT: " + str(result))
return result
class CustomBuyingPowerModel(BuyingPowerModel):
def __init__(self, algorithm):
self.algorithm = algorithm
# def HasSufficientBuyingPowerForOrder(self, parameters):
# # custom behavior: this model will assume that there is always enough buying power
# hasSufficientBuyingPowerForOrderResult = HasSufficientBuyingPowerForOrderResult(True)
# return hasSufficientBuyingPowerForOrderResult
# def GetInitialMarginRequiredForOrder(self, parameters):
# fees = parameters.Security.FeeModel.GetOrderFee(parameters.Security, parameters.Order).Value
# feesInAccountCurrency = parameters.CurrencyConverter.ConvertToAccountCurrency.Amount
# orderMargin = self.GetInitialMarginRequirement(parameters.Security, parameters.Order.Quantity);
# result=orderMargin + math.copysign(1,(orderMargin) * feesInAccountCurrency)
# self.algorithm.Log("IN CUSTOM MODEL, RESULT: "+ str(result))
# return result
#region imports
from AlgorithmImports import *
import random
import ast
#endregion
import queue
from CustomModels import *
class MuscularBlackLion(QCAlgorithm):
def Initialize(self):
#RECORDING SETTINGS:
self.recordIVWindow = False
self.IVWindow = queue.Queue(252)
self.grabIVWindow("ivWindow_2011-04-01 00:00:00_2011-12-31 23:59:59.999999")
#OPTION FILTER SETTINGS
self.minDTE = 35 #int(self.GetParameter("minDTE")) #20-35
self.maxDTE = 60
self.marginPctToUse = 100
self.deltaTarget = 0.05
self.callDeltaRatio = 0.65
self.putDeltaRatio = 6.8
#VOLATILITY MANAGEMENT SETTINGS
self.IVMetric = "logIVRP" #choices[int(IVChoice)] #0
self.IvrTarget= 0 #int(self.GetParameter("IvrTarget"))#0
self.IVRWaitimeDayTreshold = 20 #max days to wait after loss while monitoring IVMetric for reentry
self.IvrDangerThreshold = 55 #int(self.GetParameter("IvrDangerThreshold")) #70
#RISK MANAGEMENT SETTINGS
self.closeBeforeExpDate = 1
self.takeProfit = 60 #int(self.GetParameter("takeProfit"))#60
self.stopLoss = 175 #int(self.GetParameter("stopLoss"))#175
self.trailingStopPercent = 30
self.trailingStopPercentGain = 30 #int(self.GetParameter("trailingStopPercent"))#30
self.trailingStopPercentLoss = 250
#ROLLING SETTINGS
self.rollingEnabled=True
self.callStrengthDangerThreshold=35
self.putStrengthDangerThreshold=10
self.daysBetweenManagement= 10
self.rollCallRatio=2.5
self.rollPutRatio=1
self.breachedDaysThresholdCall = 1
self.breachedDaysThresholdPut = 1
self.SetStartDate(2012, 1, 1) # Set Start Date
self.SetEndDate(2016, 1, 1) # Set Start Date
self.SetCash(100000) # Set Strategy Cash
self.equity = self.AddEquity("SPY", Resolution.Minute)
self.equity.VolatilityModel = StandardDeviationOfReturnsVolatilityModel(30)
option = self.AddOption("SPY", Resolution.Minute)
option.SetFilter(lambda universe: universe.IncludeWeeklys().Strikes(-1, 1).Expiration(timedelta(0), timedelta(36)))
option.PriceModel = OptionPriceModels.BjerksundStensland()
self.strangleQty = 0
self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.symbol = option.Symbol
self.benchmarkTicker = 'SPY'
self.SetBenchmark(self.benchmarkTicker)
self.initBenchmarkPrice = None
self.start = datetime.now()
self.end = datetime.now()
self.expiry= None
self.DTE = 45
self.SetWarmUp(TimeSpan.FromDays(50))
self.CostOfContract = 0
self.profitPercent=0
self.vix = self.AddData(CBOE, "VIX").Symbol
self.putContract = None
self.putCost=0
self.callCost=0
self.callContract = None
self.lastManagedDatePut = self.StartDate
self.lastManagedDateCall = self.StartDate
self.Portfolio.MarginCallModel = MarginCallModel.Null
self.previousMargin=0
self.daysNotTradingInARow=0
self.IVMetricWindow = queue.Queue(15)
self.IVR=-1
self.IVP=-1
self.logIVRP=-1
self.currIv=0
self.dailyAverageIv=0
self.dailyAverageIvr=0
self.dailyAverageIvrCount=0
self.dailyAverageIvp=0
self.dailyAverageIvpCount=0
self.dailyAverageIvmetric = 0
self.dailyIvmetricCount = 0
self.dailyIvCount = 0
self.endOfDayReached=False
self.daysBreached = 0
self.lastBreached = None
self.daysBreachedPut = 0
self.lastBreachedPut = None
self.currentDay = None
self.expiryWeCantFindPutFor=self.StartDate
self.callContracts= []
self.putContracts= []
self.rollingPutUp=False
self.rollingCallDown=False
self.waitUntilIVRLowers=False
self.waitUntilIVRLowersDays=0
self.IvHours=[9,10,11,12,13,14,15]
self.SetSecurityInitializer(self.securityInitializer)
self.optionStep=0
self.minBuyBack = sys.maxsize
self.maxProfit = -sys.maxsize - 1
self.activateTrailingStopLoss=False
self.underlyingPriceAtStrangleSale=0
# self.ObjectStore.Save("test", str(self.IvHours))
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
def OnEndOfAlgorithm(self):
if self.recordIVWindow:
key="ivWindow_"+str(self.StartDate)+"_"+str(self.EndDate)
if not self.ObjectStore.ContainsKey(key):
self.ObjectStore.Save(key, str(list(self.IVWindow.queue)))
self.Debug("RECORDED IVWINDOW WITH KEY: "+key)
def securityInitializer(self, security):
security.SetLeverage(2)
if security.Type == SecurityType.Option:
security.SetMarginModel(IBOptionMarginModel(self))
security.SetBuyingPowerModel(CustomBuyingPowerModel(self))
def OnData(self, slice):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
Arguments:
slice: Slice object keyed by symbol containing the stock data
'''
if self.Time.hour ==9 and self.Time.minute==31 and self.Time.second==0:
self.start = datetime.now()
if self.Portfolio.Invested:
self.daysNotTradingInARow=0
if not self.IsWarmingUp and self.notBuggyDay():
# if self.Time.Day==self.StartDate.Day:
self.calculateDailyIv()
if self.IVWindow.qsize() > 1:
self.currIv=self.getCurrentIV()
self.calculateIVR()
self.calculateIVP()
self.logIVRP = self.calculateLogIVRP(self.IVR, self.IVP)
# if self.LiveMode:
# self.Debug("IVWindow size: " + str(self.IVWindow.qsize()))
# self.Debug("CurrIV: " + str(self.currIv))
'''
We are either Recording, Rolling, Buying, or seeing if we need to sell.
'''
if self.recordIVWindow:
self.recordIVWindow
#Rolling
#Buying if we can
elif self.buyCondition(self.IVMetric):
if not self.callContract:
if self.callContracts==[]:
self.callContracts = self.optionsFilter(slice, OptionRight.Call, self.equity.Price*1.03, self.equity.Price*1.2)
else:
self.callContract = self.getCallContract(slice, self.getCallDelta())
if not self.putContract and self.callContract:
if self.putContracts==[]:
self.putContracts = self.optionsFilter(slice, OptionRight.Put, self.equity.Price*0.80, self.equity.Price*0.97)
else:
self.putContract = self.getPutContract(slice, self.getPutDelta())
elif self.callContract and self.putContract:
self.putContracts=[]
if self.notStale() and self.isTradeable():
self.sellToOpenStrangle(self.marginPctToUse)
self.optionStep=0
self.expiryWeCantFindPutFor=self.StartDate
else:
self.putContract=None
self.callContract=None
self.cleanUp()
#Seeing if we need to sell
elif self.putContract and self.callContract:
daysLeft =(self.callContract.Expiry - self.Time).days
profitPercent = self.ProfitPercentage()
self.checkIfNeedToRoll(0)
if daysLeft == self.closeBeforeExpDate:
self.buyToCloseStrangle()
elif self.activateTrailingStopLoss and profitPercent > 0:
self.stopLossManagement()
elif profitPercent > self.takeProfit:
self.activateTrailingStopLoss=True
elif profitPercent < -self.stopLoss:
self.buyToCloseStrangle()
self.waitUntilIVRLowers=True
elif self.rollingCallDown or self.rollingPutUp:
self.rollIfNeeded()
if self.Time.hour ==15 and self.Time.minute==58:
self.end = datetime.now()
def rollIfNeeded(self):
if not self.rollingEnabled:
return
if self.rollingCallDown:
if self.optionStep > 25:
self.optionStep=0
self.callContracts=[]
if self.callContracts==[]:
self.callContracts = self.optionsFilter(slice, OptionRight.Call, self.equity.Price, self.equity.Price*1.5)
else:
contract = self.getRolledCall()
if contract != None:
self.callContract = contract
self.lastManagedDateCall = self.Time
self.rollingCallDown=False
self.daysBreachedPut=0
return True
elif self.rollingPutUp:
if self.optionStep > 25:
self.optionStep=0
self.putContracts=[]
if self.putContracts==[]:
self.putContracts = self.optionsFilter(slice, OptionRight.Put, self.equity.Price*0.5, self.equity.Price)
else:
contract = self.getRolledPut()
if contract != None:
self.putContract = contract
self.lastManagedDatePut = self.Time
self.rollingPutUp=False
self.daysBreached=0
return True
else:
return False
def expiringInAnHour(self):
daysLeft = len(list(self.TradingCalendar.GetDaysByType(TradingDayType.BusinessDay, self.Time, self.Time + (self.callContract.Expiry - self.Time))))
if daysLeft == 1:
return self.Time.hour == 15 and self.Time.minute == 59 and self.ProfitPercentage()<0
else:
return False
def notStale(self):
keys = self.CurrentSlice.Keys
if (self.putContract.Symbol not in keys) or (self.callContract.Symbol not in keys):
return False
if (self.CurrentSlice[self.callContract.Symbol]!=None and self.CurrentSlice[self.putContract.Symbol]!=None):
isNotStale = (not self.CurrentSlice[self.callContract.Symbol].IsFillForward) \
and (not self.CurrentSlice[self.putContract.Symbol].IsFillForward)
return isNotStale
else:
return False
def isTradeable(self):
return self.Securities[self.callContract.Symbol].IsTradable \
and self.Securities[self.putContract.Symbol].IsTradable
def buyCondition(self, IVMetric):
ivm = getattr(self, self.IVMetric)
initialCondition = (not self.Portfolio.Invested and self.currIv!=0)
if self.waitUntilIVRLowers:
if (ivm < self.IvrDangerThreshold) or self.waitUntilIVRLowersDays >= self.IVRWaitimeDayTreshold:
self.waitUntilIVRLowers=False
self.waitUntilIVRLowersDays=0
return initialCondition
else:
return False
else:
return initialCondition and self.IvrTarget < ivm
def cleanUp(self):
minutesWithoutStrangle=self.optionStep/2
if minutesWithoutStrangle > 200 and not self.Portfolio.Invested:
# self.expiryWeCantFindPutFor=self.callContract.Expiry
self.callContract=None
self.putContract=None
self.optionStep=0
self.callContracts=[]
self.putContracts=[]
if(self.callContract) or self.isEven(self.optionStep):
self.callContracts=[]
if(self.putContract) or self.isEven(self.optionStep):
self.putContracts=[]
def isEven(self, num):
return (num % 2) == 0
def stopLossManagement(self):
profitPct=self.ProfitPercentage()
profit = self.profit()
totalCost = self.putCost + self.callCost
profit = self.profit()
if profit > self.maxProfit:
self.maxProfit=profit
profitLossCutOffPoint=self.maxProfit*(1-(self.trailingStopPercentGain/100))
if profitLossCutOffPoint!= 0 and 0 < profit < profitLossCutOffPoint:
self.buyToCloseStrangle()
def sellToOpenStrangle(self, marginPct):
UC = self.Securities["SPY"].Price
#call
callCPC = self.callContract.BidPrice
Strike = self.callContract.Strike
#Effect call has on margin
# callMEOLD = ((0.2*UC)-(Strike-UC)+callCPC)*1*100
callME = ((Strike*100)*0.2)-(callCPC*100)
#put
putCPC = self.putContract.BidPrice
Strike = self.putContract.Strike
#Effect put # putMEOLD = ((0.2*UC)-(UC-Strike)+putCPC)*1*100
putME=((Strike*100)*0.25)-(putCPC*100)
totalME = max(putME+(callCPC*100), callME+ (putCPC*100))
# totalMEOLD = callMEOLD + putMEOLD
self.strangleQty = math.floor((self.Portfolio.MarginRemaining * (self.marginPctToUse/100))/totalME)
self.putCost=self.MarketOrder(self.putContract.Symbol, -self.strangleQty).AverageFillPrice*100*self.strangleQty
self.callCost=self.MarketOrder(self.callContract.Symbol, -self.strangleQty).AverageFillPrice*100*self.strangleQty
self.underlyingPriceAtStrangleSale = self.equity.Price
return
def buyToCloseStrangle(self):
self.Liquidate()
self.putContract = None
self.callContract = None
self.lastManagedDatePut = self.StartDate;
self.lastManagedDateCall = self.StartDate;
self.daysBreached = 0
self.lastBreached = None
self.daysBreachedPut = 0
self.lastBreachedPut = None
self.maxProfit = -sys.maxsize - 1
self.minBuyBack = sys.maxsize
self.activateTrailingStopLoss=False
self.rollingCallDown=False
self.rollingPutUp=False
def profit(self):
totalCost=self.putCost + self.callCost
amountToBuyPut = self.amountToBuyPut()
amountToBuyCall = self.amountToBuyCall()
profit = totalCost - (amountToBuyPut + amountToBuyCall)
return profit
def amountToBuyPut(self):
return self.Securities[self.putContract.Symbol].BidPrice*100*self.strangleQty
def amountToBuyCall(self):
return self.Securities[self.callContract.Symbol].BidPrice*100*self.strangleQty
def ProfitPercentage(self):
profit = self.profit()
totalcost = totalCost=self.putCost + self.callCost
if(totalCost!=0 ):
return (profit/totalCost) * 100
else:
return 0
def withinPercent(self, number, target, pctTarget, absolute=True):
# oldPct= (abs(target/number)-1)*100
if absolute:
absNumber=abs(number)
absTarget=abs(target)
pctFromTarget = abs((absNumber/absTarget)-1)*100
return pctFromTarget < pctTarget
def checkIfNeedToRoll(self, daysToWaitForManagement):
if not self.rollingEnabled:
return
putStrength= self.putStrength()
callStrength= self.callStrength()
if (self.callContract.Expiry - self.Time).days > daysToWaitForManagement \
and putStrength < self.putStrengthDangerThreshold \
and (self.Time - self.lastManagedDateCall).days > self.daysBetweenManagement:
if self.shouldRollCall():
self.rollingCallDown=True
if (self.putContract.Expiry - self.Time).days > daysToWaitForManagement \
and callStrength < self.callStrengthDangerThreshold \
and (self.Time - self.lastManagedDatePut).days > self.daysBetweenManagement:
if self.shouldRollPut():
self.rollingPutUp=True
return
def getRolledPut(self):
expiry = self.putContract.Expiry
newPut = self.getPutContract(self.CurrentSlice, self.getPutDelta()*self.rollPutRatio, expiry)
if newPut:
buyToCloseCost = self.MarketOrder(self.putContract.Symbol, self.strangleQty).AverageFillPrice*100*self.strangleQty
buyToCloseProfit = self.putCost - buyToCloseCost
ticket = self.MarketOrder(newPut.Symbol, -self.strangleQty)
contractCost = ticket.AverageFillPrice*100*self.strangleQty
self.putCost = contractCost - buyToCloseProfit
return newPut
def getRolledCall(self):
expiry = self.callContract.Expiry
newCall = self.getCallContract(self.CurrentSlice, self.getCallDelta()*self.rollCallRatio, expiry)
if newCall:
buyToCloseCost = self.MarketOrder(self.callContract.Symbol, self.strangleQty).AverageFillPrice*100*self.strangleQty
buyToCloseProfit = self.callCost - buyToCloseCost
contractCost = self.MarketOrder(newCall.Symbol, -self.strangleQty).AverageFillPrice*100*self.strangleQty
self.callCost = contractCost - buyToCloseProfit
return newCall
def isWeekend(self, Time):
return Time.weekday() == DayOfWeek.Sunday or Time.weekday() == DayOfWeek.Saturday
def shouldRollPut(self):
if self.isWeekend(self.Time):
if self.lastBreachedPut!=None and not self.isWeekend(self.lastBreachedPut):
self.lastBreachedPut = self.lastBreachedPut + timedelta(days=1)
return False
if self.daysBreachedPut < self.breachedDaysThresholdPut:
timeSinceLastBreach = None
if self.lastBreachedPut!=None:
diff=(self.Time-self.lastBreachedPut)
days, seconds = diff.days, diff.seconds
timeSinceLastBreach = days * 24 + seconds // 3600
if timeSinceLastBreach == None or (timeSinceLastBreach >= 24 and timeSinceLastBreach <= 31):
self.daysBreachedPut+=1
self.lastBreachedPut = self.Time
elif timeSinceLastBreach > 31:
self.daysBreachedPut = 0
self.lastBreachedPut = None
return not (self.daysBreachedPut <= self.breachedDaysThresholdPut)
else:
return True
def shouldRollCall(self):
if self.isWeekend(self.Time):
if self.lastBreached!=None and not self.isWeekend(self.lastBreached):
self.lastBreached = self.lastBreached + timedelta(days=1)
return False
if self.daysBreached < self.breachedDaysThresholdCall:
timeSinceLastBreach = None
if self.lastBreached!=None:
diff=(self.Time-self.lastBreached )
days, seconds = diff.days, diff.seconds
timeSinceLastBreach = days * 24 + seconds // 3600
#if time since last breach is none, its because last breach is none, which means its our first breach moment
if timeSinceLastBreach == None or (timeSinceLastBreach >= 24 and timeSinceLastBreach <= 31):
self.daysBreached+=1
self.lastBreached = self.Time
elif timeSinceLastBreach > 31:
self.daysBreached = 0
self.lastBreached = None
return not (self.daysBreached <= self.breachedDaysThresholdCall)
return True
def calculateIVV(self, IVMetric):
lst = list(self.IVMetricWindow.queue)
return averageVariance(lst)
def averageVariance(numlist):
devationSquared=varianceList(numlist)
return math.sqrt(sum(deviationSquared) / len(deviationSquared))
def varianceList(self,numlist):
mean = sum(numlist) / len(numlist)
deviationSquared=[]
for value in lst:
deviationSquared.append((value-mean)**2)
return deviationSquared
def lastVariance(self, numlist):
devationSquared=varianceList(numlist)
return math.sqrt(deviationSquared[-1])
def updateIvMetricWindow(self, IVMetric):
ivm = getattr(self, IVMetric)
self.IVMetricWindow.put(ivm)
def calculateIVR(self):
if self.currIv == None:
return
nowIvList=list(self.IVWindow.queue)
nowIvList.append(self.currIv)
sorted_IVs = sorted(nowIvList, reverse=True)
max_IV = sorted_IVs[0]
min_IV = sorted_IVs[-1]
self.IVR = (self.currIv - min_IV)*100 / (max_IV - min_IV)
if self.IVR!=0:
self.dailyAverageIvr+=self.IVR
self.dailyAverageIvrCount+=1
def ivTransform(self, iv):
if iv!=None and iv!=0:
return math.log(iv)
def calculateLogIVRP(self, ivr, ivp):
IVRCoeffs=[0, 0.25, 0.5, 0.75, 1]
IVRCoeff=IVRCoeffs[2]
IVPCoeff=1-IVRCoeff
if ivr!=0 and ivp!=0:
return ((IVRCoeff*ivr)+(IVPCoeff*ivp))
else:
# self.Debug("iv: " + str(self.currIv)+"ivr: "+str(ivr) + "ivp: "+str(ivp))
return 0
def calculateIVP(self):
if self.currIv == None:
return
nowIvList=list(self.IVWindow.queue)
tradingDaysUnder = len([x for x in nowIvList if x < self.currIv])
totalLength = len(nowIvList)
if tradingDaysUnder == 0 or totalLength == 0:
return
# if self.IVR==0:
# self.Debug("tradingDaysUnder: " +str(tradingDaysUnder) + " totalLength : "+ str(totalLength))
self.IVP = (tradingDaysUnder/totalLength)*100
if self.IVP!=0:
self.dailyAverageIvp+=self.IVP
self.dailyAverageIvpCount+=1
def getCurrentIV(self):
option=self.getAtmOption()
if option!=None:
return self.ivTransform(option.ImpliedVolatility)
# return random.uniform(0,1)
def getAtmOption(self):
for kvp in self.CurrentSlice.OptionChains:
if kvp.Key != self.symbol: continue
chain = kvp.Value
spot_price = chain.Underlying.Price
# Sort to find ATM contracts
sorted_strikes = sorted(chain, key=lambda k:abs(k.Strike - spot_price), reverse=False)
# sorted_strikes = [x for x in sorted_strikes if x.Expiry>self.Time]
# # IV of ATM contract
return sorted_strikes[0]
def calculateDailyIv(self):
currIv=self.getCurrentIV()
if currIv!=None and currIv!= 0:
self.dailyAverageIv += currIv
self.dailyIvCount+=1
def OnEndOfDay(self, symbol):
if symbol==list(self.ActiveSecurities.Keys)[0]:
# self.removeUninvestedOptions()
if self.waitUntilIVRLowers:
self.waitUntilIVRLowersDays+=1
if not self.Portfolio.Invested:
self.daysNotTradingInARow += 1
self.endOfDayReached=True
if self.IVWindow.full():
self.IVWindow.get()
if self.IVMetricWindow.full():
self.IVMetricWindow.get()
if self.dailyAverageIv != 0:
dailyIv = self.dailyAverageIv/self.dailyIvCount
self.IVWindow.put(dailyIv)
# self.Plot("IV", "iv", dailyIv)
self.dailyAverageIv=0
self.dailyIvCount=0
if self.dailyAverageIvrCount!=0:
ivr = self.dailyAverageIvr/self.dailyAverageIvrCount
# self.Plot("IV Metrics", "ivr",ivr)
self.dailyAverageIvr=0
self.dailyAverageIvrCount=0
if self.dailyAverageIvpCount!=0:
ivp = self.dailyAverageIvp/self.dailyAverageIvpCount
# self.Plot("IV Metrics", "IVP",ivp)
self.dailyAverageIvp=0
self.dailyAverageIvpCount=0
self.Plot("IV Metrics", "LogIVRP", self.calculateLogIVRP(ivr, ivp))
self.updateIvMetricWindow(self.IVMetric)
# self.Plot("IVV", "IVV", self.calculateIVV(self.IVMetric))
self.Plot("Data Chart", "SPY", self.Securities["SPY"].Close)
if self.putContract:
self.Plot("Data Chart", "Put Strike", self.putContract.Strike)
self.Plot("Deltas", "Put Delta", self.putContract.Greeks.Delta)
self.Plot("Deltas", "Delta Target", -self.putTarget)
# self.Plot("DTE on Order", "Put DTE", (self.putContract.Expiry - self.Time).days)
self.Plot("ITM Vulnerability", "Put Strength", self.putStrength())
if self.callContract:
self.Plot("Data Chart", "Call Strike", self.callContract.Strike)
self.Plot("Deltas", "Call Delta", self.callContract.Greeks.Delta)
# self.Plot("DTE on Order", "Call DTE", (self.callContract.Expiry - self.Time).days)
self.Plot("ITM Vulnerability", "Call Strength", self.callStrength())
# self.Plot("IVWindow", "Length", len(list(self.IVWindow.queue)))
dm=divmod((datetime.now()-self.start).total_seconds(), 60)
minutes=dm[0]
seconds=dm[1]
self.Plot("Daily Runtime", "Minutes", str(minutes+(seconds/100)))
def callStrength(self):
strike = self.callContract.Strike
originalPrice = self.underlyingPriceAtStrangleSale
currentPrice = self.equity.Price
strength=((strike-currentPrice)/(strike-originalPrice))*100
return strength
def putStrength(self):
strike = self.putContract.Strike
originalPrice = self.underlyingPriceAtStrangleSale
currentPrice = self.equity.Price
strength=((strike-currentPrice)/(strike-originalPrice))*100
# self.Debug("PUT STRENGTH Strike: " + str(strike)+" originalPrice :"+ str(originalPrice)+ " currentPrice: "+ str(currentPrice)+"CALCULATED PUT STRENGTH: "+str(strength))
return strength
def optionsFilter(self, slice, right, minStrike, maxStrike):
self.optionStep+=1
minDTE=self.minDTE
if self.rollingPutUp or self.rollingCallDown:
minDTE=0
results=[]
contract_symbols = self.OptionChainProvider.GetOptionContractList(self.equity.Symbol, self.CurrentSlice.Time)
contracts = [OptionContract(symbol, self.equity.Symbol) for symbol in contract_symbols]
contracts = [x for x in contracts if minDTE < (x.Expiry-self.Time).days < self.maxDTE \
and x.Right == right and minStrike < x.Strike < maxStrike]
for contract in contracts:
option = self.AddOptionContract(contract.Symbol, Resolution.Minute)
option.PriceModel = OptionPriceModels.BinomialTian()
results.append(contract.Symbol)
return results
def getCallContract(self, slice, delta, expiry=None):
self.optionStep+=1
for symbol, chain in slice.OptionChains.items():
chainContracts=chain.Contracts
for c in self.callContracts:
if slice.ContainsKey(c):
contract = chainContracts[c]
if expiry == None:
if self.withinPercent(contract.Greeks.Delta, delta, 10) and contract.Expiry!=self.expiryWeCantFindPutFor:
return contract
else:
if self.withinPercent(contract.Greeks.Delta, delta, 10) and contract.Expiry==expiry:
return contract
def getPutContract(self, slice, delta, expiry=None):
self.optionStep+=1
for symbol, chain in slice.OptionChains.items():
chainContracts=chain.Contracts
putContracts=[]
for c in self.putContracts:
if slice.ContainsKey(c):
contract = chainContracts[c]
if expiry == None:
if self.callContract.Expiry and self.withinPercent(contract.Greeks.Delta, delta, 15) and contract.Expiry==self.callContract.Expiry:
# if self.callContract.Expiry and self.withinPercent(contract.Greeks.Delta, delta, 15):
self.putTarget=delta
return contract
else:
if self.withinPercent(contract.Greeks.Delta, delta, 10) and contract.Expiry==expiry:
self.Debug("Contract delta: " + str(contract.Greeks.Delta) + "Contract Expiry: "+str(contract.Expiry)+ "Wanted Expiry: "+str(expiry))
self.putTarget=delta
return contract
def getCallDelta(self):
ivm = getattr(self, self.IVMetric)
ivmRatio=ivm/100
#ivmRatio goes here
ratioSide = (self.deltaTarget*self.callDeltaRatio)*ivmRatio
targetSide = (self.deltaTarget)*(1-ivmRatio)
return ratioSide+targetSide
# return self.deltaTarget*self.callDeltaRatio
def getPutDelta(self):
ivm = getattr(self, self.IVMetric)
ivmRatio=ivm/100
ratioSide = (self.deltaTarget*self.putDeltaRatio)*ivmRatio
targetSide = (self.deltaTarget)*(1-ivmRatio)
return ratioSide+targetSide
# return self.deltaTarget*self.putDeltaRatio
def removeUninvestedOptions(self):
for x in self.ActiveSecurities:
if x.Value.Type == SecurityType.Option and x.Value.Invested == False:
if self.callContract and x.Value.Symbol == self.callContract.Symbol:
continue
if self.putContract and x.Value.Symbol == self.putContract.Symbol:
continue
self.RemoveOptionContract(x.Value.Symbol)
def notBuggyDay(self):
return not (self.Time.year==2010 and self.Time.month==4 and self.Time.day==21)
def grabIVWindow(self, key):
if self.ObjectStore.ContainsKey(key) and not self.recordIVWindow:
value=self.ObjectStore.Read(key)
grabbedIVWindow = ast.literal_eval(value)
for x in grabbedIVWindow:
self.IVWindow.put(x)
if len(list(self.IVWindow.queue))!=0:
self.Debug("Successfully grabbed IVWindow from key: "+key)
#region imports from AlgorithmImports import * #endregion #Put all volatility info here # Your New Python File