mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-31 10:57:43 +00:00
86fe32a682
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>
57 lines
2.5 KiB
Plaintext
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))
|