Overall Statistics
Total Trades
42
Average Win
13.87%
Average Loss
-9.48%
Compounding Annual Return
-8.393%
Drawdown
27.900%
Expectancy
0.120
Net Profit
-1.625%
Sharpe Ratio
0.383
Probabilistic Sharpe Ratio
36.546%
Loss Rate
55%
Win Rate
45%
Profit-Loss Ratio
1.46
Alpha
0.335
Beta
1.264
Annual Standard Deviation
0.875
Annual Variance
0.766
Information Ratio
0.388
Tracking Error
0.864
Treynor Ratio
0.265
Total Fees
$3382.30
Estimated Strategy Capacity
$6000.00
Lowest Capacity Asset
SPY 2Z4U27US75QZQ|SPY R735QTJ8XC9X
# region imports
from AlgorithmImports import *
# endregion

class EnergeticBrownCobra(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2012, 3, 1)  # Set Start Date
        self.SetEndDate(2012, 5, 8)  # Set Start Date

        self.SetCash(100000)  # Set Strategy Cash
        self.SetWarmUp(50, Resolution.Daily)

        self.equity = self.AddEquity("SPY", Resolution.Minute)
        self.option = self.AddOption(self.equity.Symbol, Resolution.Minute)
        self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
        self.equity.VolatilityModel = StandardDeviationOfReturnsVolatilityModel(30)
        self.option.SetFilter(lambda universe: universe.IncludeWeeklys().Strikes(-5, 5).Expiration(timedelta(0), timedelta(10)))
        self.option.PriceModel = OptionPriceModels.BinomialTian()
        self.option.VolatilityModel = StandardDeviationOfReturnsVolatilityModel(30)

    def withinPercent(self, number, target, pctTarget, absolute=True):
        if absolute:
            absNumber=abs(number)
            absTarget=abs(target)
        pctFromTarget = abs((absNumber/absTarget)-1)*100

        return pctFromTarget < pctTarget

    def OnData(self, slice):
        if not self.IsWarmingUp and not self.Portfolio.Invested:
            for kvp in slice.OptionChains:         
                chain = kvp.Value
                puts = [x for x in chain if x.Greeks.Delta!=0 and x.Right==OptionRight.Put and self.withinPercent(x.Strike, self.equity.Price, 5)]
                if len(puts)>0:
                    putToSell = puts[0]
                    putToBuy = min([x for x in chain if x.Strike > putToSell.Strike and x.Right == OptionRight.Put and x.Expiry == putToSell.Expiry], key=lambda y: abs(putToSell.Strike-y.Strike))
                    self.sellToOpenBullSpread(50, putToSell, putToBuy)
                    self.sellPut = putToSell
                    self.buyPut = putToBuy
        if self.Time.hour==15 and self.Time.minute==59:
            self.Plot("SPY", "SPY", self.equity.Price)
            if self.Portfolio.Invested:
                self.Plot("SPY", "sellPutStrike", self.sellPut.Strike)
                self.Plot("SPY", "buyPutStrike", self.buyPut.Strike)
    def sellToOpenBullSpread(self, equityPct, sellPut, buyPut):
        #sell put with higher strike
        #buy put with lower strike
        #This is selling a put spread with limited risk, which should not get margin called 

        sellPutBid = self.Securities[sellPut.Symbol].BidPrice
        buyPutAsk= self.Securities[buyPut.Symbol].AskPrice

        bp= self.Portfolio.GetBuyingPower(sellPut.Symbol)
        costPerSpread= sellPut.Strike-buyPut.Strike -(sellPutBid-buyPutAsk)
        bpEffect= costPerSpread*100
        optionStrategyQty = abs(math.floor((bp * (equityPct/100))/bpEffect))
        legOneTicket= self.MarketOrder(sellPut.Symbol, optionStrategyQty)
        legTwoTicket= self.MarketOrder(buyPut.Symbol, -optionStrategyQty)
        self.legOneCost = legOneTicket.AverageFillPrice*100*optionStrategyQty   
        self.legTwoCost = -legTwoTicket.AverageFillPrice*100*optionStrategyQty
        return
    

    def OnOrderEvent(self, orderEvent):
        if orderEvent.IsAssignment:
            self.Liquidate()