Overall Statistics |
Total Trades 543 Average Win 0.19% Average Loss -0.02% Compounding Annual Return -4.983% Drawdown 5.800% Expectancy -0.481 Net Profit -4.275% Sharpe Ratio -1.369 Probabilistic Sharpe Ratio 0.005% Loss Rate 94% Win Rate 6% Profit-Loss Ratio 7.74 Alpha -0.038 Beta -0.009 Annual Standard Deviation 0.03 Annual Variance 0.001 Information Ratio -2.339 Tracking Error 0.124 Treynor Ratio 4.718 Total Fees $645.89 |
#https://www.quantconnect.com/forum/discussion/7867/tim-sykes-and-penny-stocks/p1 class CalibratedUncoupledCoreWave(QCAlgorithm): def Initialize(self): self.SetStartDate(2019, 1, 1) # Set Start Date self.SetEndDate(2019, 11, 10) # Set End Date self.SetCash(100000) # Set Strategy Cash # Setup universe self.UniverseSettings.Resolution = Resolution.Minute self.AddUniverse(self.SelectCoarse,self.SelectFine) self.AddEquity("SPY", Resolution.Minute) # Liquidate all positions before the market close each day self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 30), self.ClosePositions) self.coarseclose={} # Store yesterday's close in a dictionary for reference self.traded={} # Ensure only 1 trade per day per stock self.targetentry=2 # Only enter a trade if today's price doubles yesterday's close self.stops = {} # Keep track of stop loss orders so we can update them self.coarsefilter = 100 # return the top x stocks sorted by momentum self.histlength = 25 # lngth of history to call to ensure sufficient data self.momlength = 21 # lookback period for momentum def SelectCoarse(self, coarse): # Penny Stock filter myuniverse = [x for x in coarse if x.HasFundamentalData and \ x.DollarVolume > 1000 and \ x.DollarVolume < 500000 and \ x.Price > 0 and x.Price <= 5.0] self.coarseclose.clear() # Clear the dictionary each day before re-populating it stocks = {x.Symbol: x for x in myuniverse} histStocks=list(stocks.keys()) history = self.History(histStocks, self.histlength, Resolution.Daily) mom={} for stock in histStocks: if stock in history.index: df = history.loc[stock].dropna() if df.empty or len(df)<self.histlength: continue #mom[stock]=((df["close"].pct_change()).std())*15.87*100 mom[stock]=(df["close"].iloc[-1]/df["close"].iloc[-self.momlength])-1 sortedbyMomentum = sorted(mom.items(), key=lambda x: x[1], reverse=False)[:self.coarsefilter] # Save yesterday's close for c in myuniverse: self.coarseclose[c.Symbol] = c.AdjustedPrice return [x[0] for x in sortedbyMomentum[:self.coarsefilter]] # Return filtered stocks for further filtering by the SelectFine def SelectFine(self,fine): ''' This function takes the stock of the CoarceFundamental function and narrow the list adding specific fundamental filters Largely to ensure that only common stock is traded and not EG Preference Shares or ETFs ''' # Primary share, common stock, not limited partnership, and not ADR fine_filter = [x.Symbol for x in fine if x.SecurityReference.IsPrimaryShare == 1 and \ x.SecurityReference.SecurityType == 'ST00000001' and \ x.CompanyReference.IsLimitedPartnership == 0 and \ x.SecurityReference.IsDepositaryReceipt == 0 ] self.traded.clear() self.traded = {k: 0 for k in fine_filter} 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 ''' for kvp in data.Bars: symbol = kvp.Key close = kvp.Value.Close # Entry conditions: # - We have no position in this stock # - We haven't traded this symbol today # - Bar closed above our target # - Before 10:30am # - Large dollar volume for this bar if (self.Portfolio[symbol].Quantity == 0.0 and symbol in self.traded.keys() and self.traded[symbol] == 0 and close >= self.coarseclose[symbol]*self.targetentry and self.Time.hour <= 15 and self.Time.minute <=29 and close * kvp.Value.Volume >= 5000): # Signal today's entry self.traded[symbol] = 1 # Determine position size quantity = int(self.Portfolio.TotalPortfolioValue / 100 / data[symbol].Close) #self.CalculateOrderQuantity(symbol, 0.01) // 2 if quantity < 4: continue # Enter with market order enter_ticket = self.MarketOrder(symbol, -quantity) # Set profit targets quarter = int(quantity / 4) final = quantity - 3 * quarter for i in range(3): order = self.LimitOrder(symbol, quarter, enter_ticket.AverageFillPrice * (1 + (i+1)*0.05)) updateSettings = UpdateOrderFields() updateSettings.Tag = "pt" order.Update(updateSettings) order = self.LimitOrder(symbol, final, enter_ticket.AverageFillPrice * 1.2) order.Update(updateSettings) # Set stop loss self.stops[symbol] = self.StopMarketOrder(symbol, -quantity, enter_ticket.AverageFillPrice * 1.05) updateSettings.Tag = "sl" self.stops[symbol].Update(updateSettings) def OnOrderEvent(self, orderEvent): if orderEvent.Status == OrderStatus.Filled: order = self.Transactions.GetOrderById(orderEvent.OrderId) if order.Tag == 'pt': # If hit profit target, update stop order quantity updateSettings = UpdateOrderFields() updateSettings.Quantity = self.stops[orderEvent.Symbol].Quantity - orderEvent.Quantity self.stops[orderEvent.Symbol].Update(updateSettings) elif order.Tag == 'sl': # If hit stop loss, cancel profit target orders self.Transactions.CancelOpenOrders(orderEvent.Symbol, "Hit stop price") def ClosePositions(self): if self.Portfolio.Invested: self.Transactions.CancelOpenOrders() self.Liquidate()