Harmonic Patterns + Fib
//Created by CRT Trader [https://x.com/bapiserv] //@version=5 indicator("Harmonic Patterns + Fib [CRT Trader]", overlay=true, max_lines_count=500, max_labels_count=200, max_bars_back=1000) show_butt = input.bool(true, "Butterfly", group="Formation") show_bat = input.bool(true, "Bat", group="Formation") show_crab = input.bool(true, "Crab", group="Formation") show_shark = input.bool(true, "Shark", group="Formation") show_gart = input.bool(true, "Gartley", group="Formation") show_abcd = input.bool(false, "ABCD", group="Formation") // Optimized parameters max_patterns = input.int(1, "Max Patterns", minval=1, maxval=5, group="Settings") lookback = input.int(5, "Pivot Lookback", minval=3, maxval=15, group="Settings") depth = input.int(20, "Depth", minval=10, maxval=30, group="Settings") tolerance = input.float(15, "Tolerance (%)", minval=5, maxval=30, group="Settings") scan_frequency = input.int(10, "Scan Every N Bars", minval=1, maxval=50, group="Settings") show_fib = input.bool(true, "Show Fib", group="Options") show_bearish = input.bool(true, "Show Bearish Formations", group="Options") show_lines = input.bool(true, "Show Lines", group="Options") show_labels = input.bool(true, "Show Labels", group="Options") show_table = input.bool(false, "Information Table", group="Options") // Colors bullish_color = input.color(color.lime, "Bullish Color", group="Colors") bearish_color = input.color(color.red, "Bearish Color", group="Colors") abcd_color = input.color(color.blue, "ABCD Color", group="Colors") fib_color = input.color(color.blue, "Fibonacci Lines Color", group="Colors") var lines = array.new_line() var labels = array.new_label() var linefills = array.new_linefill() // Pivot detection with reduced frequency pivot_high = ta.pivothigh(high, lookback, lookback) pivot_low = ta.pivotlow(low, lookback, lookback) // Optimized pivot storage var array
pivots_high = array.new
() var array
pivots_high_bar = array.new
() var array
pivots_low = array.new
() var array
pivots_low_bar = array.new
() // Add new pivots only when found if not na(pivot_high) if array.size(pivots_high) >= depth array.pop(pivots_high) array.pop(pivots_high_bar) array.unshift(pivots_high, pivot_high) array.unshift(pivots_high_bar, bar_index - lookback) if not na(pivot_low) if array.size(pivots_low) >= depth array.pop(pivots_low) array.pop(pivots_low_bar) array.unshift(pivots_low, pivot_low) array.unshift(pivots_low_bar, bar_index - lookback) // Optimized Fibonacci check fib_check(actual, expected, tolerance_pct) => math.abs(actual - expected) / expected <= tolerance_pct / 100 // Pattern data type type PatternData float x float a float b float c float d int x_bar int a_bar int b_bar int c_bar int d_bar bool is_bullish string pattern_type // Optimized pattern detection with early exits detect_pattern_fast(x, a, b, c, d) => xa = math.abs(a - x) ab = math.abs(b - a) bc = math.abs(c - b) cd = math.abs(d - c) ad = math.abs(d - a) // Early exit for invalid ratios if xa == 0 or ab == 0 or bc == 0 or cd == 0 or ad == 0 "" else ab_xa = ab / xa bc_ab = bc / ab cd_bc = cd / bc ad_xa = ad / xa // Quick range checks before expensive fib_check calls if ab_xa < 0.3 or ab_xa > 2.0 or bc_ab < 0.5 or bc_ab > 1.5 "" else pattern_name = "" // Check patterns in order of commonness if show_bat and fib_check(ab_xa, 0.382, tolerance) and fib_check(bc_ab, 0.886, tolerance) and fib_check(cd_bc, 1.618, tolerance) and fib_check(ad_xa, 0.886, tolerance) pattern_name := "Bat" else if show_gart and fib_check(ab_xa, 0.618, tolerance) and fib_check(bc_ab, 0.618, tolerance) and fib_check(cd_bc, 1.272, tolerance) and fib_check(ad_xa, 0.786, tolerance) pattern_name := "Gartley" else if show_butt and fib_check(ab_xa, 0.786, tolerance) and fib_check(bc_ab, 0.618, tolerance) and fib_check(cd_bc, 1.618, tolerance) and fib_check(ad_xa, 1.27, tolerance) pattern_name := "Butterfly" else if show_crab and fib_check(ab_xa, 0.618, tolerance) and fib_check(bc_ab, 0.886, tolerance) and fib_check(cd_bc, 2.24, tolerance) and fib_check(ad_xa, 1.618, tolerance) pattern_name := "Crab" else if show_shark and fib_check(ab_xa, 0.618, tolerance) and fib_check(bc_ab, 1.13, tolerance) and fib_check(cd_bc, 1.618, tolerance) and fib_check(ad_xa, 0.886, tolerance) pattern_name := "Shark" pattern_name // ABCD Pattern Detection (4-point pattern) detect_abcd_only(a, b, c, d) => ab = math.abs(b - a) bc = math.abs(c - b) cd = math.abs(d - c) if ab == 0 or bc == 0 or cd == 0 "" else bc_ab = bc / ab cd_bc = cd / bc // ABCD ratios with tolerance if show_abcd and bc_ab >= (0.382 * (1 - tolerance/100)) and bc_ab <= (0.886 * (1 + tolerance/100)) and cd_bc >= (1.13 * (1 - tolerance/100)) and cd_bc <= (2.618 * (1 + tolerance/100)) "ABCD" else "" // Heavily optimized pattern finding with reduced loops (including ABCD) find_patterns_optimized() => var array
patterns = array.new
() array.clear(patterns) high_size = array.size(pivots_high) low_size = array.size(pivots_low) patterns_found = 0 // Early exit if not enough pivots if high_size < 2 or low_size < 3 patterns else // 5-point bullish patterns (L-H-L-H-L) and bullish ABCD (H-L-H-L) if high_size >= 2 and low_size >= 3 and patterns_found < max_patterns max_d = math.min(low_size - 1, 8) for d_idx = 0 to max_d if patterns_found >= max_patterns or d_idx >= low_size break d_price = array.get(pivots_low, d_idx) d_bar = array.get(pivots_low_bar, d_idx) max_c = math.min(high_size - 1, 6) for c_idx = 0 to max_c if patterns_found >= max_patterns or c_idx >= high_size break c_price = array.get(pivots_high, c_idx) c_bar = array.get(pivots_high_bar, c_idx) if c_bar < d_bar and c_bar > d_bar - 30 max_b = math.min(low_size - 1, d_idx + 8) for b_idx = d_idx + 1 to max_b if patterns_found >= max_patterns or b_idx >= low_size break b_price = array.get(pivots_low, b_idx) b_bar = array.get(pivots_low_bar, b_idx) if b_bar < c_bar and b_price < c_price max_a = math.min(high_size - 1, c_idx + 6) for a_idx = c_idx + 1 to max_a if patterns_found >= max_patterns or a_idx >= high_size break a_price = array.get(pivots_high, a_idx) a_bar = array.get(pivots_high_bar, a_idx) if a_bar < b_bar and a_price > b_price // Check for bullish ABCD pattern (A-B-C-D) if show_abcd and patterns_found < max_patterns abcd_pattern = detect_abcd_only(a_price, b_price, c_price, d_price) if abcd_pattern == "ABCD" pattern = PatternData.new() pattern.x := na pattern.a := a_price pattern.b := b_price pattern.c := c_price pattern.d := d_price pattern.x_bar := na pattern.a_bar := a_bar pattern.b_bar := b_bar pattern.c_bar := c_bar pattern.d_bar := d_bar pattern.is_bullish := true pattern.pattern_type := "ABCD" array.push(patterns, pattern) patterns_found += 1 // 5-point patterns max_x = math.min(low_size - 1, b_idx + 6) for x_idx = b_idx + 1 to max_x if patterns_found >= max_patterns or x_idx >= low_size break x_price = array.get(pivots_low, x_idx) x_bar = array.get(pivots_low_bar, x_idx) if x_bar < a_bar and x_price < a_price and x_price < b_price if x_bar < a_bar and a_bar < b_bar and b_bar < c_bar and c_bar < d_bar pattern_name = detect_pattern_fast(x_price, a_price, b_price, c_price, d_price) if pattern_name != "" pattern = PatternData.new() pattern.x := x_price pattern.a := a_price pattern.b := b_price pattern.c := c_price pattern.d := d_price pattern.x_bar := x_bar pattern.a_bar := a_bar pattern.b_bar := b_bar pattern.c_bar := c_bar pattern.d_bar := d_bar pattern.is_bullish := true pattern.pattern_type := "5-point" array.push(patterns, pattern) patterns_found += 1 // 5-point bearish patterns (H-L-H-L-H) and bearish ABCD (L-H-L-H) if high_size >= 3 and low_size >= 2 and show_bearish and patterns_found < max_patterns max_d = math.min(high_size - 1, 8) for d_idx = 0 to max_d if patterns_found >= max_patterns or d_idx >= high_size break d_price = array.get(pivots_high, d_idx) d_bar = array.get(pivots_high_bar, d_idx) max_c = math.min(low_size - 1, 6) for c_idx = 0 to max_c if patterns_found >= max_patterns or c_idx >= low_size break c_price = array.get(pivots_low, c_idx) c_bar = array.get(pivots_low_bar, c_idx) if c_bar < d_bar and c_bar > d_bar - 30 max_b = math.min(high_size - 1, d_idx + 8) for b_idx = d_idx + 1 to max_b if patterns_found >= max_patterns or b_idx >= high_size break b_price = array.get(pivots_high, b_idx) b_bar = array.get(pivots_high_bar, b_idx) if b_bar < c_bar and b_price > c_price max_a = math.min(low_size - 1, c_idx + 6) for a_idx = c_idx + 1 to max_a if patterns_found >= max_patterns or a_idx >= low_size break a_price = array.get(pivots_low, a_idx) a_bar = array.get(pivots_low_bar, a_idx) if a_bar < b_bar and a_price < b_price // Check for bearish ABCD pattern (A-B-C-D) if show_abcd and patterns_found < max_patterns abcd_pattern = detect_abcd_only(a_price, b_price, c_price, d_price) if abcd_pattern == "ABCD" pattern = PatternData.new() pattern.x := na pattern.a := a_price pattern.b := b_price pattern.c := c_price pattern.d := d_price pattern.x_bar := na pattern.a_bar := a_bar pattern.b_bar := b_bar pattern.c_bar := c_bar pattern.d_bar := d_bar pattern.is_bullish := false pattern.pattern_type := "ABCD" array.push(patterns, pattern) patterns_found += 1 // 5-point patterns max_x = math.min(high_size - 1, b_idx + 6) for x_idx = b_idx + 1 to max_x if patterns_found >= max_patterns or x_idx >= high_size break x_price = array.get(pivots_high, x_idx) x_bar = array.get(pivots_high_bar, x_idx) if x_bar < a_bar and x_price > a_price and x_price > b_price if x_bar < a_bar and a_bar < b_bar and b_bar < c_bar and c_bar < d_bar pattern_name = detect_pattern_fast(x_price, a_price, b_price, c_price, d_price) if pattern_name != "" pattern = PatternData.new() pattern.x := x_price pattern.a := a_price pattern.b := b_price pattern.c := c_price pattern.d := d_price pattern.x_bar := x_bar pattern.a_bar := a_bar pattern.b_bar := b_bar pattern.c_bar := c_bar pattern.d_bar := d_bar pattern.is_bullish := false pattern.pattern_type := "5-point" array.push(patterns, pattern) patterns_found += 1 patterns // Optimized drawing function draw_pattern_fast(pattern_data, pattern_name, is_bullish, draw_fib) => pattern_color = pattern_name == "ABCD" ? abcd_color : (is_bullish ? bullish_color : bearish_color) transparency = 20 if show_lines if pattern_data.pattern_type == "ABCD" // ABCD pattern lines (4 points) line_ab = line.new(pattern_data.a_bar, pattern_data.a, pattern_data.b_bar, pattern_data.b, color=color.new(pattern_color, transparency), width=2) line_bc = line.new(pattern_data.b_bar, pattern_data.b, pattern_data.c_bar, pattern_data.c, color=color.new(pattern_color, transparency), width=2) line_cd = line.new(pattern_data.c_bar, pattern_data.c, pattern_data.d_bar, pattern_data.d, color=color.new(pattern_color, transparency), width=2) array.push(lines, line_ab) array.push(lines, line_bc) array.push(lines, line_cd) // Helper lines for ABCD line_ac = line.new(pattern_data.a_bar, pattern_data.a, pattern_data.c_bar, pattern_data.c, color=color.new(pattern_color, 70), width=1, style=line.style_dashed) line_bd = line.new(pattern_data.b_bar, pattern_data.b, pattern_data.d_bar, pattern_data.d, color=color.new(pattern_color, 70), width=1, style=line.style_dashed) array.push(lines, line_ac) array.push(lines, line_bd) array.push(linefills, linefill.new(line_ab, line_ac, color.new(abcd_color, 70))) array.push(linefills, linefill.new(line_bc, line_bd, color.new(abcd_color, 70))) else line_xa = line.new(pattern_data.x_bar, pattern_data.x, pattern_data.a_bar, pattern_data.a, color=color.new(pattern_color, transparency), width=2) line_ab = line.new(pattern_data.a_bar, pattern_data.a, pattern_data.b_bar, pattern_data.b, color=color.new(pattern_color, transparency), width=2) line_xb = line.new(pattern_data.x_bar, pattern_data.x, pattern_data.b_bar, pattern_data.b, color=color(na), width=2) line_bc = line.new(pattern_data.b_bar, pattern_data.b, pattern_data.c_bar, pattern_data.c, color=color.new(pattern_color, transparency), width=2) line_cd = line.new(pattern_data.c_bar, pattern_data.c, pattern_data.d_bar, pattern_data.d, color=color.new(pattern_color, transparency), width=2) line_bd = line.new(pattern_data.b_bar, pattern_data.b, pattern_data.d_bar, pattern_data.d, color=color(na), width=2) // 5-point pattern lines array.push(lines, line_xa) array.push(lines, line_ab) array.push(lines, line_bc) array.push(lines, line_cd) array.push(linefills, linefill.new(line_xa, line_xb, is_bullish ? color.new(bullish_color, 70) : color.new(bearish_color, 70))) array.push(linefills, linefill.new(line_bc, line_bd, is_bullish ? color.new(bullish_color, 70) : color.new(bearish_color, 70))) // Essential helper lines only array.push(lines, line.new(pattern_data.x_bar, pattern_data.x, pattern_data.b_bar, pattern_data.b, color=color.new(pattern_color, 70), width=1, style=line.style_dashed)) array.push(lines, line.new(pattern_data.a_bar, pattern_data.a, pattern_data.c_bar, pattern_data.c, color=color.new(pattern_color, 70), width=1, style=line.style_dashed)) if show_labels // Calculate label_y for all cases if pattern_data.pattern_type == "ABCD" // ABCD point labels array.push(labels, label.new(pattern_data.a_bar, pattern_data.a, "A", color=color(na), textcolor=pattern_color, size=size.small, yloc = is_bullish ? yloc.abovebar : yloc.belowbar)) array.push(labels, label.new(pattern_data.b_bar, pattern_data.b, "B", color=color(na), textcolor=pattern_color, size=size.small, yloc = is_bullish ? yloc.belowbar : yloc.abovebar)) array.push(labels, label.new(pattern_data.c_bar, pattern_data.c, "C", color=color(na), textcolor=pattern_color, size=size.small, yloc = is_bullish ? yloc.abovebar : yloc.belowbar)) array.push(labels, label.new(pattern_data.d_bar, pattern_data.d, "D", color=color(na), textcolor=pattern_color, size=size.small, yloc = is_bullish ? yloc.belowbar : yloc.abovebar)) // ABCD pattern label position label_y_abcd = is_bullish ? math.min(pattern_data.a, pattern_data.b, pattern_data.c, pattern_data.d) * 0.997 : math.max(pattern_data.a, pattern_data.b, pattern_data.c, pattern_data.d) * 1.003 array.push(labels, label.new(pattern_data.d_bar, label_y_abcd, pattern_name, color=is_bullish ? bullish_color : bearish_color, textcolor=color.white, size=size.normal, style=is_bullish ? label.style_label_up : label.style_label_down)) else // 5-point pattern labels array.push(labels, label.new(pattern_data.x_bar, pattern_data.x, "X", color=color(na), textcolor=pattern_color, size=size.small, yloc = is_bullish ? yloc.belowbar : yloc.abovebar)) array.push(labels, label.new(pattern_data.a_bar, pattern_data.a, "A", color=color(na), textcolor=pattern_color, size=size.small, yloc = is_bullish ? yloc.abovebar : yloc.belowbar)) array.push(labels, label.new(pattern_data.b_bar, pattern_data.b, "B", color=color(na), textcolor=pattern_color, size=size.small, yloc = is_bullish ? yloc.belowbar : yloc.abovebar)) array.push(labels, label.new(pattern_data.c_bar, pattern_data.c, "C", color=color(na), textcolor=pattern_color, size=size.small, yloc = is_bullish ? yloc.abovebar : yloc.belowbar)) array.push(labels, label.new(pattern_data.d_bar, pattern_data.d, "D", color=color(na), textcolor=pattern_color, size=size.small, yloc = is_bullish ? yloc.belowbar : yloc.abovebar)) // 5-point pattern label position label_y_5point = is_bullish ? math.min(pattern_data.x, pattern_data.a, pattern_data.b, pattern_data.c, pattern_data.d) * 0.997 : math.max(pattern_data.x, pattern_data.a, pattern_data.b, pattern_data.c, pattern_data.d) * 1.003 array.push(labels, label.new(pattern_data.d_bar, label_y_5point, pattern_name, color=is_bullish ? bullish_color : bearish_color, textcolor=color.white, size=size.normal, style=is_bullish ? label.style_label_up : label.style_label_down)) if show_fib and draw_fib if not(pattern_data.pattern_type == "ABCD") and not na(pattern_data.c) and not na(pattern_data.d) rang = math.abs(pattern_data.d - pattern_data.c) fibLevels = array.from(0, 0.236, 0.382, 0.5, 0.618, 0.786, 1) base = is_bullish ? pattern_data.d : pattern_data.c for i = 0 to array.size(fibLevels) - 1 lvl = array.get(fibLevels, i) yValue = base + rang * lvl array.push(lines, line.new(yValue == pattern_data.c ? pattern_data.c_bar : pattern_data.d_bar, yValue, bar_index, yValue, xloc=xloc.bar_index, extend=extend.none, color=fib_color, style=line.style_dashed, width=1)) array.push(labels, label.new(bar_index, yValue, text = str.tostring(lvl, "#.###") + " (" + str.tostring(yValue, "#.##") + ")", style = label.style_label_left, textcolor=fib_color, color=color(na))) // Clear old drawings clear_drawings() => if array.size(labels) > 0 for i = 0 to array.size(labels) - 1 label.delete(array.get(labels, i)) if array.size(lines) > 0 for i = 0 to array.size(lines) - 1 line.delete(array.get(lines, i)) if array.size(linefills) > 0 for i = 0 to array.size(linefills) - 1 linefill.delete(array.get(linefills, i)) array.clear(labels) array.clear(lines) array.clear(linefills) // Main execution with reduced frequency var int last_scan_bar = 0 var int found_patterns = 0 if barstate.islast or (bar_index - last_scan_bar >= scan_frequency and barstate.isconfirmed) last_scan_bar := bar_index clear_drawings() patterns = find_patterns_optimized() found_patterns := array.size(patterns) if found_patterns > 0 for i = 0 to math.min(found_patterns - 1, max_patterns - 1) pattern_data = array.get(patterns, i) pattern_name = pattern_data.pattern_type == "ABCD" ? "ABCD" : detect_pattern_fast(pattern_data.x, pattern_data.a, pattern_data.b, pattern_data.c, pattern_data.d) draw_pattern_fast(pattern_data, pattern_name, pattern_data.is_bullish, i == 0) // Information table var table info_table = table.new(position.top_right, 2, 4, bgcolor=color.white, border_width=1) if show_table and barstate.islast table.cell(info_table, 0, 0, "Tolerance", text_color=color.black, text_size=size.small, bgcolor=color.silver) table.cell(info_table, 1, 0, str.tostring(tolerance) + "%", text_color=color.black, text_size=size.small) table.cell(info_table, 0, 1, "High Pivots", text_color=color.black, text_size=size.small, bgcolor=color.silver) table.cell(info_table, 1, 1, str.tostring(array.size(pivots_high)), text_color=color.black, text_size=size.small) table.cell(info_table, 0, 2, "Low Pivots", text_color=color.black, text_size=size.small, bgcolor=color.silver) table.cell(info_table, 1, 2, str.tostring(array.size(pivots_low)), text_color=color.black, text_size=size.small) table.cell(info_table, 0, 3, "Patterns", text_color=color.black, text_size=size.small, bgcolor=color.silver) table.cell(info_table, 1, 3, str.tostring(found_patterns), text_color=color.black, text_size=size.small)
Kopyala