Hi, i'm faced with an error: value error

ValueError : min() arg is an empty sequenceat OnDatanextResistanceLevel = greater_than_price[min(range(len(greater_than_price)) in main.py: line 69

every time i try executing this algorithm, yet when i look through the backtest logs, i see there seem to be not an empty sequence as there exist support values as well as resistance values. need some help and advice. 

Here's code of the algorithm for further review. 

  1. from datetime import datetime,timedelta
  2. import numpy as np
  3. Macdlong = None
  4. AboveSupport = None
  5. BelowResistance = None
  6. class CreativeYellowTapir(QCAlgorithm):
  7. def Initialize(self):
  8. self.SetStartDate(2019, 1, 30) # Set Start Date
  9. self.SetEndDate(2020, 12, 30)
  10. self.SetCash(100000) # Set Strategy Cash
  11. self.ticker = "USDCAD"
  12. # Rolling Windows to hold bar close data keyed by symbol
  13. self.Data = {}
  14. #for ticker in tickers:
  15. symbol = self.AddForex(self.ticker, Resolution.Hour, Market.Oanda).Symbol
  16. self.Data[symbol] = SymbolData(self, symbol)
  17. self.tolerance = 0.0025
  18. self.toleranceR = 0.986761994
  19. self.toleranceS = 1.004000555
  20. self.stopLossLevel = -0.05 # stop loss percentage
  21. self.stopProfitLevel = 0.01# stop profit percentage
  22. self.SetWarmUp(400, Resolution.Hour)
  23. #def MarketClose(self):
  24. #self.SupportResistance.Reset()
  25. def OnData(self, data):
  26. #if self.IsWarmingUp: #Data to warm up the algo is being collected.
  27. # return
  28. for symbol, symbolData in self.Data.items(): #Return the dictionary's key-value pairs:
  29. if not (data.ContainsKey(symbol) and data[symbol] is not None and symbolData.IsReady):
  30. continue
  31. if self.IsWarmingUp or not all([symbolData.IsReady for symbolData in self.Data.values()]):
  32. return
  33. MACD = symbolData.macd.Current.Value
  34. MACDfast = symbolData.macd.Fast.Current.Value
  35. RSI = symbolData.rsi.Current.Value
  36. current_price = data[symbol].Close
  37. signalDeltaPercent = (MACD - MACD)/MACDfast
  38. supports, resistances = self.NextSupportResistance(symbolData.closeWindow)
  39. self.Log(f"Symbol: {symbol.Value} , Supports: {supports} , Resistances: {resistances}")
  40. #Getting the next support level
  41. if not len(supports) > 1 and not len(resistances) > 1:
  42. return
  43. #Getting the next resistance level *****
  44. greater_than_price = [y for y in resistances if y > current_price ]
  45. nextResistanceLevel = greater_than_price[min(range(len(greater_than_price)), key=lambda i: abs(greater_than_price[i] - current_price))]
  46. #Getting the next support level *****
  47. less_than_price = [x for x in supports if x < current_price ]
  48. nextSupportLevel = less_than_price[min(range(len(less_than_price)), key=lambda i: abs(less_than_price[i] - current_price))]
  49. if self.Portfolio[symbol].Invested:
  50. if self.isLong:
  51. condStopProfit = (current_price - self.buyInPrice)/self.buyInPrice > self.stopProfitLevel
  52. condStopLoss = (current_price - self.buyInPrice)/self.buyInPrice < self.stopLossLevel
  53. if condStopProfit:
  54. self.Liquidate(symbol)
  55. self.Log(f"{self.Time} Long Position Stop Profit at {current_price}")
  56. if condStopLoss:
  57. self.Liquidate(symbol)
  58. self.Log(f"{self.Time} Long Position Stop Loss at {current_price}")
  59. else:
  60. condStopProfit = (self.sellInPrice - current_price)/self.sellInPrice > self.stopProfitLevel
  61. condStopLoss = (self.sellInPrice - current_price)/self.sellInPrice < self.stopLossLevel
  62. if condStopProfit:
  63. self.Liquidate(symbol)
  64. self.Log(f"{self.Time} Short Position Stop Profit at {current_price}")
  65. if condStopLoss:
  66. self.Liquidate(symbol)
  67. self.Log(f"{self.Time} Short Position Stop Loss at {current_price}")
  68. if not self.Portfolio[symbol].Invested:
  69. closestResistanceZone = nextResistanceLevel
  70. closestSupportZone = nextSupportLevel
  71. MacdLong = signalDeltaPercent > self.tolerance
  72. AboveSupport = current_price > closestSupportZone * self.toleranceS
  73. BelowResistance = current_price < closestResistanceZone * self.toleranceR
  74. # tolerance = will be dependent on the minimum number of pips before a r/s level
  75. if RSI > 50 and Macdlong and BelowResistance:
  76. self.SetHoldings(symbol, 1)
  77. # get buy-in price for trailing stop loss/profit
  78. self.buyInPrice = current_price
  79. # entered long position
  80. self.isLong = True
  81. self.Log(f"{self.Time} Entered Long Position at {current_price}")
  82. if RSI < 50 and not Macdlong and AboveSupport:
  83. self.SetHoldings(symbol, -1)
  84. # get sell-in price for trailing stop loss/profit
  85. self.sellInPrice = current_price
  86. # entered short position
  87. self.isLong = False
  88. self.Log(f"{self.Time} Entered Short Position at {current_price}")
  89. def NextSupportResistance(self, window, variation = 0.005, h = 3):
  90. #price = self.Securities[self.ticker].Close
  91. series = window
  92. supports = []
  93. resistances = []
  94. maxima = []
  95. minima = []
  96. # finding maxima and minima by looking for hills/troughs locally
  97. for i in range(h, series.Size-h):
  98. if series[i] > series[i-h] and series[i] > series[i+h]:
  99. maxima.append(series[i])
  100. elif series[i] < series[i-h] and series[i] < series[i+h]:
  101. minima.append(series[i])
  102. # identifying maximas which are resistances
  103. for m in maxima:
  104. r = m * variation
  105. # maxima which are near each other
  106. commonLevel = [x for x in maxima if x > m - r and x < m + r]
  107. # if 2 or more maxima are clustered near an area, it is a resistance
  108. if len(commonLevel) > 1:
  109. # we pick the highest maxima if the cluster as our resistance
  110. level = max(commonLevel)
  111. if level not in resistances:
  112. resistances.append(level)
  113. # identify minima which are supports
  114. for l in minima:
  115. r = l * variation
  116. # minima which are near each other
  117. commonLevel = [x for x in minima if x > l - r and x < l + r]
  118. # if 2 or more minima are clustered near an area, it is a support
  119. if len(commonLevel) > 1:
  120. # We pick the lowest minima of the cluster as our support
  121. level = min(commonLevel)
  122. if level not in supports:
  123. supports.append(level)
  124. return supports, resistances #nextSupportLevel, nextResistanceLevel
  125. class SymbolData:
  126. def __init__(self, algorithm, symbol):
  127. self.macd = MovingAverageConvergenceDivergence(12,26,9)
  128. self.rsi = RelativeStrengthIndex(14)
  129. self.macdWindow = RollingWindow[IndicatorDataPoint](2) #setting the Rolling Window for the fast MACD indicator, takes two values
  130. algorithm.RegisterIndicator(symbol, self.macd, timedelta(hours=4))
  131. self.macd.Updated += self.MacdUpdated #Updating those two values
  132. self.rsiWindow = RollingWindow[IndicatorDataPoint](2) #setting the Rolling Window for the slow SMA indicator, takes two values
  133. algorithm.RegisterIndicator(symbol, self.rsi, timedelta(hours=4))
  134. self.rsi.Updated += self.RsiUpdated #Updating those two values
  135. self.closeWindow = RollingWindow[float](200)
  136. # Add consolidator to track rolling close prices
  137. self.consolidator = QuoteBarConsolidator(4)
  138. self.consolidator.DataConsolidated += self.CloseUpdated
  139. algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator)
  140. def MacdUpdated(self, sender, updated):
  141. '''Event holder to update the MACD Rolling Window values'''
  142. if self.macd.IsReady:
  143. self.macdWindow.Add(updated)
  144. def RsiUpdated(self, sender, updated):
  145. '''Event holder to update the RSI Rolling Window values'''
  146. if self.rsi.IsReady:
  147. self.rsiWindow.Add(updated)
  148. def CloseUpdated(self, sender, bar):
  149. '''Event holder to update the close Rolling Window values'''
  150. self.closeWindow.Add(bar.Close)
  151. @property
  152. def IsReady(self):
  153. return self.macd.IsReady and self.rsi.IsReady and self.closeWindow.IsReady
+ Expand

and here are the logs of that backtest.

137906_1631792145.jpg

I would appreciate any and all the help that i can get.

Author

Samwel Kibet

September 2021