
Modjoy-Adaptive Support and Resistance Zones: A Revolutionary Trading Strategy by BigBeluga
The foreign exchange market is a complex and dynamic environment where traders need to adapt quickly to changing market conditions. One of the most effective ways to navigate this landscape is by using support and resistance zones, which can help traders identify potential areas of buying and selling opportunities. In this article, we will explore the Modjoy-Adaptive Support and Resistance Zones strategy developed by BigBeluga, a renowned trading expert.
Introduction to Support and Resistance Zones
Support and resistance zones are areas on a chart where the price of an asset has historically bounced back or reversed direction. These zones can be used to identify potential areas of buying and selling opportunities, as well as to set stop-loss and take-profit levels. However, traditional support and resistance zones can be limited by their static nature, failing to account for changing market conditions and volatility.
The Modjoy-Adaptive Approach
The Modjoy-Adaptive Support and Resistance Zones strategy developed by BigBeluga addresses the limitations of traditional support and resistance zones by incorporating adaptive and dynamic elements. This approach uses a combination of technical indicators and algorithms to identify and adjust support and resistance zones in real-time, taking into account changes in market volatility, trend direction, and other factors.
Key Components of the Modjoy-Adaptive Strategy
The Modjoy-Adaptive Support and Resistance Zones strategy consists of the following key components:
- Adaptive Zone Calculation: The strategy uses a proprietary algorithm to calculate support and resistance zones based on historical price data and market volatility.
- Dynamic Zone Adjustment: The zones are adjusted in real-time to reflect changes in market conditions, such as shifts in trend direction or changes in volatility.
- Multi-Time Frame Analysis: The strategy incorporates analysis of multiple time frames to provide a more comprehensive view of market conditions and to identify potential trading opportunities.
Benefits of the Modjoy-Adaptive Strategy
The Modjoy-Adaptive Support and Resistance Zones strategy offers several benefits to traders, including:
- Improved Accuracy: The adaptive and dynamic nature of the strategy allows for more accurate identification of support and resistance zones.
- Increased Flexibility: The strategy can be applied to various markets and time frames, making it a versatile tool for traders.
- Enhanced Risk Management: The strategy provides traders with a more effective way to manage risk by identifying potential areas of support and resistance.
Conclusion
The Modjoy-Adaptive Support and Resistance Zones strategy developed by BigBeluga is a powerful tool for traders looking to improve their trading performance. By incorporating adaptive and dynamic elements, this strategy provides a more accurate and effective way to identify support and resistance zones, ultimately leading to better trading decisions and improved risk management. Whether you are a seasoned trader or just starting out, the Modjoy-Adaptive strategy is definitely worth considering as part of your trading arsenal.
Exclusive Source Code: Modjoy-Adaptive Support and Resistance Zones [BigBeluga]
// This work is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
//@version=6
indicator("Modjoy-Adaptive Support and Resistance Zones [BigBeluga]", shorttitle="Adaptive S/R [BigBeluga]", overlay=true, max_lines_count=500, max_labels_count=200, max_boxes_count=200)
// INPUTS ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
var grpSwing = "Swing Detection"
pivotLen = input.int(5, "Pivot Length", minval=2, maxval=50, group=grpSwing, tooltip="The number of bars on each side of a high or low to confirm a pivot point.")
minStrength = input.float(0.1, "Min ATR Strength", minval=0.0, maxval=5.0, step=0.05, group=grpSwing, tooltip="Minimum distance required between the pivot and its neighbors.")
maxAgeBars = input.int(300, "Max Level Age (bars)", minval=20, maxval=2000, group=grpSwing, tooltip="Maximum bars a level exists before removal. Also used to calculate longevity scaling.")
var grpLevels = "Levels"
showSupport = input.bool(true, "Show Support Levels", group=grpLevels)
showResist = input.bool(true, "Show Resistance Levels", group=grpLevels)
maxLevels = input.int(5, "Max Active Levels Each", minval=1, maxval=20, group=grpLevels)
mergeThresh = input.float(0.5, "Merge Threshold (ATR x)", minval=0.0, maxval=3.0, step=0.05, group=grpLevels)
showZones = input.bool(true, "Show Level Zones", group=grpLevels)
zoneWidth = input.float(0.25, "Zone Width (ATR x)", minval=0.05, maxval=2.0, step=0.05, group=grpLevels)
var grpBreak = "Breakouts"
showBroken = input.bool(true, "Show Broken Levels", group=grpBreak)
breakSens = input.float(0.1, "Break Sensitivity (ATR x)", minval=0.0, maxval=2.0, step=0.05, group=grpBreak)
showBreakLbl = input.bool(true, "Show Break Labels", group=grpBreak)
maxBroken = input.int(4, "Max Broken Levels Shown", minval=0, maxval=20, group=grpBreak)
var grpVis = "Visuals"
supColor = input.color(color.new(#22bac5, 0), "Support Color", group=grpVis)
resColor = input.color(color.new(#ff6f43, 0), "Resistance Color", group=grpVis)
brokenColor = input.color(color.new(#94a3b8, 0), "Broken Level Color", group=grpVis)
lineWidth = input.int(2, "Base Line Width", minval=1, maxval=5, group=grpVis, tooltip="Used when Longevity Scaling is OFF.")
// NEW LONGEVITY INPUTS
useDynamicWidth = input.bool(true, "Enable Longevity Width", group=grpVis, tooltip="When enabled, older levels become thicker over time.")
maxLineWidth = input.int(7, "Max Longevity Width", minval=1, maxval=10, group=grpVis, tooltip="The maximum thickness an old level can reach.")
showDash = input.bool(true, "Show Dashboard", group=grpVis)
showPriceLbl = input.bool(true, "Show Price Labels on Active Levels", group=grpVis)
var grpDash = "Dashboard"
dashPos = input.string("Bottom Right", "Dashboard Position", options=["Top Right","Bottom Right","Top Left","Bottom Left"], group=grpDash)
// }
// CALCULATIONS――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
type SRLevel
float price
int barStart
int levelType
bool active
bool broken
int breakBar
bool retested
line mainLine
box zoneBox
label breakLabel
label priceLabel
var array activeLevels = array.new()
var array brokenLevels = array.new()
var string lastBreakDir = "—"
var int lastBreakBar = na
atrVal = ta.atr(14)
atrSafe = na(atrVal) or atrVal == 0 ? syminfo.mintick * 10 : atrVal
ph = ta.pivothigh(high, pivotLen, pivotLen)
pl = ta.pivotlow(low, pivotLen, pivotLen)
f_isTooClose(_price, _type) =>
bool tooClose = false
int sz = array.size(activeLevels)
if sz > 0
for i = 0 to sz - 1
lvl = array.get(activeLevels, i)
if lvl.levelType == _type and lvl.active
if math.abs(lvl.price - _price) < mergeThresh * atrSafe
tooClose := true
break
tooClose
f_addLevel(_price, _type, _barIdx) =>
if not f_isTooClose(_price, _type)
int sz = array.size(activeLevels)
int cnt = 0
if sz > 0
for i = 0 to sz - 1
lvl = array.get(activeLevels, i)
if lvl.levelType == _type and lvl.active
cnt += 1
if cnt < maxLevels
_baseColor = _type == 1 ? resColor : supColor
_zoneTop = _price + zoneWidth * atrSafe * 0.5
_zoneBot = _price - zoneWidth * atrSafe * 0.5
newLine = line.new(
x1 = _barIdx,
y1 = _price,
x2 = _barIdx + 1,
y2 = _price,
extend = extend.right,
color = color.new(_baseColor, 0),
width = lineWidth,
style = line.style_solid
)
newBox = showZones ? box.new(
left = _barIdx,
top = _zoneTop,
right = _barIdx + 1,
bottom = _zoneBot,
border_color = color.new(_baseColor, 90),
bgcolor = color.new(_baseColor, 88),
extend = extend.right
) : na
newPriceLbl = showPriceLbl ? label.new(
x = bar_index + 20,
y = _price,
text = str.tostring(_price, format.mintick),
style = label.style_label_center,
textcolor = _baseColor,
color = color.new(chart.bg_color, 0),
size = size.small
) : na
array.push(activeLevels, SRLevel.new(
price = _price,
barStart = _barIdx,
levelType = _type,
active = true,
broken = false,
breakBar = na,
retested = false,
mainLine = newLine,
zoneBox = newBox,
breakLabel = na,
priceLabel = newPriceLbl
))
f_pivotStrong(_price, _type) =>
bool strong = true
if minStrength > 0
if _type == 1
nearHigh = math.max(high[pivotLen - 1], high[pivotLen + 1])
if (_price - nearHigh) < minStrength * atrSafe
strong := false
else
nearLow = math.min(low[pivotLen - 1], low[pivotLen + 1])
if (nearLow - _price) < minStrength * atrSafe
strong := false
strong
// Prune old levels
int pruneSize = array.size(activeLevels)
if pruneSize > 0
for i = pruneSize - 1 to 0
if i < array.size(activeLevels)
lvl = array.get(activeLevels, i)
if lvl.active and (bar_index - lvl.barStart) > maxAgeBars
line.delete(lvl.mainLine)
if not na(lvl.zoneBox)
box.delete(lvl.zoneBox)
if not na(lvl.priceLabel)
label.delete(lvl.priceLabel)
array.remove(activeLevels, i)
// Add new pivots
if not na(ph) and showResist
if f_pivotStrong(ph, 1)
f_addLevel(ph, 1, bar_index - pivotLen)
if not na(pl) and showSupport
if f_pivotStrong(pl, -1)
f_addLevel(pl, -1, bar_index - pivotLen)
// Breakout logic
int activeSize = array.size(activeLevels)
if activeSize > 0
for i = activeSize - 1 to 0
if i >= array.size(activeLevels)
continue
lvl = array.get(activeLevels, i)
if not lvl.active
continue
breakBuffer = breakSens * atrSafe
if lvl.levelType == 1 and close > lvl.price + breakBuffer
lvl.active := false
lvl.broken := true
lvl.breakBar := bar_index
lastBreakDir := "Bullish"
lastBreakBar := bar_index
if not na(lvl.priceLabel)
label.delete(lvl.priceLabel)
lvl.priceLabel := na
line.set_color(lvl.mainLine, color.new(brokenColor, 0))
line.set_style(lvl.mainLine, line.style_dotted)
line.set_width(lvl.mainLine, 1)
line.set_extend(lvl.mainLine, extend.none)
line.set_x2(lvl.mainLine, bar_index)
if not na(lvl.zoneBox)
box.set_bgcolor(lvl.zoneBox, color.new(brokenColor, 93))
box.set_border_color(lvl.zoneBox, color.new(brokenColor, 100))
box.set_extend(lvl.zoneBox, extend.none)
box.set_right(lvl.zoneBox, bar_index)
mid = math.avg(lvl.zoneBox.get_top(), lvl.zoneBox.get_bottom())
lvl.zoneBox.set_top(mid + breakBuffer)
lvl.zoneBox.set_bottom(mid - breakBuffer)
if showBreakLbl
lvl.breakLabel := label.new(
x = bar_index,
y = lvl.price,
text = "< Break",
style = label.style_label_left,
textcolor = supColor,
color = color.new(#22c55e, 100),
size = size.small
)
if showBroken
array.push(brokenLevels, lvl)
if array.size(brokenLevels) > maxBroken and array.size(brokenLevels) > 0
old = array.shift(brokenLevels)
if not na(old.mainLine)
line.delete(old.mainLine)
if not na(old.zoneBox)
box.delete(old.zoneBox)
if not na(old.breakLabel)
label.delete(old.breakLabel)
else
line.delete(lvl.mainLine)
if not na(lvl.zoneBox)
box.delete(lvl.zoneBox)
array.remove(activeLevels, i)
else if lvl.levelType == -1 and close < lvl.price - breakBuffer
lvl.active := false
lvl.broken := true
lvl.breakBar := bar_index
lastBreakDir := "Bearish"
lastBreakBar := bar_index
if not na(lvl.priceLabel)
label.delete(lvl.priceLabel)
lvl.priceLabel := na
line.set_color(lvl.mainLine, color.new(brokenColor, 0))
line.set_style(lvl.mainLine, line.style_dotted)
line.set_width(lvl.mainLine, 1)
line.set_extend(lvl.mainLine, extend.none)
line.set_x2(lvl.mainLine, bar_index)
if not na(lvl.zoneBox)
box.set_bgcolor(lvl.zoneBox, color.new(brokenColor, 93))
box.set_border_color(lvl.zoneBox, color.new(brokenColor, 100))
box.set_extend(lvl.zoneBox, extend.none)
box.set_right(lvl.zoneBox, bar_index)
mid = math.avg(lvl.zoneBox.get_top(), lvl.zoneBox.get_bottom())
lvl.zoneBox.set_top(mid + breakBuffer)
lvl.zoneBox.set_bottom(mid - breakBuffer)
if showBreakLbl
lvl.breakLabel := label.new(
x = bar_index,
y = lvl.price,
text = "< Break",
style = label.style_label_left,
textcolor = resColor,
color = color.new(#ef4444, 100),
size = size.small
)
if showBroken
array.push(brokenLevels, lvl)
if array.size(brokenLevels) > maxBroken and array.size(brokenLevels) > 0
old = array.shift(brokenLevels)
if not na(old.mainLine)
line.delete(old.mainLine)
if not na(old.zoneBox)
box.delete(old.zoneBox)
if not na(old.breakLabel)
label.delete(old.breakLabel)
else
line.delete(lvl.mainLine)
if not na(lvl.zoneBox)
box.delete(lvl.zoneBox)
array.remove(activeLevels, i)
// }
// PLOT ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{
// Extend visuals on active levels
int extSize = array.size(activeLevels)
if extSize > 0
for i = 0 to extSize - 1
lvl = array.get(activeLevels, i)
if lvl.active
// DYNAMIC LONGEVITY WIDTH CALCULATION
if useDynamicWidth
age = bar_index - lvl.barStart
// Scale width from 1 to maxLineWidth based on maxAgeBars
calcWidth = math.min(maxLineWidth, 1 + math.floor((age / maxAgeBars) * (maxLineWidth - 1)))
line.set_width(lvl.mainLine, int(calcWidth))
else
line.set_width(lvl.mainLine, lineWidth)
line.set_x2(lvl.mainLine, bar_index + 1)
if not na(lvl.zoneBox)
box.set_right(lvl.zoneBox, bar_index + 1)
if showPriceLbl and not na(lvl.priceLabel)
label.set_x(lvl.priceLabel, bar_index + 10)
var float nearestSup = na
var float nearestRes = na
nearestSup := na
nearestRes := na
// Dashboard scanning
int dashScanSize = array.size(activeLevels)
if dashScanSize > 0
for i = 0 to dashScanSize - 1
lvl = array.get(activeLevels, i)
if not lvl.active
continue
if lvl.levelType == -1 and lvl.price < close
if na(nearestSup) or lvl.price > nearestSup
nearestSup := lvl.price
if lvl.levelType == 1 and lvl.price > close
if na(nearestRes) or lvl.price < nearestRes
nearestRes := lvl.price
// Draw Dashboard
var table dashTable = na
if showDash
tablePos = switch dashPos
"Top Right" => position.top_right
"Bottom Right" => position.bottom_right
"Top Left" => position.top_left
"Bottom Left" => position.bottom_left
=> position.bottom_right
if barstate.isfirst
dashTable := table.new(
position = tablePos,
columns = 2,
rows = 5,
bgcolor = color.new(#0d1117, 5),
border_color = color.new(#30363d, 40),
border_width = 1,
frame_color = color.new(#30363d, 20),
frame_width = 1
)
if barstate.islast and not na(dashTable)
table.cell(dashTable, 0, 0, "S/R Dashboard", text_color=color.new(#f0f6fc, 0), text_size=size.normal, bgcolor=color.new(#161b22, 0), text_halign=text.align_center)
table.merge_cells(dashTable, 0, 0, 1, 0)
table.cell(dashTable, 0, 1, "Resistance", text_color=color.new(#8b949e, 0), text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_left)
table.cell(dashTable, 1, 1,
na(nearestRes) ? "—" : str.tostring(nearestRes, format.mintick),
text_color = na(nearestRes) ? color.new(#484f58, 0) : resColor,
text_size = size.normal,
bgcolor = color.new(#0d1117, 10),
text_halign = text.align_right
)
table.cell(dashTable, 0, 2, "Support", text_color=color.new(#8b949e, 0), text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_left)
table.cell(dashTable, 1, 2,
na(nearestSup) ? "—" : str.tostring(nearestSup, format.mintick),
text_color = na(nearestSup) ? color.new(#484f58, 0) : supColor,
text_size = size.normal,
bgcolor = color.new(#0d1117, 10),
text_halign = text.align_right
)
table.cell(dashTable, 0, 3, "Last Break", text_color=color.new(#8b949e, 0), text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_left)
breakDirColor = lastBreakDir == "Bullish" ? supColor : lastBreakDir == "Bearish" ? resColor : color.new(#484f58, 0)
table.cell(dashTable, 1, 3, lastBreakDir, text_color=breakDirColor, text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_right)
activeCnt = array.size(activeLevels)
table.cell(dashTable, 0, 4, "Active Levels", text_color=color.new(#8b949e, 0), text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_left)
table.cell(dashTable, 1, 4, str.tostring(activeCnt), text_color=color.new(#f0f6fc, 0), text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_right)
// }