// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © boitoki
//@version=5
indicator("Barbwire", overlay=true, precision=2, max_boxes_count=300, max_lines_count=500)
import boitoki/AwesomeColor/5 as ac
import boitoki/ma_function/3 as ma
import boitoki/RCI/4 as rci_func
[hopen, hclose] = request.security(ticker.heikinashi(syminfo.tickerid), timeframe.period, [open, close])
hoc2 = math.avg(math.max(hopen, hclose), math.min(hopen, hclose))
oc2 = math.avg(math.max(open, close), math.min(open, close))
////////////
// DEFINE //
option_source1 = 'Open-Close Heikin-Ashi'
option_source4 = 'Open-Close'
option_source2 = 'High-Low'
option_source3 = 'Hybrid'
sign = 'Display'
GP1 = sign
GP2 = sign
GP3 = sign
color_red = #D93611
color_blue = #1D5A73
//////////////
// FUNCTION //
//
f_HR (_open, _close) => math.abs(_open - _close)
//
f_source (_type) =>
switch _type
option_source1 => f_HR(hopen, hlc3)
option_source2 => f_HR(high, low)
option_source3 => math.avg(f_HR(hopen, hlc3) * 0.6, f_HR(open, close) * 0.3, f_HR(high, low) * 0.1)
option_source4 => f_HR(open, close)
=> f_HR(high, low)
//
f_get_data (_source, _len) =>
data = array.new<float>()
for i = 1 to _len
array.push(data, _source[i])
data
f_remove_boxes (_arr, _max) =>
if array.size(_arr) > _max
for i = _max to array.size(_arr)
box.delete(array.shift(_arr))
f_get_width_by_box (_id) => math.abs(box.get_right(_id) - box.get_left(_id))
//
f_renderBox (_start, _processing, _end, _min, _border_width, _border_color, _bgcolor, _drawing_max, _show) =>
start_notif = false
end_notif = false
count = 0
if _show
var box barb_box = na
var label txt = na
var line top = na
var line bot = na
var float y1 = na
var float y2 = na
var int x1 = na
line_style = line.style_dotted
var boxes = array.new<box>()
count := f_get_width_by_box(barb_box)
if _start
x1 := bar_index
y1 := high
y2 := low
barb_box := box.new(x1, y1, x1, y2, _border_color, _border_width, line.style_solid, bgcolor=_bgcolor)
txt := label.new(x1, y1, '•', color=color.new(_border_color, 5), textcolor=ac.panda('verydarkgray'), size=size.tiny)
if _processing
y1 := math.max(y1, high)
y2 := math.min(y2, low)
box.set_top(barb_box, y1)
box.set_bottom(barb_box, y2)
box.set_right(barb_box, bar_index)
label.set_y(txt, y1)
label.set_text(txt, '•••')
if count == _min
start_notif := true
if _end
box.set_right(barb_box, bar_index)
label.delete(txt)
if count < _min
box.delete(barb_box)
else
array.push(boxes, barb_box)
f_remove_boxes(boxes, _drawing_max)
end_notif := true
y1 := na, y2 := na
[start_notif, end_notif, count]
//
//
f_barb_start (in_barb) => in_barb and (not in_barb[1])
f_barb_end (in_barb) => (not in_barb) and in_barb[1]
//
//
f_dir_by_roc (_src, _len, _scale=2.0) =>
roc_arr = array.new<float>(_len)
roc = ta.roc(_src, 2)
roc_moved = math.abs(roc - roc[3])
for i = 1 to _len
array.push(roc_arr, roc_moved[i])
min_roc_value = array.min(roc_arr)
min_roc_value := array.stdev(roc_arr) * _scale
roc_moved <= min_roc_value
//
f_barb_roc (_len) =>
height = math.max(hopen, hclose) - math.min(hopen, hclose)
roc = ta.roc(height, _len)
roc <= 0
//
f_barb_stoch (_source1, _source2, _len, _lv) =>
v1 = ta.stoch(_source1, _source1, _source1, _len)
v2 = ta.stoch(_source2, _source2, _source2, math.round(_len * 0.5))
(v1 <= _lv) and (v2 <= _lv)
//
f_barb_rank (_source, _len, _sens) =>
arr = array.new<float>(_len)
new_arr = array.new<float>()
for i = 1 to _len
array.push(arr, _source[i])
min_value = array.min(arr)
min_value := array.percentile_nearest_rank(arr, _sens)
min_value := math.max(min_value, syminfo.mintick * 2)
in_barb = _source <= (min_value)
in_barb
f_le (_v, _std, _malt) => _v <= _std * _malt
f_ge (_v, _std, _malt) => _v >= _std * _malt
f_id (_v, _arr) => array.indexof(_arr, array.min(_arr)) < _v
////////////
// INPUTS //
i_source_type = input.string(option_source3, 'Source', options=[option_source1, option_source4, option_source2, option_source3])
i_min = input.int(4, 'Num. of minimum bars', minval=0)
i_show_barb = input.bool(true, 'Mixed', group=GP1)
i_show_barb_stoch = input.bool(false, 'Stochastic', group=GP1, tooltip='Length • Level %')
i_stoch_length = input.int(50, '↔', inline='stoch_param', group=GP1)
i_stoch_level = input.int(18, '/ ≤', inline='stoch_param', group=GP1)
i_show_barb_rank = input.bool(false, 'Rank %', group=GP2, tooltip='Length • Level %')
i_len = input.int(100, '↔', inline='rank_param', group=GP2)
i_rank_level = input.int(5, '/ ≤', minval=0, inline='rank_param', group=GP2)
i_show_barb_stdev = false //input.bool(false, '• Stdev', inline='stdev', group=GP3, tooltip='Level')
i_stdev_mult = 0.20 //input.float(0.20, '', minval=0.0, step=0.01, inline='stdev', group=GP3)
// FILTER
i_dir_roc_sens = 2.0 // input.float(2.0, '', minval=0, step=0.1, group='FILTER')
i_filter_stdev5 = true // input.bool(true, 'Filtered ">5STDEV"', group='Filter')
// STYLE
i_border_width = input.int(2, '', minval=0, group='style', inline='style', tooltip='Border width / color / bgcolor')
i_boxcolor = input.color(color.new(#F2A341, 20), '', group='style', inline='style')
i_bgcolor = input.color(color.new(#F4C58B, 84), '', group='style', inline='style')
i_barcolor = input.bool(false, "Bar colors", group='OPTIONS')
i_spot_smallest = input.bool(false, 'Smallest bar', inline='smallest_bar', group='OPTIONS')
i_smallest_color = input.color(#F2A341, '', inline='smallest_bar', group='OPTIONS')
i_spot_largest = input.bool(false, 'Largest bar', inline='largest_bar', group='OPTIONS')
i_largest_color = input.color(#0C74A6, '', inline='largest_bar', group='OPTIONS')
i_spot_priceflip = false //input.bool(false, 'Price flip', group='OPTIONS')
i_memory_cleaning = false //input.bool(false, 'Memory cleaning', group='OPTIONS')
i_drawing_max = i_memory_cleaning ? 5 : 200
//////////
// DATA //
HR = f_source(i_source_type)
data_len = i_len
all_data = f_get_data(HR, data_len)
all_stdev = array.stdev(all_data)
a_data = array.new<float>()
if i_filter_stdev5 and array.size(all_data) > 0
for i = 0 to array.size(all_data) - 1
my_value = array.get(all_data, i)
if my_value < all_stdev * 5
array.push(a_data, my_value)
else
a_data := array.copy(all_data)
v_std = array.stdev(a_data)
v_avg = array.avg(a_data)
i_stdev_xs = 0.18
i_stdev_s = 0.50
i_stdev_l = 4.00
i_stdev_xl = 5.00
is_le030 = f_le(HR, v_std, i_stdev_s)
is_le005 = f_le(HR, v_std, i_stdev_xs)
is_small = f_le(HR, v_std, i_stdev_xs)
is_geL = f_ge(HR, v_std, i_stdev_l)
is_geXL = f_ge(HR, v_std, i_stdev_xl)
is_largest = is_geXL
is_smallest = (f_id(1, a_data) or f_le(HR, v_std, i_stdev_xs))
if is_smallest[1]
is_smallest := false
//////////
// CALC //
// FILTER //
is_dir_by_roc = f_dir_by_roc(hoc2, i_len, i_dir_roc_sens)
in_barb_by_stoch = f_barb_stoch(f_HR(hopen, ohlc4), f_HR(high, low), i_stoch_length, i_stoch_level)
in_barb_by_rank = f_barb_rank(HR, i_len, i_rank_level) and is_dir_by_roc
in_barb_by_stdev = f_le(HR, v_std, i_stdev_mult) and is_dir_by_roc
in_barb_by_roc = f_barb_roc(16)
in_barb = in_barb_by_stoch or in_barb_by_rank or in_barb_by_stdev
///////////////////
// Conditions
///////////////////
//////////////
// BARBWIRE //
//if i_filter_roc
// is_barb := is_barb and is_dir_by_roc
stoch_barb_start = f_barb_start(in_barb_by_stoch)
stoch_barb_end = f_barb_end(in_barb_by_stoch)
rank_barb_start = f_barb_start(in_barb_by_rank)
rank_barb_end = f_barb_end(in_barb_by_rank)
stdev_barb_start = f_barb_start(in_barb_by_stdev)
stdev_barb_end = f_barb_end(in_barb_by_stdev)
barb_start = f_barb_start(in_barb)
barb_end = f_barb_end(in_barb)
// RENDERING //
f_renderBox(stoch_barb_start, in_barb_by_stoch, stoch_barb_end, i_min, i_border_width, i_boxcolor, i_bgcolor, i_drawing_max, i_show_barb_stoch and barstate.isconfirmed)
f_renderBox(rank_barb_start, in_barb_by_rank, rank_barb_end, i_min, i_border_width, i_boxcolor, i_bgcolor, i_drawing_max, i_show_barb_rank and barstate.isconfirmed)
f_renderBox(stdev_barb_start, in_barb_by_stdev, stdev_barb_end, i_min, i_border_width, i_boxcolor, i_bgcolor, i_drawing_max, i_show_barb_stdev and barstate.isconfirmed)
[start_notif, end_notif, barb_count] = f_renderBox(barb_start, in_barb, barb_end, i_min, i_border_width, i_boxcolor, i_bgcolor, i_drawing_max, i_show_barb and barstate.isconfirmed)
if in_barb and barb_count >= i_min
is_smallest := false
////////////////
// CONDITIONS //
bar_type = close > open ? 1 : -1
hbar_type = ohlc4 > hopen ? 1 : -1
// TD Sequence
var TD = 0
var TS = 0
TD := ohlc4 > ohlc4[4] ? nz(TD[1])+1 : 0
TS := ohlc4 < ohlc4[4] ? nz(TS[1])+1 : 0
TDUp = TD - ta.valuewhen(TD < TD[1], TD , 1)
TDDn = TS - ta.valuewhen(TS < TS[1], TS , 1)
is_priceflip = hbar_type != hbar_type[1]
///////////////
// RENDERING //
//////////////
// PLOTTING //
color bar_color = na
if i_barcolor
if is_largest
bar_color := i_largest_color
else if is_smallest
bar_color := i_smallest_color
else
bar_color := na
barcolor(i_barcolor ? bar_color : na)
plotshape(i_spot_smallest and is_smallest ? oc2[1] : na, 'Smallest bar', text="Smallest bar", style=shape.diamond, color=color.new(i_smallest_color, 30), location=location.absolute, size=size.tiny , textcolor=color.new(color.white, 100), offset=-1)
plotshape(i_spot_largest and is_largest ? oc2[0] : na, 'Largest bar' , text="Largest bar" , style=shape.diamond, color=color.new(i_largest_color , 30), location=location.absolute, size=size.tiny , textcolor=color.new(color.white, 100))
plotshape(is_priceflip and hbar_type == -1 and TDUp and TD >= 12, 'Price flip sell', text="⌁", color=color_red , textcolor=color.white, style=shape.labeldown, location=location.abovebar, size=size.tiny, display=display.none)
plotshape(is_priceflip and hbar_type == 1 and TDDn and TS >= 12, 'Price flip buy', text="⌁", color=color_blue, textcolor=color.white, style=shape.labelup , location=location.belowbar, size=size.tiny, display=display.none)
///////////
// ALERT //
alertcondition(start_notif, "Barbwire start", "Barbwire start")
alertcondition(end_notif , "Barbwire end" , "Barbwire end" )
alertcondition(is_smallest, "The smallest bar", "The smallest bar appeared")
//////////////
// ANALYSIS //
i_analysis_show = false//input.bool(false, 'Analysis', group='ANALYSIS')
i_analysis_asc = false//input.bool(false, 'Order ascending', group='ANALYSIS')
verticalAdj = 0.6
lookbackLength = i_len//input.int(200, 'Length', group='ANALYSIS')
priceHighest = ta.highest(high, lookbackLength)
priceLowest = ta.lowest (low , lookbackLength)
priceChangeRate = (priceHighest - priceLowest) / priceHighest
oscTop = priceLowest * (1 - priceChangeRate * 0.2)
oscBottom = priceLowest * (1 - priceChangeRate * verticalAdj)
priceHighest := priceHighest * (1 + priceChangeRate * verticalAdj)
barIndex = 0
oscHeight = oscTop - oscBottom
oscHighest = array.max(a_data)
analysis_data_ = f_get_data(HR, lookbackLength)
analysis_data = array.new<float>()
analysis_stdev = array.stdev(analysis_data_)
if i_filter_stdev5 and array.size(analysis_data_) > 0
for i = 0 to array.size(analysis_data_) - 1
my_value = array.get(analysis_data_, i)
if my_value < analysis_stdev * 5
array.push(analysis_data, my_value)
else
analysis_data := array.copy(analysis_data_)
var a_line = array.new<line>()
var a_labels = array.new<label>()
if barstate.islast and i_analysis_show and array.size(analysis_data) > 0
if (array.size(a_line) > 0)
for i = 0 to array.size(a_line) - 1
line.delete(array.shift(a_line))
if (array.size(a_labels) > 0)
for i = 0 to array.size(a_labels) - 1
label.delete(array.shift(a_labels))
hightAdj = oscHeight / oscHighest
rank = array.percentile_nearest_rank(analysis_data, i_rank_level)
stdev = array.stdev(analysis_data)
stdev_xs = stdev * i_stdev_xs
stdev_s = stdev * i_stdev_s
stdev_l = stdev * i_stdev_l
if i_analysis_asc
array.sort(analysis_data, order.ascending)
array.push(a_line, line.new(bar_index, oscTop, bar_index - lookbackLength, oscTop, width=1, color=color.new(color.blue, 75)))
array.push(a_line, line.new(bar_index, oscBottom, bar_index - lookbackLength, oscBottom, width=1))
array.push(a_line, line.new(bar_index, oscBottom, bar_index - lookbackLength, oscBottom, width=1))
array.push(a_line, line.new(bar_index, oscBottom + (rank * hightAdj), bar_index - lookbackLength, oscBottom + (rank * hightAdj), style=line.style_dotted, width=1, color=color.new(color.orange, 30)))
array.push(a_line, line.new(bar_index, oscBottom + (stdev_xs * hightAdj), bar_index - lookbackLength, oscBottom + (stdev_xs * hightAdj), style=line.style_dotted, width=1, color=color.new(color.purple, 30)))
array.push(a_line, line.new(bar_index, oscBottom + (stdev_l * hightAdj), bar_index - lookbackLength, oscBottom + (stdev_l * hightAdj), style=line.style_dotted, width=1))
array.push(a_labels, label.new(bar_index + 1, oscBottom + (rank * hightAdj), 'Rank', color=color.new(color.orange, 30), style=label.style_label_left, textcolor=color.white, size=size.tiny))
array.push(a_labels, label.new(bar_index + 1, oscBottom + (stdev_xs * hightAdj), 'Stdev XS', color=color.new(color.purple, 30), style=label.style_label_left, textcolor=color.white, size=size.tiny))
array.push(a_labels, label.new(bar_index + 1, oscBottom + (stdev_l * hightAdj), 'Stdev L' , color=color.new(color.blue , 30), style=label.style_label_left, textcolor=color.white, size=size.tiny))
xc = int(math.avg(bar_index, bar_index - lookbackLength))
array.push(a_line, line.new(xc, oscBottom, xc, oscBottom + oscHeight, style=line.style_dotted))
for i = 0 to array.size(analysis_data) - 1
y2 = array.get(analysis_data, i)
color_bar = y2 < (rank) ? color.orange : y2 < (stdev) ? color.blue : color.from_gradient(50, 0, 100, color.blue, color.black)
color_bar := y2 < stdev_xs ? color.purple : color_bar
array.push(a_line, line.new(bar_index - i, oscBottom, bar_index - i, oscBottom + (y2 * hightAdj), color=color.new(color_bar, 40), width=2) )
Show all 423 lines