本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © The_Forex_Steward
//@version=6
indicator("Market Structure- ZigZag, Break of Structure & Order Blocks", overlay=true)
// === User Inputs ===
showBullishOrderBlocks = input.bool(true, title="Show Bullish Order Blocks (Green)")
showBearishOrderBlocks = input.bool(true, title="Show Bearish Order Blocks (Red)")
orderBlockDuration = 20
deleteMitigatedBoxes = input.bool(true, title="Delete Mitigated Boxes")
internalShiftMode = input.string("High/Low", title="Calculate Internal Shift By", options=["Open", "High/Low"])
bullishBlockColor = input.color(color.rgb(76, 175, 79, 75), title="Bullish Order Block Fill Color")
bearishBlockColor = input.color(color.rgb(255, 82, 82, 75), title="Bearish Order Block Fill Color")
bullishBorderColor = input.color(color.rgb(76, 175, 79), title="Bullish Order Block Border Color")
bearishBorderColor = input.color(color.rgb(255, 82, 82), title="Bearish Order Block Border Color")
// === Variables to Track State ===
var float lastBearishHigh = na
var float lastBearishLow = na
var int lastBearishBarIndex = na
var bool bearishBroken = true
var float lastBullishHigh = na
var float lastBullishLow = na
var int lastBullishBarIndex = na
var bool bullishBroken = true
isBearish = close < open
isBullish = close > open
// === Track latest box objects ===
var box[] bullishBoxes = array.new<box>()
var box[] bearishBoxes = array.new<box>()
// === Capture Candle State ===
if isBearish
lastBearishHigh := high
lastBearishLow := low
lastBearishBarIndex := bar_index
bearishBroken := false
if isBullish
lastBullishLow := low
lastBullishHigh := high
lastBullishBarIndex := bar_index
bullishBroken := false
// === Break Conditions ===
bullishBreak = not bearishBroken and close > lastBearishHigh
bearishBreak = not bullishBroken and close < lastBullishLow
if bullishBreak
bearishBroken := true
if bearishBreak
bullishBroken := true
// === Plot Engulfment Triangles ===
plotshape(bullishBreak, title="Bullish Engulfment", location=location.belowbar, color=color.rgb(76, 175, 79), style=shape.triangleup, size=size.tiny)
plotshape(bearishBreak, title="Bearish Engulfment", location=location.abovebar, color=color.rgb(255, 82, 82), style=shape.triangledown, size=size.tiny)
// === Delete invalidated boxes ===
if array.size(bullishBoxes) > 0
for i = array.size(bullishBoxes) - 1 to 0
boxItem = array.get(bullishBoxes, i)
if low < box.get_bottom(boxItem)
box.delete(boxItem)
array.remove(bullishBoxes, i)
if array.size(bearishBoxes) > 0
for i = array.size(bearishBoxes) - 1 to 0
boxItem = array.get(bearishBoxes, i)
if high > box.get_top(boxItem)
box.delete(boxItem)
array.remove(bearishBoxes, i)
// === Delete mitigated boxes (optional) ===
var bool bullishMitigated = false
var bool bearishMitigated = false
bullishMitigated := false
bearishMitigated := false
if deleteMitigatedBoxes
if array.size(bullishBoxes) > 0
for i = array.size(bullishBoxes) - 1 to 0
boxItem = array.get(bullishBoxes, i)
if low < box.get_top(boxItem)
bullishMitigated := true
box.delete(boxItem)
array.remove(bullishBoxes, i)
if array.size(bearishBoxes) > 0
for i = array.size(bearishBoxes) - 1 to 0
boxItem = array.get(bearishBoxes, i)
if high > box.get_bottom(boxItem)
bearishMitigated := true
box.delete(boxItem)
array.remove(bearishBoxes, i)
// === Draw New Order Blocks ===
if showBullishOrderBlocks and bullishBreak and not na(lastBearishBarIndex)
bullishBox = box.new(left=lastBearishBarIndex, right=bar_index + orderBlockDuration, top=lastBearishHigh, bottom=lastBearishLow, border_color=bullishBorderColor, bgcolor=bullishBlockColor)
array.push(bullishBoxes, bullishBox)
if showBearishOrderBlocks and bearishBreak and not na(lastBullishBarIndex)
bearishBox = box.new(left=lastBullishBarIndex, right=bar_index + orderBlockDuration, top=lastBullishHigh, bottom=lastBullishLow, border_color=bearishBorderColor, bgcolor=bearishBlockColor)
array.push(bearishBoxes, bearishBox)
// === Internal Structure Logic ===
var int bullishCount = 0
var int bearishCount = 0
var float lowestBullishPrice = na
var float highestBearishPrice = na
var float firstBullishOpen = na
var float firstBearishOpen = na
var int lastInternalShift = 0
if isBullish
bullishCount += 1
bearishCount := 0
if bullishCount == 1 or low < lowestBullishPrice
lowestBullishPrice := low
if bullishCount == 1
firstBullishOpen := open
else if isBearish
bearishCount += 1
bullishCount := 0
if bearishCount == 1 or high > highestBearishPrice
highestBearishPrice := high
if bearishCount == 1
firstBearishOpen := open
else
bullishCount := 0
bearishCount := 0
lowestBullishPrice := na
highestBearishPrice := na
// === Determine Internal Shift Based on User Input ===
internalShiftBearish = internalShiftMode == "Open" ? close < firstBullishOpen : close < lowestBullishPrice
internalShiftBullish = internalShiftMode == "Open" ? close > firstBearishOpen : close > highestBearishPrice
allowInternalShiftBearish = internalShiftBearish and lastInternalShift != -1
allowInternalShiftBullish = internalShiftBullish and lastInternalShift != 1
var bool plotBearishInternalShift = false
var bool plotBullishInternalShift = false
plotBearishInternalShift := false
plotBullishInternalShift := false
if allowInternalShiftBearish
plotBearishInternalShift := true
lastInternalShift := -1
if allowInternalShiftBullish
plotBullishInternalShift := true
lastInternalShift := 1
// === Plot internal shift markers ===
plotshape(plotBullishInternalShift, title="Bullish Internal Shift", location=location.belowbar, color=color.black, style=shape.triangleup, size=size.tiny)
plotshape(plotBearishInternalShift, title="Bearish Internal Shift", location=location.abovebar, color=color.black, style=shape.triangledown, size=size.tiny)
// === Persistent variables for multiple line handling ===
var line[] zigzagLines = array.new<line>()
var int lastBearishShiftBar = na
var int lastBullishShiftBar = na
var float lastZigzagPrice = na // Keeps track of the last plotted price for zigzag
var int lastLowIndex = na // Stores index of last low in zigzag
var int lastHighIndex = na // Stores index of last high in zigzag
var float lastSwingHigh = na
var float lastSwingLow = na
// Save shift bar indices
if plotBearishInternalShift
lastBearishShiftBar := bar_index
if plotBullishInternalShift
lastBullishShiftBar := bar_index
// Bearish shift followed by Bullish shift → Track lowest low
if plotBullishInternalShift and not na(lastBearishShiftBar)
shiftLength = bar_index - lastBearishShiftBar
if shiftLength <= 10000
lowest = low
lowIndex = bar_index
for i = 0 to shiftLength
if low[i] < lowest
lowest := low[i]
lowIndex := bar_index - i
// Plot zigzag line
if not na(lastZigzagPrice)
zigzagLine = line.new(x1=lastHighIndex, y1=lastZigzagPrice, x2=lowIndex, y2=lowest, color=color.black, width=3)
array.push(zigzagLines, zigzagLine)
lastZigzagPrice := lowest
lastSwingLow := lowest // Save last swing low
lastBearishShiftBar := bar_index
lastLowIndex := lowIndex
// Bullish shift followed by Bearish shift → Track highest high
if plotBearishInternalShift and not na(lastBullishShiftBar)
shiftLength = bar_index - lastBullishShiftBar
if shiftLength <= 10000
highest = high
highIndex = bar_index
for i = 0 to shiftLength
if high[i] > highest
highest := high[i]
highIndex := bar_index - i
// Plot zigzag line
if not na(lastZigzagPrice)
zigzagLine = line.new(x1=lastLowIndex, y1=lastZigzagPrice, x2=highIndex, y2=highest, color=color.black, width=3)
array.push(zigzagLines, zigzagLine)
lastZigzagPrice := highest
lastSwingHigh := highest // Save last swing high
lastBullishShiftBar := bar_index
lastHighIndex := highIndex
// === Track Break of Structure (BOS) markers ===
// Initialize flags as mutable `var` variables
var bool plotBullishBOS = false
var bool plotBearishBOS = false
// === Conditions to plot the BOS markers ===
// Bullish BOS (Only plot the first candle breaking the swing high)
if not na(lastSwingHigh) and close > lastSwingHigh and not plotBullishBOS
plotBullishBOS := true // Set the flag to true after the first BOS
// No need for plotshape here since we plot it below in the global scope
// Bearish BOS (Only plot the first candle breaking the swing low)
if not na(lastSwingLow) and close < lastSwingLow and not plotBearishBOS
plotBearishBOS := true // Set the flag to true after the first BOS
// No need for plotshape here since we plot it below in the global scope
// === Plot Break of Structure (BOS) with horizontal lines ===
// Modify these flags
var line bullishBOSLine = na
var line bearishBOSLine = na
// === Plot Break of Structure (BOS) with horizontal lines ===
// === Conditions to plot the BOS markers ===
// Bullish BOS (Only plot the first candle breaking the swing high)
if not na(lastSwingHigh) and close > lastSwingHigh and na(bullishBOSLine)
// Draw horizontal line from the last swing high to the current price (breaking candle)
bullishBOSLine := line.new(x1=lastHighIndex, y1=lastSwingHigh, x2=bar_index, y2=lastSwingHigh, color=color.green, width=3, style=line.style_dotted)
// Bearish BOS (Only plot the first candle breaking the swing low)
if not na(lastSwingLow) and close < lastSwingLow and na(bearishBOSLine)
// Draw horizontal line from the last swing low to the current price (breaking candle)
bearishBOSLine := line.new(x1=lastLowIndex, y1=lastSwingLow, x2=bar_index, y2=lastSwingLow, color=color.red, width=3, style=line.style_dotted)
// Optionally reset lines after new swings are formed, if needed
if close < lastSwingHigh
bullishBOSLine := na // Reset bullish BOS line when a new swing high is formed
if close > lastSwingLow
bearishBOSLine := na // Reset bearish BOS line when a new swing low is formed
// === Alerts ===
alertcondition(bullishBreak, title="Bullish Engulfment", message="Bullish engulfment! New order block available.")
alertcondition(bearishBreak, title="Bearish Engulfment", message="Bearish engulfment! New order block available.")
alertcondition(plotBullishInternalShift, title="Bullish Internal Shift", message="Bullish Internal Shift detected! Update your swing low.")
alertcondition(plotBearishInternalShift, title="Bearish Internal Shift", message="Bearish Internal Shift detected! Update your swing high.")
alertcondition(not na(lastSwingHigh) and close > lastSwingHigh, title="Bullish Break of Structure", message="Bullish Break of Structure detected!")
alertcondition(not na(lastSwingLow) and close < lastSwingLow, title="Bearish Break of Structure", message="Bearish Break of Structure detected!")
alertcondition(bullishMitigated, title="Bullish Order Block Mitigated", message="Bullish Order Block has been mitigated!")
alertcondition(bearishMitigated, title="Bearish Order Block Mitigated", message="Bearish Order Block has been mitigated!")