Files
QuanTAlib/quantower/lib/apchannel.pine
T
Miha Kralj 86fe32a682 SIMD Refactor: Merge simd-dev into dev (#55)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: aider (openrouter/anthropic/claude-sonnet-4) <aider@aider.chat>
Co-authored-by: Warp <agent@warp.dev>
2026-01-18 19:02:03 -08:00

57 lines
2.5 KiB
Plaintext

// The MIT License (MIT)
// © mihakralj
//@version=6
indicator("Andrews' Pitchfork (AP)", "AP", overlay=true)
//@function Calculates Andrews' Pitchfork lines based on three pivot points
//@param p1_back Bars back to first pivot point (leftmost)
//@param p2_back Bars back to second pivot point (middle)
//@param p3_back Bars back to third pivot point (rightmost)
//@returns tuple of [median, upper, lower] lines for current bar
//@optimized Geometric projection with O(1) complexity per bar
apchannel(simple int p1_back, simple int p2_back, simple int p3_back) =>
if p1_back <= 0 or p2_back <= 0 or p3_back <= 0 or not (p1_back > p2_back and p2_back > p3_back)
runtime.error("Use P1 oldest, P2 newer, P3 newest — all >0")
[na, na, na]
int p1_b = math.min(p1_back, bar_index)
int p2_b = math.min(p2_back, bar_index)
int p3_b = math.min(p3_back, bar_index)
int p1_time = bar_index - p1_b
int p2_time = bar_index - p2_b
int p3_time = bar_index - p3_b
float p1_price = nz(close[p1_b])
float p2_price = nz(high[p2_b])
float p3_price = nz(low[p3_b])
if na(close[p1_b]) or na(high[p2_b]) or na(low[p3_b])
[float(na), float(na), float(na)]
float mid_time_float = (float(p2_time) + float(p3_time)) / 2.0
float mid_price = (p2_price + p3_price) / 2.0
float time_diff = mid_time_float - float(p1_time)
float median_slope = math.abs(time_diff) > 1e-10 ? (mid_price - p1_price) / time_diff : 0.0
float median_value = p1_price + median_slope * (float(bar_index) - float(p1_time))
float upper_value = p2_price + median_slope * (float(bar_index) - float(p2_time))
float lower_value = p3_price + median_slope * (float(bar_index) - float(p3_time))
if math.abs(median_value) > 1e9 or math.abs(upper_value) > 1e9 or math.abs(lower_value) > 1e9
[float(na), float(na), float(na)]
[median_value, upper_value, lower_value]
// ---------- Main loop ----------
// Inputs
i_p1_back = input.int(45, "Point 1 (Leftmost)", minval=1)
i_p2_back = input.int(30, "Point 2 (Second)", minval=1)
i_p3_back = input.int(15, "Point 3 (Third)", minval=1)
// Validation
if i_p1_back <= i_p2_back or i_p2_back <= i_p3_back
runtime.error("Points must be in chronological order (P1 > P2 > P3)")
// Calculation
[median, upper, lower] = apchannel(i_p1_back, i_p2_back, i_p3_back)
// Plot
plot(median, "Median", color=color.yellow, linewidth=2)
p1 = plot(upper, "Upper", color=color.new(color.blue, 50), linewidth=1)
p2 = plot(lower, "Lower", color=color.new(color.blue, 50), linewidth=1)
fill(p1, p2, color=color.new(color.blue, 90))