Files
QuanTAlib/lib/trends_IIR/pma/pma.pine
T
Miha Kralj 3dd05f23e4 Refactor indicators to include "Ehlers" in names and descriptions for clarity
- Updated the name and description of the Hilbert Trendline (HTIT) to "Ehlers Hilbert Transform Instantaneous Trend (HTIT)".
- Changed the name and description of the MESA Adaptive Moving Average (MAMA) to "Ehlers MESA Adaptive Moving Average".
- Modified the Center of Gravity (CG) indicator to "Ehlers Center of Gravity (CG)".
- Renamed the Detrended Synthetic Price (DSP) to "Ehlers Detrended Synthetic Price (DSP)".
- Updated the Autocorrelation Periodogram (EACP) to "Ehlers Autocorrelation Periodogram (EACP)".
- Changed the Homodyne Discriminator (HOMOD) to "Ehlers Homodyne Discriminator (HOMOD)".
- Updated the Hilbert Transform Dominant Cycle Period and Phase indicators to include "Ehlers" in their names.
- Renamed the Hilbert Transform Phasor Components to "Ehlers Hilbert Transform Phasor Components (HT_PHASOR)".
- Updated the SineWave indicator to "Ehlers Hilbert Transform SineWave (HT_SINE)".
- Changed the Phasor Analysis indicator to "Ehlers Hilbert Transform Phasor Components (HT_PHASOR)".
- Updated the SSF-Based Detrended Synthetic Price to "Ehlers SSF Detrended Synthetic Price (SSFDSP)".
- Renamed the Ultimate Channel to "Ehlers Ultimate Channel (UCHANNEL)".
- Added new indicators: Moving Average Variable Period (MAVP), Ehlers Predictive Moving Average (PMA), Ehlers Reverse EMA (REVERSEEMA), and Ehlers Trendflex Indicator (TRENDFLEX).
- Updated various SVG badges to reflect changes in classes, comments, source files, lines of code, methods, and public types.
2026-02-18 19:08:15 -08:00

92 lines
3.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// The MIT License (MIT)
// © mihakralj
//@version=6
// Indicator algorithm (C) 2004-2024 John F. Ehlers
indicator("Ehlers Predictive Moving Average (PMA)", "PMA", overlay=true)
//@function Calculates Ehlers Predictive Moving Average using WMA-based linear extrapolation
//@param source Series to calculate PMA from
//@param period Lookback period for WMA smoothing (>= 1, default 7 per Ehlers)
//@returns [pma, trigger] where PMA = 2×WMA WMA(WMA) and Trigger = (4×WMA WMA(WMA)) / 3
//@optimized Uses dual running sums with cached denominator for O(1) WMA complexity per bar
pma(series float source, simple int period) =>
if period <= 0
runtime.error("Period must be greater than 0")
// --- First WMA: WMA(source, period) --- matches canonical wma.pine pattern
var array<float> buffer1 = array.new_float(period, na)
var int head1 = 0
var float sum1 = 0.0
var float weighted_sum1 = 0.0
var int count1 = 0
var float norm1 = 0.0
float oldest1 = array.get(buffer1, head1)
float current1 = nz(source)
if not na(oldest1)
float old_sum1 = sum1
sum1 -= oldest1
sum1 += current1
weighted_sum1 := weighted_sum1 - old_sum1 + (period * current1)
else
count1 += 1
sum1 += current1
weighted_sum1 := weighted_sum1 + (count1 * current1)
norm1 := count1 * (count1 + 1) * 0.5
array.set(buffer1, head1, current1)
head1 := (head1 + 1) % period
float wma1 = weighted_sum1 / norm1
// --- Second WMA: WMA(WMA1, period) --- same O(1) circular buffer on first WMA output
var array<float> buffer2 = array.new_float(period, na)
var int head2 = 0
var float sum2 = 0.0
var float weighted_sum2 = 0.0
var int count2 = 0
var float norm2 = 0.0
float oldest2 = array.get(buffer2, head2)
float current2 = nz(wma1)
if not na(oldest2)
float old_sum2 = sum2
sum2 -= oldest2
sum2 += current2
weighted_sum2 := weighted_sum2 - old_sum2 + (period * current2)
else
count2 += 1
sum2 += current2
weighted_sum2 := weighted_sum2 + (count2 * current2)
norm2 := count2 * (count2 + 1) * 0.5
array.set(buffer2, head2, current2)
head2 := (head2 + 1) % period
float wma2 = weighted_sum2 / norm2
// Predictive line: cancels one WMA lag via linear extrapolation
// PMA = 2 × WMA(src) WMA(WMA(src))
float pma_val = 2.0 * wma1 - wma2
// Trigger/signal line: weighted blend for crossover signals
// Trigger = (4 × WMA(src) WMA(WMA(src))) / 3
float trigger_val = (4.0 * wma1 - wma2) / 3.0
[na(source) ? na : pma_val, na(source) ? na : trigger_val]
// ---------- Main loop ----------
// Inputs
i_period = input.int(7, "Period", minval=1, tooltip="Lookback period for WMA smoothing (Ehlers default: 7)")
i_source = input.source(close, "Source")
// Calculation
[pma_value, trigger_value] = pma(i_source, i_period)
// Plot
plot(pma_value, "PMA", color=color.yellow, linewidth=2)
plot(trigger_value, "Trigger", color=color.orange, linewidth=1)