//@version = 4 // v2 - 46 // v3 - 124 // v4 - 234 //Volume is distributed uniformly along the candlestick range (low-high) study("Uniform Volume profile","Profile",true,max_bars_back=365*5,max_lines_count=500) var lookback = input(150,'Количество баров',minval=1,maxval=1000,group='Basic', tooltip='Number of most recent bars to use for calculation.') var precision= input(100,'Количество линий профиля',minval=1,maxval=500,group='Basic',tooltip='Number of slices to display.') var high_color = input(color.rgb(255, 0, 0), "High color", type = input.color, tooltip = "Pick the color of larger profiles") var low_color = input(color.new(color.blue,80), "Low color", type = input.color, tooltip = "Pick the color of lower profiles") var gradient_render = input(title="Gradient change", defval="uniform", options=["uniform", "sigmoid", "arctanh"], tooltip = "Select how the change between High and Low colors will be done.") // Sigmoid -> 1/(-1 + e^(2 π))*((1 + e^(2 π)) * sigmoid((4*pi)(x-0.5)) - 1). // Rationale: // Select f(x) = A*sigmoid(x)-B such f(-2pi) = 0 and f(2pi) = 1. // Center f(x) (g(x) = f(C*(x-0.5)) so that g(0) = 0 and g(1) = 1. // Arctanh -> 1/2*(tanh^-1(2*tanh(A)*(x-0.5))/(A) + 1) where A = pi. // Rationale: // Crop tanh(x). This is f(A,x) = arctanh(tanh(A)*x)/A. Notice ALWAYS f(A,1) = 1 and f(A,-1) = -1. // Select such A so f(A,x) nicely peaks when x tends to 1 and -1. For example A = pi ~ 0.99627. // Scale x in f(A,x), this is: g(x) = f(A,Z*(x-W)) so that g(0) = -1 and g(1) = 1. This is Z = 2 and W=0.5. // Scale the values of g(x) so it goes between 0 and 1. ie G(x) = 1/2*(g(x)+1). // G(x) = (g(x)+1)/2 = ( f(A,2*(x-0.5)) + 1 )/2 = (arctanh(tanh(A)*(2*(x-0.5)))/(A) + 1 )/2 where A = Pi //----------------------------------------------------------------------------------------- // CONST --------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------- c_red = #ff0000 c_green = #00ff00 var palette_0_to_100 = array.new_color(na) if barstate.isfirst array.push(palette_0_to_100,#cacaca),array.push(palette_0_to_100,#c8c9ca), array.push(palette_0_to_100,#c5c8c9), array.push(palette_0_to_100,#c3c7c9), array.push(palette_0_to_100,#c1c6c8), array.push(palette_0_to_100,#bec5c8),array.push(palette_0_to_100,#bcc5c8), array.push(palette_0_to_100,#bac4c7), array.push(palette_0_to_100,#b7c3c7), array.push(palette_0_to_100,#b5c2c6),array.push(palette_0_to_100,#b2c1c6), array.push(palette_0_to_100,#b0c0c5), array.push(palette_0_to_100,#aebfc5), array.push(palette_0_to_100,#abbec5), array.push(palette_0_to_100,#a9bdc4),array.push(palette_0_to_100,#a6bcc4), array.push(palette_0_to_100,#a4bbc3), array.push(palette_0_to_100,#a2bac3), array.push(palette_0_to_100,#9fbac3), array.push(palette_0_to_100,#9db9c2),array.push(palette_0_to_100,#9ab8c2), array.push(palette_0_to_100,#98b7c1), array.push(palette_0_to_100,#95b6c1), array.push(palette_0_to_100,#93b5c0), array.push(palette_0_to_100,#90b4c0),array.push(palette_0_to_100,#8fb3bf), array.push(palette_0_to_100,#8db2bf), array.push(palette_0_to_100,#8bb2bf), array.push(palette_0_to_100,#89b1bf), array.push(palette_0_to_100,#87b0bf), array.push(palette_0_to_100,#86b0bf), array.push(palette_0_to_100,#84afbf), array.push(palette_0_to_100,#82aebf), array.push(palette_0_to_100,#80aebf), array.push(palette_0_to_100,#7eadbf), array.push(palette_0_to_100,#7cadbf), array.push(palette_0_to_100,#7aacbf), array.push(palette_0_to_100,#78abbf), array.push(palette_0_to_100,#76abbf), array.push(palette_0_to_100,#74aabf), array.push(palette_0_to_100,#72a9bf), array.push(palette_0_to_100,#70a9bf), array.push(palette_0_to_100,#6ea8bf), array.push(palette_0_to_100,#6ca7bf), array.push(palette_0_to_100,#6aa6c0), array.push(palette_0_to_100,#68a6c0), array.push(palette_0_to_100,#66a5c0), array.push(palette_0_to_100,#64a4c0), array.push(palette_0_to_100,#62a4c0), array.push(palette_0_to_100,#60a3c0), array.push(palette_0_to_100,#5fa2bf), array.push(palette_0_to_100,#5da1bf), array.push(palette_0_to_100,#5ca1bf), array.push(palette_0_to_100,#5aa0bf), array.push(palette_0_to_100,#58a0bf), array.push(palette_0_to_100,#579fbf), array.push(palette_0_to_100,#559fbf), array.push(palette_0_to_100,#539ebf), array.push(palette_0_to_100,#519dbf), array.push(palette_0_to_100,#509dbf), array.push(palette_0_to_100,#4e9cbf), array.push(palette_0_to_100,#4c9cbf), array.push(palette_0_to_100,#4a9bbf), array.push(palette_0_to_100,#489bbf), array.push(palette_0_to_100,#469abf),array.push(palette_0_to_100,#4499c0), array.push(palette_0_to_100,#4299c0), array.push(palette_0_to_100,#4098c0), array.push(palette_0_to_100,#3e98c0), array.push(palette_0_to_100,#3c97c0),array.push(palette_0_to_100,#3a96c0), array.push(palette_0_to_100,#3796c0), array.push(palette_0_to_100,#3595c0), array.push(palette_0_to_100,#3395c0), array.push(palette_0_to_100,#3094c0), array.push(palette_0_to_100,#3093bf), array.push(palette_0_to_100,#2991c0), array.push(palette_0_to_100,#218fc0), array.push(palette_0_to_100,#188dc1), array.push(palette_0_to_100,#0c8bc1), array.push(palette_0_to_100,#0089c2), array.push(palette_0_to_100,#0087c2), array.push(palette_0_to_100,#0085c3), array.push(palette_0_to_100,#0083c3), array.push(palette_0_to_100,#0080c3), array.push(palette_0_to_100,#007ec4), array.push(palette_0_to_100,#007cc4), array.push(palette_0_to_100,#007ac4), array.push(palette_0_to_100,#0077c4), array.push(palette_0_to_100,#0075c4),array.push(palette_0_to_100,#0073c4), array.push(palette_0_to_100,#0070c4), array.push(palette_0_to_100,#006ec4), array.push(palette_0_to_100,#006bc4), array.push(palette_0_to_100,#0069c3), array.push(palette_0_to_100,#0066c3), array.push(palette_0_to_100,#0063c2), array.push(palette_0_to_100,#0061c2), array.push(palette_0_to_100,#005ec1), array.push(palette_0_to_100,#005bc0) A = math.pi var tanh_A = (exp(2*A)- 1)/(exp(2*A) + 1) //----------------------------------------------------------------------------------------- // COMMONS --------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------- print_lookbar() => highest = highest(lookback) lowest = lowest(lookback) if barstate.islast var lbl = label.new(na, na) label.set_x(lbl, bar_index-lookback) label.set_y(lbl, highest) label.set_style(lbl, label.style_none) label.set_text(lbl, "Lookback") var lin = line.new(na,na,na,na) line.set_x1(lin, bar_index-lookback) line.set_y1(lin, lowest) line.set_x2(lin, bar_index-lookback) line.set_y2(lin, highest) print_lookbar() //----------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------- _debug(msg,i) => label.new(bar_index, high[1] + 100*(i+1) , style=label.style_none, text=tostring(msg)) var histogram = array.new_line() if barstate.isfirst for i = 0 to precision-1 array.push(histogram,line.new(na,na,na,na,width=2)) levels = array.new_float(0) float highest = highest(lookback) float lowest = lowest(lookback) if barstate.islast height = (highest - lowest)/precision for i = 0 to precision array.push(levels,lowest + i*height) volume_level = array.new_float(0) var total_volume = 0. if barstate.islast for level = 0 to precision-1 total_volume := 0. min = array.get(levels,level) max = array.get(levels,level+1) for k = 0 to lookback -1 // if intersects if high[k] >= min and max >= low[k] // equiv to: if not (high[k] < min_level or max_level < low[k]) // if this candlestick is fully contained if min <= low[k] and high[k] <= max total_volume := total_volume + volume[k] else length = high[k] - low[k] + 1e-6 intersected_length = min(max,high[k])-max(min,low[k]) total_volume := total_volume + volume[k] * intersected_length / length array.push(volume_level,total_volume) if barstate.islast for j = 0 to precision-1 percentage = array.get(volume_level,j) / array.max(volume_level) line current_line = array.get(histogram,j) line.set_xy1(current_line,bar_index-round(lookback*percentage),array.get(levels,j)) line.set_xy2(current_line,bar_index,array.get(levels,j)) line.set_width(current_line, 1) //line.set_color(current_line,array.get(palette_0_to_100, round(percentage*99))) modified_percentage = percentage if gradient_render == "sigmoid" // with sigmoid -> 1/(-1 + e^(2 π))*((1 + e^(2 π)) * sigmoid((4*pi)(x-0.5)) - 1) m_sigmoid = (1/(1+exp(-(4.*math.pi)*(percentage-0.5)))) modified_percentage := 1/(-1+exp(2.*math.pi)) * ((1+exp(2.*math.pi))*m_sigmoid-1) if gradient_render == "arctanh" // 1/2*(tanh^-1(2*tanh(A)*(x-0.5))/(A) + 1). arctanh_arg = 2.*tanh_A*(percentage-0.5) _tanh = 1/2.*log((1+arctanh_arg)/(1-arctanh_arg)) modified_percentage := (_tanh/A+1)/2 line_color_t = color.t(low_color) + modified_percentage * (color.t(high_color) - color.t(low_color)) line_color_r = color.r(low_color) + modified_percentage * (color.r(high_color) - color.r(low_color)) line_color_g = color.g(low_color) + modified_percentage * (color.g(high_color) - color.g(low_color)) line_color_b = color.b(low_color) + modified_percentage * (color.b(high_color) - color.b(low_color)) line_col = color.rgb(line_color_r, line_color_g, line_color_b, line_color_t) line.set_color(current_line,line_col)