Hey,

I already have list of Support levels of the Daily chart and of the 4hr timeframe, as well as resistance levels of daily and 4 hour timeframe. The challenge i have is, how do i identify the most relevant support and resitance level? (The ones closest to my current_price) so that i can use it as a condition to trade. depending on how close i am to it.

Here is my code block for the Daily support and resistance levels:

  1. from datetime import datetime,timedelta
  2. import numpy as np
  3. class ReversalAlpha(QCAlgorithm):
  4. def Initialize(self):
  5. tickers = ["EURUSD","USDCAD"]
  6. # Rolling Windows to hold bar close data keyed by symbol
  7. self.closingData = {}
  8. for ticker in tickers:
  9. symbol = self.AddForex(ticker, Resolution.Daily, Market.Oanda).Symbol
  10. self.closingData[symbol] = RollingWindow[float](50)
  11. # Warm up our rolling windows
  12. self.SetWarmUp(50)
  13. def OnData(self, data):
  14. for symbol, window in self.closingData.items():
  15. if data.ContainsKey(symbol) and data[symbol] is not None:
  16. window.Add(data[symbol].Close)
  17. if self.IsWarmingUp or not all([window.IsReady for window in self.closingData.values()]):
  18. return
  19. for symbol, window in self.closingData.items(): #references the key-value pairs in the dictionary
  20. supports_D, resistances_D = self.GetPriceLevels(window) # Daily Supports and Daily Resistances
  21. self.Log(f"Symbol: {symbol.Value} , Supports: {supports_D} , Resistances: {resistances_D}")
  22. def GetPriceLevels(self, series, variation = 0.005, h = 3):
  23. supports_D = [] # List that will hold daily Supports points
  24. resistances_D = [] # List that will hold daily Resistances points
  25. maxima = []
  26. minima = []
  27. # finding maxima and minima by looking for hills/troughs locally
  28. for i in range(h, series.Size-h):
  29. if series[i] > series[i-h] and series[i] > series[i+h]:
  30. maxima.append(series[i])
  31. elif series[i] < series[i-h] and series[i] < series[i+h]:
  32. minima.append(series[i])
  33. # identifying maximas which are resistances
  34. for m in maxima:
  35. r = m * variation
  36. # maxima which are near each other
  37. commonLevel = [x for x in maxima if x > m - r and x < m + r]
  38. # if 2 or more maxima are clustered near an area, it is a resistance
  39. if len(commonLevel) > 1:
  40. # we pick the highest maxima if the cluster as our resistance
  41. level = max(commonLevel)
  42. if level not in resistances_D:
  43. resistances_D.append(level)
  44. # identify minima which are supports
  45. for l in minima:
  46. r = l * variation
  47. # minima which are near each other
  48. commonLevel = [x for x in minima if x > l - r and x < l + r]
  49. # if 2 or more minima are clustered near an area, it is a support
  50. if len(commonLevel) > 1:
  51. # We pick the lowest minima of the cluster as our support
  52. level = min(commonLevel)
  53. if level not in supports_D:
  54. supports_D.append(level)
  55. return supports_D, resistances_D
  56. # Your New Python File
+ Expand

as well as the code block for the 4hr support and resistance;

  1. from datetime import datetime,timedelta
  2. import numpy as np
  3. class ReversalBeta(QCAlgorithm):
  4. def Initialize(self):
  5. self.SetStartDate(2020, 1, 30) # Set Start Date
  6. self.SetEndDate(2020, 12, 30)
  7. self.SetCash(100000) # Set Strategy Cash
  8. tickers = ["EURUSD","USDCAD"]
  9. # Rolling Windows to hold bar close data keyed by symbol
  10. self.closingData = {} # Dictionary to hold a rolling window with bar close data for each ticker symbol
  11. for ticker in tickers:
  12. symbol = self.AddForex(ticker, Resolution.Hour, Market.Oanda).Symbol
  13. self.closingData[symbol] = SymbolData(self, symbol) #RollingWindow[float](50)
  14. # Warm up our rolling windows
  15. self.SetWarmUp(50)
  16. def OnData(self, data):
  17. if self.IsWarmingUp:
  18. return
  19. for symbol, symbolData in self.closingData.items(): #Returns self.closingData's dictionary key-value pairs
  20. if not (data.ContainsKey(symbol) and data[symbol] is not None and symbolData.IsReady):
  21. continue
  22. for symbol, window in self.closingData.items(): #references the key-value pairs in the dictionary
  23. supports_4H, resistances_4H = self.GetPriceLevels(window) #4 Hour Support and resistances
  24. self.Log(f"Symbol: {symbol.Value} , Supports: {supports_4H} , Resistances: {resistances_4H}")
  25. def GetPriceLevels(self, series, variation = 0.01, h = 3):
  26. supports_4H = [] # List that will hold 4 hour Supports points
  27. resistances_4H = [] # List that will hold 4 hour resistance points
  28. maxima = []
  29. minima = []
  30. # finding maxima and minima by looking for hills/troughs locally
  31. for i in range(h, series.Size-h):
  32. if series[i] > series[i-h] and series[i] > series[i+h]:
  33. maxima.append(series[i])
  34. elif series[i] < series[i-h] and series[i] < series[i+h]:
  35. minima.append(series[i])
  36. # identifying maximas which are resistances
  37. for m in maxima:
  38. r = m * variation
  39. # maxima which are near each other
  40. commonLevel = [x for x in maxima if x > m - r and x < m + r]
  41. # if 2 or more maxima are clustered near an area, it is a resistance
  42. if len(commonLevel) > 1:
  43. # we pick the highest maxima if the cluster as our resistance
  44. level = max(commonLevel)
  45. if level not in resistances_4H:
  46. resistances_4H.append(level)
  47. # identify minima which are supports
  48. for l in minima:
  49. r = l * variation
  50. # minima which are near each other
  51. commonLevel = [x for x in minima if x > l - r and x < l + r]
  52. # if 2 or more minima are clustered near an area, it is a support
  53. if len(commonLevel) > 1:
  54. # We pick the lowest minima of the cluster as our support
  55. level = min(commonLevel)
  56. if level not in supports_4H:
  57. supports_4H.append(level)
  58. return supports_4H, resistances_4H
  59. #creating a class for consolidating data into 4hour time frames
  60. class SymbolData:
  61. def __init__(self, algorithm, symbol):
  62. self.closeWindow = RollingWindow[float](50)
  63. # Add consolidator to track rolling close prices
  64. self.consolidator = TradeBarConsolidator(4)
  65. self.consolidator.DataConsolidated += self.CloseUpdated
  66. algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator)
  67. def CloseUpdated(self, sender, bar):
  68. '''Event holder to update the close Rolling Window values'''
  69. self.closeWindow.Add(bar.Close)
  70. @property
  71. def IsReady(self):
  72. return self.closeWindow.IsReady
  73. #the next support is the one with the smallest difference between current price
  74. #since we have a list of support levels we need to merge the 4hr and the daily support level into one list
  75. # and then rank them from them in decsending order
  76. # we can further process the support data and resitance data gathered from above, by perhaps creating another function.
  77. # where the final output will be directly below or above the current price.
+ Expand

Author

Samwel Kibet

August 2021