本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。
//@version=6
// @description This Order Block Finder is built specifically for XAUUSD / Gold. It identifies institutional supply and demand zones optimized for M30, H1, and H4 timeframes.
indicator("ProjectSyndicate Gold Order Block Finder", shorttitle="PS Gold OB Finder", overlay=true, max_boxes_count=50, max_labels_count=50)
// ═══════════════════════════════════════════════════════════════════════════════
// INPUT PARAMETERS
// ═══════════════════════════════════════════════════════════════════════════════
swing_length = input.int(7, "Swing Detection Length", minval=3, maxval=20, tooltip="Number of candles to left and right for swing detection. Optimized for Gold volatility.")
lookback = input.int(20, "Order Block Lookback", minval=5, maxval=50, tooltip="How many candles to look back to find the OB candle after a swing is detected.")
displacement_mult = input.float(1.3, "Displacement Multiplier", minval=0.5, maxval=5.0, step=0.1, tooltip="Minimum price movement required to validate the OB. Higher values = stronger zones.")
max_obs = input.int(5, "Max Order Blocks", minval=1, maxval=10, tooltip="Maximum number of active order blocks to display per type.")
show_bullish = input.bool(true, "Show Bullish OBs", inline="bull")
bull_color = input.color(color.new(color.green, 85), "", inline="bull")
bull_border = input.color(color.new(color.green, 30), "Border", inline="bull")
show_bearish = input.bool(true, "Show Bearish OBs", inline="bear")
bear_color = input.color(color.new(color.red, 85), "", inline="bear")
bear_border = input.color(color.new(color.red, 30), "Border", inline="bear")
show_labels = input.bool(true, "Show Labels")
// ═══════════════════════════════════════════════════════════════════════════════
// TYPE DEFINITION
// ═══════════════════════════════════════════════════════════════════════════════
type OB
box b
label l
float top
float bot
int bar_idx
bool bullish
// ═══════════════════════════════════════════════════════════════════════════════
// VARIABLES
// ═══════════════════════════════════════════════════════════════════════════════
var array<OB> bull_obs = array.new<OB>()
var array<OB> bear_obs = array.new<OB>()
// ═══════════════════════════════════════════════════════════════════════════════
// SWING DETECTION
// ═══════════════════════════════════════════════════════════════════════════════
swing_high = ta.pivothigh(high, swing_length, swing_length)
swing_low = ta.pivotlow(low, swing_length, swing_length)
// ═══════════════════════════════════════════════════════════════════════════════
// HELPER FUNCTIONS
// ═══════════════════════════════════════════════════════════════════════════════
// Check if OB is mitigated
is_mitigated(ob, curr_close) =>
ob.bullish ? curr_close < ob.bot : curr_close > ob.top
// Remove mitigated OBs
clean_obs(obs) =>
if array.size(obs) > 0
for i = array.size(obs) - 1 to 0
if i < array.size(obs)
ob = array.get(obs, i)
if is_mitigated(ob, close)
box.delete(ob.b)
if not na(ob.l)
label.delete(ob.l)
array.remove(obs, i)
// Limit array size
limit_size(obs, max_size) =>
while array.size(obs) > max_size
old = array.shift(obs)
box.delete(old.b)
if not na(old.l)
label.delete(old.l)
// Update box extensions
update_boxes(obs) =>
if array.size(obs) > 0
for i = 0 to array.size(obs) - 1
ob = array.get(obs, i)
box.set_right(ob.b, bar_index + 20)
// ═══════════════════════════════════════════════════════════════════════════════
// ORDER BLOCK DETECTION
// ═══════════════════════════════════════════════════════════════════════════════
// Find bullish OB (last bearish candle before bullish move)
if not na(swing_low) and show_bullish
bool found = false
float ob_top = na
float ob_bot = na
int ob_bar = na
// Look back for bearish candle
for i = swing_length + 1 to swing_length + lookback
if i < bar_index and not found
if close[i] < open[i] // Bearish candle
disp = swing_low - low[i]
rng = high[i] - low[i]
if disp > (rng * displacement_mult) and rng > 0
ob_top := high[i]
ob_bot := low[i]
ob_bar := bar_index - i
found := true
if found and not na(ob_top)
// Create box
b = box.new(ob_bar, ob_top, bar_index + 20, ob_bot,
border_color=bull_border,
bgcolor=bull_color,
border_width=2,
extend=extend.right)
// Create label
label l = na
if show_labels
l := label.new(ob_bar, ob_bot, "Bull OB",
color=color.new(color.green, 20),
textcolor=color.white,
style=label.style_label_up,
size=size.small)
// Add to array
new_ob = OB.new(b, l, ob_top, ob_bot, ob_bar, true)
array.push(bull_obs, new_ob)
// Find bearish OB (last bullish candle before bearish move)
if not na(swing_high) and show_bearish
bool found = false
float ob_top = na
float ob_bot = na
int ob_bar = na
// Look back for bullish candle
for i = swing_length + 1 to swing_length + lookback
if i < bar_index and not found
if close[i] > open[i] // Bullish candle
disp = high[i] - swing_high
rng = high[i] - low[i]
if disp > (rng * displacement_mult) and rng > 0
ob_top := high[i]
ob_bot := low[i]
ob_bar := bar_index - i
found := true
if found and not na(ob_top)
// Create box
b = box.new(ob_bar, ob_top, bar_index + 20, ob_bot,
border_color=bear_border,
bgcolor=bear_color,
border_width=2,
extend=extend.right)
// Create label
label l = na
if show_labels
l := label.new(ob_bar, ob_top, "Bear OB",
color=color.new(color.red, 20),
textcolor=color.white,
style=label.style_label_down,
size=size.small)
// Add to array
new_ob = OB.new(b, l, ob_top, ob_bot, ob_bar, false)
array.push(bear_obs, new_ob)
// ═══════════════════════════════════════════════════════════════════════════════
// MAINTENANCE
// ═══════════════════════════════════════════════════════════════════════════════
clean_obs(bull_obs)
clean_obs(bear_obs)
limit_size(bull_obs, max_obs)
limit_size(bear_obs, max_obs)
update_boxes(bull_obs)
update_boxes(bear_obs)