diff --git a/.editorconfig b/.editorconfig
index 27ae0e75..b99bec2f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -5,4 +5,12 @@ root = true
# Suppress S3776 (Cognitive Complexity)
dotnet_diagnostic.S3776.severity = none
# Suppress CA1416 (Platform Compatibility)
-dotnet_diagnostic.CA1416.severity = none
\ No newline at end of file
+dotnet_diagnostic.CA1416.severity = none
+dotnet_style_parentheses_in_control_flow_statements = always_for_clarity:suggestion
+csharp_new_line_before_open_brace = none
+csharp_new_line_before_else = false
+csharp_new_line_before_catch = false
+csharp_new_line_before_finally = false
+csharp_new_line_before_members_in_object_initializers = false
+csharp_new_line_before_members_in_anonymous_types = false
+csharp_new_line_between_query_expression_clauses = false
\ No newline at end of file
diff --git a/.github/TradingPlatform.BusinessLayer-Miha’s MacBook Pro.dll b/.github/TradingPlatform.BusinessLayer-Miha’s MacBook Pro.dll
new file mode 100644
index 00000000..11c3b4e3
Binary files /dev/null and b/.github/TradingPlatform.BusinessLayer-Miha’s MacBook Pro.dll differ
diff --git a/.github/workflow/SonarCloud.yml b/.github/workflow/SonarCloud.yml
new file mode 100644
index 00000000..93975f32
--- /dev/null
+++ b/.github/workflow/SonarCloud.yml
@@ -0,0 +1,30 @@
+name: SonarCloud analysis
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+permissions:
+ pull-requests: read # allows SonarCloud to decorate PRs with analysis results
+
+jobs:
+ Analysis:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+
+ - name: Analyze with SonarCloud
+ uses: SonarSource/sonarcloud-github-action@v2.0.2
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Generate a token on Sonarcloud.io, add it to the secrets of this repo with the name SONAR_TOKEN
+ with:
+ # Additional arguments for the SonarScanner CLI
+ args: >
+ -Dsonar.projectKey=mihakralj_QuanTAlib
+ -Dsonar.organization=mihakralj
+ -Dsonar.sources=.
+ -Dsonar.verbose=false
diff --git a/.github/workflows/main_automation.yml b/.github/workflows/main_automation.yml
index 2130d485..12fac48c 100644
--- a/.github/workflows/main_automation.yml
+++ b/.github/workflows/main_automation.yml
@@ -3,10 +3,10 @@ on:
workflow_dispatch:
push:
branches:
- - '*'
+ - main
pull_request:
branches:
- - '*'
+ - main
jobs:
build_test:
diff --git a/.refactoring/base.cs b/.refactoring/base.cs
new file mode 100644
index 00000000..883293e9
--- /dev/null
+++ b/.refactoring/base.cs
@@ -0,0 +1,237 @@
+using System;
+
+public readonly record struct TValue(DateTime Time, double Value, bool IsNew = true, bool IsHot = true)
+{
+ public DateTime Time { get; init; } = Time;
+ public double Value { get; init; } = Value;
+ public bool IsNew { get; init; } = IsNew;
+ public bool IsHot { get; init; } = IsHot;
+
+ public TValue() : this(DateTime.UtcNow, 0) { }
+ public TValue(double value) : this(DateTime.UtcNow, value) { }
+ public TValue((DateTime time, double value) tuple) : this(tuple.time, tuple.value) { }
+
+ public static implicit operator double(TValue tv) => tv.Value;
+ public static implicit operator DateTime(TValue tv) => tv.Time;
+ public static implicit operator TValue(double value) => new TValue(DateTime.UtcNow, value);
+
+ public override string ToString() => $"[{Time:yyyy-MM-dd HH:mm:ss}: {Value:F2}]";
+}
+
+
+public readonly record struct TBar(DateTime Time, double Open, double High, double Low, double Close, double Volume, bool IsNew = true)
+{
+ public DateTime Time { get; init; } = Time;
+ public double Open { get; init; } = Open;
+ public double High { get; init; } = High;
+ public double Low { get; init; } = Low;
+ public double Close { get; init; } = Close;
+ public double Volume { get; init; } = Volume;
+ public bool IsNew { get; init; } = IsNew;
+
+ public TBar() : this(DateTime.UtcNow, 0, 0, 0, 0, 0) { }
+ public TBar(double open, double high, double low, double close, double volume) : this(DateTime.UtcNow, open, high, low, close, volume) { }
+ public TBar((DateTime time, double open, double high, double low, double close, double volume) tuple) : this(tuple.time, tuple.open, tuple.high, tuple.low, tuple.close, tuple.volume) { }
+
+ public override string ToString() => $"[{Time:yyyy-MM-dd HH:mm:ss}: O={Open:F2}, H={High:F2}, L={Low:F2}, C={Close:F2}, V={Volume:F2}]";
+}
+
+/////////////////////
+///
+/////////////////////
+
+public class GBM_Feed
+{
+ private readonly double _mu;
+ private readonly double _sigma;
+ private readonly Random _random;
+ private double _lastClose;
+ private double _lastHigh;
+ private double _lastLow;
+
+ public GBM_Feed(double initialPrice, double mu, double sigma)
+ {
+ _lastClose = initialPrice;
+ _lastHigh = initialPrice;
+ _lastLow = initialPrice;
+ _mu = mu;
+ _sigma = sigma;
+ _random = Random.Shared;
+ }
+
+ public TBar Generate(bool IsNew = true)
+ {
+ DateTime time = DateTime.UtcNow;
+ double dt = 1.0 / 252; // Assuming daily steps in a trading year of 252 days
+ double drift = (_mu - 0.5 * _sigma * _sigma) * dt;
+ double diffusion = _sigma * Math.Sqrt(dt) * NormalRandom();
+ double newClose = _lastClose * Math.Exp(drift + diffusion);
+
+ double open = _lastClose;
+ double high = Math.Max(open, newClose) * (1 + _random.NextDouble() * 0.01);
+ double low = Math.Min(open, newClose) * (1 - _random.NextDouble() * 0.01);
+ double volume = 1000 + _random.NextDouble() * 1000; // Random volume between 1000 and 2000
+
+ if (!IsNew)
+ {
+ high = Math.Max(_lastHigh, high);
+ low = Math.Min(_lastLow, low);
+ }
+ else
+ {
+ _lastClose = newClose;
+ }
+
+ _lastHigh = high;
+ _lastLow = low;
+
+ return new TBar(time, open, high, low, newClose, volume, IsNew);
+ }
+
+ private double NormalRandom()
+ {
+ // Box-Muller transform to generate standard normal random variable
+ double u1 = 1.0 - _random.NextDouble(); // Uniform(0,1] random doubles
+ double u2 = 1.0 - _random.NextDouble();
+ return Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
+ }
+}
+
+
+///
+/// ////////////////
+///
+
+public class EMA
+{
+ private double lastEma, lastEmaCandidate, k;
+ private int period, i;
+ public TValue Value { get; private set; }
+ public bool IsHot { get; private set; }
+
+ public EMA(int period) {
+ Init(period);
+ }
+
+ public void Init(int period)
+ {
+ this.period = period;
+ this.k = 2.0 / (period + 1);
+ this.lastEma = this.lastEmaCandidate = double.NaN;
+ this.i = 0;
+ }
+ public TValue Update(TValue input, bool IsNew = true) {
+ double ema;
+
+ if (double.IsNaN(lastEma)) { lastEma = input.Value; }
+
+ if (IsNew) {
+ lastEma = lastEmaCandidate;
+ i++;
+ }
+
+ double kk = (i= period;
+ Value = new TValue(input.Time, ema, IsNew, IsHot);
+ return Value;
+ }
+}
+
+/////////////////
+///
+
+public class SMA
+{
+ private CircularBuffer buffer;
+ private int period;
+ private double sum;
+ public TValue Value { get; private set; }
+ public bool IsHot { get; private set; }
+
+ public SMA(int period)
+ {
+ Init(period);
+ }
+
+ public void Init(int period)
+ {
+ this.period = period;
+ this.buffer = new CircularBuffer(period);
+ this.sum = 0;
+ this.IsHot = false;
+ this.Value = default;
+ }
+
+ public TValue Update(TValue input, bool IsNew = true)
+ {
+ if (IsNew)
+ {
+ if (buffer.Count == period) {
+ sum -= buffer[0];
+ }
+ buffer.Add(input);
+ sum += input.Value;
+ } else {
+ if (buffer.Count > 0) {
+ sum -= buffer[buffer.Count - 1];
+ sum += input.Value;
+ buffer[buffer.Count - 1] = input;
+ } else {
+ buffer.Add(input);
+ sum += input.Value;
+ }
+ }
+
+ double sma = buffer.Count > 0 ? sum / buffer.Count : double.NaN;
+ IsHot = buffer.Count >= period;
+ Value = new TValue(input.Time, sma, IsNew, IsHot);
+ return Value;
+ }
+}
+
+/////////////////////
+///
+/////////////////////
+
+
+public class CircularBuffer
+{
+ private double[] _buffer;
+ private int _start;
+ private int _size;
+
+ public CircularBuffer(int capacity) {
+ _buffer = new double[capacity];
+ _start = 0;
+ _size = 0;
+ }
+
+ public int Capacity => _buffer.Length;
+ public int Count => _size;
+
+ public void Add(double item) {
+ if (_size < Capacity) {
+ _buffer[(_start + _size) % Capacity] = item;
+ _size++;
+ } else {
+ _buffer[_start] = item;
+ _start = (_start + 1) % Capacity;
+ }
+ }
+
+ public double this[int index] {
+ get {
+ if (index < 0 || index >= _size)
+ throw new IndexOutOfRangeException();
+ return _buffer[(_start + index) % Capacity];
+ }
+ set {
+ if (index < 0 || index >= _size)
+ throw new IndexOutOfRangeException();
+ _buffer[(_start + index) % Capacity] = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/.refactoring/test.dib b/.refactoring/test.dib
new file mode 100644
index 00000000..d2277e66
--- /dev/null
+++ b/.refactoring/test.dib
@@ -0,0 +1,163 @@
+#!meta
+
+{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
+
+#!csharp
+
+#r "\bin\Debug\calculations.dll"
+using QuanTAlib;
+
+#!csharp
+
+TValue vv = new(10);
+display(vv.ToString());
+display(vv.IsHot);
+
+TBar bb = new(1,1,1,1,10);
+display(bb.ToString());
+display(bb.IsNew);
+
+#!csharp
+
+int i=10;
+SMA sma = new(i);
+Console.WriteLine($"{"Close",10} {"SMA(" + i + ")",10}");
+for (int i = 0; i < 20; i++)
+{
+ TValue c =(double)i+1;
+ sma.Update(10000,true);
+ sma.Update(1,false);
+ sma.Update(-1000,false);
+ sma.Update(c,false);
+
+ Console.WriteLine($"{i+1} {(double)c,10:F2} {(double)sma.Value,10:F2} {sma.Value.IsHot}");
+}
+
+#!csharp
+
+public class Emitter {
+ private Random random = new Random();
+ public event EventHandler> Pub;
+ public void Emit() {
+ DateTime now = DateTime.Now;
+ double randomValue = random.NextDouble() * 100; // Generates a random number between 0 and 100
+ TValue value = new TValue(now, randomValue);
+
+ EventArg eventArg = new EventArg(value, true, true);
+ OnValuePub(eventArg);
+ }
+ protected virtual void OnValuePub(EventArg eventArg) {
+ Pub?.Invoke(this, eventArg);
+ }
+}
+
+public class BarEmitter
+{
+ private Random random = new Random();
+ public event EventHandler> Pub;
+ private double lastClose = 100.0; // Starting price
+
+ public void Emit()
+ {
+ double open = lastClose;
+ double close = open * (1 + (random.NextDouble() - 0.5) * 0.02); // +/- 1% change
+ double high = Math.Max(open, close) * (1 + random.NextDouble() * 0.005); // Up to 0.5% higher
+ double low = Math.Min(open, close) * (1 - random.NextDouble() * 0.005); // Up to 0.5% lower
+ double volume = random.NextDouble() * 1000000; // Random volume between 0 and 1,000,000
+
+ TBar bar = new TBar(DateTime.Now, open, high, low, close, volume);
+ lastClose = close;
+
+ EventArg eventArg = new EventArg(bar, true, true);
+ OnBarPub(eventArg);
+ }
+
+ protected virtual void OnBarPub(EventArg eventArg)
+ {
+ Pub?.Invoke(this, eventArg);
+ }
+}
+
+
+public class Listener
+{
+ public void Sub(object sender, EventArgs e)
+ {
+ if (e is EventArg tValueArg) {
+ Console.WriteLine($"TValue: {tValueArg.Data.Value:F2}");
+ } else if (e is EventArg tBarArg) {
+ Console.WriteLine($"TBar: o={tBarArg.Data.Open:F2}, v={tBarArg.Data.Volume:F2}");
+ } else {
+ Console.WriteLine($"Unknown type: {e.GetType().Name}");
+ }
+ }
+}
+
+#!csharp
+
+Emitter em1 = new();
+BarEmitter em2 = new();
+Listener list = new();
+
+em1.Pub += list.Sub;
+em2.Pub += list.Sub;
+
+// Emit 5 random values
+for (int i = 0; i < 3; i++) {
+ em1.Emit();
+ em2.Emit();
+}
+
+#!csharp
+
+public abstract class Indicator {
+ protected Indicator() {
+ Init(); }
+ public virtual void Init() {}
+ public virtual TValue Calc(TValue input, bool isNew=true, bool isHot=true) {
+ return new TValue();
+ }
+}
+
+public class EMA : Indicator
+{
+ private double lastEma, lastEmaCandidate, k;
+ private int period, i;
+
+ public EMA(int period) {
+ Init(period);
+ }
+
+ public void Init(int period)
+ {
+ this.period = period;
+ this.k = 2.0 / (period + 1);
+ this.lastEma = this.lastEmaCandidate = double.NaN;
+ this.i = 0;
+ }
+
+ public override TValue Calc(TValue input, bool isNew = true, bool isHot = true) {
+ double ema;
+
+ if (double.IsNaN(lastEma)) { lastEma = lastEmaCandidate = input.Value; }
+
+ if (isNew) {
+ lastEma = lastEmaCandidate;
+ i++;
+ }
+
+ double kk = (i>=period)?k:(2.0/(i+1));
+ ema = lastEma + kk * (input.Value - lastEma);
+ lastEmaCandidate = ema;
+
+ return new TValue(input.Timestamp, ema);
+ }
+}
+
+#!csharp
+
+EMA ema = new(3);
+display(ema.Calc(100));
+display(ema.Calc(0,false));
+display(ema.Calc(100,false));
+display(ema.Calc(0));
diff --git a/.sonarlint/mihakralj_quantalibcsharp.ruleset b/.sonarlint/mihakralj_quantalibcsharp.ruleset
index 5ad478ec..a2e953a9 100644
--- a/.sonarlint/mihakralj_quantalibcsharp.ruleset
+++ b/.sonarlint/mihakralj_quantalibcsharp.ruleset
@@ -1,390 +1,390 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Calculations/Basics/ADD_Series.cs b/Calculations/Basics/ADD_Series.cs
index 0588d216..6d0436fe 100644
--- a/Calculations/Basics/ADD_Series.cs
+++ b/Calculations/Basics/ADD_Series.cs
@@ -9,21 +9,24 @@ Remarks:
*/
-public class ADD_Series : Pair_TSeries_Indicator
+public class ADD_Series : Pair_TSeries_Indicator
{
- public ADD_Series(TSeries d1, TSeries d2 ) : base(d1, d2) {
- if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
+ public ADD_Series(TSeries d1, TSeries d2) : base(d1, d2)
+ {
+ if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
- public ADD_Series(TSeries d1, double dd2 ) : base(d1, dd2) {
- if (base._d1.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
+ public ADD_Series(TSeries d1, double dd2) : base(d1, dd2)
+ {
+ if (base._d1.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
}
- public ADD_Series(double dd1, TSeries d2 ) : base(dd1, d2) {
- if (base._d2.Count > 0) { for (int i=0; i< base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
+ public ADD_Series(double dd1, TSeries d2) : base(dd1, d2)
+ {
+ if (base._d2.Count > 0) { for (int i = 0; i < base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
}
- public override void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update)
+ public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
{
- (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t, TValue1.v+TValue2.v);
+ (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t, TValue1.v + TValue2.v);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
diff --git a/Calculations/Basics/CORR_Series.cs b/Calculations/Basics/CORR_Series.cs
index 246baa79..8052b4e2 100644
--- a/Calculations/Basics/CORR_Series.cs
+++ b/Calculations/Basics/CORR_Series.cs
@@ -1,52 +1,52 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-CORR: Pearson's Correlation Coefficient
- PCC is a measure of linear correlation between two sets of data.
- It is the ratio between the covariance of two variables and the product of
- their standard deviations; it is essentially a normalized measurement of
- the covariance, such that the result always has a value between −1 and 1.
-
-Sources:
- https://en.wikipedia.org/wiki/Pearson_correlation_coefficient
-
- */
-
-public class CORR_Series : Pair_TSeries_Indicator
-{
- public CORR_Series(TSeries d1, TSeries d2, int period, bool useNaN = false) : base(d1, d2, period, useNaN)
- {
- if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
- }
-
- private readonly System.Collections.Generic.List _x = new();
- private readonly System.Collections.Generic.List _xx = new();
- private readonly System.Collections.Generic.List _y = new();
- private readonly System.Collections.Generic.List _yy = new();
- private readonly System.Collections.Generic.List _xy = new();
-
- public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
- {
- Add_Replace_Trim(_x, TValue1.v, _p, update);
- Add_Replace_Trim(_xx, TValue1.v * TValue1.v, _p, update);
- Add_Replace_Trim(_y, TValue2.v, _p, update);
- Add_Replace_Trim(_yy, TValue2.v * TValue2.v, _p, update);
- Add_Replace_Trim(_xy, TValue1.v * TValue2.v, _p, update);
-
- double _sumx = _x.Sum();
- double _sumxx = _xx.Sum();
- double _sumy = _y.Sum();
- double _sumyy = _yy.Sum();
- double _sumxy = _xy.Sum();
-
- double _covar = (_sumxx - _sumx * _sumx / _p) * (_sumyy - _sumy * _sumy / _p);
- double _cor = (_covar != 0) ? (_sumxy - _sumx * _sumy / _p) / Math.Sqrt(_covar) : 0.0;
-
- var result = (TValue1.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _cor);
- if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
-
- }
-}
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+CORR: Pearson's Correlation Coefficient
+ PCC is a measure of linear correlation between two sets of data.
+ It is the ratio between the covariance of two variables and the product of
+ their standard deviations; it is essentially a normalized measurement of
+ the covariance, such that the result always has a value between −1 and 1.
+
+Sources:
+ https://en.wikipedia.org/wiki/Pearson_correlation_coefficient
+
+ */
+
+public class CORR_Series : Pair_TSeries_Indicator
+{
+ public CORR_Series(TSeries d1, TSeries d2, int period, bool useNaN = false) : base(d1, d2, period, useNaN)
+ {
+ if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
+ }
+
+ private readonly System.Collections.Generic.List _x = new();
+ private readonly System.Collections.Generic.List _xx = new();
+ private readonly System.Collections.Generic.List _y = new();
+ private readonly System.Collections.Generic.List _yy = new();
+ private readonly System.Collections.Generic.List _xy = new();
+
+ public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
+ {
+ Add_Replace_Trim(_x, TValue1.v, _p, update);
+ Add_Replace_Trim(_xx, TValue1.v * TValue1.v, _p, update);
+ Add_Replace_Trim(_y, TValue2.v, _p, update);
+ Add_Replace_Trim(_yy, TValue2.v * TValue2.v, _p, update);
+ Add_Replace_Trim(_xy, TValue1.v * TValue2.v, _p, update);
+
+ double _sumx = _x.Sum();
+ double _sumxx = _xx.Sum();
+ double _sumy = _y.Sum();
+ double _sumyy = _yy.Sum();
+ double _sumxy = _xy.Sum();
+
+ double _covar = (_sumxx - _sumx * _sumx / _p) * (_sumyy - _sumy * _sumy / _p);
+ double _cor = (_covar != 0) ? (_sumxy - _sumx * _sumy / _p) / Math.Sqrt(_covar) : 0.0;
+
+ var result = (TValue1.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _cor);
+ if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
+
+ }
+}
diff --git a/Calculations/Basics/COVAR_Series.cs b/Calculations/Basics/COVAR_Series.cs
index 3826ee9d..7368689c 100644
--- a/Calculations/Basics/COVAR_Series.cs
+++ b/Calculations/Basics/COVAR_Series.cs
@@ -1,46 +1,48 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-COVAR: Covariance
- Covariance is defined as the expected value (or mean) of the product
- of their deviations from their individual expected values.
-
-Sources:
- https://en.wikipedia.org/wiki/Covariance
-
- */
-
-
-public class COVAR_Series : Pair_TSeries_Indicator
-{
- public COVAR_Series(TSeries d1, TSeries d2, int period, bool useNaN = false) : base(d1, d2, period, useNaN)
- {
- if (base._d1.Count > 0 && base._d2.Count > 0) {
- for (int i = 0; i < base._d1.Count; i++) {
- this.Add(base._d1[i], base._d2[i], false);
- }
- }
- }
-
- private readonly System.Collections.Generic.List _x = new();
- private readonly System.Collections.Generic.List _y = new();
- private readonly System.Collections.Generic.List _xy = new();
-
- public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
- {
- BufferTrim(_x, TValue1.v, _p, update);
- BufferTrim(_y, TValue2.v, _p, update);
- BufferTrim(_xy, TValue1.v * TValue2.v, _p, update);
-
- double _avgx = _x.Average();
- double _avgy = _y.Average();
- double _avgxy = _xy.Average();
- double _covar = _avgxy - (_avgx * _avgy);
-
- var result = (TValue1.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _covar);
- if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
- }
-}
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+COVAR: Covariance
+ Covariance is defined as the expected value (or mean) of the product
+ of their deviations from their individual expected values.
+
+Sources:
+ https://en.wikipedia.org/wiki/Covariance
+
+ */
+
+
+public class COVAR_Series : Pair_TSeries_Indicator
+{
+ public COVAR_Series(TSeries d1, TSeries d2, int period, bool useNaN = false) : base(d1, d2, period, useNaN)
+ {
+ if (base._d1.Count > 0 && base._d2.Count > 0)
+ {
+ for (int i = 0; i < base._d1.Count; i++)
+ {
+ this.Add(base._d1[i], base._d2[i], false);
+ }
+ }
+ }
+
+ private readonly System.Collections.Generic.List _x = new();
+ private readonly System.Collections.Generic.List _y = new();
+ private readonly System.Collections.Generic.List _xy = new();
+
+ public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
+ {
+ BufferTrim(_x, TValue1.v, _p, update);
+ BufferTrim(_y, TValue2.v, _p, update);
+ BufferTrim(_xy, TValue1.v * TValue2.v, _p, update);
+
+ double _avgx = _x.Average();
+ double _avgy = _y.Average();
+ double _avgxy = _xy.Average();
+ double _covar = _avgxy - (_avgx * _avgy);
+
+ var result = (TValue1.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _covar);
+ if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
+ }
+}
diff --git a/Calculations/Basics/DIV_Series.cs b/Calculations/Basics/DIV_Series.cs
index 16069917..962e4f6f 100644
--- a/Calculations/Basics/DIV_Series.cs
+++ b/Calculations/Basics/DIV_Series.cs
@@ -8,22 +8,25 @@ Remarks:
Most of scaffolding is packaged in abstracty class Pair_TSeries_Indicator.
*/
-public class DIV_Series : Pair_TSeries_Indicator
+public class DIV_Series : Pair_TSeries_Indicator
{
- public DIV_Series(TSeries d1, TSeries d2 ) : base(d1, d2) {
- if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
+ public DIV_Series(TSeries d1, TSeries d2) : base(d1, d2)
+ {
+ if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
- public DIV_Series(TSeries d1, double dd2 ) : base(d1, dd2) {
- if (base._d1.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
+ public DIV_Series(TSeries d1, double dd2) : base(d1, dd2)
+ {
+ if (base._d1.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
}
- public DIV_Series(double dd1, TSeries d2 ) : base(dd1, d2) {
- if (base._d2.Count > 0) { for (int i=0; i< base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
+ public DIV_Series(double dd1, TSeries d2) : base(dd1, d2)
+ {
+ if (base._d2.Count > 0) { for (int i = 0; i < base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
}
- public override void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update)
+ public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
{
- (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,
- (TValue2.v is not 0) ? TValue1.v/TValue2.v : Double.PositiveInfinity);
+ (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,
+ (TValue2.v is not 0) ? TValue1.v / TValue2.v : Double.PositiveInfinity);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
\ No newline at end of file
diff --git a/Calculations/Basics/MUL_Series.cs b/Calculations/Basics/MUL_Series.cs
index c1c573bd..b2bae613 100644
--- a/Calculations/Basics/MUL_Series.cs
+++ b/Calculations/Basics/MUL_Series.cs
@@ -6,22 +6,25 @@ MUL - multiply TSeries*TSeries together, or TSeries*double, or double*TSeries
*/
-public class MUL_Series : Pair_TSeries_Indicator
+public class MUL_Series : Pair_TSeries_Indicator
{
- public MUL_Series(TSeries d1, TSeries d2 ) : base(d1, d2) {
- if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
+ public MUL_Series(TSeries d1, TSeries d2) : base(d1, d2)
+ {
+ if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
- public MUL_Series(TSeries d1, double dd2 ) : base(d1, dd2) {
- if (base._d1.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
+ public MUL_Series(TSeries d1, double dd2) : base(d1, dd2)
+ {
+ if (base._d1.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
}
- public MUL_Series(double dd1, TSeries d2 ) : base(dd1, d2) {
- if (base._d2.Count > 0) { for (int i=0; i< base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
+ public MUL_Series(double dd1, TSeries d2) : base(dd1, d2)
+ {
+ if (base._d2.Count > 0) { for (int i = 0; i < base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
}
- public override void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update)
+ public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
{
- (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,
- TValue1.v*TValue2.v);
+ (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,
+ TValue1.v * TValue2.v);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
\ No newline at end of file
diff --git a/Calculations/Basics/SUB_Series.cs b/Calculations/Basics/SUB_Series.cs
index 88511f81..e4333ec6 100644
--- a/Calculations/Basics/SUB_Series.cs
+++ b/Calculations/Basics/SUB_Series.cs
@@ -7,22 +7,25 @@ SUB - subtracting TSeries-TSeries, or TSeries-double, or double-TSeries
*/
-public class SUB_Series : Pair_TSeries_Indicator
+public class SUB_Series : Pair_TSeries_Indicator
{
- public SUB_Series(TSeries d1, TSeries d2 ) : base(d1, d2) {
- if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
+ public SUB_Series(TSeries d1, TSeries d2) : base(d1, d2)
+ {
+ if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
- public SUB_Series(TSeries d1, double dd2 ) : base(d1, dd2) {
- if (base._d1.Count > 0) { for (int i=0; i< base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
+ public SUB_Series(TSeries d1, double dd2) : base(d1, dd2)
+ {
+ if (base._d1.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
}
- public SUB_Series(double dd1, TSeries d2 ) : base(dd1, d2) {
- if (base._d2.Count > 0) { for (int i=0; i< base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
+ public SUB_Series(double dd1, TSeries d2) : base(dd1, d2)
+ {
+ if (base._d2.Count > 0) { for (int i = 0; i < base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
}
- public override void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update)
+ public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
{
- (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,
- TValue1.v-TValue2.v);
+ (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,
+ TValue1.v - TValue2.v);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
\ No newline at end of file
diff --git a/Calculations/Calculations.csproj b/Calculations/Calculations.csproj
index 701f67f7..0ed29821 100644
--- a/Calculations/Calculations.csproj
+++ b/Calculations/Calculations.csproj
@@ -1,80 +1,80 @@
-
-
-
- QuanTAlib
- 0.2.30
- 0.2.30
- 0.2.30
- Library of TA Calculations, Charts and Strategies for Quantower
- Quantitative Technical Analysis Library in C# for Quantower
- git
- https://github.com/mihakralj/QuanTAlib
- true
- Miha Kralj
- Miha Kralj
- Apache-2.0
- readme.md
- net8.0;net7.0
- disable
- preview
- disable
- true
- en-US
- QuanTAlib
- QuanTAlib
- True
- AnyCPU
- False
- full
- True
- True
-
- Indicators;Stock;Market;Technical;Analysis;Algorithmic;Trading;Trade;Trend;Momentum;Finance;Algorithm;Algo;
- AlgoTrading;Financial;Strategy;Chart;Charting;Oscillator;Overlay;Equity;Bitcoin;Crypto;Cryptocurrency;Forex;
- Quantitative;Historical;Quotes;
-
-
-
-
-
-
-
-
-
- full
- True
- 7
- True
- anycpu
-
-
- full
- True
- 7
- True
- anycpu
-
-
- QuanTAlib2.png
- https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png
- True
- ..\.sonarlint\mihakralj_quantalibcsharp.ruleset
- 0.2.1-dev.2
-
-
-
-
-
-
- True
-
-
-
-
- True
- False
-
-
-
-
+
+
+
+ QuanTAlib
+ 0.2.30
+ 0.2.30
+ 0.2.30
+ Library of TA Calculations, Charts and Strategies for Quantower
+ Quantitative Technical Analysis Library in C# for Quantower
+ git
+ https://github.com/mihakralj/QuanTAlib
+ true
+ Miha Kralj
+ Miha Kralj
+ Apache-2.0
+ readme.md
+ net8.0;net7.0
+ disable
+ preview
+ disable
+ true
+ en-US
+ QuanTAlib
+ QuanTAlib
+ True
+ AnyCPU
+ False
+ full
+ True
+ True
+
+ Indicators;Stock;Market;Technical;Analysis;Algorithmic;Trading;Trade;Trend;Momentum;Finance;Algorithm;Algo;
+ AlgoTrading;Financial;Strategy;Chart;Charting;Oscillator;Overlay;Equity;Bitcoin;Crypto;Cryptocurrency;Forex;
+ Quantitative;Historical;Quotes;
+
+
+
+
+
+
+
+
+
+ full
+ True
+ 7
+ True
+ anycpu
+
+
+ full
+ True
+ 7
+ True
+ anycpu
+
+
+ QuanTAlib2.png
+ https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png
+ True
+ ..\.sonarlint\mihakralj_quantalibcsharp.ruleset
+ 0.2.1-dev.2
+
+
+
+
+
+
+ True
+
+
+
+
+ True
+ False
+
+
+
+
\ No newline at end of file
diff --git a/Calculations/ClassStructures/Pair_TSeries_Abstract.cs b/Calculations/ClassStructures/Pair_TSeries_Abstract.cs
index 2203d3f1..682b1b87 100644
--- a/Calculations/ClassStructures/Pair_TSeries_Abstract.cs
+++ b/Calculations/ClassStructures/Pair_TSeries_Abstract.cs
@@ -1,132 +1,157 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-Abstract classes with all scaffolding required to build indicators.
- All abstracts support period, NaN, and all permutations of Add() methods.
- Indicator classess need to implement:
- - Chaining constructor (Abstract's constructor executes first)
- - Default Add(value) class
- - optional Add(series) bulk insert class (for optimization of historical analysis)
-
- Single_TSeries_Indicator - one single-value TSeries in, one TSeries out.
- Pair_TSeries_Indicator - Two TSeries in, one TSeries out. (includes simple semaphoring)
- Single_TBars_Indicator - One OHLCV TBars in, one TSeries out.
-
- */
-
-public abstract class Pair_TSeries_Indicator : TSeries {
- protected readonly int _p;
- protected readonly bool _NaN;
- protected readonly TSeries _d1;
- protected readonly TSeries _d2;
- protected readonly double _dd1, _dd2;
-
- // Chainable Constructors - add them at the end of primary constructors if needed
- protected Pair_TSeries_Indicator(TSeries source1, TSeries source2, int period, bool useNaN) {
- _p = period;
- _NaN = useNaN;
- _d1 = source1;
- _d2 = source2;
- _dd1 = double.NaN;
- _dd2 = double.NaN;
- _d1.Pub += Sub;
- _d2.Pub += Sub;
- }
-
- protected Pair_TSeries_Indicator(TSeries source1, TSeries source2) {
- _d1 = source1;
- _d2 = source2;
- _dd1 = double.NaN;
- _dd2 = double.NaN;
- _d1.Pub += Sub;
- _d2.Pub += Sub;
- }
-
- protected Pair_TSeries_Indicator(TSeries source1, double dd2) {
- _d1 = source1;
- _d2 = new TSeries();
- _dd1 = double.NaN;
- _dd2 = dd2;
- _d1.Pub += Sub;
- }
-
- protected Pair_TSeries_Indicator(double dd1, TSeries source2) {
- _d1 = new TSeries();
- _d2 = source2;
- _dd1 = dd1;
- _dd2 = double.NaN;
- _d2.Pub += Sub;
- }
-
- // overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list
- public virtual void Add((DateTime t, double v) TValue1, (DateTime t, double v) TValue2, bool update) {
- base.Add((TValue1.t, 0), update);
- // default inserts zeros
- }
-
- // potentially overridable Add() bulk variations (could be replaced with faster bulk algos)
- public virtual void Add(TSeries d1, TSeries d2) {
- for (var i = 0; i < d1.Count; i++) {
- Add(d1[i], d2[i], false);
- }
- }
-
- public virtual void Add(TSeries d1, double dd2) {
- for (var i = 0; i < d1.Count; i++) {
- Add(d1[i], (d1[i].t, dd2), false);
- }
- }
-
- public virtual void Add(double dd1, TSeries d2) {
- for (var i = 0; i < d2.Count; i++) {
- Add((d2[i].t, dd1), d2[i], false);
- }
- }
-
- public void Add((DateTime t, double v) TValue1, (DateTime t, double v) TValue2) {
- Add(TValue1, TValue2, false);
- }
-
- public void Add(bool update) {
- if (_dd1 is double.NaN && _dd2 is double.NaN) {
- // (Series, Series)
- if (update || (_d1.Count > Count && _d2.Count > Count)) {
- Add(_d1[_d1.Count - 1], _d2[_d2.Count - 1], update);
- }
- }
- else if (_dd2 is not double.NaN && _dd1 is double.NaN) {
- // (Series, Double)
- Add(_d1[_d1.Count - 1], (_d1[_d1.Count - 1].t, _dd2), update);
- }
- else {
- // (Double, Series)
- Add((_d2[_d2.Count - 1].t, _dd1), _d2[_d2.Count - 1], update);
- }
- }
-
- public void Add() {
- Add(false);
- }
-
- public new void Sub(object source, TSeriesEventArgs e) {
- Add(e.update);
- }
-
- protected static void Add_Replace(List l, double v, bool update) {
- if (update) {
- l[l.Count - 1] = v;
- }
- else {
- l.Add(v);
- }
- }
-
- protected static void Add_Replace_Trim(List l, double v, int p, bool update) {
- Add_Replace(l, v, update);
- if (l.Count > p && p != 0) {
- l.RemoveAt(0);
- }
- }
-}
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+Abstract classes with all scaffolding required to build indicators.
+ All abstracts support period, NaN, and all permutations of Add() methods.
+ Indicator classess need to implement:
+ - Chaining constructor (Abstract's constructor executes first)
+ - Default Add(value) class
+ - optional Add(series) bulk insert class (for optimization of historical analysis)
+
+ Single_TSeries_Indicator - one single-value TSeries in, one TSeries out.
+ Pair_TSeries_Indicator - Two TSeries in, one TSeries out. (includes simple semaphoring)
+ Single_TBars_Indicator - One OHLCV TBars in, one TSeries out.
+
+ */
+
+public abstract class Pair_TSeries_Indicator : TSeries
+{
+ protected readonly int _p;
+ protected readonly bool _NaN;
+ protected readonly TSeries _d1;
+ protected readonly TSeries _d2;
+ protected readonly double _dd1, _dd2;
+
+ // Chainable Constructors - add them at the end of primary constructors if needed
+ protected Pair_TSeries_Indicator(TSeries source1, TSeries source2, int period, bool useNaN)
+ {
+ _p = period;
+ _NaN = useNaN;
+ _d1 = source1;
+ _d2 = source2;
+ _dd1 = double.NaN;
+ _dd2 = double.NaN;
+ _d1.Pub += Sub;
+ _d2.Pub += Sub;
+ }
+
+ protected Pair_TSeries_Indicator(TSeries source1, TSeries source2)
+ {
+ _d1 = source1;
+ _d2 = source2;
+ _dd1 = double.NaN;
+ _dd2 = double.NaN;
+ _d1.Pub += Sub;
+ _d2.Pub += Sub;
+ }
+
+ protected Pair_TSeries_Indicator(TSeries source1, double dd2)
+ {
+ _d1 = source1;
+ _d2 = new TSeries();
+ _dd1 = double.NaN;
+ _dd2 = dd2;
+ _d1.Pub += Sub;
+ }
+
+ protected Pair_TSeries_Indicator(double dd1, TSeries source2)
+ {
+ _d1 = new TSeries();
+ _d2 = source2;
+ _dd1 = dd1;
+ _dd2 = double.NaN;
+ _d2.Pub += Sub;
+ }
+
+ // overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list
+ public virtual void Add((DateTime t, double v) TValue1, (DateTime t, double v) TValue2, bool update)
+ {
+ base.Add((TValue1.t, 0), update);
+ // default inserts zeros
+ }
+
+ // potentially overridable Add() bulk variations (could be replaced with faster bulk algos)
+ public virtual void Add(TSeries d1, TSeries d2)
+ {
+ for (var i = 0; i < d1.Count; i++)
+ {
+ Add(d1[i], d2[i], false);
+ }
+ }
+
+ public virtual void Add(TSeries d1, double dd2)
+ {
+ for (var i = 0; i < d1.Count; i++)
+ {
+ Add(d1[i], (d1[i].t, dd2), false);
+ }
+ }
+
+ public virtual void Add(double dd1, TSeries d2)
+ {
+ for (var i = 0; i < d2.Count; i++)
+ {
+ Add((d2[i].t, dd1), d2[i], false);
+ }
+ }
+
+ public void Add((DateTime t, double v) TValue1, (DateTime t, double v) TValue2)
+ {
+ Add(TValue1, TValue2, false);
+ }
+
+ public void Add(bool update)
+ {
+ if (_dd1 is double.NaN && _dd2 is double.NaN)
+ {
+ // (Series, Series)
+ if (update || (_d1.Count > Count && _d2.Count > Count))
+ {
+ Add(_d1[_d1.Count - 1], _d2[_d2.Count - 1], update);
+ }
+ }
+ else if (_dd2 is not double.NaN && _dd1 is double.NaN)
+ {
+ // (Series, Double)
+ Add(_d1[_d1.Count - 1], (_d1[_d1.Count - 1].t, _dd2), update);
+ }
+ else
+ {
+ // (Double, Series)
+ Add((_d2[_d2.Count - 1].t, _dd1), _d2[_d2.Count - 1], update);
+ }
+ }
+
+ public void Add()
+ {
+ Add(false);
+ }
+
+ public new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(e.update);
+ }
+
+ protected static void Add_Replace(List l, double v, bool update)
+ {
+ if (update)
+ {
+ l[l.Count - 1] = v;
+ }
+ else
+ {
+ l.Add(v);
+ }
+ }
+
+ protected static void Add_Replace_Trim(List l, double v, int p, bool update)
+ {
+ Add_Replace(l, v, update);
+ if (l.Count > p && p != 0)
+ {
+ l.RemoveAt(0);
+ }
+ }
+}
diff --git a/Calculations/Feeds/Alphavantage_Feed.cs b/Calculations/Feeds/Alphavantage_Feed.cs
index 5c9fc35f..f2bcc60e 100644
--- a/Calculations/Feeds/Alphavantage_Feed.cs
+++ b/Calculations/Feeds/Alphavantage_Feed.cs
@@ -13,7 +13,7 @@ Alphavantage - Free API to collect 100 recent daily quotes. It requires a (free)
*/
public class Alphavantage_Feed : TBars
{
- public enum Interval { Month, Week, Day, Hour, Min30, Min15, Min5, Min1}
+ public enum Interval { Month, Week, Day, Hour, Min30, Min15, Min5, Min1 }
public Alphavantage_Feed(string Symbol = "IBM", string APIkey = "demo")
{
System.Net.Http.HttpClient client = new();
@@ -22,8 +22,8 @@ public class Alphavantage_Feed : TBars
var msg = client.GetStringAsync(req).Result;
var jres = JsonSerializer.Deserialize(msg).RootElement;
jres.TryGetProperty("Time Series (Daily)", out JsonElement json);
-
- if (json.ValueKind == JsonValueKind.Undefined) {throw new InvalidOperationException("Stock symbol "+Symbol+" not found"); }
+
+ if (json.ValueKind == JsonValueKind.Undefined) { throw new InvalidOperationException("Stock symbol " + Symbol + " not found"); }
foreach (var val in json.EnumerateObject()) { base.Add(GetOHLC(val)); }
base.Reverse();
}
diff --git a/Calculations/Feeds/GBM_Feed.cs b/Calculations/Feeds/GBM_Feed.cs
index a08568c1..c99a282f 100644
--- a/Calculations/Feeds/GBM_Feed.cs
+++ b/Calculations/Feeds/GBM_Feed.cs
@@ -23,41 +23,45 @@ public class GBM_Feed : TBars
private double seed;
readonly double drift, volatility;
readonly int precision;
- public GBM_Feed(int Bars = 252, double Volatility = 1.0, double Drift = 0.05, double Seed = 100.0, int Precision = 2) {
+ public GBM_Feed(int Bars = 252, double Volatility = 1.0, double Drift = 0.05, double Seed = 100.0, int Precision = 2)
+ {
this.seed = Seed;
- volatility = Volatility*0.01;
- drift = Drift*0.01;
+ volatility = Volatility * 0.01;
+ drift = Drift * 0.01;
precision = Precision;
- for (int i = 0; i OCMin)? (2 * OCMin) - Low : Low;
+ double OCMin = Math.Min(Open, Close);
+ double Low = (GBM_value(seed, volatility * 0.5, 0, precision));
+ Low = (Low > OCMin) ? (2 * OCMin) - Low : Low;
- double Volume = GBM_value(seed*10, volatility*2, Drift:0, precision: 1);
+ double Volume = GBM_value(seed * 10, volatility * 2, Drift: 0, precision: 1);
base.Add((timestamp, Open, High, Low, Close, Volume), update);
seed = Close;
}
- private static double GBM_value(double Seed, double Volatility, double Drift, int precision) {
+ private static double GBM_value(double Seed, double Volatility, double Drift, int precision)
+ {
Random rnd = new();
- double U1 = 1.0-rnd.NextDouble();
- double U2 = 1.0-rnd.NextDouble();
+ double U1 = 1.0 - rnd.NextDouble();
+ double U2 = 1.0 - rnd.NextDouble();
double Z = Math.Sqrt(-2.0 * Math.Log(U1)) * Math.Sin(2.0 * Math.PI * U2);
- return Math.Round(Seed * Math.Exp( Drift - (Volatility*Volatility*0.5) + (Volatility * Z)), digits: precision);
+ return Math.Round(Seed * Math.Exp(Drift - (Volatility * Volatility * 0.5) + (Volatility * Z)), digits: precision);
}
}
\ No newline at end of file
diff --git a/Calculations/Feeds/Yahoo_Feed.cs b/Calculations/Feeds/Yahoo_Feed.cs
index 5b9029a1..1d87e97d 100644
--- a/Calculations/Feeds/Yahoo_Feed.cs
+++ b/Calculations/Feeds/Yahoo_Feed.cs
@@ -14,34 +14,36 @@ Yahoo Finance - Free API feed to collect daily market quotes
*/
public class Yahoo_Feed : TBars
{
- public Yahoo_Feed(string Symbol = "IBM", int Period = 252) {
- Period = (int)(Period*1.45);
- string requestUrl = "https://query1.finance.yahoo.com/v8/finance/chart/"+
- Symbol+"?interval=1d&period1="+
- (int)new DateTimeOffset(DateTime.UtcNow.AddDays(-Period+1)).ToUnixTimeSeconds()+"&period2="+
+ public Yahoo_Feed(string Symbol = "IBM", int Period = 252)
+ {
+ Period = (int)(Period * 1.45);
+ string requestUrl = "https://query1.finance.yahoo.com/v8/finance/chart/" +
+ Symbol + "?interval=1d&period1=" +
+ (int)new DateTimeOffset(DateTime.UtcNow.AddDays(-Period + 1)).ToUnixTimeSeconds() + "&period2=" +
(int)new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
System.Net.Http.HttpClient client = new();
var msg = client.GetStringAsync(requestUrl).Result;
var jresult = JsonSerializer.Deserialize(msg).RootElement;
- jresult.TryGetProperty("chart",out JsonElement json);
- json.TryGetProperty("result",out json);
- json[0].TryGetProperty("timestamp",out JsonElement datetime);
- json[0].TryGetProperty("indicators",out json);
- json.TryGetProperty("quote",out json);
- json[0].TryGetProperty("open",out JsonElement open);
- json[0].TryGetProperty("high",out JsonElement high);
- json[0].TryGetProperty("low",out JsonElement low);
- json[0].TryGetProperty("close",out JsonElement close);
- json[0].TryGetProperty("volume",out JsonElement volume);
+ jresult.TryGetProperty("chart", out JsonElement json);
+ json.TryGetProperty("result", out json);
+ json[0].TryGetProperty("timestamp", out JsonElement datetime);
+ json[0].TryGetProperty("indicators", out json);
+ json.TryGetProperty("quote", out json);
+ json[0].TryGetProperty("open", out JsonElement open);
+ json[0].TryGetProperty("high", out JsonElement high);
+ json[0].TryGetProperty("low", out JsonElement low);
+ json[0].TryGetProperty("close", out JsonElement close);
+ json[0].TryGetProperty("volume", out JsonElement volume);
- for (int i=0; i */
-public class COMPARE_Series : Pair_TSeries_Indicator {
+public class COMPARE_Series : Pair_TSeries_Indicator
+{
- public COMPARE_Series(TSeries d1, TSeries d2) : base(d1, d2) {
- if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
- }
- public COMPARE_Series(TSeries d1, double dd2) : base(d1, dd2) {
- if (base._d1.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
- }
- public COMPARE_Series(double dd1, TSeries d2) : base(dd1, d2) {
- if (base._d2.Count > 0) { for (int i = 0; i < base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
- }
+ public COMPARE_Series(TSeries d1, TSeries d2) : base(d1, d2)
+ {
+ if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
+ }
+ public COMPARE_Series(TSeries d1, double dd2) : base(d1, dd2)
+ {
+ if (base._d1.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
+ }
+ public COMPARE_Series(double dd1, TSeries d2) : base(dd1, d2)
+ {
+ if (base._d2.Count > 0) { for (int i = 0; i < base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
+ }
- public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update) {
+ public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
+ {
- double val = TValue1.v > TValue2.v ? 1 : -1;
- val = TValue1.v == TValue2.v ? 0 : val;
- (System.DateTime t, double v) over = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t, TValue1.v > TValue2.v ? 1 : val);
- if (update) { base[^1] = over; }
- else { base.Add(over); }
+ double val = TValue1.v > TValue2.v ? 1 : -1;
+ val = TValue1.v == TValue2.v ? 0 : val;
+ (System.DateTime t, double v) over = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t, TValue1.v > TValue2.v ? 1 : val);
+ if (update) { base[^1] = over; }
+ else { base.Add(over); }
- }
+ }
}
diff --git a/Calculations/Logic/CROSS_Series.cs b/Calculations/Logic/CROSS_Series.cs
index aab93397..6d62a54c 100644
--- a/Calculations/Logic/CROSS_Series.cs
+++ b/Calculations/Logic/CROSS_Series.cs
@@ -1,44 +1,49 @@
-namespace QuanTAlib;
-using System;
-
-/*
-OVER - Generates +1 if A is above B, -1 if A is below B and 0 if A=B
-
-Remarks:
- OVER.Cross generates 1 when A breaks B from below and -1 when A breaks B from above
-
- */
-
-public class CROSS_Series : Pair_TSeries_Indicator {
- public TSeries Cross { get; set; } = new();
-
- private double _previous = double.NaN;
- public CROSS_Series(TSeries d1, TSeries d2) : base(d1, d2) {
- if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
- }
- public CROSS_Series(TSeries d1, double dd2) : base(d1, dd2) {
- if (base._d1.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
- }
- public CROSS_Series(double dd1, TSeries d2) : base(dd1, d2) {
- if (base._d2.Count > 0) { for (int i = 0; i < base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
- }
-
- public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update) {
-
- double val = TValue1.v > TValue2.v ? 1 : -1;
- val = TValue1.v == TValue2.v ? 0 : val;
- double over = TValue1.v > TValue2.v ? 1 : val;
-
- val = (_previous < over) ? 1 : -1;
- val = ((_previous == over) || Double.IsNaN(this._previous) || (this._previous == 0)) ? 0 : val;
- (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,val);
-
- this._previous = over;
-
- if (update) { base[^1] = result; }
- else { base.Add(result); }
-
- }
-}
-
-
+namespace QuanTAlib;
+using System;
+
+/*
+OVER - Generates +1 if A is above B, -1 if A is below B and 0 if A=B
+
+Remarks:
+ OVER.Cross generates 1 when A breaks B from below and -1 when A breaks B from above
+
+ */
+
+public class CROSS_Series : Pair_TSeries_Indicator
+{
+ public TSeries Cross { get; set; } = new();
+
+ private double _previous = double.NaN;
+ public CROSS_Series(TSeries d1, TSeries d2) : base(d1, d2)
+ {
+ if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
+ }
+ public CROSS_Series(TSeries d1, double dd2) : base(d1, dd2)
+ {
+ if (base._d1.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], (base._d1[i].t, dd2), false); } }
+ }
+ public CROSS_Series(double dd1, TSeries d2) : base(dd1, d2)
+ {
+ if (base._d2.Count > 0) { for (int i = 0; i < base._d2.Count; i++) { this.Add((base._d2[i].t, dd1), base._d2[i], false); } }
+ }
+
+ public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
+ {
+
+ double val = TValue1.v > TValue2.v ? 1 : -1;
+ val = TValue1.v == TValue2.v ? 0 : val;
+ double over = TValue1.v > TValue2.v ? 1 : val;
+
+ val = (_previous < over) ? 1 : -1;
+ val = ((_previous == over) || Double.IsNaN(this._previous) || (this._previous == 0)) ? 0 : val;
+ (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t, val);
+
+ this._previous = over;
+
+ if (update) { base[^1] = result; }
+ else { base.Add(result); }
+
+ }
+}
+
+
diff --git a/Calculations/Logic/EQUITY_Series.cs b/Calculations/Logic/EQUITY_Series.cs
index 8323feb7..36a97667 100644
--- a/Calculations/Logic/EQUITY_Series.cs
+++ b/Calculations/Logic/EQUITY_Series.cs
@@ -1,91 +1,91 @@
-namespace QuanTAlib;
-using System;
-
-/*
-EQUITY - Generates P&L portfolio based on trades signals and equity prices
-
- */
-
-
-//base prices: bars.close
-//trade signals: trades
-//optional: long, short, long&short
-//optional: warmup period: warmup
-
-/*
-
-public class EQUITY_Series : Single_TSeries_Indicator {
- readonly TSeries inmarket; //for every bar
- private readonly TSeries _price;
- private double _equity;
- private readonly double _capital;
-
- readonly int _warmup;
- double _cash;
- int _units;
- private bool _longbuy, _longsell;
- double _long_order, _open_order;
- double _investment_value;
- short _inmarket;
-
- public EQUITY_Series(TSeries signal, TSeries price, int warmup = 0, double capital = 1000) : base(signal, period: 0, useNaN: false) {
- _capital = capital;
- _cash = _capital;
- _investment_value = 0;
- _warmup = (warmup > 0) ? warmup : 1;
-
- inmarket = new();
- _longbuy = _longsell = false;
- _open_order = 0;
- _inmarket = 0;
- _units = 0;
- _long_order = 0;
-
- _price = price; //we buy on the Open price of the NEXT bar
- _long_order = 0;
-
- if (base._data.Count > 0) { base.Add(base._data); }
- }
-
- public override void Add((System.DateTime t, double v) TValue, bool update) {
-
- if (this.Count > _warmup) {
-
- // harvest the gain-loss from previous day
- _investment_value = _units * _price[this.Count - 1].v;
- _equity = _cash + _investment_value;
-
-
- //execute orders from previous bar
- if (_longbuy && _inmarket == 0) { //time to execute the long buy
- _units = (int)(_cash / _price[this.Count - 1].v);
- _long_order = _units * _price[this.Count - 1].v;
- _cash -= _long_order;
- _open_order = _long_order;
- _equity = _cash + _open_order;
- _inmarket = 1;
- _longbuy = false;
- }
-
- if (_longsell && _inmarket == 1) { //time to execute the long sell
- _long_order = (_units * _price[this.Count - 1].v);
- _cash += _long_order;
- _units = 0;
-
- _open_order = 0;
- _equity = _cash + _open_order;
- _inmarket = 0;
- _longsell = false;
- }
-
- if (_inmarket == 0 && TValue.v == 1) { _longbuy = true; } //out of market, enter long
- if (_inmarket == 1 && TValue.v == -1) { _longsell = true; } //long market, exit long
-
- //Console.WriteLine($"{TValue.v,3}\t {(_inmarket)} : {_cash,10:f2} + {_units*_price[^1].v,7:f2} = {_equity-_capital:f2}");
- }
- inmarket.Add((TValue.t, (double)_inmarket));
- base.Add((TValue.t, _equity), update, _NaN);
- }
-}
-
+namespace QuanTAlib;
+using System;
+
+/*
+EQUITY - Generates P&L portfolio based on trades signals and equity prices
+
+ */
+
+
+//base prices: bars.close
+//trade signals: trades
+//optional: long, short, long&short
+//optional: warmup period: warmup
+
+/*
+
+public class EQUITY_Series : Single_TSeries_Indicator {
+ readonly TSeries inmarket; //for every bar
+ private readonly TSeries _price;
+ private double _equity;
+ private readonly double _capital;
+
+ readonly int _warmup;
+ double _cash;
+ int _units;
+ private bool _longbuy, _longsell;
+ double _long_order, _open_order;
+ double _investment_value;
+ short _inmarket;
+
+ public EQUITY_Series(TSeries signal, TSeries price, int warmup = 0, double capital = 1000) : base(signal, period: 0, useNaN: false) {
+ _capital = capital;
+ _cash = _capital;
+ _investment_value = 0;
+ _warmup = (warmup > 0) ? warmup : 1;
+
+ inmarket = new();
+ _longbuy = _longsell = false;
+ _open_order = 0;
+ _inmarket = 0;
+ _units = 0;
+ _long_order = 0;
+
+ _price = price; //we buy on the Open price of the NEXT bar
+ _long_order = 0;
+
+ if (base._data.Count > 0) { base.Add(base._data); }
+ }
+
+ public override void Add((System.DateTime t, double v) TValue, bool update) {
+
+ if (this.Count > _warmup) {
+
+ // harvest the gain-loss from previous day
+ _investment_value = _units * _price[this.Count - 1].v;
+ _equity = _cash + _investment_value;
+
+
+ //execute orders from previous bar
+ if (_longbuy && _inmarket == 0) { //time to execute the long buy
+ _units = (int)(_cash / _price[this.Count - 1].v);
+ _long_order = _units * _price[this.Count - 1].v;
+ _cash -= _long_order;
+ _open_order = _long_order;
+ _equity = _cash + _open_order;
+ _inmarket = 1;
+ _longbuy = false;
+ }
+
+ if (_longsell && _inmarket == 1) { //time to execute the long sell
+ _long_order = (_units * _price[this.Count - 1].v);
+ _cash += _long_order;
+ _units = 0;
+
+ _open_order = 0;
+ _equity = _cash + _open_order;
+ _inmarket = 0;
+ _longsell = false;
+ }
+
+ if (_inmarket == 0 && TValue.v == 1) { _longbuy = true; } //out of market, enter long
+ if (_inmarket == 1 && TValue.v == -1) { _longsell = true; } //long market, exit long
+
+ //Console.WriteLine($"{TValue.v,3}\t {(_inmarket)} : {_cash,10:f2} + {_units*_price[^1].v,7:f2} = {_equity-_capital:f2}");
+ }
+ inmarket.Add((TValue.t, (double)_inmarket));
+ base.Add((TValue.t, _equity), update, _NaN);
+ }
+}
+
*/
\ No newline at end of file
diff --git a/Calculations/Logic/TOrders.cs b/Calculations/Logic/TOrders.cs
index bb1a1e71..1e122b2b 100644
--- a/Calculations/Logic/TOrders.cs
+++ b/Calculations/Logic/TOrders.cs
@@ -1,34 +1,38 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Data;
-using System.Linq;
-
-
-public enum OType {
- NIL = 0, // No position
- BTO = 1, // Buy to Open
- STC = 2, // Sell to Close
- STO = 3, // Sell to Open
- BTC = 4, // Buy to Close
- END = 5, // Exit the trade
-}
-
-
-public class TOrders : List<(DateTime t, OType o)> {
-
- public void Add((DateTime t, OType o) TOrder, bool update = false)
- {
- if (update) { this[^1] = TOrder; }
- else { base.Add(TOrder); }
- OnEvent(update);
- }
-
-
- protected virtual void OnEvent(bool update = false) {
- Pub?.Invoke(this, new TSeriesEventArgs { update = update }); }
- public delegate void NewDataEventHandler(object source, TSeriesEventArgs args);
- public event NewDataEventHandler Pub;
-
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Data;
+using System.Linq;
+
+
+public enum OType
+{
+ NIL = 0, // No position
+ BTO = 1, // Buy to Open
+ STC = 2, // Sell to Close
+ STO = 3, // Sell to Open
+ BTC = 4, // Buy to Close
+ END = 5, // Exit the trade
+}
+
+
+public class TOrders : List<(DateTime t, OType o)>
+{
+
+ public void Add((DateTime t, OType o) TOrder, bool update = false)
+ {
+ if (update) { this[^1] = TOrder; }
+ else { base.Add(TOrder); }
+ OnEvent(update);
+ }
+
+
+ protected virtual void OnEvent(bool update = false)
+ {
+ Pub?.Invoke(this, new TSeriesEventArgs { update = update });
+ }
+ public delegate void NewDataEventHandler(object source, TSeriesEventArgs args);
+ public event NewDataEventHandler Pub;
+
}
\ No newline at end of file
diff --git a/Calculations/_Updated/ADL_Series.cs b/Calculations/_Updated/ADL_Series.cs
index aa33c7b2..d84c1cf6 100644
--- a/Calculations/_Updated/ADL_Series.cs
+++ b/Calculations/_Updated/ADL_Series.cs
@@ -1,69 +1,79 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-ADL: Chaikin Accumulation/Distribution Line
- ADL is a volume-based indicator that measures the cumulative Money Flow Volume:
-
- 1. Money Flow Multiplier = [(Close - Low) - (High - Close)] /(High - Low)
- 2. Money Flow Volume = Money Flow Multiplier x Volume for the Period
- 3. ADL = Previous ADL + Current Period's Money Flow Volume
-
-Sources:
- https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line
-
- */
-
-public class ADL_Series : TSeries {
- protected readonly TBars _data;
- private double _lastadl, _lastlastadl;
-
- //core constructors
- public ADL_Series() {
- Name = $"ADL()";
- _lastadl = _lastlastadl = 0;
- }
- public ADL_Series(TBars source) {
- _data = source;
- Name = $"ADL({(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _lastadl = _lastlastadl = 0;
- _data.Pub += Sub;
- Add(data: _data);
- }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
- if (update) { this._lastadl = this._lastlastadl; }
- else { this._lastlastadl = this._lastadl; }
-
- double _adl = 0;
- double tmp = TBar.h - TBar.l;
- if (tmp > 0.0) {
- _adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v);
- }
- _lastadl = _adl;
-
- var ret = (TBar.t, _adl);
- return base.Add(ret, update);
- }
-
- public new void Add(TBars data) {
- foreach (var item in data) { Add(item, false); }
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TBar: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TBar: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TBar: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _lastadl = _lastlastadl = 0;
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+ADL: Chaikin Accumulation/Distribution Line
+ ADL is a volume-based indicator that measures the cumulative Money Flow Volume:
+
+ 1. Money Flow Multiplier = [(Close - Low) - (High - Close)] /(High - Low)
+ 2. Money Flow Volume = Money Flow Multiplier x Volume for the Period
+ 3. ADL = Previous ADL + Current Period's Money Flow Volume
+
+Sources:
+ https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line
+
+ */
+
+public class ADL_Series : TSeries
+{
+ protected readonly TBars _data;
+ private double _lastadl, _lastlastadl;
+
+ //core constructors
+ public ADL_Series()
+ {
+ Name = $"ADL()";
+ _lastadl = _lastlastadl = 0;
+ }
+ public ADL_Series(TBars source)
+ {
+ _data = source;
+ Name = $"ADL({(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _lastadl = _lastlastadl = 0;
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
+ {
+ if (update) { this._lastadl = this._lastlastadl; }
+ else { this._lastlastadl = this._lastadl; }
+
+ double _adl = 0;
+ double tmp = TBar.h - TBar.l;
+ if (tmp > 0.0)
+ {
+ _adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v);
+ }
+ _lastadl = _adl;
+
+ var ret = (TBar.t, _adl);
+ return base.Add(ret, update);
+ }
+
+ public new void Add(TBars data)
+ {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _lastadl = _lastlastadl = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/ADOSC_Series.cs b/Calculations/_Updated/ADOSC_Series.cs
index 63aa2104..bc5b4305 100644
--- a/Calculations/_Updated/ADOSC_Series.cs
+++ b/Calculations/_Updated/ADOSC_Series.cs
@@ -1,90 +1,100 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-ADOSC: Chaikin Accumulation/Distribution Oscillator
- ADO measures the momentum of ADL using the difference between slow (10-day) EMA(ADL)
- and fast (3-day) EMA(ADL):
-
- Chaikin A/D Oscillator is defined as 3-day EMA of ADL minus 10-day EMA of ADL
-
-Sources:
- https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_oscillator
-
- */
-
-public class ADOSC_Series : TSeries {
- protected readonly TBars _data;
- private readonly double _k1, _k2;
- private double _lastema1, _lastlastema1, _lastema2, _lastlastema2;
- private double _lastadl, _lastlastadl;
-
- //core constructors
- public ADOSC_Series(int shortPeriod, int longPeriod, bool useNaN = false) {
- Name = $"ADOSC()";
- _k1 = 2.0 / (shortPeriod + 1);
- _k2 = 2.0 / (longPeriod + 1);
- _lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
- }
- public ADOSC_Series(TBars source, int shortPeriod, int longPeriod, bool useNaN = false) :this(shortPeriod, longPeriod, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _lastadl = _lastlastadl = 0;
- _data.Pub += Sub;
- Add(data: _data);
- }
-
- public ADOSC_Series() : this(shortPeriod: 3, longPeriod: 10, useNaN: false) {}
-
- public ADOSC_Series(TBars source) : this(source, shortPeriod: 3, longPeriod:10, useNaN:false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update= false) {
-
- if (update) {
- _lastadl = _lastlastadl;
- _lastema1 = _lastlastema1;
- _lastema2 = _lastlastema2;
- }
-
- double _adl = 0;
- double tmp = TBar.h - TBar.l;
- if (tmp > 0.0) { _adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v); }
- if (this.Count == 0) { _lastema1 = _lastema2 = _adl; }
-
- double _ema1 = (_adl - _lastema1) * _k1 + _lastema1;
- double _ema2 = (_adl - _lastema2) * _k2 + _lastema2;
-
- _lastlastadl = _lastadl;
- _lastadl = _adl;
- _lastlastema1 = _lastema1;
- _lastema1 = _ema1;
- _lastlastema2 = _lastema2;
- _lastema2 = _ema2;
-
- double _adosc = _ema1 - _ema2;
-
- var ret = (TBar.t, _adosc);
- return base.Add(ret, update);
- }
-
- public new void Add(TBars data) {
- foreach (var item in data) { Add(item, false); }
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TBar: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TBar: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TBar: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+ADOSC: Chaikin Accumulation/Distribution Oscillator
+ ADO measures the momentum of ADL using the difference between slow (10-day) EMA(ADL)
+ and fast (3-day) EMA(ADL):
+
+ Chaikin A/D Oscillator is defined as 3-day EMA of ADL minus 10-day EMA of ADL
+
+Sources:
+ https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_oscillator
+
+ */
+
+public class ADOSC_Series : TSeries
+{
+ protected readonly TBars _data;
+ private readonly double _k1, _k2;
+ private double _lastema1, _lastlastema1, _lastema2, _lastlastema2;
+ private double _lastadl, _lastlastadl;
+
+ //core constructors
+ public ADOSC_Series(int shortPeriod, int longPeriod, bool useNaN = false)
+ {
+ Name = $"ADOSC()";
+ _k1 = 2.0 / (shortPeriod + 1);
+ _k2 = 2.0 / (longPeriod + 1);
+ _lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
+ }
+ public ADOSC_Series(TBars source, int shortPeriod, int longPeriod, bool useNaN = false) : this(shortPeriod, longPeriod, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _lastadl = _lastlastadl = 0;
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+
+ public ADOSC_Series() : this(shortPeriod: 3, longPeriod: 10, useNaN: false) { }
+
+ public ADOSC_Series(TBars source) : this(source, shortPeriod: 3, longPeriod: 10, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
+ {
+
+ if (update)
+ {
+ _lastadl = _lastlastadl;
+ _lastema1 = _lastlastema1;
+ _lastema2 = _lastlastema2;
+ }
+
+ double _adl = 0;
+ double tmp = TBar.h - TBar.l;
+ if (tmp > 0.0) { _adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v); }
+ if (this.Count == 0) { _lastema1 = _lastema2 = _adl; }
+
+ double _ema1 = (_adl - _lastema1) * _k1 + _lastema1;
+ double _ema2 = (_adl - _lastema2) * _k2 + _lastema2;
+
+ _lastlastadl = _lastadl;
+ _lastadl = _adl;
+ _lastlastema1 = _lastema1;
+ _lastema1 = _ema1;
+ _lastlastema2 = _lastema2;
+ _lastema2 = _ema2;
+
+ double _adosc = _ema1 - _ema2;
+
+ var ret = (TBar.t, _adosc);
+ return base.Add(ret, update);
+ }
+
+ public new void Add(TBars data)
+ {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/ALMA_Series.cs b/Calculations/_Updated/ALMA_Series.cs
index 514e0e34..a25ac7d5 100644
--- a/Calculations/_Updated/ALMA_Series.cs
+++ b/Calculations/_Updated/ALMA_Series.cs
@@ -1,114 +1,129 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-ALMA: Arnaud Legoux Moving Average
- The ALMA moving average uses the curve of the Normal (Gauss) distribution, which
- can be shifted from 0 to 1. This allows regulating the smoothness and high
- sensitivity of the indicator. Sigma is another parameter that is responsible for
- the shape of the curve coefficients. This moving average reduces lag of the data
- in conjunction with smoothing to reduce noise.
-
-
-Sources:
- https://phemex.com/academy/what-is-arnaud-legoux-moving-averages
- https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/
-
- Discrepancy with Pandas-TA (but passes the validation with Skender.GetAlma)
- */
-
-public class ALMA_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- private readonly System.Collections.Generic.List _buffer = new();
- private readonly System.Collections.Generic.List _weight;
- private double _norm;
- private readonly double _offset, _sigma;
-
- //core constructors
- public ALMA_Series(int period, double offset, double sigma, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"ALMA({period})";
- _offset = offset;
- _sigma = sigma;
- _weight = new();
- }
- public ALMA_Series(TSeries source, int period, double offset, double sigma, bool useNaN) : this(period, offset, sigma, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
-
- public ALMA_Series() : this(period:0, offset:0.85, sigma:6.0, useNaN: false) { }
- public ALMA_Series(int period) : this(period: period, offset:0.85, sigma:6.0, useNaN:false) { }
- public ALMA_Series(TBars source) : this(source:source.Close, period:0, offset:0.85, sigma:6.0, useNaN:false) { }
- public ALMA_Series(TBars source, int period) : this(source:source.Close, period:period, offset: 0.85, sigma: 6.0, useNaN: false) { }
- public ALMA_Series(TBars source, int period, double offset, double sigma, bool useNaN) : this(source.Close, period:period, offset: offset, sigma: sigma, useNaN: false) { }
- public ALMA_Series(TSeries source) : this(source, period:0, offset:0.85, sigma:6.0, useNaN:false) { }
- public ALMA_Series(TSeries source, int period) : this(source:source, period:period, offset:0.85, sigma:6.0, useNaN:false) { }
- public ALMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, offset: 0.85, sigma: 6.0, useNaN: useNaN) { }
-
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, double.NaN), update);
- }
-
- BufferTrim(_buffer, TValue.v, _period, update);
- if (_weight.Count < _buffer.Count) {
- for (var i = 0; i < _buffer.Count - _weight.Count; i++) {
- _weight.Add(0.0);
- }
- }
-
-
- if (_buffer.Count <= _period || _period == 0) {
- var _len = _buffer.Count;
- _norm = 0;
- var _m = _offset * (_len - 1);
- var _s = _len / _sigma;
- for (var i = 0; i < _len; i++) {
- var _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
- _weight[i] = _wt;
- _norm += _wt;
- }
- }
-
- double _weightedSum = 0;
- for (var i = 0; i < _buffer.Count; i++) {
- _weightedSum += _weight[i] * _buffer[i];
- }
-
- var _alma = _weightedSum / _norm;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _alma);
- return base.Add(res, update);
- }
-
- //variation of Add()
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- _weight.Clear();
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+ALMA: Arnaud Legoux Moving Average
+ The ALMA moving average uses the curve of the Normal (Gauss) distribution, which
+ can be shifted from 0 to 1. This allows regulating the smoothness and high
+ sensitivity of the indicator. Sigma is another parameter that is responsible for
+ the shape of the curve coefficients. This moving average reduces lag of the data
+ in conjunction with smoothing to reduce noise.
+
+
+Sources:
+ https://phemex.com/academy/what-is-arnaud-legoux-moving-averages
+ https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/
+
+ Discrepancy with Pandas-TA (but passes the validation with Skender.GetAlma)
+ */
+
+public class ALMA_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ private readonly System.Collections.Generic.List _buffer = new();
+ private readonly System.Collections.Generic.List _weight;
+ private double _norm;
+ private readonly double _offset, _sigma;
+
+ //core constructors
+ public ALMA_Series(int period, double offset, double sigma, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"ALMA({period})";
+ _offset = offset;
+ _sigma = sigma;
+ _weight = new();
+ }
+ public ALMA_Series(TSeries source, int period, double offset, double sigma, bool useNaN) : this(period, offset, sigma, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+
+ public ALMA_Series() : this(period: 0, offset: 0.85, sigma: 6.0, useNaN: false) { }
+ public ALMA_Series(int period) : this(period: period, offset: 0.85, sigma: 6.0, useNaN: false) { }
+ public ALMA_Series(TBars source) : this(source: source.Close, period: 0, offset: 0.85, sigma: 6.0, useNaN: false) { }
+ public ALMA_Series(TBars source, int period) : this(source: source.Close, period: period, offset: 0.85, sigma: 6.0, useNaN: false) { }
+ public ALMA_Series(TBars source, int period, double offset, double sigma, bool useNaN) : this(source.Close, period: period, offset: offset, sigma: sigma, useNaN: false) { }
+ public ALMA_Series(TSeries source) : this(source, period: 0, offset: 0.85, sigma: 6.0, useNaN: false) { }
+ public ALMA_Series(TSeries source, int period) : this(source: source, period: period, offset: 0.85, sigma: 6.0, useNaN: false) { }
+ public ALMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, offset: 0.85, sigma: 6.0, useNaN: useNaN) { }
+
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, double.NaN), update);
+ }
+
+ BufferTrim(_buffer, TValue.v, _period, update);
+ if (_weight.Count < _buffer.Count)
+ {
+ for (var i = 0; i < _buffer.Count - _weight.Count; i++)
+ {
+ _weight.Add(0.0);
+ }
+ }
+
+
+ if (_buffer.Count <= _period || _period == 0)
+ {
+ var _len = _buffer.Count;
+ _norm = 0;
+ var _m = _offset * (_len - 1);
+ var _s = _len / _sigma;
+ for (var i = 0; i < _len; i++)
+ {
+ var _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
+ _weight[i] = _wt;
+ _norm += _wt;
+ }
+ }
+
+ double _weightedSum = 0;
+ for (var i = 0; i < _buffer.Count; i++)
+ {
+ _weightedSum += _weight[i] * _buffer[i];
+ }
+
+ var _alma = _weightedSum / _norm;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _alma);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ _weight.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/ATRP_Series.cs b/Calculations/_Updated/ATRP_Series.cs
index 3ba2c1dc..ee429ea0 100644
--- a/Calculations/_Updated/ATRP_Series.cs
+++ b/Calculations/_Updated/ATRP_Series.cs
@@ -1,87 +1,97 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-ATRP: Average True Range Percent
- Average True Range Percent is (ATR/Close Price)*100.
- This normalizes so it can be compared to other stocks.
-
-Sources:
- https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/atrp
-
- */
-
-public class ATRP_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TBars _data;
- private double _k;
- private int _len;
- private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
-
- //core constructors
- public ATRP_Series(int period, bool useNaN) {
- _period = period;
- _k = 1.0 / (double)(_period);
- _NaN = useNaN;
- _len = 0;
- Name = $"ATRP({period})";
- }
- public ATRP_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(data: _data);
- }
- public ATRP_Series() : this(period: 1, useNaN: false) { }
- public ATRP_Series(int period) : this(period: period, useNaN: false) { }
- public ATRP_Series(TBars source) : this(source, period: 1, useNaN: false) { }
- public ATRP_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
- if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
- else {
- _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum;
- _k = (_period == 0) ? 1 / (double)_len : _k;
- _len++;
- }
-
- if (_len == 1) { _cm1 = TBar.c; }
- double d1 = Math.Abs(TBar.h - TBar.l);
- double d2 = Math.Abs(_cm1 - TBar.h);
- double d3 = Math.Abs(_cm1 - TBar.l);
- (DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
- _cm1 = TBar.c;
-
- double _atr = 0;
- if (this.Count == 0) { _atr = d.v; }
- else if (this.Count < _period + 1) { _sum += d.v; _atr = _sum / (this.Count); }
- else { _atr = _k * (d.v - _lastatr) + _lastatr; }
- _lastatr = _atr;
- double _atrp = 100 * (_atr / TBar.c);
-
- var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _atrp);
- return base.Add(res, update);
- }
-
- public new void Add(TBars data) {
- foreach (var item in data) { Add(item, false); }
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TBar: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TBar: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TBar: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _len = 0;
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+ATRP: Average True Range Percent
+ Average True Range Percent is (ATR/Close Price)*100.
+ This normalizes so it can be compared to other stocks.
+
+Sources:
+ https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/atrp
+
+ */
+
+public class ATRP_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TBars _data;
+ private double _k;
+ private int _len;
+ private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
+
+ //core constructors
+ public ATRP_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _k = 1.0 / (double)(_period);
+ _NaN = useNaN;
+ _len = 0;
+ Name = $"ATRP({period})";
+ }
+ public ATRP_Series(TBars source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+ public ATRP_Series() : this(period: 1, useNaN: false) { }
+ public ATRP_Series(int period) : this(period: period, useNaN: false) { }
+ public ATRP_Series(TBars source) : this(source, period: 1, useNaN: false) { }
+ public ATRP_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
+ {
+ if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
+ else
+ {
+ _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum;
+ _k = (_period == 0) ? 1 / (double)_len : _k;
+ _len++;
+ }
+
+ if (_len == 1) { _cm1 = TBar.c; }
+ double d1 = Math.Abs(TBar.h - TBar.l);
+ double d2 = Math.Abs(_cm1 - TBar.h);
+ double d3 = Math.Abs(_cm1 - TBar.l);
+ (DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
+ _cm1 = TBar.c;
+
+ double _atr = 0;
+ if (this.Count == 0) { _atr = d.v; }
+ else if (this.Count < _period + 1) { _sum += d.v; _atr = _sum / (this.Count); }
+ else { _atr = _k * (d.v - _lastatr) + _lastatr; }
+ _lastatr = _atr;
+ double _atrp = 100 * (_atr / TBar.c);
+
+ var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _atrp);
+ return base.Add(res, update);
+ }
+
+ public new void Add(TBars data)
+ {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _len = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/ATR_Series.cs b/Calculations/_Updated/ATR_Series.cs
index 9935f5c4..c09ce7b2 100644
--- a/Calculations/_Updated/ATR_Series.cs
+++ b/Calculations/_Updated/ATR_Series.cs
@@ -1,88 +1,98 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-ATR: wildeR Moving Average
- The average true range (ATR) is a price volatility indicator
- showing the average price variation of assets within a given time period.
-
-Sources:
- https://en.wikipedia.org/wiki/Average_true_range
- https://www.tradingview.com/wiki/Average_True_Range_(ATR)
- https://www.investopedia.com/terms/a/atr.asp
-
- */
-
-public class ATR_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TBars _data;
- private double _k;
- private int _len;
- private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
-
- //core constructors
- public ATR_Series(int period, bool useNaN) {
- _period = period;
- _k = 1.0 / (double)(_period);
- _NaN = useNaN;
- _len = 0;
- Name = $"ATR({period})";
- }
- public ATR_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(data: _data);
- }
- public ATR_Series() : this(period: 1, useNaN: false) { }
- public ATR_Series(int period) : this(period: period, useNaN: false) { }
- public ATR_Series(TBars source) : this(source, period: 1, useNaN: false) { }
- public ATR_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
- if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
- else {
- _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum;
- _k = (_period == 0) ? 1 / (double)_len : _k;
- _len++;
- }
-
- if (_len == 1) { _cm1 = TBar.c; }
- double d1 = Math.Abs(TBar.h - TBar.l);
- double d2 = Math.Abs(_cm1 - TBar.h);
- double d3 = Math.Abs(_cm1 - TBar.l);
- (DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
- _cm1 = TBar.c;
-
- double _atr = 0;
- if (this.Count == 0) { _atr = d.v; }
- else if (this.Count < _period + 1) { _sum += d.v; _atr = _sum / (this.Count); }
- else { _atr = _k * (d.v - _lastatr) + _lastatr; }
- _lastatr = _atr;
-
- var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _atr);
- return base.Add(res, update);
- }
-
- public new void Add(TBars data) {
- foreach (var item in data) { Add(item, false); }
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TBar: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TBar: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TBar: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _len = 0;
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+ATR: wildeR Moving Average
+ The average true range (ATR) is a price volatility indicator
+ showing the average price variation of assets within a given time period.
+
+Sources:
+ https://en.wikipedia.org/wiki/Average_true_range
+ https://www.tradingview.com/wiki/Average_True_Range_(ATR)
+ https://www.investopedia.com/terms/a/atr.asp
+
+ */
+
+public class ATR_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TBars _data;
+ private double _k;
+ private int _len;
+ private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
+
+ //core constructors
+ public ATR_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _k = 1.0 / (double)(_period);
+ _NaN = useNaN;
+ _len = 0;
+ Name = $"ATR({period})";
+ }
+ public ATR_Series(TBars source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+ public ATR_Series() : this(period: 1, useNaN: false) { }
+ public ATR_Series(int period) : this(period: period, useNaN: false) { }
+ public ATR_Series(TBars source) : this(source, period: 1, useNaN: false) { }
+ public ATR_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
+ {
+ if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
+ else
+ {
+ _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum;
+ _k = (_period == 0) ? 1 / (double)_len : _k;
+ _len++;
+ }
+
+ if (_len == 1) { _cm1 = TBar.c; }
+ double d1 = Math.Abs(TBar.h - TBar.l);
+ double d2 = Math.Abs(_cm1 - TBar.h);
+ double d3 = Math.Abs(_cm1 - TBar.l);
+ (DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
+ _cm1 = TBar.c;
+
+ double _atr = 0;
+ if (this.Count == 0) { _atr = d.v; }
+ else if (this.Count < _period + 1) { _sum += d.v; _atr = _sum / (this.Count); }
+ else { _atr = _k * (d.v - _lastatr) + _lastatr; }
+ _lastatr = _atr;
+
+ var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _atr);
+ return base.Add(res, update);
+ }
+
+ public new void Add(TBars data)
+ {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _len = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/BBANDS_Series.cs b/Calculations/_Updated/BBANDS_Series.cs
index 198b2a38..e64398ff 100644
--- a/Calculations/_Updated/BBANDS_Series.cs
+++ b/Calculations/_Updated/BBANDS_Series.cs
@@ -1,112 +1,121 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-BBANDS: Bollinger Bands®
- Price channels created by John Bollinger, depict volatility as standard deviation boundary
- line range from a moving average of price. The bands automatically widen when volatility
- increases and contract when volatility decreases. Their dynamic nature allows them to be
- used on different securities with the standard settings.
-
- Mid Band = simple moving average (SMA)
- Upper Band = SMA + (standard deviation of price x multiplier)
- Lower Band = SMA - (standard deviation of price x multiplier)
- Bandwidth = Width of the channel: (Upper-Lower)/SMA
- %B = The location of the data point within the channel: (Price-Lower)/(Upper/Lower)
- Z-Score = number of standard deviations of the data point from SMA
-
-Sources:
- https://www.investopedia.com/terms/b/bollingerbands.asp
- https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands
-
-Note:
- Bollinger Bands® is a registered trademark of John A. Bollinger.
-
- */
-
-public class BBANDS_Series : TSeries {
- protected readonly int _period;
- protected readonly double _multiplier;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- public SMA_Series Mid { get; }
- public TSeries Upper { get; }
- public TSeries Lower { get; }
- public TSeries PercentB { get; }
- public TSeries Bandwidth { get; }
- public TSeries Zscore { get; }
- private readonly SDEV_Series _sdev;
-
- //core constructors
- public BBANDS_Series(int period, double multiplier, bool useNaN) {
- _period = period;
- _multiplier = multiplier;
- _NaN = useNaN;
- Name = $"BBANDS({period})";
- }
- public BBANDS_Series(TSeries source, int period, double multiplier, bool useNaN) : this(period, multiplier, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- Upper = new("BB_Up");
- Lower = new("BB_Low");
- Bandwidth = new("BBandwidth");
- PercentB = new("%BBandwidth");
- Zscore = new("Zscore");
-
- Mid = new(period, false);
- _sdev = new(period, false);
-
- _data.Pub += Sub;
- Add(_data);
- }
-
- public BBANDS_Series() : this(period:0, multiplier: 2.0, useNaN: false) { }
- public BBANDS_Series(int period) : this(period: period, multiplier: 2.0, useNaN:false) { }
- public BBANDS_Series(TBars source) : this(source:source.Close, period:0, multiplier: 2.0, useNaN:false) { }
- public BBANDS_Series(TBars source, int period) : this(source:source.Close, period:period, multiplier: 2.0, useNaN: false) { }
- public BBANDS_Series(TBars source, int period, double multiplier, bool useNaN) : this(source.Close, period:period, multiplier:multiplier, useNaN: false) { }
- public BBANDS_Series(TSeries source) : this(source, period:0, useNaN:false) { }
- public BBANDS_Series(TSeries source, int period) : this(source:source, period:period, useNaN:false) { }
- public BBANDS_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, multiplier: 2.0, useNaN: useNaN) { }
-
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) {
- var _mid = Mid.Add(TValue,update);
- var _sd = this._sdev.Add(TValue, update);
- var _upper = Upper.Add((TValue.t, _mid.v + _sd.v * _multiplier), update);
- var _lower = Lower.Add((TValue.t, _mid.v - _sd.v * _multiplier), update);
- double _pbdnd = TValue.v - _lower.v;
- double _pbdvr = _upper.v - _lower.v;
- PercentB.Add((TValue.t, _pbdnd/_pbdvr), update);
- Zscore.Add((TValue.t, (TValue.v-_mid.v)/_sd.v), update);
- Bandwidth.Add((TValue.t, _pbdvr / _mid.v), update);
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _pbdvr / _mid.v);
- return base.Add(res, update);
- }
-
- //variation of Add()
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
- //reset calculation
- public override void Reset() {
- Mid.Clear();
- _sdev.Clear();
- Upper.Clear();
- Lower.Clear();
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+BBANDS: Bollinger Bands®
+ Price channels created by John Bollinger, depict volatility as standard deviation boundary
+ line range from a moving average of price. The bands automatically widen when volatility
+ increases and contract when volatility decreases. Their dynamic nature allows them to be
+ used on different securities with the standard settings.
+
+ Mid Band = simple moving average (SMA)
+ Upper Band = SMA + (standard deviation of price x multiplier)
+ Lower Band = SMA - (standard deviation of price x multiplier)
+ Bandwidth = Width of the channel: (Upper-Lower)/SMA
+ %B = The location of the data point within the channel: (Price-Lower)/(Upper/Lower)
+ Z-Score = number of standard deviations of the data point from SMA
+
+Sources:
+ https://www.investopedia.com/terms/b/bollingerbands.asp
+ https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands
+
+Note:
+ Bollinger Bands® is a registered trademark of John A. Bollinger.
+
+ */
+
+public class BBANDS_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly double _multiplier;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ public SMA_Series Mid { get; }
+ public TSeries Upper { get; }
+ public TSeries Lower { get; }
+ public TSeries PercentB { get; }
+ public TSeries Bandwidth { get; }
+ public TSeries Zscore { get; }
+ private readonly SDEV_Series _sdev;
+
+ //core constructors
+ public BBANDS_Series(int period, double multiplier, bool useNaN)
+ {
+ _period = period;
+ _multiplier = multiplier;
+ _NaN = useNaN;
+ Name = $"BBANDS({period})";
+ }
+ public BBANDS_Series(TSeries source, int period, double multiplier, bool useNaN) : this(period, multiplier, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ Upper = new("BB_Up");
+ Lower = new("BB_Low");
+ Bandwidth = new("BBandwidth");
+ PercentB = new("%BBandwidth");
+ Zscore = new("Zscore");
+
+ Mid = new(period, false);
+ _sdev = new(period, false);
+
+ _data.Pub += Sub;
+ Add(_data);
+ }
+
+ public BBANDS_Series() : this(period: 0, multiplier: 2.0, useNaN: false) { }
+ public BBANDS_Series(int period) : this(period: period, multiplier: 2.0, useNaN: false) { }
+ public BBANDS_Series(TBars source) : this(source: source.Close, period: 0, multiplier: 2.0, useNaN: false) { }
+ public BBANDS_Series(TBars source, int period) : this(source: source.Close, period: period, multiplier: 2.0, useNaN: false) { }
+ public BBANDS_Series(TBars source, int period, double multiplier, bool useNaN) : this(source.Close, period: period, multiplier: multiplier, useNaN: false) { }
+ public BBANDS_Series(TSeries source) : this(source, period: 0, useNaN: false) { }
+ public BBANDS_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+ public BBANDS_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, multiplier: 2.0, useNaN: useNaN) { }
+
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ var _mid = Mid.Add(TValue, update);
+ var _sd = this._sdev.Add(TValue, update);
+ var _upper = Upper.Add((TValue.t, _mid.v + _sd.v * _multiplier), update);
+ var _lower = Lower.Add((TValue.t, _mid.v - _sd.v * _multiplier), update);
+ double _pbdnd = TValue.v - _lower.v;
+ double _pbdvr = _upper.v - _lower.v;
+ PercentB.Add((TValue.t, _pbdnd / _pbdvr), update);
+ Zscore.Add((TValue.t, (TValue.v - _mid.v) / _sd.v), update);
+ Bandwidth.Add((TValue.t, _pbdvr / _mid.v), update);
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _pbdvr / _mid.v);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+ //reset calculation
+ public override void Reset()
+ {
+ Mid.Clear();
+ _sdev.Clear();
+ Upper.Clear();
+ Lower.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/BIAS_Series.cs b/Calculations/_Updated/BIAS_Series.cs
index df9bc5a5..cf724bf3 100644
--- a/Calculations/_Updated/BIAS_Series.cs
+++ b/Calculations/_Updated/BIAS_Series.cs
@@ -1,72 +1,81 @@
-namespace QuanTAlib;
-using System;
-
-/*
-BIAS: Rate of change between the source and a moving average.
- Bias is a statistical term which means a systematic deviation from the actual value.
-
-BIAS = (close - SMA) / SMA
- = (close / SMA) - 1
-
-Sources:
- https://en.wikipedia.org/wiki/Bias_of_an_estimator
-
- */
-
-public class BIAS_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private readonly SMA_Series _sma;
-
- //core constructors
- public BIAS_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"BIAS({period})";
- _sma = new(period, false);
- }
- public BIAS_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public BIAS_Series() : this(period: 0, useNaN: false) { }
- public BIAS_Series(int period) : this(period: period, useNaN: false) { }
- public BIAS_Series(TBars source) : this(source.Close, 0, false) { }
- public BIAS_Series(TBars source, int period) : this(source.Close, period, false) { }
- public BIAS_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public BIAS_Series(TSeries source) : this(source, 0, false) { }
- public BIAS_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- var _s = _sma.Add(TValue,update);
- double _bias = (TValue.v / ((_s.v!=0)?_s.v:1)) - 1;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _bias);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _sma.Reset();
- }
+namespace QuanTAlib;
+using System;
+
+/*
+BIAS: Rate of change between the source and a moving average.
+ Bias is a statistical term which means a systematic deviation from the actual value.
+
+BIAS = (close - SMA) / SMA
+ = (close / SMA) - 1
+
+Sources:
+ https://en.wikipedia.org/wiki/Bias_of_an_estimator
+
+ */
+
+public class BIAS_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private readonly SMA_Series _sma;
+
+ //core constructors
+ public BIAS_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"BIAS({period})";
+ _sma = new(period, false);
+ }
+ public BIAS_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public BIAS_Series() : this(period: 0, useNaN: false) { }
+ public BIAS_Series(int period) : this(period: period, useNaN: false) { }
+ public BIAS_Series(TBars source) : this(source.Close, 0, false) { }
+ public BIAS_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public BIAS_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public BIAS_Series(TSeries source) : this(source, 0, false) { }
+ public BIAS_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ var _s = _sma.Add(TValue, update);
+ double _bias = (TValue.v / ((_s.v != 0) ? _s.v : 1)) - 1;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _bias);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _sma.Reset();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/CCI_Series.cs b/Calculations/_Updated/CCI_Series.cs
index 3bf2e553..4886857b 100644
--- a/Calculations/_Updated/CCI_Series.cs
+++ b/Calculations/_Updated/CCI_Series.cs
@@ -1,86 +1,97 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-CCI: Commodity Channel Index
- Commodity Channel Index is a momentum oscillator used to primarily identify overbought
- and oversold levels relative to a mean. CCI measures the current price level relative
- to an average price level over a given period of time:
- - CCI is relatively high when prices are far above their average.
- - CCI is relatively low when prices are far below their average.
- Using this method, CCI can be used to identify overbought and oversold levels.
-
-Sources:
- https://www.investopedia.com/terms/c/commoditychannelindex.asp
- https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/cci
-
- */
-
-public class CCI_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TBars _data;
- private readonly System.Collections.Generic.List _tp = new();
-
- //core constructors
- public CCI_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"CCI({period})";
- }
- public CCI_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(data: _data);
- }
- public CCI_Series() : this(period: 2, useNaN: false) { }
- public CCI_Series(int period) : this(period: period, useNaN: false) { }
- public CCI_Series(TBars source) : this(source, period: 2, useNaN: false) { }
- public CCI_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
- double _tpItem = (TBar.h + TBar.l + TBar.c) / 3.0;
- if (update) {
- this._tp[this._tp.Count - 1] = _tpItem;
- }
- else {
- this._tp.Add(_tpItem);
- }
- if (this._tp.Count > this._period) { this._tp.RemoveAt(0); }
-
- // average TP over _tp buffer
- double _avgTp = _tp.Average();
-
- // average Deviation over _tp buffer
- double _avgDv = 0;
- for (int i = 0; i < this._tp.Count; i++) { _avgDv += Math.Abs(_avgTp - this._tp[i]); }
- _avgDv /= this._tp.Count;
-
- double _cci = (_avgDv == 0) ? 0 : (this._tp[this._tp.Count - 1] - _avgTp) / (0.015 * _avgDv);
- var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _cci);
- return base.Add(res, update);
- }
-
- public new void Add(TBars data) {
- foreach (var item in data) { Add(item, false); }
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TBar: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TBar: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TBar: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _tp.Clear();
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+CCI: Commodity Channel Index
+ Commodity Channel Index is a momentum oscillator used to primarily identify overbought
+ and oversold levels relative to a mean. CCI measures the current price level relative
+ to an average price level over a given period of time:
+ - CCI is relatively high when prices are far above their average.
+ - CCI is relatively low when prices are far below their average.
+ Using this method, CCI can be used to identify overbought and oversold levels.
+
+Sources:
+ https://www.investopedia.com/terms/c/commoditychannelindex.asp
+ https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/cci
+
+ */
+
+public class CCI_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TBars _data;
+ private readonly System.Collections.Generic.List _tp = new();
+
+ //core constructors
+ public CCI_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"CCI({period})";
+ }
+ public CCI_Series(TBars source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+ public CCI_Series() : this(period: 2, useNaN: false) { }
+ public CCI_Series(int period) : this(period: period, useNaN: false) { }
+ public CCI_Series(TBars source) : this(source, period: 2, useNaN: false) { }
+ public CCI_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
+ {
+ double _tpItem = (TBar.h + TBar.l + TBar.c) / 3.0;
+ if (update)
+ {
+ this._tp[this._tp.Count - 1] = _tpItem;
+ }
+ else
+ {
+ this._tp.Add(_tpItem);
+ }
+ if (this._tp.Count > this._period) { this._tp.RemoveAt(0); }
+
+ // average TP over _tp buffer
+ double _avgTp = _tp.Average();
+
+ // average Deviation over _tp buffer
+ double _avgDv = 0;
+ for (int i = 0; i < this._tp.Count; i++) { _avgDv += Math.Abs(_avgTp - this._tp[i]); }
+ _avgDv /= this._tp.Count;
+
+ double _cci = (_avgDv == 0) ? 0 : (this._tp[this._tp.Count - 1] - _avgTp) / (0.015 * _avgDv);
+ var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _cci);
+ return base.Add(res, update);
+ }
+
+ public new void Add(TBars data)
+ {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _tp.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/CMO_Series.cs b/Calculations/_Updated/CMO_Series.cs
index 6906067a..fe793bb0 100644
--- a/Calculations/_Updated/CMO_Series.cs
+++ b/Calculations/_Updated/CMO_Series.cs
@@ -1,90 +1,100 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-CMO: Chande Momentum Oscillator
- Chande Momentum Oscillator (also known as CMO indicator) was developed by Tushar S. Chande
- CMO is similar to other momentum oscillators (e.g. RSI or Stochastics). Alike RSI oscillator,
- the CMO values move in the range from -100 to +100 points and its aim is to detect the
- overbought and oversold market conditions. CMO calculates the price momentum on both the up
- days as well as the down days. The CMO calculation is based on non-smoothed price values
- meaning that it can reach its extremes more frequently and the short-time swings are more visible.
-
-Sources:
- https://www.technicalindicators.net/indicators-technical-analysis/144-cmo-chande-momentum-oscillator
-
- */
-
-public class CMO_Series : TSeries {
- private readonly System.Collections.Generic.List _buff_up = new();
- private readonly System.Collections.Generic.List _buff_dn = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private double _plast_value, _last_value;
-
- //core constructors
- public CMO_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"CMO({period})";
- }
- public CMO_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public CMO_Series() : this(period: 0, useNaN: false) { }
- public CMO_Series(int period) : this(period: period, useNaN: false) { }
- public CMO_Series(TBars source) : this(source.Close, 0, false) { }
- public CMO_Series(TBars source, int period) : this(source.Close, period, false) { }
- public CMO_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public CMO_Series(TSeries source) : this(source, 0, false) { }
- public CMO_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (update) { _last_value = _plast_value; } else { _plast_value = _last_value; }
- BufferTrim(buffer:_buff_up, (TValue.v > _last_value) ? TValue.v - _last_value : 0, period:_period, update: update);
- BufferTrim(buffer: _buff_dn, (TValue.v < _last_value) ? _last_value - TValue.v : 0, period: _period, update: update);
- _last_value = TValue.v;
- double _cmo_up = 0;
- double _cmo_dn = 0;
- for (int i = 0; i < Math.Min(_buff_up.Count, _buff_dn.Count); i++) {
- _cmo_up += _buff_up[i];
- _cmo_dn += _buff_dn[i];
- }
- double _cmo = 100 * (_cmo_up - _cmo_dn) / (_cmo_up + _cmo_dn);
- if (_cmo_up + _cmo_dn == 0) { _cmo = 0; }
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _cmo);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
-
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buff_up.Clear();
- _buff_dn.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+CMO: Chande Momentum Oscillator
+ Chande Momentum Oscillator (also known as CMO indicator) was developed by Tushar S. Chande
+ CMO is similar to other momentum oscillators (e.g. RSI or Stochastics). Alike RSI oscillator,
+ the CMO values move in the range from -100 to +100 points and its aim is to detect the
+ overbought and oversold market conditions. CMO calculates the price momentum on both the up
+ days as well as the down days. The CMO calculation is based on non-smoothed price values
+ meaning that it can reach its extremes more frequently and the short-time swings are more visible.
+
+Sources:
+ https://www.technicalindicators.net/indicators-technical-analysis/144-cmo-chande-momentum-oscillator
+
+ */
+
+public class CMO_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buff_up = new();
+ private readonly System.Collections.Generic.List _buff_dn = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private double _plast_value, _last_value;
+
+ //core constructors
+ public CMO_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"CMO({period})";
+ }
+ public CMO_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public CMO_Series() : this(period: 0, useNaN: false) { }
+ public CMO_Series(int period) : this(period: period, useNaN: false) { }
+ public CMO_Series(TBars source) : this(source.Close, 0, false) { }
+ public CMO_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public CMO_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public CMO_Series(TSeries source) : this(source, 0, false) { }
+ public CMO_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (update) { _last_value = _plast_value; } else { _plast_value = _last_value; }
+ BufferTrim(buffer: _buff_up, (TValue.v > _last_value) ? TValue.v - _last_value : 0, period: _period, update: update);
+ BufferTrim(buffer: _buff_dn, (TValue.v < _last_value) ? _last_value - TValue.v : 0, period: _period, update: update);
+ _last_value = TValue.v;
+ double _cmo_up = 0;
+ double _cmo_dn = 0;
+ for (int i = 0; i < Math.Min(_buff_up.Count, _buff_dn.Count); i++)
+ {
+ _cmo_up += _buff_up[i];
+ _cmo_dn += _buff_dn[i];
+ }
+ double _cmo = 100 * (_cmo_up - _cmo_dn) / (_cmo_up + _cmo_dn);
+ if (_cmo_up + _cmo_dn == 0) { _cmo = 0; }
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _cmo);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buff_up.Clear();
+ _buff_dn.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/CUSUM_Series.cs b/Calculations/_Updated/CUSUM_Series.cs
index e61d288d..38036f94 100644
--- a/Calculations/_Updated/CUSUM_Series.cs
+++ b/Calculations/_Updated/CUSUM_Series.cs
@@ -1,71 +1,80 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-CUSUM: Cumulative Sum (aka Running Total)
- SUM across a period provides a rolling sum of all values across the period.
- If SUM values would be divided with period, the output would be SMA()
-
-Sources:
- https://en.wikipedia.org/wiki/CUSUM
- */
-
-public class CUSUM_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
-
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public CUSUM_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"CUSUM({period})";
- }
- public CUSUM_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public CUSUM_Series() : this(period: 0, useNaN: false) { }
- public CUSUM_Series(int period) : this(period: period, useNaN: false) { }
- public CUSUM_Series(TBars source) : this(source.Close, 0, false) { }
- public CUSUM_Series(TBars source, int period) : this(source.Close, period, false) { }
- public CUSUM_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public CUSUM_Series(TSeries source) : this(source, period: 0, useNaN: false) { }
- public CUSUM_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _sum = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sum += _buffer[i]; }
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sum);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+CUSUM: Cumulative Sum (aka Running Total)
+ SUM across a period provides a rolling sum of all values across the period.
+ If SUM values would be divided with period, the output would be SMA()
+
+Sources:
+ https://en.wikipedia.org/wiki/CUSUM
+ */
+
+public class CUSUM_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public CUSUM_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"CUSUM({period})";
+ }
+ public CUSUM_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public CUSUM_Series() : this(period: 0, useNaN: false) { }
+ public CUSUM_Series(int period) : this(period: period, useNaN: false) { }
+ public CUSUM_Series(TBars source) : this(source.Close, 0, false) { }
+ public CUSUM_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public CUSUM_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public CUSUM_Series(TSeries source) : this(source, period: 0, useNaN: false) { }
+ public CUSUM_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _sum = 0;
+ for (int i = 0; i < _buffer.Count; i++) { _sum += _buffer[i]; }
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sum);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/DECAY_Series.cs b/Calculations/_Updated/DECAY_Series.cs
index a0193dc2..8236956e 100644
--- a/Calculations/_Updated/DECAY_Series.cs
+++ b/Calculations/_Updated/DECAY_Series.cs
@@ -1,83 +1,93 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-DECAY:
- Linear decay can be modeled by a straight line with a negative slope of 1/period.
- The value decreases in a straight line from the last maximum to 0.
- Decay = Last Max - distance/period
-
- Exponential decay is modeled as an exponential curve with diminishing factor of
- 1-1/p
-
- */
-
-public class DECAY_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private readonly bool _exp;
- private double _pdecay, _ppdecay;
- private readonly double _dfactor;
-
- //core constructors
- public DECAY_Series(int period, bool exponential, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"DECAY({period})";
- _exp = exponential;
- _dfactor = (_exp) ? 1.0 - 1.0 / (double)_period : 1 / (double)_period;
- _pdecay = _ppdecay = 0;
- }
- public DECAY_Series(TSeries source, int period, bool exponential, bool useNaN) : this(period, exponential, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public DECAY_Series() : this(period: 0, exponential: false, useNaN: false) { }
- public DECAY_Series(int period) : this(period: period, exponential: false, useNaN: false) { }
- public DECAY_Series(TBars source) : this(source.Close, period: 0, exponential: false, useNaN: false) { }
- public DECAY_Series(TBars source, int period) : this(source.Close, period: period, exponential:false, useNaN:false) { }
- public DECAY_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, exponential: false, useNaN) { }
- public DECAY_Series(TSeries source) : this(source, period: 0, exponential: false, useNaN:false) { }
- public DECAY_Series(TSeries source, int period) : this(source: source, period: period, exponential: false, useNaN: false) { }
- public DECAY_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, exponential: false, useNaN: useNaN) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, Double.NaN), update);
- }
- if (update) { _pdecay = _ppdecay; }
- else { _ppdecay = _pdecay; }
-
- if (this.Count == 0) { _pdecay = TValue.v; }
- double _decay = Math.Max(TValue.v, Math.Max((_exp) ? _pdecay * _dfactor : _pdecay - _dfactor, 0));
- _pdecay = _decay;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _decay);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _pdecay = _ppdecay = 0;
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+DECAY:
+ Linear decay can be modeled by a straight line with a negative slope of 1/period.
+ The value decreases in a straight line from the last maximum to 0.
+ Decay = Last Max - distance/period
+
+ Exponential decay is modeled as an exponential curve with diminishing factor of
+ 1-1/p
+
+ */
+
+public class DECAY_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private readonly bool _exp;
+ private double _pdecay, _ppdecay;
+ private readonly double _dfactor;
+
+ //core constructors
+ public DECAY_Series(int period, bool exponential, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"DECAY({period})";
+ _exp = exponential;
+ _dfactor = (_exp) ? 1.0 - 1.0 / (double)_period : 1 / (double)_period;
+ _pdecay = _ppdecay = 0;
+ }
+ public DECAY_Series(TSeries source, int period, bool exponential, bool useNaN) : this(period, exponential, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public DECAY_Series() : this(period: 0, exponential: false, useNaN: false) { }
+ public DECAY_Series(int period) : this(period: period, exponential: false, useNaN: false) { }
+ public DECAY_Series(TBars source) : this(source.Close, period: 0, exponential: false, useNaN: false) { }
+ public DECAY_Series(TBars source, int period) : this(source.Close, period: period, exponential: false, useNaN: false) { }
+ public DECAY_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, exponential: false, useNaN) { }
+ public DECAY_Series(TSeries source) : this(source, period: 0, exponential: false, useNaN: false) { }
+ public DECAY_Series(TSeries source, int period) : this(source: source, period: period, exponential: false, useNaN: false) { }
+ public DECAY_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, exponential: false, useNaN: useNaN) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+ if (update) { _pdecay = _ppdecay; }
+ else { _ppdecay = _pdecay; }
+
+ if (this.Count == 0) { _pdecay = TValue.v; }
+ double _decay = Math.Max(TValue.v, Math.Max((_exp) ? _pdecay * _dfactor : _pdecay - _dfactor, 0));
+ _pdecay = _decay;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _decay);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _pdecay = _ppdecay = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/DEMA_Series.cs b/Calculations/_Updated/DEMA_Series.cs
index 0cdac2b0..8bcf0ed7 100644
--- a/Calculations/_Updated/DEMA_Series.cs
+++ b/Calculations/_Updated/DEMA_Series.cs
@@ -1,127 +1,144 @@
-namespace QuanTAlib;
-
-using System;
-using System.Linq;
-
-/*
-DEMA: Double Exponential Moving Average
- DEMA uses EMA(EMA()) to calculate smoother Exponential moving average.
-
-Sources:
- https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/double-exponential-moving-average-dema/
-
-Remark:
- ema1 = EMA(close, length)
- ema2 = EMA(ema1, length)
- DEMA = 2 * ema1 - ema2
-
- */
-
-public class DEMA_Series : TSeries {
- private double _k;
- private double _sum, _oldsum;
- private double _lastema1, _oldema1, _lastema2, _oldema2;
- private int _len;
- private readonly bool _useSMA;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
-//core constructor
- public DEMA_Series(int period, bool useNaN, bool useSMA) {
- _period = period;
- _NaN = useNaN;
- _useSMA = useSMA;
- Name = $"DEMA({period})";
- _k = 2.0 / (_period + 1);
- _len = 0;
- _sum = _oldsum = _lastema1 = _lastema2 = 0;
- }
- //generic constructors (source)
-
- public DEMA_Series() : this(0, false, true) {}
- public DEMA_Series(int period) : this(period, false, true) {}
- public DEMA_Series(TBars source) : this(source.Close, 0, false) {}
- public DEMA_Series(TBars source, int period) : this(source.Close, period, false) {}
- public DEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
- public DEMA_Series(TSeries source, int period) : this(source, period, false, true) {}
- public DEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {}
- public DEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
-
-// core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (update) {
- _lastema1 = _oldema1;
- _lastema2 = _oldema2;
- _sum = _oldsum;
- }
- else {
- _oldema1 = _lastema1;
- _oldema2 = _lastema2;
- _oldsum = _sum;
- _len++;
- }
-
- if (_period == 0) {
- _k = 2.0 / (_len + 1);
- }
-
- double _ema1, _ema2, _dema;
- if (Count == 0) {
- _ema1 = _ema2 = _sum = TValue.v;
- }
- else if (_len <= _period && _useSMA && _period != 0) {
- _sum += TValue.v;
- _ema1 = _sum / Math.Min(_len, _period);
- _ema2 = _ema1;
- }
- else {
- _ema1 = (TValue.v - _lastema1) * _k + _lastema1;
- _ema2 = (_ema1 - _lastema2) * _k + _lastema2;
- }
-
- _dema = 2 * _ema1 - _ema2;
-
- _lastema1 = double.IsNaN(_ema1) ? _lastema1 : _ema1;
- _lastema2 = double.IsNaN(_ema2) ? _lastema2 : _ema2;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _dema);
- return base.Add(res, update);
- }
-
-//variation of Add()
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) {
- return (DateTime.Today, double.NaN);
- }
-
- foreach (var item in data) {
- Add(item, false);
- }
-
- return _data.Last;
- }
-
- public (DateTime t, double v) Add(bool update) {
- return Add(_data.Last, update);
- }
-
- public (DateTime t, double v) Add() {
- return Add(_data.Last, false);
- }
-
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(_data.Last, e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _sum = _oldsum = _lastema1 = _lastema2 = 0;
- _len = 0;
- }
+namespace QuanTAlib;
+
+using System;
+using System.Linq;
+
+/*
+DEMA: Double Exponential Moving Average
+ DEMA uses EMA(EMA()) to calculate smoother Exponential moving average.
+
+Sources:
+ https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/double-exponential-moving-average-dema/
+
+Remark:
+ ema1 = EMA(close, length)
+ ema2 = EMA(ema1, length)
+ DEMA = 2 * ema1 - ema2
+
+ */
+
+public class DEMA_Series : TSeries
+{
+ private double _k;
+ private double _sum, _oldsum;
+ private double _lastema1, _oldema1, _lastema2, _oldema2;
+ private int _len;
+ private readonly bool _useSMA;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructor
+ public DEMA_Series(int period, bool useNaN, bool useSMA)
+ {
+ _period = period;
+ _NaN = useNaN;
+ _useSMA = useSMA;
+ Name = $"DEMA({period})";
+ _k = 2.0 / (_period + 1);
+ _len = 0;
+ _sum = _oldsum = _lastema1 = _lastema2 = 0;
+ }
+ //generic constructors (source)
+
+ public DEMA_Series() : this(0, false, true) { }
+ public DEMA_Series(int period) : this(period, false, true) { }
+ public DEMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public DEMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public DEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public DEMA_Series(TSeries source, int period) : this(source, period, false, true) { }
+ public DEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
+ public DEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (update)
+ {
+ _lastema1 = _oldema1;
+ _lastema2 = _oldema2;
+ _sum = _oldsum;
+ }
+ else
+ {
+ _oldema1 = _lastema1;
+ _oldema2 = _lastema2;
+ _oldsum = _sum;
+ _len++;
+ }
+
+ if (_period == 0)
+ {
+ _k = 2.0 / (_len + 1);
+ }
+
+ double _ema1, _ema2, _dema;
+ if (Count == 0)
+ {
+ _ema1 = _ema2 = _sum = TValue.v;
+ }
+ else if (_len <= _period && _useSMA && _period != 0)
+ {
+ _sum += TValue.v;
+ _ema1 = _sum / Math.Min(_len, _period);
+ _ema2 = _ema1;
+ }
+ else
+ {
+ _ema1 = (TValue.v - _lastema1) * _k + _lastema1;
+ _ema2 = (_ema1 - _lastema2) * _k + _lastema2;
+ }
+
+ _dema = 2 * _ema1 - _ema2;
+
+ _lastema1 = double.IsNaN(_ema1) ? _lastema1 : _ema1;
+ _lastema2 = double.IsNaN(_ema2) ? _lastema2 : _ema2;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _dema);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null)
+ {
+ return (DateTime.Today, double.NaN);
+ }
+
+ foreach (var item in data)
+ {
+ Add(item, false);
+ }
+
+ return _data.Last;
+ }
+
+ public (DateTime t, double v) Add(bool update)
+ {
+ return Add(_data.Last, update);
+ }
+
+ public (DateTime t, double v) Add()
+ {
+ return Add(_data.Last, false);
+ }
+
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(_data.Last, e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _sum = _oldsum = _lastema1 = _lastema2 = 0;
+ _len = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/DWMA_Series.cs b/Calculations/_Updated/DWMA_Series.cs
index 3e5f4808..d9d9b847 100644
--- a/Calculations/_Updated/DWMA_Series.cs
+++ b/Calculations/_Updated/DWMA_Series.cs
@@ -1,122 +1,143 @@
-namespace QuanTAlib;
-
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-
-/*
-DWMA: Double Weighted Moving Average
- The weights are decreasing over the period with p^2 decay
- and the most recent data has the heaviest weight.
-
- */
-
-public class DWMA_Series : TSeries {
- private readonly List _buffer = new();
- private List _weights;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- protected int _len;
-
-//core constructors
- public DWMA_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"DWMA({period})";
- _len = 0;
- _weights = CalculateWeights(_period);
- }
-
- public DWMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
-
- public DWMA_Series() : this(0, false) {
- }
-
- public DWMA_Series(int period) : this(period, false) {
- }
-
- public DWMA_Series(TBars source) : this(source.Close, 0, false) {
- }
-
- public DWMA_Series(TBars source, int period) : this(source.Close, period, false) {
- }
-
- public DWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {
- }
-
- public DWMA_Series(TSeries source, int period) : this(source, period, false) {
- }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(_buffer, TValue.v, _period, update);
- if (_period == 0) {
- _len++;
- _weights = CalculateWeights(_len);
- }
-
- double _dwma = 0, _wsum = 0;
- var bufferCount = _buffer.Count;
-
- var lockObj = new object();
- Parallel.For(0, bufferCount, i =>
- {
- var temp = _buffer[i] * _weights[i];
- lock (lockObj) {
- _dwma += temp;
- _wsum += _weights[i];
- }
- });
- _dwma /= _wsum;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _dwma);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) {
- return (DateTime.Today, double.NaN);
- }
-
- foreach (var item in data) {
- Add(item, false);
- }
-
- return _data.Last;
- }
-
- public (DateTime t, double v) Add(bool update) {
- return Add(_data.Last, update);
- }
-
- public (DateTime t, double v) Add() {
- return Add(_data.Last, false);
- }
-
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(_data.Last, e.update);
- }
-
- //calculating weights
- private static List CalculateWeights(int period) {
- var weights = new List(period);
- for (var i = 0; i < period; i++) {
- weights.Add((i + 1) * (i + 1));
- }
-
- return weights;
- }
-
- //reset calculation
- public override void Reset() {
- _len = 0;
- _buffer.Clear();
- _weights = CalculateWeights(_period);
- }
+namespace QuanTAlib;
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+/*
+DWMA: Double Weighted Moving Average
+ The weights are decreasing over the period with p^2 decay
+ and the most recent data has the heaviest weight.
+
+ */
+
+public class DWMA_Series : TSeries
+{
+ private readonly List _buffer = new();
+ private List _weights;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ protected int _len;
+
+ //core constructors
+ public DWMA_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"DWMA({period})";
+ _len = 0;
+ _weights = CalculateWeights(_period);
+ }
+
+ public DWMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+
+ public DWMA_Series() : this(0, false)
+ {
+ }
+
+ public DWMA_Series(int period) : this(period, false)
+ {
+ }
+
+ public DWMA_Series(TBars source) : this(source.Close, 0, false)
+ {
+ }
+
+ public DWMA_Series(TBars source, int period) : this(source.Close, period, false)
+ {
+ }
+
+ public DWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN)
+ {
+ }
+
+ public DWMA_Series(TSeries source, int period) : this(source, period, false)
+ {
+ }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(_buffer, TValue.v, _period, update);
+ if (_period == 0)
+ {
+ _len++;
+ _weights = CalculateWeights(_len);
+ }
+
+ double _dwma = 0, _wsum = 0;
+ var bufferCount = _buffer.Count;
+
+ var lockObj = new object();
+ Parallel.For(0, bufferCount, i =>
+ {
+ var temp = _buffer[i] * _weights[i];
+ lock (lockObj)
+ {
+ _dwma += temp;
+ _wsum += _weights[i];
+ }
+ });
+ _dwma /= _wsum;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _dwma);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null)
+ {
+ return (DateTime.Today, double.NaN);
+ }
+
+ foreach (var item in data)
+ {
+ Add(item, false);
+ }
+
+ return _data.Last;
+ }
+
+ public (DateTime t, double v) Add(bool update)
+ {
+ return Add(_data.Last, update);
+ }
+
+ public (DateTime t, double v) Add()
+ {
+ return Add(_data.Last, false);
+ }
+
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(_data.Last, e.update);
+ }
+
+ //calculating weights
+ private static List CalculateWeights(int period)
+ {
+ var weights = new List(period);
+ for (var i = 0; i < period; i++)
+ {
+ weights.Add((i + 1) * (i + 1));
+ }
+
+ return weights;
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _len = 0;
+ _buffer.Clear();
+ _weights = CalculateWeights(_period);
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/EMA_Series.cs b/Calculations/_Updated/EMA_Series.cs
index 138f04ea..26edf8ef 100644
--- a/Calculations/_Updated/EMA_Series.cs
+++ b/Calculations/_Updated/EMA_Series.cs
@@ -1,120 +1,136 @@
-namespace QuanTAlib;
-
-using System;
-using System.Linq;
-
-/*
-EMA: Exponential Moving Average
- EMA needs very short history buffer and calculates the EMA value using just the
- previous EMA value. The weight of the new datapoint (k) is k = 2 / (period-1)
-
-Sources:
- https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages
- https://www.investopedia.com/ask/answers/122314/what-exponential-moving-average-ema-formula-and-how-ema-calculated.asp
- https://blog.fugue88.ws/archives/2017-01/The-correct-way-to-start-an-Exponential-Moving-Average-EMA
-
-Issues:
- There is no consensus what the first EMA value should be - a zero, a first
- datapoint, or an average of the initial Period bars. All three starting methods
- converge within 20+ bars to the same moving average. Most implementations (including this one)
- use SMA() for the first Period bars as a seeding value for EMA.
-
- */
-
-public class EMA_Series : TSeries {
- private double _k;
- private double _lastema, _oldema;
- private double _sum, _oldsum;
- private int _len;
- private readonly bool _useSMA;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
-//core constructors
-
- public EMA_Series(int period, bool useNaN, bool useSMA) {
- _period = period;
- _NaN = useNaN;
- _useSMA = useSMA;
- Name = $"EMA({period})";
- _k = 2.0 / (_period + 1);
- _len = 0;
- _sum = _oldsum = _lastema = _oldema = 0;
- }
- public EMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public EMA_Series() : this(0, false, true) {}
- public EMA_Series(int period) : this(period, false, true) {}
- public EMA_Series(TBars source) : this(source.Close, 0, false) {}
- public EMA_Series(TBars source, int period) : this(source.Close, period, false) {}
- public EMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
- public EMA_Series(TSeries source, int period) : this(source, period, false, true) {}
- public EMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {}
-
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (update) {
- _lastema = _oldema;
- _sum = _oldsum;
- }
- else {
- _oldema = _lastema;
- _oldsum = _sum;
- _len++;
- }
-
- double _ema = 0;
- if (_period == 0) {
- _k = 2.0 / (_len + 1);
- }
-
- if (Count == 0) {
- _ema = _sum = TValue.v;
- }
- else if (_len <= _period && _useSMA && _period != 0) {
- _sum += TValue.v;
- if (_period != 0 && _len > _period) {
- _sum -= _data[Count - _period - (update ? 1 : 0)].v;
- }
-
- _ema = _sum / Math.Min(_len, _period);
- }
- else {
- _ema = _k * (TValue.v - _lastema) + _lastema;
- }
-
- _lastema = double.IsNaN(_ema) ? _lastema : _ema;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _ema);
- return base.Add(res, update);
- }
-
-//variation of Add()
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _sum = _oldsum = _lastema = _oldema = 0;
- _len = 0;
- }
+namespace QuanTAlib;
+
+using System;
+using System.Linq;
+
+/*
+EMA: Exponential Moving Average
+ EMA needs very short history buffer and calculates the EMA value using just the
+ previous EMA value. The weight of the new datapoint (k) is k = 2 / (period-1)
+
+Sources:
+ https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages
+ https://www.investopedia.com/ask/answers/122314/what-exponential-moving-average-ema-formula-and-how-ema-calculated.asp
+ https://blog.fugue88.ws/archives/2017-01/The-correct-way-to-start-an-Exponential-Moving-Average-EMA
+
+Issues:
+ There is no consensus what the first EMA value should be - a zero, a first
+ datapoint, or an average of the initial Period bars. All three starting methods
+ converge within 20+ bars to the same moving average. Most implementations (including this one)
+ use SMA() for the first Period bars as a seeding value for EMA.
+
+ */
+
+public class EMA_Series : TSeries
+{
+ private double _k;
+ private double _lastema, _oldema;
+ private double _sum, _oldsum;
+ private int _len;
+ private readonly bool _useSMA;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+
+ public EMA_Series(int period, bool useNaN, bool useSMA)
+ {
+ _period = period;
+ _NaN = useNaN;
+ _useSMA = useSMA;
+ Name = $"EMA({period})";
+ _k = 2.0 / (_period + 1);
+ _len = 0;
+ _sum = _oldsum = _lastema = _oldema = 0;
+ }
+ public EMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public EMA_Series() : this(0, false, true) { }
+ public EMA_Series(int period) : this(period, false, true) { }
+ public EMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public EMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public EMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public EMA_Series(TSeries source, int period) : this(source, period, false, true) { }
+ public EMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
+
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (update)
+ {
+ _lastema = _oldema;
+ _sum = _oldsum;
+ }
+ else
+ {
+ _oldema = _lastema;
+ _oldsum = _sum;
+ _len++;
+ }
+
+ double _ema = 0;
+ if (_period == 0)
+ {
+ _k = 2.0 / (_len + 1);
+ }
+
+ if (Count == 0)
+ {
+ _ema = _sum = TValue.v;
+ }
+ else if (_len <= _period && _useSMA && _period != 0)
+ {
+ _sum += TValue.v;
+ if (_period != 0 && _len > _period)
+ {
+ _sum -= _data[Count - _period - (update ? 1 : 0)].v;
+ }
+
+ _ema = _sum / Math.Min(_len, _period);
+ }
+ else
+ {
+ _ema = _k * (TValue.v - _lastema) + _lastema;
+ }
+
+ _lastema = double.IsNaN(_ema) ? _lastema : _ema;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _ema);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _sum = _oldsum = _lastema = _oldema = 0;
+ _len = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/ENTROPY_Series.cs b/Calculations/_Updated/ENTROPY_Series.cs
index 23523a50..6c3bd399 100644
--- a/Calculations/_Updated/ENTROPY_Series.cs
+++ b/Calculations/_Updated/ENTROPY_Series.cs
@@ -1,87 +1,97 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-ENTROPY:
- Introduced by Claude Shannon in 1948, entropy measures the unpredictability
- of the data, or equivalently, of its average information.
-
-Calculation:
- P = close / Σ(close)
- ENTROPY = Σ(-P * Log(P) / Log(base))
-
-Sources:
- https://en.wikipedia.org/wiki/Entropy_(information_theory)
- https://math.stackexchange.com/questions/3428693/how-to-calculate-entropy-from-a-set-of-correlated-samples
-
- */
-
-public class ENTROPY_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private readonly double _logbase;
- private readonly System.Collections.Generic.List _buffer = new();
- private readonly System.Collections.Generic.List _buff2 = new();
-
- //core constructors
- public ENTROPY_Series(int period, double logbase, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- _logbase = logbase;
- Name = $"ENTROPY({period})";
- }
- public ENTROPY_Series(TSeries source, int period, double logbase, bool useNaN) : this(period, logbase, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public ENTROPY_Series() : this(period: 0, logbase: 2.0, useNaN: false) { }
- public ENTROPY_Series(int period) : this(period: period, logbase: 2.0, useNaN: false) { }
- public ENTROPY_Series(TBars source) : this(source.Close, period: 0, logbase: 2.0, useNaN: false) { }
- public ENTROPY_Series(TBars source, int period) : this(source.Close, period, logbase: 2.0, useNaN: false) { }
- public ENTROPY_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, logbase: 2.0, useNaN: useNaN) { }
- public ENTROPY_Series(TSeries source) : this(source, period: 0, logbase: 2.0, useNaN: false) { }
- public ENTROPY_Series(TSeries source, int period) : this(source: source, period: period, logbase: 2.0, useNaN: false) { }
- public ENTROPY_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, logbase: 2.0, useNaN: useNaN) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, Double.NaN), update);
- }
- BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
- double _sum = _buffer.Sum();
- double _pp = this._buffer[^1] / _sum;
- double _ppp = -_pp * Math.Log(_pp) / Math.Log(this._logbase);
- BufferTrim(_buff2, _ppp, _period, update);
- double _entp = _buff2.Sum();
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _entp);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- _buff2.Clear();
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+ENTROPY:
+ Introduced by Claude Shannon in 1948, entropy measures the unpredictability
+ of the data, or equivalently, of its average information.
+
+Calculation:
+ P = close / Σ(close)
+ ENTROPY = Σ(-P * Log(P) / Log(base))
+
+Sources:
+ https://en.wikipedia.org/wiki/Entropy_(information_theory)
+ https://math.stackexchange.com/questions/3428693/how-to-calculate-entropy-from-a-set-of-correlated-samples
+
+ */
+
+public class ENTROPY_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private readonly double _logbase;
+ private readonly System.Collections.Generic.List _buffer = new();
+ private readonly System.Collections.Generic.List _buff2 = new();
+
+ //core constructors
+ public ENTROPY_Series(int period, double logbase, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ _logbase = logbase;
+ Name = $"ENTROPY({period})";
+ }
+ public ENTROPY_Series(TSeries source, int period, double logbase, bool useNaN) : this(period, logbase, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public ENTROPY_Series() : this(period: 0, logbase: 2.0, useNaN: false) { }
+ public ENTROPY_Series(int period) : this(period: period, logbase: 2.0, useNaN: false) { }
+ public ENTROPY_Series(TBars source) : this(source.Close, period: 0, logbase: 2.0, useNaN: false) { }
+ public ENTROPY_Series(TBars source, int period) : this(source.Close, period, logbase: 2.0, useNaN: false) { }
+ public ENTROPY_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, logbase: 2.0, useNaN: useNaN) { }
+ public ENTROPY_Series(TSeries source) : this(source, period: 0, logbase: 2.0, useNaN: false) { }
+ public ENTROPY_Series(TSeries source, int period) : this(source: source, period: period, logbase: 2.0, useNaN: false) { }
+ public ENTROPY_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, logbase: 2.0, useNaN: useNaN) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+ double _sum = _buffer.Sum();
+ double _pp = this._buffer[^1] / _sum;
+ double _ppp = -_pp * Math.Log(_pp) / Math.Log(this._logbase);
+ BufferTrim(_buff2, _ppp, _period, update);
+ double _entp = _buff2.Sum();
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _entp);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ _buff2.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/FWMA_Series.cs b/Calculations/_Updated/FWMA_Series.cs
index 78cfef0e..f9976814 100644
--- a/Calculations/_Updated/FWMA_Series.cs
+++ b/Calculations/_Updated/FWMA_Series.cs
@@ -1,94 +1,105 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using System.Numerics;
-using System.Linq;
-
-/*
-FWMA: Fibonacci's Weighted Moving Average is similar to a Weighted Moving Average
- (WMA) where the weights are based on the Fibonacci Sequence.
-
- */
-public class FWMA_Series : TSeries {
- private readonly List _buffer = new();
- private List _weights;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- protected int _len;
-
- public FWMA_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"FWMA({period})";
- _len = 0;
- _weights = CalculateWeights(_period);
- }
-
- public FWMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
-
- public FWMA_Series() : this(period: 0, useNaN: false) { }
- public FWMA_Series(int period) : this(period: period, useNaN: false) { }
- public FWMA_Series(TBars source) : this(source.Close, 0, false) { }
- public FWMA_Series(TBars source, int period) : this(source.Close, period, false) { }
- public FWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public FWMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
- if (_period == 0) {
- _len++;
- _weights = CalculateWeights(_len);
- }
- double _fwma = 0;
- double totalWeights = _weights.Sum();
- object lockObj = new object();
- Parallel.For(0, _buffer.Count, i =>
- {
- double temp = _buffer[i] * _weights[i];
- lock (lockObj) { _fwma += temp; }
- });
- _fwma /= totalWeights;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _fwma);
- return base.Add(res, update);
- }
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- private static List CalculateWeights(int period) {
- //to prevent overflow, max period can be no more than 1476
- period = (period > 1476) ? 1476 : period;
- List weights = new List(period);
- BigInteger a = 0;
- BigInteger b = 1;
- for (int i = 0; i < period; i++) {
- BigInteger temp = a;
- a = b;
- b = temp + b;
- weights.Add((double)Decimal.Parse(a.ToString()));
- }
- return weights;
- }
-
- public override void Reset() {
- _weights = CalculateWeights(_period);
- _buffer.Clear();
- }
-}
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using System.Numerics;
+using System.Linq;
+
+/*
+FWMA: Fibonacci's Weighted Moving Average is similar to a Weighted Moving Average
+ (WMA) where the weights are based on the Fibonacci Sequence.
+
+ */
+public class FWMA_Series : TSeries
+{
+ private readonly List _buffer = new();
+ private List _weights;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ protected int _len;
+
+ public FWMA_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"FWMA({period})";
+ _len = 0;
+ _weights = CalculateWeights(_period);
+ }
+
+ public FWMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+
+ public FWMA_Series() : this(period: 0, useNaN: false) { }
+ public FWMA_Series(int period) : this(period: period, useNaN: false) { }
+ public FWMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public FWMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public FWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public FWMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+ if (_period == 0)
+ {
+ _len++;
+ _weights = CalculateWeights(_len);
+ }
+ double _fwma = 0;
+ double totalWeights = _weights.Sum();
+ object lockObj = new object();
+ Parallel.For(0, _buffer.Count, i =>
+ {
+ double temp = _buffer[i] * _weights[i];
+ lock (lockObj) { _fwma += temp; }
+ });
+ _fwma /= totalWeights;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _fwma);
+ return base.Add(res, update);
+ }
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ private static List CalculateWeights(int period)
+ {
+ //to prevent overflow, max period can be no more than 1476
+ period = (period > 1476) ? 1476 : period;
+ List weights = new List(period);
+ BigInteger a = 0;
+ BigInteger b = 1;
+ for (int i = 0; i < period; i++)
+ {
+ BigInteger temp = a;
+ a = b;
+ b = temp + b;
+ weights.Add((double)Decimal.Parse(a.ToString()));
+ }
+ return weights;
+ }
+
+ public override void Reset()
+ {
+ _weights = CalculateWeights(_period);
+ _buffer.Clear();
+ }
+}
diff --git a/Calculations/_Updated/HEMA_Series.cs b/Calculations/_Updated/HEMA_Series.cs
index b2f53114..c52f6c06 100644
--- a/Calculations/_Updated/HEMA_Series.cs
+++ b/Calculations/_Updated/HEMA_Series.cs
@@ -1,116 +1,133 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-HEMA: Hull-EMA Moving Average - a hybrid indicator
- Modified HUll Moving Average; instead of using WMA (Weighted MA) for calculation,
- HEMA uses EMA for Hull's formula:
-
-EMA1 = EMA(n/2) of price - where k = 4/(n/2 +1)
-EMA2 = EMA(n) of price - where k = 3/(n+1)
-Raw HMA = (2 * EMA1) - EMA2
-EMA3 = EMA(sqrt(n)) of Raw HMA - where k = 2/(sqrt(n)+1)
- */
-
-public class HEMA_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private double _k1, _k2, _k3;
- private int _len;
- private double _lastema1, _oldema1;
- private double _lastema2, _oldema2;
- private double _lasthema, _oldhema;
-
- //core constructors
- public HEMA_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"HEMA({period})";
- (_k1, _k2, _k3) = CalculateK(_period);
- _len = 0;
- _lastema1 = _oldema1 = _lastema2 = _oldema2 = _lasthema = _oldhema = 0;
- }
- public HEMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public HEMA_Series() : this(period: 0, useNaN: false) { }
- public HEMA_Series(int period) : this(period: period, useNaN: false) { }
- public HEMA_Series(TBars source) : this(source.Close, 0, false) { }
- public HEMA_Series(TBars source, int period) : this(source.Close, period, false) { }
- public HEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public HEMA_Series(TSeries source) : this(source, 0, false) { }
- public HEMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (update) {
- _lastema1 = _oldema1;
- _lastema2 = _oldema2;
- _lasthema = _oldhema;
- }
- else {
- _oldema1 = _lastema1;
- _oldema2 = _lastema2;
- _oldhema = _lasthema;
- }
- double _ema1, _ema2, _hema;
- if (_period == 0) {
- _len++;
- (_k1, _k2, _k3) = CalculateK(_len);
- }
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, double.NaN), update);
- } else if (this.Count == 0) {
- _ema1 = _ema2 = _hema = TValue.v;
- }
- else {
- _ema1 = _k1 * (TValue.v - _lastema1) + _lastema1;
- _ema2 = _k2 * (TValue.v - _lastema2) + _lastema2;
- _hema = _k3 * (((2 * _ema1) - _ema2) - _lasthema) + _lasthema;
- }
-
- _lastema1 = _ema1;
- _lastema2 = _ema2;
- _lasthema = _hema;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hema);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _lastema1 = _lastema2 = _lasthema = 0;
- _oldema1 = _oldema2 = _oldhema = 0;
- _len = 0;
- }
-
- public static (double k1, double k2, double k3) CalculateK(int len) {
- double k1 = 8 / (double)(len + 7);
- double k2 = 3 / (double)(len + 2);
- double k3 = 2 / Math.Sqrt(len + 3);
-
- return (k1, k2, k3);
- }
-
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+HEMA: Hull-EMA Moving Average - a hybrid indicator
+ Modified HUll Moving Average; instead of using WMA (Weighted MA) for calculation,
+ HEMA uses EMA for Hull's formula:
+
+EMA1 = EMA(n/2) of price - where k = 4/(n/2 +1)
+EMA2 = EMA(n) of price - where k = 3/(n+1)
+Raw HMA = (2 * EMA1) - EMA2
+EMA3 = EMA(sqrt(n)) of Raw HMA - where k = 2/(sqrt(n)+1)
+ */
+
+public class HEMA_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private double _k1, _k2, _k3;
+ private int _len;
+ private double _lastema1, _oldema1;
+ private double _lastema2, _oldema2;
+ private double _lasthema, _oldhema;
+
+ //core constructors
+ public HEMA_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"HEMA({period})";
+ (_k1, _k2, _k3) = CalculateK(_period);
+ _len = 0;
+ _lastema1 = _oldema1 = _lastema2 = _oldema2 = _lasthema = _oldhema = 0;
+ }
+ public HEMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public HEMA_Series() : this(period: 0, useNaN: false) { }
+ public HEMA_Series(int period) : this(period: period, useNaN: false) { }
+ public HEMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public HEMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public HEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public HEMA_Series(TSeries source) : this(source, 0, false) { }
+ public HEMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (update)
+ {
+ _lastema1 = _oldema1;
+ _lastema2 = _oldema2;
+ _lasthema = _oldhema;
+ }
+ else
+ {
+ _oldema1 = _lastema1;
+ _oldema2 = _lastema2;
+ _oldhema = _lasthema;
+ }
+ double _ema1, _ema2, _hema;
+ if (_period == 0)
+ {
+ _len++;
+ (_k1, _k2, _k3) = CalculateK(_len);
+ }
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, double.NaN), update);
+ }
+ else if (this.Count == 0)
+ {
+ _ema1 = _ema2 = _hema = TValue.v;
+ }
+ else
+ {
+ _ema1 = _k1 * (TValue.v - _lastema1) + _lastema1;
+ _ema2 = _k2 * (TValue.v - _lastema2) + _lastema2;
+ _hema = _k3 * (((2 * _ema1) - _ema2) - _lasthema) + _lasthema;
+ }
+
+ _lastema1 = _ema1;
+ _lastema2 = _ema2;
+ _lasthema = _hema;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hema);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _lastema1 = _lastema2 = _lasthema = 0;
+ _oldema1 = _oldema2 = _oldhema = 0;
+ _len = 0;
+ }
+
+ public static (double k1, double k2, double k3) CalculateK(int len)
+ {
+ double k1 = 8 / (double)(len + 7);
+ double k2 = 3 / (double)(len + 2);
+ double k3 = 2 / Math.Sqrt(len + 3);
+
+ return (k1, k2, k3);
+ }
+
}
\ No newline at end of file
diff --git a/Calculations/_Updated/HMA_Series.cs b/Calculations/_Updated/HMA_Series.cs
index 9230a76b..4401886e 100644
--- a/Calculations/_Updated/HMA_Series.cs
+++ b/Calculations/_Updated/HMA_Series.cs
@@ -1,88 +1,98 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-HMA: Hull Moving Average
- Developed by Alan Hull, an extremely fast and smooth moving average; almost
- eliminates lag altogether and manages to improve smoothing at the same time.
-
-Sources:
- https://alanhull.com/hull-moving-average
- https://school.stockcharts.com/doku.php?id=technical_indicators:hull_moving_average
-
-WMA1 = WMA(n/2) of price
-WMA2 = WMA(n) of price
-Raw HMA = (2 * WMA1) - WMA2
-HMA = WMA(sqrt(n)) of Raw HMA
-
- */
-
-public class HMA_Series : TSeries {
- protected int _period, _period2, _psqrt;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- protected WMA_Series _wma1, _wma2, _wma3;
-
- //core constructors
- public HMA_Series(int period, bool useNaN) {
- _period = period;
- _period2 = period /2;
- _psqrt = (int)Math.Sqrt(period);
- _NaN = useNaN;
- _wma1 = new(Math.Max(_period2,1), false);
- _wma2 = new(Math.Max(_period,1), false);
- _wma3 = new(Math.Max(_psqrt,1), useNaN);
- Name = $"HMA({period})";
- }
- public HMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public HMA_Series() : this(period: 0, useNaN: false) { }
- public HMA_Series(int period) : this(period: period, useNaN: false) { }
- public HMA_Series(TBars source) : this(source.Close, 0, false) { }
- public HMA_Series(TBars source, int period) : this(source.Close, period, false) { }
- public HMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public HMA_Series(TSeries source) : this(source, 0, false) { }
- public HMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (_period == 0) {
- _wma1.Len = this.Count / 2;
- _wma2.Len = this.Count;
- _wma1.Len = (int)Math.Sqrt(this.Count);
- }
- double _w1 = _wma1.Add(TValue, update).v;
- double _w2 = _wma2.Add(TValue, update).v;
- double _hma = _wma3.Add((2 * _w1) - _w2, update).v;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hma);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _wma1.Reset();
- _wma2.Reset();
- _wma3.Reset();
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+HMA: Hull Moving Average
+ Developed by Alan Hull, an extremely fast and smooth moving average; almost
+ eliminates lag altogether and manages to improve smoothing at the same time.
+
+Sources:
+ https://alanhull.com/hull-moving-average
+ https://school.stockcharts.com/doku.php?id=technical_indicators:hull_moving_average
+
+WMA1 = WMA(n/2) of price
+WMA2 = WMA(n) of price
+Raw HMA = (2 * WMA1) - WMA2
+HMA = WMA(sqrt(n)) of Raw HMA
+
+ */
+
+public class HMA_Series : TSeries
+{
+ protected int _period, _period2, _psqrt;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ protected WMA_Series _wma1, _wma2, _wma3;
+
+ //core constructors
+ public HMA_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _period2 = period / 2;
+ _psqrt = (int)Math.Sqrt(period);
+ _NaN = useNaN;
+ _wma1 = new(Math.Max(_period2, 1), false);
+ _wma2 = new(Math.Max(_period, 1), false);
+ _wma3 = new(Math.Max(_psqrt, 1), useNaN);
+ Name = $"HMA({period})";
+ }
+ public HMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public HMA_Series() : this(period: 0, useNaN: false) { }
+ public HMA_Series(int period) : this(period: period, useNaN: false) { }
+ public HMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public HMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public HMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public HMA_Series(TSeries source) : this(source, 0, false) { }
+ public HMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (_period == 0)
+ {
+ _wma1.Len = this.Count / 2;
+ _wma2.Len = this.Count;
+ _wma1.Len = (int)Math.Sqrt(this.Count);
+ }
+ double _w1 = _wma1.Add(TValue, update).v;
+ double _w2 = _wma2.Add(TValue, update).v;
+ double _hma = _wma3.Add((2 * _w1) - _w2, update).v;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hma);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _wma1.Reset();
+ _wma2.Reset();
+ _wma3.Reset();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/HWMA_Series.cs b/Calculations/_Updated/HWMA_Series.cs
index f67249e2..6e3f7896 100644
--- a/Calculations/_Updated/HWMA_Series.cs
+++ b/Calculations/_Updated/HWMA_Series.cs
@@ -1,132 +1,146 @@
-namespace QuanTAlib;
-
-using System;
-using System.Linq;
-
-/*
-HWMA: Holt-Winter Moving Average
- Indicator HWMA (Holt-Winter Moving Average) is a three-parameter moving
- average by the Holt-Winter method; Holt-Winters Exponential Smoothing is
- used for forecasting time series data that exhibits both a trend and a
- seasonal variation.
-
-
-Sources:
- https://timeseriesreasoning.com/contents/holt-winters-exponential-smoothing/
- https://www.mql5.com/en/code/20856
-
-nA - smoothed series (from 0 to 1)
-nB - assess the trend (from 0 to 1)
-nC - assess seasonality (from 0 to 1)
-
-Heuristic for determining alpha, beta, and gamma from period:
- alpha = 2 / (1 + period)
- beta = 1 / period
- gamma = 1 / period
-
-F[i] = (1-nA) * (F[i-1] + V[i-1] + 0.5 * A[i-1]) + nA * Price[i]
-V[i] = (1-nB) * (V[i-1] + A[i-1]) + nB * (F[i] - F[i-1])
-A[i] = (1-nC) * A[i-1] + nC * (V[i] - V[i-1])
-HWMA[i] = F[i] + V[i] + 0.5 * A[i]
-
- */
-
-public class HWMA_Series : TSeries {
- private int _len;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- double _nA, _nB, _nC;
- double _pF, _pV, _pA;
- double _ppF, _ppV, _ppA;
-
- //core constructors
-
- public HWMA_Series(double nA, double nB, double nC, bool useNaN) {
- _period = (int)((2 - nA) / nA);
- _nA = nA;
- _nB = nB;
- _nC = nC;
- _NaN = useNaN;
- Name = $"HWMA({_period})";
- _len = 0;
- }
- public HWMA_Series(TSeries source, double nA, double nB, double nC, bool useNaN = false) : this(nA, nB, nC, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public HWMA_Series() : this(period: 0, useNaN: false) { }
- public HWMA_Series(int period) : this(period, useNaN: false) { }
- public HWMA_Series(int period, bool useNaN) : this(nA: 2 / (1 + (double)period), nB: 1 / (double)period, nC: 1 / (double)period, useNaN) {
- _period = period;
- }
- public HWMA_Series(TBars source) : this(source.Close, period: 0, useNaN: false) { }
- public HWMA_Series(TBars source, int period) : this(source.Close, period, false) { }
- public HWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public HWMA_Series(TSeries source, int period) : this(source, period, false) { }
- public HWMA_Series(TSeries source, int period, bool useNaN) : this(source, nA: 2 / (1 + (double)period), nB: 1 / (double)period, nC: 1 / (double)period, useNaN: useNaN) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, Double.NaN), update);
- }
- double _F, _V, _A;
- if (_len == 0) { _pF = TValue.v; _pA = _pV = 0; }
-
- if (update) { _pF = _ppF; _pV = _ppV; _pA = _ppA; }
- else {
- _ppF = _pF;
- _ppV = _pV;
- _ppA = _pA;
- _len++;
- }
-
- if (_period == 0) {
- _nA = 2 / (1 + (double)_len);
- _nB = 1 / (double)_len;
- _nC = 1 / (double)_len;
- }
- if (_period == 1) {
- _nA = 1;
- _nB = 0;
- _nC = 0;
- }
-
- _F = (1 - _nA) * (_pF + _pV + 0.5 * _pA) + _nA * TValue.v;
- _V = (1 - _nB) * (_pV + _pA) + _nB * (_F - _pF);
- _A = (1 - _nC) * _pA + _nC * (_V - _pV);
-
- double _hwma = _F + _V + 0.5 * _A;
- _pF = _F;
- _pV = _V;
- _pA = _A;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hwma);
- return base.Add(res, update);
- }
-
- //variation of Add()
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _len = 0;
- }
+namespace QuanTAlib;
+
+using System;
+using System.Linq;
+
+/*
+HWMA: Holt-Winter Moving Average
+ Indicator HWMA (Holt-Winter Moving Average) is a three-parameter moving
+ average by the Holt-Winter method; Holt-Winters Exponential Smoothing is
+ used for forecasting time series data that exhibits both a trend and a
+ seasonal variation.
+
+
+Sources:
+ https://timeseriesreasoning.com/contents/holt-winters-exponential-smoothing/
+ https://www.mql5.com/en/code/20856
+
+nA - smoothed series (from 0 to 1)
+nB - assess the trend (from 0 to 1)
+nC - assess seasonality (from 0 to 1)
+
+Heuristic for determining alpha, beta, and gamma from period:
+ alpha = 2 / (1 + period)
+ beta = 1 / period
+ gamma = 1 / period
+
+F[i] = (1-nA) * (F[i-1] + V[i-1] + 0.5 * A[i-1]) + nA * Price[i]
+V[i] = (1-nB) * (V[i-1] + A[i-1]) + nB * (F[i] - F[i-1])
+A[i] = (1-nC) * A[i-1] + nC * (V[i] - V[i-1])
+HWMA[i] = F[i] + V[i] + 0.5 * A[i]
+
+ */
+
+public class HWMA_Series : TSeries
+{
+ private int _len;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ double _nA, _nB, _nC;
+ double _pF, _pV, _pA;
+ double _ppF, _ppV, _ppA;
+
+ //core constructors
+
+ public HWMA_Series(double nA, double nB, double nC, bool useNaN)
+ {
+ _period = (int)((2 - nA) / nA);
+ _nA = nA;
+ _nB = nB;
+ _nC = nC;
+ _NaN = useNaN;
+ Name = $"HWMA({_period})";
+ _len = 0;
+ }
+ public HWMA_Series(TSeries source, double nA, double nB, double nC, bool useNaN = false) : this(nA, nB, nC, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public HWMA_Series() : this(period: 0, useNaN: false) { }
+ public HWMA_Series(int period) : this(period, useNaN: false) { }
+ public HWMA_Series(int period, bool useNaN) : this(nA: 2 / (1 + (double)period), nB: 1 / (double)period, nC: 1 / (double)period, useNaN)
+ {
+ _period = period;
+ }
+ public HWMA_Series(TBars source) : this(source.Close, period: 0, useNaN: false) { }
+ public HWMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public HWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public HWMA_Series(TSeries source, int period) : this(source, period, false) { }
+ public HWMA_Series(TSeries source, int period, bool useNaN) : this(source, nA: 2 / (1 + (double)period), nB: 1 / (double)period, nC: 1 / (double)period, useNaN: useNaN) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+ double _F, _V, _A;
+ if (_len == 0) { _pF = TValue.v; _pA = _pV = 0; }
+
+ if (update) { _pF = _ppF; _pV = _ppV; _pA = _ppA; }
+ else
+ {
+ _ppF = _pF;
+ _ppV = _pV;
+ _ppA = _pA;
+ _len++;
+ }
+
+ if (_period == 0)
+ {
+ _nA = 2 / (1 + (double)_len);
+ _nB = 1 / (double)_len;
+ _nC = 1 / (double)_len;
+ }
+ if (_period == 1)
+ {
+ _nA = 1;
+ _nB = 0;
+ _nC = 0;
+ }
+
+ _F = (1 - _nA) * (_pF + _pV + 0.5 * _pA) + _nA * TValue.v;
+ _V = (1 - _nB) * (_pV + _pA) + _nB * (_F - _pF);
+ _A = (1 - _nC) * _pA + _nC * (_V - _pV);
+
+ double _hwma = _F + _V + 0.5 * _A;
+ _pF = _F;
+ _pV = _V;
+ _pA = _A;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hwma);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _len = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/JMA_Series.cs b/Calculations/_Updated/JMA_Series.cs
index 8d5b9af0..517bbbe3 100644
--- a/Calculations/_Updated/JMA_Series.cs
+++ b/Calculations/_Updated/JMA_Series.cs
@@ -1,176 +1,176 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-JMA: Jurik Moving Average
- Mark Jurik's Moving Average (JMA) attempts to eliminate noise to see the
- underlying activity. It has extremely low lag, is very smooth and is responsive
- to market gaps.
-
-Sources:
- https://c.mql5.com/forextsd/forum/164/jurik_1.pdf
- https://www.prorealcode.com/prorealtime-indicators/jurik-volatility-bands/
-
-Issues:
- Real JMA algorithm is not published and this formula is derived through
- deduction and reverse analysis of JMA behavior. It is really close, but not
- exact - published JMA tests against JMA.CSV fail with small deviation. The
- original algo is slightly different, yet this approximation is close enough.
-
- */
-
-public class JMA_Series : TSeries
-{
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private readonly System.Collections.Generic.List volty_short = new();
- private readonly System.Collections.Generic.List vsum_buff = new();
- private readonly double pr;
- private double upperBand, lowerBand, vsum, Kv;
- private double prev_ma1, prev_det0, prev_det1, prev_vsum, prev_jma;
- private double p_upperBand, p_lowerBand, p_Kv, p_prev_ma1, p_prev_det0, p_prev_det1, p_prev_vsum, p_prev_jma;
- private readonly int _voltyS, _voltyL;
-
- //core constructors
- public JMA_Series(int period, double phase, int vshort, int vlong, bool useNaN)
- {
- _period = period;
- _NaN = useNaN;
- Name = $"JMA({period})";
- upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0;
- pr = (phase * 0.01) + 1.5;
- if (phase < -100) { pr = 0.5; }
- if (phase > 100) { pr = 2.5; }
- _voltyS = vshort;
- _voltyL = vlong;
- }
-
- public JMA_Series(TSeries source, int period, double phase, int vshort, int vlong, bool useNaN) : this(period, phase, vshort, vlong, useNaN)
- {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public JMA_Series() : this(period: 0, phase: 0, vshort: 10, vlong: 65, useNaN: false) { }
- public JMA_Series(int period) : this(period: period, phase: 0, vshort: 10, vlong: 65, useNaN: false) { }
- public JMA_Series(TBars source) : this(source.Close, period: 0, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
- public JMA_Series(TBars source, int period) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
- public JMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { }
- public JMA_Series(TSeries source) : this(source, period: 0, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
- public JMA_Series(TSeries source, int period) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
- public JMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
- {
- if (this.Count == 0) { prev_ma1 = prev_jma = TValue.v; }
- if (update)
- {
- upperBand = p_upperBand;
- lowerBand = p_lowerBand;
- Kv = p_Kv;
- prev_vsum = p_prev_vsum;
- prev_ma1 = p_prev_ma1;
- prev_det0 = p_prev_det0;
- prev_det1 = p_prev_det1;
- prev_jma = p_prev_jma;
- }
- else
- {
- p_upperBand = upperBand;
- p_lowerBand = lowerBand;
- p_Kv = Kv;
- p_prev_vsum = prev_vsum;
- p_prev_ma1 = prev_ma1;
- p_prev_det0 = prev_det0;
- p_prev_det1 = prev_det1;
- p_prev_jma = prev_jma;
- }
-
- if (double.IsNaN(TValue.v))
- {
- return base.Add((TValue.t, double.NaN), update);
- }
-
- // from Tvalue to volty
- double del1 = TValue.v - upperBand;
- double del2 = TValue.v - lowerBand;
- upperBand = (del1 > 0) ? TValue.v : TValue.v - (Kv * del1);
- lowerBand = (del2 < 0) ? TValue.v : TValue.v - (Kv * del2);
- double volty = Math.Abs(del1) > Math.Abs(del2) ? Math.Abs(del1) :
- (Math.Abs(del1) < Math.Abs(del2) ? Math.Abs(del2) :
- Math.Abs(0.5 * (del1 + del2)));
-
- //// from volty to avolty
- if (update) { volty_short[volty_short.Count - 1] = volty; }
- else { volty_short.Add(volty); }
- if (volty_short.Count > _voltyS) { volty_short.RemoveAt(0); }
- vsum = prev_vsum + 0.1 * (volty - volty_short.First());
- prev_vsum = vsum;
- if (update) { vsum_buff[vsum_buff.Count - 1] = vsum; }
- else { vsum_buff.Add(vsum); }
- if (vsum_buff.Count > _voltyL) { vsum_buff.RemoveAt(0); }
- double avolty = 0;
- for (int i = 0; i < vsum_buff.Count; i++) { avolty += vsum_buff[i]; }
- avolty /= vsum_buff.Count;
-
- /// from avolty to rolty
- double rvolty = (avolty != 0) ? volty / avolty : 0;
- double len1 = (Math.Log(Math.Sqrt(_period)) / Math.Log(2.0)) + 2;
- if (len1 < 0) { len1 = 0; }
-
- double pow1 = Math.Max(len1 - 2.0, 0.5);
- if (rvolty > Math.Pow(len1, 1.0 / pow1)) { rvolty = Math.Pow(len1, 1.0 / pow1); }
- if (rvolty < 1) { rvolty = 1; }
-
- //// from rvolty to second smoothing
- double pow2 = Math.Pow(rvolty, pow1);
- double beta = 0.45 * (_period - 1) / (0.45 * (_period - 1) + 2);
- Kv = Math.Pow(beta, Math.Sqrt(pow2));
- double alpha = Math.Pow(beta, pow2);
- double ma1 = (1 - alpha) * TValue.v + alpha * prev_ma1;
- prev_ma1 = ma1;
-
- double det0 = (1 - beta) * (TValue.v - ma1) + beta * prev_det0;
- prev_det0 = det0;
- double ma2 = ma1 + pr * det0;
-
- double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - prev_jma)) + (alpha * alpha * prev_det1);
- prev_det1 = det1;
- double jma = prev_jma + det1;
- prev_jma = jma;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : jma);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data)
- {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update)
- {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add()
- {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e)
- {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset()
- {
- upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0;
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+JMA: Jurik Moving Average
+ Mark Jurik's Moving Average (JMA) attempts to eliminate noise to see the
+ underlying activity. It has extremely low lag, is very smooth and is responsive
+ to market gaps.
+
+Sources:
+ https://c.mql5.com/forextsd/forum/164/jurik_1.pdf
+ https://www.prorealcode.com/prorealtime-indicators/jurik-volatility-bands/
+
+Issues:
+ Real JMA algorithm is not published and this formula is derived through
+ deduction and reverse analysis of JMA behavior. It is really close, but not
+ exact - published JMA tests against JMA.CSV fail with small deviation. The
+ original algo is slightly different, yet this approximation is close enough.
+
+ */
+
+public class JMA_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private readonly System.Collections.Generic.List volty_short = new();
+ private readonly System.Collections.Generic.List vsum_buff = new();
+ private readonly double pr;
+ private double upperBand, lowerBand, vsum, Kv;
+ private double prev_ma1, prev_det0, prev_det1, prev_vsum, prev_jma;
+ private double p_upperBand, p_lowerBand, p_Kv, p_prev_ma1, p_prev_det0, p_prev_det1, p_prev_vsum, p_prev_jma;
+ private readonly int _voltyS, _voltyL;
+
+ //core constructors
+ public JMA_Series(int period, double phase, int vshort, int vlong, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"JMA({period})";
+ upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0;
+ pr = (phase * 0.01) + 1.5;
+ if (phase < -100) { pr = 0.5; }
+ if (phase > 100) { pr = 2.5; }
+ _voltyS = vshort;
+ _voltyL = vlong;
+ }
+
+ public JMA_Series(TSeries source, int period, double phase, int vshort, int vlong, bool useNaN) : this(period, phase, vshort, vlong, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public JMA_Series() : this(period: 0, phase: 0, vshort: 10, vlong: 65, useNaN: false) { }
+ public JMA_Series(int period) : this(period: period, phase: 0, vshort: 10, vlong: 65, useNaN: false) { }
+ public JMA_Series(TBars source) : this(source.Close, period: 0, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
+ public JMA_Series(TBars source, int period) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
+ public JMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { }
+ public JMA_Series(TSeries source) : this(source, period: 0, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
+ public JMA_Series(TSeries source, int period) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
+ public JMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (this.Count == 0) { prev_ma1 = prev_jma = TValue.v; }
+ if (update)
+ {
+ upperBand = p_upperBand;
+ lowerBand = p_lowerBand;
+ Kv = p_Kv;
+ prev_vsum = p_prev_vsum;
+ prev_ma1 = p_prev_ma1;
+ prev_det0 = p_prev_det0;
+ prev_det1 = p_prev_det1;
+ prev_jma = p_prev_jma;
+ }
+ else
+ {
+ p_upperBand = upperBand;
+ p_lowerBand = lowerBand;
+ p_Kv = Kv;
+ p_prev_vsum = prev_vsum;
+ p_prev_ma1 = prev_ma1;
+ p_prev_det0 = prev_det0;
+ p_prev_det1 = prev_det1;
+ p_prev_jma = prev_jma;
+ }
+
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, double.NaN), update);
+ }
+
+ // from Tvalue to volty
+ double del1 = TValue.v - upperBand;
+ double del2 = TValue.v - lowerBand;
+ upperBand = (del1 > 0) ? TValue.v : TValue.v - (Kv * del1);
+ lowerBand = (del2 < 0) ? TValue.v : TValue.v - (Kv * del2);
+ double volty = Math.Abs(del1) > Math.Abs(del2) ? Math.Abs(del1) :
+ (Math.Abs(del1) < Math.Abs(del2) ? Math.Abs(del2) :
+ Math.Abs(0.5 * (del1 + del2)));
+
+ //// from volty to avolty
+ if (update) { volty_short[volty_short.Count - 1] = volty; }
+ else { volty_short.Add(volty); }
+ if (volty_short.Count > _voltyS) { volty_short.RemoveAt(0); }
+ vsum = prev_vsum + 0.1 * (volty - volty_short.First());
+ prev_vsum = vsum;
+ if (update) { vsum_buff[vsum_buff.Count - 1] = vsum; }
+ else { vsum_buff.Add(vsum); }
+ if (vsum_buff.Count > _voltyL) { vsum_buff.RemoveAt(0); }
+ double avolty = 0;
+ for (int i = 0; i < vsum_buff.Count; i++) { avolty += vsum_buff[i]; }
+ avolty /= vsum_buff.Count;
+
+ /// from avolty to rolty
+ double rvolty = (avolty != 0) ? volty / avolty : 0;
+ double len1 = (Math.Log(Math.Sqrt(_period)) / Math.Log(2.0)) + 2;
+ if (len1 < 0) { len1 = 0; }
+
+ double pow1 = Math.Max(len1 - 2.0, 0.5);
+ if (rvolty > Math.Pow(len1, 1.0 / pow1)) { rvolty = Math.Pow(len1, 1.0 / pow1); }
+ if (rvolty < 1) { rvolty = 1; }
+
+ //// from rvolty to second smoothing
+ double pow2 = Math.Pow(rvolty, pow1);
+ double beta = 0.45 * (_period - 1) / (0.45 * (_period - 1) + 2);
+ Kv = Math.Pow(beta, Math.Sqrt(pow2));
+ double alpha = Math.Pow(beta, pow2);
+ double ma1 = (1 - alpha) * TValue.v + alpha * prev_ma1;
+ prev_ma1 = ma1;
+
+ double det0 = (1 - beta) * (TValue.v - ma1) + beta * prev_det0;
+ prev_det0 = det0;
+ double ma2 = ma1 + pr * det0;
+
+ double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - prev_jma)) + (alpha * alpha * prev_det1);
+ prev_det1 = det1;
+ double jma = prev_jma + det1;
+ prev_jma = jma;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : jma);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/KAMA_Series.cs b/Calculations/_Updated/KAMA_Series.cs
index a3bcf394..ae3a96cd 100644
--- a/Calculations/_Updated/KAMA_Series.cs
+++ b/Calculations/_Updated/KAMA_Series.cs
@@ -1,107 +1,118 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-KAMA: Kaufman's Adaptive Moving Average
- Created in 1988 by American quantitative finance theorist Perry J. Kaufman and is known as
- Kaufman's Adaptive Moving Average (KAMA). Even though the method was developed as early as 1972,
- it was not until the popular book titled "Trading Systems and Methods" that it was made widely
- available to the public. Unlike other conventional moving averages systems, the Kaufman's Adaptive
- Moving Average, considers market volatility apart from price fluctuations.
-
- KAMA[i] = KAMA[i-1] + SC * ( price - KAMA[i-1] )
-
-Sources:
- https://www.tutorialspoint.com/kaufman-s-adaptive-moving-average-kama-formula-and-how-does-it-work
- https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/kaufmans-adaptive-moving-average-kama/
- https://www.technicalindicators.net/indicators-technical-analysis/152-kama-kaufman-adaptive-moving-average
-
-Remark:
- If useNaN:true argument is provided, KAMA starts calculating values from [period] bar onwards.
- Without useNaN argument (default setting), KAMA starts calculating values from bar 1 - and yields
- slightly different results for the first 50 bars - and then converges with the other one.
-
- */
-
-public class KAMA_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- private double _lastkama, _lastlastkama;
- private readonly double _scFast, _scSlow;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public KAMA_Series(int period, int fast, int slow, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- _scFast = 2.0 / (((period < fast) ? period : fast) + 1);
- _scSlow = 2.0 / (slow + 1);
- _lastkama = _lastlastkama = 0;
- Name = $"KAMA({period})";
- }
- public KAMA_Series(TSeries source, int period, int fast, int slow, bool useNaN) : this(period, fast, slow, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public KAMA_Series() : this(period: 0, fast: 2, slow: 30, useNaN: false) { }
- public KAMA_Series(int period) : this(period: period, fast: 2, slow: 30, useNaN: false) { }
- public KAMA_Series(TBars source) : this(source.Close, period: 0, fast: 2, slow: 30, useNaN: false) { }
- public KAMA_Series(TBars source, int period) : this(source.Close, period: period, fast: 2, slow: 30, useNaN: false) { }
- public KAMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, fast: 2, slow: 30, useNaN: useNaN) { }
- public KAMA_Series(TSeries source) : this(source, period: 0, fast: 2, slow: 30, useNaN: false) { }
- public KAMA_Series(TSeries source, int period) : this(source: source, period: period, fast: 2, slow: 30, useNaN: false) { }
- public KAMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, fast: 2, slow: 30, useNaN: useNaN) { }
- public KAMA_Series(TSeries source, int period, int fast, int slow) : this(source: source, period: period, fast: fast, slow: slow, useNaN: false) { }
-
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, Double.NaN), update);
- }
-
- if (update) { _lastkama = _lastlastkama; }
- else { _lastlastkama = _lastkama; }
- BufferTrim(buffer: _buffer, value: TValue.v, period: _period + 1, update: update);
-
- double _kama = 0;
- if (this.Count < _period) { _kama = TValue.v; }
- else {
- double _change = Math.Abs(_buffer[^1] - _buffer[(_buffer.Count > _period + 1) ? 1 : 0]);
- double _sumpv = 0;
- for (int i = 1; i < _buffer.Count; i++) { _sumpv += Math.Abs(_buffer[(_buffer.Count > 0) ? i : 0] - _buffer[i - 1]); }
- double _er = (_sumpv == 0) ? 0 : _change / _sumpv;
- double _sc = (_er * (_scFast - _scSlow)) + _scSlow;
- _kama = (_lastkama + (_sc * _sc * (TValue.v - _lastkama)));
- }
- _lastkama = _kama;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kama);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- _lastkama = _lastlastkama = 0;
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+KAMA: Kaufman's Adaptive Moving Average
+ Created in 1988 by American quantitative finance theorist Perry J. Kaufman and is known as
+ Kaufman's Adaptive Moving Average (KAMA). Even though the method was developed as early as 1972,
+ it was not until the popular book titled "Trading Systems and Methods" that it was made widely
+ available to the public. Unlike other conventional moving averages systems, the Kaufman's Adaptive
+ Moving Average, considers market volatility apart from price fluctuations.
+
+ KAMA[i] = KAMA[i-1] + SC * ( price - KAMA[i-1] )
+
+Sources:
+ https://www.tutorialspoint.com/kaufman-s-adaptive-moving-average-kama-formula-and-how-does-it-work
+ https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/kaufmans-adaptive-moving-average-kama/
+ https://www.technicalindicators.net/indicators-technical-analysis/152-kama-kaufman-adaptive-moving-average
+
+Remark:
+ If useNaN:true argument is provided, KAMA starts calculating values from [period] bar onwards.
+ Without useNaN argument (default setting), KAMA starts calculating values from bar 1 - and yields
+ slightly different results for the first 50 bars - and then converges with the other one.
+
+ */
+
+public class KAMA_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ private double _lastkama, _lastlastkama;
+ private readonly double _scFast, _scSlow;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public KAMA_Series(int period, int fast, int slow, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ _scFast = 2.0 / (((period < fast) ? period : fast) + 1);
+ _scSlow = 2.0 / (slow + 1);
+ _lastkama = _lastlastkama = 0;
+ Name = $"KAMA({period})";
+ }
+ public KAMA_Series(TSeries source, int period, int fast, int slow, bool useNaN) : this(period, fast, slow, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public KAMA_Series() : this(period: 0, fast: 2, slow: 30, useNaN: false) { }
+ public KAMA_Series(int period) : this(period: period, fast: 2, slow: 30, useNaN: false) { }
+ public KAMA_Series(TBars source) : this(source.Close, period: 0, fast: 2, slow: 30, useNaN: false) { }
+ public KAMA_Series(TBars source, int period) : this(source.Close, period: period, fast: 2, slow: 30, useNaN: false) { }
+ public KAMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, fast: 2, slow: 30, useNaN: useNaN) { }
+ public KAMA_Series(TSeries source) : this(source, period: 0, fast: 2, slow: 30, useNaN: false) { }
+ public KAMA_Series(TSeries source, int period) : this(source: source, period: period, fast: 2, slow: 30, useNaN: false) { }
+ public KAMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, fast: 2, slow: 30, useNaN: useNaN) { }
+ public KAMA_Series(TSeries source, int period, int fast, int slow) : this(source: source, period: period, fast: fast, slow: slow, useNaN: false) { }
+
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+
+ if (update) { _lastkama = _lastlastkama; }
+ else { _lastlastkama = _lastkama; }
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period + 1, update: update);
+
+ double _kama = 0;
+ if (this.Count < _period) { _kama = TValue.v; }
+ else
+ {
+ double _change = Math.Abs(_buffer[^1] - _buffer[(_buffer.Count > _period + 1) ? 1 : 0]);
+ double _sumpv = 0;
+ for (int i = 1; i < _buffer.Count; i++) { _sumpv += Math.Abs(_buffer[(_buffer.Count > 0) ? i : 0] - _buffer[i - 1]); }
+ double _er = (_sumpv == 0) ? 0 : _change / _sumpv;
+ double _sc = (_er * (_scFast - _scSlow)) + _scSlow;
+ _kama = (_lastkama + (_sc * _sc * (TValue.v - _lastkama)));
+ }
+ _lastkama = _kama;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kama);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ _lastkama = _lastlastkama = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/KURTOSIS_Series.cs b/Calculations/_Updated/KURTOSIS_Series.cs
index 71b8cfba..bfc972af 100644
--- a/Calculations/_Updated/KURTOSIS_Series.cs
+++ b/Calculations/_Updated/KURTOSIS_Series.cs
@@ -1,96 +1,107 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-KURTOSIS: Kurtosis of population
- Kurtosis characterizes the relative peakedness or flatness of a distribution
- compared with the normal distribution. Positive kurtosis indicates a relatively
- peaked distribution. Negative kurtosis indicates a relatively flat distribution.
-
- The normal curve is called Mesokurtic curve. If the curve of a distribution is
- more outlier prone (or heavier-tailed) than a normal or mesokurtic curve then
- it is referred to as a Leptokurtic curve. If a curve is less outlier prone (or
- lighter-tailed) than a normal curve, it is called as a platykurtic curve.
-
-Calculation:
- sum4 = Σ(close-SMA)^4
- sum2 = (Σ(close-SMA)^2)^2
- KURTOSIS = length * (sum4/sum2)
-
-Sources:
- https://en.wikipedia.org/wiki/Kurtosis
- https://stats.oarc.ucla.edu/other/mult-pkg/faq/general/faq-whats-with-the-different-formulas-for-kurtosis/
-
- */
-
-public class KURTOSIS_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private readonly System.Collections.Generic.List _buffer = new();
-
- //core constructors
- public KURTOSIS_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"KURTOSIS({period})";
- }
- public KURTOSIS_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public KURTOSIS_Series() : this(period: 0, useNaN: false) { }
- public KURTOSIS_Series(int period) : this(period: period, useNaN: false) { }
- public KURTOSIS_Series(TSeries source) : this(source, period: 0, useNaN: false) { }
- public KURTOSIS_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, Double.NaN), update);
- }
-
- BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
- double _n = _buffer.Count;
- double _avg = _buffer.Average();
-
- double _s2 = 0;
- double _s4 = 0;
- for (int i = 0; i < this._buffer.Count; i++) {
- _s2 += (_buffer[i] - _avg) * (_buffer[i] - _avg);
- _s4 += (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg);
- }
-
- double _Vx = _s2 / (_n - 1);
- double _kurt = (_n > 3) ?
- (_n * (_n + 1) * _s4) / (_Vx * _Vx * (_n - 3) * (_n - 1) * (_n - 2)) - (3 * (_n - 1) * (_n - 1) / ((_n - 2) * (_n - 3))) //using Sheskin Algo
- : (_s2 * _s2) / _n - 3; //using Snedecor and Cochran (1967) algo
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kurt);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+KURTOSIS: Kurtosis of population
+ Kurtosis characterizes the relative peakedness or flatness of a distribution
+ compared with the normal distribution. Positive kurtosis indicates a relatively
+ peaked distribution. Negative kurtosis indicates a relatively flat distribution.
+
+ The normal curve is called Mesokurtic curve. If the curve of a distribution is
+ more outlier prone (or heavier-tailed) than a normal or mesokurtic curve then
+ it is referred to as a Leptokurtic curve. If a curve is less outlier prone (or
+ lighter-tailed) than a normal curve, it is called as a platykurtic curve.
+
+Calculation:
+ sum4 = Σ(close-SMA)^4
+ sum2 = (Σ(close-SMA)^2)^2
+ KURTOSIS = length * (sum4/sum2)
+
+Sources:
+ https://en.wikipedia.org/wiki/Kurtosis
+ https://stats.oarc.ucla.edu/other/mult-pkg/faq/general/faq-whats-with-the-different-formulas-for-kurtosis/
+
+ */
+
+public class KURTOSIS_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private readonly System.Collections.Generic.List _buffer = new();
+
+ //core constructors
+ public KURTOSIS_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"KURTOSIS({period})";
+ }
+ public KURTOSIS_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public KURTOSIS_Series() : this(period: 0, useNaN: false) { }
+ public KURTOSIS_Series(int period) : this(period: period, useNaN: false) { }
+ public KURTOSIS_Series(TSeries source) : this(source, period: 0, useNaN: false) { }
+ public KURTOSIS_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+ double _n = _buffer.Count;
+ double _avg = _buffer.Average();
+
+ double _s2 = 0;
+ double _s4 = 0;
+ for (int i = 0; i < this._buffer.Count; i++)
+ {
+ _s2 += (_buffer[i] - _avg) * (_buffer[i] - _avg);
+ _s4 += (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg);
+ }
+
+ double _Vx = _s2 / (_n - 1);
+ double _kurt = (_n > 3) ?
+ (_n * (_n + 1) * _s4) / (_Vx * _Vx * (_n - 3) * (_n - 1) * (_n - 2)) - (3 * (_n - 1) * (_n - 1) / ((_n - 2) * (_n - 3))) //using Sheskin Algo
+ : (_s2 * _s2) / _n - 3; //using Snedecor and Cochran (1967) algo
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kurt);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/MACD_Series.cs b/Calculations/_Updated/MACD_Series.cs
index a81ce1a9..251f6577 100644
--- a/Calculations/_Updated/MACD_Series.cs
+++ b/Calculations/_Updated/MACD_Series.cs
@@ -1,78 +1,88 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-MACD: Moving Average Convergence/Divergence
- Moving average convergence divergence (MACD) is a trend-following momentum
- indicator that shows the relationship between two moving averages of a series.
- The MACD is calculated by subtracting the 26-period exponential moving average (EMA)
- from the 12-period EMA. MACD Signal is 9-day EMA of MACD.
-
- */
-
-public class MACD_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
-
- protected readonly int _slow, _fast, _signal;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private readonly EMA_Series _TSlow;
- private readonly EMA_Series _TFast;
- public EMA_Series Signal { get; }
-
- //core constructors
- public MACD_Series(int slow = 26, int fast = 12, int signal = 9, bool useNaN = false) {
- _slow = slow;
- _fast = fast;
- _signal = signal;
- _NaN = useNaN;
- Name = $"MACD({slow},{fast},{signal})";
- _TSlow = new(slow, useNaN:false, useSMA:true);
- _TFast = new(fast, useNaN: false, useSMA: true);
- Signal = new(signal, useNaN: false, useSMA: true);
- }
- public MACD_Series(TSeries source, int slow, int fast, int signal, bool useNaN) : this(slow, fast, signal, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public MACD_Series(TSeries source) : this(source:source, slow:26, fast:12, signal:9 , useNaN:false) { }
- public MACD_Series(TSeries source, int slow, int fast, int signal) : this(source: source, slow: slow, fast:fast, signal:signal, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, Double.NaN), update);
- }
-
- var _sslow = _TSlow.Add(TValue,update);
- var _sfast = _TFast.Add(TValue, update);
- Signal.Add((TValue.t, _sfast.v-_sslow.v));
-
- var res = (TValue.t, Count < _fast - 1 && _NaN ? double.NaN : _sfast.v-_sslow.v);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+MACD: Moving Average Convergence/Divergence
+ Moving average convergence divergence (MACD) is a trend-following momentum
+ indicator that shows the relationship between two moving averages of a series.
+ The MACD is calculated by subtracting the 26-period exponential moving average (EMA)
+ from the 12-period EMA. MACD Signal is 9-day EMA of MACD.
+
+ */
+
+public class MACD_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+
+ protected readonly int _slow, _fast, _signal;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private readonly EMA_Series _TSlow;
+ private readonly EMA_Series _TFast;
+ public EMA_Series Signal { get; }
+
+ //core constructors
+ public MACD_Series(int slow = 26, int fast = 12, int signal = 9, bool useNaN = false)
+ {
+ _slow = slow;
+ _fast = fast;
+ _signal = signal;
+ _NaN = useNaN;
+ Name = $"MACD({slow},{fast},{signal})";
+ _TSlow = new(slow, useNaN: false, useSMA: true);
+ _TFast = new(fast, useNaN: false, useSMA: true);
+ Signal = new(signal, useNaN: false, useSMA: true);
+ }
+ public MACD_Series(TSeries source, int slow, int fast, int signal, bool useNaN) : this(slow, fast, signal, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MACD_Series(TSeries source) : this(source: source, slow: 26, fast: 12, signal: 9, useNaN: false) { }
+ public MACD_Series(TSeries source, int slow, int fast, int signal) : this(source: source, slow: slow, fast: fast, signal: signal, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+
+ var _sslow = _TSlow.Add(TValue, update);
+ var _sfast = _TFast.Add(TValue, update);
+ Signal.Add((TValue.t, _sfast.v - _sslow.v));
+
+ var res = (TValue.t, Count < _fast - 1 && _NaN ? double.NaN : _sfast.v - _sslow.v);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/MAD_Series.cs b/Calculations/_Updated/MAD_Series.cs
index 0378f1c5..3ba8ca1b 100644
--- a/Calculations/_Updated/MAD_Series.cs
+++ b/Calculations/_Updated/MAD_Series.cs
@@ -1,79 +1,88 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-MAD: Mean Absolute Deviation
- Also known as AAD - Average Absolute Deviation, to differentiate it from Median Absolute Deviation
- MAD defines the degree of variation across the series.
-
-Calculation:
- MAD = Σ(|close-SMA|) / period
-
-Sources:
- https://en.wikipedia.org/wiki/Average_absolute_deviation
-
- */
-
-public class MAD_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public MAD_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"MAD({period})";
- }
- public MAD_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public MAD_Series() : this(period: 0, useNaN: false) { }
- public MAD_Series(int period) : this(period: period, useNaN: false) { }
- public MAD_Series(TBars source) : this(source.Close, 0, false) { }
- public MAD_Series(TBars source, int period) : this(source.Close, period, false) { }
- public MAD_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public MAD_Series(TSeries source) : this(source, 0, false) { }
- public MAD_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _sma = _buffer.Average();
- double _mad = 0;
- for (int i = 0; i < _buffer.Count; i++) { _mad += Math.Abs(_buffer[i] - _sma); }
- _mad /= this._buffer.Count;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mad);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+MAD: Mean Absolute Deviation
+ Also known as AAD - Average Absolute Deviation, to differentiate it from Median Absolute Deviation
+ MAD defines the degree of variation across the series.
+
+Calculation:
+ MAD = Σ(|close-SMA|) / period
+
+Sources:
+ https://en.wikipedia.org/wiki/Average_absolute_deviation
+
+ */
+
+public class MAD_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public MAD_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"MAD({period})";
+ }
+ public MAD_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MAD_Series() : this(period: 0, useNaN: false) { }
+ public MAD_Series(int period) : this(period: period, useNaN: false) { }
+ public MAD_Series(TBars source) : this(source.Close, 0, false) { }
+ public MAD_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public MAD_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public MAD_Series(TSeries source) : this(source, 0, false) { }
+ public MAD_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _sma = _buffer.Average();
+ double _mad = 0;
+ for (int i = 0; i < _buffer.Count; i++) { _mad += Math.Abs(_buffer[i] - _sma); }
+ _mad /= this._buffer.Count;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mad);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/MAE_Series.cs b/Calculations/_Updated/MAE_Series.cs
index b01839d2..7a8d05f6 100644
--- a/Calculations/_Updated/MAE_Series.cs
+++ b/Calculations/_Updated/MAE_Series.cs
@@ -1,77 +1,86 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-MAE: Mean Absolute Error
- Defined as a Mean (Average) of the absolute difference between actual and estimated values.
- MAE = (1/n) * Σ|y_i - MA_i|
-
-Sources:
- https://en.wikipedia.org/wiki/Mean_absolute_error
-
- */
-
-public class MAE_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public MAE_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"MSE({period})";
- }
- public MAE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public MAE_Series() : this(period: 0, useNaN: false) { }
- public MAE_Series(int period) : this(period: period, useNaN: false) { }
- public MAE_Series(TBars source) : this(source.Close, 0, false) { }
- public MAE_Series(TBars source, int period) : this(source.Close, period, false) { }
- public MAE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public MAE_Series(TSeries source) : this(source, 0, false) { }
- public MAE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _sma = _buffer.Average();
-
- double _mae = 0;
- for (int i = 0; i < _buffer.Count; i++) { _mae += Math.Abs(_buffer[i] - _sma); }
- _mae /= this._buffer.Count;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mae);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+MAE: Mean Absolute Error
+ Defined as a Mean (Average) of the absolute difference between actual and estimated values.
+ MAE = (1/n) * Σ|y_i - MA_i|
+
+Sources:
+ https://en.wikipedia.org/wiki/Mean_absolute_error
+
+ */
+
+public class MAE_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public MAE_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"MSE({period})";
+ }
+ public MAE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MAE_Series() : this(period: 0, useNaN: false) { }
+ public MAE_Series(int period) : this(period: period, useNaN: false) { }
+ public MAE_Series(TBars source) : this(source.Close, 0, false) { }
+ public MAE_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public MAE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public MAE_Series(TSeries source) : this(source, 0, false) { }
+ public MAE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _sma = _buffer.Average();
+
+ double _mae = 0;
+ for (int i = 0; i < _buffer.Count; i++) { _mae += Math.Abs(_buffer[i] - _sma); }
+ _mae /= this._buffer.Count;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mae);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/MAMA_Series.cs b/Calculations/_Updated/MAMA_Series.cs
index 52bd5d7b..e450337a 100644
--- a/Calculations/_Updated/MAMA_Series.cs
+++ b/Calculations/_Updated/MAMA_Series.cs
@@ -1,189 +1,207 @@
-namespace QuanTAlib;
-
-using System;
-using System.Linq;
-
-/*
-MAMA: MESA Adaptive Moving Average
- Created by John Ehlers, the MAMA indicator is a 5-period adaptive moving average of
- high/low price that uses classic electrical radio-frequency signal processing algorithms
- to reduce noise.
-
- KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 )
-
-Sources:
- https://mesasoftware.com/papers/MAMA.pdf
- https://www.tradingview.com/script/foQxLbU3-Ehlers-MESA-Adaptive-Moving-Average-LazyBear/
-
- */
-
-public class MAMA_Series : TSeries {
- private int _len;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- private double sumPr;
- private double fastl, slowl;
- private (double i, double i1, double i2, double i3, double i4, double i5, double i6, double io) pr, i1, q1, sm, dt;
- private (double i, double i1, double io) i2, q2, re, im, pd, ph, mama, fama;
- public TSeries Fama { get; }
- private double mamaseed, famaseed;
-
- //core constructors
-
- public MAMA_Series(double fastlimit, double slowlimit, bool useNaN) {
- _period = (int)(2 / fastlimit) - 1;
- fastl = fastlimit;
- slowl = slowlimit;
- Fama = new TSeries();
- _NaN = useNaN;
- Name = $"MAMA({_period})";
- _len = 0;
- }
- public MAMA_Series(TSeries source, double fastlimit, double slowlimit, bool useNaN = false) : this(fastlimit, slowlimit, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public MAMA_Series() : this(period: 0, useNaN: false) { }
- public MAMA_Series(int period) : this(period, useNaN: false) { }
- public MAMA_Series(int period, bool useNaN) : this(fastlimit: 2 / (period + 1), slowlimit: 0.2 / (period + 1), useNaN) {
- _period = period;
- }
- public MAMA_Series(TBars source) : this(source.Close, period: 0, useNaN: false) { }
- public MAMA_Series(TBars source, int period) : this(source.Close, period, false) { }
- public MAMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public MAMA_Series(TSeries source, int period) : this(source, period, false) { }
- public MAMA_Series(TSeries source, int period, bool useNaN) : this(source, fastlimit: 2 / ((double)period + 1), slowlimit: 0.2 / ((double)period + 1), useNaN: useNaN) { }
-
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, Double.NaN), update);
- }
- if (!update) {
- // roll forward (oldx = x)
- pr.io = pr.i6; pr.i6 = pr.i5; pr.i5 = pr.i4; pr.i4 = pr.i3; pr.i3 = pr.i2; pr.i2 = pr.i1; pr.i1 = pr.i;
- i1.io = i1.i6; i1.i6 = i1.i5; i1.i5 = i1.i4; i1.i4 = i1.i3; i1.i3 = i1.i2; i1.i2 = i1.i1; i1.i1 = i1.i;
- q1.io = q1.i6; q1.i6 = q1.i5; q1.i5 = q1.i4; q1.i4 = q1.i3; q1.i3 = q1.i2; q1.i2 = q1.i1; q1.i1 = q1.i;
- dt.io = dt.i6; dt.i6 = dt.i5; dt.i5 = dt.i4; dt.i4 = dt.i3; dt.i3 = dt.i2; dt.i2 = dt.i1; dt.i1 = dt.i;
- sm.io = sm.i6; sm.i6 = sm.i5; sm.i5 = sm.i4; sm.i4 = sm.i3; sm.i3 = sm.i2; sm.i2 = sm.i1; sm.i1 = sm.i;
- i2.io = i2.i1; i2.i1 = i2.i; q2.io = q2.i1; q2.i1 = q2.i;
- re.io = re.i1; re.i1 = re.i; im.io = im.i1; im.i1 = im.i;
- pd.io = pd.i1; pd.i1 = pd.i; ph.io = ph.i1; ph.i1 = ph.i;
- mama.io = mama.i1; mama.i1 = mama.i;
- fama.io = fama.i1;
- fama.i1 = fama.i;
- _len++;
- }
- if (_period == 0) {
- fastl = 2 / (double)_len;
- slowl = fastl * 0.1;
- }
- if (_period == 1) {
- fastl = 1;
- slowl = 1;
- }
- var i = _len - 1;
- pr.i = TValue.v;
- if (i > 5) {
- var adj = 0.075 * pd.i1 + 0.54;
-
- // smooth and detrender
- sm.i = (4 * pr.i + 3 * pr.i1 + 2 * pr.i2 + pr.i3) / 10;
- dt.i = (0.0962 * sm.i + 0.5769 * sm.i2 - 0.5769 * sm.i4 - 0.0962 * sm.i6) * adj;
-
- // in-phase and quadrature
- q1.i = (0.0962 * dt.i + 0.5769 * dt.i2 - 0.5769 * dt.i4 - 0.0962 * dt.i6) * adj;
- i1.i = dt.i3;
-
- // advance the phases by 90 degrees
- double jI = (0.0962 * i1.i + 0.5769 * i1.i2 - 0.5769 * i1.i4 - 0.0962 * i1.i6) * adj;
- double jQ = (0.0962 * q1.i + 0.5769 * q1.i2 - 0.5769 * q1.i4 - 0.0962 * q1.i6) * adj;
-
- // phasor addition for 3-bar averaging
- i2.i = i1.i - jQ;
- q2.i = q1.i + jI;
-
- i2.i = 0.2 * i2.i + 0.8 * i2.i1; // smoothing it
- q2.i = 0.2 * q2.i + 0.8 * q2.i1;
-
- // homodyne discriminator
- re.i = i2.i * i2.i1 + q2.i * q2.i1;
- im.i = i2.i * q2.i1 - q2.i * i2.i1;
-
- re.i = 0.2 * re.i + 0.8 * re.i1; // smoothing it
- im.i = 0.2 * im.i + 0.8 * im.i1;
-
- // calculate period
- pd.i = im.i != 0 && re.i != 0 ? 6.283185307179586 / Math.Atan(im.i / re.i) : 0d;
-
- // adjust period to thresholds
- pd.i = pd.i > 1.5 * pd.i1 ? 1.5 * pd.i1 : pd.i;
- pd.i = pd.i < 0.67 * pd.i1 ? 0.67 * pd.i1 : pd.i;
- pd.i = pd.i < 6d ? 6d : pd.i;
- pd.i = pd.i > 50d ? 50d : pd.i;
-
- // smooth the period
- pd.i = 0.2 * pd.i + 0.8 * pd.i1;
-
- // determine phase position
- ph.i = i1.i != 0 ? Math.Atan(q1.i / i1.i) * 57.29577951308232 : 0;
-
- // change in phase
- var delta = Math.Max(ph.i1 - ph.i, 1d);
-
- // adaptive alpha value
- var alpha = Math.Max(fastl / delta, slowl);
-
- // final indicators
- mama.i = alpha * (pr.i - mama.i1) + mama.i1;
- fama.i = 0.5d * alpha * (mama.i - fama.i1) + fama.i1;
- }
- else {
- sumPr += pr.i;
- pd.i = sm.i = dt.i = i1.i = q1.i = i2.i = q2.i = re.i = im.i = ph.i = 0;
- mama.i = fama.i = sumPr / (i + 1);
-
- if (_len == 1) {
- mamaseed = famaseed = TValue.v;
- }
- else {
- mamaseed = fastl * (TValue.v - mamaseed) + mamaseed;
- famaseed = slowl * (TValue.v - famaseed) + famaseed;
- }
- }
-
- double _fama = (i > 5) ? fama.i : famaseed;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _fama);
- Fama.Add(res, update);
- double _mama = (i > 5) ? mama.i : mamaseed;
- res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mama);
- return base.Add(res, update);
- }
-
- //variation of Add()
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _len = 0;
- }
+namespace QuanTAlib;
+
+using System;
+using System.Linq;
+
+/*
+MAMA: MESA Adaptive Moving Average
+ Created by John Ehlers, the MAMA indicator is a 5-period adaptive moving average of
+ high/low price that uses classic electrical radio-frequency signal processing algorithms
+ to reduce noise.
+
+ KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 )
+
+Sources:
+ https://mesasoftware.com/papers/MAMA.pdf
+ https://www.tradingview.com/script/foQxLbU3-Ehlers-MESA-Adaptive-Moving-Average-LazyBear/
+
+ */
+
+public class MAMA_Series : TSeries
+{
+ private int _len;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ private double sumPr;
+ private double fastl, slowl;
+ private (double i, double i1, double i2, double i3, double i4, double i5, double i6, double io) pr, i1, q1, sm, dt;
+ private (double i, double i1, double io) i2, q2, re, im, pd, ph, mama, fama;
+ public TSeries Fama { get; }
+ private double mamaseed, famaseed;
+
+ //core constructors
+
+ public MAMA_Series(double fastlimit, double slowlimit, bool useNaN)
+ {
+ _period = (int)(2 / fastlimit) - 1;
+ fastl = fastlimit;
+ slowl = slowlimit;
+ Fama = new TSeries();
+ _NaN = useNaN;
+ Name = $"MAMA({_period})";
+ _len = 0;
+ }
+ public MAMA_Series(TSeries source, double fastlimit, double slowlimit, bool useNaN = false) : this(fastlimit, slowlimit, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MAMA_Series() : this(period: 0, useNaN: false) { }
+ public MAMA_Series(int period) : this(period, useNaN: false) { }
+ public MAMA_Series(int period, bool useNaN) : this(fastlimit: 2 / (period + 1), slowlimit: 0.2 / (period + 1), useNaN)
+ {
+ _period = period;
+ }
+ public MAMA_Series(TBars source) : this(source.Close, period: 0, useNaN: false) { }
+ public MAMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public MAMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public MAMA_Series(TSeries source, int period) : this(source, period, false) { }
+ public MAMA_Series(TSeries source, int period, bool useNaN) : this(source, fastlimit: 2 / ((double)period + 1), slowlimit: 0.2 / ((double)period + 1), useNaN: useNaN) { }
+
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+ if (!update)
+ {
+ // roll forward (oldx = x)
+ pr.io = pr.i6; pr.i6 = pr.i5; pr.i5 = pr.i4; pr.i4 = pr.i3; pr.i3 = pr.i2; pr.i2 = pr.i1; pr.i1 = pr.i;
+ i1.io = i1.i6; i1.i6 = i1.i5; i1.i5 = i1.i4; i1.i4 = i1.i3; i1.i3 = i1.i2; i1.i2 = i1.i1; i1.i1 = i1.i;
+ q1.io = q1.i6; q1.i6 = q1.i5; q1.i5 = q1.i4; q1.i4 = q1.i3; q1.i3 = q1.i2; q1.i2 = q1.i1; q1.i1 = q1.i;
+ dt.io = dt.i6; dt.i6 = dt.i5; dt.i5 = dt.i4; dt.i4 = dt.i3; dt.i3 = dt.i2; dt.i2 = dt.i1; dt.i1 = dt.i;
+ sm.io = sm.i6; sm.i6 = sm.i5; sm.i5 = sm.i4; sm.i4 = sm.i3; sm.i3 = sm.i2; sm.i2 = sm.i1; sm.i1 = sm.i;
+ i2.io = i2.i1; i2.i1 = i2.i; q2.io = q2.i1; q2.i1 = q2.i;
+ re.io = re.i1; re.i1 = re.i; im.io = im.i1; im.i1 = im.i;
+ pd.io = pd.i1; pd.i1 = pd.i; ph.io = ph.i1; ph.i1 = ph.i;
+ mama.io = mama.i1; mama.i1 = mama.i;
+ fama.io = fama.i1;
+ fama.i1 = fama.i;
+ _len++;
+ }
+ if (_period == 0)
+ {
+ fastl = 2 / (double)_len;
+ slowl = fastl * 0.1;
+ }
+ if (_period == 1)
+ {
+ fastl = 1;
+ slowl = 1;
+ }
+ var i = _len - 1;
+ pr.i = TValue.v;
+ if (i > 5)
+ {
+ var adj = 0.075 * pd.i1 + 0.54;
+
+ // smooth and detrender
+ sm.i = (4 * pr.i + 3 * pr.i1 + 2 * pr.i2 + pr.i3) / 10;
+ dt.i = (0.0962 * sm.i + 0.5769 * sm.i2 - 0.5769 * sm.i4 - 0.0962 * sm.i6) * adj;
+
+ // in-phase and quadrature
+ q1.i = (0.0962 * dt.i + 0.5769 * dt.i2 - 0.5769 * dt.i4 - 0.0962 * dt.i6) * adj;
+ i1.i = dt.i3;
+
+ // advance the phases by 90 degrees
+ double jI = (0.0962 * i1.i + 0.5769 * i1.i2 - 0.5769 * i1.i4 - 0.0962 * i1.i6) * adj;
+ double jQ = (0.0962 * q1.i + 0.5769 * q1.i2 - 0.5769 * q1.i4 - 0.0962 * q1.i6) * adj;
+
+ // phasor addition for 3-bar averaging
+ i2.i = i1.i - jQ;
+ q2.i = q1.i + jI;
+
+ i2.i = 0.2 * i2.i + 0.8 * i2.i1; // smoothing it
+ q2.i = 0.2 * q2.i + 0.8 * q2.i1;
+
+ // homodyne discriminator
+ re.i = i2.i * i2.i1 + q2.i * q2.i1;
+ im.i = i2.i * q2.i1 - q2.i * i2.i1;
+
+ re.i = 0.2 * re.i + 0.8 * re.i1; // smoothing it
+ im.i = 0.2 * im.i + 0.8 * im.i1;
+
+ // calculate period
+ pd.i = im.i != 0 && re.i != 0 ? 6.283185307179586 / Math.Atan(im.i / re.i) : 0d;
+
+ // adjust period to thresholds
+ pd.i = pd.i > 1.5 * pd.i1 ? 1.5 * pd.i1 : pd.i;
+ pd.i = pd.i < 0.67 * pd.i1 ? 0.67 * pd.i1 : pd.i;
+ pd.i = pd.i < 6d ? 6d : pd.i;
+ pd.i = pd.i > 50d ? 50d : pd.i;
+
+ // smooth the period
+ pd.i = 0.2 * pd.i + 0.8 * pd.i1;
+
+ // determine phase position
+ ph.i = i1.i != 0 ? Math.Atan(q1.i / i1.i) * 57.29577951308232 : 0;
+
+ // change in phase
+ var delta = Math.Max(ph.i1 - ph.i, 1d);
+
+ // adaptive alpha value
+ var alpha = Math.Max(fastl / delta, slowl);
+
+ // final indicators
+ mama.i = alpha * (pr.i - mama.i1) + mama.i1;
+ fama.i = 0.5d * alpha * (mama.i - fama.i1) + fama.i1;
+ }
+ else
+ {
+ sumPr += pr.i;
+ pd.i = sm.i = dt.i = i1.i = q1.i = i2.i = q2.i = re.i = im.i = ph.i = 0;
+ mama.i = fama.i = sumPr / (i + 1);
+
+ if (_len == 1)
+ {
+ mamaseed = famaseed = TValue.v;
+ }
+ else
+ {
+ mamaseed = fastl * (TValue.v - mamaseed) + mamaseed;
+ famaseed = slowl * (TValue.v - famaseed) + famaseed;
+ }
+ }
+
+ double _fama = (i > 5) ? fama.i : famaseed;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _fama);
+ Fama.Add(res, update);
+ double _mama = (i > 5) ? mama.i : mamaseed;
+ res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mama);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _len = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/MAPE_Series.cs b/Calculations/_Updated/MAPE_Series.cs
index 43a6a9c6..b2869c63 100644
--- a/Calculations/_Updated/MAPE_Series.cs
+++ b/Calculations/_Updated/MAPE_Series.cs
@@ -1,85 +1,95 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-MAPE: Mean Absolute Percentage Error
- Measures the size of the error in percentage terms
-
-Calculation:
- MAPE = Σ(|close – SMA| / |close|) / n
-
-Sources:
- https://en.wikipedia.org/wiki/Mean_absolute_percentage_error
-
-Remark:
- returns infinity if any of observations is 0.
- Use SMAPE or WMAPE instead to avoid division-by-zero in MAPE
-
- */
-
-public class MAPE_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public MAPE_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"MAPE({period})";
- }
- public MAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public MAPE_Series() : this(period: 0, useNaN: false) { }
- public MAPE_Series(int period) : this(period: period, useNaN: false) { }
- public MAPE_Series(TBars source) : this(source.Close, 0, false) { }
- public MAPE_Series(TBars source, int period) : this(source.Close, period, false) { }
- public MAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public MAPE_Series(TSeries source) : this(source, 0, false) { }
- public MAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _sma = _buffer.Average();
-
- double _mape = 0;
- for (int i = 0; i < _buffer.Count; i++) {
- _mape += (_buffer[i] != 0) ? Math.Abs(_buffer[i] - _sma) / Math.Abs(_buffer[i]) : double.PositiveInfinity;
- }
- _mape /= (_buffer.Count > 0) ? _buffer.Count : 1;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mape);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+MAPE: Mean Absolute Percentage Error
+ Measures the size of the error in percentage terms
+
+Calculation:
+ MAPE = Σ(|close – SMA| / |close|) / n
+
+Sources:
+ https://en.wikipedia.org/wiki/Mean_absolute_percentage_error
+
+Remark:
+ returns infinity if any of observations is 0.
+ Use SMAPE or WMAPE instead to avoid division-by-zero in MAPE
+
+ */
+
+public class MAPE_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public MAPE_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"MAPE({period})";
+ }
+ public MAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MAPE_Series() : this(period: 0, useNaN: false) { }
+ public MAPE_Series(int period) : this(period: period, useNaN: false) { }
+ public MAPE_Series(TBars source) : this(source.Close, 0, false) { }
+ public MAPE_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public MAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public MAPE_Series(TSeries source) : this(source, 0, false) { }
+ public MAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _sma = _buffer.Average();
+
+ double _mape = 0;
+ for (int i = 0; i < _buffer.Count; i++)
+ {
+ _mape += (_buffer[i] != 0) ? Math.Abs(_buffer[i] - _sma) / Math.Abs(_buffer[i]) : double.PositiveInfinity;
+ }
+ _mape /= (_buffer.Count > 0) ? _buffer.Count : 1;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mape);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/MAX_Series.cs b/Calculations/_Updated/MAX_Series.cs
index f199a329..4c96e41e 100644
--- a/Calculations/_Updated/MAX_Series.cs
+++ b/Calculations/_Updated/MAX_Series.cs
@@ -1,68 +1,77 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-MAX - Maximum value in the given period in the series.
- If period = 0 => period = full length of the series
-
- */
-
-public class MAX_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public MAX_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"MAX({period})";
- }
- public MAX_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public MAX_Series() : this(period: 0, useNaN: false) { }
- public MAX_Series(int period) : this(period: period, useNaN: false) { }
- public MAX_Series(TBars source) : this(source.Close, 0, false) { }
- public MAX_Series(TBars source, int period) : this(source.Close, period, false) { }
- public MAX_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public MAX_Series(TSeries source) : this(source, 0, false) { }
- public MAX_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _max= _buffer.Max();
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _max);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+MAX - Maximum value in the given period in the series.
+ If period = 0 => period = full length of the series
+
+ */
+
+public class MAX_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public MAX_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"MAX({period})";
+ }
+ public MAX_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MAX_Series() : this(period: 0, useNaN: false) { }
+ public MAX_Series(int period) : this(period: period, useNaN: false) { }
+ public MAX_Series(TBars source) : this(source.Close, 0, false) { }
+ public MAX_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public MAX_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public MAX_Series(TSeries source) : this(source, 0, false) { }
+ public MAX_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _max = _buffer.Max();
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _max);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/MEDIAN_Series.cs b/Calculations/_Updated/MEDIAN_Series.cs
index 0df36399..e896d1ce 100644
--- a/Calculations/_Updated/MEDIAN_Series.cs
+++ b/Calculations/_Updated/MEDIAN_Series.cs
@@ -1,86 +1,95 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-MED - Median value
- Median of numbers is the middlemost value of the given set of numbers.
- It separates the higher half and the lower half of a given data sample.
- At least half of the observations are smaller than or equal to median
- and at least half of the observations are greater than or equal to the median.
-
- If the number of values is odd, the middlemost observation of the sorted
- list is the median of the given data. If the number of values is even,
- median is the average of (n/2)th and [(n/2) + 1]th values of the sorted list.
-
- If period = 0 => period is max
-
-Sources:
- https://corporatefinanceinstitute.com/resources/knowledge/other/median/
- https://en.wikipedia.org/wiki/Median
-
- */
-
-public class MEDIAN_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public MEDIAN_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"MEDIAN({period})";
- }
- public MEDIAN_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public MEDIAN_Series() : this(period: 0, useNaN: false) { }
- public MEDIAN_Series(int period) : this(period: period, useNaN: false) { }
- public MEDIAN_Series(TBars source) : this(source.Close, 0, false) { }
- public MEDIAN_Series(TBars source, int period) : this(source.Close, period, false) { }
- public MEDIAN_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public MEDIAN_Series(TSeries source) : this(source, 0, false) { }
- public MEDIAN_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- System.Collections.Generic.List _s = new(this._buffer);
- _s.Sort();
- int _p1 = _s.Count / 2;
- int _p2 = Math.Max(0, (_s.Count / 2) - 1);
- double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _med);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+MED - Median value
+ Median of numbers is the middlemost value of the given set of numbers.
+ It separates the higher half and the lower half of a given data sample.
+ At least half of the observations are smaller than or equal to median
+ and at least half of the observations are greater than or equal to the median.
+
+ If the number of values is odd, the middlemost observation of the sorted
+ list is the median of the given data. If the number of values is even,
+ median is the average of (n/2)th and [(n/2) + 1]th values of the sorted list.
+
+ If period = 0 => period is max
+
+Sources:
+ https://corporatefinanceinstitute.com/resources/knowledge/other/median/
+ https://en.wikipedia.org/wiki/Median
+
+ */
+
+public class MEDIAN_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public MEDIAN_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"MEDIAN({period})";
+ }
+ public MEDIAN_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MEDIAN_Series() : this(period: 0, useNaN: false) { }
+ public MEDIAN_Series(int period) : this(period: period, useNaN: false) { }
+ public MEDIAN_Series(TBars source) : this(source.Close, 0, false) { }
+ public MEDIAN_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public MEDIAN_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public MEDIAN_Series(TSeries source) : this(source, 0, false) { }
+ public MEDIAN_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ System.Collections.Generic.List _s = new(this._buffer);
+ _s.Sort();
+ int _p1 = _s.Count / 2;
+ int _p2 = Math.Max(0, (_s.Count / 2) - 1);
+ double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _med);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/MIDPOINT_Series.cs b/Calculations/_Updated/MIDPOINT_Series.cs
index 46bdd221..ca27243a 100644
--- a/Calculations/_Updated/MIDPOINT_Series.cs
+++ b/Calculations/_Updated/MIDPOINT_Series.cs
@@ -1,72 +1,81 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-MIDPOINT: Midpoint value (max+min)/2 in the given period in the series.
- If period = 0 => period = full length of the series
-
-Sources:
- https://thefaqblog.com/what-is-the-midpoint-in-statistics/
-
- */
-
-public class MIDPOINT_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public MIDPOINT_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"MIDPOINT({period})";
- }
- public MIDPOINT_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public MIDPOINT_Series() : this(period: 0, useNaN: false) { }
- public MIDPOINT_Series(int period) : this(period: period, useNaN: false) { }
- public MIDPOINT_Series(TBars source) : this(source.Close, 0, false) { }
- public MIDPOINT_Series(TBars source, int period) : this(source.Close, period, false) { }
- public MIDPOINT_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public MIDPOINT_Series(TSeries source) : this(source, 0, false) { }
- public MIDPOINT_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _max= _buffer.Max();
- double _min = _buffer.Min();
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : (_max+_min)*0.5);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+MIDPOINT: Midpoint value (max+min)/2 in the given period in the series.
+ If period = 0 => period = full length of the series
+
+Sources:
+ https://thefaqblog.com/what-is-the-midpoint-in-statistics/
+
+ */
+
+public class MIDPOINT_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public MIDPOINT_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"MIDPOINT({period})";
+ }
+ public MIDPOINT_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MIDPOINT_Series() : this(period: 0, useNaN: false) { }
+ public MIDPOINT_Series(int period) : this(period: period, useNaN: false) { }
+ public MIDPOINT_Series(TBars source) : this(source.Close, 0, false) { }
+ public MIDPOINT_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public MIDPOINT_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public MIDPOINT_Series(TSeries source) : this(source, 0, false) { }
+ public MIDPOINT_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _max = _buffer.Max();
+ double _min = _buffer.Min();
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : (_max + _min) * 0.5);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/MIDPRICE_Series.cs b/Calculations/_Updated/MIDPRICE_Series.cs
index 1bb914a8..099f90c8 100644
--- a/Calculations/_Updated/MIDPRICE_Series.cs
+++ b/Calculations/_Updated/MIDPRICE_Series.cs
@@ -1,65 +1,74 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-MIDPRICE: Midpoint price (highhest high + lowest low)/2 in the given period in the series.
- If period = 0 => period = full length of the series
-
- */
-
-public class MIDPRICE_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TBars _data;
- private readonly System.Collections.Generic.List _bufferhi = new();
- private readonly System.Collections.Generic.List _bufferlo = new();
-
- //core constructors
- public MIDPRICE_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"MIDPRICE({period})";
- }
- public MIDPRICE_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(data: _data);
- }
- public MIDPRICE_Series() : this(period: 2, useNaN: false) { }
- public MIDPRICE_Series(int period) : this(period: period, useNaN: false) { }
- public MIDPRICE_Series(TBars source) : this(source, period: 2, useNaN: false) { }
- public MIDPRICE_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
- BufferTrim(_bufferhi, TBar.h, _period, update);
- BufferTrim(_bufferlo, TBar.l, _period, update);
- double _mid = (_bufferhi.Max() + _bufferlo.Min()) * 0.5;
-
- var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _mid);
- return base.Add(res, update);
- }
-
- public new void Add(TBars data) {
- foreach (var item in data) { Add(item, false); }
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TBar: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TBar: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TBar: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _bufferhi.Clear();
- _bufferlo.Clear();
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+MIDPRICE: Midpoint price (highhest high + lowest low)/2 in the given period in the series.
+ If period = 0 => period = full length of the series
+
+ */
+
+public class MIDPRICE_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TBars _data;
+ private readonly System.Collections.Generic.List _bufferhi = new();
+ private readonly System.Collections.Generic.List _bufferlo = new();
+
+ //core constructors
+ public MIDPRICE_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"MIDPRICE({period})";
+ }
+ public MIDPRICE_Series(TBars source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+ public MIDPRICE_Series() : this(period: 2, useNaN: false) { }
+ public MIDPRICE_Series(int period) : this(period: period, useNaN: false) { }
+ public MIDPRICE_Series(TBars source) : this(source, period: 2, useNaN: false) { }
+ public MIDPRICE_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
+ {
+ BufferTrim(_bufferhi, TBar.h, _period, update);
+ BufferTrim(_bufferlo, TBar.l, _period, update);
+ double _mid = (_bufferhi.Max() + _bufferlo.Min()) * 0.5;
+
+ var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _mid);
+ return base.Add(res, update);
+ }
+
+ public new void Add(TBars data)
+ {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _bufferhi.Clear();
+ _bufferlo.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/MIN_Series.cs b/Calculations/_Updated/MIN_Series.cs
index 3f30ffbe..4bb44ca9 100644
--- a/Calculations/_Updated/MIN_Series.cs
+++ b/Calculations/_Updated/MIN_Series.cs
@@ -1,68 +1,77 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-MIN - Minimum value in the given period in the series.
- If period = 0 => period = full length of the series
-
- */
-
-public class MIN_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public MIN_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"MAX({period})";
- }
- public MIN_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public MIN_Series() : this(period: 0, useNaN: false) { }
- public MIN_Series(int period) : this(period: period, useNaN: false) { }
- public MIN_Series(TBars source) : this(source.Close, 0, false) { }
- public MIN_Series(TBars source, int period) : this(source.Close, period, false) { }
- public MIN_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public MIN_Series(TSeries source) : this(source, 0, false) { }
- public MIN_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _max= _buffer.Min();
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _max);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+MIN - Minimum value in the given period in the series.
+ If period = 0 => period = full length of the series
+
+ */
+
+public class MIN_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public MIN_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"MAX({period})";
+ }
+ public MIN_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MIN_Series() : this(period: 0, useNaN: false) { }
+ public MIN_Series(int period) : this(period: period, useNaN: false) { }
+ public MIN_Series(TBars source) : this(source.Close, 0, false) { }
+ public MIN_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public MIN_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public MIN_Series(TSeries source) : this(source, 0, false) { }
+ public MIN_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _max = _buffer.Min();
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _max);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/MSE_Series.cs b/Calculations/_Updated/MSE_Series.cs
index 262cbd6a..7be1a30a 100644
--- a/Calculations/_Updated/MSE_Series.cs
+++ b/Calculations/_Updated/MSE_Series.cs
@@ -1,76 +1,85 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-MSE: Mean Square Error
- Defined as a Mean (Average) of the Square of the difference between actual and estimated values.
-
-Sources:
- https://en.wikipedia.org/wiki/Mean_squared_error
-
- */
-
-public class MSE_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public MSE_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"MSE({period})";
- }
- public MSE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public MSE_Series() : this(period: 0, useNaN: false) { }
- public MSE_Series(int period) : this(period: period, useNaN: false) { }
- public MSE_Series(TBars source) : this(source.Close, 0, false) { }
- public MSE_Series(TBars source, int period) : this(source.Close, period, false) { }
- public MSE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public MSE_Series(TSeries source) : this(source, 0, false) { }
- public MSE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _sma = _buffer.Average();
-
- double _mse = 0;
- for (int i = 0; i < _buffer.Count; i++) { _mse += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
- _mse /= this._buffer.Count;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mse);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+MSE: Mean Square Error
+ Defined as a Mean (Average) of the Square of the difference between actual and estimated values.
+
+Sources:
+ https://en.wikipedia.org/wiki/Mean_squared_error
+
+ */
+
+public class MSE_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public MSE_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"MSE({period})";
+ }
+ public MSE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MSE_Series() : this(period: 0, useNaN: false) { }
+ public MSE_Series(int period) : this(period: period, useNaN: false) { }
+ public MSE_Series(TBars source) : this(source.Close, 0, false) { }
+ public MSE_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public MSE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public MSE_Series(TSeries source) : this(source, 0, false) { }
+ public MSE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _sma = _buffer.Average();
+
+ double _mse = 0;
+ for (int i = 0; i < _buffer.Count; i++) { _mse += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
+ _mse /= this._buffer.Count;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mse);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/OBV_Series.cs b/Calculations/_Updated/OBV_Series.cs
index 57531bdd..f589cc3b 100644
--- a/Calculations/_Updated/OBV_Series.cs
+++ b/Calculations/_Updated/OBV_Series.cs
@@ -1,96 +1,106 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-OBV: On-Balance Volume
- On-balance volume (OBV) is a technical trading momentum indicator that uses volume flow to predict
- changes in stock price. Joseph Granville first developed the OBV metric in the 1963 book
- Granville's New Key to Stock Market Profits.
-
- | +volume; if close > close[previous]
- OBV = OBV[previous] + | 0; if close = close[previous]
- | -volume; if close < close[previous]
-
-Sources:
- https://www.investopedia.com/terms/o/onbalancevolume.asp
- https://www.tradingview.com/wiki/On_Balance_Volume_(OBV)
- https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/on-balance-volume-obv/
- https://www.motivewave.com/studies/on_balance_volume.htm
-
-Note:
- There is no consensus on what is the first OBV value in the series:
- - TA-LIB uses the first volume: OBV[0] = volume[0]
- - Skender stock library uses 0: OBV[0] = 0
-
- */
-
-public class OBV_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TBars _data;
- private double _lastobv, _lastlastobv;
- private double _lastclose, _lastlastclose;
-
- //core constructors
- public OBV_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"OBV({period})";
- this._lastobv = this._lastlastobv = 0;
- this._lastclose = this._lastlastclose = 0;
- }
- public OBV_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(data: _data);
- }
- public OBV_Series() : this(period: 2, useNaN: false) { }
- public OBV_Series(int period) : this(period: period, useNaN: false) { }
- public OBV_Series(TBars source) : this(source, period: 2, useNaN: false) { }
- public OBV_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
-
- if (update) {
- this._lastobv = this._lastlastobv;
- this._lastclose = this._lastlastclose;
- }
-
- double _obv = this._lastobv;
- if (TBar.c > this._lastclose) { _obv += TBar.v; }
- if (TBar.c < this._lastclose) { _obv -= TBar.v; }
-
- this._lastlastobv = this._lastobv;
- this._lastobv = _obv;
-
- this._lastlastclose = this._lastclose;
- this._lastclose = TBar.c;
-
- var res = (TBar.t, (this.Count < this._period && this._NaN) ? double.NaN : _obv);
- return base.Add(res, update);
- }
-
- public new void Add(TBars data) {
- foreach (var item in data) { Add(item, false); }
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TBar: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TBar: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TBar: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- this._lastobv = this._lastlastobv = 0;
- this._lastclose = this._lastlastclose = 0;
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+OBV: On-Balance Volume
+ On-balance volume (OBV) is a technical trading momentum indicator that uses volume flow to predict
+ changes in stock price. Joseph Granville first developed the OBV metric in the 1963 book
+ Granville's New Key to Stock Market Profits.
+
+ | +volume; if close > close[previous]
+ OBV = OBV[previous] + | 0; if close = close[previous]
+ | -volume; if close < close[previous]
+
+Sources:
+ https://www.investopedia.com/terms/o/onbalancevolume.asp
+ https://www.tradingview.com/wiki/On_Balance_Volume_(OBV)
+ https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/on-balance-volume-obv/
+ https://www.motivewave.com/studies/on_balance_volume.htm
+
+Note:
+ There is no consensus on what is the first OBV value in the series:
+ - TA-LIB uses the first volume: OBV[0] = volume[0]
+ - Skender stock library uses 0: OBV[0] = 0
+
+ */
+
+public class OBV_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TBars _data;
+ private double _lastobv, _lastlastobv;
+ private double _lastclose, _lastlastclose;
+
+ //core constructors
+ public OBV_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"OBV({period})";
+ this._lastobv = this._lastlastobv = 0;
+ this._lastclose = this._lastlastclose = 0;
+ }
+ public OBV_Series(TBars source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+ public OBV_Series() : this(period: 2, useNaN: false) { }
+ public OBV_Series(int period) : this(period: period, useNaN: false) { }
+ public OBV_Series(TBars source) : this(source, period: 2, useNaN: false) { }
+ public OBV_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
+ {
+
+ if (update)
+ {
+ this._lastobv = this._lastlastobv;
+ this._lastclose = this._lastlastclose;
+ }
+
+ double _obv = this._lastobv;
+ if (TBar.c > this._lastclose) { _obv += TBar.v; }
+ if (TBar.c < this._lastclose) { _obv -= TBar.v; }
+
+ this._lastlastobv = this._lastobv;
+ this._lastobv = _obv;
+
+ this._lastlastclose = this._lastclose;
+ this._lastclose = TBar.c;
+
+ var res = (TBar.t, (this.Count < this._period && this._NaN) ? double.NaN : _obv);
+ return base.Add(res, update);
+ }
+
+ public new void Add(TBars data)
+ {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ this._lastobv = this._lastlastobv = 0;
+ this._lastclose = this._lastlastclose = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/RMA_Series.cs b/Calculations/_Updated/RMA_Series.cs
index bd84105f..217c895d 100644
--- a/Calculations/_Updated/RMA_Series.cs
+++ b/Calculations/_Updated/RMA_Series.cs
@@ -1,116 +1,133 @@
-namespace QuanTAlib;
-
-using System;
-using System.Linq;
-
-/*
-RMA: wildeR Moving Average
- J. Welles Wilder introduced RMA as an alternative to EMA. RMA's weight (k) is
- set as 1/period, giving less weight to the new data compared to EMA.
-
-Sources:
- https://archive.org/details/newconceptsintec00wild/page/23/mode/2up
- https://tlc.thinkorswim.com/center/reference/Tech-Indicators/studies-library/V-Z/WildersSmoothing
- https://www.incrediblecharts.com/indicators/wilder_moving_average.php
-
-Issues:
- Pandas-TA library calculates RMA using straight Exponential Weighted Mean:
- pandas.ewm().mean() and returns incorrect first (period) of bars compared to
- published formula. This implementation passess the validation test in Wilder's book.
-
- */
-
-public class RMA_Series : TSeries {
- private double _k;
- private double _lastrma, _oldrma;
- private double _sum, _oldsum;
- private readonly bool _useSMA;
- private int _len;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
-//core constructor
- public RMA_Series(int period, bool useNaN, bool useSMA) {
- _period = period;
- _NaN = useNaN;
- _useSMA = useSMA;
- Name = $"RMA({period})";
- _k = 1.0 / (double)(this._period);
- _len = 0;
- _sum = _oldsum = _lastrma = _oldrma = 0;
- }
- //generic constructors (source)
-
- public RMA_Series() : this(0, false, true) {}
- public RMA_Series(int period) : this(period, false, true) {}
- public RMA_Series(TBars source) : this(source.Close, 0, false) {}
- public RMA_Series(TBars source, int period) : this(source.Close, period, false) {}
- public RMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
- public RMA_Series(TSeries source, int period) : this(source, period, false, true) {}
- public RMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {}
- public RMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
-
-// core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (update) {
- _lastrma = _oldrma;
- _sum = _oldsum;
- }
- else {
- _oldrma = _lastrma;
- _oldsum = _sum;
- _len++;
- }
-
- double _rma = 0;
- if (_period == 0) {
- _k = 1.0 / (double)(this._len);
- }
-
- if (Count == 0) {
- _rma = _sum = TValue.v;
-
- } else if (_len <= _period && _useSMA && _period != 0) {
- _sum += TValue.v;
- if (_period != 0 && _len > _period) {
- _sum -= _data[Count - _period - (update ? 1 : 0)].v;
- }
- _rma = _sum / Math.Min(_len, _period);
- }
- else {
- _rma = _k * (TValue.v - _lastrma) + _lastrma;
- }
-
- _lastrma = double.IsNaN(_rma) ? _lastrma : _rma;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _rma);
- return base.Add(res, update);
- }
-
-//variation of Add()
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _sum = _oldsum = _lastrma = _oldrma = 0;
- _len = 0;
- }
+namespace QuanTAlib;
+
+using System;
+using System.Linq;
+
+/*
+RMA: wildeR Moving Average
+ J. Welles Wilder introduced RMA as an alternative to EMA. RMA's weight (k) is
+ set as 1/period, giving less weight to the new data compared to EMA.
+
+Sources:
+ https://archive.org/details/newconceptsintec00wild/page/23/mode/2up
+ https://tlc.thinkorswim.com/center/reference/Tech-Indicators/studies-library/V-Z/WildersSmoothing
+ https://www.incrediblecharts.com/indicators/wilder_moving_average.php
+
+Issues:
+ Pandas-TA library calculates RMA using straight Exponential Weighted Mean:
+ pandas.ewm().mean() and returns incorrect first (period) of bars compared to
+ published formula. This implementation passess the validation test in Wilder's book.
+
+ */
+
+public class RMA_Series : TSeries
+{
+ private double _k;
+ private double _lastrma, _oldrma;
+ private double _sum, _oldsum;
+ private readonly bool _useSMA;
+ private int _len;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructor
+ public RMA_Series(int period, bool useNaN, bool useSMA)
+ {
+ _period = period;
+ _NaN = useNaN;
+ _useSMA = useSMA;
+ Name = $"RMA({period})";
+ _k = 1.0 / (double)(this._period);
+ _len = 0;
+ _sum = _oldsum = _lastrma = _oldrma = 0;
+ }
+ //generic constructors (source)
+
+ public RMA_Series() : this(0, false, true) { }
+ public RMA_Series(int period) : this(period, false, true) { }
+ public RMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public RMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public RMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public RMA_Series(TSeries source, int period) : this(source, period, false, true) { }
+ public RMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
+ public RMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (update)
+ {
+ _lastrma = _oldrma;
+ _sum = _oldsum;
+ }
+ else
+ {
+ _oldrma = _lastrma;
+ _oldsum = _sum;
+ _len++;
+ }
+
+ double _rma = 0;
+ if (_period == 0)
+ {
+ _k = 1.0 / (double)(this._len);
+ }
+
+ if (Count == 0)
+ {
+ _rma = _sum = TValue.v;
+
+ }
+ else if (_len <= _period && _useSMA && _period != 0)
+ {
+ _sum += TValue.v;
+ if (_period != 0 && _len > _period)
+ {
+ _sum -= _data[Count - _period - (update ? 1 : 0)].v;
+ }
+ _rma = _sum / Math.Min(_len, _period);
+ }
+ else
+ {
+ _rma = _k * (TValue.v - _lastrma) + _lastrma;
+ }
+
+ _lastrma = double.IsNaN(_rma) ? _lastrma : _rma;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _rma);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _sum = _oldsum = _lastrma = _oldrma = 0;
+ _len = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/RSI_Series.cs b/Calculations/_Updated/RSI_Series.cs
index 7acb6daa..ee9c883b 100644
--- a/Calculations/_Updated/RSI_Series.cs
+++ b/Calculations/_Updated/RSI_Series.cs
@@ -1,120 +1,134 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-RSI: Relative Strength Index
- Created by J. Welles Wilder, the Relative Strength Index measures strength
- of the winning/losing streak over N lookback periods on a scale of 0 to 100,
- to depict overbought and oversold conditions.
-
-Sources:
- https://www.investopedia.com/terms/r/rsi.asp
-
- */
-
-public class RSI_Series : TSeries {
- private readonly System.Collections.Generic.List _gain = new();
- private readonly System.Collections.Generic.List _loss = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private double _avgGain, _avgLoss, _lastValue;
- private double _avgGain_o, _avgLoss_o, _lastValue_o;
- private int i;
-
- //core constructors
- public RSI_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"RSI({period})";
- i = 0;
- }
- public RSI_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public RSI_Series() : this(period: 0, useNaN: false) { }
- public RSI_Series(int period) : this(period: period, useNaN: false) { }
- public RSI_Series(TBars source) : this(source.Close, 0, false) { }
- public RSI_Series(TBars source, int period) : this(source.Close, period, false) { }
- public RSI_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public RSI_Series(TSeries source) : this(source, 0, false) { }
- public RSI_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
-
- double _rsi = 0;
- if (update) {
- _lastValue = _lastValue_o;
- _avgGain = _avgGain_o;
- _avgLoss = _avgLoss_o;
- }
- else {
- _lastValue_o = _lastValue;
- _avgGain_o = _avgGain;
- _avgLoss_o = _avgLoss;
- }
-
- if (i == 0) { _lastValue = TValue.v; }
-
- double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0;
- BufferTrim(_gain, _gainval, _period, update);
- double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0;
- BufferTrim(_loss, _lossval, _period, update);
- _lastValue = TValue.v;
-
- // calculate RSI
- if (i > _period && _period != 0) {
- _avgGain = ((_avgGain * (_period - 1)) + _gain[^1]) / _period;
- _avgLoss = ((_avgLoss * (_period - 1)) + _loss[^1]) / _period;
- if (_avgLoss > 0) {
- double rs = _avgGain / _avgLoss;
- _rsi = 100 - (100 / (1 + rs));
- }
- else { _rsi = 100; }
- }
- // initialize average gain
- else {
- double _sumGain = 0;
- for (int p = 0; p < _gain.Count; p++) { _sumGain += _gain[p]; }
- double _sumLoss = 0;
- for (int p = 0; p < _loss.Count; p++) { _sumLoss += _loss[p]; }
-
- _avgGain = _sumGain / _gain.Count;
- _avgLoss = _sumLoss / _loss.Count;
-
- _rsi = (_avgLoss > 0) ? 100 - (100 / (1 + (_avgGain / _avgLoss))) : 100;
- }
- if (!update) { i++; }
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _rsi);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- i = 0;
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+RSI: Relative Strength Index
+ Created by J. Welles Wilder, the Relative Strength Index measures strength
+ of the winning/losing streak over N lookback periods on a scale of 0 to 100,
+ to depict overbought and oversold conditions.
+
+Sources:
+ https://www.investopedia.com/terms/r/rsi.asp
+
+ */
+
+public class RSI_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _gain = new();
+ private readonly System.Collections.Generic.List _loss = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private double _avgGain, _avgLoss, _lastValue;
+ private double _avgGain_o, _avgLoss_o, _lastValue_o;
+ private int i;
+
+ //core constructors
+ public RSI_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"RSI({period})";
+ i = 0;
+ }
+ public RSI_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public RSI_Series() : this(period: 0, useNaN: false) { }
+ public RSI_Series(int period) : this(period: period, useNaN: false) { }
+ public RSI_Series(TBars source) : this(source.Close, 0, false) { }
+ public RSI_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public RSI_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public RSI_Series(TSeries source) : this(source, 0, false) { }
+ public RSI_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+
+ double _rsi = 0;
+ if (update)
+ {
+ _lastValue = _lastValue_o;
+ _avgGain = _avgGain_o;
+ _avgLoss = _avgLoss_o;
+ }
+ else
+ {
+ _lastValue_o = _lastValue;
+ _avgGain_o = _avgGain;
+ _avgLoss_o = _avgLoss;
+ }
+
+ if (i == 0) { _lastValue = TValue.v; }
+
+ double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0;
+ BufferTrim(_gain, _gainval, _period, update);
+ double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0;
+ BufferTrim(_loss, _lossval, _period, update);
+ _lastValue = TValue.v;
+
+ // calculate RSI
+ if (i > _period && _period != 0)
+ {
+ _avgGain = ((_avgGain * (_period - 1)) + _gain[^1]) / _period;
+ _avgLoss = ((_avgLoss * (_period - 1)) + _loss[^1]) / _period;
+ if (_avgLoss > 0)
+ {
+ double rs = _avgGain / _avgLoss;
+ _rsi = 100 - (100 / (1 + rs));
+ }
+ else { _rsi = 100; }
+ }
+ // initialize average gain
+ else
+ {
+ double _sumGain = 0;
+ for (int p = 0; p < _gain.Count; p++) { _sumGain += _gain[p]; }
+ double _sumLoss = 0;
+ for (int p = 0; p < _loss.Count; p++) { _sumLoss += _loss[p]; }
+
+ _avgGain = _sumGain / _gain.Count;
+ _avgLoss = _sumLoss / _loss.Count;
+
+ _rsi = (_avgLoss > 0) ? 100 - (100 / (1 + (_avgGain / _avgLoss))) : 100;
+ }
+ if (!update) { i++; }
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _rsi);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ i = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/SDEV_Series.cs b/Calculations/_Updated/SDEV_Series.cs
index 4b5a91be..b7b5cc1a 100644
--- a/Calculations/_Updated/SDEV_Series.cs
+++ b/Calculations/_Updated/SDEV_Series.cs
@@ -1,82 +1,91 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-SDEV: Population Standard Deviation
- Population Standard Deviation is the square root of the biased variance, also knons as
- Uncorrected Sample Standard Deviation
-
-Sources:
- https://en.wikipedia.org/wiki/Standard_deviation#Uncorrected_sample_standard_deviation
-
-Remark:
- SDEV (Population Standard Deviation) is also known as a biased/uncorrected Standard Deviation.
- For unbiased version that uses Bessel's correction, use SDEV instead.
-
- */
-
-public class SDEV_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public SDEV_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"SDEV({period})";
- }
- public SDEV_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public SDEV_Series() : this(period: 0, useNaN: false) { }
- public SDEV_Series(int period) : this(period: period, useNaN: false) { }
- public SDEV_Series(TBars source) : this(source.Close, 0, false) { }
- public SDEV_Series(TBars source, int period) : this(source.Close, period, false) { }
- public SDEV_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public SDEV_Series(TSeries source) : this(source, 0, false) { }
- public SDEV_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _sma = _buffer.Average();
-
- double _var = 0;
- for (int i = 0; i < _buffer.Count; i++) { _var += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
- _var /= this._buffer.Count;
- double _sdev = Math.Sqrt(_var);
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sdev);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+SDEV: Population Standard Deviation
+ Population Standard Deviation is the square root of the biased variance, also knons as
+ Uncorrected Sample Standard Deviation
+
+Sources:
+ https://en.wikipedia.org/wiki/Standard_deviation#Uncorrected_sample_standard_deviation
+
+Remark:
+ SDEV (Population Standard Deviation) is also known as a biased/uncorrected Standard Deviation.
+ For unbiased version that uses Bessel's correction, use SDEV instead.
+
+ */
+
+public class SDEV_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public SDEV_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"SDEV({period})";
+ }
+ public SDEV_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public SDEV_Series() : this(period: 0, useNaN: false) { }
+ public SDEV_Series(int period) : this(period: period, useNaN: false) { }
+ public SDEV_Series(TBars source) : this(source.Close, 0, false) { }
+ public SDEV_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public SDEV_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public SDEV_Series(TSeries source) : this(source, 0, false) { }
+ public SDEV_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _sma = _buffer.Average();
+
+ double _var = 0;
+ for (int i = 0; i < _buffer.Count; i++) { _var += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
+ _var /= this._buffer.Count;
+ double _sdev = Math.Sqrt(_var);
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sdev);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/SLOPE_Series.cs b/Calculations/_Updated/SLOPE_Series.cs
index c9fc3eae..8d7580c2 100644
--- a/Calculations/_Updated/SLOPE_Series.cs
+++ b/Calculations/_Updated/SLOPE_Series.cs
@@ -1,122 +1,130 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-SLOPE: Slope of linear regression (using Least Square Method)
- Linear Regression provides a slope of a straight line that is the best approximation of the given set of data.
- The method of least squares is a standard approach in linear regression analysis to approximate the solution
- by minimizing the sum of the squares of the residuals made in the results of each individual equation.
-
-Additional outputs provided by LINREG:
- .Intercept - y-intercept point of the best fit line
- .RSquared - R-Squared (R²), Coefficient of Determination
- .StdDev - Standard Deviation of data over given periods
-
- y = Slope * x + Intercept
-
-Sources:
- https://en.wikipedia.org/wiki/Least_squares
-
- */
-
-public class SLOPE_Series : TSeries {
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private readonly TSeries p_Intercept = new();
- private readonly TSeries p_RSquared = new();
- private readonly TSeries p_StdDev = new();
- private readonly System.Collections.Generic.List _buffer = new();
- public TSeries Intercept => p_Intercept;
- public TSeries RSquared => p_RSquared;
- public TSeries StdDev => p_StdDev;
- //core constructors
- public SLOPE_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"SLOPE({period})";
- }
- public SLOPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public SLOPE_Series() : this(period: 0, useNaN: false) { }
- public SLOPE_Series(int period) : this(period: period, useNaN: false) { }
- public SLOPE_Series(TBars source) : this(source.Close, 0, false) { }
- public SLOPE_Series(TBars source, int period) : this(source.Close, period, false) { }
- public SLOPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public SLOPE_Series(TSeries source) : this(source, 0, false) { }
- public SLOPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- int _len = this._buffer.Count;
-
- // get averages for period
- double sumX = 0;
- double sumY = 0;
-
- for (int p = 0; p < _len; p++) {
- sumX += this.Count - _len + 2 + p;
- sumY += _buffer[p];
- }
- double avgX = sumX / _len;
- double avgY = sumY / _len;
-
- // least squares method
- double sumSqX = 0;
- double sumSqY = 0;
- double sumSqXY = 0;
-
- for (int p = 0; p < _len; p++) {
- double devX = this.Count - _len + 2 + p - avgX;
- double devY = _buffer[p] - avgY;
-
- sumSqX += devX * devX;
- sumSqY += devY * devY;
- sumSqXY += devX * devY;
- }
-
- double _slope = sumSqXY / sumSqX;
- double _intercept = avgY - (_slope * avgX);
-
- // calculate Standard Deviation and R-Squared
- double stdDevX = Math.Sqrt(sumSqX / _len);
- double stdDevY = Math.Sqrt(sumSqY / _len);
- double _StdDev = stdDevY;
-
- double arrr = (stdDevX * stdDevY != 0) ? sumSqXY / (stdDevX * stdDevY) / _len : 0;
- double _RSquared = arrr * arrr;
-
- var ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _intercept);
- p_Intercept.Add(ret, update);
-
- ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _StdDev);
- p_StdDev.Add(ret, update);
-
- ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _RSquared);
- p_RSquared.Add(ret, update);
-
- ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _slope);
- return base.Add(ret, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+SLOPE: Slope of linear regression (using Least Square Method)
+ Linear Regression provides a slope of a straight line that is the best approximation of the given set of data.
+ The method of least squares is a standard approach in linear regression analysis to approximate the solution
+ by minimizing the sum of the squares of the residuals made in the results of each individual equation.
+
+Additional outputs provided by LINREG:
+ .Intercept - y-intercept point of the best fit line
+ .RSquared - R-Squared (R²), Coefficient of Determination
+ .StdDev - Standard Deviation of data over given periods
+
+ y = Slope * x + Intercept
+
+Sources:
+ https://en.wikipedia.org/wiki/Least_squares
+
+ */
+
+public class SLOPE_Series : TSeries
+{
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private readonly TSeries p_Intercept = new();
+ private readonly TSeries p_RSquared = new();
+ private readonly TSeries p_StdDev = new();
+ private readonly System.Collections.Generic.List _buffer = new();
+ public TSeries Intercept => p_Intercept;
+ public TSeries RSquared => p_RSquared;
+ public TSeries StdDev => p_StdDev;
+ //core constructors
+ public SLOPE_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"SLOPE({period})";
+ }
+ public SLOPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public SLOPE_Series() : this(period: 0, useNaN: false) { }
+ public SLOPE_Series(int period) : this(period: period, useNaN: false) { }
+ public SLOPE_Series(TBars source) : this(source.Close, 0, false) { }
+ public SLOPE_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public SLOPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public SLOPE_Series(TSeries source) : this(source, 0, false) { }
+ public SLOPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ int _len = this._buffer.Count;
+
+ // get averages for period
+ double sumX = 0;
+ double sumY = 0;
+
+ for (int p = 0; p < _len; p++)
+ {
+ sumX += this.Count - _len + 2 + p;
+ sumY += _buffer[p];
+ }
+ double avgX = sumX / _len;
+ double avgY = sumY / _len;
+
+ // least squares method
+ double sumSqX = 0;
+ double sumSqY = 0;
+ double sumSqXY = 0;
+
+ for (int p = 0; p < _len; p++)
+ {
+ double devX = this.Count - _len + 2 + p - avgX;
+ double devY = _buffer[p] - avgY;
+
+ sumSqX += devX * devX;
+ sumSqY += devY * devY;
+ sumSqXY += devX * devY;
+ }
+
+ double _slope = sumSqXY / sumSqX;
+ double _intercept = avgY - (_slope * avgX);
+
+ // calculate Standard Deviation and R-Squared
+ double stdDevX = Math.Sqrt(sumSqX / _len);
+ double stdDevY = Math.Sqrt(sumSqY / _len);
+ double _StdDev = stdDevY;
+
+ double arrr = (stdDevX * stdDevY != 0) ? sumSqXY / (stdDevX * stdDevY) / _len : 0;
+ double _RSquared = arrr * arrr;
+
+ var ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _intercept);
+ p_Intercept.Add(ret, update);
+
+ ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _StdDev);
+ p_StdDev.Add(ret, update);
+
+ ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _RSquared);
+ p_RSquared.Add(ret, update);
+
+ ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _slope);
+ return base.Add(ret, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/SMAPE_Series.cs b/Calculations/_Updated/SMAPE_Series.cs
index 00ff1237..082fcd26 100644
--- a/Calculations/_Updated/SMAPE_Series.cs
+++ b/Calculations/_Updated/SMAPE_Series.cs
@@ -1,75 +1,84 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-SMAPE: Symmetric Mean Absolute Percentage Error
- Measures the size of the error in percentage terms
-
-Sources:
- https://en.wikipedia.org/wiki/Symmetric_mean_absolute_percentage_error
-
- */
-
-public class SMAPE_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public SMAPE_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"SMAPE({period})";
- }
- public SMAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public SMAPE_Series() : this(period: 0, useNaN: false) { }
- public SMAPE_Series(int period) : this(period: period, useNaN: false) { }
- public SMAPE_Series(TBars source) : this(source.Close, 0, false) { }
- public SMAPE_Series(TBars source, int period) : this(source.Close, period, false) { }
- public SMAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public SMAPE_Series(TSeries source) : this(source, 0, false) { }
- public SMAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _sma = _buffer.Average();
- double _smape = 0;
- for (int i = 0; i < _buffer.Count; i++) { _smape += Math.Abs(_buffer[i] - _sma) / (Math.Abs(_buffer[i]) + Math.Abs(_sma)); }
- _smape /= this._buffer.Count;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _smape);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+SMAPE: Symmetric Mean Absolute Percentage Error
+ Measures the size of the error in percentage terms
+
+Sources:
+ https://en.wikipedia.org/wiki/Symmetric_mean_absolute_percentage_error
+
+ */
+
+public class SMAPE_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public SMAPE_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"SMAPE({period})";
+ }
+ public SMAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public SMAPE_Series() : this(period: 0, useNaN: false) { }
+ public SMAPE_Series(int period) : this(period: period, useNaN: false) { }
+ public SMAPE_Series(TBars source) : this(source.Close, 0, false) { }
+ public SMAPE_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public SMAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public SMAPE_Series(TSeries source) : this(source, 0, false) { }
+ public SMAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _sma = _buffer.Average();
+ double _smape = 0;
+ for (int i = 0; i < _buffer.Count; i++) { _smape += Math.Abs(_buffer[i] - _sma) / (Math.Abs(_buffer[i]) + Math.Abs(_sma)); }
+ _smape /= this._buffer.Count;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _smape);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/SMA_Series.cs b/Calculations/_Updated/SMA_Series.cs
index ba25a3f6..0c5a19fa 100644
--- a/Calculations/_Updated/SMA_Series.cs
+++ b/Calculations/_Updated/SMA_Series.cs
@@ -1,96 +1,112 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-SMA: Simple Moving Average
- The weights are equally distributed across the period, resulting in a mean() of
- the data within the period
-
-Sources:
- https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/simple-moving-average-sma/
- https://stats.stackexchange.com/a/24739
-
-Remark:
- This calc doesn't use LINQ or SUM() or any of (slow) iterative methods. It is not as fast as TA-LIB
- implementation, but it does allow incremental additions of inputs and real-time calculations of SMA()
-
- */
-public class SMA_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
-
- private double _sum, _oldsum;
- private readonly int _period;
- private readonly TSeries _data;
- protected readonly bool _NaN;
-
- //core constructor
- public SMA_Series(int period, bool useNaN) {
- _period = Math.Max(0, period);
- _NaN = useNaN;
- Name = $"SMA({period})";
- _sum = _oldsum = 0;
- }
- public SMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public SMA_Series() : this(0, false) {}
- public SMA_Series(int period) : this(period, false) {}
- public SMA_Series(TBars source) : this(source.Close, 0, false) {}
- public SMA_Series(TBars source, int period) : this(source.Close, period, false) {}
- public SMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
- public SMA_Series(TSeries source) : this(source, 0, false) {}
- public SMA_Series(TSeries source, int period) : this(source, period, false) {}
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) { return (TValue.t, double.NaN);
- } else {
- if (update && _buffer.Count > 0) {
- _sum -= _buffer[^1];
- _buffer[^1] = TValue.v;
- _oldsum = _sum;
- }
- else {
- _buffer.Add(TValue.v);
- _oldsum = _sum;
- }
-
- _sum += TValue.v;
- if (_period != 0 && _buffer.Count > _period) {
- _sum -= _buffer[0];
- _buffer.RemoveAt(0);
- }
- }
-
- double _div = _period == 0 ? _buffer.Count : Math.Min(_buffer.Count, _period);
- var _sma = _sum / _div;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sma);
- return base.Add(res, update);
- }
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
-
- //reset calculation
- public override void Reset() {
- _sum = _oldsum = 0;
- _buffer.Clear();
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+SMA: Simple Moving Average
+ The weights are equally distributed across the period, resulting in a mean() of
+ the data within the period
+
+Sources:
+ https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/simple-moving-average-sma/
+ https://stats.stackexchange.com/a/24739
+
+Remark:
+ This calc doesn't use LINQ or SUM() or any of (slow) iterative methods. It is not as fast as TA-LIB
+ implementation, but it does allow incremental additions of inputs and real-time calculations of SMA()
+
+ */
+public class SMA_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+
+ private double _sum, _oldsum;
+ private readonly int _period;
+ private readonly TSeries _data;
+ protected readonly bool _NaN;
+
+ //core constructor
+ public SMA_Series(int period, bool useNaN)
+ {
+ _period = Math.Max(0, period);
+ _NaN = useNaN;
+ Name = $"SMA({period})";
+ _sum = _oldsum = 0;
+ }
+ public SMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public SMA_Series() : this(0, false) { }
+ public SMA_Series(int period) : this(period, false) { }
+ public SMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public SMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public SMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public SMA_Series(TSeries source) : this(source, 0, false) { }
+ public SMA_Series(TSeries source, int period) : this(source, period, false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return (TValue.t, double.NaN);
+ }
+ else
+ {
+ if (update && _buffer.Count > 0)
+ {
+ _sum -= _buffer[^1];
+ _buffer[^1] = TValue.v;
+ _oldsum = _sum;
+ }
+ else
+ {
+ _buffer.Add(TValue.v);
+ _oldsum = _sum;
+ }
+
+ _sum += TValue.v;
+ if (_period != 0 && _buffer.Count > _period)
+ {
+ _sum -= _buffer[0];
+ _buffer.RemoveAt(0);
+ }
+ }
+
+ double _div = _period == 0 ? _buffer.Count : Math.Min(_buffer.Count, _period);
+ var _sma = _sum / _div;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sma);
+ return base.Add(res, update);
+ }
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+
+ //reset calculation
+ public override void Reset()
+ {
+ _sum = _oldsum = 0;
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/SMMA_Series.cs b/Calculations/_Updated/SMMA_Series.cs
index f653eab3..46b975c5 100644
--- a/Calculations/_Updated/SMMA_Series.cs
+++ b/Calculations/_Updated/SMMA_Series.cs
@@ -1,93 +1,105 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-SMMA: Smoothed Moving Average
- The Smoothed Moving Average (SMMA) is a combination of a SMA and an EMA. It gives the recent prices
- an equal weighting as the historic prices as it takes all available price data into account.
- The main advantage of a smoothed moving average is that it removes short-term fluctuations.
-
- SMMA(i) = (SMMA-1*(N-1) + CLOSE (i)) / N
-
-Sources:
- https://blog.earn2trade.com/smoothed-moving-average
- https://guide.traderevolution.com/traderevolution/mobile-applications/phone/android/technical-indicators/moving-averages/smma-smoothed-moving-average
- https://www.chartmill.com/documentation/technical-analysis-indicators/217-MOVING-AVERAGES-%7C-The-Smoothed-Moving-Average-%28SMMA%29
-
- */
-
-public class SMMA_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
-
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private double _lastsmma, _lastlastsmma;
-
- //core constructors
- public SMMA_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"SMMA({period})";
- }
- public SMMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public SMMA_Series() : this(period: 0, useNaN: false) { }
- public SMMA_Series(int period) : this(period: period, useNaN: false) { }
- public SMMA_Series(TBars source) : this(source.Close, 0, false) { }
- public SMMA_Series(TBars source, int period) : this(source.Close, period, false) { }
- public SMMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public SMMA_Series(TSeries source) : this(source, 0, false) { }
- public SMMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, double.NaN),update);
- }
-
- double _smma = 0;
- if (update) { this._lastsmma = this._lastlastsmma; }
-
- if (this.Count < this._period) {
- BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
- _smma = _buffer.Average();
- }
- else {
- _smma = ((_lastsmma * (_period - 1)) + TValue.v) / _period;
- }
-
- this._lastlastsmma = this._lastsmma;
- this._lastsmma = _smma;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _smma);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- this._lastsmma = this._lastlastsmma = 0;
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+SMMA: Smoothed Moving Average
+ The Smoothed Moving Average (SMMA) is a combination of a SMA and an EMA. It gives the recent prices
+ an equal weighting as the historic prices as it takes all available price data into account.
+ The main advantage of a smoothed moving average is that it removes short-term fluctuations.
+
+ SMMA(i) = (SMMA-1*(N-1) + CLOSE (i)) / N
+
+Sources:
+ https://blog.earn2trade.com/smoothed-moving-average
+ https://guide.traderevolution.com/traderevolution/mobile-applications/phone/android/technical-indicators/moving-averages/smma-smoothed-moving-average
+ https://www.chartmill.com/documentation/technical-analysis-indicators/217-MOVING-AVERAGES-%7C-The-Smoothed-Moving-Average-%28SMMA%29
+
+ */
+
+public class SMMA_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private double _lastsmma, _lastlastsmma;
+
+ //core constructors
+ public SMMA_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"SMMA({period})";
+ }
+ public SMMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public SMMA_Series() : this(period: 0, useNaN: false) { }
+ public SMMA_Series(int period) : this(period: period, useNaN: false) { }
+ public SMMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public SMMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public SMMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public SMMA_Series(TSeries source) : this(source, 0, false) { }
+ public SMMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, double.NaN), update);
+ }
+
+ double _smma = 0;
+ if (update) { this._lastsmma = this._lastlastsmma; }
+
+ if (this.Count < this._period)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+ _smma = _buffer.Average();
+ }
+ else
+ {
+ _smma = ((_lastsmma * (_period - 1)) + TValue.v) / _period;
+ }
+
+ this._lastlastsmma = this._lastsmma;
+ this._lastsmma = _smma;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _smma);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ this._lastsmma = this._lastlastsmma = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/SSDEV_Series.cs b/Calculations/_Updated/SSDEV_Series.cs
index 20d41b95..490c579c 100644
--- a/Calculations/_Updated/SSDEV_Series.cs
+++ b/Calculations/_Updated/SSDEV_Series.cs
@@ -1,82 +1,91 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-SSDEV: (Corrected) Sample Standard Deviation
- Sample Standard Deviaton uses Bessel's correction to correct the bias in the variance.
-
-Sources:
- https://en.wikipedia.org/wiki/Standard_deviation#Corrected_sample_standard_deviation
- Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
-
-Remark:
- SSDEV (Sample Standard Deviation) is also known as a unbiased/corrected Standard Deviation.
- For a population/biased/uncorrected Standard Deviation, use PSDEV instead
-
- */
-
-public class SSDEV_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public SSDEV_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"SSDEV({period})";
- }
- public SSDEV_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public SSDEV_Series() : this(period: 0, useNaN: false) { }
- public SSDEV_Series(int period) : this(period: period, useNaN: false) { }
- public SSDEV_Series(TBars source) : this(source.Close, 0, false) { }
- public SSDEV_Series(TBars source, int period) : this(source.Close, period, false) { }
- public SSDEV_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public SSDEV_Series(TSeries source) : this(source, 0, false) { }
- public SSDEV_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _sma = _buffer.Average();
-
- double _svar = 0;
- for (int i = 0; i < this._buffer.Count; i++) { _svar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
- _svar /= (_buffer.Count > 1) ? _buffer.Count - 1 : 1; // Bessel's correction
- double _ssdev = Math.Sqrt(_svar);
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _ssdev);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+SSDEV: (Corrected) Sample Standard Deviation
+ Sample Standard Deviaton uses Bessel's correction to correct the bias in the variance.
+
+Sources:
+ https://en.wikipedia.org/wiki/Standard_deviation#Corrected_sample_standard_deviation
+ Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
+
+Remark:
+ SSDEV (Sample Standard Deviation) is also known as a unbiased/corrected Standard Deviation.
+ For a population/biased/uncorrected Standard Deviation, use PSDEV instead
+
+ */
+
+public class SSDEV_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public SSDEV_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"SSDEV({period})";
+ }
+ public SSDEV_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public SSDEV_Series() : this(period: 0, useNaN: false) { }
+ public SSDEV_Series(int period) : this(period: period, useNaN: false) { }
+ public SSDEV_Series(TBars source) : this(source.Close, 0, false) { }
+ public SSDEV_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public SSDEV_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public SSDEV_Series(TSeries source) : this(source, 0, false) { }
+ public SSDEV_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _sma = _buffer.Average();
+
+ double _svar = 0;
+ for (int i = 0; i < this._buffer.Count; i++) { _svar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
+ _svar /= (_buffer.Count > 1) ? _buffer.Count - 1 : 1; // Bessel's correction
+ double _ssdev = Math.Sqrt(_svar);
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _ssdev);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/SVAR_Series.cs b/Calculations/_Updated/SVAR_Series.cs
index b121fe8b..01020519 100644
--- a/Calculations/_Updated/SVAR_Series.cs
+++ b/Calculations/_Updated/SVAR_Series.cs
@@ -1,81 +1,90 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-VAR: Population Variance
- Population variance without Bessel's correction
-
-Sources:
- https://en.wikipedia.org/wiki/Variance
- Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
-
-Remark:
- VAR (Population Variance) is also known as a biased Sample Variance. For unbiased
- sample variance use SVAR instead.
-
- */
-
-public class SVAR_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public SVAR_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"SVAR({period})";
- }
- public SVAR_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public SVAR_Series() : this(period: 0, useNaN: false) { }
- public SVAR_Series(int period) : this(period: period, useNaN: false) { }
- public SVAR_Series(TBars source) : this(source.Close, 0, false) { }
- public SVAR_Series(TBars source, int period) : this(source.Close, period, false) { }
- public SVAR_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public SVAR_Series(TSeries source) : this(source, 0, false) { }
- public SVAR_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _sma = _buffer.Average();
-
- double _svar = 0;
- for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); }
- _svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _svar);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+VAR: Population Variance
+ Population variance without Bessel's correction
+
+Sources:
+ https://en.wikipedia.org/wiki/Variance
+ Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
+
+Remark:
+ VAR (Population Variance) is also known as a biased Sample Variance. For unbiased
+ sample variance use SVAR instead.
+
+ */
+
+public class SVAR_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public SVAR_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"SVAR({period})";
+ }
+ public SVAR_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public SVAR_Series() : this(period: 0, useNaN: false) { }
+ public SVAR_Series(int period) : this(period: period, useNaN: false) { }
+ public SVAR_Series(TBars source) : this(source.Close, 0, false) { }
+ public SVAR_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public SVAR_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public SVAR_Series(TSeries source) : this(source, 0, false) { }
+ public SVAR_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _sma = _buffer.Average();
+
+ double _svar = 0;
+ for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); }
+ _svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _svar);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/T3_Series.cs b/Calculations/_Updated/T3_Series.cs
index 1ffac970..6f87ea07 100644
--- a/Calculations/_Updated/T3_Series.cs
+++ b/Calculations/_Updated/T3_Series.cs
@@ -1,161 +1,173 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Numerics;
-
-/*
-T3: Tillson T3 Moving Average
- Tim Tillson described it in "Technical Analysis of Stocks and Commodities", January 1998 in the
- article "Better Moving Averages". Tillson’s moving average becomes a popular indicator of
- technical analysis as it gets less lag with the price chart and its curve is considerably smoother.
-
-Sources:
- https://technicalindicators.net/indicators-technical-analysis/150-t3-moving-average
- http://www.binarytribune.com/forex-trading-indicators/t3-moving-average-indicator/
- */
-
-public class T3_Series : TSeries {
- private readonly double _k, _k1m, _c1, _c2, _c3, _c4;
- private readonly System.Collections.Generic.List _buffer1 = new();
- private readonly System.Collections.Generic.List _buffer2 = new();
- private readonly System.Collections.Generic.List _buffer3 = new();
- private readonly System.Collections.Generic.List _buffer4 = new();
- private readonly System.Collections.Generic.List _buffer5 = new();
- private readonly System.Collections.Generic.List _buffer6 = new();
- private readonly bool _useSMA;
- private double _lastema1, _lastema2, _lastema3, _lastema4, _lastema5, _lastema6;
- private double _llastema1, _llastema2, _llastema3, _llastema4, _llastema5, _llastema6;
- protected int _len;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public T3_Series(int period, double vfactor, bool useSMA, bool useNaN) {
- _period = period;
- _len = 0;
- _NaN = useNaN;
- Name = $"T3({period})";
- _useSMA = useSMA;
- double _a = vfactor; //0.7; //0.618
- _c1 = -_a * _a * _a;
- _c2 = 3 * _a * _a + 3 * _a * _a * _a;
- _c3 = -6 * _a * _a - 3 * _a - 3 * _a * _a * _a;
- _c4 = 1 + 3 * _a + _a * _a * _a + 3 * _a * _a;
-
- _k = 2.0 / (_period + 1);
- _k1m = 1.0 - _k;
- _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0;
- }
- public T3_Series(TSeries source, int period, double vfactor, bool useSMA, bool useNaN) : this(period, vfactor, useSMA, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public T3_Series() : this(period: 0, vfactor: 0.7, useSMA: true, useNaN: false) { }
- public T3_Series(int period) : this(period: period, vfactor: 0.7, useSMA: true, useNaN: false) { }
- public T3_Series(TBars source) : this(source.Close, 0, vfactor: 0.7, useSMA: true, useNaN: false) { }
- public T3_Series(TBars source, int period) : this(source.Close, period, vfactor: 0.7, useSMA: true, useNaN: false) { }
- public T3_Series(TBars source, int period, bool useNaN) : this(source.Close, period, vfactor: 0.7, useSMA: true, useNaN: useNaN) { }
- public T3_Series(TBars source, int period, double vfactor, bool useNaN) : this(source.Close, period, vfactor: vfactor, useSMA: true, useNaN: useNaN) { }
- public T3_Series(TBars source, int period, bool useSMA, bool useNaN) : this(source.Close, period, vfactor: 0.7, useSMA: useSMA, useNaN: useNaN) { }
- public T3_Series(TSeries source) : this(source, 0, vfactor: 0.7, useSMA: true, useNaN: false) { }
- public T3_Series(TSeries source, int period) : this(source: source, period: period, vfactor: 0.7, useSMA: true, useNaN: false) { }
- public T3_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, vfactor: 0.7, useSMA: true, useNaN: useNaN) { }
- public T3_Series(TSeries source, int period, double vfactor) : this(source: source, period: period, vfactor: vfactor, useSMA: true, useNaN: false) { }
- public T3_Series(TSeries source, int period, double vfactor, bool useNaN) : this(source: source, period: period, vfactor: vfactor, useSMA: true, useNaN: useNaN) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- double _ema1, _ema2, _ema3, _ema4, _ema5, _ema6;
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, Double.NaN),update);
- }
-
- if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; _lastema4 = _llastema4; _lastema5 = _llastema5; _lastema6 = _llastema6; }
- else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _llastema4 = _lastema4; _llastema5 = _lastema5; _llastema6 = _lastema6; }
-
- if (_len == 0) { _lastema1 = _lastema2 = _lastema3 = _lastema4 = _lastema5 = _lastema6 = TValue.v; }
-
-
- if ((_len < _period) && _useSMA) {
- BufferTrim(_buffer1, TValue.v, _period, update);
- _ema1 = 0;
- for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; }
- _ema1 /= _buffer1.Count;
-
- BufferTrim(_buffer2, _ema1, _period, update);
- _ema2 = 0;
- for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; }
- _ema2 /= _buffer2.Count;
-
- BufferTrim(_buffer3, _ema2, _period, update);
- _ema3 = 0;
- for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; }
- _ema3 /= _buffer3.Count;
-
- BufferTrim(_buffer4, _ema3, _period, update);
- _ema4 = 0;
- for (int i = 0; i < _buffer4.Count; i++) { _ema4 += _buffer4[i]; }
- _ema4 /= _buffer4.Count;
-
- BufferTrim(_buffer5, _ema4, _period, update);
- _ema5 = 0;
- for (int i = 0; i < _buffer5.Count; i++) { _ema5 += _buffer5[i]; }
- _ema5 /= _buffer5.Count;
-
- BufferTrim(_buffer6, _ema5, _period, update);
- _ema6 = 0;
- for (int i = 0; i < _buffer6.Count; i++) { _ema6 += _buffer6[i]; }
- _ema6 /= _buffer6.Count;
- }
- else {
- _ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m);
- _ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m);
- _ema3 = (_ema2 * this._k) + (this._lastema3 * this._k1m);
- _ema4 = (_ema3 * this._k) + (this._lastema4 * this._k1m);
- _ema5 = (_ema4 * this._k) + (this._lastema5 * this._k1m);
- _ema6 = (_ema5 * this._k) + (this._lastema6 * this._k1m);
- }
- _len++;
- _lastema1 = _ema1;
- _lastema2 = _ema2;
- _lastema3 = _ema3;
- _lastema4 = _ema4;
- _lastema5 = _ema5;
- _lastema6 = _ema6;
-
- double _T3 = _c1 * _ema6 + _c2 * _ema5 + _c3 * _ema4 + _c4 * _ema3;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _T3);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0;
- _buffer1.Clear();
- _buffer2.Clear();
- _buffer3.Clear();
- _buffer4.Clear();
- _buffer5.Clear();
- _buffer6.Clear();
- _len = 0;
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+
+/*
+T3: Tillson T3 Moving Average
+ Tim Tillson described it in "Technical Analysis of Stocks and Commodities", January 1998 in the
+ article "Better Moving Averages". Tillson’s moving average becomes a popular indicator of
+ technical analysis as it gets less lag with the price chart and its curve is considerably smoother.
+
+Sources:
+ https://technicalindicators.net/indicators-technical-analysis/150-t3-moving-average
+ http://www.binarytribune.com/forex-trading-indicators/t3-moving-average-indicator/
+ */
+
+public class T3_Series : TSeries
+{
+ private readonly double _k, _k1m, _c1, _c2, _c3, _c4;
+ private readonly System.Collections.Generic.List _buffer1 = new();
+ private readonly System.Collections.Generic.List _buffer2 = new();
+ private readonly System.Collections.Generic.List _buffer3 = new();
+ private readonly System.Collections.Generic.List _buffer4 = new();
+ private readonly System.Collections.Generic.List _buffer5 = new();
+ private readonly System.Collections.Generic.List _buffer6 = new();
+ private readonly bool _useSMA;
+ private double _lastema1, _lastema2, _lastema3, _lastema4, _lastema5, _lastema6;
+ private double _llastema1, _llastema2, _llastema3, _llastema4, _llastema5, _llastema6;
+ protected int _len;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public T3_Series(int period, double vfactor, bool useSMA, bool useNaN)
+ {
+ _period = period;
+ _len = 0;
+ _NaN = useNaN;
+ Name = $"T3({period})";
+ _useSMA = useSMA;
+ double _a = vfactor; //0.7; //0.618
+ _c1 = -_a * _a * _a;
+ _c2 = 3 * _a * _a + 3 * _a * _a * _a;
+ _c3 = -6 * _a * _a - 3 * _a - 3 * _a * _a * _a;
+ _c4 = 1 + 3 * _a + _a * _a * _a + 3 * _a * _a;
+
+ _k = 2.0 / (_period + 1);
+ _k1m = 1.0 - _k;
+ _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0;
+ }
+ public T3_Series(TSeries source, int period, double vfactor, bool useSMA, bool useNaN) : this(period, vfactor, useSMA, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public T3_Series() : this(period: 0, vfactor: 0.7, useSMA: true, useNaN: false) { }
+ public T3_Series(int period) : this(period: period, vfactor: 0.7, useSMA: true, useNaN: false) { }
+ public T3_Series(TBars source) : this(source.Close, 0, vfactor: 0.7, useSMA: true, useNaN: false) { }
+ public T3_Series(TBars source, int period) : this(source.Close, period, vfactor: 0.7, useSMA: true, useNaN: false) { }
+ public T3_Series(TBars source, int period, bool useNaN) : this(source.Close, period, vfactor: 0.7, useSMA: true, useNaN: useNaN) { }
+ public T3_Series(TBars source, int period, double vfactor, bool useNaN) : this(source.Close, period, vfactor: vfactor, useSMA: true, useNaN: useNaN) { }
+ public T3_Series(TBars source, int period, bool useSMA, bool useNaN) : this(source.Close, period, vfactor: 0.7, useSMA: useSMA, useNaN: useNaN) { }
+ public T3_Series(TSeries source) : this(source, 0, vfactor: 0.7, useSMA: true, useNaN: false) { }
+ public T3_Series(TSeries source, int period) : this(source: source, period: period, vfactor: 0.7, useSMA: true, useNaN: false) { }
+ public T3_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, vfactor: 0.7, useSMA: true, useNaN: useNaN) { }
+ public T3_Series(TSeries source, int period, double vfactor) : this(source: source, period: period, vfactor: vfactor, useSMA: true, useNaN: false) { }
+ public T3_Series(TSeries source, int period, double vfactor, bool useNaN) : this(source: source, period: period, vfactor: vfactor, useSMA: true, useNaN: useNaN) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ double _ema1, _ema2, _ema3, _ema4, _ema5, _ema6;
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+
+ if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; _lastema4 = _llastema4; _lastema5 = _llastema5; _lastema6 = _llastema6; }
+ else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _llastema4 = _lastema4; _llastema5 = _lastema5; _llastema6 = _lastema6; }
+
+ if (_len == 0) { _lastema1 = _lastema2 = _lastema3 = _lastema4 = _lastema5 = _lastema6 = TValue.v; }
+
+
+ if ((_len < _period) && _useSMA)
+ {
+ BufferTrim(_buffer1, TValue.v, _period, update);
+ _ema1 = 0;
+ for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; }
+ _ema1 /= _buffer1.Count;
+
+ BufferTrim(_buffer2, _ema1, _period, update);
+ _ema2 = 0;
+ for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; }
+ _ema2 /= _buffer2.Count;
+
+ BufferTrim(_buffer3, _ema2, _period, update);
+ _ema3 = 0;
+ for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; }
+ _ema3 /= _buffer3.Count;
+
+ BufferTrim(_buffer4, _ema3, _period, update);
+ _ema4 = 0;
+ for (int i = 0; i < _buffer4.Count; i++) { _ema4 += _buffer4[i]; }
+ _ema4 /= _buffer4.Count;
+
+ BufferTrim(_buffer5, _ema4, _period, update);
+ _ema5 = 0;
+ for (int i = 0; i < _buffer5.Count; i++) { _ema5 += _buffer5[i]; }
+ _ema5 /= _buffer5.Count;
+
+ BufferTrim(_buffer6, _ema5, _period, update);
+ _ema6 = 0;
+ for (int i = 0; i < _buffer6.Count; i++) { _ema6 += _buffer6[i]; }
+ _ema6 /= _buffer6.Count;
+ }
+ else
+ {
+ _ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m);
+ _ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m);
+ _ema3 = (_ema2 * this._k) + (this._lastema3 * this._k1m);
+ _ema4 = (_ema3 * this._k) + (this._lastema4 * this._k1m);
+ _ema5 = (_ema4 * this._k) + (this._lastema5 * this._k1m);
+ _ema6 = (_ema5 * this._k) + (this._lastema6 * this._k1m);
+ }
+ _len++;
+ _lastema1 = _ema1;
+ _lastema2 = _ema2;
+ _lastema3 = _ema3;
+ _lastema4 = _ema4;
+ _lastema5 = _ema5;
+ _lastema6 = _ema6;
+
+ double _T3 = _c1 * _ema6 + _c2 * _ema5 + _c3 * _ema4 + _c4 * _ema3;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _T3);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0;
+ _buffer1.Clear();
+ _buffer2.Clear();
+ _buffer3.Clear();
+ _buffer4.Clear();
+ _buffer5.Clear();
+ _buffer6.Clear();
+ _len = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/TBars.cs b/Calculations/_Updated/TBars.cs
index 920dd17c..7b9af4ce 100644
--- a/Calculations/_Updated/TBars.cs
+++ b/Calculations/_Updated/TBars.cs
@@ -1,138 +1,153 @@
-namespace QuanTAlib;
-using System;
-
-/*
-TBars class - includes all series for common data used in indicators and other calculations.
- Has a bit limited overloading and casting (compared to TSeries)
- Includes Select(int) method to simplify choosing the most optimal data source for indicators
- Includes the most basic pricing calcs: HL2, OC2, OHL3, HLC3, OHLC4, HLCC4
- (it is 'cheaper' to calculate them once during data capture than each time during data analysis)
-
- */
-
-public class TBars : System.Collections.Generic.List<(DateTime t, double o, double h, double l, double c, double v)>
-{
- public string Name { get; set; }
- private readonly TSeries _open = new("open");
- private readonly TSeries _high = new("high");
- private readonly TSeries _low = new("low");
- private readonly TSeries _close = new("close");
- private readonly TSeries _volume = new("volume");
- private readonly TSeries _hl2 = new("HL2");
- private readonly TSeries _oc2 = new("OC2");
- private readonly TSeries _ohl3 = new("OHL3");
- private readonly TSeries _hlc3 = new("HLC3");
- private readonly TSeries _ohlc4 = new("OHLC4");
- private readonly TSeries _hlcc4 = new("HLCC4");
-
- public TSeries Open => this._open;
- public TSeries High => this._high;
- public TSeries Low => this._low;
- public TSeries Close => this._close;
- public TSeries Volume => this._volume;
- public TSeries HL2 => this._hl2;
- public TSeries OC2 => this._oc2;
- public TSeries OHL3 => this._ohl3;
- public TSeries HLC3 => this._hlc3;
- public TSeries OHLC4 => this._ohlc4;
- public TSeries HLCC4 => this._hlcc4;
-
- public TBars() { }
-
- public TBars(string Name) {
- this.Name = Name;
- }
-
- public (DateTime t, double o, double h, double l, double c, double v) Last => this[^1];
- public TBars Tail(int count = 10)
- {
- TBars outBars = new();
- if (count > this.Count) { count = this.Count; }
- for (int i = this.Count - count; i < this.Count; i++) { outBars.Add(this[i]); }
- return outBars;
- }
- public TSeries Select(int source)
- {
- return source switch
- {
- 0 => _open,
- 1 => _high,
- 2 => _low,
- 3 => _close,
- 4 => _hl2,
- 5 => _oc2,
- 6 => _ohl3,
- 7 => _hlc3,
- 8 => _ohlc4,
- _ => _hlcc4,
- };
- }
- public static string SelectStr(int source)
- {
- return source switch
- {
- 0 => "Open",
- 1 => "High",
- 2 => "Low",
- 3 => "Close",
- 4 => "HL2",
- 5 => "OC2",
- 6 => "OHL3",
- 7 => "HLC3",
- 8 => "OHLC4",
- _ => "HLCC4",
- };
- }
-
- public virtual (DateTime t, double v) Add((double o, double h, double l, double c, double v) p, bool update = false) =>
- Add((t: (this.Count == 0) ? DateTime.Today : this[^1].t.AddDays(1),p.o,p.h,p.l,p.c,p.v),update);
-
- public virtual (DateTime t, double v) Add(double o, double h, double l, double c, double v, bool update = false) =>
- Add((o,h,l,c,v),update);
-
- public virtual (DateTime t, double v) Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) =>
- this.Add((t, o, h, l, c, v), update);
-
- public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
- if (update) { this[^1] = TBar; } else { base.Add(TBar); }
-
- _open.Add((TBar.t, TBar.o), update);
- _high.Add((TBar.t, TBar.h), update);
- _low.Add((TBar.t, TBar.l), update);
- _close.Add((TBar.t, TBar.c), update);
- _volume.Add((TBar.t, TBar.v), update);
- _hl2.Add((TBar.t, (TBar.h + TBar.l) * 0.5), update);
- _oc2.Add((TBar.t, (TBar.o + TBar.c) * 0.5), update);
- _ohl3.Add((TBar.t, (TBar.o + TBar.h + TBar.l) * 0.333333333333333), update);
- _hlc3.Add((TBar.t, (TBar.h + TBar.l + TBar.c) * 0.333333333333333), update);
- _ohlc4.Add((TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25), update);
- _hlcc4.Add((TBar.t, (TBar.h + TBar.l + TBar.c + TBar.c) * 0.25), update);
-
- this.OnEvent(update);
- return (TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25);
- }
-
- public delegate void NewDataEventHandler(object source, TSeriesEventArgs args);
- public event NewDataEventHandler Pub;
- protected virtual void OnEvent(bool update = false) { if (Pub != null && Pub.Target != this) {
- Pub(this, new TSeriesEventArgs { update = update }); } }
-
- public void Sub(object source, TSeriesEventArgs e) { TBars ss = (TBars)source; if (ss.Count > 1) {
- for (int i = 0; i < ss.Count; i++) { this.Add(ss[i]); }
- } else {
- this.Add(ss[^1], e.update);
- }
- }
-
- /// common helpers
- public static void BufferTrim(System.Collections.Generic.List buffer, double value, int period, bool update) {
- if (!update) {
- buffer.Add(value);
- if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); }
- return;
- }
- buffer[^1] = value;
- }
- public virtual void Reset() {
- }
-}
+namespace QuanTAlib;
+using System;
+
+/*
+TBars class - includes all series for common data used in indicators and other calculations.
+ Has a bit limited overloading and casting (compared to TSeries)
+ Includes Select(int) method to simplify choosing the most optimal data source for indicators
+ Includes the most basic pricing calcs: HL2, OC2, OHL3, HLC3, OHLC4, HLCC4
+ (it is 'cheaper' to calculate them once during data capture than each time during data analysis)
+
+ */
+
+public class TBars : System.Collections.Generic.List<(DateTime t, double o, double h, double l, double c, double v)>
+{
+ public string Name { get; set; }
+ private readonly TSeries _open = new("open");
+ private readonly TSeries _high = new("high");
+ private readonly TSeries _low = new("low");
+ private readonly TSeries _close = new("close");
+ private readonly TSeries _volume = new("volume");
+ private readonly TSeries _hl2 = new("HL2");
+ private readonly TSeries _oc2 = new("OC2");
+ private readonly TSeries _ohl3 = new("OHL3");
+ private readonly TSeries _hlc3 = new("HLC3");
+ private readonly TSeries _ohlc4 = new("OHLC4");
+ private readonly TSeries _hlcc4 = new("HLCC4");
+
+ public TSeries Open => this._open;
+ public TSeries High => this._high;
+ public TSeries Low => this._low;
+ public TSeries Close => this._close;
+ public TSeries Volume => this._volume;
+ public TSeries HL2 => this._hl2;
+ public TSeries OC2 => this._oc2;
+ public TSeries OHL3 => this._ohl3;
+ public TSeries HLC3 => this._hlc3;
+ public TSeries OHLC4 => this._ohlc4;
+ public TSeries HLCC4 => this._hlcc4;
+
+ public TBars() { }
+
+ public TBars(string Name)
+ {
+ this.Name = Name;
+ }
+
+ public (DateTime t, double o, double h, double l, double c, double v) Last => this[^1];
+ public TBars Tail(int count = 10)
+ {
+ TBars outBars = new();
+ if (count > this.Count) { count = this.Count; }
+ for (int i = this.Count - count; i < this.Count; i++) { outBars.Add(this[i]); }
+ return outBars;
+ }
+ public TSeries Select(int source)
+ {
+ return source switch
+ {
+ 0 => _open,
+ 1 => _high,
+ 2 => _low,
+ 3 => _close,
+ 4 => _hl2,
+ 5 => _oc2,
+ 6 => _ohl3,
+ 7 => _hlc3,
+ 8 => _ohlc4,
+ _ => _hlcc4,
+ };
+ }
+ public static string SelectStr(int source)
+ {
+ return source switch
+ {
+ 0 => "Open",
+ 1 => "High",
+ 2 => "Low",
+ 3 => "Close",
+ 4 => "HL2",
+ 5 => "OC2",
+ 6 => "OHL3",
+ 7 => "HLC3",
+ 8 => "OHLC4",
+ _ => "HLCC4",
+ };
+ }
+
+ public virtual (DateTime t, double v) Add((double o, double h, double l, double c, double v) p, bool update = false) =>
+ Add((t: (this.Count == 0) ? DateTime.Today : this[^1].t.AddDays(1), p.o, p.h, p.l, p.c, p.v), update);
+
+ public virtual (DateTime t, double v) Add(double o, double h, double l, double c, double v, bool update = false) =>
+ Add((o, h, l, c, v), update);
+
+ public virtual (DateTime t, double v) Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) =>
+ this.Add((t, o, h, l, c, v), update);
+
+ public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
+ {
+ if (update) { this[^1] = TBar; } else { base.Add(TBar); }
+
+ _open.Add((TBar.t, TBar.o), update);
+ _high.Add((TBar.t, TBar.h), update);
+ _low.Add((TBar.t, TBar.l), update);
+ _close.Add((TBar.t, TBar.c), update);
+ _volume.Add((TBar.t, TBar.v), update);
+ _hl2.Add((TBar.t, (TBar.h + TBar.l) * 0.5), update);
+ _oc2.Add((TBar.t, (TBar.o + TBar.c) * 0.5), update);
+ _ohl3.Add((TBar.t, (TBar.o + TBar.h + TBar.l) * 0.333333333333333), update);
+ _hlc3.Add((TBar.t, (TBar.h + TBar.l + TBar.c) * 0.333333333333333), update);
+ _ohlc4.Add((TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25), update);
+ _hlcc4.Add((TBar.t, (TBar.h + TBar.l + TBar.c + TBar.c) * 0.25), update);
+
+ this.OnEvent(update);
+ return (TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25);
+ }
+
+ public delegate void NewDataEventHandler(object source, TSeriesEventArgs args);
+ public event NewDataEventHandler Pub;
+ protected virtual void OnEvent(bool update = false)
+ {
+ if (Pub != null && Pub.Target != this)
+ {
+ Pub(this, new TSeriesEventArgs { update = update });
+ }
+ }
+
+ public void Sub(object source, TSeriesEventArgs e)
+ {
+ TBars ss = (TBars)source; if (ss.Count > 1)
+ {
+ for (int i = 0; i < ss.Count; i++) { this.Add(ss[i]); }
+ }
+ else
+ {
+ this.Add(ss[^1], e.update);
+ }
+ }
+
+ /// common helpers
+ public static void BufferTrim(System.Collections.Generic.List buffer, double value, int period, bool update)
+ {
+ if (!update)
+ {
+ buffer.Add(value);
+ if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); }
+ return;
+ }
+ buffer[^1] = value;
+ }
+ public virtual void Reset()
+ {
+ }
+}
diff --git a/Calculations/_Updated/TEMA_Series.cs b/Calculations/_Updated/TEMA_Series.cs
index a9653f6b..88218161 100644
--- a/Calculations/_Updated/TEMA_Series.cs
+++ b/Calculations/_Updated/TEMA_Series.cs
@@ -1,120 +1,134 @@
-namespace QuanTAlib;
-
-using System;
-using System.Linq;
-
-/*
-TEMA: Triple Exponential Moving Average
- TEMA uses EMA(EMA(EMA())) to calculate less laggy Exponential moving average.
-
-Sources:
- https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triple-exponential-moving-average-tema/
-
-Remark:
- ema1 = EMA(close, length)
- ema2 = EMA(ema1, length)
- ema3 = EMA(ema2, length)
- TEMA = 3 * (ema1 - ema2) + ema3
-
- */
-
-public class TEMA_Series : TSeries {
- private double _k;
- private double _sum, _oldsum;
- private double _lastema1, _oldema1, _lastema2, _oldema2, _lastema3, _oldema3;
- private int _len;
- private readonly bool _useSMA;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
-//core constructor
- public TEMA_Series(int period, bool useNaN, bool useSMA) {
- _period = period;
- _NaN = useNaN;
- _useSMA = useSMA;
- Name = $"TEMA({period})";
- _k = 2.0 / (_period + 1);
- _len = 0;
- _sum = _oldsum = _lastema1 = _lastema2 = _lastema3 = 0;
- }
- public TEMA_Series() : this(0, false, true) {}
- public TEMA_Series(int period) : this(period, false, true) {}
- public TEMA_Series(TBars source) : this(source.Close, 0, false) {}
- public TEMA_Series(TBars source, int period) : this(source.Close, period, false) {}
- public TEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
- public TEMA_Series(TSeries source, int period) : this(source, period, false, true) {}
- public TEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {}
- public TEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
-
-// core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (update) {
- _lastema1 = _oldema1;
- _lastema2 = _oldema2;
- _lastema3 = _oldema3;
- _sum = _oldsum;
- }
- else {
- _oldema1 = _lastema1;
- _oldema2 = _lastema2;
- _oldema3 = _lastema3;
- _oldsum = _sum;
- _len++;
- }
-
- if (_period == 0) { _k = 2.0 / (_len + 1); }
-
- double _ema1, _ema2, _ema3, _tema;
- if (this.Count == 0) {
- _ema1 = _ema2 = _ema3 =_sum = TValue.v;
- }
- else if (_len <= _period && _useSMA && _period != 0) {
- _sum += TValue.v;
- _ema1 = _sum / Math.Min(_len, _period);
- _ema2 = _ema1;
- _ema3 = _ema2;
- }
- else {
- _ema1 = (TValue.v - _lastema1) * _k + _lastema1;
- _ema2 = (_ema1 - _lastema2) * _k + _lastema2;
- _ema3 = (_ema2 - _lastema3) * _k + _lastema3;
- }
-
- _tema = (3 * (_ema1 - _ema2)) + _ema3;
-
- _lastema1 = Double.IsNaN(_ema1)?_lastema1:_ema1;
- _lastema2 = Double.IsNaN(_ema2)?_lastema2:_ema2;
- _lastema3 = Double.IsNaN(_ema3) ? _lastema3 : _ema3;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _tema);
- return base.Add(res, update);
- }
-
-//variation of Add()
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _sum = _oldsum = _lastema1 = _lastema2 = 0;
- _len = 0;
- }
+namespace QuanTAlib;
+
+using System;
+using System.Linq;
+
+/*
+TEMA: Triple Exponential Moving Average
+ TEMA uses EMA(EMA(EMA())) to calculate less laggy Exponential moving average.
+
+Sources:
+ https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triple-exponential-moving-average-tema/
+
+Remark:
+ ema1 = EMA(close, length)
+ ema2 = EMA(ema1, length)
+ ema3 = EMA(ema2, length)
+ TEMA = 3 * (ema1 - ema2) + ema3
+
+ */
+
+public class TEMA_Series : TSeries
+{
+ private double _k;
+ private double _sum, _oldsum;
+ private double _lastema1, _oldema1, _lastema2, _oldema2, _lastema3, _oldema3;
+ private int _len;
+ private readonly bool _useSMA;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructor
+ public TEMA_Series(int period, bool useNaN, bool useSMA)
+ {
+ _period = period;
+ _NaN = useNaN;
+ _useSMA = useSMA;
+ Name = $"TEMA({period})";
+ _k = 2.0 / (_period + 1);
+ _len = 0;
+ _sum = _oldsum = _lastema1 = _lastema2 = _lastema3 = 0;
+ }
+ public TEMA_Series() : this(0, false, true) { }
+ public TEMA_Series(int period) : this(period, false, true) { }
+ public TEMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public TEMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public TEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public TEMA_Series(TSeries source, int period) : this(source, period, false, true) { }
+ public TEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
+ public TEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (update)
+ {
+ _lastema1 = _oldema1;
+ _lastema2 = _oldema2;
+ _lastema3 = _oldema3;
+ _sum = _oldsum;
+ }
+ else
+ {
+ _oldema1 = _lastema1;
+ _oldema2 = _lastema2;
+ _oldema3 = _lastema3;
+ _oldsum = _sum;
+ _len++;
+ }
+
+ if (_period == 0) { _k = 2.0 / (_len + 1); }
+
+ double _ema1, _ema2, _ema3, _tema;
+ if (this.Count == 0)
+ {
+ _ema1 = _ema2 = _ema3 = _sum = TValue.v;
+ }
+ else if (_len <= _period && _useSMA && _period != 0)
+ {
+ _sum += TValue.v;
+ _ema1 = _sum / Math.Min(_len, _period);
+ _ema2 = _ema1;
+ _ema3 = _ema2;
+ }
+ else
+ {
+ _ema1 = (TValue.v - _lastema1) * _k + _lastema1;
+ _ema2 = (_ema1 - _lastema2) * _k + _lastema2;
+ _ema3 = (_ema2 - _lastema3) * _k + _lastema3;
+ }
+
+ _tema = (3 * (_ema1 - _ema2)) + _ema3;
+
+ _lastema1 = Double.IsNaN(_ema1) ? _lastema1 : _ema1;
+ _lastema2 = Double.IsNaN(_ema2) ? _lastema2 : _ema2;
+ _lastema3 = Double.IsNaN(_ema3) ? _lastema3 : _ema3;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _tema);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _sum = _oldsum = _lastema1 = _lastema2 = 0;
+ _len = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/TRIMA_Series.cs b/Calculations/_Updated/TRIMA_Series.cs
index 210be772..703f594d 100644
--- a/Calculations/_Updated/TRIMA_Series.cs
+++ b/Calculations/_Updated/TRIMA_Series.cs
@@ -1,84 +1,94 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-TRIMA: Triangular Moving Average
- A weighted moving average where the shape of the weights are triangular and the greatest
- weight is in the middle of the period,
-
-Sources:
- https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triangular-moving-average-trima/
-
-Remark:
- trima = sma(sma(signal, n/2), n/2)
-
- */
-
-public class TRIMA_Series : TSeries {
- private readonly int _p1a, _p1b;
- private readonly SMA_Series sma, trima;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public TRIMA_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"xMA({period})";
- _p1a = (int)Math.Floor((period * 0.5) + 1);
- _p1b = (int)Math.Ceiling(0.5 * period);
- sma = new(_p1a);
- trima = new(_p1b);
-
- }
- public TRIMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public TRIMA_Series() : this(period: 0, useNaN: false) { }
- public TRIMA_Series(int period) : this(period: period, useNaN: false) { }
- public TRIMA_Series(TBars source) : this(source.Close, 0, false) { }
- public TRIMA_Series(TBars source, int period) : this(source.Close, period, false) { }
- public TRIMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public TRIMA_Series(TSeries source) : this(source, 0, false) { }
- public TRIMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, Double.NaN), update);
- }
-
- var _sma = sma.Add(TValue, update);
- var _trima = trima.Add(_sma, update);
-
- var res = (_trima.t, Count < _period - 1 && _NaN ? double.NaN : _trima.v);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- sma.Reset();
- trima.Reset();
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+TRIMA: Triangular Moving Average
+ A weighted moving average where the shape of the weights are triangular and the greatest
+ weight is in the middle of the period,
+
+Sources:
+ https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triangular-moving-average-trima/
+
+Remark:
+ trima = sma(sma(signal, n/2), n/2)
+
+ */
+
+public class TRIMA_Series : TSeries
+{
+ private readonly int _p1a, _p1b;
+ private readonly SMA_Series sma, trima;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public TRIMA_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"xMA({period})";
+ _p1a = (int)Math.Floor((period * 0.5) + 1);
+ _p1b = (int)Math.Ceiling(0.5 * period);
+ sma = new(_p1a);
+ trima = new(_p1b);
+
+ }
+ public TRIMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public TRIMA_Series() : this(period: 0, useNaN: false) { }
+ public TRIMA_Series(int period) : this(period: period, useNaN: false) { }
+ public TRIMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public TRIMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public TRIMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public TRIMA_Series(TSeries source) : this(source, 0, false) { }
+ public TRIMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+
+ var _sma = sma.Add(TValue, update);
+ var _trima = trima.Add(_sma, update);
+
+ var res = (_trima.t, Count < _period - 1 && _NaN ? double.NaN : _trima.v);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ sma.Reset();
+ trima.Reset();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/TRIX_Series.cs b/Calculations/_Updated/TRIX_Series.cs
index 30d9f58e..049c23da 100644
--- a/Calculations/_Updated/TRIX_Series.cs
+++ b/Calculations/_Updated/TRIX_Series.cs
@@ -1,118 +1,132 @@
-namespace QuanTAlib;
-
-using System;
-using System.Linq;
-
-/*
-TRIX: Triple Exponential Average Oscillator
- Developed by Jack Hutson in the early 1980s, the triple exponential average (TRIX)
- has become a popular technical analysis tool to aid chartists in spotting diversions
- and directional cues in stock trading patterns.
-
-Sources:
- https://www.investopedia.com/terms/t/trix.asp
-
- */
-
-public class TRIX_Series : TSeries {
- private readonly double _k;
- private readonly System.Collections.Generic.List _buffer1 = new();
- private readonly System.Collections.Generic.List _buffer2 = new();
- private readonly System.Collections.Generic.List _buffer3 = new();
- private double _lastema1, _lastema2, _lastema3;
- private double _llastema1, _llastema2, _llastema3;
- private int _len;
- private readonly bool _useSMA;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
-//core constructors
-
- public TRIX_Series(int period, bool useNaN, bool useSMA) {
- _period = period;
- _NaN = useNaN;
- _useSMA = useSMA;
- Name = $"TRIX({period})";
- _k = 2.0 / (_period + 1);
- _len = 0;
- _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = 0;
- }
- public TRIX_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public TRIX_Series() : this(0, false, true) {}
- public TRIX_Series(int period) : this(period, false, true) {}
- public TRIX_Series(TBars source) : this(source.Close, 0, false) {}
- public TRIX_Series(TBars source, int period) : this(source.Close, period, false) {}
- public TRIX_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {}
- public TRIX_Series(TSeries source, int period) : this(source, period, false, true) {}
- public TRIX_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {}
-
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, Double.NaN), update);
- }
- if (_len == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; }
- if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; }
- else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _len++;
- }
-
- double _ema1, _ema2, _ema3;
- if ((this.Count < _period) && _useSMA) {
- BufferTrim(_buffer1, TValue.v, _period, update);
- _ema1 = 0;
- for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; }
- _ema1 /= _buffer1.Count;
-
- BufferTrim(_buffer2, _ema1, _period, update);
- _ema2 = 0;
- for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; }
- _ema2 /= _buffer2.Count;
-
- BufferTrim(_buffer3, _ema2, _period, update);
- _ema3 = 0;
- for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; }
- _ema3 /= _buffer3.Count;
- }
- else {
- _ema1 = (TValue.v - _lastema1) * _k + _lastema1;
- _ema2 = (_ema1 - _lastema2) * _k + _lastema2;
- _ema3 = (_ema2 - _lastema3) * _k + _lastema3;
- }
- double _trix = 100 * (_ema3 - _lastema3) / _lastema3;
- _lastema1 = _ema1;
- _lastema2 = _ema2;
- _lastema3 = _ema3;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _trix);
- return base.Add(res, update);
- }
-
-//variation of Add()
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _len = 0;
- }
+namespace QuanTAlib;
+
+using System;
+using System.Linq;
+
+/*
+TRIX: Triple Exponential Average Oscillator
+ Developed by Jack Hutson in the early 1980s, the triple exponential average (TRIX)
+ has become a popular technical analysis tool to aid chartists in spotting diversions
+ and directional cues in stock trading patterns.
+
+Sources:
+ https://www.investopedia.com/terms/t/trix.asp
+
+ */
+
+public class TRIX_Series : TSeries
+{
+ private readonly double _k;
+ private readonly System.Collections.Generic.List _buffer1 = new();
+ private readonly System.Collections.Generic.List _buffer2 = new();
+ private readonly System.Collections.Generic.List _buffer3 = new();
+ private double _lastema1, _lastema2, _lastema3;
+ private double _llastema1, _llastema2, _llastema3;
+ private int _len;
+ private readonly bool _useSMA;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+
+ public TRIX_Series(int period, bool useNaN, bool useSMA)
+ {
+ _period = period;
+ _NaN = useNaN;
+ _useSMA = useSMA;
+ Name = $"TRIX({period})";
+ _k = 2.0 / (_period + 1);
+ _len = 0;
+ _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = 0;
+ }
+ public TRIX_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public TRIX_Series() : this(0, false, true) { }
+ public TRIX_Series(int period) : this(period, false, true) { }
+ public TRIX_Series(TBars source) : this(source.Close, 0, false) { }
+ public TRIX_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public TRIX_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public TRIX_Series(TSeries source, int period) : this(source, period, false, true) { }
+ public TRIX_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
+
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (double.IsNaN(TValue.v))
+ {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+ if (_len == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; }
+ if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; }
+ else
+ {
+ _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _len++;
+ }
+
+ double _ema1, _ema2, _ema3;
+ if ((this.Count < _period) && _useSMA)
+ {
+ BufferTrim(_buffer1, TValue.v, _period, update);
+ _ema1 = 0;
+ for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; }
+ _ema1 /= _buffer1.Count;
+
+ BufferTrim(_buffer2, _ema1, _period, update);
+ _ema2 = 0;
+ for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; }
+ _ema2 /= _buffer2.Count;
+
+ BufferTrim(_buffer3, _ema2, _period, update);
+ _ema3 = 0;
+ for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; }
+ _ema3 /= _buffer3.Count;
+ }
+ else
+ {
+ _ema1 = (TValue.v - _lastema1) * _k + _lastema1;
+ _ema2 = (_ema1 - _lastema2) * _k + _lastema2;
+ _ema3 = (_ema2 - _lastema3) * _k + _lastema3;
+ }
+ double _trix = 100 * (_ema3 - _lastema3) / _lastema3;
+ _lastema1 = _ema1;
+ _lastema2 = _ema2;
+ _lastema3 = _ema3;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _trix);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _len = 0;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/TR_Series.cs b/Calculations/_Updated/TR_Series.cs
index e3c61058..308e08e8 100644
--- a/Calculations/_Updated/TR_Series.cs
+++ b/Calculations/_Updated/TR_Series.cs
@@ -1,79 +1,91 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-TR: True Range
- True Range was introduced by J. Welles Wilder in his book New Concepts in Technical Trading Systems.
- It measures the daily range plus any gap from the closing price of the preceding day.
-
-Calculation:
- d1 = ABS(High - Low)
- d2 = ABS(High - Previous close)
- d3 = ABS(Previous close - Low)
- TR = MAX(d1,d2,d3)
-
-Sources:
- https://www.macroption.com/true-range/
-
- */
-
-public class TR_Series : TSeries {
- protected readonly TBars _data;
- private double _cm1, _cm1_o;
-
- //core constructors
- public TR_Series() {
- Name = $"TR()";
- _cm1 = _cm1_o = double.NaN;
- }
- public TR_Series(TBars source) {
- _data = source;
- Name = $"TR({(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _cm1 = _cm1_o = double.NaN;
- _data.Pub += Sub;
- Add(data: _data);
- }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
-
- if (update) {
- _cm1 = _cm1_o;
- }
- else {
- _cm1_o = _cm1;
- }
-
- if (_cm1 is double.NaN) {
- _cm1 = TBar.c;
- }
-
- double d1 = Math.Abs(TBar.h - TBar.l);
- double d2 = Math.Abs(_cm1 - TBar.h);
- double d3 = Math.Abs(_cm1 - TBar.l);
- _cm1 = TBar.c;
- var ret = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
- return base.Add(ret, update);
-
- }
-
- public new void Add(TBars data) {
- foreach (var item in data) { Add(item, false); }
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TBar: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TBar: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TBar: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _cm1 = _cm1_o = double.NaN;
- }
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+TR: True Range
+ True Range was introduced by J. Welles Wilder in his book New Concepts in Technical Trading Systems.
+ It measures the daily range plus any gap from the closing price of the preceding day.
+
+Calculation:
+ d1 = ABS(High - Low)
+ d2 = ABS(High - Previous close)
+ d3 = ABS(Previous close - Low)
+ TR = MAX(d1,d2,d3)
+
+Sources:
+ https://www.macroption.com/true-range/
+
+ */
+
+public class TR_Series : TSeries
+{
+ protected readonly TBars _data;
+ private double _cm1, _cm1_o;
+
+ //core constructors
+ public TR_Series()
+ {
+ Name = $"TR()";
+ _cm1 = _cm1_o = double.NaN;
+ }
+ public TR_Series(TBars source)
+ {
+ _data = source;
+ Name = $"TR({(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _cm1 = _cm1_o = double.NaN;
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
+ {
+
+ if (update)
+ {
+ _cm1 = _cm1_o;
+ }
+ else
+ {
+ _cm1_o = _cm1;
+ }
+
+ if (_cm1 is double.NaN)
+ {
+ _cm1 = TBar.c;
+ }
+
+ double d1 = Math.Abs(TBar.h - TBar.l);
+ double d2 = Math.Abs(_cm1 - TBar.h);
+ double d3 = Math.Abs(_cm1 - TBar.l);
+ _cm1 = TBar.c;
+ var ret = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
+ return base.Add(ret, update);
+
+ }
+
+ public new void Add(TBars data)
+ {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _cm1 = _cm1_o = double.NaN;
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/TSeries.cs b/Calculations/_Updated/TSeries.cs
index ccde468d..00ba50a2 100644
--- a/Calculations/_Updated/TSeries.cs
+++ b/Calculations/_Updated/TSeries.cs
@@ -1,103 +1,137 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Data;
-using System.Linq;
-
-/*
-TSeries is the cornerstone of all QuanTAlib classes.
- TSeries is a single List of tuples (time, value) and contains several operators, casts, overloads
- and other helpers that simplify usage of library.
- Think of TSeries as an equivalent of Numpy array.
-
- - includes Length property (to mimic array's method)
- - includes publishing and subscribing methods that attach to events
-
- */
-public class TSeriesEventArgs : EventArgs {
- public bool update { get; set; }
-}
-
-public class TSeries : List<(DateTime t, double v)> {
- private readonly (DateTime t, double v) Default = (DateTime.MinValue, double.NaN);
- public IEnumerable t => this.Select(item => item.t);
- public IEnumerable v => this.Select(item => item.v);
- public (DateTime t, double v) Last => Count > 0 ? this[^1] : Default;
-
- public int Length => Count;
- public string Name { get; set; }
-
- public TSeries() {
- this.Name = "data";
- }
-
- public TSeries(string Name) {
- this.Name = Name;
- }
-
- public virtual (DateTime t, double v) Add(double v, bool update = false) {
- return Add((t: Count == 0 ? DateTime.Today : this[^1].t.AddDays(1), v), update);
- }
-
- public virtual (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (update) {
- this[^1] = TValue;
- }
- else {
- base.Add(TValue);
- }
-
- OnEvent(update);
- return TValue;
- }
-
- public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
- if (update) {
- this[this.Count - 1] = (TBar.t, TBar.c);
- }
- else {
- base.Add((TBar.t, TBar.c));
- }
-
- OnEvent(update);
- return (TBar.t, TBar.c);
- }
-
- public virtual (DateTime t, double v) Add(TSeries data) {
- foreach (var item in data) { Add(item); }
- return data.Last;
- }
-
- public virtual (DateTime t, double v) Add(TBars data) {
- foreach (var item in data) { Add(item.c, false); }
- return (data.Last.t, data.Last.c);
- }
-
- public void Sub(object source, TSeriesEventArgs e) {
- var data = (TSeries) source;
- if (data == null) { return; }
- foreach (var item in data) { Add(item); }
- }
-
- public delegate void NewEventHandler(object source, TSeriesEventArgs args);
-
- public event NewEventHandler Pub;
-
- protected virtual void OnEvent(bool update = false)
- {
- Pub?.Invoke(this, new TSeriesEventArgs {update = update});
- }
-
- /// common helpers
- public static void BufferTrim(List buffer, double value, int period, bool update) {
- if (!update) {
- buffer.Add(value);
- if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); }
- return;
- }
- buffer[^1] = value;
- }
- public virtual void Reset() {
- }
-}
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Data;
+using System.Linq;
+
+/*
+TSeries is the cornerstone of all QuanTAlib classes.
+ TSeries is a single List of tuples (time, value) and contains several operators, casts, overloads
+ and other helpers that simplify usage of library.
+ Think of TSeries as an equivalent of Numpy array.
+
+ - includes Length property (to mimic array's method)
+ - includes publishing and subscribing methods that attach to events
+
+ */
+public class TSeriesEventArgs : EventArgs
+{
+ public bool update { get; set; }
+}
+
+public class TSeries : List<(DateTime t, double v)>
+{
+ private readonly (DateTime t, double v) Default = (DateTime.MinValue, double.NaN);
+ public IEnumerable t => this.Select(item => item.t);
+ public IEnumerable v => this.Select(item => item.v);
+ public (DateTime t, double v) Last => Count > 0 ? this[^1] : Default;
+
+ public int Length => Count;
+ public string Name { get; set; }
+ public int Keep = 0;
+
+ public TSeries()
+ {
+ this.Name = "data";
+ }
+
+ public TSeries(string Name)
+ {
+ this.Name = Name;
+ }
+
+ public virtual (DateTime t, double v) Add(double v, bool update = false)
+ {
+ return Add((t: Count == 0 ? DateTime.Today : this[^1].t.AddDays(1), v), update);
+ }
+
+ public virtual (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ if (update)
+ {
+ this[^1] = TValue;
+ }
+ else
+ {
+ base.Add(TValue);
+ }
+
+ OnEvent(update);
+ return TValue;
+ }
+
+ public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false)
+ {
+ if (update)
+ {
+ this[this.Count - 1] = (TBar.t, TBar.c);
+ }
+ else
+ {
+ base.Add((TBar.t, TBar.c));
+ }
+
+ OnEvent(update);
+ return (TBar.t, TBar.c);
+ }
+
+ public virtual (DateTime t, double v) Add(TSeries data)
+ {
+ foreach (var item in data) { Add(item); }
+ return data.Last;
+ }
+
+ public virtual (DateTime t, double v) Add(TBars data)
+ {
+ foreach (var item in data) { Add(item.c, false); }
+ return (data.Last.t, data.Last.c);
+ }
+
+ public void Sub(object source, TSeriesEventArgs e)
+ {
+ var data = (TSeries)source;
+ if (data == null) { return; }
+ foreach (var item in data) { Add(item); }
+ }
+
+ public delegate void NewEventHandler(object source, TSeriesEventArgs args);
+
+ public event NewEventHandler Pub;
+
+ protected virtual void OnEvent(bool update = false)
+ {
+ if (Keep > 0)
+ {
+ TrimToSize(keep: Keep);
+ }
+ Pub?.Invoke(this, new TSeriesEventArgs { update = update });
+ }
+
+ /// common helpers
+ public static void BufferTrim(List buffer, double value, int period, bool update)
+ {
+ if (!update)
+ {
+ buffer.Add(value);
+ if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); }
+ return;
+ }
+ buffer[^1] = value;
+ }
+ public virtual void Reset()
+ {
+ }
+
+ public void TrimToSize(int keep)
+ {
+ if (keep >= this.Count)
+ {
+ return; // No need to trim if the series is already smaller than or equal to n
+ }
+
+ // Remove elements from the beginning of the list
+ int elementsToRemove = this.Count - keep;
+ RemoveRange(0, elementsToRemove);
+ }
+}
diff --git a/Calculations/_Updated/VAR_Series.cs b/Calculations/_Updated/VAR_Series.cs
index 72562277..20b7a556 100644
--- a/Calculations/_Updated/VAR_Series.cs
+++ b/Calculations/_Updated/VAR_Series.cs
@@ -1,81 +1,90 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-VAR: Population Variance
- Population variance without Bessel's correction
-
-Sources:
- https://en.wikipedia.org/wiki/Variance
- Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
-
-Remark:
- VAR (Population Variance) is also known as a biased Sample Variance. For unbiased
- sample variance use SVAR instead.
-
- */
-
-public class VAR_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public VAR_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"VAR({period})";
- }
- public VAR_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public VAR_Series() : this(period: 0, useNaN: false) { }
- public VAR_Series(int period) : this(period: period, useNaN: false) { }
- public VAR_Series(TBars source) : this(source.Close, 0, false) { }
- public VAR_Series(TBars source, int period) : this(source.Close, period, false) { }
- public VAR_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public VAR_Series(TSeries source) : this(source, 0, false) { }
- public VAR_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _sma = _buffer.Average();
-
- double _pvar = 0;
- for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
- _pvar /= this._buffer.Count;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _pvar);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+VAR: Population Variance
+ Population variance without Bessel's correction
+
+Sources:
+ https://en.wikipedia.org/wiki/Variance
+ Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
+
+Remark:
+ VAR (Population Variance) is also known as a biased Sample Variance. For unbiased
+ sample variance use SVAR instead.
+
+ */
+
+public class VAR_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public VAR_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"VAR({period})";
+ }
+ public VAR_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public VAR_Series() : this(period: 0, useNaN: false) { }
+ public VAR_Series(int period) : this(period: period, useNaN: false) { }
+ public VAR_Series(TBars source) : this(source.Close, 0, false) { }
+ public VAR_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public VAR_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public VAR_Series(TSeries source) : this(source, 0, false) { }
+ public VAR_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _sma = _buffer.Average();
+
+ double _pvar = 0;
+ for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
+ _pvar /= this._buffer.Count;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _pvar);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/WMAPE_Series.cs b/Calculations/_Updated/WMAPE_Series.cs
index b0479cb8..7dfc95cb 100644
--- a/Calculations/_Updated/WMAPE_Series.cs
+++ b/Calculations/_Updated/WMAPE_Series.cs
@@ -1,82 +1,92 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-WMAPE: Weighted Mean Absolute Percentage Error
- Measures the size of the error in percentage terms. Improves problems with MAPE
- when there are zero or close-to-zero values because there would be a division by zero
- or values of MAPE tending to infinity.
-
-Sources:
- https://en.wikipedia.org/wiki/WMAPE
-
- */
-
-public class WMAPE_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public WMAPE_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"WMAPE({period})";
- }
- public WMAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public WMAPE_Series() : this(period: 0, useNaN: false) { }
- public WMAPE_Series(int period) : this(period: period, useNaN: false) { }
- public WMAPE_Series(TBars source) : this(source.Close, 0, false) { }
- public WMAPE_Series(TBars source, int period) : this(source.Close, period, false) { }
- public WMAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public WMAPE_Series(TSeries source) : this(source, 0, false) { }
- public WMAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
-
- double _sma = _buffer.Average();
-
- double _div = 0;
- double _wmape = 0;
- for (int i = 0; i < _buffer.Count; i++) {
- _wmape += Math.Abs(_buffer[i] - _sma);
- _div += Math.Abs(_buffer[i]);
- }
- _wmape = (_div != 0) ? _wmape / _div : double.PositiveInfinity;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wmape);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+WMAPE: Weighted Mean Absolute Percentage Error
+ Measures the size of the error in percentage terms. Improves problems with MAPE
+ when there are zero or close-to-zero values because there would be a division by zero
+ or values of MAPE tending to infinity.
+
+Sources:
+ https://en.wikipedia.org/wiki/WMAPE
+
+ */
+
+public class WMAPE_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public WMAPE_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"WMAPE({period})";
+ }
+ public WMAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public WMAPE_Series() : this(period: 0, useNaN: false) { }
+ public WMAPE_Series(int period) : this(period: period, useNaN: false) { }
+ public WMAPE_Series(TBars source) : this(source.Close, 0, false) { }
+ public WMAPE_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public WMAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public WMAPE_Series(TSeries source) : this(source, 0, false) { }
+ public WMAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+
+ double _sma = _buffer.Average();
+
+ double _div = 0;
+ double _wmape = 0;
+ for (int i = 0; i < _buffer.Count; i++)
+ {
+ _wmape += Math.Abs(_buffer[i] - _sma);
+ _div += Math.Abs(_buffer[i]);
+ }
+ _wmape = (_div != 0) ? _wmape / _div : double.PositiveInfinity;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wmape);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/WMA_Series.cs b/Calculations/_Updated/WMA_Series.cs
index 48679fe4..957660fd 100644
--- a/Calculations/_Updated/WMA_Series.cs
+++ b/Calculations/_Updated/WMA_Series.cs
@@ -1,104 +1,117 @@
-namespace QuanTAlib;
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-/*
-WMA: (linearly) Weighted Moving Average
- The weights are linearly decreasing over the period and the most recent data has
- the heaviest weight.
-
-Sources:
- https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/weighted-moving-average-wma/
- https://www.technicalindicators.net/indicators-technical-analysis/83-moving-averages-simple-exponential-weighted
-
- */
-
-public class WMA_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- private System.Collections.Generic.List _weights;
- protected int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- protected int _len;
- public int Len {
- get { return _len; }
- set { _len = value; }
- }
-
- //core constructors
- public WMA_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"WMA({period})";
- _len = 1;
- _weights = CalculateWeights(_period);
- }
- public WMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public WMA_Series() : this(period: 0, useNaN: false) { }
- public WMA_Series(int period) : this(period: period, useNaN: false) { }
- public WMA_Series(TBars source) : this(source.Close, 0, false) { }
- public WMA_Series(TBars source, int period) : this(source.Close, period, false) { }
- public WMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public WMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) {
- BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
- if (_period == 0) {
- _weights = CalculateWeights(_len);
- _len++;
- }
- double _wma = 0;
- double totalWeights = (_buffer.Count * (_buffer.Count + 1)) * 0.5;
- object lockObj = new object();
- Parallel.For(0, _buffer.Count, i =>
- {
- double temp = _buffer[i] * this._weights[i];
- lock (lockObj) { _wma += temp; }
- });
- _wma /= totalWeights;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wma);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //calculating weights
- private static List CalculateWeights(int period) {
- List weights = new List(period);
- for (int i = 0; i < period; i++) {
- weights.Add(i + 1);
- }
- return weights;
- }
-
- //reset calculation
- public override void Reset() {
- _len = 0;
- _weights = CalculateWeights(_period);
- _buffer.Clear();
- }
+namespace QuanTAlib;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+/*
+WMA: (linearly) Weighted Moving Average
+ The weights are linearly decreasing over the period and the most recent data has
+ the heaviest weight.
+
+Sources:
+ https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/weighted-moving-average-wma/
+ https://www.technicalindicators.net/indicators-technical-analysis/83-moving-averages-simple-exponential-weighted
+
+ */
+
+public class WMA_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ private System.Collections.Generic.List _weights;
+ protected int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ protected int _len;
+ public int Len
+ {
+ get { return _len; }
+ set { _len = value; }
+ }
+
+ //core constructors
+ public WMA_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"WMA({period})";
+ _len = 1;
+ _weights = CalculateWeights(_period);
+ }
+ public WMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public WMA_Series() : this(period: 0, useNaN: false) { }
+ public WMA_Series(int period) : this(period: period, useNaN: false) { }
+ public WMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public WMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public WMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public WMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+ if (_period == 0)
+ {
+ _weights = CalculateWeights(_len);
+ _len++;
+ }
+ double _wma = 0;
+ double totalWeights = (_buffer.Count * (_buffer.Count + 1)) * 0.5;
+ object lockObj = new object();
+ Parallel.For(0, _buffer.Count, i =>
+ {
+ double temp = _buffer[i] * this._weights[i];
+ lock (lockObj) { _wma += temp; }
+ });
+ _wma /= totalWeights;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wma);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //calculating weights
+ private static List CalculateWeights(int period)
+ {
+ List weights = new List(period);
+ for (int i = 0; i < period; i++)
+ {
+ weights.Add(i + 1);
+ }
+ return weights;
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _len = 0;
+ _weights = CalculateWeights(_period);
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/ZLEMA_Series.cs b/Calculations/_Updated/ZLEMA_Series.cs
index 512b5cc0..d0c2158d 100644
--- a/Calculations/_Updated/ZLEMA_Series.cs
+++ b/Calculations/_Updated/ZLEMA_Series.cs
@@ -1,95 +1,105 @@
-namespace QuanTAlib;
-
-using System;
-using System.Linq;
-
-/*
-ZLEMA: Zero Lag Exponential Moving Average
- The Zero lag exponential moving average (ZLEMA) indicator was created by John
- Ehlers and Ric Way.
-
-The formula for a given N-Day period and for a given Data series is:
- Lag = (Period-1)/2
- Ema Data = {Data+(Data-Data(Lag days ago))
- ZLEMA = EMA (EmaData,Period)
-
-Remark:
- The idea is do a regular exponential moving average (EMA) calculation but on a
- de-lagged data instead of doing it on the regular data. Data is de-lagged by
- removing the data from "lag" days ago thus removing (or attempting to remove)
- the cumulative lag effect of the moving average.
-
- */
-
-public class ZLEMA_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- private int _len;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private readonly EMA_Series _ema;
-
- //core constructor
- public ZLEMA_Series(int period, bool useNaN, bool useSMA) {
- _period = period;
- _NaN = useNaN;
- Name = $"ZLEMA({period})";
- _len = 1;
- _ema = new(period);
- }
- //generic constructors (source)
-
- public ZLEMA_Series() : this(0, false, true) { }
- public ZLEMA_Series(int period) : this(period, false, true) { }
- public ZLEMA_Series(TBars source) : this(source.Close, 0, false) { }
- public ZLEMA_Series(TBars source, int period) : this(source.Close, period, false) { }
- public ZLEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public ZLEMA_Series(TSeries source, int period) : this(source, period, false, true) { }
- public ZLEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
- public ZLEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
-
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
- int _lag;
- if (_period == 0) {
- _lag = (int)((_len - 1) * 0.5);
- _len++;
- }
- else { _lag = (int)((_period - 1) * 0.5); }
- _lag = Math.Min(_lag, _buffer.Count - 1);
- _lag = Math.Max(_lag, 0) + 1;
- double _zlValue = 2 * TValue.v - _buffer[^_lag];
- double _zlema = _ema.Add((TValue.t, _zlValue), update).v;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlema);
- return base.Add(res, update);
- }
-
- //variation of Add()
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
-
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- _ema.Reset();
- }
+namespace QuanTAlib;
+
+using System;
+using System.Linq;
+
+/*
+ZLEMA: Zero Lag Exponential Moving Average
+ The Zero lag exponential moving average (ZLEMA) indicator was created by John
+ Ehlers and Ric Way.
+
+The formula for a given N-Day period and for a given Data series is:
+ Lag = (Period-1)/2
+ Ema Data = {Data+(Data-Data(Lag days ago))
+ ZLEMA = EMA (EmaData,Period)
+
+Remark:
+ The idea is do a regular exponential moving average (EMA) calculation but on a
+ de-lagged data instead of doing it on the regular data. Data is de-lagged by
+ removing the data from "lag" days ago thus removing (or attempting to remove)
+ the cumulative lag effect of the moving average.
+
+ */
+
+public class ZLEMA_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ private int _len;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private readonly EMA_Series _ema;
+
+ //core constructor
+ public ZLEMA_Series(int period, bool useNaN, bool useSMA)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"ZLEMA({period})";
+ _len = 1;
+ _ema = new(period);
+ }
+ //generic constructors (source)
+
+ public ZLEMA_Series() : this(0, false, true) { }
+ public ZLEMA_Series(int period) : this(period, false, true) { }
+ public ZLEMA_Series(TBars source) : this(source.Close, 0, false) { }
+ public ZLEMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public ZLEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public ZLEMA_Series(TSeries source, int period) : this(source, period, false, true) { }
+ public ZLEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
+ public ZLEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+ int _lag;
+ if (_period == 0)
+ {
+ _lag = (int)((_len - 1) * 0.5);
+ _len++;
+ }
+ else { _lag = (int)((_period - 1) * 0.5); }
+ _lag = Math.Min(_lag, _buffer.Count - 1);
+ _lag = Math.Max(_lag, 0) + 1;
+ double _zlValue = 2 * TValue.v - _buffer[^_lag];
+ double _zlema = _ema.Add((TValue.t, _zlValue), update).v;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlema);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ _ema.Reset();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/ZL_Series.cs b/Calculations/_Updated/ZL_Series.cs
index 0f6af1aa..f7f6088b 100644
--- a/Calculations/_Updated/ZL_Series.cs
+++ b/Calculations/_Updated/ZL_Series.cs
@@ -1,90 +1,100 @@
-namespace QuanTAlib;
-
-using System;
-using System.Linq;
-
-/*
-ZL: Zero Lag
- Data is de-lagged by removing the data from “lag” days ago, thus removing
- (or attempting to) the cumulative effect of the moving average.
-
-Calculation:
- Lag = (Period-1)/2
- ZL = Data + (Data - Data(Lag days ago) )
-
-Sources:
- https://mudrex.com/blog/zero-lag-ema-trading-strategy/
-
- */
-
-public class ZL_Series: TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- private int _len;
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- private readonly EMA_Series _ema;
-
- //core constructor
- public ZL_Series(int period, bool useNaN, bool useSMA) {
- _period = period;
- _NaN = useNaN;
- Name = $"ZL({period})";
- _len = 1;
- _ema = new(period);
- }
- //generic constructors (source)
-
- public ZL_Series() : this(0, false, true) { }
- public ZL_Series(int period) : this(period, false, true) { }
- public ZL_Series(TBars source) : this(source.Close, 0, false) { }
- public ZL_Series(TBars source, int period) : this(source.Close, period, false) { }
- public ZL_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public ZL_Series(TSeries source, int period) : this(source, period, false, true) { }
- public ZL_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
- public ZL_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
-
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
- int _lag;
- if (_period == 0) {
- _lag = (int)((_len - 1) * 0.5);
- _len++;
- }
- else { _lag = (int)((_period - 1) * 0.5); }
- _lag = Math.Min(_lag, _buffer.Count - 1);
- _lag = Math.Max(_lag, 0) + 1;
- double _zlValue = 2 * TValue.v - _buffer[^_lag];
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlValue);
- return base.Add(res, update);
- }
-
- //variation of Add()
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- _ema.Reset();
- }
+namespace QuanTAlib;
+
+using System;
+using System.Linq;
+
+/*
+ZL: Zero Lag
+ Data is de-lagged by removing the data from “lag” days ago, thus removing
+ (or attempting to) the cumulative effect of the moving average.
+
+Calculation:
+ Lag = (Period-1)/2
+ ZL = Data + (Data - Data(Lag days ago) )
+
+Sources:
+ https://mudrex.com/blog/zero-lag-ema-trading-strategy/
+
+ */
+
+public class ZL_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ private int _len;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private readonly EMA_Series _ema;
+
+ //core constructor
+ public ZL_Series(int period, bool useNaN, bool useSMA)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"ZL({period})";
+ _len = 1;
+ _ema = new(period);
+ }
+ //generic constructors (source)
+
+ public ZL_Series() : this(0, false, true) { }
+ public ZL_Series(int period) : this(period, false, true) { }
+ public ZL_Series(TBars source) : this(source.Close, 0, false) { }
+ public ZL_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public ZL_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public ZL_Series(TSeries source, int period) : this(source, period, false, true) { }
+ public ZL_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { }
+ public ZL_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+ int _lag;
+ if (_period == 0)
+ {
+ _lag = (int)((_len - 1) * 0.5);
+ _len++;
+ }
+ else { _lag = (int)((_period - 1) * 0.5); }
+ _lag = Math.Min(_lag, _buffer.Count - 1);
+ _lag = Math.Max(_lag, 0) + 1;
+ double _zlValue = 2 * TValue.v - _buffer[^_lag];
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlValue);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ _ema.Reset();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/ZSCORE_Series.cs b/Calculations/_Updated/ZSCORE_Series.cs
index c3ab4288..d8e5699d 100644
--- a/Calculations/_Updated/ZSCORE_Series.cs
+++ b/Calculations/_Updated/ZSCORE_Series.cs
@@ -1,88 +1,97 @@
-using System.Linq;
-
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-
-/*
-ZSCORE: number of standard deviations from SMA
- Z-score describes a value's relationship to the mean of a series, as measured in
- terms of standard deviations from the mean. If a Z-score is 0, it indicates that
- the data point's score is identical to the mean score. A Z-score of 1.0 would
- indicate a value that is one standard deviation from the mean. Z-scores may be
- positive or negative, with a positive value indicating the score is above the
- mean and a negative score indicating it is below the mean.
-
-Sources:
- https://en.wikipedia.org/wiki/Z-score
- https://www.investopedia.com/terms/z/zscore.asp
-
-Calculation:
- std = std * STDEV(close, length)
- mean = SMA(close, length)
- ZSCORE = (close - mean) / std
-
- */
-
-public class ZSCORE_Series : TSeries {
- private readonly System.Collections.Generic.List _buffer = new();
- protected readonly int _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- //core constructors
- public ZSCORE_Series(int period, bool useNaN) {
- _period = period;
- _NaN = useNaN;
- Name = $"ZSCORE({period})";
- }
- public ZSCORE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
- _data = source;
- Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
- _data.Pub += Sub;
- Add(_data);
- }
- public ZSCORE_Series() : this(period: 0, useNaN: false) { }
- public ZSCORE_Series(int period) : this(period: period, useNaN: false) { }
- public ZSCORE_Series(TBars source) : this(source.Close, 0, false) { }
- public ZSCORE_Series(TBars source, int period) : this(source.Close, period, false) { }
- public ZSCORE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public ZSCORE_Series(TSeries source) : this(source, 0, false) { }
- public ZSCORE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
-
- //////////////////
- // core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
- double _sma = _buffer.Average();
-
- double _pvar = 0;
- for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
- _pvar /= this._buffer.Count;
- double _psdev = Math.Sqrt(_pvar);
- double _zscore = (_psdev == 0) ? 1 : (TValue.v - _sma) / _psdev;
-
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zscore);
- return base.Add(res, update);
- }
-
- public override (DateTime t, double v) Add(TSeries data) {
- if (data == null) { return (DateTime.Today, Double.NaN); }
- foreach (var item in data) { Add(item, false); }
- return _data.Last;
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
- public (DateTime t, double v) Add() {
- return Add(TValue: _data.Last, update: false);
- }
- private new void Sub(object source, TSeriesEventArgs e) {
- Add(TValue: _data.Last, update: e.update);
- }
-
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- }
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+ZSCORE: number of standard deviations from SMA
+ Z-score describes a value's relationship to the mean of a series, as measured in
+ terms of standard deviations from the mean. If a Z-score is 0, it indicates that
+ the data point's score is identical to the mean score. A Z-score of 1.0 would
+ indicate a value that is one standard deviation from the mean. Z-scores may be
+ positive or negative, with a positive value indicating the score is above the
+ mean and a negative score indicating it is below the mean.
+
+Sources:
+ https://en.wikipedia.org/wiki/Z-score
+ https://www.investopedia.com/terms/z/zscore.asp
+
+Calculation:
+ std = std * STDEV(close, length)
+ mean = SMA(close, length)
+ ZSCORE = (close - mean) / std
+
+ */
+
+public class ZSCORE_Series : TSeries
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ //core constructors
+ public ZSCORE_Series(int period, bool useNaN)
+ {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"ZSCORE({period})";
+ }
+ public ZSCORE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN)
+ {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public ZSCORE_Series() : this(period: 0, useNaN: false) { }
+ public ZSCORE_Series(int period) : this(period: period, useNaN: false) { }
+ public ZSCORE_Series(TBars source) : this(source.Close, 0, false) { }
+ public ZSCORE_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public ZSCORE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public ZSCORE_Series(TSeries source) : this(source, 0, false) { }
+ public ZSCORE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
+ {
+ BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
+ double _sma = _buffer.Average();
+
+ double _pvar = 0;
+ for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
+ _pvar /= this._buffer.Count;
+ double _psdev = Math.Sqrt(_pvar);
+ double _zscore = (_psdev == 0) ? 1 : (TValue.v - _sma) / _psdev;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zscore);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data)
+ {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update)
+ {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add()
+ {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e)
+ {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset()
+ {
+ _buffer.Clear();
+ }
}
\ No newline at end of file
diff --git a/Indicators/Charts/2MACross_chart.cs b/Indicators/Charts/2MACross_chart.cs
index 2bc81b8e..19ead156 100644
--- a/Indicators/Charts/2MACross_chart.cs
+++ b/Indicators/Charts/2MACross_chart.cs
@@ -1,278 +1,298 @@
-using System;
-using System.Drawing;
-using System.Linq;
-using TradingPlatform.BusinessLayer;
-namespace QuanTAlib;
-
-public class MovingAverage_chart : Indicator {
- #region Parameters
- [InputParameter("MA1: Type:", 0, variants: new object[]
- { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
- "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
- private int MA1type = 15;
-
- [InputParameter("MA1: Smoothing period:", 1, 1, 999, 1, 1)]
- private int MA1Period = 10;
-
- [InputParameter("MA1: Data source:", 2, variants: new object[]
- { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
- "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
- private int MA1DataSource = 3;
-
- [InputParameter("MA2: Type:", 3, variants: new object[]
- { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
- "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
- private int MA2type = 16;
-
- [InputParameter("MA2: Smoothing period:", 4, 1, 999, 1, 1)]
- private int MA2Period = 50;
-
- [InputParameter("MA2: Data source:", 5, variants: new object[]
- { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
- "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
- private int MA2DataSource = 8;
-
- [InputParameter("Long trades", 6)]
- private bool LongTrades = true;
-
- [InputParameter("Short trades", 6)]
- private bool ShortTrades = true;
-
- #endregion Parameters
-
- protected HistoricalData History;
- private TBars bars;
-
- ///////
- private TSeries MA1, MA2;
- private CROSS_Series trades;
- private COMPARE_Series overunder;
-
- ///////
-
- public MovingAverage_chart() {
- this.SeparateWindow = false;
- this.Name = "MAs Crossover";
- this.AddLineSeries("MA1", Color.LimeGreen, 2, LineStyle.Solid);
- this.AddLineSeries("MA2", Color.OrangeRed, 2, LineStyle.Solid);
- }
-
- protected override void OnInit() {
- this.bars = new();
- this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
- for (int i = this.History.Count - 1; i >= 0; i--) {
- var rec = this.History[i, SeekOriginHistory.Begin];
- bars.Add(rec.TimeLeft, rec[PriceType.Open],
- rec[PriceType.High], rec[PriceType.Low],
- rec[PriceType.Close], rec[PriceType.Volume]);
- }
- this.Name = "MAs Cross: [ ";
- switch (MA1type) {
- case 0:
- MA1 = new SMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"SMA";
- break;
- case 1:
- MA1 = new EMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"EMA";
- break;
- case 2:
- MA1 = new WMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"WMA";
- break;
- case 3:
- MA1 = new T3_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"T3";
- break;
- case 4:
- MA1 = new SMMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"SMMA";
- break;
- case 5:
- MA1 = new TRIMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"TRIMA";
- break;
- case 6:
- MA1 = new DWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"DWMA";
- break;
- case 7:
- MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period);
- this.Name += $"FWMA";
- break;
- case 8:
- MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"DEMA";
- break;
- case 9:
- MA1 = new TEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"TEMA";
- break;
- case 10:
- MA1 = new ALMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"ALMA";
- break;
- case 11:
- MA1 = new HMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"HMA";
- break;
- case 12:
- MA1 = new HEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"HEMA";
- break;
- case 13:
- double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA1Period);
- MA1 = new MAMA_Series(source: bars.Select(this.MA1DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
- this.Name += $"MAMA";
- break;
- case 14:
- MA1 = new KAMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"KAMA";
- break;
- case 15:
- MA1 = new ZLEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"ZLEMA";
- break;
- default:
- MA1 = new JMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"JMA";
- break;
- }
-
- this.Name = this.Name + $" ({MA1Period}:{TBars.SelectStr(this.MA1DataSource)}) : ";
-
- switch (MA2type) {
- case 0:
- MA2 = new SMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"SMA";
- break;
- case 1:
- MA2 = new EMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"EMA";
- break;
- case 2:
- MA2 = new WMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"WMA";
- break;
- case 3:
- MA2 = new T3_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"T3";
- break;
- case 4:
- MA2 = new SMMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"SMMA";
- break;
- case 5:
- MA2 = new TRIMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"TRIMA";
- break;
- case 6:
- MA2 = new DWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"DWMA";
- break;
- case 7:
- MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period);
- this.Name += $"FWMA";
- break;
- case 8:
- MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"DEMA";
- break;
- case 9:
- MA2 = new TEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"TEMA";
- break;
- case 10:
- MA2 = new ALMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"ALMA";
- break;
- case 11:
- MA2 = new HMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"HMA";
- break;
- case 12:
- MA2 = new HEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"HEMA";
- break;
- case 13:
- double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA2Period);
- MA2 = new MAMA_Series(source: bars.Select(this.MA2DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
- this.Name += $"MAMA";
- break;
- case 14:
- MA2 = new KAMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"KAMA";
- break;
- case 15:
- MA2 = new ZLEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"ZLEMA";
- break;
- default:
- MA2 = new JMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"JMA";
- break;
- }
- this.Name += $"({MA2Period}:{TBars.SelectStr(this.MA2DataSource)}) ]";
-
- overunder = new(MA1, MA2);
- trades = new(MA1, MA2);
- }
-
- protected override void OnUpdate(UpdateArgs args) {
- bool update = !(args.Reason == UpdateReason.NewBar ||
- args.Reason == UpdateReason.HistoricalBar);
- this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
- this.GetPrice(PriceType.High),
- this.GetPrice(PriceType.Low),
- this.GetPrice(PriceType.Close),
- this.GetPrice(PriceType.Volume), update);
- this.SetValue(this.MA1[^1].v, lineIndex: 0);
- this.SetValue(this.MA2[^1].v, lineIndex: 1);
-
- if (trades[^1].v == 1) {
- this.EndCloud(0, 1, Color.Empty);
- if (LongTrades) {
- this.LinesSeries[0].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.UpArrow));
- this.BeginCloud(0, 1, Color.FromArgb(127, Color.Green));
- }
- if (ShortTrades) {
- this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow));
- }
- }
- if (trades[^1].v == -1) {
- this.EndCloud(0, 1, Color.Empty);
- if (ShortTrades) {
- this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.UpArrow));
- this.BeginCloud(0, 1, Color.FromArgb(127, Color.Red));
- }
- if (LongTrades) {
- this.LinesSeries[0].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
- }
- }
- }
- public override void OnPaintChart(PaintChartEventArgs args) {
- base.OnPaintChart(args);
- if (this.CurrentChart == null) {return;}
- Graphics graphics = args.Graphics;
- var mainWindow = this.CurrentChart.MainWindow;
- int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
- int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
- int historycount = HistoricalData.Count;
- int ymax = mainWindow.ClientRectangle.Height;
- int xmax = mainWindow.ClientRectangle.Width;
-
- /*
- for (int i = leftIndex; i <= rightIndex; i++) {
- int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
- int width = this.CurrentChart.BarsWidth;
- int height = (int)((equity[i+historycount].v) *proportion);
-
- Brush bb = Brushes.DarkSlateGray;
- bb = (overunder[i+historycount].v>0 && LongTrades)? Brushes.Green : bb;
- bb = (overunder[i + historycount].v < 0 && ShortTrades) ? Brushes.Red : bb;
-
- graphics.FillRectangle(bb, xi, ymax - height, width, height);
- }
- */
- }
-}
+using System;
+using System.Drawing;
+using System.Linq;
+using TradingPlatform.BusinessLayer;
+namespace QuanTAlib;
+
+public class MovingAverage_chart : Indicator
+{
+ #region Parameters
+ [InputParameter("MA1: Type:", 0, variants: new object[]
+ { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
+ "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
+ private int MA1type = 15;
+
+ [InputParameter("MA1: Smoothing period:", 1, 1, 999, 1, 1)]
+ private int MA1Period = 10;
+
+ [InputParameter("MA1: Data source:", 2, variants: new object[]
+ { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
+ "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
+ private int MA1DataSource = 3;
+
+ [InputParameter("MA2: Type:", 3, variants: new object[]
+ { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
+ "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
+ private int MA2type = 16;
+
+ [InputParameter("MA2: Smoothing period:", 4, 1, 999, 1, 1)]
+ private int MA2Period = 50;
+
+ [InputParameter("MA2: Data source:", 5, variants: new object[]
+ { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
+ "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
+ private int MA2DataSource = 8;
+
+ [InputParameter("Long trades", 6)]
+ private bool LongTrades = true;
+
+ [InputParameter("Short trades", 6)]
+ private bool ShortTrades = true;
+
+ #endregion Parameters
+
+ protected HistoricalData History;
+ private TBars bars;
+
+ ///////
+ private TSeries MA1, MA2;
+ private CROSS_Series trades;
+ private COMPARE_Series overunder;
+
+ ///////
+
+ public MovingAverage_chart()
+ {
+ this.SeparateWindow = false;
+ this.Name = "MAs Crossover";
+ this.AddLineSeries("MA1", Color.LimeGreen, 2, LineStyle.Solid);
+ this.AddLineSeries("MA2", Color.OrangeRed, 2, LineStyle.Solid);
+ }
+
+ protected override void OnInit()
+ {
+ this.bars = new();
+ this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
+ for (int i = this.History.Count - 1; i >= 0; i--)
+ {
+ var rec = this.History[i, SeekOriginHistory.Begin];
+ bars.Add(rec.TimeLeft, rec[PriceType.Open],
+ rec[PriceType.High], rec[PriceType.Low],
+ rec[PriceType.Close], rec[PriceType.Volume]);
+ }
+ this.Name = "MAs Cross: [ ";
+ switch (MA1type)
+ {
+ case 0:
+ MA1 = new SMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"SMA";
+ break;
+ case 1:
+ MA1 = new EMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"EMA";
+ break;
+ case 2:
+ MA1 = new WMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"WMA";
+ break;
+ case 3:
+ MA1 = new T3_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"T3";
+ break;
+ case 4:
+ MA1 = new SMMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"SMMA";
+ break;
+ case 5:
+ MA1 = new TRIMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"TRIMA";
+ break;
+ case 6:
+ MA1 = new DWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"DWMA";
+ break;
+ case 7:
+ MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period);
+ this.Name += $"FWMA";
+ break;
+ case 8:
+ MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"DEMA";
+ break;
+ case 9:
+ MA1 = new TEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"TEMA";
+ break;
+ case 10:
+ MA1 = new ALMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"ALMA";
+ break;
+ case 11:
+ MA1 = new HMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"HMA";
+ break;
+ case 12:
+ MA1 = new HEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"HEMA";
+ break;
+ case 13:
+ double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA1Period);
+ MA1 = new MAMA_Series(source: bars.Select(this.MA1DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
+ this.Name += $"MAMA";
+ break;
+ case 14:
+ MA1 = new KAMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"KAMA";
+ break;
+ case 15:
+ MA1 = new ZLEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"ZLEMA";
+ break;
+ default:
+ MA1 = new JMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"JMA";
+ break;
+ }
+
+ this.Name = this.Name + $" ({MA1Period}:{TBars.SelectStr(this.MA1DataSource)}) : ";
+
+ switch (MA2type)
+ {
+ case 0:
+ MA2 = new SMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"SMA";
+ break;
+ case 1:
+ MA2 = new EMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"EMA";
+ break;
+ case 2:
+ MA2 = new WMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"WMA";
+ break;
+ case 3:
+ MA2 = new T3_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"T3";
+ break;
+ case 4:
+ MA2 = new SMMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"SMMA";
+ break;
+ case 5:
+ MA2 = new TRIMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"TRIMA";
+ break;
+ case 6:
+ MA2 = new DWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"DWMA";
+ break;
+ case 7:
+ MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period);
+ this.Name += $"FWMA";
+ break;
+ case 8:
+ MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"DEMA";
+ break;
+ case 9:
+ MA2 = new TEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"TEMA";
+ break;
+ case 10:
+ MA2 = new ALMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"ALMA";
+ break;
+ case 11:
+ MA2 = new HMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"HMA";
+ break;
+ case 12:
+ MA2 = new HEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"HEMA";
+ break;
+ case 13:
+ double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA2Period);
+ MA2 = new MAMA_Series(source: bars.Select(this.MA2DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
+ this.Name += $"MAMA";
+ break;
+ case 14:
+ MA2 = new KAMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"KAMA";
+ break;
+ case 15:
+ MA2 = new ZLEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"ZLEMA";
+ break;
+ default:
+ MA2 = new JMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"JMA";
+ break;
+ }
+ this.Name += $"({MA2Period}:{TBars.SelectStr(this.MA2DataSource)}) ]";
+
+ int maxKeep = Math.Max(Math.Max(this.MA1Period, this.MA2Period), 100);
+ MA1.Keep = maxKeep;
+ MA2.Keep = maxKeep;
+ trades.Keep = maxKeep;
+ overunder.Keep = maxKeep;
+
+ overunder = new(MA1, MA2);
+ trades = new(MA1, MA2);
+ }
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ bool update = !(args.Reason == UpdateReason.NewBar ||
+ args.Reason == UpdateReason.HistoricalBar);
+ this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
+ this.GetPrice(PriceType.High),
+ this.GetPrice(PriceType.Low),
+ this.GetPrice(PriceType.Close),
+ this.GetPrice(PriceType.Volume), update);
+ this.SetValue(this.MA1[^1].v, lineIndex: 0);
+ this.SetValue(this.MA2[^1].v, lineIndex: 1);
+
+ if (trades[^1].v == 1)
+ {
+ this.EndCloud(0, 1, Color.Empty);
+ if (LongTrades)
+ {
+ this.LinesSeries[0].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.UpArrow));
+ this.BeginCloud(0, 1, Color.FromArgb(127, Color.Green));
+ }
+ if (ShortTrades)
+ {
+ this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow));
+ }
+ }
+ if (trades[^1].v == -1)
+ {
+ this.EndCloud(0, 1, Color.Empty);
+ if (ShortTrades)
+ {
+ this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.UpArrow));
+ this.BeginCloud(0, 1, Color.FromArgb(127, Color.Red));
+ }
+ if (LongTrades)
+ {
+ this.LinesSeries[0].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
+ }
+ }
+ }
+ public override void OnPaintChart(PaintChartEventArgs args)
+ {
+ base.OnPaintChart(args);
+ if (this.CurrentChart == null) { return; }
+ Graphics graphics = args.Graphics;
+ var mainWindow = this.CurrentChart.MainWindow;
+ int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
+ int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
+ int historycount = HistoricalData.Count;
+ int ymax = mainWindow.ClientRectangle.Height;
+ int xmax = mainWindow.ClientRectangle.Width;
+
+ /*
+ for (int i = leftIndex; i <= rightIndex; i++) {
+ int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
+ int width = this.CurrentChart.BarsWidth;
+ int height = (int)((equity[i+historycount].v) *proportion);
+
+ Brush bb = Brushes.DarkSlateGray;
+ bb = (overunder[i+historycount].v>0 && LongTrades)? Brushes.Green : bb;
+ bb = (overunder[i + historycount].v < 0 && ShortTrades) ? Brushes.Red : bb;
+
+ graphics.FillRectangle(bb, xi, ymax - height, width, height);
+ }
+ */
+ }
+}
diff --git a/Indicators/Charts/2MASlope_chart.cs b/Indicators/Charts/2MASlope_chart.cs
index 547dc860..c031e513 100644
--- a/Indicators/Charts/2MASlope_chart.cs
+++ b/Indicators/Charts/2MASlope_chart.cs
@@ -1,298 +1,320 @@
-using System;
-using System.Drawing;
-using System.Linq;
-using TradingPlatform.BusinessLayer;
-namespace QuanTAlib;
-
-public class MovingAverageSlope_chart : Indicator {
- #region Parameters
- [InputParameter("MA1: Type:", 0, variants: new object[]
- { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
- "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
- private int MA1type = 16;
-
- [InputParameter("MA1: Smoothing period:", 1, 1, 999, 1, 1)]
- private int MA1Period = 10;
-
- [InputParameter("MA1: Data source:", 2, variants: new object[]
- { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
- "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
- private int MA1DataSource = 3;
-
- [InputParameter("MA2: Type:", 3, variants: new object[]
- { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
- "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
- private int MA2type = 6;
-
- [InputParameter("MA2: Smoothing period:", 4, 1, 999, 1, 1)]
- private int MA2Period = 50;
-
- [InputParameter("MA2: Data source:", 5, variants: new object[]
- { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
- "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
- private int MA2DataSource = 8;
-
- [InputParameter("Data required for slope calc:", 6, 2, 10, 1, 1)]
- private int SlopePeriod = 3;
-
- [InputParameter("Long trades", 7)]
- private bool LongTrades = true;
-
- [InputParameter("Short trades", 8)]
- private bool ShortTrades;
-
- #endregion Parameters
-
- protected HistoricalData History;
- private TBars bars;
-
- ///////
- private TSeries MA1, MA2;
- private SLOPE_Series sMA1, sMA2;
- private CROSS_Series sig1, sig2;
-
- private bool inLong, inShort;
- ///////
-
- public MovingAverageSlope_chart() {
- this.SeparateWindow = false;
- this.Name = "Slopes convergence";
- this.AddLineSeries("MA1", Color.DarkSlateGray, 2, LineStyle.Solid);
- this.AddLineSeries("MA2", Color.DarkSlateGray, 2, LineStyle.Solid);
- }
-
- protected override void OnInit() {
- this.bars = new();
- this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
- for (int i = this.History.Count - 1; i >= 0; i--) {
- var rec = this.History[i, SeekOriginHistory.Begin];
- bars.Add(rec.TimeLeft, rec[PriceType.Open],
- rec[PriceType.High], rec[PriceType.Low],
- rec[PriceType.Close], rec[PriceType.Volume]);
- }
- this.Name = "Slopes convergence: [ ";
- switch (MA1type) {
- case 0:
- MA1 = new SMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"SMA";
- break;
- case 1:
- MA1 = new EMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"EMA";
- break;
- case 2:
- MA1 = new WMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"WMA";
- break;
- case 3:
- MA1 = new T3_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"T3";
- break;
- case 4:
- MA1 = new SMMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"SMMA";
- break;
- case 5:
- MA1 = new TRIMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"TRIMA";
- break;
- case 6:
- MA1 = new DWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"DWMA";
- break;
- case 7:
- MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period);
- this.Name += $"FWMA";
- break;
- case 8:
- MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"DEMA";
- break;
- case 9:
- MA1 = new TEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"TEMA";
- break;
- case 10:
- MA1 = new ALMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"ALMA";
- break;
- case 11:
- MA1 = new HMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"HMA";
- break;
- case 12:
- MA1 = new HEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"HEMA";
- break;
- case 13:
- double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA1Period);
- MA1 = new MAMA_Series(source: bars.Select(this.MA1DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
- this.Name += $"MAMA";
- break;
- case 14:
- MA1 = new KAMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"KAMA";
- break;
- case 15:
- MA1 = new ZLEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"ZLEMA";
- break;
- default:
- MA1 = new JMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
- this.Name += $"JMA";
- break;
- }
-
- this.Name = this.Name + $" ({MA1Period}:{TBars.SelectStr(this.MA1DataSource)}) : ";
-
- switch (MA2type) {
- case 0:
- MA2 = new SMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"SMA";
- break;
- case 1:
- MA2 = new EMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"EMA";
- break;
- case 2:
- MA2 = new WMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"WMA";
- break;
- case 3:
- MA2 = new T3_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"T3";
- break;
- case 4:
- MA2 = new SMMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"SMMA";
- break;
- case 5:
- MA2 = new TRIMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"TRIMA";
- break;
- case 6:
- MA2 = new DWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"DWMA";
- break;
- case 7:
- MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period);
- this.Name += $"FWMA";
- break;
- case 8:
- MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"DEMA";
- break;
- case 9:
- MA2 = new TEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"TEMA";
- break;
- case 10:
- MA2 = new ALMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"ALMA";
- break;
- case 11:
- MA2 = new HMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"HMA";
- break;
- case 12:
- MA2 = new HEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"HEMA";
- break;
- case 13:
- double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA2Period);
- MA2 = new MAMA_Series(source: bars.Select(this.MA2DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
- this.Name += $"MAMA";
- break;
- case 14:
- MA2 = new KAMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"KAMA";
- break;
- case 15:
- MA2 = new ZLEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"ZLEMA";
- break;
- default:
- MA2 = new JMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
- this.Name += $"JMA";
- break;
- }
- this.Name += $"({MA2Period}:{TBars.SelectStr(this.MA2DataSource)}) ]";
-
- sMA1 = new(MA1, SlopePeriod);
- sMA2 = new(MA2, SlopePeriod);
- sig1 = new(sMA1, 0);
- sig2 = new(sMA2, 0);
- }
-
- protected override void OnUpdate(UpdateArgs args) {
- bool update = !(args.Reason == UpdateReason.NewBar ||
- args.Reason == UpdateReason.HistoricalBar);
- this.bars.Add(this.Time(),this.Open(), this.High(), this.Low(), this.Close(), this.Volume(), update);
- this.SetValue(this.MA1[^1].v, lineIndex: 0);
- this.SetValue(this.MA2[^1].v, lineIndex: 1);
-
- Color s1Color= (this.sMA1[^1].v > 0)?Color.LimeGreen:Color.OrangeRed;
- Color s2Color = (this.sMA2[^1].v > 0) ? Color.LimeGreen : Color.OrangeRed;
-
- this.LinesSeries[0].SetMarker(0,s1Color);
- this.LinesSeries[1].SetMarker(0,s2Color);
-
- if (sig1[^1].v > 0 || sig2[^1].v > 0) {
- if (sMA1[^1].v >= 0 && sMA2[^1].v >= 0 && LongTrades)
- {
- inLong = true;
- this.BeginCloud(0, 1, Color.FromArgb(127, Color.DarkGreen));
- this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v)? 0 : 1 ].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.UpArrow));
- }
- else {
- this.EndCloud(0, 1, Color.Empty);
- if (inShort)
- {
- this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v) ? 1 : 0].SetMarker(1, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow));
- inShort = false;
- }
- }
- }
-
- if (sig1[^1].v < 0 || sig2[^1].v < 0) {
- if (sMA1[^1].v <= 0 && sMA2[^1].v <= 0 && ShortTrades)
- {
- inShort = true;
- this.BeginCloud(0, 1, Color.FromArgb(100, Color.Red));
- this.LinesSeries[(this.MA1[^1].v > this.MA2[^1].v) ? 0 : 1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.UpArrow));
- }
- else {
- this.EndCloud(0, 1, Color.Empty);
- if (inLong) {
- LinesSeries[(this.MA1[^1].v > this.MA2[^1].v)?1:0].SetMarker(1, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
- inLong = false;
- }
- }
- }
- }
- public override void OnPaintChart(PaintChartEventArgs args) {
- base.OnPaintChart(args);
- if (this.CurrentChart == null) {return;}
- Graphics graphics = args.Graphics;
- var mainWindow = this.CurrentChart.MainWindow;
- int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
- int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
-/*
- int historycount = HistoricalData.Count;
- int ymax = mainWindow.ClientRectangle.Height;
-
-
- for (int i = leftIndex; i <= rightIndex; i++) {
- int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
- int width = this.CurrentChart.BarsWidth;
- int height = (int)((equity[i+historycount].v) *proportion);
-
- Brush bb = Brushes.DarkSlateGray;
- bb = (overunder[i+historycount].v>0 && LongTrades)? Brushes.Green : bb;
- bb = (overunder[i + historycount].v < 0 && ShortTrades) ? Brushes.Red : bb;
-
- graphics.FillRectangle(bb, xi, ymax - height, width, height);
- }
-*/
- }
-}
+using System;
+using System.Drawing;
+using System.Linq;
+using TradingPlatform.BusinessLayer;
+namespace QuanTAlib;
+
+public class MovingAverageSlope_chart : Indicator
+{
+ #region Parameters
+ [InputParameter("MA1: Type:", 0, variants: new object[]
+ { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
+ "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
+ private int MA1type = 16;
+
+ [InputParameter("MA1: Smoothing period:", 1, 1, 999, 1, 1)]
+ private int MA1Period = 10;
+
+ [InputParameter("MA1: Data source:", 2, variants: new object[]
+ { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
+ "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
+ private int MA1DataSource = 3;
+
+ [InputParameter("MA2: Type:", 3, variants: new object[]
+ { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9,
+ "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})]
+ private int MA2type = 6;
+
+ [InputParameter("MA2: Smoothing period:", 4, 1, 999, 1, 1)]
+ private int MA2Period = 50;
+
+ [InputParameter("MA2: Data source:", 5, variants: new object[]
+ { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
+ "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
+ private int MA2DataSource = 8;
+
+ [InputParameter("Data required for slope calc:", 6, 2, 10, 1, 1)]
+ private int SlopePeriod = 3;
+
+ [InputParameter("Long trades", 7)]
+ private bool LongTrades = true;
+
+ [InputParameter("Short trades", 8)]
+ private bool ShortTrades;
+
+ #endregion Parameters
+
+ protected HistoricalData History;
+ private TBars bars;
+
+ ///////
+ private TSeries MA1, MA2;
+ private SLOPE_Series sMA1, sMA2;
+ private CROSS_Series sig1, sig2;
+
+ private bool inLong, inShort;
+ ///////
+
+ public MovingAverageSlope_chart()
+ {
+ this.SeparateWindow = false;
+ this.Name = "Slopes convergence";
+ this.AddLineSeries("MA1", Color.DarkSlateGray, 2, LineStyle.Solid);
+ this.AddLineSeries("MA2", Color.DarkSlateGray, 2, LineStyle.Solid);
+ }
+
+ protected override void OnInit()
+ {
+ this.bars = new();
+ this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
+ for (int i = this.History.Count - 1; i >= 0; i--)
+ {
+ var rec = this.History[i, SeekOriginHistory.Begin];
+ bars.Add(rec.TimeLeft, rec[PriceType.Open],
+ rec[PriceType.High], rec[PriceType.Low],
+ rec[PriceType.Close], rec[PriceType.Volume]);
+ }
+ this.Name = "Slopes convergence: [ ";
+ switch (MA1type)
+ {
+ case 0:
+ MA1 = new SMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"SMA";
+ break;
+ case 1:
+ MA1 = new EMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"EMA";
+ break;
+ case 2:
+ MA1 = new WMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"WMA";
+ break;
+ case 3:
+ MA1 = new T3_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"T3";
+ break;
+ case 4:
+ MA1 = new SMMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"SMMA";
+ break;
+ case 5:
+ MA1 = new TRIMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"TRIMA";
+ break;
+ case 6:
+ MA1 = new DWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"DWMA";
+ break;
+ case 7:
+ MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period);
+ this.Name += $"FWMA";
+ break;
+ case 8:
+ MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"DEMA";
+ break;
+ case 9:
+ MA1 = new TEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"TEMA";
+ break;
+ case 10:
+ MA1 = new ALMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"ALMA";
+ break;
+ case 11:
+ MA1 = new HMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"HMA";
+ break;
+ case 12:
+ MA1 = new HEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"HEMA";
+ break;
+ case 13:
+ double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA1Period);
+ MA1 = new MAMA_Series(source: bars.Select(this.MA1DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
+ this.Name += $"MAMA";
+ break;
+ case 14:
+ MA1 = new KAMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"KAMA";
+ break;
+ case 15:
+ MA1 = new ZLEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"ZLEMA";
+ break;
+ default:
+ MA1 = new JMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false);
+ this.Name += $"JMA";
+ break;
+ }
+
+ this.Name = this.Name + $" ({MA1Period}:{TBars.SelectStr(this.MA1DataSource)}) : ";
+
+ switch (MA2type)
+ {
+ case 0:
+ MA2 = new SMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"SMA";
+ break;
+ case 1:
+ MA2 = new EMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"EMA";
+ break;
+ case 2:
+ MA2 = new WMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"WMA";
+ break;
+ case 3:
+ MA2 = new T3_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"T3";
+ break;
+ case 4:
+ MA2 = new SMMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"SMMA";
+ break;
+ case 5:
+ MA2 = new TRIMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"TRIMA";
+ break;
+ case 6:
+ MA2 = new DWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"DWMA";
+ break;
+ case 7:
+ MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period);
+ this.Name += $"FWMA";
+ break;
+ case 8:
+ MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"DEMA";
+ break;
+ case 9:
+ MA2 = new TEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"TEMA";
+ break;
+ case 10:
+ MA2 = new ALMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"ALMA";
+ break;
+ case 11:
+ MA2 = new HMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"HMA";
+ break;
+ case 12:
+ MA2 = new HEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"HEMA";
+ break;
+ case 13:
+ double factor = 1.015 * Math.Exp(-0.043 * (double)this.MA2Period);
+ MA2 = new MAMA_Series(source: bars.Select(this.MA2DataSource), fastlimit: factor, slowlimit: factor * 0.1, useNaN: false);
+ this.Name += $"MAMA";
+ break;
+ case 14:
+ MA2 = new KAMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"KAMA";
+ break;
+ case 15:
+ MA2 = new ZLEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"ZLEMA";
+ break;
+ default:
+ MA2 = new JMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false);
+ this.Name += $"JMA";
+ break;
+ }
+ this.Name += $"({MA2Period}:{TBars.SelectStr(this.MA2DataSource)}) ]";
+
+ sMA1 = new(MA1, SlopePeriod);
+ sMA2 = new(MA2, SlopePeriod);
+ sig1 = new(sMA1, 0);
+ sig2 = new(sMA2, 0);
+
+ int maxKeep = Math.Max(Math.Max(this.MA1Period, this.MA2Period), 100);
+
+ MA1.Keep = maxKeep;
+ MA2.Keep = maxKeep;
+ sMA1.Keep = maxKeep;
+ sMA2.Keep = maxKeep;
+ sig1.Keep = maxKeep;
+ sig2.Keep = maxKeep;
+ }
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ bool update = !(args.Reason == UpdateReason.NewBar ||
+ args.Reason == UpdateReason.HistoricalBar);
+ this.bars.Add(this.Time(), this.Open(), this.High(), this.Low(), this.Close(), this.Volume(), update);
+ this.SetValue(this.MA1[^1].v, lineIndex: 0);
+ this.SetValue(this.MA2[^1].v, lineIndex: 1);
+
+ Color s1Color = (this.sMA1[^1].v > 0) ? Color.LimeGreen : Color.OrangeRed;
+ Color s2Color = (this.sMA2[^1].v > 0) ? Color.LimeGreen : Color.OrangeRed;
+
+ this.LinesSeries[0].SetMarker(0, s1Color);
+ this.LinesSeries[1].SetMarker(0, s2Color);
+
+ if (sig1[^1].v > 0 || sig2[^1].v > 0)
+ {
+ if (sMA1[^1].v >= 0 && sMA2[^1].v >= 0 && LongTrades)
+ {
+ inLong = true;
+ this.BeginCloud(0, 1, Color.FromArgb(127, Color.DarkGreen));
+ this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v) ? 0 : 1].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.UpArrow));
+ }
+ else
+ {
+ this.EndCloud(0, 1, Color.Empty);
+ if (inShort && this.Count > 1)
+ {
+ this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v) ? 1 : 0].SetMarker(1, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow));
+ inShort = false;
+ }
+ }
+ }
+
+ if (sig1[^1].v < 0 || sig2[^1].v < 0)
+ {
+ if (sMA1[^1].v <= 0 && sMA2[^1].v <= 0 && ShortTrades)
+ {
+ inShort = true;
+ this.BeginCloud(0, 1, Color.FromArgb(100, Color.Red));
+ this.LinesSeries[(this.MA1[^1].v > this.MA2[^1].v) ? 0 : 1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.UpArrow));
+ }
+ else
+ {
+ this.EndCloud(0, 1, Color.Empty);
+ if (inLong && this.Count > 1)
+ {
+ LinesSeries[(this.MA1[^1].v > this.MA2[^1].v) ? 1 : 0].SetMarker(1, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
+ inLong = false;
+ }
+ }
+ }
+ }
+ public override void OnPaintChart(PaintChartEventArgs args)
+ {
+ base.OnPaintChart(args);
+ if (this.CurrentChart == null) { return; }
+ Graphics graphics = args.Graphics;
+ var mainWindow = this.CurrentChart.MainWindow;
+ int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
+ int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
+ /*
+ int historycount = HistoricalData.Count;
+ int ymax = mainWindow.ClientRectangle.Height;
+
+
+ for (int i = leftIndex; i <= rightIndex; i++) {
+ int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
+ int width = this.CurrentChart.BarsWidth;
+ int height = (int)((equity[i+historycount].v) *proportion);
+
+ Brush bb = Brushes.DarkSlateGray;
+ bb = (overunder[i+historycount].v>0 && LongTrades)? Brushes.Green : bb;
+ bb = (overunder[i + historycount].v < 0 && ShortTrades) ? Brushes.Red : bb;
+
+ graphics.FillRectangle(bb, xi, ymax - height, width, height);
+ }
+ */
+ }
+}
diff --git a/Indicators/Charts/JMA_chart.cs b/Indicators/Charts/JMA_chart.cs
index 7d5e5341..d35174cf 100644
--- a/Indicators/Charts/JMA_chart.cs
+++ b/Indicators/Charts/JMA_chart.cs
@@ -1,96 +1,104 @@
-using System;
-using System.Diagnostics;
-using System.Drawing;
-using System.Linq;
-using TradingPlatform.BusinessLayer;
-using TradingPlatform.BusinessLayer.Chart;
-namespace QuanTAlib;
-
-public class JMA_chart : Indicator {
- #region Parameters
-
- [InputParameter("Data source", 0, variants: new object[]
- { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
- "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
- private int DataSource = 3;
-
- [InputParameter("Smoothing period", 1, 1, 999, 1, 1)]
- private int Period = 9;
-
- [InputParameter("Volatility short", 2, 3, 50, 1, 1)]
- private int Vshort = 10;
-
- [InputParameter("Volatility long", 3, 20, 500, 1, 1)]
- private int Vlong = 65;
-
- [InputParameter("Phase", 4, -100, 100, 1, 2)]
- private double Jphase;
-
- #endregion Parameters
-
- ///////
- private JMA_Series indicator;
- ///////
-
- protected TBars bars;
- protected IChartWindow mainWindow;
- protected Graphics graphics;
- protected int firstOnScreenBarIndex, lastOnScreenBarIndex;
- protected HistoricalData History;
- protected int HistPeriod;
- public JMA_chart() {
- Name = "JMA - Jurik Moving Avg";
- Description = "Jurik Moving Average description";
- AddLineSeries(lineName: "JMA", lineColor: Color.Yellow, lineWidth: 3,lineStyle: LineStyle.Solid);
- SeparateWindow = false;
- HistPeriod = Period;
- }
-
-
- protected override void OnInit() {
- base.OnInit();
- bars = new();
- var dur1 = this.HistoricalData.FromTime;
- var dur = this.HistoricalData.Period.Duration.TotalSeconds * (HistPeriod * 4); //seconds of two periods
-
- this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
-
- for (int i = this.History.Count - 1; i >= 0; i--) {
-
- var rec = this.History[i, SeekOriginHistory.Begin];
-
- bars.Add(rec.TimeLeft, rec[PriceType.Open],
- rec[PriceType.High], rec[PriceType.Low],
- rec[PriceType.Close], rec[PriceType.Volume]);
- }
-
- indicator = new(source: bars.Select(DataSource), period: Period, phase: Jphase, vshort: Vshort, vlong: Vlong, useNaN: true);
- }
-
- protected override void OnUpdate(UpdateArgs args) {
- base.OnUpdate(args);
- bars.Add(Time(), GetPrice(PriceType.Open),
- GetPrice(PriceType.High),
- GetPrice(PriceType.Low),
- GetPrice(PriceType.Close),
- GetPrice(PriceType.Volume),
- update: !(args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar));
-
- this.SetValue(indicator[^1].v, lineIndex: 0);
- }
- public override void OnPaintChart(PaintChartEventArgs args) {
- base.OnPaintChart(args);
- if (this.CurrentChart == null) {
- return;
- }
-
- graphics = args.Graphics;
- mainWindow = this.CurrentChart.MainWindow;
-
- DateTime leftTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left);
- DateTime rightTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right);
- firstOnScreenBarIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(leftTime);
- lastOnScreenBarIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(rightTime));
- }
-
-}
+using System;
+using System.Diagnostics;
+using System.Drawing;
+using System.Linq;
+using TradingPlatform.BusinessLayer;
+using TradingPlatform.BusinessLayer.Chart;
+namespace QuanTAlib;
+
+public class JMA_chart : Indicator
+{
+ #region Parameters
+
+ [InputParameter("Data source", 0, variants: new object[]
+ { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
+ "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
+ private int DataSource = 3;
+
+ [InputParameter("Smoothing period", 1, 1, 999, 1, 1)]
+ private int Period = 9;
+
+ [InputParameter("Volatility short", 2, 3, 50, 1, 1)]
+ private int Vshort = 10;
+
+ [InputParameter("Volatility long", 3, 20, 500, 1, 1)]
+ private int Vlong = 65;
+
+ [InputParameter("Phase", 4, -100, 100, 1, 2)]
+ private double Jphase;
+
+ #endregion Parameters
+
+ ///////
+ private JMA_Series indicator;
+ ///////
+
+ protected TBars bars;
+ protected IChartWindow mainWindow;
+ protected Graphics graphics;
+ protected int firstOnScreenBarIndex, lastOnScreenBarIndex;
+ protected HistoricalData History;
+ protected int HistPeriod;
+ public JMA_chart()
+ {
+ Name = "JMA - Jurik Moving Avg";
+ Description = "Jurik Moving Average description";
+ AddLineSeries(lineName: "JMA", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
+ SeparateWindow = false;
+ HistPeriod = Period;
+ }
+
+
+ protected override void OnInit()
+ {
+ base.OnInit();
+ bars = new();
+ var dur1 = this.HistoricalData.FromTime;
+ var dur = this.HistoricalData.Period.Duration.TotalSeconds * (HistPeriod * 4); //seconds of two periods
+
+ this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
+
+ for (int i = this.History.Count - 1; i >= 0; i--)
+ {
+
+ var rec = this.History[i, SeekOriginHistory.Begin];
+
+ bars.Add(rec.TimeLeft, rec[PriceType.Open],
+ rec[PriceType.High], rec[PriceType.Low],
+ rec[PriceType.Close], rec[PriceType.Volume]);
+ }
+
+ indicator = new(source: bars.Select(DataSource), period: Period, phase: Jphase, vshort: Vshort, vlong: Vlong, useNaN: true);
+ indicator.Keep = Math.Max(Period, 100);
+ }
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ base.OnUpdate(args);
+ bars.Add(Time(), GetPrice(PriceType.Open),
+ GetPrice(PriceType.High),
+ GetPrice(PriceType.Low),
+ GetPrice(PriceType.Close),
+ GetPrice(PriceType.Volume),
+ update: !(args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar));
+
+ this.SetValue(indicator[^1].v, lineIndex: 0);
+ }
+ public override void OnPaintChart(PaintChartEventArgs args)
+ {
+ base.OnPaintChart(args);
+ if (this.CurrentChart == null)
+ {
+ return;
+ }
+
+ graphics = args.Graphics;
+ mainWindow = this.CurrentChart.MainWindow;
+
+ DateTime leftTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left);
+ DateTime rightTime = mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right);
+ firstOnScreenBarIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(leftTime);
+ lastOnScreenBarIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(rightTime));
+ }
+
+}
diff --git a/Indicators/Charts/TrailingStop.cs b/Indicators/Charts/TrailingStop.cs
index 29aee917..8ee9f476 100644
--- a/Indicators/Charts/TrailingStop.cs
+++ b/Indicators/Charts/TrailingStop.cs
@@ -1,95 +1,102 @@
-using System;
-using System.Diagnostics;
-using System.Drawing;
-using System.Linq;
-using TradingPlatform.BusinessLayer;
-namespace QuanTAlib;
-
-public class TrailingStop_chart : Indicator {
- #region Parameters
-
- [InputParameter("Period", 0, 1, 100, 1, 1)]
- protected int _period = 30;
-
- [InputParameter("Factor", 1, 1, 100, 0.1, 1)]
- protected double _factor = 10;
-
- [InputParameter("Long TS", 2)]
- private bool _LongTS = true;
-
- [InputParameter("Short TS", 3)]
- private bool _ShortTS = true;
-
- #endregion Parameters
-
- ///////
- private HistoricalData History;
- private TBars bars;
- private ATR_Series _atr;
- private double _tslineL, _ratchetL, _tslineS, _ratchetS;
-
- ///////
-
- public TrailingStop_chart() {
- Name = $"ATR Trailing Stop";
- AddLineSeries(lineName: "TrailingATR Long", lineColor: Color.Yellow, lineWidth: 1,lineStyle: LineStyle.Dot);
- AddLineSeries(lineName: "Ratchet Long", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
-
- AddLineSeries(lineName: "TrailingATR Short", lineColor: Color.Yellow, lineWidth: 1, lineStyle: LineStyle.Dot);
- AddLineSeries(lineName: "Ratchet Short", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
-
- SeparateWindow = false;
- }
-
-
- protected override void OnInit() {
- this.Name = $"Trailing Stop (ATR:{_period}, Mult:{_factor:f2})";
- this.bars = new();
-
- this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
- for (int i = this.History.Count - 1; i >= 0; i--) {
- var rec = this.History[i, SeekOriginHistory.Begin];
- bars.Add(rec.TimeLeft, rec[PriceType.Open],
- rec[PriceType.High], rec[PriceType.Low],
- rec[PriceType.Close], rec[PriceType.Volume]);
- }
- _atr = new(source: bars, _period, useNaN: true);
- _ratchetL = Double.NegativeInfinity;
- _ratchetS = Double.PositiveInfinity;
-
- this.LinesSeries[0].Visible = _LongTS;
- this.LinesSeries[1].Visible = _LongTS;
- this.LinesSeries[2].Visible = _ShortTS;
- this.LinesSeries[3].Visible = _ShortTS;
- }
-
- protected override void OnUpdate(UpdateArgs args) {
- bool update = !(args.Reason == UpdateReason.NewBar ||
- args.Reason == UpdateReason.HistoricalBar);
- this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
- this.GetPrice(PriceType.High),
- this.GetPrice(PriceType.Low),
- this.GetPrice(PriceType.Close),
- this.GetPrice(PriceType.Volume), update);
-
- _tslineL = bars.High[^1].v - (_factor * _atr[^1].v);
- _ratchetL = Math.Max(_tslineL,_ratchetL);
- if (_ratchetL > bars.Low[^1].v) {
- this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.Yellow, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
- _ratchetL = _tslineL;
- }
-
- _tslineS = bars.High[^1].v + (_factor * _atr[^1].v);
- _ratchetS = Math.Min(_tslineS, _ratchetS);
- if (_ratchetS < bars.High[^1].v) {
- this.LinesSeries[3].SetMarker(0, new IndicatorLineMarker(Color.Yellow, upperIcon: IndicatorLineMarkerIconType.UpArrow));
- _ratchetS = _tslineS;
- }
-
- this.SetValue(_tslineL, lineIndex: 0);
- this.SetValue(_ratchetL, lineIndex: 1);
- this.SetValue(_tslineS, lineIndex: 2);
- this.SetValue(_ratchetS, lineIndex: 3);
- }
-}
-
+using System;
+using System.Diagnostics;
+using System.Drawing;
+using System.Linq;
+using TradingPlatform.BusinessLayer;
+namespace QuanTAlib;
+
+public class TrailingStop_chart : Indicator
+{
+ #region Parameters
+
+ [InputParameter("Period", 0, 1, 100, 1, 1)]
+ protected int _period = 30;
+
+ [InputParameter("Factor", 1, 1, 100, 0.1, 1)]
+ protected double _factor = 10;
+
+ [InputParameter("Long TS", 2)]
+ private bool _LongTS = true;
+
+ [InputParameter("Short TS", 3)]
+ private bool _ShortTS = true;
+
+ #endregion Parameters
+
+ ///////
+ private HistoricalData History;
+ private TBars bars;
+ private ATR_Series _atr;
+ private double _tslineL, _ratchetL, _tslineS, _ratchetS;
+
+ ///////
+
+ public TrailingStop_chart()
+ {
+ Name = $"ATR Trailing Stop";
+ AddLineSeries(lineName: "TrailingATR Long", lineColor: Color.Yellow, lineWidth: 1, lineStyle: LineStyle.Dot);
+ AddLineSeries(lineName: "Ratchet Long", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
+
+ AddLineSeries(lineName: "TrailingATR Short", lineColor: Color.Yellow, lineWidth: 1, lineStyle: LineStyle.Dot);
+ AddLineSeries(lineName: "Ratchet Short", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
+
+ SeparateWindow = false;
+ }
+
+
+ protected override void OnInit()
+ {
+ this.Name = $"Trailing Stop (ATR:{_period}, Mult:{_factor:f2})";
+ this.bars = new();
+
+ this.History = this.Symbol.GetHistory(period: this.HistoricalData.Period, fromTime: HistoricalData.FromTime);
+ for (int i = this.History.Count - 1; i >= 0; i--)
+ {
+ var rec = this.History[i, SeekOriginHistory.Begin];
+ bars.Add(rec.TimeLeft, rec[PriceType.Open],
+ rec[PriceType.High], rec[PriceType.Low],
+ rec[PriceType.Close], rec[PriceType.Volume]);
+ }
+ _atr = new(source: bars, _period, useNaN: true);
+ _ratchetL = Double.NegativeInfinity;
+ _ratchetS = Double.PositiveInfinity;
+
+ this.LinesSeries[0].Visible = _LongTS;
+ this.LinesSeries[1].Visible = _LongTS;
+ this.LinesSeries[2].Visible = _ShortTS;
+ this.LinesSeries[3].Visible = _ShortTS;
+ }
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ bool update = !(args.Reason == UpdateReason.NewBar ||
+ args.Reason == UpdateReason.HistoricalBar);
+ this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
+ this.GetPrice(PriceType.High),
+ this.GetPrice(PriceType.Low),
+ this.GetPrice(PriceType.Close),
+ this.GetPrice(PriceType.Volume), update);
+
+ _tslineL = bars.High[^1].v - (_factor * _atr[^1].v);
+ _ratchetL = Math.Max(_tslineL, _ratchetL);
+ if (_ratchetL > bars.Low[^1].v)
+ {
+ this.LinesSeries[1].SetMarker(0, new IndicatorLineMarker(Color.Yellow, bottomIcon: IndicatorLineMarkerIconType.DownArrow));
+ _ratchetL = _tslineL;
+ }
+
+ _tslineS = bars.High[^1].v + (_factor * _atr[^1].v);
+ _ratchetS = Math.Min(_tslineS, _ratchetS);
+ if (_ratchetS < bars.High[^1].v)
+ {
+ this.LinesSeries[3].SetMarker(0, new IndicatorLineMarker(Color.Yellow, upperIcon: IndicatorLineMarkerIconType.UpArrow));
+ _ratchetS = _tslineS;
+ }
+
+ this.SetValue(_tslineL, lineIndex: 0);
+ this.SetValue(_ratchetL, lineIndex: 1);
+ this.SetValue(_tslineS, lineIndex: 2);
+ this.SetValue(_ratchetS, lineIndex: 3);
+ }
+}
+
diff --git a/Indicators/Indicators.csproj b/Indicators/Indicators.csproj
index 5b9da593..eaa8bbb0 100644
--- a/Indicators/Indicators.csproj
+++ b/Indicators/Indicators.csproj
@@ -1,56 +1,56 @@
-
-
- net7.0
- preview
- false
- AnyCPU
- Indicator
- QuanTAlib_Indicators
- QuanTAlib
- embedded
- AnyCPU
- disable
- False
- ..\.sonarlint\mihakralj_quantalibcsharp.ruleset
- 0.2.1.0
- 0.2.1.0
- 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d
- 0.2.1-dev.2
- NETSDK1057
- true
- NETSDK1057
-
-
- True
- 3
- True
- anycpu
- full
-
-
- embedded
- True
- 3
- True
- anycpu
-
-
-
-
-
-
-
-
-
-
-
-
- QuanTAlib\%(RecursiveDir)%(Filename)%(Extension)
-
-
-
-
- ..\.github\TradingPlatform.BusinessLayer.dll
-
-
+
+
+ net7.0
+ preview
+ false
+ AnyCPU
+ Indicator
+ QuanTAlib_Indicators
+ QuanTAlib
+ embedded
+ AnyCPU
+ disable
+ False
+ ..\.sonarlint\mihakralj_quantalibcsharp.ruleset
+ 0.2.1.0
+ 0.2.1.0
+ 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d
+ 0.2.1-dev.2
+ NETSDK1057
+ true
+ NETSDK1057
+
+
+ True
+ 3
+ True
+ anycpu
+ full
+
+
+ embedded
+ True
+ 3
+ True
+ anycpu
+
+
+
+
+
+
+
+
+
+
+
+
+ QuanTAlib\%(RecursiveDir)%(Filename)%(Extension)
+
+
+
+
+ ..\.github\TradingPlatform.BusinessLayer.dll
+
+
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 261eeb9e..29f81d81 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,201 +1,201 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/QuanTAlib.sln b/QuanTAlib.sln
index d0b6ce59..ab71a1e8 100644
--- a/QuanTAlib.sln
+++ b/QuanTAlib.sln
@@ -1,74 +1,24 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
+Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32210.308
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Calculations", "Calculations\Calculations.csproj", "{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Indicators", "Indicators\Indicators.csproj", "{43AD2D78-024C-4D96-A70B-915CF519965A}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strategies", "Strategies\Strategies.csproj", "{FA526AF6-95BC-4AC0-8B46-A304FD06689D}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{47B6ACDB-F535-4FEB-9A0A-C427CAE8C28E}"
- ProjectSection(SolutionItems) = preProject
- docs\.nojekyll = docs\.nojekyll
- docs\ALMA.md = docs\ALMA.md
- docs\DEMA.md = docs\DEMA.md
- docs\DWMA.md = docs\DWMA.md
- docs\EMA.md = docs\EMA.md
- docs\FMA.md = docs\FMA.md
- docs\getting_started.ipynb = docs\getting_started.ipynb
- docs\HEMA.md = docs\HEMA.md
- docs\HMA.md = docs\HMA.md
- docs\HWMA.md = docs\HWMA.md
- docs\index.html = docs\index.html
- docs\indicators.md = docs\indicators.md
- docs\JMA.md = docs\JMA.md
- docs\KAMA.md = docs\KAMA.md
- docs\LICENSE = docs\LICENSE
- docs\MAMA.md = docs\MAMA.md
- docs\QA.md = docs\QA.md
- docs\readme.md = docs\readme.md
- docs\RMA.md = docs\RMA.md
- docs\SMA.md = docs\SMA.md
- docs\SMMA.md = docs\SMMA.md
- docs\T3.md = docs\T3.md
- docs\TEMA.md = docs\TEMA.md
- docs\TRIMA.md = docs\TRIMA.md
- docs\WMA.md = docs\WMA.md
- docs\ZLEMA.md = docs\ZLEMA.md
- docs\_sidebar.md = docs\_sidebar.md
- EndProjectSection
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Calculations", "v2\calculations.csproj", "{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}"
EndProject
Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Release|Any CPU.Build.0 = Release|Any CPU
- {283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Release|Any CPU.Build.0 = Release|Any CPU
- {43AD2D78-024C-4D96-A70B-915CF519965A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {43AD2D78-024C-4D96-A70B-915CF519965A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {43AD2D78-024C-4D96-A70B-915CF519965A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {43AD2D78-024C-4D96-A70B-915CF519965A}.Release|Any CPU.Build.0 = Release|Any CPU
- {FA526AF6-95BC-4AC0-8B46-A304FD06689D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FA526AF6-95BC-4AC0-8B46-A304FD06689D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FA526AF6-95BC-4AC0-8B46-A304FD06689D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FA526AF6-95BC-4AC0-8B46-A304FD06689D}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {E5592DC2-0542-45B2-A0CF-C6B1EDC72B87}
- EndGlobalSection
-EndGlobal
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {E5592DC2-0542-45B2-A0CF-C6B1EDC72B87}
+ EndGlobalSection
+EndGlobal
\ No newline at end of file
diff --git a/Strategies/Strategies.csproj b/Strategies/Strategies.csproj
index e665dc50..5cf21f57 100644
--- a/Strategies/Strategies.csproj
+++ b/Strategies/Strategies.csproj
@@ -1,53 +1,53 @@
-
-
- net7.0
- preview
- false
- AnyCPU
- Strategy
- QuanTAlib_Strategies
- QuanTAlib
- embedded
- AnyCPU
- disable
- False
- ..\.sonarlint\mihakralj_quantalibcsharp.ruleset
- 0.2.1.0
- 0.2.1.0
- 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d
- 0.2.1-dev.2
- NETSDK1057
- true
- NETSDK1057
-
-
- True
- 3
- True
- anycpu
- full
-
-
- embedded
- True
- 3
- True
- anycpu
-
-
-
-
-
-
- QuanTAlib\%(RecursiveDir)%(Filename)%(Extension)
-
-
-
-
-
-
-
- ..\.github\TradingPlatform.BusinessLayer.dll
-
-
+
+
+ net7.0
+ preview
+ false
+ AnyCPU
+ Strategy
+ QuanTAlib_Strategies
+ QuanTAlib
+ embedded
+ AnyCPU
+ disable
+ False
+ ..\.sonarlint\mihakralj_quantalibcsharp.ruleset
+ 0.2.1.0
+ 0.2.1.0
+ 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d
+ 0.2.1-dev.2
+ NETSDK1057
+ true
+ NETSDK1057
+
+
+ True
+ 3
+ True
+ anycpu
+ full
+
+
+ embedded
+ True
+ 3
+ True
+ anycpu
+
+
+
+
+
+
+ QuanTAlib\%(RecursiveDir)%(Filename)%(Extension)
+
+
+
+
+
+
+
+ ..\.github\TradingPlatform.BusinessLayer.dll
+
+
\ No newline at end of file
diff --git a/Tests/Basic tests/Indicators.cs b/Tests/Basic tests/Indicators.cs
index de49baae..0bac1c17 100644
--- a/Tests/Basic tests/Indicators.cs
+++ b/Tests/Basic tests/Indicators.cs
@@ -1,155 +1,156 @@
-using Xunit;
-using System;
-using QuanTAlib;
-
-namespace Basics;
-#nullable disable
-public class Indicators
-{
- private static Type[] maSeriesTypes = new Type[]
- {
- typeof(SMA_Series),
- typeof(EMA_Series),
- typeof(DEMA_Series),
- typeof(TEMA_Series),
- typeof(WMA_Series),
- typeof(ALMA_Series),
- typeof(DWMA_Series),
- typeof(FWMA_Series),
- typeof(HMA_Series),
- typeof(ZLEMA_Series),
- typeof(RMA_Series),
- typeof(HEMA_Series),
- typeof(JMA_Series),
- typeof(CUSUM_Series),
- typeof(SMMA_Series),
- typeof(T3_Series),
- typeof(KAMA_Series),
- typeof(TRIMA_Series),
- typeof(MAMA_Series),
- typeof(HWMA_Series),
-};
-
- [Theory]
- [MemberData(nameof(MASeriesData))]
- public void Name_exists(Type classType)
- {
- TSeries data = new("Data") {1,2,3};
-
- var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
- Assert.NotEmpty(MA_Series.Name);
- }
-
- [Theory]
- [MemberData(nameof(MASeriesData))]
- public void Series_Length(Type classType)
- {
- GBM_Feed feed = new(1000);
- TSeries data = feed.OHLC4;
-
- var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
- Assert.Equal(1000, MA_Series.Count);
- }
-
- [Theory]
- [MemberData(nameof(MASeriesData))]
- public void Return_data(Type classType)
- {
- TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
-
- var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
- var result = MA_Series.Add(20);
- Assert.Equal(result.v, MA_Series.Last.v);
- }
-
- [Theory]
- [MemberData(nameof(MASeriesData))]
- public void Update(Type classType)
- {
- TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
-
- var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries;
- var pre_update = MA_Series.Last.v;
-
- double pre_data = data.Last.v;
- data.Add(20, true);
- data.Add(pre_data, true);
-
- Assert.Equal(pre_update, MA_Series.Last.v);
- Assert.Equal(data.Count, MA_Series.Count);
-}
-
- [Theory]
- [MemberData(nameof(MASeriesData))]
- public void Period_zero(Type classType)
- {
- GBM_Feed feed = new(100);
- TSeries data = feed.OHLC4;
-
- var MA_Series = Activator.CreateInstance(classType, data, 0, false) as TSeries;
- Assert.Equal(data.Count, MA_Series.Count);
- Assert.False(double.IsNaN(MA_Series.Last.v));
- }
-
- [Theory]
- [MemberData(nameof(MASeriesData))]
- public void Reset(Type classType)
- {
- GBM_Feed feed = new(10);
- TSeries data = feed.OHLC4;
- var MA_Series = Activator.CreateInstance(classType, data, 10, false) as TSeries;
- MA_Series.Reset();
- data.Add(0);
- Assert.Equal(data.Last.v, MA_Series.Last.v);
- }
-
- [Theory]
- [MemberData(nameof(MASeriesData))]
- public void Period_one(Type classType)
- {
- GBM_Feed feed = new(100);
- TSeries data = feed.OHLC4;
-
- var MA_Series = Activator.CreateInstance(classType, data, 1, false) as TSeries;
- Assert.InRange(MA_Series.Last.v - data.Last.v, -10e-6, 10e-6);
- }
-
- [Theory]
- [MemberData(nameof(MASeriesData))]
- public void NaN_test(Type classType)
- {
- GBM_Feed feed = new(100);
- TSeries data = feed.OHLC4;
-
- var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries;
- Assert.True(double.IsNaN(MA_Series[0].v));
- Assert.True(double.IsNaN(MA_Series[8].v));
- Assert.False(double.IsNaN(MA_Series[9].v));
- }
-
- [Theory]
- [MemberData(nameof(MASeriesData))]
- public void Edge_numbers(Type classType)
- {
- TSeries data = new() { double.Epsilon, double.PositiveInfinity, double.MaxValue, double.NegativeInfinity };
- var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries;
- Assert.Equal(4, MA_Series.Count);
- }
-
- [Theory]
- [MemberData(nameof(MASeriesData))]
- public void handling_NaN(Type classType) {
- TSeries data = new("Name") { 1, 2, 3, 4, 5, 6, double.NaN, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
-var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries;
- Assert.False(double.IsNaN(MA_Series.Last.v));
- }
-
-public static IEnumerable