I have reviewed the OnOrderEvent documentation and - at least for me - it isn't quite clear how to reference the filled order data in the algorithm. If the algorithm logic dictates taking a long position, and the associated trailing stop-loss is hit, I do not want to re-enter long, rather, I want to wait until the indicator dictates taking a short position to trade again (and vice versa). To do this, I need to reference the most recent order ticket filled quantity as a short cover will be >0 and a long cover will be <0. Any suggestions?

The code below is a mashup of the ‘Trailing Stop Loss’ and ‘MACD Simplified’ templates provided by Quantconnect:

  1. class MACDTrendAlgorithm(QCAlgorithm):
  2. stopMarketTicket = None
  3. stopMarketOrderFillTime = datetime.min
  4. stopLoss = 0
  5. fill_quantity = 0
  6. def Initialize(self):
  7. #algorith basics setup
  8. self.SetStartDate(2018, 1, 1)
  9. self.SetEndDate(2021, 10, 22)
  10. self.SetCash(25000)
  11. self.stock = self.AddEquity("TQQQ", Resolution.Minute)
  12. # self.stock.SetDataNormalizationMode(DataNormalizationMode.Raw)
  13. self.symbol = self.stock.Symbol
  14. #indicator setup
  15. self.macd = self.MACD(self.symbol, 6, 35, 6, MovingAverageType.Exponential, Resolution.Daily)
  16. self.PlotIndicator("MACD", True, self.macd, self.macd.Signal)
  17. self.PlotIndicator("TQQQ", self.macd.Fast, self.macd.Slow)
  18. self.SetWarmUp(5*41, Resolution.Daily)
  19. #risk-management setup
  20. #self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.10))
  21. def OnData(self, data):
  22. if self.IsWarmingUp or not self.macd.IsReady: return
  23. tolerance = 0.0025
  24. holdings = self.Portfolio[self.symbol].Quantity
  25. signalDeltaPercent = (self.macd.Current.Value - self.macd.Signal.Current.Value)/self.macd.Fast.Current.Value
  26. #if not invested, but previously was invested and stop loss was triggered, wait until signal flips to take position
  27. if holdings <= 0 and signalDeltaPercent > tolerance and fill_quantity > 0: #need to add OnOrderEvent.FillQuantity logic to check for stop loss trigger
  28. self.SetHoldings(self.symbol, 1.0)
  29. self.stopMarketTicket = self.StopMarketOrder(self.stock, -self.Portfolio[self.stock].Quantity, 0.9 * self.Securities[self.stock].Close)
  30. elif holdings >= 0 and signalDeltaPercent < -tolerance and fill_quantity < 0: #need to add OnOrderEvent.FillQuantity logic to check for stop loss trigger
  31. self.SetHoldings(self.symbol, -1.0)
  32. self.stopMarketTicket = self.StopMarketOrder(self.stock, self.Portfolio[self.stock].Quantity, 0.9 * self.Securities[self.stock].Close)
  33. #if not invested, but previously was invested and stop loss wasn't triggered, flip position
  34. elif holdings <= 0 and signalDeltaPercent > tolerance:
  35. self.Liquidate()
  36. self.SetHoldings(self.symbol, 1.0)
  37. self.stopMarketTicket = self.StopMarketOrder(self.stock, -self.Portfolio[self.stock].Quantity, 0.9 * self.Securities[self.stock].Close)
  38. elif holdings >= 0 and signalDeltaPercent < -tolerance:
  39. self.Liquidate()
  40. self.SetHoldings(self.symbol, -1.0)
  41. self.stopMarketTicket = self.StopMarketOrder(self.stock, self.Portfolio[self.stock].Quantity, 0.9 * self.Securities[self.stock].Close)
  42. #trailing stop loss logic if position is long
  43. if self.Porfolio[self.stock] > 0 and self.Securities[self.stock].Close > self.stopLoss:
  44. self.stopLoss = self.Securities[self.stock].Close
  45. updateFields = UpdateOrderFields()
  46. updateFields.StopPrice = self.stopLoss * 0.95
  47. self.stopMarketTicket.Update(updateFields)
  48. self.Debug("SPY: " + str(self.stopLoss) + " Stop: " + str(updateFields.StopPrice))
  49. #trailing stop loss logic if position is short
  50. elif self.Porfolio[self.stock] < 0 and self.Securities[self.stock].Close < self.stopLoss:
  51. self.stopLoss = self.Securities[self.stock].Close
  52. updateFields = UpdateOrderFields()
  53. updateFields.StopPrice = self.stopLoss * 0.95
  54. self.stopMarketTicket.Update(updateFields)
  55. self.Debug("SPY: " + str(self.stopLoss) + " Stop: " + str(updateFields.StopPrice))
  56. def OnOrderEvent(self, orderEvent):
  57. if orderEvent.Status != OrderStatus.Filled:
  58. return
  59. if self.stopMarketTicket is not None and self.stopMarketTicket.OrderId == orderEvent.OrderId:
  60. self.stopMarketOrderFillTime = self.Time
  61. fill_quantity = self.Securities[self.stock].FillQuantity
+ Expand


 

Author

James Hawkins

October 2021