Overall Statistics |
Total Trades 10 Average Win 0.29% Average Loss -0.16% Compounding Annual Return -32.316% Drawdown 17.400% Expectancy 1.069 Net Profit -7.509% Sharpe Ratio -0.5 Probabilistic Sharpe Ratio 20.380% Loss Rate 25% Win Rate 75% Profit-Loss Ratio 1.76 Alpha 0 Beta 0 Annual Standard Deviation 0.389 Annual Variance 0.151 Information Ratio -0.5 Tracking Error 0.389 Treynor Ratio 0 Total Fees $10.28 Estimated Strategy Capacity $97000000.00 Lowest Capacity Asset SBUX R735QTJ8XC9X |
import numpy as np from datetime import datetime import pandas as pd class AppendingInvestedToCoasre(QCAlgorithm): def Initialize(self): self.SetStartDate(2018, 6, 20) # Start date of backtest self.SetEndDate(2018, 9, 1) # End date of backtest self.coarse_amount = 5 self.SetCash(25000) # Amount of cash in account for backtest self.AddUniverse(self.CoarseSelectionFunction) # Adding CoarseSelectionFunction as Universe self.UniverseSettings.Resolution = Resolution.Daily # Sets Universe resolution to minute self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) self.Data= {} def CoarseSelectionFunction(self, coarse): sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True) stocks = [x.Symbol for x in sortedByDollarVolume if x.Price > 15 and x.DollarVolume >= 900000 and x.HasFundamentalData == True] #HasFundamentalData effectivley removes indexs/ETFs invested = [ x.Symbol for x in self.Portfolio.Values if x.Invested ] invested_tickers = [ x.Symbol.Value for x in self.Portfolio.Values if x.Invested ] #Debug Code self.Debug(f"(Coarse) Invested in {len(invested)} stocks: {invested_tickers}") stocks = invested + stocks try: if invested[0] in stocks[:self.coarse_amount]: index_of_invested = stocks.index(invested[0]) self.Debug(f"The index of invested[0] in stocks is {index_of_invested} and is {stocks[index_of_invested]}") except: pass try: if invested[1] in stocks[:self.coarse_amount]: index_of_invested = stocks.index(invested[1]) self.Debug(f"The index of invested[1] in stocks is {index_of_invested} and is {stocks[index_of_invested]}") except: pass return_amount = self.coarse_amount + len(invested) self.Debug(f"We are returning {(return_amount)} symbols from the Coarse function") return stocks[:return_amount] def OnSecuritiesChanged(self, changes): i=0 syms=[] for security in changes.AddedSecurities: i+=1 syms.append(security.Symbol.Value) symbol = security.Symbol if symbol not in self.Data: self.Data[symbol] = SymbolData(self, symbol) self.Debug(f"in Added Securities we looped through {i} added securities: {syms}") i=0 syms=[] for security in changes.RemovedSecurities: symbol = security.Symbol i+=1 syms.append(security.Symbol.Value) if symbol in self.Data: symbolData = self.Data.pop(symbol, None) self.SubscriptionManager.RemoveConsolidator(symbol, symbolData.consolidator) # Remove subcription for symbols removed from universe self.SubscriptionManager.RemoveConsolidator(symbol, symbolData.consolidatorMinute) self.Debug(f"in Removed Securities we looped through {i} removed securities: {syms}") # =============== ON DATA ============================ # def OnData(self, data): self.Debug(f"===On Data===") invested = [ x.Symbol.Value for x in self.Portfolio.Values if x.Invested ] self.Debug(f"\n(onData) Invested in {len(invested)} stocks") if len(invested) > 0: for i in range(0,len(invested)): self.Debug(f"{i+1}/{len(invested)}: {invested[i]}") symbols_in_onData = [] for symbol in self.Data.keys(): symbols_in_onData.append(symbol.Value) if symbol in invested: self.Debug(f"{symbol.value} was in invested") symbolData = self.Data[symbol] if not symbolData.IsReady: self.Debug(f"{symbol.Value} was not ready") #Check for sell conditions try: if symbol in invested: s1 = symbolData.Bars[0].Close < symbolData.Bars[1].Close if s1: self.Liquidate(symbol) self.Debug(f"{symbol.Value} was liquidated") else: pass except: self.Debug(f"Error in selling code: with {symbol.Value}") #Check for Buy conditions try: b1 = symbolData.Bars[0].Close > symbolData.Bars[1].Close b2 = symbolData.Bars[1].Close > symbolData.Bars[2].Close if b1 and b2: self.SetHoldings(symbol, 0.5) self.Debug(f"Conditions to buy met for {symbol.Value} ") else: pass except: self.Debug(f"Error in buy code: with {symbol.Value}") len_onData = len(symbols_in_onData) self.Debug(f" {len_onData} symbols were looped through onData slice {symbols_in_onData}") i=0 for symbol in invested: if symbol in symbols_in_onData: i+=1 self.Debug(f" {symbol} found in onData symbols") self.Debug(f"{i}/{len(invested)} invested symbols found in the {len_onData} symbols)") #======= ORDER EVENTS=================== def OnOrderEvent(self, orderEvent): order = self.Transactions.GetOrderById(orderEvent.OrderId) if order.Status == OrderStatus.Filled: if order.Type == OrderType.Limit or order.Type == OrderType.StopMarket: self.Transactions.CancelOpenOrders(order.Symbol) if order.Status == OrderStatus.Canceled: pass #self.Log(str(orderEvent)) #============= SYMBOL DATA CLASS ========================== # class SymbolData: def __init__(self, algorithm, symbol): self.algorithm = algorithm self.symbol = symbol #self.emaOne = algorithm.EMA(symbol, 1, Resolution.Minute) self.ema3 = algorithm.EMA(symbol, 3, Resolution.Daily) self.ema4 = algorithm.EMA(symbol, 4, Resolution.Daily) self.ema50 = algorithm.EMA(symbol, 50, Resolution.Daily) self.ema200 = algorithm.EMA(symbol, 200, Resolution.Daily) self.ema200D = algorithm.EMA(symbol, 200, Resolution.Daily) self.ema200Window = RollingWindow[float](20) self.bb = algorithm.BB(symbol, 20, 2, MovingAverageType.Simple, Resolution.Daily) self.bbWindow = RollingWindow[float](5) self.bb17 = algorithm.BB(symbol, 20, 1.5, MovingAverageType.Simple, Resolution.Daily) self.bb17Window = RollingWindow[float](5) self.bb17LowerBandWindow = RollingWindow[float](5) self.momp = algorithm.MOMP(symbol, 30, Resolution.Daily) self.mompWindow = RollingWindow[float](200) self.rsi = algorithm.RSI(symbol, 14 , Resolution.Daily) self.rsiWindow = RollingWindow[float](20) self.macd = {} #do I need? self.macd = algorithm.MACD(symbol, 12, 26, 9, MovingAverageType.Exponential, Resolution.Daily) self.macdWindow = RollingWindow[float](5) self.macdHistogramWindow = RollingWindow[float](5) #====== V-MACD ============= self.vwap12 = algorithm.VWAP(symbol, 12, Resolution.Daily) #12 period VWAP self.vwap26 = algorithm.VWAP(symbol, 26, Resolution.Daily) #26 perios VWAP self.vmacd = IndicatorExtensions.Minus(self.vwap12, self.vwap26) #vwap26 - vwap12 self.vmacdSignal = IndicatorExtensions.EMA(self.vmacd, 9) self.vmacdHistogram = IndicatorExtensions.Minus(self.vmacd, self.vmacdSignal) #swap self.vmacdHistogramWindow = RollingWindow[float](5) self.close_window = RollingWindow[float](22) self.Bars = RollingWindow[IBaseDataBar](22) # Rolling window for data bars self.consolidator = TradeBarConsolidator(timedelta(days=1)) self.consolidator.DataConsolidated += self.OnDataConsolidated algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator) self.BarsWeek = RollingWindow[IBaseDataBar](22) # Rolling window for data bars self.consolidatorWeek = TradeBarConsolidator(timedelta(days=1)) self.consolidatorWeek.DataConsolidated += self.OnDataConsolidatedWeek algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidatorWeek) self.BarsMinute = RollingWindow[IBaseDataBar](22) # Rolling window for data bars self.consolidatorMinute = TradeBarConsolidator(timedelta(days=2)) self.consolidatorMinute.DataConsolidated += self.OnDataConsolidatedMinute algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidatorMinute) #=====History Calls======== history = algorithm.History(self.symbol, 25, Resolution.Daily).loc[self.symbol] for time, row in history.iterrows(): tradebar = TradeBar(time, self.symbol, row.open, row.high, row.low, row.close, row.volume) self.consolidatorMinute.Update(tradebar) history = algorithm.History(self.symbol, 200, Resolution.Daily).loc[self.symbol] for time, row in history.iterrows(): tradebar = TradeBar(time, self.symbol, row.open, row.high, row.low, row.close, row.volume) self.consolidator.Update(tradebar) self.consolidatorWeek.Update(tradebar) self.vwap12.Update(tradebar) self.vwap26.Update(tradebar) # Warm up indicators history = algorithm.History([symbol], 201, Resolution.Daily) for time, row in history.loc[symbol].iterrows(): #self.emaOne.Update(time, row["close"]) self.ema200.Update(time, row["close"]) self.momp.Update(time, row["close"]) self.ema3.Update(time, row["close"]) self.ema4.Update(time, row["close"]) self.bb.Update(time, row["close"]) self.bb17.Update(time, row["close"]) self.rsi.Update(time, row["close"]) self.macd.Update(time, row["close"]) self.close_window.Add(row["close"]) #Per anwser it needs the close only #Warm the Rolling Windows if self.ema200.IsReady: self.ema200Window.Add(self.ema200.Current.Value) if self.rsi.IsReady: self.rsiWindow.Add(self.rsi.Current.Value) if self.bb.IsReady: self.bbWindow.Add(self.bb.Current.Value) if self.bb17.IsReady: self.bb17Window.Add(self.bb17.Current.Value) self.bb17LowerBandWindow.Add(self.bb17.LowerBand.Current.Value) if self.macd.IsReady: self.macdWindow.Add(self.macd.Current.Value) self.macdHistogramWindow.Add(self.macd.Histogram.Current.Value) self.vmacdHistogramWindow.Add(self.vmacdHistogram.Current.Value) if self.momp.IsReady: self.mompWindow.Add(self.momp.Current.Value) history = algorithm.History([symbol], 200, Resolution.Daily) for time, row in history.loc[symbol].iterrows(): self.ema200D.Update(time, row["close"]) # Consolidators def OnDataConsolidated(self, sender, bar): self.Bars.Add(bar) def OnDataConsolidatedMinute(self, sender, bar): self.BarsMinute.Add(bar) def OnDataConsolidatedWeek(self, sender, bar): self.BarsWeek.Add(bar) @property def IsReady(self): return self.Bars.IsReady and self.BarsWeek.IsReady and self.rsi.IsReady and self.ema200.IsReady and self.macd.IsReady #and self.macdWindow.IsReady