feat: add new indicators (Decay, Edecay, MinusDi, MinusDm, PlusDi, PlusDm, Maxindex, Minindex, Sarext) and update pine scripts, core libs, validation tests, and python bindings

This commit is contained in:
Miha Kralj
2026-03-09 13:45:46 -07:00
parent 8e43d62cbb
commit 031f1b5fe6
491 changed files with 6156 additions and 5590 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
// Indicator algorithm (C) 2015 John F. Ehlers
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
// Indicator algorithm (C) 2004 John F. Ehlers
+8 -11
View File
@@ -198,13 +198,14 @@ public sealed class BaxterKing : AbstractBase
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double ComputeFilter()
{
// Apply symmetric FIR: sum of weights[i] * buffer[i]
// Buffer[0] is oldest (K bars ago from center), buffer[2K] is newest
// Apply symmetric FIR: dot product of weights with buffer (oldest to newest)
// The "center" is buffer[K], which represents time t-K (delayed output)
double sum = 0.0;
for (int i = 0; i < _filterLen; i++)
_buffer.GetSequencedSpans(out var first, out var second);
ReadOnlySpan<double> w = _weights;
double sum = w.Slice(0, first.Length).DotProduct(first);
if (!second.IsEmpty)
{
sum += _weights[i] * _buffer[i];
sum += w.Slice(first.Length).DotProduct(second);
}
return sum;
}
@@ -270,6 +271,7 @@ public sealed class BaxterKing : AbstractBase
ComputeWeights(weights, pLow, pHigh, k);
int n = source.Length;
ReadOnlySpan<double> w = weights;
for (int i = 0; i < n; i++)
{
@@ -279,12 +281,7 @@ public sealed class BaxterKing : AbstractBase
}
else
{
double sum = 0.0;
for (int j = 0; j < filterLen; j++)
{
sum += weights[j] * source[i - filterLen + 1 + j];
}
output[i] = sum;
output[i] = w.DotProduct(source.Slice(i - filterLen + 1, filterLen));
}
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Baxter-King Band-Pass Filter (BAXTERKING)", "BAXTERKING", overlay=false)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Bessel 2nd Order Filter (BESSEL)", "BESSEL", overlay=true)
+9 -9
View File
@@ -114,10 +114,10 @@ public sealed class Bilateral : AbstractBase
{
double val = GetValidValue(source[i]);
double removed = _buffer.Add(val);
_state.SumSq += (val * val);
_state.SumSq = Math.FusedMultiplyAdd(val, val, _state.SumSq);
if (_buffer.IsFull)
{
_state.SumSq -= (removed * removed);
_state.SumSq = Math.FusedMultiplyAdd(-removed, removed, _state.SumSq);
}
}
@@ -187,10 +187,10 @@ public sealed class Bilateral : AbstractBase
double val = GetValidValue(input.Value);
double removed = _buffer.Add(val);
_state.SumSq += (val * val);
_state.SumSq = Math.FusedMultiplyAdd(val, val, _state.SumSq);
if (_buffer.IsFull)
{
_state.SumSq -= (removed * removed);
_state.SumSq = Math.FusedMultiplyAdd(-removed, removed, _state.SumSq);
}
}
else
@@ -207,15 +207,15 @@ public sealed class Bilateral : AbstractBase
if (_buffer.Count == 0)
{
_buffer.Add(val);
_state.SumSq += (val * val);
_state.SumSq = Math.FusedMultiplyAdd(val, val, _state.SumSq);
}
else
{
double oldNewest = _buffer.Newest; // Get current newest before overwriting
_buffer.UpdateNewest(val);
_state.SumSq -= (oldNewest * oldNewest);
_state.SumSq += (val * val);
_state.SumSq = Math.FusedMultiplyAdd(-oldNewest, oldNewest, _state.SumSq);
_state.SumSq = Math.FusedMultiplyAdd(val, val, _state.SumSq);
}
}
@@ -421,12 +421,12 @@ public sealed class Bilateral : AbstractBase
{
removed = window[windowIdx];
sum -= removed;
sumSq -= removed * removed;
sumSq = Math.FusedMultiplyAdd(-removed, removed, sumSq);
}
window[windowIdx] = val;
sum += val;
sumSq += val * val;
sumSq = Math.FusedMultiplyAdd(val, val, sumSq);
int currentNewestIdx = windowIdx;
windowIdx = (windowIdx + 1) % period;
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Bilateral Filter (BILATERAL)", "BILATERAL", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Bandpass Filter (BPF)", "BPF", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Ehlers 2-Pole Butterworth Filter (BUTTER2)", "BUTTER2", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
// Indicator algorithm (C) 2004-2024 John F. Ehlers
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Christiano-Fitzgerald Band-Pass Filter (CFITZ)", "CFITZ", overlay=false, max_bars_back=5000)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Chebyshev Type I Filter (CHEBY1)", "CHEBY1", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Chebyshev Type II Filter (CHEBY2)", "CHEBY2", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("EDCF: Ehlers Distance Coefficient Filter", "EDCF", overlay = true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Elliptic 2nd Order Filter (ELLIPTIC)", "ELLIPTIC", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Gaussian Filter (GAUSS)", "GAUSS", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Hann FIR Filter (HANN)", "HANN", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Hodrick-Prescott Filter (HP)", "HP", overlay=false)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Ehlers Highpass Filter (HPF)", "HPF", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Kalman Filter (KALMAN)", "KALMAN", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
// Indicator algorithm (C) 2004 John F. Ehlers
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Least Mean Squares Adaptive Filter (LMS)", "LMS", overlay=true)
+1 -43
View File
@@ -1,4 +1,3 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -309,48 +308,7 @@ public sealed class Loess : AbstractBase
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double DotProduct(ReadOnlySpan<double> a, ReadOnlySpan<double> b)
{
// a and b expected to be same length (slice called in Update ensures this)
int length = a.Length;
if (length == 0)
{
return 0;
}
int i = 0;
double sum = 0;
if (Vector.IsHardwareAccelerated && length >= Vector<double>.Count)
{
var vSum = Vector<double>.Zero;
ref double rA = ref MemoryMarshal.GetReference(a);
ref double rB = ref MemoryMarshal.GetReference(b);
int vectorCount = Vector<double>.Count;
int limit = length - vectorCount;
for (; i <= limit; i += vectorCount)
{
var vA = Vector.LoadUnsafe(ref rA, (nuint)i);
var vB = Vector.LoadUnsafe(ref rB, (nuint)i);
vSum += vA * vB;
}
// Reduce vector sum
for (int j = 0; j < vectorCount; j++)
{
sum += vSum[j];
}
}
// Remainder
for (; i < length; i++)
{
sum += a[i] * b[i];
}
return sum;
}
=> a.DotProduct(b);
public static (TSeries Results, Loess Indicator) Calculate(TSeries source, int period)
{
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("LOESS Filter", "LOESS", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Modular Filter (MODF)", "MODF", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Notch Filter (NOTCH)", "NOTCH", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("One Euro Filter (ONEEURO)", "ONEEURO", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Recursive Least Squares Adaptive Filter (RLS)", "RLS", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
// Indicator algorithm (C) 2004-2024 John F. Ehlers
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Savitzky-Golay Filter (SGF)", "SGF", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
// Indicator algorithm (C) 2016 John F. Ehlers
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
// Indicator algorithm (C) 2004-2024 John F. Ehlers
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
// Indicator algorithm (C) 2004-2024 John F. Ehlers
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Ehlers Ultimate Smoother Filter (USF)", "USF", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Ehlers Voss Predictive Filter (VOSS)", "VOSS", overlay=false)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Wavelet Denoising Filter (WAVELET)", "WAVELET", overlay=true)
+1 -1
View File
@@ -1,4 +1,4 @@
// The MIT License (MIT)
// Licensed under the Apache License, Version 2.0
// © mihakralj
//@version=6
indicator("Wiener Filter (WIENER)", "WIENER", overlay=true)