diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 44158e8a..974ec457 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -33,7 +33,6 @@ - diff --git a/Tests/test_skender.stock.cs b/Tests/test_skender.stock.cs index 7c7fe3d5..fabc63db 100644 --- a/Tests/test_skender.stock.cs +++ b/Tests/test_skender.stock.cs @@ -13,10 +13,9 @@ public class SkenderTests private readonly Random rnd; private readonly double range; private int period; - private readonly int iterations; + private readonly int iterations = 3; // Initialized directly at declaration private readonly IEnumerable quotes; - public SkenderTests() { rnd = new((int)DateTime.Now.Ticks); @@ -24,7 +23,6 @@ public class SkenderTests bars = new(feed); range = 1e-9; feed.Add(10000); - iterations = 3; quotes = bars.Select(q => new Quote { Date = q.Time, @@ -338,15 +336,11 @@ public class SkenderTests var atrValues = quotes.GetAtr(lookbackPeriods: period).Select(i => i.Atr.Null2NaN()!); const int AdditionalPeriods = 500; -<<<<<<< HEAD - for (int i = QL.Length - 1; i > period + 500; i--) -======= for (int i = QL.Length - 1; i > period + AdditionalPeriods; i--) ->>>>>>> dev { Assert.InRange(atrValues.ElementAt(i) - QL[i].Value, -range, range); } } } -} \ No newline at end of file +} diff --git a/lib/averages/Frama.cs b/lib/averages/Frama.cs index 89733302..223b1458 100644 --- a/lib/averages/Frama.cs +++ b/lib/averages/Frama.cs @@ -81,16 +81,8 @@ public class Frama : AbstractBase } } -<<<<<<< HEAD - protected override double Calculation() - { - ManageState(Input.IsNew); - - _buffer.Add(Input.Value, Input.IsNew); -======= double n1 = (hh - ll) / _period; double n2 = (hh1 - ll1 + hh2 - ll2) / (_period / 2); ->>>>>>> dev double d = (Math.Log(n2 + double.Epsilon) - Math.Log(n1 + double.Epsilon)) / Math.Log(2); diff --git a/lib/averages/Qema.cs b/lib/averages/Qema.cs index 76d1f96f..d09e6ef0 100644 --- a/lib/averages/Qema.cs +++ b/lib/averages/Qema.cs @@ -2,33 +2,24 @@ namespace QuanTAlib; public class Qema : AbstractBase { - private readonly double _k1, _k2, _k3, _k4; + private readonly Ema _ema1, _ema2, _ema3, _ema4; private double _lastQema, _p_lastQema; -<<<<<<< HEAD - public Qema(double k1 = 0.2, double k2 = 0.2, double k3 = 0.2, double k4 = 0.2) : base() -======= public Qema(double k1 = 0.2, double k2 = 0.2, double k3 = 0.2, double k4 = 0.2) ->>>>>>> dev { if (k1 <= 0 || k2 <= 0 || k3 <= 0 || k4 <= 0) { - throw new ArgumentOutOfRangeException("All k values must be in the range (0, 1]."); + throw new ArgumentOutOfRangeException(nameof(k1), "All k values must be in the range (0, 1]."); } - _k1 = k1; - _k2 = k2; - _k3 = k3; - _k4 = k4; - _ema1 = new Ema(k1); _ema2 = new Ema(k2); _ema3 = new Ema(k3); _ema4 = new Ema(k4); Name = $"QEMA ({k1:F2},{k2:F2},{k3:F2},{k4:F2})"; - double smK = Math.Min(Math.Min(_k1, _k2), Math.Min(_k3, _k4)); + double smK = Math.Min(Math.Min(k1, k2), Math.Min(k3, k4)); WarmupPeriod = (int)((2 - smK) / smK); Init(); diff --git a/lib/averages/Rma.cs b/lib/averages/Rma.cs index d1381725..d41c19e9 100644 --- a/lib/averages/Rma.cs +++ b/lib/averages/Rma.cs @@ -1,45 +1,29 @@ using System; -using System.Runtime.CompilerServices; -<<<<<<< HEAD -namespace QuanTAlib -{ - - public class Rma : AbstractBase - { - private readonly int _period; - private double _alpha; - private double _lastRMA; - private double _savedLastRMA; - - public Rma(int period) : base() - { - if (period < 1) - { - throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period)); - } - _period = period; - WarmupPeriod = period * 2; - _alpha = 1.0 / _period; // Wilder's smoothing factor - Name = $"Rma({_period})"; - Init(); - } - - public Rma(object source, int period) : this(period) - { - var pubEvent = source.GetType().GetEvent("Pub"); - pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); - } -======= namespace QuanTAlib; - - +/// +/// RMA: Relative Moving Average (also known as Wilder's Moving Average) +/// RMA is similar to EMA but uses a different smoothing factor. +/// +/// +/// Key characteristics: +/// - Uses no buffer, relying only on the previous RMA value. +/// - The weight of new data points (alpha) is calculated as 1 / period. +/// - Provides a smoother curve compared to SMA and EMA, reacting more slowly to price changes. +/// +/// Calculation method: +/// RMA = (Previous RMA * (period - 1) + New Data) / period +/// +/// Sources: +/// - https://www.tradingview.com/pine-script-reference/v5/#fun_ta{dot}rma +/// - https://www.investopedia.com/terms/w/wilders-smoothing.asp +/// public class Rma : AbstractBase { private readonly int _period; + private double _lastRma; private readonly double _alpha; - private double _lastRMA; - private double _savedLastRMA; + private double _savedLastRma; public Rma(int period) { @@ -63,21 +47,22 @@ public class Rma : AbstractBase public override void Init() { base.Init(); - _lastRMA = 0; - _savedLastRMA = 0; + _lastRma = 0; + _savedLastRma = 0; } protected override void ManageState(bool isNew) { - if (!isNew) + if (isNew) { - _lastRMA = _savedLastRMA; - return; + _savedLastRma = _lastRma; + _lastValidValue = Input.Value; + _index++; + } + else + { + _lastRma = _savedLastRma; } - - _savedLastRMA = _lastRMA; - _lastValidValue = Input.Value; - _index++; } protected override double Calculation() @@ -88,73 +73,22 @@ public class Rma : AbstractBase if (_index == 1) { - return Input.Value; + rma = Input.Value; } - - if (_index <= _period) + else if (_index <= _period) { // Simple average during initial period - return (_lastRMA * (_index - 1) + Input.Value) / _index; + rma = (_lastRma * (_index - 1) + Input.Value) / _index; + } + else + { + // Wilder's smoothing method + rma = _alpha * (_lastRma - Input.Value) + _lastRma; } - // Wilder's smoothing method - return _alpha * (Input.Value - _lastRMA) + _lastRMA; - } - - _lastRMA = rma; + _lastRma = rma; IsHot = _index >= WarmupPeriod; ->>>>>>> dev - public override void Init() - { - base.Init(); - _lastRMA = 0; - _savedLastRMA = 0; - } - - protected override void ManageState(bool isNew) - { - if (isNew) - { - _savedLastRMA = _lastRMA; - _lastValidValue = Input.Value; - _index++; - } - else - { - _lastRMA = _savedLastRMA; - } - } - - protected override double Calculation() - { - ManageState(Input.IsNew); - - double rma; - - if (_index == 1) - { - rma = Input.Value; - } - else if (_index <= _period) - { - // Simple average during initial period - rma = (_lastRMA * (_index - 1) + Input.Value) / _index; - } - else - { - // Wilder's smoothing method - rma = _alpha * (Input.Value - _lastRMA) + _lastRMA; - } - - _lastRMA = rma; - IsHot = _index >= WarmupPeriod; - - return rma; - } + return rma; } -<<<<<<< HEAD } -======= -} ->>>>>>> dev diff --git a/lib/core/AbstractBarBase.cs b/lib/core/AbstractBarBase.cs index 16b9c79a..3e46d8d9 100644 --- a/lib/core/AbstractBarBase.cs +++ b/lib/core/AbstractBarBase.cs @@ -8,7 +8,7 @@ namespace QuanTAlib; /// and methods used by inheriting indicator types. It handles the basic flow of /// receiving bar data, performing calculations, and publishing results. /// -public abstract class AbstractBarBase : iTValue +public abstract class AbstractBarBase : ITValue { public DateTime Time { get; set; } public double Value { get; set; } diff --git a/lib/core/circularbuffer.cs b/lib/core/circularbuffer.cs index 5a2e9c7a..42740f67 100644 --- a/lib/core/circularbuffer.cs +++ b/lib/core/circularbuffer.cs @@ -89,9 +89,9 @@ public class CircularBuffer : IEnumerable } [MethodImpl(MethodImplOptions.NoInlining)] - private static void ThrowArgumentOutOfRangeException() + private static void ThrowArgumentOutOfRangeException(string paramName) { - throw new ArgumentOutOfRangeException("index", "Index is out of range."); + throw new ArgumentOutOfRangeException(paramName, "Index is out of range."); } /// @@ -221,13 +221,6 @@ public class CircularBuffer : IEnumerable if (_start + _size <= Capacity) { return new ReadOnlySpan(_buffer, _start, _size); -<<<<<<< HEAD - } - else - { - return new ReadOnlySpan(ToArray()); -======= ->>>>>>> dev } return new ReadOnlySpan(ToArray()); diff --git a/lib/feeds/GbmFeed.cs b/lib/feeds/GbmFeed.cs index f4f93f77..f4c69a0e 100644 --- a/lib/feeds/GbmFeed.cs +++ b/lib/feeds/GbmFeed.cs @@ -8,11 +8,7 @@ public class GbmFeed : TBarSeries private readonly Random _random; private double _lastClose, _lastHigh, _lastLow; -<<<<<<< HEAD - public GbmFeed(double initialPrice = 100.0, double mu = 0.05, double sigma = 0.2) : base() -======= public GbmFeed(double initialPrice = 100.0, double mu = 0.05, double sigma = 0.2) ->>>>>>> dev { _lastClose = _lastHigh = _lastLow = initialPrice; _mu = mu; @@ -26,7 +22,6 @@ public class GbmFeed : TBarSeries public void Add(int count) { DateTime startTime = DateTime.UtcNow - TimeSpan.FromHours(count); - TBar lastBar = new(); for (int i = 0; i < count; i++) { Add(startTime, true); diff --git a/lib/statistics/Min.cs b/lib/statistics/Min.cs index fade78e9..6eea3fad 100644 --- a/lib/statistics/Min.cs +++ b/lib/statistics/Min.cs @@ -26,11 +26,7 @@ public class Min : AbstractBase /// /// Thrown when period is less than 1 or decay is negative. /// -<<<<<<< HEAD - public Min(int period, double decay = 0) : base() -======= public Min(int period, double decay = 0) ->>>>>>> dev { if (period < 1) { diff --git a/lib/statistics/Mode.cs b/lib/statistics/Mode.cs index 7579bf84..33438f7b 100644 --- a/lib/statistics/Mode.cs +++ b/lib/statistics/Mode.cs @@ -21,11 +21,7 @@ public class Mode : AbstractBase /// /// Thrown when period is less than 1. /// -<<<<<<< HEAD - public Mode(int period) : base() -======= public Mode(int period) ->>>>>>> dev { if (period < 1) { diff --git a/lib/statistics/Percentile.cs b/lib/statistics/Percentile.cs index b4de2b69..b15155c8 100644 --- a/lib/statistics/Percentile.cs +++ b/lib/statistics/Percentile.cs @@ -24,11 +24,7 @@ public class Percentile : AbstractBase /// /// Thrown when period is less than 2 or percent is not between 0 and 100. /// -<<<<<<< HEAD - public Percentile(int period, double percent) : base() -======= public Percentile(int period, double percent) ->>>>>>> dev { if (period < 2) { diff --git a/lib/statistics/Skew.cs b/lib/statistics/Skew.cs index babb967f..38e4e1be 100644 --- a/lib/statistics/Skew.cs +++ b/lib/statistics/Skew.cs @@ -22,11 +22,7 @@ public class Skew : AbstractBase /// /// Thrown when period is less than 3. /// -<<<<<<< HEAD - public Skew(int period) : base() -======= public Skew(int period) ->>>>>>> dev { if (period < 3) { diff --git a/lib/statistics/Stddev.cs b/lib/statistics/Stddev.cs index d7d01fd8..247413dd 100644 --- a/lib/statistics/Stddev.cs +++ b/lib/statistics/Stddev.cs @@ -11,7 +11,6 @@ namespace QuanTAlib; /// public class Stddev : AbstractBase { - private readonly int Period; private readonly bool IsPopulation; private readonly CircularBuffer _buffer; @@ -26,17 +25,12 @@ public class Stddev : AbstractBase /// /// Thrown when period is less than 2. /// -<<<<<<< HEAD - public Stddev(int period, bool isPopulation = false) : base() -======= public Stddev(int period, bool isPopulation = false) ->>>>>>> dev { if (period < 2) { throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2."); } - Period = period; IsPopulation = isPopulation; WarmupPeriod = 0; _buffer = new CircularBuffer(period); diff --git a/lib/statistics/Variance.cs b/lib/statistics/Variance.cs index a669a828..a7c6f3e0 100644 --- a/lib/statistics/Variance.cs +++ b/lib/statistics/Variance.cs @@ -11,7 +11,6 @@ namespace QuanTAlib; /// public class Variance : AbstractBase { - private readonly int Period; private readonly bool IsPopulation; private readonly CircularBuffer _buffer; @@ -26,17 +25,12 @@ public class Variance : AbstractBase /// /// Thrown when period is less than 2. /// -<<<<<<< HEAD - public Variance(int period, bool isPopulation = false) : base() -======= public Variance(int period, bool isPopulation = false) ->>>>>>> dev { if (period < 2) { throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2."); } - Period = period; IsPopulation = isPopulation; WarmupPeriod = 0; _buffer = new CircularBuffer(period); diff --git a/lib/statistics/Zscore.cs b/lib/statistics/Zscore.cs index 2a7e4664..946a8e34 100644 --- a/lib/statistics/Zscore.cs +++ b/lib/statistics/Zscore.cs @@ -21,11 +21,7 @@ public class Zscore : AbstractBase /// /// Thrown when period is less than 2. /// -<<<<<<< HEAD - public Zscore(int period) : base() -======= public Zscore(int period) ->>>>>>> dev { if (period < 2) { diff --git a/lib/volatility/Atr.cs b/lib/volatility/Atr.cs index 34df9043..e6c20845 100644 --- a/lib/volatility/Atr.cs +++ b/lib/volatility/Atr.cs @@ -8,11 +8,7 @@ namespace QuanTAlib; /// of the true range. The true range is the greatest of: current high - current low, /// absolute value of current high - previous close, or absolute value of current low - previous close. /// -<<<<<<< HEAD -public class Atr : AbstractBarBase -======= public class Atr : AbstractBase ->>>>>>> dev { private readonly Ema _ma; private double _prevClose, _p_prevClose; @@ -86,11 +82,7 @@ public class Atr : AbstractBase /// protected override double Calculation() { -<<<<<<< HEAD - ManageState(Input.IsNew); -======= ManageState(BarInput.IsNew); ->>>>>>> dev double trueRange = Math.Max( Math.Max( @@ -101,11 +93,7 @@ public class Atr : AbstractBase ); if (_index < 2) { -<<<<<<< HEAD - trueRange = Input.High - Input.Low; -======= trueRange = BarInput.High - BarInput.Low; ->>>>>>> dev } TValue emaTrueRange = _ma.Calc(new TValue(Input.Time, trueRange, Input.IsNew)); diff --git a/lib/volatility/Historical.cs b/lib/volatility/Historical.cs index a6fcb880..9417b14d 100644 --- a/lib/volatility/Historical.cs +++ b/lib/volatility/Historical.cs @@ -25,11 +25,7 @@ public class Historical : AbstractBase /// /// Thrown when period is less than 2. /// -<<<<<<< HEAD - public Historical(int period, bool isAnnualized = true) : base() -======= public Historical(int period, bool isAnnualized = true) ->>>>>>> dev { if (period < 2) { diff --git a/lib/volatility/Realized.cs b/lib/volatility/Realized.cs index 09dfb139..5798919b 100644 --- a/lib/volatility/Realized.cs +++ b/lib/volatility/Realized.cs @@ -25,11 +25,7 @@ public class Realized : AbstractBase /// /// Thrown when period is less than 2. /// -<<<<<<< HEAD - public Realized(int period, bool isAnnualized = true) : base() -======= public Realized(int period, bool isAnnualized = true) ->>>>>>> dev { if (period < 2) { diff --git a/lib/volatility/Rvi.cs b/lib/volatility/Rvi.cs index 35ff6824..7047176c 100644 --- a/lib/volatility/Rvi.cs +++ b/lib/volatility/Rvi.cs @@ -15,7 +15,6 @@ namespace QuanTAlib; /// public class Rvi : AbstractBase { - private readonly int Period; private readonly Stddev _upStdDev, _downStdDev; private readonly Sma _upSma, _downSma; private double _previousClose; @@ -27,17 +26,13 @@ public class Rvi : AbstractBase /// /// Thrown when period is less than 2. /// -<<<<<<< HEAD - public Rvi(int period) : base() -======= public Rvi(int period) ->>>>>>> dev { if (period < 2) { throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2."); } - Period = period; + int Period = period; WarmupPeriod = period; Name = $"RVI(period={period})"; _upStdDev = new Stddev(Period); @@ -109,18 +104,7 @@ public class Rvi : AbstractBase _downSma.Calc(_downStdDev.Calc(new TValue(Input.Time, downMove, Input.IsNew))); double rvi; -<<<<<<< HEAD - if (_upSma.Value + _downSma.Value != 0) - { - rvi = 100 * _upSma.Value / (_upSma.Value + _downSma.Value); - } - else - { - rvi = 0; - } -======= rvi = (_upSma.Value + _downSma.Value != 0) ? 100 * _upSma.Value / (_upSma.Value + _downSma.Value) : 0; ->>>>>>> dev _previousClose = close; IsHot = _index >= WarmupPeriod;