Overall Statistics
Total Trades
148
Average Win
0.04%
Average Loss
-0.59%
Compounding Annual Return
-58.749%
Drawdown
7.800%
Expectancy
-0.133
Net Profit
-7.469%
Sharpe Ratio
-5.424
Probabilistic Sharpe Ratio
1.075%
Loss Rate
19%
Win Rate
81%
Profit-Loss Ratio
0.07
Alpha
-0.252
Beta
-0.241
Annual Standard Deviation
0.095
Annual Variance
0.009
Information Ratio
-7.324
Tracking Error
0.219
Treynor Ratio
2.132
Total Fees
$173.71
class VentralVerticalGearbox(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2019, 1, 1)  # Set Start Date
        self.SetEndDate(2019,2, 1)  # Set End Date
        self.SetCash(100000)  # Set Strategy Cash
        # Setup universe
        self.UniverseSettings.Resolution = Resolution.Minute
        self.UniverseSettings.FillForward  = True
        self.SetSecurityInitializer(lambda x: x.SetDataNormalizationMode(DataNormalizationMode.Raw))
        self.AddUniverse(self.SelectCoarse,self.SelectFine)
        
        # Store yesterday's close in a dictionary for reference
        self.coarseclose={}  
        # Only enter a trade if today's price [doubles] yesterday's close
        self.targetentry=2
        # Position sizing
        self.numstocks = 100

        # Exit when stock rises more tha [1.5] times from the entry level
        # Subject to a limit of [10] times the entry level
        self.stoplevel = 1.5
        self.limitlevel = 10
        # Keep track of stop loss orders so we can update them
        self.stops = {}        
        # Exclude any stocks where the data is incorrect
        self.excluded = ['MDIAV','SNDE','WLL','VTL','AMMA']
        
        # Provide triggers to take action on corporate events
        self.symbolchange = {}
        self.split = {}
        self.exitb4split= {}
        
        # Provide a trigger to exit stale trades
        self.daysintrade={}
    
    def SelectCoarse(self, coarse):
        # Penny Stock filter
        myuniverse = [x for x in coarse if x.Price < 2 and x.DollarVolume < 100000]
        myuniverse = [x for x in myuniverse if x.Symbol.Value not in self.excluded]
        # Clear the closing price dictionary each day before re-populating it
        self.coarseclose.clear()  
        # Save yesterday's close
        for c in myuniverse:
            self.coarseclose[c.Symbol] = c.Price
        return [x.Symbol for x in myuniverse] # Return filtered stocks for further filtering by the SelectFine
        
    def SelectFine(self,fine):
        fine_filter = [x.Symbol for x in fine] 

        for f in fine:
            # Reset these dictionaries each day
            self.symbolchange[f.Symbol] = 0
            self.split[f.Symbol] = 0
            self.exitb4split[f.Symbol]= 0

        return fine_filter


    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
            Arguments:
                data: Slice object keyed by symbol containing the stock data
        '''
        # Mark a symbol change for possible action    
        for kvp in data.SymbolChangedEvents:
            symbol = kvp.Key
            self.symbolchange[symbol] =1
        
        # Mark a data split so you don't get a false signal on a reverse split 
        # Necessary because we are using raw unadjusted data
        for kvp in data.Splits:
            symbol = kvp.Key
            value = kvp.Value
            if value.Type == 0:
                self.exitb4split[symbol] =1
            if value.Type == 1:
                self.split[symbol] =1

            
        for kvp in data:
            symbol = kvp.Key
            openOrders = self.Transactions.GetOpenOrders(symbol)
            open = kvp.Value.Open
            
            # To do: cancel stale entry orders
             
            # Optional provision to exit positions where 
            # Corporate actions interfere
            
            if ((self.Securities[symbol].Invested and 
                self.Securities[symbol].HasData) and
                (self.symbolchange[symbol] ==1 or 
                self.exitb4split[symbol] ==1)) :
                    #cancelledOrders = self.Transactions.CancelOpenOrders(symbol)
                    quantity = self.Portfolio[symbol].AbsoluteQuantity
                    if quantity < 0:
                        #exit_ticket = self.LimitOrder(symbol, -quantity,open, "Short Cover Split or SymbolChange")
                        #exit_ticket = self.MarketOrder(symbol, quantity,Tag =  "Short Cover Split or SymbolChange")
                        self.symbolchange[symbol] =3 
                        self.exitb4split[symbol] =3
             
            # Optional cancellation of stale positions           
            if (self.Securities[symbol].Invested and 
                self.Securities[symbol].HasData and
                #self.symbolchange[symbol] ==0 and 
                #self.exitb4split[symbol] ==0 and
                symbol in self.daysintrade.keys()):
                    #self.Debug(str(self.daysintrade[symbol]))
                    if self.daysintrade[symbol]>=10:
                        #cancelledOrders = self.Transactions.CancelOpenOrders(symbol)
                        quantity = self.Portfolio[symbol].Quantity
                        if quantity < 0:
                            #exit_ticket = self.LimitOrder(symbol, -quantity,open, "Exit stale trade")
                            self.daysintrade[symbol]=0
            
            # Short entry after sharp rise from yesterday's close
            # Don't enter if the rise is an illusion caused by a reverse split
            if ((not self.Securities[symbol].Invested and 
                not openOrders) and self.Securities[symbol].HasData and
                symbol in self.coarseclose.keys() and
                self.split[symbol]==0 and 
                self.exitb4split[symbol] ==0 and 
                self.symbolchange[symbol] ==0 and
                open >= self.coarseclose[symbol]*self.targetentry and 
                self.Time.hour <= 15 and self.Time.minute <=00):
                    
                quantity = int(self.Portfolio.TotalPortfolioValue / self.numstocks / data[symbol].Close)
                if quantity < 1:
                        continue
                # Enter with limit order
                enter_ticket = self.LimitOrder(symbol, -quantity,open, "Short Entry")
                self.daysintrade[symbol]=1

    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Filled: 
            order = self.Transactions.GetOrderById(orderEvent.OrderId)
            
            #Place profit taking and stop loss orders
            if order.Tag == "Short Entry": 
            
                quantity = orderEvent.AbsoluteFillQuantity
                quarter = int(quantity / 4)
                final = quantity - 3 * quarter
                fill= orderEvent.FillPrice
                symbol = orderEvent.Symbol
                for i in range(3):
                    if i==0:
                        order1 = self.LimitOrder(symbol, quarter, fill * (1 + (i+1)*-0.1)," 1st Profit Taking Limit Order")
                    if i ==1:
                        order2 = self.LimitOrder(symbol, quarter, fill * (1 + (i+1)*-0.1),"2nd Profit Taking Limit Order")
                    if i==2:
                        order3 = self.LimitOrder(symbol, quarter, fill * (1 + (i+1)*-0.1),"3rd Profit Taking Limit Order")                
                    order4 = self.LimitOrder(symbol, final, fill * 0.6,"4th Profit Taking Limit Order")
                
                # Set stop loss
                self.stops[symbol] = self.StopLimitOrder(symbol, quantity, fill * self.stoplevel, fill * self.limitlevel,"Stop Limit Order")
            
            # If hit profit target, update stop order quantity
            if (order.Tag == "1st Profit Taking Limit Order" or
                order.Tag == "2nd Profit Taking Limit Order" or
                order.Tag == "3rd Profit Taking Limit Order" or
                order.Tag == "4th Profit Taking Limit Order"):                   
                    updateSettings = UpdateOrderFields()
                    updateSettings.Quantity =  - self.Portfolio[orderEvent.Symbol].Quantity
                    if updateSettings.Quantity !=0:
                        self.stops[orderEvent.Symbol].Update(updateSettings)
                    else:
                        self.stops[orderEvent.Symbol].Cancel()
            
    # Increment Stale trade counter
    def OnEndOfDay(self):
        for kvp in self.Portfolio:
            symbol = kvp.Key
            holding = kvp.Value 
            if holding.Invested and symbol in self.daysintrade.keys():
                self.daysintrade[symbol] += 1