From bbdaee1d1a89bf765a86f6cc2bd25929cbb1c95b Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 2 Aug 2025 01:54:08 +0000 Subject: [PATCH] Add all project files --- auto_trendlines.pine | 684 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 684 insertions(+) create mode 100644 auto_trendlines.pine diff --git a/auto_trendlines.pine b/auto_trendlines.pine new file mode 100644 index 0000000..d9f9feb --- /dev/null +++ b/auto_trendlines.pine @@ -0,0 +1,684 @@ +//@version=5 +indicator("Auto Trend Lines - Long Period", overlay=true, max_lines_count=500) + +// Input parameters +lookback_period = input.int(50, "Lookback Period for Pivot Detection", minval=10, maxval=200) +min_touches = input.int(2, "Minimum Touches for Valid Trend Line", minval=2, maxval=5) +max_lines = input.int(20, "Maximum Number of Trend Lines", minval=5, maxval=50) +max_bars_back = input.int(500, "Maximum Bars Back for Lines", minval=100, maxval=2000) +merge_similar_lines = input.bool(true, "Merge Similar Lines") +slope_tolerance = input.float(0.1, "Slope Tolerance for Merging (%)", minval=0.01, maxval=1.0) +price_tolerance = input.float(0.5, "Price Tolerance for Merging (%)", minval=0.1, maxval=2.0) +line_extend = input.string("right", "Line Extension", options=["none", "left", "right", "both"]) +show_support = input.bool(true, "Show Support Lines") +show_resistance = input.bool(true, "Show Resistance Lines") + +// Enhanced K-line features +show_close_based_lines = input.bool(true, "Show Close-Based Trend Lines (Thick)") +show_wick_based_lines = input.bool(true, "Show Wick-Based Trend Lines (Thin)") +show_current_hl = input.bool(true, "Show Current Bar High/Low Points") + +// Volume filtering +use_volume_filter = input.bool(true, "Enable Volume Filtering") +volume_threshold_multiplier = input.float(1.5, "Volume Threshold Multiplier", minval=0.5, maxval=5.0) +volume_lookback = input.int(20, "Volume Average Lookback", minval=5, maxval=100) + +// Line styling +support_color = input.color(color.green, "Support Line Color") +resistance_color = input.color(color.red, "Resistance Line Color") +close_support_color = input.color(color.lime, "Close-Based Support Color") +close_resistance_color = input.color(color.maroon, "Close-Based Resistance Color") +thin_line_width = input.int(2, "Thin Line Width (Wick-Based)", minval=1, maxval=5) +thick_line_width = input.int(5, "Thick Line Width (Close-Based)", minval=3, maxval=15) +line_style = input.string("solid", "Line Style", options=["solid", "dashed", "dotted"]) +current_hl_color = input.color(color.yellow, "Current High/Low Point Color") + +// Convert line style +get_line_style() => + switch line_style + "solid" => line.style_solid + "dashed" => line.style_dashed + "dotted" => line.style_dotted + => line.style_solid + +// Pivot detection +pivot_high = ta.pivothigh(high, lookback_period, lookback_period) +pivot_low = ta.pivotlow(low, lookback_period, lookback_period) + +// Arrays to store pivot points with time +var array high_prices = array.new() +var array high_bars = array.new() +var array high_times = array.new() +var array low_prices = array.new() +var array low_bars = array.new() +var array low_times = array.new() + +// Arrays to store close-based pivot points +var array high_close_prices = array.new() +var array high_close_bars = array.new() +var array low_close_prices = array.new() +var array low_close_bars = array.new() + +// Arrays to store volume data for pivots +var array high_volumes = array.new() +var array low_volumes = array.new() +var array high_close_volumes = array.new() +var array low_close_volumes = array.new() + +// Calculate volume average for filtering +volume_avg = ta.sma(volume, volume_lookback) + +// Store pivot points (high/low based) with volume data +if not na(pivot_high) + pivot_bar = bar_index - lookback_period + pivot_time = math.round(time[lookback_period]) + pivot_volume = volume[lookback_period] + // Only store if within reasonable distance + if bar_index - pivot_bar <= max_bars_back + array.push(high_prices, pivot_high) + array.push(high_bars, pivot_bar) + array.push(high_times, pivot_time) + array.push(high_volumes, pivot_volume) + // Keep only recent pivots to manage memory + if array.size(high_prices) > 50 + array.shift(high_prices) + array.shift(high_bars) + array.shift(high_times) + array.shift(high_volumes) + +if not na(pivot_low) + pivot_bar = bar_index - lookback_period + pivot_time = math.round(time[lookback_period]) + pivot_volume = volume[lookback_period] + // Only store if within reasonable distance + if bar_index - pivot_bar <= max_bars_back + array.push(low_prices, pivot_low) + array.push(low_bars, pivot_bar) + array.push(low_times, pivot_time) + array.push(low_volumes, pivot_volume) + // Keep only recent pivots to manage memory + if array.size(low_prices) > 50 + array.shift(low_prices) + array.shift(low_bars) + array.shift(low_times) + array.shift(low_volumes) + +// Store close-based pivot points (always calculate for close-based trend lines) with volume data +pivot_high_close = ta.pivothigh(close, lookback_period, lookback_period) +pivot_low_close = ta.pivotlow(close, lookback_period, lookback_period) + +if not na(pivot_high_close) + pivot_bar = bar_index - lookback_period + pivot_volume = volume[lookback_period] + if bar_index - pivot_bar <= max_bars_back + array.push(high_close_prices, pivot_high_close) + array.push(high_close_bars, pivot_bar) + array.push(high_close_volumes, pivot_volume) + if array.size(high_close_prices) > 50 + array.shift(high_close_prices) + array.shift(high_close_bars) + array.shift(high_close_volumes) + +if not na(pivot_low_close) + pivot_bar = bar_index - lookback_period + pivot_volume = volume[lookback_period] + if bar_index - pivot_bar <= max_bars_back + array.push(low_close_prices, pivot_low_close) + array.push(low_close_bars, pivot_bar) + array.push(low_close_volumes, pivot_volume) + if array.size(low_close_prices) > 50 + array.shift(low_close_prices) + array.shift(low_close_bars) + array.shift(low_close_volumes) + +// Function to calculate line slope and y-intercept +get_line_params(x1, y1, x2, y2) => + slope = (y2 - y1) / (x2 - x1) + intercept = y1 - slope * x1 + [slope, intercept] + +// Function to get y value at given x using line equation +get_y_at_x(slope, intercept, x) => + slope * x + intercept + +// Structure to store trend line data +type TrendLineData + float slope + float intercept + int bar1 + float price1 + int bar2 + float price2 + int touches + bool is_resistance + +// Function to check if two lines are similar and should be merged +lines_are_similar(line1, line2, slope_tol, price_tol) => + // Check slope similarity + slope_diff = math.abs(line1.slope - line2.slope) + avg_slope = (math.abs(line1.slope) + math.abs(line2.slope)) / 2 + slope_similar = avg_slope == 0 ? slope_diff < 0.001 : (slope_diff / avg_slope) < (slope_tol / 100) + + // Check price level similarity at a common point + mid_bar = math.round((line1.bar1 + line1.bar2 + line2.bar1 + line2.bar2) / 4) + price1_at_mid = get_y_at_x(line1.slope, line1.intercept, mid_bar) + price2_at_mid = get_y_at_x(line2.slope, line2.intercept, mid_bar) + price_diff = math.abs(price1_at_mid - price2_at_mid) + avg_price = (price1_at_mid + price2_at_mid) / 2 + price_similar = (price_diff / avg_price) < (price_tol / 100) + + slope_similar and price_similar + +// Function to merge two similar trend lines +merge_lines(line1, line2) => + // Choose the line with more touches, or the longer one + if line1.touches > line2.touches + line1 + else if line2.touches > line1.touches + line2 + else + // If same touches, choose the longer line + length1 = math.abs(line1.bar2 - line1.bar1) + length2 = math.abs(line2.bar2 - line2.bar1) + length1 >= length2 ? line1 : line2 + +// Function to check if pivot has sufficient volume +has_sufficient_volume(pivot_volume, avg_volume) => + not use_volume_filter or pivot_volume >= (avg_volume * volume_threshold_multiplier) + +// Function to count touches for wick-based trend lines with volume filtering +count_wick_touches(slope, intercept, start_bar, end_bar, is_resistance, tolerance_pct = 0.5) => + touches = 0 + current_bar = bar_index + pivot_prices = is_resistance ? high_prices : low_prices + pivot_bars_array = is_resistance ? high_bars : low_bars + pivot_volumes_array = is_resistance ? high_volumes : low_volumes + + if array.size(pivot_prices) > 0 + for i = 0 to array.size(pivot_prices) - 1 + bar_idx = array.get(pivot_bars_array, i) + price = array.get(pivot_prices, i) + pivot_volume = array.get(pivot_volumes_array, i) + + if bar_idx >= start_bar and bar_idx <= end_bar and (current_bar - bar_idx) <= max_bars_back + // Check volume filter + if has_sufficient_volume(pivot_volume, volume_avg) + expected_price = get_y_at_x(slope, intercept, bar_idx) + tolerance = expected_price * tolerance_pct / 100 + + if is_resistance + if math.abs(price - expected_price) <= tolerance and price >= expected_price - tolerance + touches += 1 + else + if math.abs(price - expected_price) <= tolerance and price <= expected_price + tolerance + touches += 1 + touches + +// Function to count touches for close-based trend lines with volume filtering +count_close_touches(slope, intercept, start_bar, end_bar, is_resistance, tolerance_pct = 0.5) => + touches = 0 + current_bar = bar_index + close_prices = is_resistance ? high_close_prices : low_close_prices + close_bars_array = is_resistance ? high_close_bars : low_close_bars + close_volumes_array = is_resistance ? high_close_volumes : low_close_volumes + + if array.size(close_prices) > 0 + for i = 0 to array.size(close_prices) - 1 + bar_idx = array.get(close_bars_array, i) + price = array.get(close_prices, i) + pivot_volume = array.get(close_volumes_array, i) + + if bar_idx >= start_bar and bar_idx <= end_bar and (current_bar - bar_idx) <= max_bars_back + // Check volume filter + if has_sufficient_volume(pivot_volume, volume_avg) + expected_price = get_y_at_x(slope, intercept, bar_idx) + tolerance = expected_price * tolerance_pct / 100 + + if is_resistance + if math.abs(price - expected_price) <= tolerance and price >= expected_price - tolerance + touches += 1 + else + if math.abs(price - expected_price) <= tolerance and price <= expected_price + tolerance + touches += 1 + touches + +// Function to draw trend lines +draw_trend_lines() => + var array wick_resistance_lines = array.new() + var array wick_support_lines = array.new() + var array close_resistance_lines = array.new() + var array close_support_lines = array.new() + + // Clear old lines + for line_obj in wick_resistance_lines + line.delete(line_obj) + for line_obj in wick_support_lines + line.delete(line_obj) + for line_obj in close_resistance_lines + line.delete(line_obj) + for line_obj in close_support_lines + line.delete(line_obj) + array.clear(wick_resistance_lines) + array.clear(wick_support_lines) + array.clear(close_resistance_lines) + array.clear(close_support_lines) + + current_bar = bar_index + + // Arrays to store trend line candidates + var array wick_resistance_candidates = array.new() + var array wick_support_candidates = array.new() + var array close_resistance_candidates = array.new() + var array close_support_candidates = array.new() + array.clear(wick_resistance_candidates) + array.clear(wick_support_candidates) + array.clear(close_resistance_candidates) + array.clear(close_support_candidates) + + // Collect WICK-based resistance line candidates (thin lines) + if show_wick_based_lines and show_resistance and array.size(high_prices) >= 2 + for i = 0 to array.size(high_prices) - 2 + for j = i + 1 to array.size(high_prices) - 1 + bar1 = array.get(high_bars, i) + price1 = array.get(high_prices, i) + volume1 = array.get(high_volumes, i) + bar2 = array.get(high_bars, j) + price2 = array.get(high_prices, j) + volume2 = array.get(high_volumes, j) + + if bar2 - bar1 < lookback_period or (current_bar - bar1) > max_bars_back or (current_bar - bar2) > max_bars_back + continue + + // Apply volume filter to both pivot points + if use_volume_filter and (not has_sufficient_volume(volume1, volume_avg) or not has_sufficient_volume(volume2, volume_avg)) + continue + + [slope, intercept] = get_line_params(bar1, price1, bar2, price2) + touches = count_wick_touches(slope, intercept, bar1, current_bar, true) + + if touches >= min_touches + trend_line = TrendLineData.new(slope, intercept, bar1, price1, bar2, price2, touches, true) + array.push(wick_resistance_candidates, trend_line) + + // Collect CLOSE-based resistance line candidates (thick lines) + if show_close_based_lines and show_resistance and array.size(high_close_prices) >= 2 + for i = 0 to array.size(high_close_prices) - 2 + for j = i + 1 to array.size(high_close_prices) - 1 + bar1 = array.get(high_close_bars, i) + price1 = array.get(high_close_prices, i) + volume1 = array.get(high_close_volumes, i) + bar2 = array.get(high_close_bars, j) + price2 = array.get(high_close_prices, j) + volume2 = array.get(high_close_volumes, j) + + if bar2 - bar1 < lookback_period or (current_bar - bar1) > max_bars_back or (current_bar - bar2) > max_bars_back + continue + + // Apply volume filter to both pivot points + if use_volume_filter and (not has_sufficient_volume(volume1, volume_avg) or not has_sufficient_volume(volume2, volume_avg)) + continue + + [slope, intercept] = get_line_params(bar1, price1, bar2, price2) + touches = count_close_touches(slope, intercept, bar1, current_bar, true) + + if touches >= min_touches + trend_line = TrendLineData.new(slope, intercept, bar1, price1, bar2, price2, touches, true) + array.push(close_resistance_candidates, trend_line) + + // Collect WICK-based support line candidates (thin lines) + if show_wick_based_lines and show_support and array.size(low_prices) >= 2 + for i = 0 to array.size(low_prices) - 2 + for j = i + 1 to array.size(low_prices) - 1 + bar1 = array.get(low_bars, i) + price1 = array.get(low_prices, i) + volume1 = array.get(low_volumes, i) + bar2 = array.get(low_bars, j) + price2 = array.get(low_prices, j) + volume2 = array.get(low_volumes, j) + + if bar2 - bar1 < lookback_period or (current_bar - bar1) > max_bars_back or (current_bar - bar2) > max_bars_back + continue + + // Apply volume filter to both pivot points + if use_volume_filter and (not has_sufficient_volume(volume1, volume_avg) or not has_sufficient_volume(volume2, volume_avg)) + continue + + [slope, intercept] = get_line_params(bar1, price1, bar2, price2) + touches = count_wick_touches(slope, intercept, bar1, current_bar, false) + + if touches >= min_touches + trend_line = TrendLineData.new(slope, intercept, bar1, price1, bar2, price2, touches, false) + array.push(wick_support_candidates, trend_line) + + // Collect CLOSE-based support line candidates (thick lines) + if show_close_based_lines and show_support and array.size(low_close_prices) >= 2 + for i = 0 to array.size(low_close_prices) - 2 + for j = i + 1 to array.size(low_close_prices) - 1 + bar1 = array.get(low_close_bars, i) + price1 = array.get(low_close_prices, i) + volume1 = array.get(low_close_volumes, i) + bar2 = array.get(low_close_bars, j) + price2 = array.get(low_close_prices, j) + volume2 = array.get(low_close_volumes, j) + + if bar2 - bar1 < lookback_period or (current_bar - bar1) > max_bars_back or (current_bar - bar2) > max_bars_back + continue + + // Apply volume filter to both pivot points + if use_volume_filter and (not has_sufficient_volume(volume1, volume_avg) or not has_sufficient_volume(volume2, volume_avg)) + continue + + [slope, intercept] = get_line_params(bar1, price1, bar2, price2) + touches = count_close_touches(slope, intercept, bar1, current_bar, false) + + if touches >= min_touches + trend_line = TrendLineData.new(slope, intercept, bar1, price1, bar2, price2, touches, false) + array.push(close_support_candidates, trend_line) + + // Process and draw lines separately for wick-based and close-based + if merge_similar_lines + // Process WICK-based resistance lines (thin) + if array.size(wick_resistance_candidates) > 0 + merged_wick_resistance = array.new() + + for i = 0 to array.size(wick_resistance_candidates) - 1 + current_line = array.get(wick_resistance_candidates, i) + should_merge = false + + if array.size(merged_wick_resistance) > 0 + for j = 0 to array.size(merged_wick_resistance) - 1 + existing_line = array.get(merged_wick_resistance, j) + if lines_are_similar(current_line, existing_line, slope_tolerance, price_tolerance) + merged_line = merge_lines(current_line, existing_line) + array.set(merged_wick_resistance, j, merged_line) + should_merge := true + break + + if not should_merge + array.push(merged_wick_resistance, current_line) + + // Draw wick-based resistance lines (thin) + lines_drawn = 0 + if array.size(merged_wick_resistance) > 0 + for i = 0 to array.size(merged_wick_resistance) - 1 + if lines_drawn >= max_lines + break + + trend_line = array.get(merged_wick_resistance, i) + extend_type = switch line_extend + "left" => extend.left + "right" => extend.right + "both" => extend.both + => extend.none + + line_obj = line.new(trend_line.bar1, trend_line.price1, trend_line.bar2, trend_line.price2, + color=resistance_color, + width=thin_line_width, + style=get_line_style(), + extend=extend_type) + array.push(wick_resistance_lines, line_obj) + lines_drawn += 1 + + // Process CLOSE-based resistance lines (thick) + if array.size(close_resistance_candidates) > 0 + merged_close_resistance = array.new() + + for i = 0 to array.size(close_resistance_candidates) - 1 + current_line = array.get(close_resistance_candidates, i) + should_merge = false + + if array.size(merged_close_resistance) > 0 + for j = 0 to array.size(merged_close_resistance) - 1 + existing_line = array.get(merged_close_resistance, j) + if lines_are_similar(current_line, existing_line, slope_tolerance, price_tolerance) + merged_line = merge_lines(current_line, existing_line) + array.set(merged_close_resistance, j, merged_line) + should_merge := true + break + + if not should_merge + array.push(merged_close_resistance, current_line) + + // Draw close-based resistance lines (thick) + lines_drawn = 0 + if array.size(merged_close_resistance) > 0 + for i = 0 to array.size(merged_close_resistance) - 1 + if lines_drawn >= max_lines + break + + trend_line = array.get(merged_close_resistance, i) + extend_type = switch line_extend + "left" => extend.left + "right" => extend.right + "both" => extend.both + => extend.none + + line_obj = line.new(trend_line.bar1, trend_line.price1, trend_line.bar2, trend_line.price2, + color=close_resistance_color, + width=thick_line_width, + style=get_line_style(), + extend=extend_type) + array.push(close_resistance_lines, line_obj) + lines_drawn += 1 + + // Process WICK-based support lines (thin) + if array.size(wick_support_candidates) > 0 + merged_wick_support = array.new() + + for i = 0 to array.size(wick_support_candidates) - 1 + current_line = array.get(wick_support_candidates, i) + should_merge = false + + if array.size(merged_wick_support) > 0 + for j = 0 to array.size(merged_wick_support) - 1 + existing_line = array.get(merged_wick_support, j) + if lines_are_similar(current_line, existing_line, slope_tolerance, price_tolerance) + merged_line = merge_lines(current_line, existing_line) + array.set(merged_wick_support, j, merged_line) + should_merge := true + break + + if not should_merge + array.push(merged_wick_support, current_line) + + // Draw wick-based support lines (thin) + lines_drawn = 0 + if array.size(merged_wick_support) > 0 + for i = 0 to array.size(merged_wick_support) - 1 + if lines_drawn >= max_lines + break + + trend_line = array.get(merged_wick_support, i) + extend_type = switch line_extend + "left" => extend.left + "right" => extend.right + "both" => extend.both + => extend.none + + line_obj = line.new(trend_line.bar1, trend_line.price1, trend_line.bar2, trend_line.price2, + color=support_color, + width=thin_line_width, + style=get_line_style(), + extend=extend_type) + array.push(wick_support_lines, line_obj) + lines_drawn += 1 + + // Process CLOSE-based support lines (thick) + if array.size(close_support_candidates) > 0 + merged_close_support = array.new() + + for i = 0 to array.size(close_support_candidates) - 1 + current_line = array.get(close_support_candidates, i) + should_merge = false + + if array.size(merged_close_support) > 0 + for j = 0 to array.size(merged_close_support) - 1 + existing_line = array.get(merged_close_support, j) + if lines_are_similar(current_line, existing_line, slope_tolerance, price_tolerance) + merged_line = merge_lines(current_line, existing_line) + array.set(merged_close_support, j, merged_line) + should_merge := true + break + + if not should_merge + array.push(merged_close_support, current_line) + + // Draw close-based support lines (thick) + lines_drawn = 0 + if array.size(merged_close_support) > 0 + for i = 0 to array.size(merged_close_support) - 1 + if lines_drawn >= max_lines + break + + trend_line = array.get(merged_close_support, i) + extend_type = switch line_extend + "left" => extend.left + "right" => extend.right + "both" => extend.both + => extend.none + + line_obj = line.new(trend_line.bar1, trend_line.price1, trend_line.bar2, trend_line.price2, + color=close_support_color, + width=thick_line_width, + style=get_line_style(), + extend=extend_type) + array.push(close_support_lines, line_obj) + lines_drawn += 1 + else + // Original behavior without merging - draw all valid candidates + // Draw wick-based resistance lines (thin) + lines_drawn = 0 + if array.size(wick_resistance_candidates) > 0 + for i = 0 to array.size(wick_resistance_candidates) - 1 + if lines_drawn >= max_lines + break + trend_line = array.get(wick_resistance_candidates, i) + extend_type = switch line_extend + "left" => extend.left + "right" => extend.right + "both" => extend.both + => extend.none + + line_obj = line.new(trend_line.bar1, trend_line.price1, trend_line.bar2, trend_line.price2, + color=resistance_color, + width=thin_line_width, + style=get_line_style(), + extend=extend_type) + array.push(wick_resistance_lines, line_obj) + lines_drawn += 1 + + // Draw close-based resistance lines (thick) + lines_drawn := 0 + if array.size(close_resistance_candidates) > 0 + for i = 0 to array.size(close_resistance_candidates) - 1 + if lines_drawn >= max_lines + break + trend_line = array.get(close_resistance_candidates, i) + extend_type = switch line_extend + "left" => extend.left + "right" => extend.right + "both" => extend.both + => extend.none + + line_obj = line.new(trend_line.bar1, trend_line.price1, trend_line.bar2, trend_line.price2, + color=close_resistance_color, + width=thick_line_width, + style=get_line_style(), + extend=extend_type) + array.push(close_resistance_lines, line_obj) + lines_drawn += 1 + + // Draw wick-based support lines (thin) + lines_drawn := 0 + if array.size(wick_support_candidates) > 0 + for i = 0 to array.size(wick_support_candidates) - 1 + if lines_drawn >= max_lines + break + trend_line = array.get(wick_support_candidates, i) + extend_type = switch line_extend + "left" => extend.left + "right" => extend.right + "both" => extend.both + => extend.none + + line_obj = line.new(trend_line.bar1, trend_line.price1, trend_line.bar2, trend_line.price2, + color=support_color, + width=thin_line_width, + style=get_line_style(), + extend=extend_type) + array.push(wick_support_lines, line_obj) + lines_drawn += 1 + + // Draw close-based support lines (thick) + lines_drawn := 0 + if array.size(close_support_candidates) > 0 + for i = 0 to array.size(close_support_candidates) - 1 + if lines_drawn >= max_lines + break + trend_line = array.get(close_support_candidates, i) + extend_type = switch line_extend + "left" => extend.left + "right" => extend.right + "both" => extend.both + => extend.none + + line_obj = line.new(trend_line.bar1, trend_line.price1, trend_line.bar2, trend_line.price2, + color=close_support_color, + width=thick_line_width, + style=get_line_style(), + extend=extend_type) + array.push(close_support_lines, line_obj) + lines_drawn += 1 + +// Execute trend line drawing every 10 bars to optimize performance +if bar_index % 10 == 0 + draw_trend_lines() + +// Show current bar high/low points +if show_current_hl + var line current_high_line = na + var line current_low_line = na + + // Delete previous lines + if not na(current_high_line) + line.delete(current_high_line) + if not na(current_low_line) + line.delete(current_low_line) + + // Draw current bar high/low points + current_high_line := line.new(bar_index, high, bar_index, high, color=current_hl_color, width=3, style=line.style_solid) + current_low_line := line.new(bar_index, low, bar_index, low, color=current_hl_color, width=3, style=line.style_solid) + +// Plot pivot points for reference (optional) +plot_pivots = input.bool(false, "Show Pivot Points") +plotshape(plot_pivots and not na(pivot_high), style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small) +plotshape(plot_pivots and not na(pivot_low), style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small) + +// Plot close-based pivot points (moved to global scope) +plotshape(plot_pivots and not na(pivot_high_close), style=shape.diamond, location=location.abovebar, color=color.orange, size=size.small) +plotshape(plot_pivots and not na(pivot_low_close), style=shape.diamond, location=location.belowbar, color=color.blue, size=size.small) + +// Volume filtering visualization +show_volume_info = input.bool(false, "Show Volume Information") +if show_volume_info + // Plot volume threshold line + volume_threshold = volume_avg * volume_threshold_multiplier + + // Create a table to show volume information + var table volume_table = table.new(position.top_right, 2, 4, bgcolor=color.white, border_width=1) + if barstate.islast + table.cell(volume_table, 0, 0, "Volume Info", text_color=color.black, text_size=size.small) + table.cell(volume_table, 1, 0, "", text_color=color.black, text_size=size.small) + table.cell(volume_table, 0, 1, "Avg Volume:", text_color=color.black, text_size=size.small) + table.cell(volume_table, 1, 1, str.tostring(math.round(volume_avg)), text_color=color.black, text_size=size.small) + table.cell(volume_table, 0, 2, "Threshold:", text_color=color.black, text_size=size.small) + table.cell(volume_table, 1, 2, str.tostring(math.round(volume_threshold)), text_color=color.black, text_size=size.small) + table.cell(volume_table, 0, 3, "Current:", text_color=color.black, text_size=size.small) + table.cell(volume_table, 1, 3, str.tostring(math.round(volume)), text_color=volume >= volume_threshold ? color.green : color.red, text_size=size.small) + +// Alert conditions +resistance_break = ta.crossover(close, ta.highest(high, 5)) +support_break = ta.crossunder(close, ta.lowest(low, 5)) + +alertcondition(resistance_break, title="Resistance Break", message="Price broke above resistance level") +alertcondition(support_break, title="Support Break", message="Price broke below support level")