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