diff --git a/.sonarlint/mihakralj_quantalib/CSharp/SonarLint.xml b/.sonarlint/mihakralj_quantalib/CSharp/SonarLint.xml new file mode 100644 index 00000000..90bc98df --- /dev/null +++ b/.sonarlint/mihakralj_quantalib/CSharp/SonarLint.xml @@ -0,0 +1,89 @@ + + + + + sonar.cs.analyzeGeneratedCode + false + + + sonar.cs.file.suffixes + .cs + + + sonar.cs.ignoreHeaderComments + true + + + sonar.cs.roslyn.ignoreIssues + false + + + + + S107 + + + max + 7 + + + + + S110 + + + max + 5 + + + + + S1479 + + + maximum + 30 + + + + + S2342 + + + flagsAttributeFormat + ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$ + + + format + ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$ + + + + + S2436 + + + max + 2 + + + maxMethod + 3 + + + + + S3776 + + + propertyThreshold + 3 + + + threshold + 15 + + + + + \ No newline at end of file diff --git a/.sonarlint/mihakralj_quantalibcsharp.ruleset b/.sonarlint/mihakralj_quantalibcsharp.ruleset index 150340f7..22a7ac94 100644 --- a/.sonarlint/mihakralj_quantalibcsharp.ruleset +++ b/.sonarlint/mihakralj_quantalibcsharp.ruleset @@ -380,6 +380,7 @@ + diff --git a/Quantower/Indicators/JMA_chart.cs b/Quantower/Indicators/JMA_chart.cs index 208a7696..d6c38982 100644 --- a/Quantower/Indicators/JMA_chart.cs +++ b/Quantower/Indicators/JMA_chart.cs @@ -8,17 +8,22 @@ namespace QuanTAlib; public class JMA_chart : Indicator { #region Parameters - [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] - private int Period = 10; - - [InputParameter("Data source", 1, variants: new object[] + [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("Slope calc", 2, 2, 10, 1, 1)] - private int SlopePeriod = 3; + private int DataSource = 3; + [InputParameter("Smoothing period", 1, 1, 999, 1, 1)] + private int Period = 10; + + [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 = 0.0; #endregion Parameters @@ -26,21 +31,19 @@ public class JMA_chart : Indicator { /////// private JMA_Series indicator; - private LINREG_Series slope; /////// public JMA_chart() { this.SeparateWindow = false; this.Name = "JMA - Jurik Moving Avg"; this.Description = "Jurik Moving Average description"; - this.AddLineSeries("JMA", Color.Blue, 4, LineStyle.Solid); + this.AddLineSeries("JMA", Color.Yellow, 3, LineStyle.Solid); } protected override void OnInit() { this.bars = new(); - this.indicator = new(source: bars.Select(this.DataSource), period: this.Period, useNaN: false); - this.slope = new(source: this.indicator, period: this.SlopePeriod); + this.indicator = new(source: bars.Select(this.DataSource), period: this.Period, phase: Jphase, vshort: Vshort, vlong: Vlong, useNaN: false); } protected override void OnUpdate(UpdateArgs args) { @@ -51,7 +54,6 @@ public class JMA_chart : Indicator { this.GetPrice(PriceType.Close), this.GetPrice(PriceType.Volume), update); double result = this.indicator[this.indicator.Count - 1].v; - this.LinesSeries[0].SetMarker(offset: 0,color: this.slope > 0 ? Color.FromArgb(0,160,0) : Color.FromArgb(255, 0, 0)); this.SetValue(result, lineIndex: 0); } } diff --git a/Quantower/Quantower.csproj b/Quantower/Quantower.csproj index 7d91a984..a1495bc3 100644 --- a/Quantower/Quantower.csproj +++ b/Quantower/Quantower.csproj @@ -1,9 +1,9 @@  - net48 + net6 preview - true + false AnyCPU Indicator Quantower_QTAlib @@ -21,9 +21,7 @@ True anycpu full - + C:\Quantower\TradingPlatform\v1.130.7\..\..\Settings\Scripts\Indicators\Quantower embedded @@ -31,21 +29,24 @@ 3 True anycpu - + C:\Quantower\TradingPlatform\v1.130.7\..\..\Settings\Scripts\Indicators\Quantower QuanTAlib\%(RecursiveDir)%(Filename)%(Extension) + + + + - C:\Quantower\TradingPlatform\v1.129.11\bin\TradingPlatform.BusinessLayer.dll + C:\Quantower\TradingPlatform\v1.130.7\bin\TradingPlatform.BusinessLayer.dll \ No newline at end of file diff --git a/Quantower/dll/TradingPlatform.BusinessLayer.dll b/Quantower/dll/TradingPlatform.BusinessLayer.dll index 95e71e6e..245e51a7 100644 Binary files a/Quantower/dll/TradingPlatform.BusinessLayer.dll and b/Quantower/dll/TradingPlatform.BusinessLayer.dll differ diff --git a/Source/Basics/Single_TSeries_Abstract.cs b/Source/Basics/Single_TSeries_Abstract.cs index 24e5e5f4..6c283237 100644 --- a/Source/Basics/Single_TSeries_Abstract.cs +++ b/Source/Basics/Single_TSeries_Abstract.cs @@ -23,30 +23,29 @@ public abstract class Single_TSeries_Indicator : TSeries protected readonly TSeries _data; protected int _p; - // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) - protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN) - { - this._data = source; - this._period = period; - this._p = _period; - this._NaN = useNaN; - this._data.Pub += this.Sub; - } + // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) + protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN) { + _data = source; + _period = period; + _p = _period; + _NaN = useNaN; + _data.Pub += Sub; + } - // overridable Add() method to add/update a single item at the end of the list + // overridable Add() method to add/update a single item at the end of the list - public virtual void Add((System.DateTime t, double v) TValue, bool update, bool useNaN) - { - if (_period == 0) { _p = this.Length; } - var res = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : TValue.v); - base.Add(res, update); - } - public new virtual void Add((System.DateTime t, double v) TValue, bool update) => base.Add(TValue, update); + public virtual void Add((DateTime t, double v) TValue, bool update, bool useNaN) { + if (_period == 0) { _p = Length; } + var res = (TValue.t, Count < _p - 1 && _NaN ? double.NaN : TValue.v); + base.Add(res, update); + } + public new virtual void Add((DateTime t, double v) TValue, bool update) => base.Add(TValue, update); - // potentially overridable Add() method for the whole series (could be replaced with faster bulk algo) - public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { this.Add(TValue: data[i], update: false); } } - - public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false); + // potentially overridable Add() method for the whole series (could be replaced with faster bulk algo) + public virtual void Add(TSeries data) { + foreach (var item in data) { Add(TValue: item, update: false); } + } + public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false); public void Add(bool update) => this.Add(TValue: this._data[this._data.Count - 1], update: update); public void Add() => this.Add(TValue: this._data[this._data.Count - 1], update: false); public new void Sub(object source, TSeriesEventArgs e) => this.Add(TValue: this._data[this._data.Count - 1], update: e.update); diff --git a/Source/Basics/TSeries.cs b/Source/Basics/TSeries.cs index af9b8da7..15f53d9f 100644 --- a/Source/Basics/TSeries.cs +++ b/Source/Basics/TSeries.cs @@ -1,5 +1,7 @@ namespace QuanTAlib; using System; +using System.Collections.Generic; +using System.Linq; /* TSeries is the cornerstone of all QuanTAlib classess. @@ -11,87 +13,44 @@ TSeries is the cornerstone of all QuanTAlib classess. - includes publishing and subscribing methods that attach to events */ -public class TSeries : System.Collections.Generic.List<(DateTime t, double v)> -{ - // when asked for a (t,v) tuple, return the last (t,v) on the List - public static implicit operator (DateTime t, double v)(TSeries l) => l[l.Count - 1]; +public class TSeries : List<(DateTime t, double v)> { - // when asked for a (double), return the value part of the last tuple on the list - public static implicit operator double(TSeries l) => l[l.Count - 1].v; + public static implicit operator (DateTime t, double v)(TSeries l) => l[^1]; + public static implicit operator double(TSeries l) => l[^1].v; + public static implicit operator DateTime(TSeries l) => l[^1].t; + public List t => this.Select(item => item.t).ToList(); + public List v => this.Select(item => item.v).ToList(); + public int Length => this.Count; - // when asked for a (DateTime), return the DateTime part of the last tuple on the list - public static implicit operator DateTime(TSeries l) => l[l.Count - 1].t; - - //convert from tuple List(t,v) to single List(DateTime) - public System.Collections.Generic.List t { - get { System.Collections.Generic.List TList = new(); - for (int i = 0; i < this.Count; i++) { TList.Add(this[i].t); } - return TList; - } - } + public TSeries Tail(int count = 10) { + var tailSeries = new TSeries(); + tailSeries.AddRange(this.Skip(Math.Max(0, this.Count - count)).Take(count)); + return tailSeries; + } + public void Add((DateTime t, double v) TValue, bool update = false) { + if (update) { this[^1] = TValue; } + else { base.Add(TValue); } + OnEvent(update); + } - //convert from tuple List(t,v) to single List(double) - public System.Collections.Generic.List v { - get { System.Collections.Generic.List VList = new(); - for (int i = 0; i < this.Count; i++) { VList.Add(this[i].v); } - return VList; - } - } + public void Add(DateTime t, double v, bool update = false) => this.Add((t, v), update); + public void Add(double v, bool update = false) => this.Add((DateTime.Now, v), update); + protected virtual void OnEvent(bool update = false) { + Pub?.Invoke(this, new TSeriesEventArgs { update = update }); } - public int Length => this.Count; + public delegate void NewDataEventHandler(object source, TSeriesEventArgs args); + public event NewDataEventHandler Pub; - public TSeries Tail(int count=10) { - TSeries outSeries = new(); - if (count > this.Count) { count = this.Count; } - for (int i = this.Count-count; i this.Add((t, v), update); - - public void Add(double v, bool update = false) => this.Add((DateTime.Now, v), update); - - // Broadcast handler - only to valid targets - protected virtual void OnEvent(bool update = false) - { - if (Pub != null && Pub.Target != this) - { - Pub(this, new TSeriesEventArgs { update = update }); - } - } - - // delegate used by event handler + event handler (Pub == publisher) - public delegate - void NewDataEventHandler(object source, TSeriesEventArgs args); - public event NewDataEventHandler Pub; - - public void Sub(object source, TSeriesEventArgs e) - { - TSeries ss = (TSeries)source; - if (ss.Count > 0) - { - for (int i = 0; i < ss.Count; i++) - { - this.Add(ss[i]); - } - } - else - { - this.Add(ss[ss.Count - 1], e.update); - } - } + public void Sub(object source, TSeriesEventArgs e) { + TSeries ss = (TSeries)source; + if (ss.Count > 0) { + this.AddRange(ss); + } else { + Add(ss[^1], e.update); + } + } } -// EventArgs extension - carries the update field -public class TSeriesEventArgs : EventArgs -{ - public bool update { get; set; } +public class TSeriesEventArgs : EventArgs{ + public bool update { get; set; } } diff --git a/Source/QuanTAlib.csproj b/Source/QuanTAlib.csproj index b8259724..8e07cace 100644 --- a/Source/QuanTAlib.csproj +++ b/Source/QuanTAlib.csproj @@ -2,7 +2,7 @@ QuanTAlib - 0.1.29 + 0.1.30 Library of Technical Indicators for .NET Quantitative Technical Analysis library for real-time (streaming) data analysis git @@ -11,7 +11,7 @@ Miha Kralj Miha Kralj readme.md - net7.0;net6.0;netstandard2.1;net48 + net6.0 disable preview disable diff --git a/Source/Trends/JMA_Series.cs b/Source/Trends/JMA_Series.cs index 855306b4..0ce50524 100644 --- a/Source/Trends/JMA_Series.cs +++ b/Source/Trends/JMA_Series.cs @@ -21,7 +21,7 @@ Issues: */ public class JMA_Series : Single_TSeries_Indicator { - private readonly System.Collections.Generic.List volty_10 = new(); + private readonly System.Collections.Generic.List volty_short = new(); private readonly System.Collections.Generic.List vsum_buff = new(); private readonly double pr; public TSeries mma1 { get; } @@ -30,14 +30,17 @@ public class JMA_Series : Single_TSeries_Indicator { private double upperBand, lowerBand, vsum, Kv, del1, del2; 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; - public JMA_Series(TSeries source, int period, double phase = 0.0, bool useNaN = false) : base(source, period, useNaN) { + public JMA_Series(TSeries source, int period, double phase = 0.0, int vshort = 10, int vlong = 65, bool useNaN = false) : base(source, period, useNaN) { upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = del1 = del2 = 0.0; Kv = 0; + pr = (phase * 0.01) + 1.5; if (phase < -100) { pr = 0.5; } if (phase > 100) { pr = 2.5; } - + _voltyS = vshort; + _voltyL = vlong; mma1 = new(); mma2 = new(); @@ -77,32 +80,32 @@ public class JMA_Series : Single_TSeries_Indicator { if (Math.Abs(del1) < Math.Abs(del2)) { volty = Math.Abs(del2); } //// from volty to avolty - if (update) { volty_10[volty_10.Count - 1] = volty; } - else { volty_10.Add(volty); } - if (volty_10.Count > 10) { volty_10.RemoveAt(0); } - vsum = prev_vsum + 0.1 * (volty - volty_10.First()); + 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 > (10 * _p)) { vsum_buff.RemoveAt(0); } + 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(2.0 * _p)) / Math.Log(2.0)) + 2; - if (len1 < 0) len1 = 0; + double len1 = (Math.Log(Math.Sqrt(_p)) / 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 len2 = Math.Sqrt(0.5 * (_p - 2)) * len1; - Kv = Math.Pow(len2 / (len2 + 2), Math.Sqrt(pow2)); double beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2); - double alpha = Math.Pow(beta * 1.1, pow2); + 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; mma1.Add(ma1); diff --git a/Tests/Validations/Trends/Pandas_TA.cs b/Tests/Validations/Trends/Pandas_TA.cs index 64d38ee9..6c05cbc8 100644 --- a/Tests/Validations/Trends/Pandas_TA.cs +++ b/Tests/Validations/Trends/Pandas_TA.cs @@ -5,6 +5,8 @@ using Python.Runtime; using Python.Included; namespace Validations; + +/* public class PandasTA : IDisposable { private readonly GBM_Feed bars; @@ -144,7 +146,7 @@ public class PandasTA : IDisposable Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } - */ + [Fact] void EMA() { EMA_Series QL = new(bars.Close, period, false); var pta = df.ta.ema(close: df.close, length: period); @@ -155,7 +157,7 @@ public class PandasTA : IDisposable Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } - /* + [Fact] void ENTROPY() { ENTROPY_Series QL = new(bars.Close, period, useNaN: false); var pta = df.ta.entropy(close: df.close, length: period); @@ -309,7 +311,7 @@ public class PandasTA : IDisposable Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } - */ + [Fact] void SMA() { SMA_Series QL = new(bars.Close, period, false); var pta = df.ta.sma(close: df.close, length: period); @@ -320,7 +322,7 @@ public class PandasTA : IDisposable Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } - /* + [Fact] void SSDEV() { SSDEV_Series QL = new(bars.Close, period, useNaN: false); var pta = df.ta.stdev(close: df.close, length: period, ddof: 1); @@ -432,5 +434,6 @@ public class PandasTA : IDisposable Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } - */ -} \ No newline at end of file + +} +*/ \ No newline at end of file