本页源码来自 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/
// © ChartPrime
//@version=6
indicator("Power Order Blocks [ChartPrime]", overlay=true, max_boxes_count=500, max_labels_count=500, max_lines_count=500)
// --------------------------------------------------------------------------------------------------------------------}
// 📌 𝙐𝙎𝙀𝙍 𝙄𝙉𝙋𝙐𝙏𝙎
// --------------------------------------------------------------------------------------------------------------------{
grp1 = "Order Block Settings"
maxBlocks = 10
dispThresh = input.float(0.5, title="Displacement Multiplier", step=0.1, group=grp1, tooltip="How much larger the engulfing candle must be to validate an OB.")
strLookback = 100
grp2 = "Styling"
bullColor = input.color(#1bd37a, title="Bullish OB Color", group=grp2)
bearColor = input.color(#bc14e6, title="Bearish OB Color", group=grp2)
borderColor = color.new(#ffffff, 100)
textColor = input.color(color.new(#ffffff, 0), title="Text Color", group=grp2)
showEqLine = input.bool(true, title="Show Equilibrium Line", group=grp2, tooltip="Draws a dashed midpoint line inside each Order Block.")
powerFade = input.bool(true, title="Power Intensity", group=grp2, tooltip="Higher power OBs appear more vivid; weaker OBs are more transparent.")
grp3 = "Signals"
showRetests = input.bool(true, title="Show Retest Labels", group=grp3, tooltip="Plots an arrow label when price taps into an active Order Block.")
// --------------------------------------------------------------------------------------------------------------------}
// 📌 𝙏𝙔𝙋𝙀𝙎
// --------------------------------------------------------------------------------------------------------------------{
type OBBlock
box bx
box infoBox
line eqLine
int touches
int birthBar
float obTop
float obBtm
float powerPct
// --------------------------------------------------------------------------------------------------------------------}
// 📌 𝙄𝙉𝘿𝙄𝘾𝘼𝙏𝙊𝙍 𝘾𝘼𝙇𝘾𝙐𝙇𝘼𝙏𝙄𝙊𝙉𝙎
// --------------------------------------------------------------------------------------------------------------------{
var OBBlock[] bullBlocks = array.new<OBBlock>()
var OBBlock[] bearBlocks = array.new<OBBlock>()
var int lastBullRetestBar = na
var int lastBearRetestBar = na
bool isBearishCandle = close[1] < open[1]
bool isBullishDisp = close > open and close > high[1] and (close - open) > (high[1] - low[1]) * dispThresh
bool bullOB = isBearishCandle and isBullishDisp
bool isBullishCandle = close[1] > open[1]
bool isBearishDisp = close < open and close < low[1] and (open - close) > (high[1] - low[1]) * dispThresh
bool bearOB = isBullishCandle and isBearishDisp
float maxCandleSize = ta.highest(high - low, strLookback)
float atr = ta.atr(14) * 0.2
// Power % drives transparency: high power = low transp (vivid), low power = high transp (faded)
// Power 100% -> transp 60, Power 0% -> transp 92
calcPowerTransp(float powerPct) =>
int transp = math.round(92 - (powerPct / 100.0) * 32)
transp
buildLabel(int touches, float pct) =>
"Power: " + str.tostring(math.round(pct)) + "% | Touches: " + str.tostring(touches)
bool bullRetestRaw = false
bool bearRetestRaw = false
// --- Update bullish blocks ---
int bullSize = array.size(bullBlocks)
if bullSize > 0
for i = bullSize - 1 to 0
OBBlock ob = array.get(bullBlocks, i)
float btm = ob.obBtm
float top = ob.obTop
if close < btm
box.delete(ob.bx)
box.delete(ob.infoBox)
if not na(ob.eqLine)
line.delete(ob.eqLine)
array.remove(bullBlocks, i)
else
int transp = powerFade ? calcPowerTransp(ob.powerPct) : 80
box.set_bgcolor(ob.bx, color.new(bullColor, transp))
box.set_right(ob.bx, bar_index + 25)
box.set_left(ob.infoBox, bar_index)
box.set_right(ob.infoBox, bar_index + 25)
box.set_top(ob.infoBox, top)
box.set_bottom(ob.infoBox, btm)
if showEqLine and not na(ob.eqLine)
line.set_x2(ob.eqLine, bar_index)
if low[1] <= top and low >= top and bar_index > box.get_left(ob.bx)
bullRetestRaw := true
ob.touches += 1
float pct = maxCandleSize > 0 ? ((top - btm) / maxCandleSize) * 100 : 0
box.set_text(ob.infoBox, "Bullish OB\n" + buildLabel(ob.touches, pct))
// --- Update bearish blocks ---
int bearSize = array.size(bearBlocks)
if bearSize > 0
for i = bearSize - 1 to 0
OBBlock ob = array.get(bearBlocks, i)
float top = ob.obTop
float btm = ob.obBtm
if close > top
box.delete(ob.bx)
box.delete(ob.infoBox)
if not na(ob.eqLine)
line.delete(ob.eqLine)
array.remove(bearBlocks, i)
else
int transp = powerFade ? calcPowerTransp(ob.powerPct) : 80
box.set_bgcolor(ob.bx, color.new(bearColor, transp))
box.set_right(ob.bx, bar_index + 25)
box.set_left(ob.infoBox, bar_index)
box.set_right(ob.infoBox, bar_index + 25)
box.set_top(ob.infoBox, top)
box.set_bottom(ob.infoBox, btm)
if showEqLine and not na(ob.eqLine)
line.set_x2(ob.eqLine, bar_index)
if high[1] >= btm and high <= btm and bar_index > box.get_left(ob.bx)
bearRetestRaw := true
ob.touches += 1
float pct = maxCandleSize > 0 ? ((top - btm) / maxCandleSize) * 100 : 0
box.set_text(ob.infoBox, "Bearish OB\n" + buildLabel(ob.touches, pct))
// Apply 10-bar gap filter
bool bullRetest = bullRetestRaw and (na(lastBullRetestBar) or bar_index - lastBullRetestBar >= 10)
bool bearRetest = bearRetestRaw and (na(lastBearRetestBar) or bar_index - lastBearRetestBar >= 10)
if bullRetest
lastBullRetestBar := bar_index
if bearRetest
lastBearRetestBar := bar_index
// --------------------------------------------------------------------------------------------------------------------}
// 📌 𝙑𝙄𝙎𝙐𝘼𝙇𝙄𝙕𝘼𝙏𝙄𝙊𝙉
// --------------------------------------------------------------------------------------------------------------------{
if bullOB
float obTop = high[1]
float obBtm = low[1]
float obMid = math.avg(obTop, obBtm)
int obLeft = bar_index[1]
float pct = maxCandleSize > 0 ? ((obTop - obBtm) / maxCandleSize) * 100 : 0
string lbl = "Bullish OB\n" + buildLabel(0, pct)
int transp = powerFade ? calcPowerTransp(pct) : 80
if array.size(bullBlocks) > 0
for i = array.size(bullBlocks) - 1 to 0
OBBlock old = array.get(bullBlocks, i)
if obTop >= old.obBtm and obBtm <= old.obTop
box.delete(old.bx)
box.delete(old.infoBox)
if not na(old.eqLine)
line.delete(old.eqLine)
array.remove(bullBlocks, i)
box newBx = box.new(obLeft, obTop, bar_index, obBtm,
border_color = borderColor,
border_style = line.style_dashed,
bgcolor = color.new(bullColor, transp))
box infoBx = box.new(bar_index, obTop, bar_index + 25, obBtm,
border_color = color.new(bullColor, 40),
border_style = line.style_solid,
bgcolor = color.new(bullColor, 92),
text = lbl,
text_color = textColor,
text_size = size.auto,
text_halign = text.align_center,
text_valign = text.align_center)
line eqL = na
if showEqLine
eqL := line.new(obLeft, obMid, bar_index, obMid,
color = color.new(bullColor, 40),
style = line.style_solid,
width = 1)
array.push(bullBlocks, OBBlock.new(newBx, infoBx, eqL, 0, bar_index, obTop, obBtm, pct))
int bullCount = array.size(bullBlocks)
if bullCount > maxBlocks
int trim = bullCount - maxBlocks
for _i = 0 to trim - 1
if array.size(bullBlocks) > 0
OBBlock old = array.shift(bullBlocks)
box.delete(old.bx)
box.delete(old.infoBox)
if not na(old.eqLine)
line.delete(old.eqLine)
if bearOB
float obTop = high[1]
float obBtm = low[1]
float obMid = math.avg(obTop, obBtm)
int obLeft = bar_index[1]
float pct = maxCandleSize > 0 ? ((obTop - obBtm) / maxCandleSize) * 100 : 0
string lbl = "Bearish OB\n" + buildLabel(0, pct)
int transp = powerFade ? calcPowerTransp(pct) : 80
if array.size(bearBlocks) > 0
for i = array.size(bearBlocks) - 1 to 0
OBBlock old = array.get(bearBlocks, i)
if obTop >= old.obBtm and obBtm <= old.obTop
box.delete(old.bx)
box.delete(old.infoBox)
if not na(old.eqLine)
line.delete(old.eqLine)
array.remove(bearBlocks, i)
box newBx = box.new(obLeft, obTop, bar_index, obBtm,
border_color = borderColor,
border_style = line.style_dashed,
bgcolor = color.new(bearColor, transp))
box infoBx = box.new(bar_index, obTop, bar_index + 25, obBtm,
border_color = color.new(bearColor, 40),
border_style = line.style_solid,
bgcolor = color.new(bearColor, 92),
text = lbl,
text_color = textColor,
text_size = size.auto,
text_halign = text.align_center,
text_valign = text.align_center)
line eqL = na
if showEqLine
eqL := line.new(obLeft, obMid, bar_index, obMid,
color = color.new(bearColor, 40),
style = line.style_solid,
width = 1)
array.push(bearBlocks, OBBlock.new(newBx, infoBx, eqL, 0, bar_index, obTop, obBtm, pct))
int bearCount = array.size(bearBlocks)
if bearCount > maxBlocks
int trim = bearCount - maxBlocks
for _i = 0 to trim - 1
if array.size(bearBlocks) > 0
OBBlock old = array.shift(bearBlocks)
box.delete(old.bx)
box.delete(old.infoBox)
if not na(old.eqLine)
line.delete(old.eqLine)
// --- Retest labels ---
if showRetests and bullRetest
label.new(
x = bar_index,
y = low - atr,
text = "⇡",
style = label.style_label_up,
color = color.new(bullColor, 100),
textcolor = bullColor,
size = size.large)
if showRetests and bearRetest
label.new(
x = bar_index,
y = high + atr,
text = "⇣",
style = label.style_label_down,
color = color.new(bearColor, 100),
textcolor = bearColor,
size = size.large)
// --- Alerts ---
alertcondition(bullRetest, title="Bullish OB Retest", message="Price retested a Bullish Order Block.")
alertcondition(bearRetest, title="Bearish OB Retest", message="Price retested a Bearish Order Block.")
// --------------------------------------------------------------------------------------------------------------------}