Overall Statistics |
Total Trades 94 Average Win 1.22% Average Loss -0.80% Compounding Annual Return 14.536% Drawdown 4.500% Expectancy 0.826 Net Profit 35.747% Sharpe Ratio 1.53 Probabilistic Sharpe Ratio 81.161% Loss Rate 28% Win Rate 72% Profit-Loss Ratio 1.52 Alpha 0.094 Beta 0.043 Annual Standard Deviation 0.066 Annual Variance 0.004 Information Ratio -0.222 Tracking Error 0.209 Treynor Ratio 2.322 Total Fees $119.34 Estimated Strategy Capacity $1100000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X |
#region imports from AlgorithmImports import * #endregion class TrailingStopLoss(QCAlgorithm): def Initialize(self): self.Transactions.MarketOrderFillTimeout = timedelta(seconds=30) startingCash = 100000 self.SetCash(startingCash) # Set Strategy Cash self.SetStartDate(2020,1 , 1) self.SetEndDate(2022, 4, 1) symbol = "SPY" self.symbol = self.AddEquity(symbol, Resolution.Daily).Symbol self.tli = self.AddData(TLI, "tli", Resolution.Daily).Symbol self.tli1 = 0 #Variable to track tli1 self.longEntryThreshhold = 0.1 self.shortEntryThreshhold = -0.1 self.longAllocation = 0.9 # 100% long self.shortAllocation = -0.9 # 100% short self.entryTicketLong = None self.stopMarketTicketLong = None self.stopMarketLongPrice = 0 self.stopMarketShortPrice = 0 self.entryTicketShort = None self.stopMarketTicketShort = None self.entryTime = datetime.min self.stopMarketOrderFillTime = datetime.min self.highestPrice = 0 self.lowestPrice = 0 self.str1 = "hello" def OnData(self, data): price = self.Securities[self.symbol].Price openOrders = self.Transactions.GetOpenOrders(self.symbol) if(openOrders): self.Debug("There are open orders?") # move long stop limit if self.entryTicketLong is not None and self.Portfolio.Invested: # move up trailing stop price if price > self.highestPrice: self.highestPrice = price self.stopMarketLongPrice = 0.98 * price self.Debug("Adjusting stopMarketTicktLong") elif price < self.stopMarketLongPrice: self.Liquidate(self.symbol) # move short stop limit if self.entryTicketShort is not None and self.Portfolio.Invested: # move down trailing stop price if price < self.lowestPrice: self.lowestPrice = price self.stopMarketShortPrice = price * 1.02 elif price > self.stopMarketShortPrice: self.Liquidate(self.symbol) #self.Debug("Price : " + str(price)) curDT = self.Time if self.tli in data: tlitime = data[self.tli].Time self.str1 = curDT.strftime("%m/%d/%Y, %H:%M:%S") + ", tliTime " + tlitime.strftime("%m/%d/%Y, %H:%M:%S") + ", tli val "+ str(data[self.tli].Value) + ", price" + str(price) self.tli1 = data[self.tli].Value self.Debug(str(data[self.tli].Value)) # Check for long entry if not self.Portfolio.Invested: if self.tli1 >= self.longEntryThreshhold: self.Debug("Entering long") #str1 = "Entry Order Long, TLI: " + str(data[self.tli].Value) + " TLI_time" + str(data[self.tli].Time) self.GoLong(self.symbol, 0.9) #(self, symbol, ratio) self.entryTime = self.Time if self.tli1 <= self.shortEntryThreshhold: self.Debug("Entering short") self.GoShort(self.symbol, 0.9) #(self, symbol, ratio) self.entryTime = self.Time # move long limit price if not filled after 1 day #if (self.Time - self.entryTime).days > 1 and (self.entryTicketLong is not None) and self.entryTicketLong.Status != OrderStatus.Filled: # self.entryTime = self.Time # updateFields = UpdateOrderFields() # updateFields.LimitPrice = price # self.entryTicketLong.Update(updateFields) # move Short limit price if not filled after 1 day #if (self.Time - self.entryTime).days > 1 and (self.entryTicketShort is not None) and self.entryTicketShort.Status != OrderStatus.Filled: # self.entryTime = self.Time # updateFields = UpdateOrderFields() # updateFields.LimitPrice = price # self.entryTicketShort.Update(updateFields) # move long stop limit #if self.Portfolio.Invested: def CancelAllOrders(self): openOrders = self.Transactions.GetOpenOrders() if len(openOrders)> 0: for x in openOrders: self.Transactions.CancelOrder(x.Id) def GoLong(self, symbol, ratio): # Make sure we can trade this security = self.Securities[symbol] if not security.IsTradable: self.Debug("{} is not tradable.".format(symbol)) return # Setup vars orderQuantity = self.CalculateOrderQuantity(symbol, ratio) limit = 1.001 # +0.1% Limit Order above current price limitPrice = round( security.Price * limit, 2 ) openOrders = self.Transactions.GetOpenOrders(symbol) self.Transactions.CancelOpenOrders(symbol) self.Log('Going long, canceled all open orders, did a Market Order') self.SetHoldings(symbol, ratio) self.entryTicketLong = 1 self.stopMarketLongPrice = 0.98 * security.Price #if(openOrders): # Cancel all outstanding orders, then do a Market Order # self.Transactions.CancelOpenOrders(symbol) # self.Log('Going long, canceled all open orders, did a Market Order') # self.SetHoldings(symbol, ratio) #else: # No open orders, try a limit order then # self.LimitOrder(symbol, orderQuantity, limitPrice) # self.Log( str(security.Price) ) # self.Log('Going long. Placed a limit order at ' + str(limitPrice)) # self.Log('Going long, did a Market Order') # self.SetHoldings(symbol, ratio) def GoShort(self, symbol, ratio): # Make sure we can trade this security = self.Securities[symbol] if not security.IsTradable: self.Debug("{} is not tradable.".format(symbol)) return # Setup vars orderQuantity = self.CalculateOrderQuantity(symbol, ratio) limit = 0.999 # +0.1% Limit Order above current price limitPrice = round( security.Price * limit, 2 ) openOrders = self.Transactions.GetOpenOrders(symbol) self.Transactions.CancelOpenOrders(symbol) self.SetHoldings(symbol, -ratio) self.entryTicketShort = 1 self.stopMarketShortPrice = 1.02 * security.Price #if(openOrders): # Cancel all outstanding orders, then do a Market Order # self.Transactions.CancelOpenOrders(symbol) # self.SetHoldings(symbol, -ratio) # self.Log('Going short, canceled all open orders, did a Market Order') #else: # No open orders, try a limit order then # self.LimitOrder(symbol, -orderQuantity, limitPrice) # self.Log( str(security.Price) ) # self.Log('Going short. Placed a limit order at ' + str(limitPrice)) # self.Log('Going short, did a Market Order') # self.SetHoldings(symbol, -ratio) class TLI(PythonData): def GetSource(self, config, date, isLive): source = "https://www.dropbox.com/s/q4njfg7ihs2cwb0/TLI_20220415.csv?dl=1" return SubscriptionDataSource(source, SubscriptionTransportMedium.RemoteFile); def Reader(self, config, line, date, isLive): if not (line.strip() and line[0].isdigit()): return None data = line.split(',') tli = TLI() try: tli.Symbol = config.Symbol # make data available Monday morning (Friday 16:00 + 66 hours) # since we can't trade on weekend anyway tli.Time = datetime.strptime(data[0], '%Y-%m-%d %H:%M:%S') + timedelta(hours=66) tli.Value = data[1] except ValueError: return None return tli