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