Add all project files
This commit is contained in:
684
auto_trendlines.pine
Normal file
684
auto_trendlines.pine
Normal file
@@ -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<float> high_prices = array.new<float>()
|
||||
var array<int> high_bars = array.new<int>()
|
||||
var array<int> high_times = array.new<int>()
|
||||
var array<float> low_prices = array.new<float>()
|
||||
var array<int> low_bars = array.new<int>()
|
||||
var array<int> low_times = array.new<int>()
|
||||
|
||||
// Arrays to store close-based pivot points
|
||||
var array<float> high_close_prices = array.new<float>()
|
||||
var array<int> high_close_bars = array.new<int>()
|
||||
var array<float> low_close_prices = array.new<float>()
|
||||
var array<int> low_close_bars = array.new<int>()
|
||||
|
||||
// Arrays to store volume data for pivots
|
||||
var array<float> high_volumes = array.new<float>()
|
||||
var array<float> low_volumes = array.new<float>()
|
||||
var array<float> high_close_volumes = array.new<float>()
|
||||
var array<float> low_close_volumes = array.new<float>()
|
||||
|
||||
// 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<line> wick_resistance_lines = array.new<line>()
|
||||
var array<line> wick_support_lines = array.new<line>()
|
||||
var array<line> close_resistance_lines = array.new<line>()
|
||||
var array<line> close_support_lines = array.new<line>()
|
||||
|
||||
// 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<TrendLineData> wick_resistance_candidates = array.new<TrendLineData>()
|
||||
var array<TrendLineData> wick_support_candidates = array.new<TrendLineData>()
|
||||
var array<TrendLineData> close_resistance_candidates = array.new<TrendLineData>()
|
||||
var array<TrendLineData> close_support_candidates = array.new<TrendLineData>()
|
||||
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<TrendLineData>()
|
||||
|
||||
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<TrendLineData>()
|
||||
|
||||
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<TrendLineData>()
|
||||
|
||||
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<TrendLineData>()
|
||||
|
||||
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")
|
||||
Reference in New Issue
Block a user