本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © JacobMagleby
//@version=5
indicator(title = "Volume Profile Bar-Magnified Order Blocks [JacobMagleby]", shorttitle = "Volume Profile Bar-Magnified Order Blocks [JacobMagleby]", overlay = true, max_boxes_count = 500, max_lines_count = 500)
// { START CONSTANTS BUILD
OB_BORDER_WIDTH = 2
// } END CONSTANTS BUILD
// { START USER INPUT BUILD
tuning = input.int(title = "Tuning", defval = 7, group = "Main Settings")
amount_of_boxes = input.int(title = "Amount Of Grids", defval = 10, group = "Main Settings")
ob_high_volume_color = input.color(title = "", defval = color.new(color.yellow, 35), group = "Color Settings", inline = "colors")
ob_low_volume_color = input.color(title = "", defval = color.new(color.orange, 35), group = "Color Settings", inline = "colors")
ob_border_color = input.color(title = "", defval = color.new(color.gray, 85), group = "Color Settings", inline = "colors")
ob_linefill_color = input.color(title = "", defval = color.new(color.gray, 75), group = "Color Settings", inline = "colors")
// } END USER INPUT BUILD
// { START FUNCTIONS BUILD
check_ob_conditions(set)=>
bear = false
for i = tuning - 1 to 0
start = tuning - 1
if i == start
if close[i] <= open[i]
break
else
if close[i] > open[i]
break
if i == 0
bear := true
bull = false
for i = tuning - 1 to 0
start = tuning - 1
if i == start
if close[i] >= open[i]
break
else
if close[i] < open[i]
break
if i == 0
bull := true
[bear, bull]
// } END FUNCTIONS BUILD
// { START OBJECT BLUEPRINTS BUILD
type orderBlock
line top_line
line bot_line
linefill bg_fill
array<box> box_array = na
array<float> box_volume = na
float top_value
float bot_value
int left_time
int right_time
string direction
method generateBorderLines(orderBlock order_block, top_value, bot_value)=>
new_top_line = line.new(x1 = order_block.left_time, y1 = top_value, x2 = time, y2 = top_value, xloc = xloc.bar_time, extend = extend.none, color = ob_border_color, style = line.style_solid, width = OB_BORDER_WIDTH)
new_bot_line = line.new(x1 = order_block.left_time, y1 = bot_value, x2 = time, y2 = bot_value, xloc = xloc.bar_time, extend = extend.none, color = ob_border_color, style = line.style_solid, width = OB_BORDER_WIDTH)
new_linefill = linefill.new(new_top_line, new_bot_line, ob_linefill_color)
order_block.top_line := new_top_line
order_block.bot_line := new_bot_line
order_block.bg_fill := new_linefill
method generateVolume(orderBlock order_block, top_value, bot_value, v_array, h_array, l_array)=>
new_volume_array = order_block.box_volume
starting_value = top_value
increment = (top_value - bot_value) / amount_of_boxes
for i = 0 to amount_of_boxes - 1
top_of_grid = starting_value - (increment * i)
bot_of_grid = starting_value - (increment * (i + 1))
if array.size(v_array) > 0 and array.size(h_array) > 0 and array.size(l_array) > 0
for j = 0 to array.size(v_array) - 1
candle_volume = array.get(v_array, j)
candle_high = array.get(h_array, j)
candle_low = array.get(l_array, j)
ltf_diff = candle_high - candle_low
if candle_low <= top_of_grid and candle_high >= bot_of_grid
top_register = math.min(candle_high, top_of_grid)
bot_register = math.max(candle_low, bot_of_grid)
register_diff = top_register - bot_register
register_vol = register_diff / ltf_diff
array.set(new_volume_array, i, array.get(new_volume_array, i) + nz(register_vol * candle_volume))
array.sum(new_volume_array)
method generateBoxes(orderBlock order_block, top_value, bot_value, left_value, right_value)=>
new_boxes_array = array.new_box()
highest_volume = array.max(order_block.box_volume)
lowest_volume = array.min(order_block.box_volume)
time_length = order_block.right_time - order_block.left_time
time_ratio = time_length / highest_volume
starting_value = top_value
increment = (top_value - bot_value) / amount_of_boxes
for i = 0 to amount_of_boxes - 1
top_of_grid = starting_value - (increment * i)
bot_of_grid = starting_value - (increment * (i + 1))
color_ = color.from_gradient(array.get(order_block.box_volume, i), lowest_volume, highest_volume, ob_low_volume_color, ob_high_volume_color)
new_box = box.new(left = order_block.left_time, top = top_of_grid, right = order_block.left_time + math.round(array.get(order_block.box_volume, i) * time_ratio), bottom = bot_of_grid, border_color = color_, border_width = 2, xloc = xloc.bar_time, bgcolor = color_, extend = extend.none)
array.push(new_boxes_array, new_box)
order_block.box_array := new_boxes_array
method updateBoxes(orderBlock order_block, current_time)=>
order_block.right_time := current_time
highest_volume = array.max(order_block.box_volume)
lowest_volume = array.min(order_block.box_volume)
time_length = order_block.right_time - order_block.left_time
time_ratio = time_length / highest_volume
for i = 0 to amount_of_boxes - 1
box.set_right(array.get(order_block.box_array, i), order_block.left_time + math.round(array.get(order_block.box_volume, i) * time_ratio))
line.set_x2(order_block.top_line, order_block.right_time)
line.set_x2(order_block.bot_line, order_block.right_time)
method wipeBlock(orderBlock order_block)=>
line.delete(order_block.top_line)
line.delete(order_block.bot_line)
linefill.delete(order_block.bg_fill)
for i = array.size(order_block.box_array) - 1 to 0
box_ = array.get(order_block.box_array, i)
box.delete(box_)
// } END OBJECT BLUEPRINTS BUILD
// { START LOWER TIMEFRAME SECURITY BUILD
tf = timeframe.isdaily ? 1440 : timeframe.isweekly ? 1440 * 7 : timeframe.ismonthly ? 1440 * 30 : str.tonumber(timeframe.period)
req_tf = math.round(tf / 15) < 1 ? "30S" : str.tostring(math.round(tf / 15))
[h, l, v] = request.security_lower_tf(syminfo.tickerid, req_tf, [high, low, volume])
// } END LOWER TIMEFRAME SECURITY BUILD
// { START INDICATOR CONSTRUCTION BUILD
[bear, bull] = check_ob_conditions(tuning)
var array<orderBlock> order_block_array = array.new<orderBlock>(0)
if not na(bar_index[tuning]) and barstate.isconfirmed
if bear
top_value = high[tuning - 1]
bot_value = low[tuning - 1]
left_value = time[tuning - 1]
right_value = time
new_order_block = orderBlock.new(top_value = top_value, bot_value = bot_value, left_time = left_value, right_time = right_value, box_volume = array.new_float(amount_of_boxes, 0), direction = "Bear")
new_order_block.generateBorderLines(new_order_block.top_value, new_order_block.bot_value)
vol = new_order_block.generateVolume(new_order_block.top_value, new_order_block.bot_value, v[tuning - 1], h[tuning - 1], l[tuning - 1])
new_order_block.generateBoxes(new_order_block.top_value, new_order_block.bot_value, new_order_block.left_time, new_order_block.right_time)
if vol == 0
new_order_block.wipeBlock()
else
array.push(order_block_array, new_order_block)
if bull
top_value = high[tuning - 1]
bot_value = low[tuning - 1]
left_value = time[tuning - 1]
right_value = time
new_order_block = orderBlock.new(top_value = top_value, bot_value = bot_value, left_time = left_value, right_time = right_value, box_volume = array.new_float(amount_of_boxes, 0), direction = "Bull")
new_order_block.generateBorderLines(new_order_block.top_value, new_order_block.bot_value)
vol = new_order_block.generateVolume(new_order_block.top_value, new_order_block.bot_value, v[tuning - 1], h[tuning - 1], l[tuning - 1])
new_order_block.generateBoxes(new_order_block.top_value, new_order_block.bot_value, new_order_block.left_time, new_order_block.right_time)
if vol == 0
new_order_block.wipeBlock()
else
array.push(order_block_array, new_order_block)
max_blocks = math.floor(500 / amount_of_boxes)
if array.size(order_block_array) > 0
for i = array.size(order_block_array) - 1 to 0
block = array.get(order_block_array, i)
block.updateBoxes(time)
bull_break = block.direction == "Bull" and close < block.bot_value
bear_break = block.direction == "Bear" and close > block.top_value
if (bull_break or bear_break or i < (array.size(order_block_array) - 1 - max_blocks)) and barstate.isconfirmed
block.wipeBlock()
array.remove(order_block_array, i)
// } END INDICATOR CONSTRUCTION BUILD