Overall Statistics |
Total Trades 3 Average Win 0.01% Average Loss 0% Compounding Annual Return 1.191% Drawdown 0.000% Expectancy 0 Net Profit 0.019% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 100% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio -16.794 Tracking Error 0.059 Treynor Ratio 0 Total Fees $9.75 |
import pandas as pd #https://www.quantconnect.com/forum/discussion/7867/tim-sykes-and-penny-stocks/p1 class CalibratedUncoupledCoreWave(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 5, 1) # Set Start Date #self.SetEndDate(2020, 3, 11) # 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.volumeprior = {} # Last x days' average dollar volume self.stddev={} # Standard Deviation self.minmax={} # Ratio of Hi Lo of last x days' close price self.cumvol={} # Cumulative volume throughout trading day self.traded={} # Ensure only 1 trade per day per stock self.targetentry=1.05 # 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 = 50 # return the top x stocks sorted by [momentum] etc self.histlength = 60 # lngth of history to call to ensure sufficient data def SelectCoarse(self, coarse): # Penny Stock filter myuniverse = [x for x in coarse if x.HasFundamentalData and \ x.DollarVolume > 1000 and \ x.DollarVolume < 50000 and \ x.Price > 0 and x.Price <= 2.0] self.coarseclose.clear() # Clear the dictionary each day before re-populating it self.volumeprior.clear() self.stddev.clear() self.minmax.clear() stocks = {x.Symbol: x for x in myuniverse} histStocks=list(stocks.keys()) history = self.History(histStocks, self.histlength, Resolution.Daily) scam={} for stock in histStocks: if stock in history.index: df = pd.DataFrame() if not history.loc[stock].empty: df = history.loc[stock].dropna() if df.empty or len(df)<self.histlength: continue # Some alternative filters self.volumeprior[stock] = df['volume'][-5:].mean() self.stddev[stock]=((df["close"][-5:].pct_change()).std())*15.87*100 self.minmax[stock]=((df["close"][-10:].max()/df["close"][-10:].min())-1)*100 if self.minmax[stock] < 10.00 and self.volumeprior[stock]< 50000 : scam[stock]= self.minmax[stock] #scammed=[key for (key, value) in sorted(scam.items(),reverse=False)] scammed=[key for (key, value) in scam.items()] # Save yesterday's close for c in myuniverse: self.coarseclose[c.Symbol] = c.AdjustedPrice return scammed[:] # 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} self.cumvol.clear() self.cumvol = {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 if symbol in self.cumvol.keys(): self.cumvol[symbol]=self.cumvol[symbol]+(kvp.Value.Close*kvp.Value.Volume) # Entry conditions: # - We have no position in this stock # - We haven't traded this symbol today # - Bar closed above our target # - Before 10:30am # - Cumulative Volume for the day exceeds average total dollar volume for past x days 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 <= 10 and self.Time.minute <=30 and self.cumvol[symbol] >= self.volumeprior[symbol]): # 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.20) order.Update(updateSettings) # Set stop loss self.stops[symbol] = self.StopMarketOrder(symbol, -quantity, enter_ticket.AverageFillPrice * 0.50) 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()