Overall Statistics
Total Trades
66
Average Win
1.18%
Average Loss
0%
Compounding Annual Return
-78.211%
Drawdown
57.700%
Expectancy
0
Net Profit
-39.920%
Sharpe Ratio
-0.169
Probabilistic Sharpe Ratio
22.821%
Loss Rate
0%
Win Rate
100%
Profit-Loss Ratio
0
Alpha
-0.341
Beta
-0.303
Annual Standard Deviation
1.402
Annual Variance
1.967
Information Ratio
0.073
Tracking Error
1.422
Treynor Ratio
0.782
Total Fees
$4217.50
from clr import AddReference
AddReference("System.Core")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
from System import *
from QuantConnect import *
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Data.UniverseSelection import *
from datetime import datetime, timedelta

class CoarseFundamentalTop3Algorithm(QCAlgorithm):
    
    def Initialize(self):
        self._volHighThreshold =.2
        self._volLowThreshold = 0.02
        self.SetStartDate(2018,9,1)   
        self.SetEndDate(2019,1,1)     
        self.SetCash(1000000)            
        self.indicators = {}
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
        self._changes = None

    def FineSelectionFunction(self, fine):
        
        symbolList = [ x.Symbol for x in fine 
                      if 
                      x.SecurityReference.IsPrimaryShare is True
                      and
                      x.SecurityReference.IsDepositaryReceipt is False
                       ]
        return symbolList  
        
    def CoarseSelectionFunction(self, coarse):
        filtered = [ x.Symbol for x in coarse 
                      if x.Price > 5 and x.DollarVolume > 1000000 ]
        return filtered
    
    def OnData(self, slice):
        account_leverage = self.Portfolio.TotalHoldingsValue / self.Portfolio.TotalPortfolioValue
        self.Plot("Leverage", "%", account_leverage)
        
        if self._changes is None: return
        for security in self._changes.AddedSecurities:
          if security.Symbol not in self.indicators:
                self.indicators[security.Symbol] = SymbolData(security.Symbol, self)
          if not slice.ContainsKey(security.Symbol): return
          if security.Type != SecurityType.Equity: continue
          if not hasattr(slice[security.Symbol],"Price"): return
              
          self.indicators[security.Symbol].update_value(self.Time, slice[security.Symbol].Price)
          if self.IsWarmingUp: continue
          lowerband = self.indicators[security.Symbol].bb_10.LowerBand.Current.Value
          upperband = self.indicators[security.Symbol].bb_10.UpperBand.Current.Value
          isVol = float((abs(slice[security.Symbol].Price - lowerband) +
                                        abs(slice[security.Symbol].Price - upperband))/slice[security.Symbol].Price/2)
          sells = [] 
          buys = [] 
          if isVol < self._volHighThreshold and isVol > self._volLowThreshold:
            option = self.AddOption(security.Symbol.Value)
            chain = slice.OptionChains.GetValue(option.Symbol)
            self.Portfolio[option.Symbol].dateEntered = datetime.now()
            if chain is None:
                return
            
            for x in chain:
              writeCalls = [x for x in chain if  x.Right == 0 and
                                         (x.Strike - x.UnderlyingLastPrice)/x.UnderlyingLastPrice > 0
                                         ]
              writePuts  = [x for x in chain if  x.Right == 1 and
                                         (x.UnderlyingLastPrice - x.Strike)/x.UnderlyingLastPrice > 0 ]
            if len(writePuts) == 0:
                self.Debug("!!!!!!!!!!!!!!! writePuts !!!!!!!!!!!!!!!!!!!!")
                return
            if len(writeCalls) == 0: 
                self.Debug("!!!!!!!!!!!!!!! writeCalls !!!!!!!!!!!!!!!!!!!!!")
                return
            
            sells.append(writePuts[len(writePuts)-1])
            buys.append(writeCalls[len(writeCalls)-1])
          
          availableCapital = self.Portfolio.TotalPortfolioValue-self.Portfolio.TotalHoldingsValue
          numTrades = round(len(sells)+len(buys)/2)
          if numTrades > 0:
              perCapitalAvail = availableCapital/numTrades
          else:
              perCapitalAvail = 0
          self.Debug("NumTRADES: "+str(numTrades)+"________________")
          for write in sells:
            twentyPercentLeverageOnLot = write.UnderlyingLastPrice*100*.8+10
            contractsForOrder = round(perCapitalAvail/twentyPercentLeverageOnLot)
            self.Sell(write.Symbol, contractsForOrder)
            
          for write in buys:
            twentyPercentLeverageOnLot = write.UnderlyingLastPrice*100*.8+10
            contractsForOrder = round(perCapitalAvail/twentyPercentLeverageOnLot)
            self.Sell(write.Symbol, contractsForOrder)
           
        self._changes = None

    # this event fires whenever we have changes to our universe
    def OnSecuritiesChanged(self, changes):
        self._changes = changes
        self.Log(f"OnSecuritiesChanged({self.UtcTime}):: {changes}")

    def OnOrderEvent(self, fill):
        self.Log(f"OnOrderEvent({self.UtcTime}):: {fill}")
    
   
            
class SymbolData(object):
    def __init__(self, symbol, context):
        self.symbol = symbol
        self.bb_10 = context.BB(symbol,10,2,MovingAverageType.Simple,Resolution.Daily)
       
    def update_value(self, time, value):
        self.bb_10.Update(time, value)