diff --git a/.github/workflows/Publish.yml b/.github/workflows/Publish.yml index 744e3dc4..34c762bf 100644 --- a/.github/workflows/Publish.yml +++ b/.github/workflows/Publish.yml @@ -79,7 +79,7 @@ jobs: - name: SonarCloud Scanner End env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: dotnet sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" + run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" Code_Coverage: runs-on: ubuntu-latest diff --git a/GitVersion.yml b/GitVersion.yml index 61134695..1fa72ce7 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,3 +1,4 @@ +next-version: 0.6.1 mode: ContinuousDelivery major-version-bump-message: '\+semver:\s?(breaking|major)' minor-version-bump-message: '\+semver:\s?(feature|minor)' @@ -14,4 +15,4 @@ branches: increment: Inherit ignore: sha: [] -merge-message-formats: {} \ No newline at end of file +merge-message-formats: {} diff --git a/Tests/test_quantower.cs b/Tests/test_quantower.cs index a82e0cbb..440040f6 100644 --- a/Tests/test_quantower.cs +++ b/Tests/test_quantower.cs @@ -21,6 +21,8 @@ namespace QuanTAlib var onInitMethod = typeof(T).GetMethod("OnInit", BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(onInitMethod); onInitMethod.Invoke(indicator, null); + var onUpdateMethod = typeof(T).GetMethod("OnUpdate", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(onUpdateMethod); var field = typeof(T).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(field); diff --git a/lib/averages/Maaf.cs b/lib/averages/Maaf.cs index fd4503da..2b31ddf0 100644 --- a/lib/averages/Maaf.cs +++ b/lib/averages/Maaf.cs @@ -1,9 +1,9 @@ -//TODO: fails consistency test - namespace QuanTAlib; // https://efs.kb.esignal.com/hc/en-us/articles/6362791434395-2005-Mar-The-Secret-Behind-The-Filter-MedianAdaptiveFilter-efs +//TODO Fix initial values + public class Maaf : AbstractBase { private readonly CircularBuffer _priceBuffer; @@ -70,6 +70,7 @@ public class Maaf : AbstractBase double smooth = (_priceBuffer[^1] + (2 * _priceBuffer[^2]) + (2 * _priceBuffer[^3]) + _priceBuffer[^4]) / 6; _smoothBuffer.Add(smooth, Input.IsNew); + if (_smoothBuffer.Count < _period) { return smooth; diff --git a/lib/averages/Zlema.cs b/lib/averages/Zlema.cs index 32868b5f..1aae1e16 100644 --- a/lib/averages/Zlema.cs +++ b/lib/averages/Zlema.cs @@ -1,73 +1,72 @@ using System; using System.Runtime.CompilerServices; -namespace QuanTAlib; - -public class Zlema : AbstractBase +namespace QuanTAlib { - private readonly int _period; - private CircularBuffer? _buffer; - private readonly double _alpha; - private readonly int _lag; - private double _lastZLEMA, _p_lastZLEMA; - - public Zlema(int period) + public class Zlema : AbstractBase { - if (period < 1) + private readonly CircularBuffer _buffer; + private readonly int _lag; + private readonly Ema _ema; + private double _lastZLEMA, _p_lastZLEMA; + + public Zlema(int period) { - throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period)); + if (period < 1) + { + throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period)); + } + WarmupPeriod = period; + _lag = (int)(0.5 * (period - 1)); + _buffer = new CircularBuffer(_lag + 1); + _ema = new Ema(period, useSma: false); + Name = $"Zlema({period})"; + Init(); } - _period = period; - WarmupPeriod = period; - _alpha = 2.0 / (_period + 1); - _lag = (_period - 1) / 2; - Name = $"Zlema({_period})"; - Init(); - } - public Zlema(object source, int period) : this(period) - { - var pubEvent = source.GetType().GetEvent("Pub"); - pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); - } - - public override void Init() - { - base.Init(); - _buffer = new CircularBuffer(_period); - _lastZLEMA = 0; - } - - protected override void ManageState(bool isNew) - { - if (isNew) + public Zlema(object source, int period) : this(period) { - _lastValidValue = Input.Value; - _index++; - _p_lastZLEMA = _lastZLEMA; + var pubEvent = source.GetType().GetEvent("Pub"); + pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - else + + public override void Init() { - _lastZLEMA = _p_lastZLEMA; + base.Init(); + _buffer.Clear(); + _ema.Init(); + _lastZLEMA = 0; + _p_lastZLEMA = 0; + } + + protected override void ManageState(bool isNew) + { + if (isNew) + { + _lastValidValue = Input.Value; + _index++; + _p_lastZLEMA = _lastZLEMA; + } + else + { + _lastZLEMA = _p_lastZLEMA; + } + } + + protected override double Calculation() + { + ManageState(Input.IsNew); + + _buffer.Add(Input.Value, Input.IsNew); + + double lagValue = _buffer[Math.Max(0, _buffer.Count - 1 - _lag)]; + double errorCorrection = 2 * Input.Value - lagValue; + double zlema = _ema.Calc(new TValue(errorCorrection, Input.IsNew)).Value; + + _lastZLEMA = zlema; + IsHot = _index >= WarmupPeriod; + + return zlema; } } - - protected override double Calculation() - { - ManageState(Input.IsNew); - - _buffer!.Add(Input.Value, Input.IsNew); - - int lag = Math.Max(Math.Min((int)((_period - 1) * 0.5), _buffer.Count - 1), 0) + 1; - double zlValue = 2 * Input.Value - _buffer[_buffer.Count - lag]; - - // Dynamic alpha factor for index <= period - double k = (_index <= _period) ? (2.0 / (_index + 1)) : _alpha; - double zlema = (zlValue - _lastZLEMA) * k + _lastZLEMA; - - _lastZLEMA = zlema; - IsHot = _index >= WarmupPeriod; - - return zlema; - } -} \ No newline at end of file +} diff --git a/lib/core/abstractBase.cs b/lib/core/abstractBase.cs index 203b8329..3859473a 100644 --- a/lib/core/abstractBase.cs +++ b/lib/core/abstractBase.cs @@ -55,41 +55,45 @@ public abstract class AbstractBase : ITValue { Input = input; Input2 = new(Time: Input.Time, Value: double.NaN, IsNew: Input.IsNew, IsHot: Input.IsHot); - return HandleErrorCalculations(input.Value, input.Time, input.IsNew); + return Process(input.Value, input.Time, input.IsNew); } public virtual TValue Calc(TBar barInput) { BarInput = barInput; - return HandleErrorCalculations(barInput.Close, barInput.Time, barInput.IsNew); + return Process(barInput.Close, barInput.Time, barInput.IsNew); } public virtual TValue Calc(TValue input1, TValue input2) { Input = input1; Input2 = input2; - return HandleErrorCalculations(input1.Value, input2.Value, input1.Time, input1.IsNew); + return Process(input1.Value, input2.Value, input1.Time, input1.IsNew); } public virtual TValue Calc(TBar input1, TBar input2) { BarInput = input1; BarInput2 = input2; - return HandleErrorCalculations(input1.Close, input2.Close, input1.Time, input1.IsNew); + return Process(input1.Close, input2.Close, input1.Time, input1.IsNew); + } + + public virtual TValue Calc(double value1, double value2) + { + DateTime now = DateTime.Now; + Input = new TValue(now, value1, true, true); + Input2 = new TValue(now, value2, true, true); + return Process(value1, value2, now, true); } /// - /// Handles error calculations and invalid input values. + /// Processes the input values, performs error checking, and calculates the indicator value. /// - /// The primary input value to check. + /// The primary input value to process. /// The timestamp of the input. /// Indicates if the input is new. /// A TValue object with the calculated or last valid value. - /// - /// This method checks for NaN or infinity in the input value. If an invalid value is detected, - /// it returns the last valid value. Otherwise, it proceeds with the calculation. - /// - protected virtual TValue HandleErrorCalculations(double value, DateTime time, bool isNew) + protected virtual TValue Process(double value, DateTime time, bool isNew) { if (double.IsNaN(value) || double.IsInfinity(value)) { @@ -100,18 +104,14 @@ public abstract class AbstractBase : ITValue } /// - /// Handles error calculations for inputs with two values. + /// Processes two input values, performs error checking, and calculates the indicator value. /// - /// The first input value to check. - /// The second input value to check. + /// The first input value to process. + /// The second input value to process. /// The timestamp of the input. /// Indicates if the input is new. /// A TValue object with the calculated or last valid value. - /// - /// This method checks for NaN or infinity in both input values. If any invalid value is detected, - /// it returns the last valid value. Otherwise, it proceeds with the calculation. - /// - protected virtual TValue HandleErrorCalculations(double value1, double value2, DateTime time, bool isNew) + protected virtual TValue Process(double value1, double value2, DateTime time, bool isNew) { if (double.IsNaN(value1) || double.IsInfinity(value1) || double.IsNaN(value2) || double.IsInfinity(value2)) @@ -121,7 +121,21 @@ public abstract class AbstractBase : ITValue this.Value = Calculation(); return Process(new TValue(Time: time, Value: this.Value, IsNew: isNew, IsHot: this.IsHot)); } - + /// + /// Processes the calculated value, updates the indicator's own state, + /// and publishes the result through an event. + /// + /// The calculated TValue to process. + /// The processed TValue. + protected virtual TValue Process(TValue value) + { + this.Time = value.Time; + this.Value = value.Value; + this.IsNew = value.IsNew; + this.IsHot = value.IsHot; + Pub?.Invoke(this, new ValueEventArgs(value)); + return value; + } /// /// Retrieves the last valid calculated value. /// @@ -143,19 +157,5 @@ public abstract class AbstractBase : ITValue /// The calculated indicator value. protected abstract double Calculation(); - /// - /// Processes the calculated value, updates the indicator's own state, - /// and publishes the result through an event. - /// - /// The calculated TValue to process. - /// The processed TValue. - protected virtual TValue Process(TValue value) - { - this.Time = value.Time; - this.Value = value.Value; - this.IsNew = value.IsNew; - this.IsHot = value.IsHot; - Pub?.Invoke(this, new ValueEventArgs(value)); - return value; - } + } diff --git a/lib/errors/Huberloss.cs b/lib/errors/Huberloss.cs index 71d77fac..e2bdac55 100644 --- a/lib/errors/Huberloss.cs +++ b/lib/errors/Huberloss.cs @@ -1,27 +1,11 @@ namespace QuanTAlib; -/// -/// Represents a Huber Loss calculator that combines the best properties of L2 squared loss for normal data -/// and L1 absolute loss for outliers. -/// -/// -/// The Huberloss class calculates the Huber Loss using circular buffers -/// to efficiently manage the actual and predicted data points within the specified period. -/// public class Huberloss : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; private readonly double _delta; - /// - /// Initializes a new instance of the Huberloss class with the specified period and delta. - /// - /// The period over which to calculate the Huber Loss. - /// The threshold at which to switch from squared to linear loss. - /// - /// Thrown when period is less than 1 or delta is less than or equal to 0. - /// public Huberloss(int period, double delta = 1.0) { if (period < 1) @@ -40,20 +24,12 @@ public class Huberloss : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mape class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. - public Huberloss(object source, int period) : this(period) + public Huberloss(object source, int period, double delta = 1.0) : this(period, delta) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Huberloss instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -61,10 +37,6 @@ public class Huberloss : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Huberloss instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -74,18 +46,6 @@ public class Huberloss : AbstractBase } } - /// - /// Performs the Huber Loss calculation for the current period. - /// - /// - /// The calculated Huber Loss value for the current period. - /// - /// - /// This method calculates the Huber Loss using the formula: - /// L(a, p) = 0.5 * (a - p)^2 for |a - p| <= delta - /// L(a, p) = delta * |a - p| - 0.5 * delta^2 for |a - p| > delta - /// where a is the actual value, p is the predicted value, and delta is the threshold. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -96,7 +56,7 @@ public class Huberloss : AbstractBase double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value; _predictedBuffer.Add(predicted, Input.IsNew); - double huberLoss = 0; + double huberloss = 0; if (_actualBuffer.Count > 0) { var actualValues = _actualBuffer.GetSpan().ToArray(); @@ -105,34 +65,24 @@ public class Huberloss : AbstractBase double sumLoss = 0; for (int i = 0; i < _actualBuffer.Count; i++) { - double error = Math.Abs(actualValues[i] - predictedValues[i]); - if (error <= _delta) + double error = actualValues[i] - predictedValues[i]; + double absError = Math.Abs(error); + + if (absError <= _delta) { sumLoss += 0.5 * error * error; } else { - sumLoss += _delta * error - 0.5 * _delta * _delta; + sumLoss += _delta * (absError - 0.5 * _delta); } } - huberLoss = sumLoss / _actualBuffer.Count; + huberloss = sumLoss / _actualBuffer.Count; } IsHot = _index >= WarmupPeriod; - return huberLoss; + return huberloss; } - /// - /// Calculates the Huber Loss for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Huber Loss. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Mae.cs b/lib/errors/Mae.cs index 316abfb4..f043af52 100644 --- a/lib/errors/Mae.cs +++ b/lib/errors/Mae.cs @@ -1,25 +1,10 @@ namespace QuanTAlib; -/// -/// Represents a Mean Absolute Error calculator that measures the average absolute difference -/// between actual values and predicted values. -/// -/// -/// The Mae class calculates the Mean Absolute Error using circular buffers -/// to efficiently manage the actual and predicted data points within the specified period. -/// public class Mae : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Mae class with the specified period. - /// - /// The period over which to calculate the Mean Absolute Error. - /// - /// Thrown when period is less than 1. - /// public Mae(int period) { if (period < 1) @@ -33,20 +18,12 @@ public class Mae : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mae class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Error. public Mae(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Mae instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -54,10 +31,6 @@ public class Mae : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Mae instance based on whether a new value is being processed. - /// - /// Indicates whether the current input is a new value. protected override void ManageState(bool isNew) { if (isNew) @@ -67,18 +40,6 @@ public class Mae : AbstractBase } } - /// - /// Performs the Mean Absolute Error calculation for the current period. - /// - /// - /// The calculated Mean Absolute Error value for the current period. - /// - /// - /// This method calculates the Mean Absolute Error using the formula: - /// MAE = sum(|actual - predicted|) / n - /// where actual is each actual value, predicted is each predicted value, and n is the number of values. - /// If Input2.Value is NaN, it uses the average of actual values as the predicted value. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -95,29 +56,17 @@ public class Mae : AbstractBase var actualValues = _actualBuffer.GetSpan().ToArray(); var predictedValues = _predictedBuffer.GetSpan().ToArray(); - double sumOfAbsoluteDifferences = 0; + double sumAbsoluteError = 0; for (int i = 0; i < _actualBuffer.Count; i++) { - sumOfAbsoluteDifferences += Math.Abs(actualValues[i] - predictedValues[i]); + sumAbsoluteError += Math.Abs(actualValues[i] - predictedValues[i]); } - mae = sumOfAbsoluteDifferences / _actualBuffer.Count; + mae = sumAbsoluteError / _actualBuffer.Count; } IsHot = _index >= WarmupPeriod; return mae; } - /// - /// Calculates the Mean Absolute Error for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Mean Absolute Error. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Mapd.cs b/lib/errors/Mapd.cs index 531836dc..55a15d73 100644 --- a/lib/errors/Mapd.cs +++ b/lib/errors/Mapd.cs @@ -1,25 +1,10 @@ namespace QuanTAlib; -/// -/// Represents a Mean Absolute Percentage Deviation calculator that measures the average absolute percentage difference -/// between actual values and predicted values. -/// -/// -/// The Mapd class calculates the Mean Absolute Percentage Deviation using circular buffers -/// to efficiently manage the actual and predicted data points within the specified period. -/// public class Mapd : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Mapd class with the specified period. - /// - /// The period over which to calculate the Mean Absolute Percentage Deviation. - /// - /// Thrown when period is less than 1. - /// public Mapd(int period) { if (period < 1) @@ -33,20 +18,12 @@ public class Mapd : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mapd class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Deviation. public Mapd(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Mapd instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -54,10 +31,6 @@ public class Mapd : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Mapd instance based on whether a new value is being processed. - /// - /// Indicates whether the current input is a new value. protected override void ManageState(bool isNew) { if (isNew) @@ -67,18 +40,6 @@ public class Mapd : AbstractBase } } - /// - /// Performs the Mean Absolute Percentage Deviation calculation for the current period. - /// - /// - /// The calculated Mean Absolute Percentage Deviation value for the current period. - /// - /// - /// This method calculates the Mean Absolute Percentage Deviation using the formula: - /// MAPD = (sum(|actual - predicted| / |actual|) / n) * 100 - /// where actual is each actual value, predicted is each predicted value, and n is the number of values. - /// If there's only one value in the buffer or if any actual value is zero, those values are excluded from the calculation. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -95,38 +56,20 @@ public class Mapd : AbstractBase var actualValues = _actualBuffer.GetSpan().ToArray(); var predictedValues = _predictedBuffer.GetSpan().ToArray(); - double sumOfAbsolutePercentageDeviations = 0; - int validCount = 0; - + double sumAbsolutePercentageDeviation = 0; for (int i = 0; i < _actualBuffer.Count; i++) { if (actualValues[i] != 0) { - sumOfAbsolutePercentageDeviations += Math.Abs((actualValues[i] - predictedValues[i]) / actualValues[i]); - validCount++; + sumAbsolutePercentageDeviation += Math.Abs((actualValues[i] - predictedValues[i]) / actualValues[i]); } } - if (validCount > 0) - { - mapd = (sumOfAbsolutePercentageDeviations / validCount) * 100; - } + mapd = sumAbsolutePercentageDeviation / _actualBuffer.Count; } IsHot = _index >= WarmupPeriod; return mapd; } - /// - /// Calculates the Mean Absolute Percentage Deviation for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Mean Absolute Percentage Deviation. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Mape.cs b/lib/errors/Mape.cs index dda866e5..f19299f9 100644 --- a/lib/errors/Mape.cs +++ b/lib/errors/Mape.cs @@ -1,25 +1,10 @@ namespace QuanTAlib; -/// -/// Represents a Mean Absolute Percentage Error calculator that measures the average absolute percentage difference -/// between actual values and predicted values. -/// -/// -/// The Mape class calculates the Mean Absolute Percentage Error using a circular buffer -/// to efficiently manage the data points within the specified period. -/// public class Mape : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Mape class with the specified period. - /// - /// The period over which to calculate the Mean Absolute Percentage Error. - /// - /// Thrown when period is less than 1. - /// public Mape(int period) { if (period < 1) @@ -33,20 +18,12 @@ public class Mape : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mape class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. public Mape(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Mape instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -54,10 +31,6 @@ public class Mape : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Mape instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -67,18 +40,6 @@ public class Mape : AbstractBase } } - /// - /// Performs the Mean Absolute Percentage Error calculation for the current period. - /// - /// - /// The calculated Mean Absolute Percentage Error value for the current period. - /// - /// - /// This method calculates the Mean Absolute Percentage Error using the formula: - /// MAPE = (sum(|actual - predicted| / |actual|) / n) * 100 - /// where actual is each actual value, predicted is each predicted value, and n is the number of values. - /// If any actual value is zero, it is excluded from the calculation to avoid division by zero. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -96,37 +57,18 @@ public class Mape : AbstractBase var predictedValues = _predictedBuffer.GetSpan().ToArray(); double sumAbsolutePercentageError = 0; - int validCount = 0; - for (int i = 0; i < _actualBuffer.Count; i++) { if (actualValues[i] != 0) { sumAbsolutePercentageError += Math.Abs((actualValues[i] - predictedValues[i]) / actualValues[i]); - validCount++; } } - if (validCount > 0) - { - mape = (sumAbsolutePercentageError / validCount) * 100; - } + mape = sumAbsolutePercentageError / _actualBuffer.Count; } IsHot = _index >= WarmupPeriod; return mape; } - - /// - /// Calculates the Mean Absolute Percentage Error for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Mean Absolute Percentage Error. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Mase.cs b/lib/errors/Mase.cs index b1e5673a..5b486ba7 100644 --- a/lib/errors/Mase.cs +++ b/lib/errors/Mase.cs @@ -1,45 +1,40 @@ +using System; + namespace QuanTAlib; /// -/// Represents a Mean Absolute Scaled Error calculator that measures the ratio of the mean absolute error -/// of the forecast values to the mean absolute error of the naive forecast. +/// Represents the Mean Absolute Scaled Error (MASE) calculation. /// -/// -/// The Mase class calculates the Mean Absolute Scaled Error using circular buffers -/// to efficiently manage the data points within the specified period. -/// public class Mase : AbstractBase { private readonly CircularBuffer _actualBuffer; - private readonly CircularBuffer _forecastBuffer; - private readonly int _period; + private readonly CircularBuffer _predictedBuffer; + private readonly CircularBuffer _naiveBuffer; /// - /// Initializes a new instance of the Mase class with the specified period. + /// Initializes a new instance of the Mase class. /// - /// The period over which to calculate the Mean Absolute Scaled Error. - /// - /// Thrown when period is less than 3. - /// + /// The period for MASE calculation. + /// Thrown when period is less than 1. public Mase(int period) { - if (period < 3) + if (period < 1) { - throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 3."); + throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1."); } - _period = period; WarmupPeriod = period; _actualBuffer = new CircularBuffer(period); - _forecastBuffer = new CircularBuffer(period); + _predictedBuffer = new CircularBuffer(period); + _naiveBuffer = new CircularBuffer(period); Name = $"Mase(period={period})"; Init(); } /// - /// Initializes a new instance of the Mase class with the specified source and period. + /// Initializes a new instance of the Mase class with a source object. /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Scaled Error. + /// The source object for event subscription. + /// The period for MASE calculation. public Mase(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); @@ -47,19 +42,20 @@ public class Mase : AbstractBase } /// - /// Initializes the Mase instance by clearing the buffers. + /// Initializes the Mase instance. /// public override void Init() { base.Init(); _actualBuffer.Clear(); - _forecastBuffer.Clear(); + _predictedBuffer.Clear(); + _naiveBuffer.Clear(); } /// - /// Manages the state of the Mase instance based on whether new values are being processed. + /// Manages the state of the Mase instance. /// - /// Indicates whether the current inputs are new values. + /// Indicates if the input is new. protected override void ManageState(bool isNew) { if (isNew) @@ -70,17 +66,9 @@ public class Mase : AbstractBase } /// - /// Performs the Mean Absolute Scaled Error calculation for the current period. + /// Performs the MASE calculation. /// - /// - /// The calculated Mean Absolute Scaled Error value for the current period. - /// - /// - /// This method calculates the Mean Absolute Scaled Error using the formula: - /// MASE = mean(|actual - forecast|) / mean(|actual[t] - actual[t-1]|) - /// where actual is each actual value and forecast is each forecast value. - /// If there are fewer than 3 values in the buffers, the method returns 0. - /// + /// The calculated MASE value. protected override double Calculation() { ManageState(Input.IsNew); @@ -88,49 +76,51 @@ public class Mase : AbstractBase double actual = Input.Value; _actualBuffer.Add(actual, Input.IsNew); - double forecast = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value; - _forecastBuffer.Add(forecast, Input.IsNew); + double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value; + _predictedBuffer.Add(predicted, Input.IsNew); - double mase = 0; - if (_actualBuffer.Count >= 3) + if (_actualBuffer.Count > 1) { - var actualValues = _actualBuffer.GetSpan().ToArray(); - var forecastValues = _forecastBuffer.GetSpan().ToArray(); - - double sumAbsoluteError = 0; - double sumAbsoluteNaiveError = 0; - - int count = Math.Min(_actualBuffer.Count, _period); - - for (int i = 1; i < count; i++) - { - sumAbsoluteError += Math.Abs(actualValues[i] - forecastValues[i]); - sumAbsoluteNaiveError += Math.Abs(actualValues[i] - actualValues[i - 1]); - } - - double meanAbsoluteError = sumAbsoluteError / (count - 1); - double meanAbsoluteNaiveError = sumAbsoluteNaiveError / (count - 1); - - if (meanAbsoluteNaiveError != 0) - { - mase = meanAbsoluteError / meanAbsoluteNaiveError; - } + _naiveBuffer.Add(_actualBuffer.GetSpan()[^2], Input.IsNew); } + double mase = CalculateMase(); + IsHot = _index >= WarmupPeriod; return mase; } - /// - /// Calculates the Mean Absolute Scaled Error for the given actual and forecast values. - /// - /// The actual value. - /// The forecast value. - /// The calculated Mean Absolute Scaled Error. - public double Calc(double actual, double forecast) + private double CalculateMase() { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, forecast); - return Calculation(); + if (_actualBuffer.Count <= 1) return 0; + + ReadOnlySpan actualValues = _actualBuffer.GetSpan(); + ReadOnlySpan predictedValues = _predictedBuffer.GetSpan(); + ReadOnlySpan naiveValues = _naiveBuffer.GetSpan(); + + double sumAbsoluteError = CalculateSumAbsoluteError(actualValues, predictedValues); + double _naiveForecastError = CalculateNaiveForecastError(actualValues, naiveValues); + + return _naiveForecastError != 0 ? (sumAbsoluteError / _actualBuffer.Count) / _naiveForecastError : double.PositiveInfinity; + } + + private static double CalculateSumAbsoluteError(ReadOnlySpan actualValues, ReadOnlySpan predictedValues) + { + double sum = 0; + for (int i = 0; i < actualValues.Length; i++) + { + sum += Math.Abs(actualValues[i] - predictedValues[i]); + } + return sum; + } + + private static double CalculateNaiveForecastError(ReadOnlySpan actualValues, ReadOnlySpan naiveValues) + { + double sum = 0; + for (int i = 1; i < actualValues.Length; i++) + { + sum += Math.Abs(actualValues[i] - naiveValues[i - 1]); + } + return sum / (actualValues.Length - 1); } } diff --git a/lib/errors/Mda.cs b/lib/errors/Mda.cs index 4c184603..ba03bced 100644 --- a/lib/errors/Mda.cs +++ b/lib/errors/Mda.cs @@ -1,65 +1,36 @@ namespace QuanTAlib; -/// -/// Represents a Mean Directional Accuracy calculator that measures the average accuracy -/// of predicted directional changes compared to actual directional changes. -/// -/// -/// The Mda class calculates the Mean Directional Accuracy using a circular buffer -/// to efficiently manage the data points within the specified period. -/// Mean Directional Accuracy is useful in financial analysis for evaluating the performance -/// of forecasting models in predicting the direction of price movements. -/// public class Mda : AbstractBase { private readonly CircularBuffer _actualBuffer; - private readonly CircularBuffer _forecastBuffer; + private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Mda class with the specified period. - /// - /// The period over which to calculate the Mean Directional Accuracy. - /// - /// Thrown when period is less than 2. - /// public Mda(int period) { - if (period < 2) + if (period < 1) { - throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2."); + throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1."); } - WarmupPeriod = 1; + WarmupPeriod = period; _actualBuffer = new CircularBuffer(period); - _forecastBuffer = new CircularBuffer(period); + _predictedBuffer = new CircularBuffer(period); Name = $"Mda(period={period})"; Init(); } - /// - /// Initializes a new instance of the Mda class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Directional Accuracy. public Mda(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Mda instance by clearing the buffers. - /// public override void Init() { base.Init(); _actualBuffer.Clear(); - _forecastBuffer.Clear(); + _predictedBuffer.Clear(); } - /// - /// Manages the state of the Mda instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -69,20 +40,6 @@ public class Mda : AbstractBase } } - /// - /// Performs the Mean Directional Accuracy calculation for the current period. - /// - /// - /// The calculated Mean Directional Accuracy value for the current period. - /// - /// - /// This method calculates the Mean Directional Accuracy using the formula: - /// MDA = (number of correct directional predictions / total number of predictions) * 100 - /// A correct directional prediction is when the sign of the actual change matches - /// the sign of the predicted change. - /// The result is expressed as a percentage, where 100% indicates perfect directional accuracy - /// and 50% indicates performance no better than random guessing. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -90,46 +47,27 @@ public class Mda : AbstractBase double actual = Input.Value; _actualBuffer.Add(actual, Input.IsNew); - double forecast = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value; - _forecastBuffer.Add(forecast, Input.IsNew); + double predicted = double.IsNaN(Input2.Value) ? _actualBuffer.Average() : Input2.Value; + _predictedBuffer.Add(predicted, Input.IsNew); double mda = 0; - if (_actualBuffer.Count > 1) + if (_actualBuffer.Count > 0) { var actualValues = _actualBuffer.GetSpan().ToArray(); - var forecastValues = _forecastBuffer.GetSpan().ToArray(); + var predictedValues = _predictedBuffer.GetSpan().ToArray(); - int correctPredictions = 0; - int totalPredictions = actualValues.Length - 1; - - for (int i = 1; i < actualValues.Length; i++) + double sumDirectionalAccuracy = 0; + for (int i = 1; i < _actualBuffer.Count; i++) { - double actualChange = actualValues[i] - actualValues[i - 1]; - double forecastChange = forecastValues[i] - actualValues[i - 1]; - - if ((actualChange >= 0 && forecastChange >= 0) || (actualChange < 0 && forecastChange < 0)) - { - correctPredictions++; - } + double actualDirection = Math.Sign(actualValues[i] - actualValues[i - 1]); + double predictedDirection = Math.Sign(predictedValues[i] - predictedValues[i - 1]); + sumDirectionalAccuracy += (actualDirection == predictedDirection) ? 1 : 0; } - mda = (double)correctPredictions / totalPredictions * 100; + mda = sumDirectionalAccuracy / (_actualBuffer.Count - 1); } - IsHot = _actualBuffer.Count > 1; // MDA calc is valid from bar 2 + IsHot = _index >= WarmupPeriod; return mda; } - - /// - /// Calculates the Mean Directional Accuracy for the given actual and forecast values. - /// - /// The actual value. - /// The forecast value. - /// The calculated Mean Directional Accuracy. - public double Calc(double actual, double forecast) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, forecast); - return Calculation(); - } } diff --git a/lib/errors/Me.cs b/lib/errors/Me.cs index e6356f79..a9118b39 100644 --- a/lib/errors/Me.cs +++ b/lib/errors/Me.cs @@ -1,25 +1,10 @@ namespace QuanTAlib; -/// -/// Represents a Mean Error calculator that measures the average difference -/// between actual values and predicted values. -/// -/// -/// The Me class calculates the Mean Error using a circular buffer -/// to efficiently manage the data points within the specified period. -/// public class Me : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Me class with the specified period. - /// - /// The period over which to calculate the Mean Error. - /// - /// Thrown when period is less than 1. - /// public Me(int period) { if (period < 1) @@ -33,20 +18,12 @@ public class Me : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mape class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. public Me(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Me instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -54,10 +31,6 @@ public class Me : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Me instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -67,17 +40,6 @@ public class Me : AbstractBase } } - /// - /// Performs the Mean Error calculation for the current period. - /// - /// - /// The calculated Mean Error value for the current period. - /// - /// - /// This method calculates the Mean Error using the formula: - /// ME = sum(actual - predicted) / n - /// where actual is each actual value, predicted is each predicted value, and n is the number of values. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -106,17 +68,4 @@ public class Me : AbstractBase IsHot = _index >= WarmupPeriod; return me; } - - /// - /// Calculates the Mean Error for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Mean Error. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Mpe.cs b/lib/errors/Mpe.cs index a9dd9be6..c9fc3a88 100644 --- a/lib/errors/Mpe.cs +++ b/lib/errors/Mpe.cs @@ -1,25 +1,10 @@ namespace QuanTAlib; -/// -/// Represents a Mean Percentage Error calculator that measures the average percentage difference -/// between actual values and predicted values. -/// -/// -/// The Mpe class calculates the Mean Percentage Error using a circular buffer -/// to efficiently manage the data points within the specified period. -/// public class Mpe : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Mpe class with the specified period. - /// - /// The period over which to calculate the Mean Percentage Error. - /// - /// Thrown when period is less than 1. - /// public Mpe(int period) { if (period < 1) @@ -33,20 +18,12 @@ public class Mpe : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mape class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. public Mpe(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Mpe instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -54,10 +31,6 @@ public class Mpe : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Mpe instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -67,18 +40,6 @@ public class Mpe : AbstractBase } } - /// - /// Performs the Mean Percentage Error calculation for the current period. - /// - /// - /// The calculated Mean Percentage Error value for the current period. - /// - /// - /// This method calculates the Mean Percentage Error using the formula: - /// MPE = (sum((actual - predicted) / actual) / n) * 100 - /// where actual is each actual value, predicted is each predicted value, and n is the number of values. - /// If any actual value is zero, it is excluded from the calculation to avoid division by zero. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -96,37 +57,18 @@ public class Mpe : AbstractBase var predictedValues = _predictedBuffer.GetSpan().ToArray(); double sumPercentageError = 0; - int validCount = 0; - for (int i = 0; i < _actualBuffer.Count; i++) { if (actualValues[i] != 0) { sumPercentageError += (actualValues[i] - predictedValues[i]) / actualValues[i]; - validCount++; } } - if (validCount > 0) - { - mpe = (sumPercentageError / validCount) * 100; - } + mpe = sumPercentageError / _actualBuffer.Count; } IsHot = _index >= WarmupPeriod; return mpe; } - - /// - /// Calculates the Mean Percentage Error for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Mean Percentage Error. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Mse.cs b/lib/errors/Mse.cs index fcde24ac..7a3e33b2 100644 --- a/lib/errors/Mse.cs +++ b/lib/errors/Mse.cs @@ -34,16 +34,16 @@ public class Mse : AbstractBase } /// - /// Initializes a new instance of the Mape class with the specified source and period. + /// Initializes a new instance of the Mse class with the specified source and period. /// /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. + /// The period over which to calculate the Mean Squared Error. public Mse(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - + /// /// Initializes the Mse instance by clearing the buffers. /// @@ -54,7 +54,6 @@ public class Mse : AbstractBase _predictedBuffer.Clear(); } - /// /// Manages the state of the Mse instance based on whether new values are being processed. /// @@ -108,17 +107,4 @@ public class Mse : AbstractBase IsHot = _index >= WarmupPeriod; return mse; } - - /// - /// Calculates the Mean Squared Error for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Mean Squared Error. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - _lastValidValue = predicted; - return Calculation(); - } } diff --git a/lib/errors/Msle.cs b/lib/errors/Msle.cs index 524b9c28..464f4e10 100644 --- a/lib/errors/Msle.cs +++ b/lib/errors/Msle.cs @@ -1,25 +1,10 @@ namespace QuanTAlib; -/// -/// Represents a Mean Squared Logarithmic Error calculator that measures the average of the squares -/// of the differences between the logarithms of actual values and predicted values. -/// -/// -/// The Msle class calculates the Mean Squared Logarithmic Error using a circular buffer -/// to efficiently manage the data points within the specified period. -/// public class Msle : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Msle class with the specified period. - /// - /// The period over which to calculate the Mean Squared Logarithmic Error. - /// - /// Thrown when period is less than 1. - /// public Msle(int period) { if (period < 1) @@ -33,20 +18,12 @@ public class Msle : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mape class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. public Msle(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Msle instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -54,10 +31,6 @@ public class Msle : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Msle instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -67,18 +40,6 @@ public class Msle : AbstractBase } } - /// - /// Performs the Mean Squared Logarithmic Error calculation for the current period. - /// - /// - /// The calculated Mean Squared Logarithmic Error value for the current period. - /// - /// - /// This method calculates the Mean Squared Logarithmic Error using the formula: - /// MSLE = sum((log(actual + 1) - log(predicted + 1))^2) / n - /// where actual is each actual value, predicted is each predicted value, and n is the number of values. - /// We add 1 to both actual and predicted values to avoid taking the log of zero. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -100,8 +61,8 @@ public class Msle : AbstractBase { double logActual = Math.Log(actualValues[i] + 1); double logPredicted = Math.Log(predictedValues[i] + 1); - double logError = logActual - logPredicted; - sumSquaredLogError += logError * logError; + double error = logActual - logPredicted; + sumSquaredLogError += error * error; } msle = sumSquaredLogError / _actualBuffer.Count; @@ -110,17 +71,4 @@ public class Msle : AbstractBase IsHot = _index >= WarmupPeriod; return msle; } - - /// - /// Calculates the Mean Squared Logarithmic Error for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Mean Squared Logarithmic Error. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Rae.cs b/lib/errors/Rae.cs index 532b397a..6b25a161 100644 --- a/lib/errors/Rae.cs +++ b/lib/errors/Rae.cs @@ -1,30 +1,15 @@ namespace QuanTAlib; -/// -/// Represents a Relative Absolute Error calculator that measures the ratio of the sum of absolute errors -/// to the sum of absolute differences between actual values and the mean of actual values. -/// -/// -/// The Rae class calculates the Relative Absolute Error using circular buffers -/// to efficiently manage the data points within the specified period. -/// public class Rae : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Rae class with the specified period. - /// - /// The period over which to calculate the Relative Absolute Error. - /// - /// Thrown when period is less than 2. - /// public Rae(int period) { - if (period < 2) + if (period < 1) { - throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2."); + throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1."); } WarmupPeriod = period; _actualBuffer = new CircularBuffer(period); @@ -33,20 +18,12 @@ public class Rae : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mape class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. public Rae(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Rae instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -54,10 +31,6 @@ public class Rae : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Rae instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -67,17 +40,6 @@ public class Rae : AbstractBase } } - /// - /// Performs the Relative Absolute Error calculation for the current period. - /// - /// - /// The calculated Relative Absolute Error value for the current period. - /// - /// - /// This method calculates the Relative Absolute Error using the formula: - /// RAE = sum(|actual - predicted|) / sum(|actual - mean(actual)|) - /// where actual is each actual value, predicted is each predicted value, and mean(actual) is the average of actual values. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -89,41 +51,23 @@ public class Rae : AbstractBase _predictedBuffer.Add(predicted, Input.IsNew); double rae = 0; - if (_actualBuffer.Count >= 2) + if (_actualBuffer.Count > 0) { var actualValues = _actualBuffer.GetSpan().ToArray(); var predictedValues = _predictedBuffer.GetSpan().ToArray(); - double actualMean = actualValues.Average(); double sumAbsoluteError = 0; - double sumAbsoluteDifferenceFromMean = 0; - + double sumAbsoluteActual = 0; for (int i = 0; i < _actualBuffer.Count; i++) { sumAbsoluteError += Math.Abs(actualValues[i] - predictedValues[i]); - sumAbsoluteDifferenceFromMean += Math.Abs(actualValues[i] - actualMean); + sumAbsoluteActual += Math.Abs(actualValues[i]); } - if (sumAbsoluteDifferenceFromMean != 0) - { - rae = sumAbsoluteError / sumAbsoluteDifferenceFromMean; - } + rae = sumAbsoluteError / sumAbsoluteActual; } IsHot = _index >= WarmupPeriod; return rae; } - - /// - /// Calculates the Relative Absolute Error for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Relative Absolute Error. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Rmse.cs b/lib/errors/Rmse.cs index 98c30097..ba56b346 100644 --- a/lib/errors/Rmse.cs +++ b/lib/errors/Rmse.cs @@ -1,25 +1,10 @@ namespace QuanTAlib; -/// -/// Represents a Root Mean Squared Error calculator that measures the square root of the average -/// of the squares of the differences between actual values and predicted values. -/// -/// -/// The Rmse class calculates the Root Mean Squared Error using a circular buffer -/// to efficiently manage the data points within the specified period. -/// public class Rmse : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Rmse class with the specified period. - /// - /// The period over which to calculate the Root Mean Squared Error. - /// - /// Thrown when period is less than 1. - /// public Rmse(int period) { if (period < 1) @@ -33,19 +18,12 @@ public class Rmse : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mape class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. public Rmse(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Rmse instance by clearing the buffers. - /// + public override void Init() { base.Init(); @@ -53,10 +31,6 @@ public class Rmse : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Rmse instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -66,17 +40,6 @@ public class Rmse : AbstractBase } } - /// - /// Performs the Root Mean Squared Error calculation for the current period. - /// - /// - /// The calculated Root Mean Squared Error value for the current period. - /// - /// - /// This method calculates the Root Mean Squared Error using the formula: - /// RMSE = sqrt(sum((actual - predicted)^2) / n) - /// where actual is each actual value, predicted is each predicted value, and n is the number of values. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -106,17 +69,4 @@ public class Rmse : AbstractBase IsHot = _index >= WarmupPeriod; return rmse; } - - /// - /// Calculates the Root Mean Squared Error for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Root Mean Squared Error. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Rmsle.cs b/lib/errors/Rmsle.cs index ed23cd34..cfeb4e35 100644 --- a/lib/errors/Rmsle.cs +++ b/lib/errors/Rmsle.cs @@ -1,25 +1,10 @@ namespace QuanTAlib; -/// -/// Represents a Root Mean Squared Logarithmic Error calculator that measures the square root of the average -/// of the squares of the differences between the logarithms of actual values and predicted values. -/// -/// -/// The Rmsle class calculates the Root Mean Squared Logarithmic Error using a circular buffer -/// to efficiently manage the data points within the specified period. -/// public class Rmsle : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Rmsle class with the specified period. - /// - /// The period over which to calculate the Root Mean Squared Logarithmic Error. - /// - /// Thrown when period is less than 1. - /// public Rmsle(int period) { if (period < 1) @@ -33,20 +18,12 @@ public class Rmsle : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mape class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. public Rmsle(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Rmsle instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -54,10 +31,6 @@ public class Rmsle : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Rmsle instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -67,18 +40,6 @@ public class Rmsle : AbstractBase } } - /// - /// Performs the Root Mean Squared Logarithmic Error calculation for the current period. - /// - /// - /// The calculated Root Mean Squared Logarithmic Error value for the current period. - /// - /// - /// This method calculates the Root Mean Squared Logarithmic Error using the formula: - /// RMSLE = sqrt(sum((log(actual + 1) - log(predicted + 1))^2) / n) - /// where actual is each actual value, predicted is each predicted value, and n is the number of values. - /// We add 1 to both actual and predicted values to avoid taking the log of zero. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -100,8 +61,8 @@ public class Rmsle : AbstractBase { double logActual = Math.Log(actualValues[i] + 1); double logPredicted = Math.Log(predictedValues[i] + 1); - double logError = logActual - logPredicted; - sumSquaredLogError += logError * logError; + double error = logActual - logPredicted; + sumSquaredLogError += error * error; } rmsle = Math.Sqrt(sumSquaredLogError / _actualBuffer.Count); @@ -110,17 +71,4 @@ public class Rmsle : AbstractBase IsHot = _index >= WarmupPeriod; return rmsle; } - - /// - /// Calculates the Root Mean Squared Logarithmic Error for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Root Mean Squared Logarithmic Error. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Rse.cs b/lib/errors/Rse.cs index 49203f86..dc26bc95 100644 --- a/lib/errors/Rse.cs +++ b/lib/errors/Rse.cs @@ -1,30 +1,15 @@ namespace QuanTAlib; -/// -/// Represents a Relative Squared Error calculator that measures the ratio of the sum of squared errors -/// to the sum of squared differences between actual values and the mean of actual values. -/// -/// -/// The Rse class calculates the Relative Squared Error using circular buffers -/// to efficiently manage the data points within the specified period. -/// public class Rse : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Rse class with the specified period. - /// - /// The period over which to calculate the Relative Squared Error. - /// - /// Thrown when period is less than 2. - /// public Rse(int period) { - if (period < 2) + if (period < 1) { - throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2."); + throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1."); } WarmupPeriod = period; _actualBuffer = new CircularBuffer(period); @@ -33,20 +18,12 @@ public class Rse : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mape class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. public Rse(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Rse instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -54,10 +31,6 @@ public class Rse : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Rse instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -67,17 +40,6 @@ public class Rse : AbstractBase } } - /// - /// Performs the Relative Squared Error calculation for the current period. - /// - /// - /// The calculated Relative Squared Error value for the current period. - /// - /// - /// This method calculates the Relative Squared Error using the formula: - /// RSE = sum((actual - predicted)^2) / sum((actual - mean(actual))^2) - /// where actual is each actual value, predicted is each predicted value, and mean(actual) is the average of actual values. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -89,44 +51,27 @@ public class Rse : AbstractBase _predictedBuffer.Add(predicted, Input.IsNew); double rse = 0; - if (_actualBuffer.Count >= 2) + if (_actualBuffer.Count > 0) { var actualValues = _actualBuffer.GetSpan().ToArray(); var predictedValues = _predictedBuffer.GetSpan().ToArray(); - double actualMean = actualValues.Average(); double sumSquaredError = 0; - double sumSquaredDifferenceFromMean = 0; + double sumSquaredActual = 0; + double meanActual = actualValues.Average(); for (int i = 0; i < _actualBuffer.Count; i++) { double error = actualValues[i] - predictedValues[i]; sumSquaredError += error * error; - - double differenceFromMean = actualValues[i] - actualMean; - sumSquaredDifferenceFromMean += differenceFromMean * differenceFromMean; + double deviation = actualValues[i] - meanActual; + sumSquaredActual += deviation * deviation; } - if (sumSquaredDifferenceFromMean != 0) - { - rse = sumSquaredError / sumSquaredDifferenceFromMean; - } + rse = Math.Sqrt(sumSquaredError / sumSquaredActual); } IsHot = _index >= WarmupPeriod; return rse; } - - /// - /// Calculates the Relative Squared Error for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Relative Squared Error. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Rsquared.cs b/lib/errors/Rsquared.cs index 16fd695e..e6213cb1 100644 --- a/lib/errors/Rsquared.cs +++ b/lib/errors/Rsquared.cs @@ -1,30 +1,15 @@ namespace QuanTAlib; -/// -/// Represents a Coefficient of Determination (R-squared) calculator that measures the proportion of -/// the variance in the dependent variable that is predictable from the independent variable(s). -/// -/// -/// The Rsquared class calculates the Coefficient of Determination using circular buffers -/// to efficiently manage the actual and predicted data points within the specified period. -/// public class Rsquared : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Rsquared class with the specified period. - /// - /// The period over which to calculate the Coefficient of Determination. - /// - /// Thrown when period is less than 2. - /// public Rsquared(int period) { - if (period < 2) + if (period < 1) { - throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2."); + throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1."); } WarmupPeriod = period; _actualBuffer = new CircularBuffer(period); @@ -33,20 +18,12 @@ public class Rsquared : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mape class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. public Rsquared(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Rsquared instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -54,10 +31,6 @@ public class Rsquared : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Rsquared instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -67,17 +40,6 @@ public class Rsquared : AbstractBase } } - /// - /// Performs the Coefficient of Determination calculation for the current period. - /// - /// - /// The calculated Coefficient of Determination value for the current period. - /// - /// - /// This method calculates the Coefficient of Determination using the formula: - /// R^2 = 1 - (SSres / SStot) - /// where SSres is the sum of squared residuals and SStot is the total sum of squares. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -89,44 +51,30 @@ public class Rsquared : AbstractBase _predictedBuffer.Add(predicted, Input.IsNew); double rsquared = 0; - if (_actualBuffer.Count >= 2) + if (_actualBuffer.Count > 0) { var actualValues = _actualBuffer.GetSpan().ToArray(); var predictedValues = _predictedBuffer.GetSpan().ToArray(); - double actualMean = actualValues.Average(); - double ssRes = 0; - double ssTot = 0; + double meanActual = actualValues.Average(); + double sumSquaredTotal = 0; + double sumSquaredResidual = 0; for (int i = 0; i < _actualBuffer.Count; i++) { - double residual = actualValues[i] - predictedValues[i]; - ssRes += residual * residual; - - double deviation = actualValues[i] - actualMean; - ssTot += deviation * deviation; + double deviation = actualValues[i] - meanActual; + sumSquaredTotal += deviation * deviation; + double error = actualValues[i] - predictedValues[i]; + sumSquaredResidual += error * error; } - if (ssTot != 0) + if (sumSquaredTotal != 0) { - rsquared = 1 - (ssRes / ssTot); + rsquared = 1 - (sumSquaredResidual / sumSquaredTotal); } } IsHot = _index >= WarmupPeriod; return rsquared; } - - /// - /// Calculates the Coefficient of Determination for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Coefficient of Determination. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/lib/errors/Smape.cs b/lib/errors/Smape.cs index 292b93b7..869ac820 100644 --- a/lib/errors/Smape.cs +++ b/lib/errors/Smape.cs @@ -1,25 +1,10 @@ namespace QuanTAlib; -/// -/// Represents a Symmetric Mean Absolute Percentage Error calculator that measures the percentage difference -/// between actual and predicted values, using a symmetric formula to handle both positive and negative errors equally. -/// -/// -/// The Smape class calculates the Symmetric Mean Absolute Percentage Error using circular buffers -/// to efficiently manage the data points within the specified period. -/// public class Smape : AbstractBase { private readonly CircularBuffer _actualBuffer; private readonly CircularBuffer _predictedBuffer; - /// - /// Initializes a new instance of the Smape class with the specified period. - /// - /// The period over which to calculate the Symmetric Mean Absolute Percentage Error. - /// - /// Thrown when period is less than 1. - /// public Smape(int period) { if (period < 1) @@ -33,20 +18,12 @@ public class Smape : AbstractBase Init(); } - /// - /// Initializes a new instance of the Mape class with the specified source and period. - /// - /// The source object to subscribe to for value updates. - /// The period over which to calculate the Mean Absolute Percentage Error. public Smape(object source, int period) : this(period) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - /// - /// Initializes the Smape instance by clearing the buffers. - /// public override void Init() { base.Init(); @@ -54,10 +31,6 @@ public class Smape : AbstractBase _predictedBuffer.Clear(); } - /// - /// Manages the state of the Smape instance based on whether new values are being processed. - /// - /// Indicates whether the current inputs are new values. protected override void ManageState(bool isNew) { if (isNew) @@ -67,17 +40,6 @@ public class Smape : AbstractBase } } - /// - /// Performs the Symmetric Mean Absolute Percentage Error calculation for the current period. - /// - /// - /// The calculated Symmetric Mean Absolute Percentage Error value for the current period. - /// - /// - /// This method calculates the Symmetric Mean Absolute Percentage Error using the formula: - /// SMAPE = (100% / n) * sum(2 * |actual - predicted| / (|actual| + |predicted|)) - /// where actual is each actual value, predicted is each predicted value, and n is the number of values. - /// protected override double Calculation() { ManageState(Input.IsNew); @@ -94,7 +56,7 @@ public class Smape : AbstractBase var actualValues = _actualBuffer.GetSpan().ToArray(); var predictedValues = _predictedBuffer.GetSpan().ToArray(); - double sumSymmetricPercentageError = 0; + double sumSymmetricAbsolutePercentageError = 0; int validCount = 0; for (int i = 0; i < _actualBuffer.Count; i++) @@ -102,31 +64,15 @@ public class Smape : AbstractBase double denominator = Math.Abs(actualValues[i]) + Math.Abs(predictedValues[i]); if (denominator != 0) { - sumSymmetricPercentageError += 2 * Math.Abs(actualValues[i] - predictedValues[i]) / denominator; + sumSymmetricAbsolutePercentageError += Math.Abs(actualValues[i] - predictedValues[i]) / denominator; validCount++; } } - if (validCount > 0) - { - smape = (100.0 / validCount) * sumSymmetricPercentageError; - } + smape = validCount > 0 ? (200 * sumSymmetricAbsolutePercentageError / validCount) : 0; } IsHot = _index >= WarmupPeriod; return smape; } - - /// - /// Calculates the Symmetric Mean Absolute Percentage Error for the given actual and predicted values. - /// - /// The actual value. - /// The predicted value. - /// The calculated Symmetric Mean Absolute Percentage Error. - public double Calc(double actual, double predicted) - { - Input = new TValue(DateTime.Now, actual); - Input2 = new TValue(DateTime.Now, predicted); - return Calculation(); - } } diff --git a/quantower/Averages/AfirmaIndicator.cs b/quantower/Averages/AfirmaIndicator.cs index c3f3fc75..a094c320 100644 --- a/quantower/Averages/AfirmaIndicator.cs +++ b/quantower/Averages/AfirmaIndicator.cs @@ -34,6 +34,8 @@ public class AfirmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; private Afirma? ma; protected LineSeries? Series; protected string? SourceName; @@ -47,6 +49,7 @@ public class AfirmaIndicator : Indicator, IWatchlistIndicator SourceName = Source.ToString(); Name = "AFIRMA - Adaptive Finite Impulse Response Moving Average"; Description = "Adaptive Finite Impulse Response Moving Average with ARMA component"; + Series = new(name: $"AFIRMA {Taps}:{Periods}:{Window}", color: Color.Yellow, width: 2, style: LineStyle.Solid); AddLineSeries(Series); } @@ -63,9 +66,17 @@ public class AfirmaIndicator : Indicator, IWatchlistIndicator TValue input = this.GetInputValue(args, Source); TValue result = ma!.Calc(input); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here Series!.SetValue(result.Value); } public override string ShortName => $"AFIRMA {Taps}:{Periods}:{Window}:{SourceName}"; + + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/AlmaIndicator.cs b/quantower/Averages/AlmaIndicator.cs index bc8781d1..50b49d30 100644 --- a/quantower/Averages/AlmaIndicator.cs +++ b/quantower/Averages/AlmaIndicator.cs @@ -8,10 +8,10 @@ public class AlmaIndicator : Indicator, IWatchlistIndicator [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)] public int Period { get; set; } = 10; - [InputParameter("Offset", sortIndex: 2)] + [InputParameter("Offset", sortIndex: 2, minimum: 0, maximum: 1, decimalPlaces: 2)] public double Offset { get; set; } = 0.85; - [InputParameter("Sigma", sortIndex: 3)] + [InputParameter("Sigma", sortIndex: 3, minimum: 0, maximum: 100, decimalPlaces: 1)] public double Sigma { get; set; } = 6.0; [InputParameter("Data source", sortIndex: 4, variants: [ @@ -28,12 +28,17 @@ public class AlmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Alma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Period; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"ALMA {Period}:{Offset:F2}:{Sigma:F1}:{SourceName}"; + public AlmaIndicator() { OnBackGround = true; @@ -58,7 +63,13 @@ public class AlmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"ALMA {Period}:{Offset:F2}:{Sigma:F0}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/DemaIndicator.cs b/quantower/Averages/DemaIndicator.cs index d7777af1..7ca1824f 100644 --- a/quantower/Averages/DemaIndicator.cs +++ b/quantower/Averages/DemaIndicator.cs @@ -22,12 +22,17 @@ public class DemaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Dema? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Period; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"DEMA {Period}:{SourceName}"; + public DemaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class DemaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"DEMA {Period}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/DsmaIndicator.cs b/quantower/Averages/DsmaIndicator.cs index b860bb62..8c22a636 100644 --- a/quantower/Averages/DsmaIndicator.cs +++ b/quantower/Averages/DsmaIndicator.cs @@ -25,12 +25,17 @@ public class DsmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Dsma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths { get; private set; } int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"DSMA {Period}:{Scale:F2}:{SourceName}"; + public DsmaIndicator() { OnBackGround = true; @@ -56,8 +61,13 @@ public class DsmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"DSMA {Period}:{Scale:F2}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } - diff --git a/quantower/Averages/DwmaIndicator.cs b/quantower/Averages/DwmaIndicator.cs index a78292ea..6b195215 100644 --- a/quantower/Averages/DwmaIndicator.cs +++ b/quantower/Averages/DwmaIndicator.cs @@ -22,12 +22,17 @@ public class DwmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Dwma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Period; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"DWMA {Period}:{SourceName}"; + public DwmaIndicator() { OnBackGround = true; @@ -52,8 +57,13 @@ public class DwmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"DWMA {Period}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } - diff --git a/quantower/Averages/EmaIndicator.cs b/quantower/Averages/EmaIndicator.cs index 657388d8..3e16cd9b 100644 --- a/quantower/Averages/EmaIndicator.cs +++ b/quantower/Averages/EmaIndicator.cs @@ -6,9 +6,11 @@ namespace QuanTAlib; public class EmaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] - public int Periods { get; set; } = 14; + public int Periods { get; set; } = 10; + [InputParameter("Use SMA for warmup period", sortIndex: 2)] + public bool UseSMA { get; set; } = false; - [InputParameter("Data source", sortIndex: 2, variants: [ + [InputParameter("Data source", sortIndex: 3, variants: [ "Open", SourceType.Open, "High", SourceType.High, "Low", SourceType.Low, @@ -22,12 +24,17 @@ public class EmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Ema? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"EMA {Periods}:{SourceName}"; + public EmaIndicator() { OnBackGround = true; @@ -41,7 +48,7 @@ public class EmaIndicator : Indicator, IWatchlistIndicator protected override void OnInit() { - ma = new Ema(Periods); + ma = new Ema(Periods, useSma: UseSMA); SourceName = Source.ToString(); base.OnInit(); } @@ -52,7 +59,13 @@ public class EmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"EMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/EpmaIndicator.cs b/quantower/Averages/EpmaIndicator.cs index e5fdad82..39aad553 100644 --- a/quantower/Averages/EpmaIndicator.cs +++ b/quantower/Averages/EpmaIndicator.cs @@ -6,7 +6,7 @@ namespace QuanTAlib; public class EpmaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] - public int Periods { get; set; } = 14; + public int Periods { get; set; } = 10; [InputParameter("Data source", sortIndex: 2, variants: [ "Open", SourceType.Open, @@ -22,12 +22,17 @@ public class EpmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Epma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"EPMA {Periods}:{SourceName}"; + public EpmaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class EpmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"EPMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/FramaIndicator.cs b/quantower/Averages/FramaIndicator.cs index df848cd8..ddcceede 100644 --- a/quantower/Averages/FramaIndicator.cs +++ b/quantower/Averages/FramaIndicator.cs @@ -6,7 +6,7 @@ namespace QuanTAlib; public class FramaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)] - public int Periods { get; set; } = 14; + public int Periods { get; set; } = 10; [InputParameter("Data source", sortIndex: 2, variants: [ "Open", SourceType.Open, @@ -22,12 +22,17 @@ public class FramaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Frama? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods * 2; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"FRAMA {Periods}:{SourceName}"; + public FramaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class FramaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"FRAMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/FwmaIndicator.cs b/quantower/Averages/FwmaIndicator.cs index 4a9af703..bb9c89a1 100644 --- a/quantower/Averages/FwmaIndicator.cs +++ b/quantower/Averages/FwmaIndicator.cs @@ -6,7 +6,7 @@ namespace QuanTAlib; public class FwmaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] - public int Periods { get; set; } = 14; + public int Periods { get; set; } = 10; [InputParameter("Data source", sortIndex: 2, variants: [ "Open", SourceType.Open, @@ -22,12 +22,17 @@ public class FwmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Fwma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"FWMA {Periods}:{SourceName}"; + public FwmaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class FwmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"FWMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/GmaIndicator.cs b/quantower/Averages/GmaIndicator.cs index 6bc0453f..f4cfce92 100644 --- a/quantower/Averages/GmaIndicator.cs +++ b/quantower/Averages/GmaIndicator.cs @@ -6,10 +6,7 @@ namespace QuanTAlib; public class GmaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] - public int Periods { get; set; } = 14; - - [InputParameter("Sigma", sortIndex: 2, 0.1, 10, 0.1, 1)] - public double Sigma { get; set; } = 1.0; + public int Periods { get; set; } = 10; [InputParameter("Data source", sortIndex: 3, variants: [ "Open", SourceType.Open, @@ -25,12 +22,17 @@ public class GmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Gma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"GMA {Periods}:{SourceName}"; + public GmaIndicator() { OnBackGround = true; @@ -55,7 +57,13 @@ public class GmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"GMA {Periods}:{Sigma}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/HmaIndicator.cs b/quantower/Averages/HmaIndicator.cs index 842f327f..e9241249 100644 --- a/quantower/Averages/HmaIndicator.cs +++ b/quantower/Averages/HmaIndicator.cs @@ -6,7 +6,7 @@ namespace QuanTAlib; public class HmaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)] - public int Periods { get; set; } = 14; + public int Periods { get; set; } = 10; [InputParameter("Data source", sortIndex: 2, variants: [ "Open", SourceType.Open, @@ -22,12 +22,17 @@ public class HmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Hma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods + (int)Math.Sqrt(Periods) - 1; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"HMA {Periods}:{SourceName}"; + public HmaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class HmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"HMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/HtitIndicator.cs b/quantower/Averages/HtitIndicator.cs index bf1b1f8a..411d8afa 100644 --- a/quantower/Averages/HtitIndicator.cs +++ b/quantower/Averages/HtitIndicator.cs @@ -19,12 +19,17 @@ public class HtitIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Htit? ma; protected LineSeries? Series; protected string? SourceName; - public int MinHistoryDepths => 12; // Based on WarmupPeriod in Htit + public static int MinHistoryDepths => 12; // Based on WarmupPeriod in Htit int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"HTIT:{SourceName}"; + public HtitIndicator() { OnBackGround = true; @@ -49,7 +54,13 @@ public class HtitIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"HTIT:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/HwmaIndicator.cs b/quantower/Averages/HwmaIndicator.cs index fd76600a..de81b817 100644 --- a/quantower/Averages/HwmaIndicator.cs +++ b/quantower/Averages/HwmaIndicator.cs @@ -5,8 +5,8 @@ namespace QuanTAlib; public class HwmaIndicator : Indicator, IWatchlistIndicator { - [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] - public int Periods { get; set; } = 14; + [InputParameter("Periods (only when nA=nB=nC=0)", sortIndex: 1, 1, 1000, 1, 0)] + public int Periods { get; set; } = 10; [InputParameter("nA", sortIndex: 2, 0, 1, 0.01, 2)] public double NA { get; set; } = 0; @@ -31,12 +31,17 @@ public class HwmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Hwma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"HWMA {Periods}:{NA}:{NB}:{NC}:{SourceName}"; + public HwmaIndicator() { OnBackGround = true; @@ -68,7 +73,13 @@ public class HwmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"HWMA {Periods}:{NA}:{NB}:{NC}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/JmaIndicator.cs b/quantower/Averages/JmaIndicator.cs index 777ec8ee..049aa19a 100644 --- a/quantower/Averages/JmaIndicator.cs +++ b/quantower/Averages/JmaIndicator.cs @@ -6,14 +6,11 @@ namespace QuanTAlib; public class JmaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] - public int Periods { get; set; } = 14; + public int Periods { get; set; } = 10; [InputParameter("Phase", sortIndex: 2, -100, 100, 1, 0)] public double Phase { get; set; } = 0; - [InputParameter("VShort", sortIndex: 3, 1, 100, 1, 0)] - public int VShort { get; set; } = 10; - [InputParameter("Data source", sortIndex: 4, variants: [ "Open", SourceType.Open, "High", SourceType.High, @@ -28,12 +25,17 @@ public class JmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Jma? ma; protected LineSeries? Series; protected string? SourceName; - public int MinHistoryDepths => Periods * 2; + public int MinHistoryDepths => Math.Max(65,Periods * 2); int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"JMA {Periods}:{Phase}:{SourceName}"; + public JmaIndicator() { OnBackGround = true; @@ -47,7 +49,7 @@ public class JmaIndicator : Indicator, IWatchlistIndicator protected override void OnInit() { - ma = new Jma(Periods, Phase, VShort); + ma = new Jma(Periods, Phase); SourceName = Source.ToString(); base.OnInit(); } @@ -58,7 +60,13 @@ public class JmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"JMA {Periods}:{Phase}:{VShort}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/KamaIndicator.cs b/quantower/Averages/KamaIndicator.cs index c6ba1abb..dfc14a90 100644 --- a/quantower/Averages/KamaIndicator.cs +++ b/quantower/Averages/KamaIndicator.cs @@ -6,7 +6,7 @@ namespace QuanTAlib; public class KamaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] - public int Periods { get; set; } = 14; + public int Periods { get; set; } = 10; [InputParameter("Fast", sortIndex: 2, 1, 100, 1, 0)] public int Fast { get; set; } = 2; @@ -28,12 +28,17 @@ public class KamaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Kama? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"KAMA {Periods}:{Fast}:{Slow}:{SourceName}"; + public KamaIndicator() { OnBackGround = true; @@ -58,7 +63,13 @@ public class KamaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"KAMA {Periods}:{Fast}:{Slow}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/LtmaIndicator.cs b/quantower/Averages/LtmaIndicator.cs index 9682a3fe..77f2f868 100644 --- a/quantower/Averages/LtmaIndicator.cs +++ b/quantower/Averages/LtmaIndicator.cs @@ -22,12 +22,17 @@ public class LtmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Ltma? ma; protected LineSeries? Series; protected string? SourceName; - public int MinHistoryDepths => 4; // Based on WarmupPeriod in Ltma + public static int MinHistoryDepths => 4; // Based on WarmupPeriod in Ltma int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"LTMA {Gamma}:{SourceName}"; + public LtmaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class LtmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"LTMA {Gamma}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/MaafIndicator.cs b/quantower/Averages/MaafIndicator.cs index 7cde3f58..fc474704 100644 --- a/quantower/Averages/MaafIndicator.cs +++ b/quantower/Averages/MaafIndicator.cs @@ -6,7 +6,7 @@ namespace QuanTAlib; public class MaafIndicator : Indicator, IWatchlistIndicator { [InputParameter("Periods", sortIndex: 1, 3, 1000, 1, 0)] - public int Periods { get; set; } = 39; + public int Periods { get; set; } = 10; [InputParameter("Threshold", sortIndex: 2, 0.0001, 0.1, 0.0001, 4)] public double Threshold { get; set; } = 0.002; @@ -25,12 +25,17 @@ public class MaafIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Maaf? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"MAAF {Periods}:{Threshold}:{SourceName}"; + public MaafIndicator() { OnBackGround = true; @@ -55,7 +60,13 @@ public class MaafIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"MAAF {Periods}:{Threshold}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/MamaIndicator.cs b/quantower/Averages/MamaIndicator.cs index 0c19be79..39b31438 100644 --- a/quantower/Averages/MamaIndicator.cs +++ b/quantower/Averages/MamaIndicator.cs @@ -25,13 +25,18 @@ public class MamaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Mama? ma; protected LineSeries? MamaSeries; protected LineSeries? FamaSeries; protected string? SourceName; - public int MinHistoryDepths => 6; + public static int MinHistoryDepths => 6; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"MAMA {FastLimit}:{SlowLimit}:{SourceName}"; + public MamaIndicator() { OnBackGround = true; @@ -58,8 +63,16 @@ public class MamaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); MamaSeries!.SetValue(result.Value); + MamaSeries!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here FamaSeries!.SetValue(ma.Fama.Value); + FamaSeries!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"MAMA {FastLimit}:{SlowLimit}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, MamaSeries!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.PaintSmoothCurve(args, FamaSeries!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/MgdiIndicator.cs b/quantower/Averages/MgdiIndicator.cs index f8ea96df..7a865b5b 100644 --- a/quantower/Averages/MgdiIndicator.cs +++ b/quantower/Averages/MgdiIndicator.cs @@ -25,12 +25,17 @@ public class MgdiIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Mgdi? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"MGDI {Periods}:{KFactor}:{SourceName}"; + public MgdiIndicator() { OnBackGround = true; @@ -55,7 +60,13 @@ public class MgdiIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"MGDI {Periods}:{KFactor}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/MmaIndicator.cs b/quantower/Averages/MmaIndicator.cs index 71e59448..c7701c74 100644 --- a/quantower/Averages/MmaIndicator.cs +++ b/quantower/Averages/MmaIndicator.cs @@ -22,12 +22,17 @@ public class MmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Mma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"MMA {Periods}:{SourceName}"; + public MmaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class MmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"MMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/PwmaIndicator.cs b/quantower/Averages/PwmaIndicator.cs index 950dc051..14eb349d 100644 --- a/quantower/Averages/PwmaIndicator.cs +++ b/quantower/Averages/PwmaIndicator.cs @@ -22,12 +22,17 @@ public class PwmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Pwma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"PWMA {Periods}:{SourceName}"; + public PwmaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class PwmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"PWMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/QemaIndicator.cs b/quantower/Averages/QemaIndicator.cs index 5ce7d79d..d9a114eb 100644 --- a/quantower/Averages/QemaIndicator.cs +++ b/quantower/Averages/QemaIndicator.cs @@ -31,12 +31,17 @@ public class QemaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Qema? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => (int)((2 - Math.Min(Math.Min(K1, K2), Math.Min(K3, K4))) / Math.Min(Math.Min(K1, K2), Math.Min(K3, K4))); int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"QEMA {K1},{K2},{K3},{K4}:{SourceName}"; + public QemaIndicator() { OnBackGround = true; @@ -61,7 +66,13 @@ public class QemaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"QEMA {K1},{K2},{K3},{K4}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/RemaIndicator.cs b/quantower/Averages/RemaIndicator.cs index ea544d08..3197b9bf 100644 --- a/quantower/Averages/RemaIndicator.cs +++ b/quantower/Averages/RemaIndicator.cs @@ -25,12 +25,17 @@ public class RemaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Rema? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"REMA {Periods}:{Lambda}:{SourceName}"; + public RemaIndicator() { OnBackGround = true; @@ -55,7 +60,13 @@ public class RemaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"REMA {Periods}:{Lambda}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/RmaIndicator.cs b/quantower/Averages/RmaIndicator.cs index aadeabfa..b0cf4306 100644 --- a/quantower/Averages/RmaIndicator.cs +++ b/quantower/Averages/RmaIndicator.cs @@ -22,12 +22,17 @@ public class RmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Rma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods * 2; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"RMA {Periods}:{SourceName}"; + public RmaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class RmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"RMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/SinemaIndicator.cs b/quantower/Averages/SinemaIndicator.cs index 306e66ae..0aa8feb8 100644 --- a/quantower/Averages/SinemaIndicator.cs +++ b/quantower/Averages/SinemaIndicator.cs @@ -22,12 +22,17 @@ public class SinemaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Sinema? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"SINEMA {Periods}:{SourceName}"; + public SinemaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class SinemaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"SINEMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/SmaIndicator.cs b/quantower/Averages/SmaIndicator.cs index e71b97ae..692b5545 100644 --- a/quantower/Averages/SmaIndicator.cs +++ b/quantower/Averages/SmaIndicator.cs @@ -6,7 +6,7 @@ namespace QuanTAlib; public class SmaIndicator : Indicator, IWatchlistIndicator { [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)] - public int Periods { get; set; } = 14; + public int Period { get; set; } = 14; [InputParameter("Data source", sortIndex: 2, variants: [ "Open", SourceType.Open, @@ -22,10 +22,14 @@ public class SmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Sma? ma; + private Mape? error; protected LineSeries? Series; protected string? SourceName; - public int MinHistoryDepths => Periods; + public int MinHistoryDepths => Period; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public SmaIndicator() @@ -35,13 +39,14 @@ public class SmaIndicator : Indicator, IWatchlistIndicator SourceName = Source.ToString(); Name = "SMA - Simple Moving Average"; Description = "Simple Moving Average"; - Series = new(name: $"SMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid); + Series = new(name: $"SMA {Period}", color: Color.Yellow, width: 2, style: LineStyle.Solid); AddLineSeries(Series); } protected override void OnInit() { - ma = new Sma(Periods); + ma = new Sma(Period); + error = new(Period); SourceName = Source.ToString(); base.OnInit(); } @@ -50,9 +55,18 @@ public class SmaIndicator : Indicator, IWatchlistIndicator { TValue input = this.GetInputValue(args, Source); TValue result = ma!.Calc(input); + error!.Calc(input, result); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here Series!.SetValue(result.Value); } - public override string ShortName => $"SMA {Periods}:{SourceName}"; + public override string ShortName => $"SMA {Period}:{SourceName}"; + + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, error!.Value.ToString()); + } } diff --git a/quantower/Averages/SmmaIndicator.cs b/quantower/Averages/SmmaIndicator.cs index 675e5c3f..befb1816 100644 --- a/quantower/Averages/SmmaIndicator.cs +++ b/quantower/Averages/SmmaIndicator.cs @@ -22,12 +22,17 @@ public class SmmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Smma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"SMMA {Periods}:{SourceName}"; + public SmmaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class SmmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"SMMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/T3Indicator.cs b/quantower/Averages/T3Indicator.cs index d46f338c..7ab6d14e 100644 --- a/quantower/Averages/T3Indicator.cs +++ b/quantower/Averages/T3Indicator.cs @@ -28,12 +28,17 @@ public class T3Indicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private T3? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"T3 {Periods}:{VolumeFactor}:{UseSma}:{SourceName}"; + public T3Indicator() { OnBackGround = true; @@ -58,7 +63,13 @@ public class T3Indicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"T3 {Periods}:{VolumeFactor}:{UseSma}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/TemaIndicator.cs b/quantower/Averages/TemaIndicator.cs index 208cb0d1..23862874 100644 --- a/quantower/Averages/TemaIndicator.cs +++ b/quantower/Averages/TemaIndicator.cs @@ -22,12 +22,17 @@ public class TemaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Tema? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => (int)Math.Ceiling(-Periods * Math.Log(1 - 0.85)); int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"TEMA {Periods}:{SourceName}"; + public TemaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class TemaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"TEMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/TrimaIndicator.cs b/quantower/Averages/TrimaIndicator.cs index 443331ec..14e477df 100644 --- a/quantower/Averages/TrimaIndicator.cs +++ b/quantower/Averages/TrimaIndicator.cs @@ -22,12 +22,17 @@ public class TrimaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Trima? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"TRIMA {Periods}:{SourceName}"; + public TrimaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class TrimaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"TRIMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/VidyaIndicator.cs b/quantower/Averages/VidyaIndicator.cs index a2b37948..5e411693 100644 --- a/quantower/Averages/VidyaIndicator.cs +++ b/quantower/Averages/VidyaIndicator.cs @@ -28,12 +28,17 @@ public class VidyaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Vidya? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => LongPeriod == 0 ? ShortPeriod * 4 : LongPeriod; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"VIDYA {ShortPeriod}:{LongPeriod}:{Alpha}:{SourceName}"; + public VidyaIndicator() { OnBackGround = true; @@ -58,7 +63,13 @@ public class VidyaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"VIDYA {ShortPeriod}:{LongPeriod}:{Alpha}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/WmaIndicator.cs b/quantower/Averages/WmaIndicator.cs index 1c00b0ec..ba8d8d60 100644 --- a/quantower/Averages/WmaIndicator.cs +++ b/quantower/Averages/WmaIndicator.cs @@ -22,12 +22,17 @@ public class WmaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Wma? ma; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"WMA {Periods}:{SourceName}"; + public WmaIndicator() { OnBackGround = true; @@ -52,7 +57,13 @@ public class WmaIndicator : Indicator, IWatchlistIndicator TValue result = ma!.Calc(input); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"WMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } } diff --git a/quantower/Averages/ZlemaIndicator.cs b/quantower/Averages/ZlemaIndicator.cs index 5ef974ef..a38b9c07 100644 --- a/quantower/Averages/ZlemaIndicator.cs +++ b/quantower/Averages/ZlemaIndicator.cs @@ -22,12 +22,18 @@ public class ZlemaIndicator : Indicator, IWatchlistIndicator ])] public SourceType Source { get; set; } = SourceType.Close; + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + private Zlema? ma; + private Huberloss? err; protected LineSeries? Series; protected string? SourceName; public int MinHistoryDepths => Periods; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + public override string ShortName => $"ZLEMA {Periods}:{SourceName}"; + public ZlemaIndicator() { OnBackGround = true; @@ -41,7 +47,8 @@ public class ZlemaIndicator : Indicator, IWatchlistIndicator protected override void OnInit() { - ma = new Zlema(Periods); + ma = new(Periods); + err = new(Periods); SourceName = Source.ToString(); base.OnInit(); } @@ -50,9 +57,16 @@ public class ZlemaIndicator : Indicator, IWatchlistIndicator { TValue input = this.GetInputValue(args, Source); TValue result = ma!.Calc(input); + err!.Calc(input, result); Series!.SetValue(result.Value); + Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } - public override string ShortName => $"ZLEMA {Periods}:{SourceName}"; + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, err!.Value.ToString()); + } } diff --git a/quantower/IndicatorExtensions.cs b/quantower/IndicatorExtensions.cs index 9de6a9d3..522c4a30 100644 --- a/quantower/IndicatorExtensions.cs +++ b/quantower/IndicatorExtensions.cs @@ -88,7 +88,6 @@ public static class IndicatorExtensions if (allPoints.Count > 1) { - if (allPoints.Count < 2) return; using (Pen defaultPen = new(series.Color, series.Width) { DashStyle = ConvertLineStyleToDashStyle(series.Style) }) @@ -140,7 +139,6 @@ public static class IndicatorExtensions _ => DashStyle.Solid, }; } - } diff --git a/quantower/Statistics/EntropyIndicator.cs b/quantower/Statistics/EntropyIndicator.cs index 6dfd343b..f5105175 100644 --- a/quantower/Statistics/EntropyIndicator.cs +++ b/quantower/Statistics/EntropyIndicator.cs @@ -25,7 +25,7 @@ public class EntropyIndicator : Indicator, IWatchlistIndicator private Entropy? entropy; protected LineSeries? EntropySeries; protected string? SourceName; - public int MinHistoryDepths => 2; + public static int MinHistoryDepths => 2; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public EntropyIndicator() diff --git a/quantower/Statistics/MaxIndicator.cs b/quantower/Statistics/MaxIndicator.cs index 23a67501..5c696095 100644 --- a/quantower/Statistics/MaxIndicator.cs +++ b/quantower/Statistics/MaxIndicator.cs @@ -28,7 +28,7 @@ public class MaxIndicator : Indicator, IWatchlistIndicator private Max? ma; protected LineSeries? MaxSeries; protected string? SourceName; - public int MinHistoryDepths => 0; + public static int MinHistoryDepths => 0; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public MaxIndicator() diff --git a/quantower/Statistics/MinIndicator.cs b/quantower/Statistics/MinIndicator.cs index a7fa2e59..7f55fcd4 100644 --- a/quantower/Statistics/MinIndicator.cs +++ b/quantower/Statistics/MinIndicator.cs @@ -28,7 +28,7 @@ public class MinIndicator : Indicator, IWatchlistIndicator private Min? mi; protected LineSeries? MinSeries; protected string? SourceName; - public int MinHistoryDepths => 0; + public static int MinHistoryDepths => 0; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public MinIndicator() diff --git a/quantower/Statistics/PercentileIndicator.cs b/quantower/Statistics/PercentileIndicator.cs index ba861496..a6cc5a2d 100644 --- a/quantower/Statistics/PercentileIndicator.cs +++ b/quantower/Statistics/PercentileIndicator.cs @@ -28,7 +28,7 @@ public class PercentileIndicator : Indicator, IWatchlistIndicator private Percentile? percentile; protected LineSeries? PercentileSeries; protected string? SourceName; - public int MinHistoryDepths => 2; + public static int MinHistoryDepths => 2; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public PercentileIndicator() diff --git a/quantower/Statistics/SkewIndicator.cs b/quantower/Statistics/SkewIndicator.cs index 6f684970..0430c064 100644 --- a/quantower/Statistics/SkewIndicator.cs +++ b/quantower/Statistics/SkewIndicator.cs @@ -25,7 +25,7 @@ public class SkewIndicator : Indicator, IWatchlistIndicator private Skew? skew; protected LineSeries? SkewSeries; protected string? SourceName; - public int MinHistoryDepths => 3; + public static int MinHistoryDepths => 3; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public SkewIndicator() diff --git a/quantower/Statistics/StddevIndicator.cs b/quantower/Statistics/StddevIndicator.cs index 0c1b557c..a9139d91 100644 --- a/quantower/Statistics/StddevIndicator.cs +++ b/quantower/Statistics/StddevIndicator.cs @@ -28,7 +28,7 @@ public class StddevIndicator : Indicator, IWatchlistIndicator private Stddev? stddev; protected LineSeries? StddevSeries; protected string? SourceName; - public int MinHistoryDepths => 2; + public static int MinHistoryDepths => 2; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public StddevIndicator() diff --git a/quantower/Statistics/VarianceIndicator.cs b/quantower/Statistics/VarianceIndicator.cs index 9f0b5234..e2c6ca2e 100644 --- a/quantower/Statistics/VarianceIndicator.cs +++ b/quantower/Statistics/VarianceIndicator.cs @@ -28,7 +28,7 @@ public class VarianceIndicator : Indicator, IWatchlistIndicator private Variance? variance; protected LineSeries? VarianceSeries; protected string? SourceName; - public int MinHistoryDepths => 2; + public static int MinHistoryDepths => 2; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public VarianceIndicator() diff --git a/quantower/Statistics/ZscoreIndicator.cs b/quantower/Statistics/ZscoreIndicator.cs index e708d54b..e2a52ead 100644 --- a/quantower/Statistics/ZscoreIndicator.cs +++ b/quantower/Statistics/ZscoreIndicator.cs @@ -25,7 +25,7 @@ public class ZscoreIndicator : Indicator, IWatchlistIndicator private Zscore? zScore; protected LineSeries? ZscoreSeries; protected string? SourceName; - public int MinHistoryDepths => 2; + public static int MinHistoryDepths => 2; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public ZscoreIndicator() diff --git a/quantower/Volatility/AtrIndicator.cs b/quantower/Volatility/AtrIndicator.cs index fb2667ad..de288567 100644 --- a/quantower/Volatility/AtrIndicator.cs +++ b/quantower/Volatility/AtrIndicator.cs @@ -10,7 +10,7 @@ public class AtrIndicator : Indicator, IWatchlistIndicator private Atr? atr; protected LineSeries? AtrSeries; - public int MinHistoryDepths => 2; + public static int MinHistoryDepths => 2; int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public AtrIndicator() diff --git a/quantower/Volatility/TestIndicator.cs b/quantower/Volatility/TestIndicator.cs index aad1dfda..fbb60c9a 100644 --- a/quantower/Volatility/TestIndicator.cs +++ b/quantower/Volatility/TestIndicator.cs @@ -27,7 +27,6 @@ public class TestIndicator : Indicator, IWatchlistIndicator private Sma? ma; protected LineSeries? Series; - //protected string? SourceName; public int MinHistoryDepths { get; set; } int IWatchlistIndicator.MinHistoryDepths => 0; //QuanTAlib indicators generate value immediately