abc-123-harmonic-ratio-custom-range-interactive.pine
Copy
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © RozaniGhani-RG
// Credits to Scott M Carney, author of Harmonic Trading : Volume One
// Harmonic Trading Ratios - Page 18
//@version=5
indicator('ABC 123 Harmonic Ratio Custom Range Interactive', shorttitle = 'AHR_CRI', overlay = true, precision = 3)
// —— Import {
import RozaniGhani-RG/PriceTimeInteractive/2 as pti
import RozaniGhani-RG/DeleteArrayObject/1 as obj
import RozaniGhani-RG/HarmonicCalculation/1 as calc
import RozaniGhani-RG/HarmonicSwitches/1 as sw
// }
// —— Content {
// 0. Input
// 1. Initialization
// 2. TRADE IDENTIFICATION - Harmonic Trading System Part 1
// 3. Draw XABCD Pattern (Trade Identification)
// 4. Table
// 5. Construct
// }
// —— 0. Input {
// ———— 1) TIME POINTS {
int point_A = timestamp('2022-07')
int point_B = timestamp('2022-08')
int point_C = timestamp('2022-09')
int time_A = input.time(point_A, 'Point A', group = '1) TIME POINTS', inline = 'A', confirm = true, tooltip = 'Point A must BEFORE Point A')
int time_B = input.time(point_B, 'Point B', group = '1) TIME POINTS', inline = 'B', confirm = true, tooltip = 'Point B must BEFORE Point C')
int time_C = input.time(point_C, 'Point C', group = '1) TIME POINTS', inline = 'C', confirm = true, tooltip = 'Point C must AFTER Point B')
// }
// ———— 2) TABLE DISPLAY {
T8 = '1) Tick to show table\n2) Small font size recommended for mobile app or multiple layout'
T9 = 'Table must be tick before change table position'
i_b_table = input.bool(true, 'Show Table |', group = '2) TABLE DISPLAY', inline = 'Table1')
i_s_font = input.string('normal', 'Font size', group = '2) TABLE DISPLAY', inline = 'Table1', options = ['tiny', 'small', 'normal', 'large', 'huge'], tooltip = T8)
i_s_Y = input.string('bottom', 'Table Position', group = '2) TABLE DISPLAY', inline = 'Table2', options = ['top', 'middle', 'bottom'])
i_s_X = input.string('left', '', group = '2) TABLE DISPLAY', inline = 'Table2', options = ['left', 'center', 'right'], tooltip = T9)
// }
// ———— 3) OTHERS {
i_f_pro = input.float( 2.240, 'Last Projection', group = '3) OTHERS', options = [2.24, 2.618, 3.140, 3.618], tooltip = 'Only applicable')
i_s_label = input.string('ABC', 'Label', group = '3) OTHERS', options = ['ABC', '123'], tooltip = 'Use number or alphabet for label')
i_s_helper = input.string('All', 'Show Helper', group = '3) OTHERS', options = ['All', 'Direction label', 'Range', 'None'])
i_b_col = input.bool( true, 'Use trend color', group = '3) OTHERS', tooltip = 'Show Trend color if true\nTrue : Lime (Bullish), Red (Bearish)\n False : Blue')
i_b_currency = input.bool( true, 'Show Currency', group = '3) OTHERS')
// }
// }
// —— 1. Initialization {
P = 'PRIMARY', PD = 'PRIMARY DERIVED', SD = 'SECONDARY DERIVED', SE = 'SECONDARY DERIVED EXTREME'
SW = switch i_f_pro
2.240 => SD
2.618 => SE
3.140 => SE
3.618 => SE
// }
// —— 2. TRADE IDENTIFICATION - Harmonic Trading System Part 1 {
// ———— 2.1 Get Price from Point A to Point C {
[high_A, low_A, close_A] = pti.hlc_time(time_A)
[high_B, low_B, close_B] = pti.hlc_time(time_B)
[high_C, low_C, _ ] = pti.hlc_time(time_C)
// }
// ———— 2.2 Determine Point A is lower or higher than Point B {
bool A_lower_B = close_A < close_B
[pr_A, pr_B, pr_C] = switch A_lower_B
// Output : pr_A, pr_B, pr_C
true => [ low_A, high_B, low_C]
=> [high_A, low_B, high_C]
[ style0, style1, col_dir] = sw.TupleSwitchStyleColor(A_lower_B)
[str_dir, str_A, str_B] = sw.TupleSwitchString( A_lower_B)
// }
// ———— 2.3 Get ratio and difference for price and time {
y_AB = calc.PriceDiff( pr_B, pr_A), time_AB = calc.TimeDiff( time_B, time_A)
y_BC = calc.PriceDiff( pr_C, pr_B), time_BC = calc.TimeDiff( time_C, time_B), y_ABC = y_BC / y_AB, time_ABC = calc.TimeDiff(time_C, time_A)
// }
// ———— 2.4 Variables for Point C {
bool bool_ret = math.abs(y_ABC) >= 0.382 and math.abs(y_ABC) <= 0.930
bool bool_pro = math.abs(y_ABC) >= 1.073 and math.abs(y_ABC) <= i_f_pro
var bool_ratio = array.new_bool(2)
bool_ratio.set(0, bool_ret)
bool_ratio.set(1, bool_pro)
// }
// ———— 2.5 Verify ratio {
// 0 1 2 3 4 5 6
float_ret = array.from(0.382, 0.500, 0.618, 0.707, 0.786, 0.886, 0.930)
float_pro = array.from(1.073, 1.130, 1.270, 1.410, 1.618, 2.000, i_f_pro)
str_ret = array.from( SD, SD, P, SD, PD, PD)
str_pro = array.from( PD, PD, SD, P, SD, SW)
ret_min = float_ret.copy(), ret_min.remove(0)
ret_max = float_ret.copy(), ret_max.remove(6)
pro_min = float_pro.copy(), pro_min.pop()
pro_max = float_pro.copy(), pro_max.shift()
int int_index = na
if bool_ratio.includes(true)
int_index := bool_ratio.indexof(bool_ratio.includes(true))
str_BB = switch int_index
0 => 'RETRACEMENT'
1 => 'PROJECTION'
float_ratio = switch bool_ratio.indexof(bool_ratio.includes(true))
0 => float_ret
1 => float_pro
float_min = switch bool_ratio.indexof(bool_ratio.includes(true))
0 => ret_min
1 => pro_min
float_max = switch bool_ratio.indexof(bool_ratio.includes(true))
0 => ret_max
1 => pro_max
str_ratio = switch bool_ratio.indexof(bool_ratio.includes(true))
0 => str_ret
1 => str_pro
f_bool(int _index) => math.abs(y_ABC) >= float_ratio.get(_index) and math.abs(y_ABC) < float_ratio.get(_index + 1)
f_rng(int _index) => str.tostring(float_ratio.get(_index), '0.000') + '; ' + str.tostring(float_ratio.get(_index + 1), '0.000')
var bool_rng = array.new_bool(6)
var str_rng = array.new_string(6)
for i = 0 to 5
bool_rng.set(i, f_bool(i))
str_rng.set(i, f_rng(i))
// }
float ratio_min = na
float ratio_max = na
float price_min = na
float price_max = na
if bool_ratio.includes(true)
ratio_min := float_ratio.get(bool_rng.indexof(bool_rng.includes(true)))
ratio_max := float_ratio.get(bool_rng.indexof(bool_rng.includes(true)) + 1)
price_min := calc.AbsoluteRange(pr_B, y_AB, ratio_min)
price_max := calc.AbsoluteRange(pr_B, y_AB, ratio_max)
harmonic = switch str_BB
'RETRACEMENT' => math.min(ratio_min, ratio_max)
'PROJECTION' => math.max(ratio_min, ratio_max)
// ———— 2.6 Overall pattern average for price and time {
y_AC = calc.PriceAverage(pr_C, pr_A), x_AC = calc.TimeAverage(time_A, time_C)
// }
// }
// —— 3. Draw ABC Pattern (Trade Identification) {
// ———— 3.1 Initialize arrays {
str_123 = array.from( '1', '2', '3')
str_ABC = array.from( 'A', 'B', 'C')
arr_pr = array.from( pr_A, pr_B, pr_C)
arr_time = array.from(time_A, time_B, time_C)
y_ratio = array.from( y_AC)
x_ratio = array.from( x_AC)
str_arr = switch i_s_label
'ABC' => str_ABC
'123' => str_123
arr_ratio = array.from(str.tostring(math.abs(y_ABC), '0.000'))
var label_ABC = array.new_label(3), obj.delete(label_ABC)
var ratio_ABC = array.new_label(1), obj.delete(ratio_ABC)
var solid_ABC = array.new_line(2), obj.delete(solid_ABC)
var dot_ABC = array.new_line(1), obj.delete( dot_ABC)
var fill_ABC = array.new_linefill(1), obj.delete( fill_ABC)
var label_rng = array.new_label(1), obj.delete(label_rng)
var hlabel_AC = array.new_label(2), obj.delete(hlabel_AC)
var hline_AC = array.new_line(2), obj.delete( hline_AC)
string txt = na
string str_C = na
if bool_ratio.includes(true)
txt := str_dir + ' ' + str_BB + '\n' +
str_ratio.get(bool_rng.indexof(bool_rng.includes(true))) + ' (' + str.tostring(harmonic, '0.000') + ')'
str_C := str_rng.get(bool_rng.indexof(bool_rng.includes(true)))
else
txt := str_dir + ' ' + str_BB + '\n' + arr_ratio.get(0)
// }
// ———— 3.2 ABC custom functions {
f_label_ABC(int _x, color _col = color.blue) =>
label.new(
x = arr_time.get(_x),
y = arr_pr.get(_x),
text = str_arr.get(_x),
xloc = xloc.bar_time,
color = color.new(color.blue, 100),
style = _x % 2 ? style1 : style0,
textcolor = i_b_col ? col_dir : _col)
f_ratio_ABC(int _x, color _col = color.blue) =>
label.new(
x = x_ratio.get(_x),
y = y_ratio.get(_x),
text = arr_ratio.get(_x),
xloc = xloc.bar_time,
style = label.style_label_center,
textcolor = i_b_col ? color.black : color.white,
color = i_b_col ? col_dir : _col)
f_hlabel(float _ratio, float _y, int _int, color _col = color.blue) =>
label.new(
x = time_A,
y = _y,
text = str.tostring(_ratio, '0.000') + ' (' + str.tostring(_y, '#.000') + ')',
xloc = xloc.bar_time,
style = _int % 2 ? label.style_label_upper_right : label.style_label_lower_right,
color = color.new(_col, 100),
textcolor = i_b_col ? col_dir : _col)
f_line(int _x1, int _y1, int _x2, int _y2, bool _bool = true, int _width = 1, int _transp = 0) =>
_style = switch _bool
true => line.style_solid
false => line.style_dotted
line.new(
x1 = arr_time.get(_x1),
y1 = arr_pr.get(_y1),
x2 = arr_time.get(_x2),
y2 = arr_pr.get(_y2),
xloc = xloc.bar_time,
color = i_b_col ? color.new(col_dir, _transp) : color.new(color.blue, _transp),
style = _style,
width = _width)
f_hline(float _y, int _width = 1, int _transp = 0) =>
line.new(
x1 = time_A,
y1 = _y,
x2 = time_C,
y2 = _y,
xloc = xloc.bar_time,
color = i_b_col ? color.new(col_dir, _transp) : color.new(color.blue, _transp),
style = line.style_solid,
width = _width)
f_fill_ABC(int _x1 = 0, int _x2 = 0, color _col = color.blue) =>
linefill.new(solid_ABC.get(_x1), dot_ABC.get(_x2), i_b_col ? color.new(col_dir, 80) : color.new(_col, 80))
f_label_rng(string _txt, color _col = color.blue) =>
label.new(
x = time_A,
y = pr_B,
text = _txt,
xloc = xloc.bar_time,
style = label.style_label_right,
color = color.new(_col, 100),
textcolor = i_b_col ? col_dir : _col)
// }
// }
// —— 4. Table {
// ———— 4.1 Table variable {
var table_ABC = table.new(position = i_s_Y + '_' + i_s_X, columns =7, rows = 6, border_color = color.new(color.blue, 100), border_width = 1)
row_0 = array.from('POINT', 'RATIO', 'SPEC', 'PRICE')
column_1 = array.from( str_A, str_B, str_C)
column_3 = array.from( pr_A, pr_B, pr_C)
// 0, 1, 2, 3
// }
// ———— 4.2 Table custom functions {
f_cell(int _column, int _row, string _text, color _col1 = color.black, color _col2 = color.white, bool halign = true) =>
table_ABC.cell(_column, _row, _text, text_color = _col1, text_size = i_s_font,
text_halign = halign ? text.align_right : text.align_center, bgcolor = _col2)
// }
// }
// —— 5. Construct {
if barstate.islast
for x = 0 to 2
label_ABC.set(x, f_label_ABC(x))
for x = 0 to 1
solid_ABC.set(x, f_line(x, x, x + 1, x + 1, true, 4))
ratio_ABC.set(0, f_ratio_ABC(0))
dot_ABC.set( 0, f_line(0, 0, 0 + 2, 0 + 2, false))
fill_ABC.set( 0, f_fill_ABC())
if array.includes(bool_ratio, true)
if i_s_helper == 'All' or i_s_helper == 'Direction label'
label_rng.set(0, f_label_rng(txt))
if i_s_helper == 'All' or i_s_helper == 'Range'
hline_AC.set( 0, f_hline(price_min))
hline_AC.set( 1, f_hline(price_max))
hlabel_AC.set(0, f_hlabel(ratio_min, price_min, 0))
hlabel_AC.set(1, f_hlabel(ratio_max, price_max, 1))
if i_b_table
if bool_ratio.includes(true)
f_cell(0, 0, txt, color.black, col_dir)
table_ABC.merge_cells(0, 0, 3, 0)
for i = 0 to 3
f_cell(i, 1, array.get(row_0, i), color.white, color.blue, false)
for i = 0 to 2
f_cell(0, i + 2, str_arr.get(i), (i + 1) % 3 ? col_dir : color.black, (i + 1) % 3 ? color.black : col_dir, false)
f_cell(1, i + 2, column_1.get(i), (i + 1) % 3 ? col_dir : color.black, (i + 1) % 3 ? color.black : col_dir, false)
f_cell(3, i + 2, calc.PriceCurrency(i_b_currency, column_3.get(i)), (i + 1) % 3 ? col_dir : color.black, (i + 1) % 3 ? color.black : col_dir, false)
f_cell(2, 2, '', color.white, color.black)
table_ABC.merge_cells(2, 2, 2, 3)
f_cell(2, 4, arr_ratio.get(0), color.black, col_dir, false)
plot(i_s_label == 'ABC' ? pr_A : na, 'A', color.new(col_dir, 100))
plot(i_s_label == 'ABC' ? pr_B : na, 'B', color.new(col_dir, 100))
plot(i_s_label == 'ABC' ? pr_C : na, 'C', color.new(col_dir, 100))
plot(i_s_label == '1' ? pr_A : na, '1', color.new(col_dir, 100))
plot(i_s_label == '2' ? pr_B : na, '2', color.new(col_dir, 100))
plot(i_s_label == '3' ? pr_C : na, '3', color.new(col_dir, 100))
plot( price_min, 'Min', color.new(color.blue, 100))
plot( price_max, 'Max', color.new(color.blue, 100))
// }
Show all 279 lines