diff --git a/.github/workflows/main_automation.yml b/.github/workflows/main_automation.yml index 9829947f..ed5b381f 100644 --- a/.github/workflows/main_automation.yml +++ b/.github/workflows/main_automation.yml @@ -52,7 +52,7 @@ jobs: /d:sonar.cs.dotcover.reportsPaths=./coveragereport.html - name: Build Core DLL - run: dotnet build ./Source/QuanTAlib.csproj --verbosity minimal --configuration Release --nologo + run: dotnet build ./Calculations/QuanTAlib.csproj --verbosity minimal --configuration Release --nologo - name: Build Quantower DLL run: dotnet build ./Quantower/Quantower.csproj --verbosity minimal --configuration Release --nologo @@ -93,11 +93,13 @@ jobs: automatic_release_tag: "latest" prerelease: true title: "Latest Build" - files: /Quantower/Settings/Scripts/Indicators/QuanTAlib/*.dll + files: | + /Quantower/Settings/Scripts/Indicators/QuanTAlib/*.dll + /Quantower/Settings/Scripts/Strategies/QuanTAlib/*.dll - - name: Authenticate to Github packages source + - name: Authenticate to Github packages Calculations if: ${{ github.ref == 'refs/heads/main' }} - run: dotnet nuget add source + run: dotnet nuget add Calculations --username mihakralj --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text @@ -105,14 +107,14 @@ jobs: - name: Push package to github if: ${{ github.ref == 'refs/heads/main' }} - run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg' + run: dotnet nuget push '.\Calculations\bin\Release\QuanTAlib.*.nupkg' --api-key ${{ secrets.GITHUB_TOKEN }} - --source https://nuget.pkg.github.com/mihakralj/index.json + --Calculations https://nuget.pkg.github.com/mihakralj/index.json --skip-duplicate - name: Push package to nuget.org if: ${{ github.ref == 'refs/heads/main' }} - run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg' + run: dotnet nuget push '.\Calculations\bin\Release\QuanTAlib.*.nupkg' --api-key ${{ secrets.NUGET_DEPLOY_KEY_QUANTLIB }} - --source https://api.nuget.org/v3/index.json + --Calculations https://api.nuget.org/v3/index.json --skip-duplicate diff --git a/Source/Basics/ADD_Series.cs b/Calculations/Basics/ADD_Series.cs similarity index 100% rename from Source/Basics/ADD_Series.cs rename to Calculations/Basics/ADD_Series.cs diff --git a/Source/Basics/DIV_Series.cs b/Calculations/Basics/DIV_Series.cs similarity index 100% rename from Source/Basics/DIV_Series.cs rename to Calculations/Basics/DIV_Series.cs diff --git a/Source/Basics/MAX_Series.cs b/Calculations/Basics/MAX_Series.cs similarity index 96% rename from Source/Basics/MAX_Series.cs rename to Calculations/Basics/MAX_Series.cs index b8b197c3..109461a9 100644 --- a/Source/Basics/MAX_Series.cs +++ b/Calculations/Basics/MAX_Series.cs @@ -1,25 +1,25 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -MAX - Maximum value in the given period in the series. - If period = 0 => period = full length of the series - */ - -public class MAX_Series : Single_TSeries_Indicator -{ - public MAX_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _max = _buffer.Max(); - - base.Add((TValue.t, _max), update, _NaN); - } +namespace QuanTAlib; +using System; +using System.Linq; + +/* +MAX - Maximum value in the given period in the series. + If period = 0 => period = full length of the series + */ + +public class MAX_Series : Single_TSeries_Indicator +{ + public MAX_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + if (base._data.Count > 0) { base.Add(base._data); } + } + private readonly System.Collections.Generic.List _buffer = new(); + + public override void Add((DateTime t, double v) TValue, bool update) + { + Add_Replace_Trim(_buffer, TValue.v, _p, update); + double _max = _buffer.Max(); + + base.Add((TValue.t, _max), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Basics/MIDPOINT_Series.cs b/Calculations/Basics/MIDPOINT_Series.cs similarity index 96% rename from Source/Basics/MIDPOINT_Series.cs rename to Calculations/Basics/MIDPOINT_Series.cs index 9bccdebf..d96a39a6 100644 --- a/Source/Basics/MIDPOINT_Series.cs +++ b/Calculations/Basics/MIDPOINT_Series.cs @@ -1,37 +1,37 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TSeries_Indicator -{ - public MIDPOINT_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) - { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _max = TValue.v; - double _min = TValue.v; - for (int i = 0; i < this._buffer.Count; i++) - { - _max = Math.Max(this._buffer[i], _max); - _min = Math.Min(this._buffer[i], _min); - } - double _mid = (_max + _min) * 0.5; - - base.Add((TValue.t, _mid), update, _NaN); - } +namespace QuanTAlib; +using System; + +/* +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 : Single_TSeries_Indicator +{ + public MIDPOINT_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + if (base._data.Count > 0) + { base.Add(base._data); } + } + private readonly System.Collections.Generic.List _buffer = new(); + + public override void Add((DateTime t, double v) TValue, bool update) + { + Add_Replace_Trim(_buffer, TValue.v, _p, update); + + double _max = TValue.v; + double _min = TValue.v; + for (int i = 0; i < this._buffer.Count; i++) + { + _max = Math.Max(this._buffer[i], _max); + _min = Math.Min(this._buffer[i], _min); + } + double _mid = (_max + _min) * 0.5; + + base.Add((TValue.t, _mid), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Basics/MIDPRICE_Series.cs b/Calculations/Basics/MIDPRICE_Series.cs similarity index 96% rename from Source/Basics/MIDPRICE_Series.cs rename to Calculations/Basics/MIDPRICE_Series.cs index f7602c3a..c3a3c444 100644 --- a/Source/Basics/MIDPRICE_Series.cs +++ b/Calculations/Basics/MIDPRICE_Series.cs @@ -1,32 +1,32 @@ -namespace QuanTAlib; -using System; -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 : Single_TBars_Indicator -{ - public MIDPRICE_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._bars.Count > 0) - { base.Add(base._bars); } - } - private readonly System.Collections.Generic.List _bufferhi = new(); - private readonly System.Collections.Generic.List _bufferlo = new(); - - public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) - { - Add_Replace_Trim(_bufferhi, TBar.h, _p, update); - Add_Replace_Trim(_bufferlo, TBar.l, _p, update); - - double _max = _bufferhi.Max(); - double _min = _bufferlo.Min(); - double _mid = (_max + _min) * 0.5; - - base.Add((TBar.t, _mid), update, _NaN); - } +namespace QuanTAlib; +using System; +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 : Single_TBars_Indicator +{ + public MIDPRICE_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) + { + if (base._bars.Count > 0) + { base.Add(base._bars); } + } + private readonly System.Collections.Generic.List _bufferhi = new(); + private readonly System.Collections.Generic.List _bufferlo = new(); + + public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) + { + Add_Replace_Trim(_bufferhi, TBar.h, _p, update); + Add_Replace_Trim(_bufferlo, TBar.l, _p, update); + + double _max = _bufferhi.Max(); + double _min = _bufferlo.Min(); + double _mid = (_max + _min) * 0.5; + + base.Add((TBar.t, _mid), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Basics/MIN_Series.cs b/Calculations/Basics/MIN_Series.cs similarity index 96% rename from Source/Basics/MIN_Series.cs rename to Calculations/Basics/MIN_Series.cs index 2621ec75..e41a0ba4 100644 --- a/Source/Basics/MIN_Series.cs +++ b/Calculations/Basics/MIN_Series.cs @@ -1,25 +1,25 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -MIN - Minimum value in the given period in the series. - If period = 0 => period = full length of the series - */ - -public class MIN_Series : Single_TSeries_Indicator -{ - public MIN_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _min = _buffer.Min(); - base.Add((TValue.t, _min), update, _NaN); - } +namespace QuanTAlib; +using System; +using System.Linq; + +/* +MIN - Minimum value in the given period in the series. + If period = 0 => period = full length of the series + */ + +public class MIN_Series : Single_TSeries_Indicator +{ + public MIN_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + if (base._data.Count > 0) { base.Add(base._data); } + } + private readonly System.Collections.Generic.List _buffer = new(); + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + Add_Replace_Trim(_buffer, TValue.v, _p, update); + + double _min = _buffer.Min(); + base.Add((TValue.t, _min), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Basics/MUL_Series.cs b/Calculations/Basics/MUL_Series.cs similarity index 100% rename from Source/Basics/MUL_Series.cs rename to Calculations/Basics/MUL_Series.cs diff --git a/Source/Basics/Pair_TSeries_Abstract.cs b/Calculations/Basics/Pair_TSeries_Abstract.cs similarity index 100% rename from Source/Basics/Pair_TSeries_Abstract.cs rename to Calculations/Basics/Pair_TSeries_Abstract.cs diff --git a/Source/Basics/SUB_Series.cs b/Calculations/Basics/SUB_Series.cs similarity index 100% rename from Source/Basics/SUB_Series.cs rename to Calculations/Basics/SUB_Series.cs diff --git a/Source/Basics/SUM_Series.cs b/Calculations/Basics/SUM_Series.cs similarity index 96% rename from Source/Basics/SUM_Series.cs rename to Calculations/Basics/SUM_Series.cs index b3846737..bb98134d 100644 --- a/Source/Basics/SUM_Series.cs +++ b/Calculations/Basics/SUM_Series.cs @@ -1,35 +1,35 @@ -namespace QuanTAlib; -using System; - -/* -SUM: 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 SUM_Series : Single_TSeries_Indicator -{ - public SUM_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - if (update) { _buffer[_buffer.Count - 1] = TValue.v; } - else { _buffer.Add(TValue.v); } - if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); } - - double _sum = 0; - for (int i = 0; i < _buffer.Count; i++) { _sum += _buffer[i]; } - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _sum); - - base.Add(result, update); - } -} +namespace QuanTAlib; +using System; + +/* +SUM: 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 SUM_Series : Single_TSeries_Indicator +{ + public SUM_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + if (base._data.Count > 0) { base.Add(base._data); } + } + private readonly System.Collections.Generic.List _buffer = new(); + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + if (update) { _buffer[_buffer.Count - 1] = TValue.v; } + else { _buffer.Add(TValue.v); } + if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); } + + double _sum = 0; + for (int i = 0; i < _buffer.Count; i++) { _sum += _buffer[i]; } + + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _sum); + + base.Add(result, update); + } +} diff --git a/Source/Basics/Single_TBars_Abstract.cs b/Calculations/Basics/Single_TBars_Abstract.cs similarity index 100% rename from Source/Basics/Single_TBars_Abstract.cs rename to Calculations/Basics/Single_TBars_Abstract.cs diff --git a/Source/Basics/Single_TSeries_Abstract.cs b/Calculations/Basics/Single_TSeries_Abstract.cs similarity index 97% rename from Source/Basics/Single_TSeries_Abstract.cs rename to Calculations/Basics/Single_TSeries_Abstract.cs index 6c283237..d52ad80d 100644 --- a/Source/Basics/Single_TSeries_Abstract.cs +++ b/Calculations/Basics/Single_TSeries_Abstract.cs @@ -1,70 +1,70 @@ -namespace QuanTAlib; -using System; -using System.Collections.Generic; -using System.Linq; - -/* -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 Single_TSeries_Indicator : TSeries -{ - protected readonly int _period; - protected readonly bool _NaN; - 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) { - _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 - - 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) { - 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); - - protected static void Add_Replace(List l, double v, bool update) - { - if (update) - { l[l.Count - 1] = v; } - else - { l.Add(v); } - } - protected static double Add_Replace_Trim(List l, double v, int p, bool update) - { - Add_Replace(l, v, update); - double ret = (l.Count > 0) ? l.First() : 0; - if (l.Count > p && p != 0) - { - l.RemoveAt(0); - } - return ret; - } -} +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Linq; + +/* +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 Single_TSeries_Indicator : TSeries +{ + protected readonly int _period; + protected readonly bool _NaN; + 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) { + _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 + + 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) { + 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); + + protected static void Add_Replace(List l, double v, bool update) + { + if (update) + { l[l.Count - 1] = v; } + else + { l.Add(v); } + } + protected static double Add_Replace_Trim(List l, double v, int p, bool update) + { + Add_Replace(l, v, update); + double ret = (l.Count > 0) ? l.First() : 0; + if (l.Count > p && p != 0) + { + l.RemoveAt(0); + } + return ret; + } +} diff --git a/Source/Basics/TBars.cs b/Calculations/Basics/TBars.cs similarity index 100% rename from Source/Basics/TBars.cs rename to Calculations/Basics/TBars.cs diff --git a/Source/Basics/TR_Series.cs b/Calculations/Basics/TR_Series.cs similarity index 100% rename from Source/Basics/TR_Series.cs rename to Calculations/Basics/TR_Series.cs diff --git a/Source/Basics/TSeries.cs b/Calculations/Basics/TSeries.cs similarity index 100% rename from Source/Basics/TSeries.cs rename to Calculations/Basics/TSeries.cs diff --git a/Source/Basics/ZL_Series.cs b/Calculations/Basics/ZL_Series.cs similarity index 96% rename from Source/Basics/ZL_Series.cs rename to Calculations/Basics/ZL_Series.cs index 7e06bf96..0a85f65b 100644 --- a/Source/Basics/ZL_Series.cs +++ b/Calculations/Basics/ZL_Series.cs @@ -1,34 +1,34 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TSeries_Indicator -{ - public ZL_Series(TSeries source, int period, bool useNaN = false) : base(source, period:period, useNaN:useNaN) { - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - int _lag = (int)((_p-1) * 0.5); - _lag = (this.Count-_lag < 0) ? 0 : this.Count-_lag; - - double _zl = TValue.v + (TValue.v - _data[_lag].v); - - var ret = (TValue.t, (base.Count==0 && base._NaN) ? double.NaN : _zl ); - base.Add(ret, update); - } +namespace QuanTAlib; +using System; + +/* +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 : Single_TSeries_Indicator +{ + public ZL_Series(TSeries source, int period, bool useNaN = false) : base(source, period:period, useNaN:useNaN) { + if (this._data.Count > 0) { base.Add(this._data); } + } + + public override void Add((DateTime t, double v) TValue, bool update) + { + int _lag = (int)((_p-1) * 0.5); + _lag = (this.Count-_lag < 0) ? 0 : this.Count-_lag; + + double _zl = TValue.v + (TValue.v - _data[_lag].v); + + var ret = (TValue.t, (base.Count==0 && base._NaN) ? double.NaN : _zl ); + base.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/QuanTAlib.csproj b/Calculations/Calculations.csproj similarity index 90% rename from Source/QuanTAlib.csproj rename to Calculations/Calculations.csproj index 8e07cace..ae442495 100644 --- a/Source/QuanTAlib.csproj +++ b/Calculations/Calculations.csproj @@ -1,71 +1,71 @@ - - - - QuanTAlib - 0.1.30 - Library of Technical Indicators for .NET - Quantitative Technical Analysis library for real-time (streaming) data analysis - git - https://github.com/mihakralj/QuanTAlib - true - Miha Kralj - Miha Kralj - readme.md - net6.0 - disable - preview - disable - true - en-US - QuanTAlib - QuanTAlib - True - AnyCPU - False - embedded - 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; - - Apache-2.0 - - - - full - True - 7 - True - anycpu - - - - True - 7 - True - anycpu - - - QuanTAlib2.png - https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png - True - ..\.sonarlint\mihakralj_quantalibcsharp.ruleset - - - - - - - True - - - - True - False - - - - + + + + QuanTAlib + 0.1.31 + 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 + readme.md + net8.0;net7.0;net6.0 + disable + preview + disable + true + en-US + QuanTAlib + QuanTAlib + True + AnyCPU + False + embedded + 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; + + Apache-2.0 + + + + full + True + 7 + True + anycpu + + + + True + 7 + True + anycpu + + + QuanTAlib2.png + https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png + True + ..\.sonarlint\mihakralj_quantalibcsharp.ruleset + + + + + + + True + + + + True + False + + + + \ No newline at end of file diff --git a/Source/Feeds/Alphavantage_Feed.cs b/Calculations/Feeds/Alphavantage_Feed.cs similarity index 97% rename from Source/Feeds/Alphavantage_Feed.cs rename to Calculations/Feeds/Alphavantage_Feed.cs index 2f521ae2..a5c52eba 100644 --- a/Source/Feeds/Alphavantage_Feed.cs +++ b/Calculations/Feeds/Alphavantage_Feed.cs @@ -1,56 +1,56 @@ -namespace QuanTAlib; -using System; -using System.Text.Json; - -/* -Alphavantage - Free API to collect 100 recent daily quotes. It requires a (free) API key - Get API key at https://www.alphavantage.co/support/#api-key - Parameters: - Symbol: stock ("AAPL"), - APIkey: unique Alphavantage API key - - - -public class Alphavantage_Feed : TBars -{ - 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(); - - string req = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED" + "&symbol=" + Symbol + "&apikey=" + APIkey; - 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"); } - foreach (var val in json.EnumerateObject()) { base.Add(GetOHLC(val)); } - base.Reverse(); - } - private static (DateTime t, double o, double h, double l, double c, double v) GetOHLC(JsonProperty json) - { - double o, h, l, c, v; - o = h = l = c = v = 0; - DateTime date = Convert.ToDateTime(json.Name); - foreach (var val in json.Value.EnumerateObject()) - { - switch (val.Name) - { - case "1. open": o = Convert.ToDouble(val.Value.ToString()); break; - case "1b. open (USD)": o = Convert.ToDouble(val.Value.ToString()); break; - case "2. high": h = Convert.ToDouble(val.Value.ToString()); break; - case "2b. high (USD)": h = Convert.ToDouble(val.Value.ToString()); break; - case "3. low": l = Convert.ToDouble(val.Value.ToString()); break; - case "3b. low (USD)": l = Convert.ToDouble(val.Value.ToString()); break; - case "4. close": c = Convert.ToDouble(val.Value.ToString()); break; - case "4b. close (USD)": c = Convert.ToDouble(val.Value.ToString()); break; - case "5. adjusted close": c = Convert.ToDouble(val.Value.ToString()); break; - case "5. volume": v = Convert.ToDouble(val.Value.ToString()); break; - case "6. volume": v = Convert.ToDouble(val.Value.ToString()); break; - default: o = 0; h = 0; l = 0; c = 0; v = 0; break; - } - } - return (date, o, h, l, c, v); - } -} +namespace QuanTAlib; +using System; +using System.Text.Json; + +/* +Alphavantage - Free API to collect 100 recent daily quotes. It requires a (free) API key + Get API key at https://www.alphavantage.co/support/#api-key + Parameters: + Symbol: stock ("AAPL"), + APIkey: unique Alphavantage API key + + + +public class Alphavantage_Feed : TBars +{ + 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(); + + string req = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED" + "&symbol=" + Symbol + "&apikey=" + APIkey; + 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"); } + foreach (var val in json.EnumerateObject()) { base.Add(GetOHLC(val)); } + base.Reverse(); + } + private static (DateTime t, double o, double h, double l, double c, double v) GetOHLC(JsonProperty json) + { + double o, h, l, c, v; + o = h = l = c = v = 0; + DateTime date = Convert.ToDateTime(json.Name); + foreach (var val in json.Value.EnumerateObject()) + { + switch (val.Name) + { + case "1. open": o = Convert.ToDouble(val.Value.ToString()); break; + case "1b. open (USD)": o = Convert.ToDouble(val.Value.ToString()); break; + case "2. high": h = Convert.ToDouble(val.Value.ToString()); break; + case "2b. high (USD)": h = Convert.ToDouble(val.Value.ToString()); break; + case "3. low": l = Convert.ToDouble(val.Value.ToString()); break; + case "3b. low (USD)": l = Convert.ToDouble(val.Value.ToString()); break; + case "4. close": c = Convert.ToDouble(val.Value.ToString()); break; + case "4b. close (USD)": c = Convert.ToDouble(val.Value.ToString()); break; + case "5. adjusted close": c = Convert.ToDouble(val.Value.ToString()); break; + case "5. volume": v = Convert.ToDouble(val.Value.ToString()); break; + case "6. volume": v = Convert.ToDouble(val.Value.ToString()); break; + default: o = 0; h = 0; l = 0; c = 0; v = 0; break; + } + } + return (date, o, h, l, c, v); + } +} */ \ No newline at end of file diff --git a/Source/Feeds/GBM_Feed.cs b/Calculations/Feeds/GBM_Feed.cs similarity index 97% rename from Source/Feeds/GBM_Feed.cs rename to Calculations/Feeds/GBM_Feed.cs index e0ca22dc..a08568c1 100644 --- a/Source/Feeds/GBM_Feed.cs +++ b/Calculations/Feeds/GBM_Feed.cs @@ -1,63 +1,63 @@ -namespace QuanTAlib; -using System; - -/* -GBM - Geometric Brownian Motion is a random simulator of market movement, returning List - GBM can be used for testing indicators, validation and Monte Carlo simulations of strategies. - - Sample usage: - GBM-Random data = new(); // generates 1 year (252) list of bars - GBM-Random data = new(Bars: 1000); // generates 1,000 bars - GBM-Random data = new(Bars: 252, Volatility: 0.05, Drift: 0.0005, Seed: 100.0) - - Parameters - Bars: number of bars (quotes) requested - Volatility: how dymamic/volatile the series should be; default is 1 - Drift: incremental drift due to annual interest rate; default is 5% - Seed: starting value of the random series; should not be 0 - - */ - -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) { - this.seed = Seed; - volatility = Volatility*0.01; - drift = Drift*0.01; - precision = Precision; - for (int i = 0; i OCMin)? (2 * OCMin) - Low : Low; - - 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) { - Random rnd = new(); - 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); - } +namespace QuanTAlib; +using System; + +/* +GBM - Geometric Brownian Motion is a random simulator of market movement, returning List + GBM can be used for testing indicators, validation and Monte Carlo simulations of strategies. + + Sample usage: + GBM-Random data = new(); // generates 1 year (252) list of bars + GBM-Random data = new(Bars: 1000); // generates 1,000 bars + GBM-Random data = new(Bars: 252, Volatility: 0.05, Drift: 0.0005, Seed: 100.0) + + Parameters + Bars: number of bars (quotes) requested + Volatility: how dymamic/volatile the series should be; default is 1 + Drift: incremental drift due to annual interest rate; default is 5% + Seed: starting value of the random series; should not be 0 + + */ + +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) { + this.seed = Seed; + volatility = Volatility*0.01; + drift = Drift*0.01; + precision = Precision; + for (int i = 0; i OCMin)? (2 * OCMin) - Low : Low; + + 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) { + Random rnd = new(); + 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); + } } \ No newline at end of file diff --git a/Source/Feeds/RND_Feed.cs b/Calculations/Feeds/RND_Feed.cs similarity index 97% rename from Source/Feeds/RND_Feed.cs rename to Calculations/Feeds/RND_Feed.cs index 1d17840d..c6e311af 100644 --- a/Source/Feeds/RND_Feed.cs +++ b/Calculations/Feeds/RND_Feed.cs @@ -1,28 +1,28 @@ -namespace QuanTAlib; -using System; - -/* -Random Bars generator - used for testing, validation and fun - Returns 'bars' number of candles that follow common market movement. - volatility defines how 'jumpy' is the series of - startvalue defines beginning closing price that then guides the rest of series - - */ - -public class RND_Feed : TBars -{ - public RND_Feed(int Bars, double Volatility = 0.05, double Startvalue = 100.0) - { - Random rnd = new(); - double c = Startvalue; - for (int i = 0; i < Bars; i++) - { - double o = Math.Round(c + (c * (((Volatility * 0.1) * rnd.NextDouble()) - 0.005)), 2); - double h = Math.Round(o + (c * Volatility * rnd.NextDouble()), 2); - double l = Math.Round(o - (c * Volatility * rnd.NextDouble()), 2); - c = Math.Round(l + ((h - l) * rnd.NextDouble()), 2); - double v = Math.Round(1000 * rnd.NextDouble(), 2); - this.Add(DateTime.Today.AddDays(i - Bars), o, h, l, c, v); - } - } +namespace QuanTAlib; +using System; + +/* +Random Bars generator - used for testing, validation and fun + Returns 'bars' number of candles that follow common market movement. + volatility defines how 'jumpy' is the series of + startvalue defines beginning closing price that then guides the rest of series + + */ + +public class RND_Feed : TBars +{ + public RND_Feed(int Bars, double Volatility = 0.05, double Startvalue = 100.0) + { + Random rnd = new(); + double c = Startvalue; + for (int i = 0; i < Bars; i++) + { + double o = Math.Round(c + (c * (((Volatility * 0.1) * rnd.NextDouble()) - 0.005)), 2); + double h = Math.Round(o + (c * Volatility * rnd.NextDouble()), 2); + double l = Math.Round(o - (c * Volatility * rnd.NextDouble()), 2); + c = Math.Round(l + ((h - l) * rnd.NextDouble()), 2); + double v = Math.Round(1000 * rnd.NextDouble(), 2); + this.Add(DateTime.Today.AddDays(i - Bars), o, h, l, c, v); + } + } } \ No newline at end of file diff --git a/Source/Feeds/Yahoo_Feed.cs b/Calculations/Feeds/Yahoo_Feed.cs similarity index 97% rename from Source/Feeds/Yahoo_Feed.cs rename to Calculations/Feeds/Yahoo_Feed.cs index 4df7d380..b904fbac 100644 --- a/Source/Feeds/Yahoo_Feed.cs +++ b/Calculations/Feeds/Yahoo_Feed.cs @@ -1,49 +1,49 @@ -namespace QuanTAlib; -using System; -using System.Text.Json; - -/* -Yahoo Finance - Free API feed to collect daily market quotes - Parameters: - Symbol: stock symbol (default: "IBM") - Period: number of days of collected history (default: 252) - Usage: - Yahoo_Feed ticker = new("MSFT", 20) - - - -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="+ - (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); - - for (int i=0; i +Yahoo Finance - Free API feed to collect daily market quotes + Parameters: + Symbol: stock symbol (default: "IBM") + Period: number of days of collected history (default: 252) + Usage: + Yahoo_Feed ticker = new("MSFT", 20) + + + +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="+ + (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); + + for (int i=0; i -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 : Single_TBars_Indicator -{ - private readonly System.Collections.Generic.List _tp = new(); - - public CCI_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) - { - if (_bars.Count > 0) { base.Add(_bars); } - } - - public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) - { - 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._p) { 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) ? double.NaN : (this._tp[this._tp.Count-1] - _avgTp) / (0.015 * _avgDv); - - base.Add((TBar.t, _cci), update, _NaN); - } +namespace QuanTAlib; +using System; +using System.Linq; +using static System.Net.Mime.MediaTypeNames; + +/* +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 : Single_TBars_Indicator +{ + private readonly System.Collections.Generic.List _tp = new(); + + public CCI_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) + { + if (_bars.Count > 0) { base.Add(_bars); } + } + + public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) + { + 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._p) { 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) ? double.NaN : (this._tp[this._tp.Count-1] - _avgTp) / (0.015 * _avgDv); + + base.Add((TBar.t, _cci), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Statistics/BIAS_Series.cs b/Calculations/Statistics/BIAS_Series.cs similarity index 100% rename from Source/Statistics/BIAS_Series.cs rename to Calculations/Statistics/BIAS_Series.cs diff --git a/Source/Statistics/CORR_Series.cs b/Calculations/Statistics/CORR_Series.cs similarity index 97% rename from Source/Statistics/CORR_Series.cs rename to Calculations/Statistics/CORR_Series.cs index f82d82de..246baa79 100644 --- a/Source/Statistics/CORR_Series.cs +++ b/Calculations/Statistics/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/Source/Statistics/COVAR_Series.cs b/Calculations/Statistics/COVAR_Series.cs similarity index 100% rename from Source/Statistics/COVAR_Series.cs rename to Calculations/Statistics/COVAR_Series.cs diff --git a/Source/Statistics/DECAY_Series.cs b/Calculations/Statistics/DECAY_Series.cs similarity index 100% rename from Source/Statistics/DECAY_Series.cs rename to Calculations/Statistics/DECAY_Series.cs diff --git a/Source/Statistics/ENTROPY_Series.cs b/Calculations/Statistics/ENTROPY_Series.cs similarity index 100% rename from Source/Statistics/ENTROPY_Series.cs rename to Calculations/Statistics/ENTROPY_Series.cs diff --git a/Source/Statistics/KURTOSIS_Series.cs b/Calculations/Statistics/KURTOSIS_Series.cs similarity index 100% rename from Source/Statistics/KURTOSIS_Series.cs rename to Calculations/Statistics/KURTOSIS_Series.cs diff --git a/Source/Statistics/LINREG_Series.cs b/Calculations/Statistics/LINREG_Series.cs similarity index 97% rename from Source/Statistics/LINREG_Series.cs rename to Calculations/Statistics/LINREG_Series.cs index 0987555c..2aff6af2 100644 --- a/Source/Statistics/LINREG_Series.cs +++ b/Calculations/Statistics/LINREG_Series.cs @@ -1,91 +1,91 @@ -namespace QuanTAlib; -using System; - -/* -LINREG: 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 LINREG_Series : Single_TSeries_Indicator -{ - public readonly TSeries Intercept = new(); - public readonly TSeries RSquared = new(); - public readonly TSeries StdDev = new(); - private readonly System.Collections.Generic.List _buffer = new(); - - public LINREG_Series(TSeries source, int period, bool useNaN = false) - : base(source, period, useNaN) - { - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, 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._p - 1 && this._NaN ? double.NaN : _slope); - base.Add(ret, update, _NaN); - - ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _intercept); - Intercept.Add(ret, update); - - ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _StdDev); - StdDev.Add(ret, update); - - ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _RSquared); - RSquared.Add(ret, update); - } +namespace QuanTAlib; +using System; + +/* +LINREG: 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 LINREG_Series : Single_TSeries_Indicator +{ + public readonly TSeries Intercept = new(); + public readonly TSeries RSquared = new(); + public readonly TSeries StdDev = new(); + private readonly System.Collections.Generic.List _buffer = new(); + + public LINREG_Series(TSeries source, int period, bool useNaN = false) + : base(source, period, useNaN) + { + if (this._data.Count > 0) { base.Add(this._data); } + } + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + Add_Replace_Trim(_buffer, TValue.v, _p, 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._p - 1 && this._NaN ? double.NaN : _slope); + base.Add(ret, update, _NaN); + + ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _intercept); + Intercept.Add(ret, update); + + ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _StdDev); + StdDev.Add(ret, update); + + ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _RSquared); + RSquared.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/Statistics/MAD_Series.cs b/Calculations/Statistics/MAD_Series.cs similarity index 100% rename from Source/Statistics/MAD_Series.cs rename to Calculations/Statistics/MAD_Series.cs diff --git a/Source/Statistics/MAPE_Series.cs b/Calculations/Statistics/MAPE_Series.cs similarity index 100% rename from Source/Statistics/MAPE_Series.cs rename to Calculations/Statistics/MAPE_Series.cs diff --git a/Source/Statistics/MEDIAN_Series.cs b/Calculations/Statistics/MEDIAN_Series.cs similarity index 100% rename from Source/Statistics/MEDIAN_Series.cs rename to Calculations/Statistics/MEDIAN_Series.cs diff --git a/Source/Statistics/MSE_Series.cs b/Calculations/Statistics/MSE_Series.cs similarity index 100% rename from Source/Statistics/MSE_Series.cs rename to Calculations/Statistics/MSE_Series.cs diff --git a/Source/Statistics/SDEV_Series.cs b/Calculations/Statistics/SDEV_Series.cs similarity index 100% rename from Source/Statistics/SDEV_Series.cs rename to Calculations/Statistics/SDEV_Series.cs diff --git a/Source/Statistics/SMAPE_Series.cs b/Calculations/Statistics/SMAPE_Series.cs similarity index 100% rename from Source/Statistics/SMAPE_Series.cs rename to Calculations/Statistics/SMAPE_Series.cs diff --git a/Source/Statistics/SSDEV_Series.cs b/Calculations/Statistics/SSDEV_Series.cs similarity index 100% rename from Source/Statistics/SSDEV_Series.cs rename to Calculations/Statistics/SSDEV_Series.cs diff --git a/Source/Statistics/SVAR_Series.cs b/Calculations/Statistics/SVAR_Series.cs similarity index 97% rename from Source/Statistics/SVAR_Series.cs rename to Calculations/Statistics/SVAR_Series.cs index 5f569081..a83d5deb 100644 --- a/Source/Statistics/SVAR_Series.cs +++ b/Calculations/Statistics/SVAR_Series.cs @@ -1,38 +1,38 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -SVAR: Sample Variance - Sample variance uses Bessel's correction to correct the bias in the estimation of population variance. - -Sources: - https://en.wikipedia.org/wiki/Variance - Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction - -Remark: - SVAR is also known as the Unbiased Sample Variance, while VAR (Population Variance) is known as - the Biased Sample Variance. - - */ - -public class SVAR_Series : Single_TSeries_Indicator -{ - public SVAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, 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 - - base.Add((TValue.t, _svar), update, _NaN); - } +namespace QuanTAlib; +using System; +using System.Linq; + +/* +SVAR: Sample Variance + Sample variance uses Bessel's correction to correct the bias in the estimation of population variance. + +Sources: + https://en.wikipedia.org/wiki/Variance + Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction + +Remark: + SVAR is also known as the Unbiased Sample Variance, while VAR (Population Variance) is known as + the Biased Sample Variance. + + */ + +public class SVAR_Series : Single_TSeries_Indicator +{ + public SVAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + if (base._data.Count > 0) { base.Add(base._data); } + } + private readonly System.Collections.Generic.List _buffer = new(); + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + Add_Replace_Trim(_buffer, TValue.v, _p, 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 + + base.Add((TValue.t, _svar), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Statistics/VAR_Series.cs b/Calculations/Statistics/VAR_Series.cs similarity index 96% rename from Source/Statistics/VAR_Series.cs rename to Calculations/Statistics/VAR_Series.cs index 2aebee3b..447ae16f 100644 --- a/Source/Statistics/VAR_Series.cs +++ b/Calculations/Statistics/VAR_Series.cs @@ -1,38 +1,38 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 : Single_TSeries_Indicator -{ - public VAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, 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; - - base.Add((TValue.t, _pvar), update, _NaN); - } +namespace QuanTAlib; +using System; +using System.Linq; + +/* +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 : Single_TSeries_Indicator +{ + public VAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + if (base._data.Count > 0) { base.Add(base._data); } + } + private readonly System.Collections.Generic.List _buffer = new(); + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + Add_Replace_Trim(_buffer, TValue.v, _p, 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; + + base.Add((TValue.t, _pvar), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Statistics/WMAPE_Series.cs b/Calculations/Statistics/WMAPE_Series.cs similarity index 100% rename from Source/Statistics/WMAPE_Series.cs rename to Calculations/Statistics/WMAPE_Series.cs diff --git a/Source/Statistics/ZSCORE_Series.cs b/Calculations/Statistics/ZSCORE_Series.cs similarity index 97% rename from Source/Statistics/ZSCORE_Series.cs rename to Calculations/Statistics/ZSCORE_Series.cs index 097482d9..fbaf02b9 100644 --- a/Source/Statistics/ZSCORE_Series.cs +++ b/Calculations/Statistics/ZSCORE_Series.cs @@ -1,46 +1,46 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 : Single_TSeries_Indicator -{ - public ZSCORE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, 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) ? double.NaN : (TValue.v - _sma) / _psdev; - - base.Add((TValue.t, _zscore), update, _NaN); - } +namespace QuanTAlib; +using System; +using System.Linq; + +/* +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 : Single_TSeries_Indicator +{ + public ZSCORE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + if (base._data.Count > 0) { base.Add(base._data); } + } + private readonly System.Collections.Generic.List _buffer = new(); + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + Add_Replace_Trim(_buffer, TValue.v, _p, 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) ? double.NaN : (TValue.v - _sma) / _psdev; + + base.Add((TValue.t, _zscore), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/ALMA_Series.cs b/Calculations/Trends/ALMA_Series.cs similarity index 97% rename from Source/Trends/ALMA_Series.cs rename to Calculations/Trends/ALMA_Series.cs index 39ff8101..ceb70320 100644 --- a/Source/Trends/ALMA_Series.cs +++ b/Calculations/Trends/ALMA_Series.cs @@ -1,63 +1,63 @@ -namespace QuanTAlib; -using System; - -/* -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/ - -TODO: Discrepancy with Pandas-TA (but passes the validation with Skender.GetAlma) - - */ - -public class ALMA_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double[] _weight; - private double _norm; - private readonly double _offset, _sigma; - - public ALMA_Series(TSeries source, int period, double offset = 0.85, double sigma = 6.0, bool useNaN = false) - : base(source, period, useNaN) - { - _offset = offset; - _sigma = sigma; - _weight = new double[period]; - - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - if (this._buffer.Count <= _p) - { - int _len = this._buffer.Count; - _norm = 0; - double _m = _offset * (_len - 1); - double _s = _len / _sigma; - for (int i = 0; i < _len; i++) - { - double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s)); - _weight[i] = _wt; - _norm += _wt; - } - } - - double _weightedSum = 0; - for (int i = 0; i < this._buffer.Count; i++) - { _weightedSum += _weight[i] * _buffer[i]; } - double _alma = _weightedSum / _norm; - - base.Add((TValue.t, _alma), update, _NaN); - } -} +namespace QuanTAlib; +using System; + +/* +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/ + +TODO: Discrepancy with Pandas-TA (but passes the validation with Skender.GetAlma) + + */ + +public class ALMA_Series : Single_TSeries_Indicator +{ + private readonly System.Collections.Generic.List _buffer = new(); + private readonly double[] _weight; + private double _norm; + private readonly double _offset, _sigma; + + public ALMA_Series(TSeries source, int period, double offset = 0.85, double sigma = 6.0, bool useNaN = false) + : base(source, period, useNaN) + { + _offset = offset; + _sigma = sigma; + _weight = new double[period]; + + if (this._data.Count > 0) { base.Add(this._data); } + } + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + Add_Replace_Trim(_buffer, TValue.v, _p, update); + + if (this._buffer.Count <= _p) + { + int _len = this._buffer.Count; + _norm = 0; + double _m = _offset * (_len - 1); + double _s = _len / _sigma; + for (int i = 0; i < _len; i++) + { + double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s)); + _weight[i] = _wt; + _norm += _wt; + } + } + + double _weightedSum = 0; + for (int i = 0; i < this._buffer.Count; i++) + { _weightedSum += _weight[i] * _buffer[i]; } + double _alma = _weightedSum / _norm; + + base.Add((TValue.t, _alma), update, _NaN); + } +} diff --git a/Source/Trends/DEMA_Series.cs b/Calculations/Trends/DEMA_Series.cs similarity index 96% rename from Source/Trends/DEMA_Series.cs rename to Calculations/Trends/DEMA_Series.cs index bc874e9e..3aaf2560 100644 --- a/Source/Trends/DEMA_Series.cs +++ b/Calculations/Trends/DEMA_Series.cs @@ -1,75 +1,75 @@ -namespace QuanTAlib; -using System; -using System.Linq; -using System.Runtime.CompilerServices; - -/* -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 : Single_TSeries_Indicator -{ - private readonly double _k; - private int _len; - private readonly bool _useSMA; - private double _sum, _lastsum, _lastlastsum; - private double _lastema1, _lastlastema1; - private double _lastema2, _lastlastema2; - - public DEMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) - { - _k = 2.0 / (_p + 1); - _len = 0; - _useSMA = useSMA; - _sum = _lastema1 = _lastema2 =0; - if (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - if (update) { - _lastsum = _lastlastsum; - _lastema1 = _lastlastema1; - _lastema2 = _lastlastema2; - } - else { - _lastlastsum = _lastsum; - _lastlastema1 = _lastema1; - _lastlastema2 = _lastema2; - _len++; - } - - double _ema1, _ema2, _dema; - if (this.Count == 0) { - _ema1 = _ema2 = _sum = TValue.v; - } - else if (_len <= _period && _useSMA && _period != 0) { - _sum += TValue.v; - if (_period != 0 && _len > _period) { - _sum -= (_data[base.Count - _period - (update ? 1 : 0)].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 = _ema1; - _lastema2 = _ema2; - - base.Add((TValue.t, _dema), update, _NaN); - } +namespace QuanTAlib; +using System; +using System.Linq; +using System.Runtime.CompilerServices; + +/* +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 : Single_TSeries_Indicator +{ + private readonly double _k; + private int _len; + private readonly bool _useSMA; + private double _sum, _lastsum, _lastlastsum; + private double _lastema1, _lastlastema1; + private double _lastema2, _lastlastema2; + + public DEMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) + { + _k = 2.0 / (_p + 1); + _len = 0; + _useSMA = useSMA; + _sum = _lastema1 = _lastema2 =0; + if (_data.Count > 0) { base.Add(_data); } + } + + public override void Add((DateTime t, double v) TValue, bool update) + { + if (update) { + _lastsum = _lastlastsum; + _lastema1 = _lastlastema1; + _lastema2 = _lastlastema2; + } + else { + _lastlastsum = _lastsum; + _lastlastema1 = _lastema1; + _lastlastema2 = _lastema2; + _len++; + } + + double _ema1, _ema2, _dema; + if (this.Count == 0) { + _ema1 = _ema2 = _sum = TValue.v; + } + else if (_len <= _period && _useSMA && _period != 0) { + _sum += TValue.v; + if (_period != 0 && _len > _period) { + _sum -= (_data[base.Count - _period - (update ? 1 : 0)].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 = _ema1; + _lastema2 = _ema2; + + base.Add((TValue.t, _dema), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/DWMA_Series.cs b/Calculations/Trends/DWMA_Series.cs similarity index 96% rename from Source/Trends/DWMA_Series.cs rename to Calculations/Trends/DWMA_Series.cs index ebda7418..7cdb0954 100644 --- a/Source/Trends/DWMA_Series.cs +++ b/Calculations/Trends/DWMA_Series.cs @@ -1,35 +1,35 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TSeries_Indicator { - public DWMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) { - for (int i = 0; i < this._p; i++) { - double _weight = (i + 1) * (i + 1); - this._weights.Add(_weight); - } - - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer1 = new(); - private readonly System.Collections.Generic.List _weights = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) { - Add_Replace_Trim(_buffer1, TValue.v, _p, update); - double _wma1 = 0; - double _wsum = 0; - for (int i = 0; i < _buffer1.Count; i++) { - _wma1 += _buffer1[i] * this._weights[i]; - _wsum += this._weights[i]; - } - _wma1 /= _wsum; - - base.Add((TValue.t, _wma1), update, _NaN); - } +namespace QuanTAlib; +using System; + +/* +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 : Single_TSeries_Indicator { + public DWMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) { + for (int i = 0; i < this._p; i++) { + double _weight = (i + 1) * (i + 1); + this._weights.Add(_weight); + } + + if (base._data.Count > 0) { base.Add(base._data); } + } + private readonly System.Collections.Generic.List _buffer1 = new(); + private readonly System.Collections.Generic.List _weights = new(); + + public override void Add((System.DateTime t, double v) TValue, bool update) { + Add_Replace_Trim(_buffer1, TValue.v, _p, update); + double _wma1 = 0; + double _wsum = 0; + for (int i = 0; i < _buffer1.Count; i++) { + _wma1 += _buffer1[i] * this._weights[i]; + _wsum += this._weights[i]; + } + _wma1 /= _wsum; + + base.Add((TValue.t, _wma1), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/EMA_Series.cs b/Calculations/Trends/EMA_Series.cs similarity index 97% rename from Source/Trends/EMA_Series.cs rename to Calculations/Trends/EMA_Series.cs index 6a3011ab..6fe35b19 100644 --- a/Source/Trends/EMA_Series.cs +++ b/Calculations/Trends/EMA_Series.cs @@ -1,71 +1,71 @@ -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 : Single_TSeries_Indicator { - private double _k; - private double _lastema, _lastlastema; - private double _sum, _oldsum; - private int _len; - private readonly bool _useSMA; - - public EMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) { - _k = 2.0 / (_p + 1); - _sum = _oldsum = _lastema = _lastlastema = 0; - _len = 0; - _useSMA = useSMA; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - - if (update) { _lastema = _lastlastema; _sum = _oldsum; } - else { _lastlastema = _lastema; _oldsum = _sum; _len++; } - - double _ema = 0; - // when period = 0, create cumulative/additive series where _k is progressively larger - if (_period == 0) { _k = 2.0 / (_len + 1); } - - // the first value of the series - if (this.Count == 0) { - _ema = _sum = TValue.v; - } - // if SMA is used for seeding, calculate SMA within period - else if (_len <= _period && _useSMA && _period != 0) { - _sum += TValue.v; - if (_period != 0 && _len > _period) { - _sum -= (_data[base.Count - _period - (update ? 1 : 0)].v); - } - _ema = _sum / Math.Min(_len, _period); - } - // calculate EMA out from last EMA and factor k - else { - _ema = _k * (TValue.v - _lastema) + _lastema; - } - _lastema = _ema; - - base.Add((TValue.t, _ema), update, _NaN); - } - public void Reset() { - _sum = _oldsum = _lastema = _lastlastema = 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 : Single_TSeries_Indicator { + private double _k; + private double _lastema, _lastlastema; + private double _sum, _oldsum; + private int _len; + private readonly bool _useSMA; + + public EMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) { + _k = 2.0 / (_p + 1); + _sum = _oldsum = _lastema = _lastlastema = 0; + _len = 0; + _useSMA = useSMA; + if (this._data.Count > 0) { base.Add(this._data); } + } + + public override void Add((DateTime t, double v) TValue, bool update) { + + if (update) { _lastema = _lastlastema; _sum = _oldsum; } + else { _lastlastema = _lastema; _oldsum = _sum; _len++; } + + double _ema = 0; + // when period = 0, create cumulative/additive series where _k is progressively larger + if (_period == 0) { _k = 2.0 / (_len + 1); } + + // the first value of the series + if (this.Count == 0) { + _ema = _sum = TValue.v; + } + // if SMA is used for seeding, calculate SMA within period + else if (_len <= _period && _useSMA && _period != 0) { + _sum += TValue.v; + if (_period != 0 && _len > _period) { + _sum -= (_data[base.Count - _period - (update ? 1 : 0)].v); + } + _ema = _sum / Math.Min(_len, _period); + } + // calculate EMA out from last EMA and factor k + else { + _ema = _k * (TValue.v - _lastema) + _lastema; + } + _lastema = _ema; + + base.Add((TValue.t, _ema), update, _NaN); + } + public void Reset() { + _sum = _oldsum = _lastema = _lastlastema = 0; + _len = 0; + } } \ No newline at end of file diff --git a/Source/Trends/FMA_Series.cs b/Calculations/Trends/FMA_Series.cs similarity index 100% rename from Source/Trends/FMA_Series.cs rename to Calculations/Trends/FMA_Series.cs diff --git a/Source/Trends/HEMA_Series.cs b/Calculations/Trends/HEMA_Series.cs similarity index 97% rename from Source/Trends/HEMA_Series.cs rename to Calculations/Trends/HEMA_Series.cs index 3f1678f5..dcb9d560 100644 --- a/Source/Trends/HEMA_Series.cs +++ b/Calculations/Trends/HEMA_Series.cs @@ -1,57 +1,57 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TSeries_Indicator -{ - public HEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - this._k1 = 4 / ((period * 0.5) + 1); - this._k2 = 3 / (double)(period + 1); - this._k3 = 2 / (Math.Sqrt(period) + 1); - this._lastema1 = this._lastlastema1 = double.NaN; - this._lastema2 = this._lastlastema2 = double.NaN; - this._lastema3 = this._lastlastema3 = double.NaN; - - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly double _k1, _k2, _k3; - private double _lastema1, _lastlastema1; - private double _lastema2, _lastlastema2; - private double _lastema3, _lastlastema3; - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - if (update) - { - this._lastema1 = this._lastlastema1; - this._lastema2 = this._lastlastema2; - this._lastema3 = this._lastlastema3; - } - double _ema1 = System.Double.IsNaN(this._lastema1) ? TValue.v : TValue.v * this._k1 + this._lastema1 * (1 - this._k1); - double _ema2 = System.Double.IsNaN(this._lastema2) ? TValue.v : TValue.v * this._k2 + this._lastema2 * (1 - this._k2); - - double _rawhema = (2 * _ema1) - _ema2; - double _ema3 = System.Double.IsNaN(this._lastema3) ? _rawhema : _rawhema * this._k3 + this._lastema3 * (1 - this._k3); - - this._lastlastema1 = this._lastema1; - this._lastlastema2 = this._lastema2; - this._lastlastema3 = this._lastema3; - this._lastema1 = _ema1; - this._lastema2 = _ema2; - this._lastema3 = _ema3; - - base.Add((TValue.t, _ema3), update, _NaN); - } +namespace QuanTAlib; +using System; + +/* +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 : Single_TSeries_Indicator +{ + public HEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + this._k1 = 4 / ((period * 0.5) + 1); + this._k2 = 3 / (double)(period + 1); + this._k3 = 2 / (Math.Sqrt(period) + 1); + this._lastema1 = this._lastlastema1 = double.NaN; + this._lastema2 = this._lastlastema2 = double.NaN; + this._lastema3 = this._lastlastema3 = double.NaN; + + if (base._data.Count > 0) { base.Add(base._data); } + } + private readonly double _k1, _k2, _k3; + private double _lastema1, _lastlastema1; + private double _lastema2, _lastlastema2; + private double _lastema3, _lastlastema3; + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + if (update) + { + this._lastema1 = this._lastlastema1; + this._lastema2 = this._lastlastema2; + this._lastema3 = this._lastlastema3; + } + double _ema1 = System.Double.IsNaN(this._lastema1) ? TValue.v : TValue.v * this._k1 + this._lastema1 * (1 - this._k1); + double _ema2 = System.Double.IsNaN(this._lastema2) ? TValue.v : TValue.v * this._k2 + this._lastema2 * (1 - this._k2); + + double _rawhema = (2 * _ema1) - _ema2; + double _ema3 = System.Double.IsNaN(this._lastema3) ? _rawhema : _rawhema * this._k3 + this._lastema3 * (1 - this._k3); + + this._lastlastema1 = this._lastema1; + this._lastlastema2 = this._lastema2; + this._lastlastema3 = this._lastema3; + this._lastema1 = _ema1; + this._lastema2 = _ema2; + this._lastema3 = _ema3; + + base.Add((TValue.t, _ema3), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/HMA_Series.cs b/Calculations/Trends/HMA_Series.cs similarity index 96% rename from Source/Trends/HMA_Series.cs rename to Calculations/Trends/HMA_Series.cs index ad6f30f8..8a522fba 100644 --- a/Source/Trends/HMA_Series.cs +++ b/Calculations/Trends/HMA_Series.cs @@ -1,119 +1,119 @@ -namespace QuanTAlib; -using System; - -/* -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 -{ - private readonly int _p; - private readonly bool _NaN; - private readonly TSeries _data; - private double _wma1, _wma2; - private readonly System.Collections.Generic.List _buf1 = new(); - private readonly System.Collections.Generic.List _buf2 = new(); - private readonly System.Collections.Generic.List _buf3 = new(); - private readonly System.Collections.Generic.List _weights = new(); - - public HMA_Series(TSeries source, int period, bool useNaN = false) - { - this._p = period; - this._data = source; - this._NaN = useNaN; - for (int i = 0; i < this._p; i++) - { - this._weights.Add(i + 1); - } - - source.Pub += this.Sub; - if (source.Count > 0) - { - for (int i = 0; i < source.Count; i++) - { - this.Add(source[i], false); - } - } - } - public new void Add((System.DateTime t, double v) data, bool update = false) - { - if (update) - { - this._buf1[this._buf1.Count - 1] = data.v; - this._buf2[this._buf2.Count - 1] = data.v; - } - else - { - this._buf1.Add(data.v); - this._buf2.Add(data.v); - } - if (this._buf1.Count > (int)((double)this._p / 2)) - { - this._buf1.RemoveAt(0); - } - if (this._buf2.Count > this._p) - { - this._buf2.RemoveAt(0); - } - - this._wma1 = 0; - for (int i = 0; i < this._buf1.Count; i++) - { - this._wma1 += this._buf1[i] * this._weights[i]; - } - this._wma1 /= (this._buf1.Count * (this._buf1.Count + 1)) * 0.5; - - this._wma2 = 0; - for (int i = 0; i < this._buf2.Count; i++) - { - this._wma2 += this._buf2[i] * this._weights[i]; - } - this._wma2 /= (this._buf2.Count * (this._buf2.Count + 1)) * 0.5; - - if (update) - { - this._buf3[this._buf3.Count - 1] = 2 * this._wma1 - this._wma2; - } - else - { - this._buf3.Add(2 * this._wma1 - this._wma2); - } - - if (this._buf3.Count > (int)Math.Sqrt(this._p)) - { - this._buf3.RemoveAt(0); - } - - double _hma = 0; - for (int i = 0; i < this._buf3.Count; i++) - { - _hma += this._buf3[i] * this._weights[i]; - } - - _hma /= (this._buf3.Count * (this._buf3.Count + 1)) * 0.5; - - (System.DateTime t, double v) result = - (data.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _hma); - base.Add(result, update); - } - public void Add(bool update = false) - { - this.Add(this._data[this._data.Count - 1], update); - } - public new void Sub(object source, TSeriesEventArgs e) - { - this.Add(this._data[this._data.Count - 1], e.update); - } -} +namespace QuanTAlib; +using System; + +/* +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 +{ + private readonly int _p; + private readonly bool _NaN; + private readonly TSeries _data; + private double _wma1, _wma2; + private readonly System.Collections.Generic.List _buf1 = new(); + private readonly System.Collections.Generic.List _buf2 = new(); + private readonly System.Collections.Generic.List _buf3 = new(); + private readonly System.Collections.Generic.List _weights = new(); + + public HMA_Series(TSeries source, int period, bool useNaN = false) + { + this._p = period; + this._data = source; + this._NaN = useNaN; + for (int i = 0; i < this._p; i++) + { + this._weights.Add(i + 1); + } + + source.Pub += this.Sub; + if (source.Count > 0) + { + for (int i = 0; i < source.Count; i++) + { + this.Add(source[i], false); + } + } + } + public new void Add((System.DateTime t, double v) data, bool update = false) + { + if (update) + { + this._buf1[this._buf1.Count - 1] = data.v; + this._buf2[this._buf2.Count - 1] = data.v; + } + else + { + this._buf1.Add(data.v); + this._buf2.Add(data.v); + } + if (this._buf1.Count > (int)((double)this._p / 2)) + { + this._buf1.RemoveAt(0); + } + if (this._buf2.Count > this._p) + { + this._buf2.RemoveAt(0); + } + + this._wma1 = 0; + for (int i = 0; i < this._buf1.Count; i++) + { + this._wma1 += this._buf1[i] * this._weights[i]; + } + this._wma1 /= (this._buf1.Count * (this._buf1.Count + 1)) * 0.5; + + this._wma2 = 0; + for (int i = 0; i < this._buf2.Count; i++) + { + this._wma2 += this._buf2[i] * this._weights[i]; + } + this._wma2 /= (this._buf2.Count * (this._buf2.Count + 1)) * 0.5; + + if (update) + { + this._buf3[this._buf3.Count - 1] = 2 * this._wma1 - this._wma2; + } + else + { + this._buf3.Add(2 * this._wma1 - this._wma2); + } + + if (this._buf3.Count > (int)Math.Sqrt(this._p)) + { + this._buf3.RemoveAt(0); + } + + double _hma = 0; + for (int i = 0; i < this._buf3.Count; i++) + { + _hma += this._buf3[i] * this._weights[i]; + } + + _hma /= (this._buf3.Count * (this._buf3.Count + 1)) * 0.5; + + (System.DateTime t, double v) result = + (data.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _hma); + base.Add(result, update); + } + public void Add(bool update = false) + { + this.Add(this._data[this._data.Count - 1], update); + } + public new void Sub(object source, TSeriesEventArgs e) + { + this.Add(this._data[this._data.Count - 1], e.update); + } +} diff --git a/Source/Trends/HWMA_Series.cs b/Calculations/Trends/HWMA_Series.cs similarity index 100% rename from Source/Trends/HWMA_Series.cs rename to Calculations/Trends/HWMA_Series.cs diff --git a/Source/Trends/JMA_Series.cs b/Calculations/Trends/JMA_Series.cs similarity index 97% rename from Source/Trends/JMA_Series.cs rename to Calculations/Trends/JMA_Series.cs index 0ce50524..09cdeeb3 100644 --- a/Source/Trends/JMA_Series.cs +++ b/Calculations/Trends/JMA_Series.cs @@ -1,125 +1,125 @@ -namespace QuanTAlib; -using System; -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 : Single_TSeries_Indicator { - 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; } - public TSeries mma2 { get; } - - 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, 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(); - - if (base._data.Count > 0) { base.Add(base._data); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) { - 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; - } - - // from Tvalue to volty - del1 = TValue.v - upperBand; - del2 = TValue.v - lowerBand; - upperBand = (del1 > 0) ? TValue.v : TValue.v - (Kv * del1); - lowerBand = (del2 < 0) ? TValue.v : TValue.v - (Kv * del2); - double volty = 0; - if (Math.Abs(del1) > Math.Abs(del2)) { volty = Math.Abs(del1); } - if (Math.Abs(del1) < Math.Abs(del2)) { volty = Math.Abs(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(_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 beta = 0.45 * (_p - 1) / (0.45 * (_p - 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; - mma1.Add(ma1); - - double det0 = (1 - beta) * (TValue.v - ma1) + beta * prev_det0; - prev_det0 = det0; - double ma2 = ma1 + pr * det0; - mma2.Add(ma2); - - double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - prev_jma)) + (alpha * alpha * prev_det1); - prev_det1 = det1; - double jma = prev_jma + det1; - prev_jma = jma; - - base.Add((TValue.t, jma), update, _NaN); - } +namespace QuanTAlib; +using System; +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 : Single_TSeries_Indicator { + 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; } + public TSeries mma2 { get; } + + 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, 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(); + + if (base._data.Count > 0) { base.Add(base._data); } + } + + public override void Add((System.DateTime t, double v) TValue, bool update) { + 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; + } + + // from Tvalue to volty + del1 = TValue.v - upperBand; + del2 = TValue.v - lowerBand; + upperBand = (del1 > 0) ? TValue.v : TValue.v - (Kv * del1); + lowerBand = (del2 < 0) ? TValue.v : TValue.v - (Kv * del2); + double volty = 0; + if (Math.Abs(del1) > Math.Abs(del2)) { volty = Math.Abs(del1); } + if (Math.Abs(del1) < Math.Abs(del2)) { volty = Math.Abs(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(_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 beta = 0.45 * (_p - 1) / (0.45 * (_p - 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; + mma1.Add(ma1); + + double det0 = (1 - beta) * (TValue.v - ma1) + beta * prev_det0; + prev_det0 = det0; + double ma2 = ma1 + pr * det0; + mma2.Add(ma2); + + double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - prev_jma)) + (alpha * alpha * prev_det1); + prev_det1 = det1; + double jma = prev_jma + det1; + prev_jma = jma; + + base.Add((TValue.t, jma), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/KAMA_Series.cs b/Calculations/Trends/KAMA_Series.cs similarity index 97% rename from Source/Trends/KAMA_Series.cs rename to Calculations/Trends/KAMA_Series.cs index 812fa6c2..808ce8c7 100644 --- a/Source/Trends/KAMA_Series.cs +++ b/Calculations/Trends/KAMA_Series.cs @@ -1,64 +1,64 @@ -namespace QuanTAlib; -using System; - -/* -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. - - KAMAi = KAMAi - 1 + SC * ( price - KAMAi-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 : Single_TSeries_Indicator -{ - private readonly double _scFast, _scSlow; - private readonly System.Collections.Generic.List _buffer = new(); - private double _lastkama = double.NaN; - private double _lastlastkama; - - public KAMA_Series(TSeries source, int period, int fast = 2, int slow= 30, bool useNaN = false) : base(source, period, useNaN) { - _scFast = 2.0 / (fast+1); - _scSlow = 2.0 / (slow+1); - if (base._data.Count > 0) { base.Add(base._data); } - } - public override void Add((System.DateTime t, double v) TValue, bool update) - { - if (update){ - _buffer[_buffer.Count - 1] = TValue.v; - _lastkama = _lastlastkama; - } - else { - _buffer.Add(TValue.v); - _lastlastkama = _lastkama; - } - if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); } - - double _kama = 0; - if (this.Count < this._p) { _kama = TValue.v; } - else { - double _change = Math.Abs(_buffer[_buffer.Count - 1] - _buffer[(_buffer.Count > _p + 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; - base.Add((TValue.t, _kama), update, _NaN); - } +namespace QuanTAlib; +using System; + +/* +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. + + KAMAi = KAMAi - 1 + SC * ( price - KAMAi-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 : Single_TSeries_Indicator +{ + private readonly double _scFast, _scSlow; + private readonly System.Collections.Generic.List _buffer = new(); + private double _lastkama = double.NaN; + private double _lastlastkama; + + public KAMA_Series(TSeries source, int period, int fast = 2, int slow= 30, bool useNaN = false) : base(source, period, useNaN) { + _scFast = 2.0 / (fast+1); + _scSlow = 2.0 / (slow+1); + if (base._data.Count > 0) { base.Add(base._data); } + } + public override void Add((System.DateTime t, double v) TValue, bool update) + { + if (update){ + _buffer[_buffer.Count - 1] = TValue.v; + _lastkama = _lastlastkama; + } + else { + _buffer.Add(TValue.v); + _lastlastkama = _lastkama; + } + if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); } + + double _kama = 0; + if (this.Count < this._p) { _kama = TValue.v; } + else { + double _change = Math.Abs(_buffer[_buffer.Count - 1] - _buffer[(_buffer.Count > _p + 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; + base.Add((TValue.t, _kama), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/MACD_Series.cs b/Calculations/Trends/MACD_Series.cs similarity index 97% rename from Source/Trends/MACD_Series.cs rename to Calculations/Trends/MACD_Series.cs index ebe205f2..02f9360c 100644 --- a/Source/Trends/MACD_Series.cs +++ b/Calculations/Trends/MACD_Series.cs @@ -1,45 +1,45 @@ -namespace QuanTAlib; -using System; - -/* -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. - -Sources: - https://www.investopedia.com/terms/m/macd.asp - https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/macd - - */ - -public class MACD_Series : Single_TSeries_Indicator -{ - private readonly EMA_Series _TSslow; - private readonly EMA_Series _TSfast; - private readonly SUB_Series _TSmacd; - public EMA_Series Signal { get; } - - public MACD_Series(TSeries source, int slow = 26, int fast = 12, int signal = 9, bool useNaN = false) - : base(source, period: 0, useNaN) - { - _TSslow = new(source: source, period: slow, useNaN: false); - _TSfast = new(source: source, period: fast, useNaN: false); - _TSmacd = new(_TSfast, _TSslow); - this.Signal = new(source: _TSmacd, period: signal, useNaN: useNaN); - - if (source.Count > 0) { base.Add(_TSmacd); } - } - public override void Add((System.DateTime t, double v) TValue, bool update) - { - double _macd; - if (update) - { - _TSslow.Add(TValue, true); - _TSfast.Add(TValue, true); - } - _macd = this._TSmacd[(this.Count < this._TSmacd.Count) ? this.Count : this._TSmacd.Count - 1].v; - base.Add((TValue.t, _macd), update, _NaN); - } +namespace QuanTAlib; +using System; + +/* +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. + +Sources: + https://www.investopedia.com/terms/m/macd.asp + https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/macd + + */ + +public class MACD_Series : Single_TSeries_Indicator +{ + private readonly EMA_Series _TSslow; + private readonly EMA_Series _TSfast; + private readonly SUB_Series _TSmacd; + public EMA_Series Signal { get; } + + public MACD_Series(TSeries source, int slow = 26, int fast = 12, int signal = 9, bool useNaN = false) + : base(source, period: 0, useNaN) + { + _TSslow = new(source: source, period: slow, useNaN: false); + _TSfast = new(source: source, period: fast, useNaN: false); + _TSmacd = new(_TSfast, _TSslow); + this.Signal = new(source: _TSmacd, period: signal, useNaN: useNaN); + + if (source.Count > 0) { base.Add(_TSmacd); } + } + public override void Add((System.DateTime t, double v) TValue, bool update) + { + double _macd; + if (update) + { + _TSslow.Add(TValue, true); + _TSfast.Add(TValue, true); + } + _macd = this._TSmacd[(this.Count < this._TSmacd.Count) ? this.Count : this._TSmacd.Count - 1].v; + base.Add((TValue.t, _macd), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/MAMA_Series.cs b/Calculations/Trends/MAMA_Series.cs similarity index 97% rename from Source/Trends/MAMA_Series.cs rename to Calculations/Trends/MAMA_Series.cs index 0224dc98..ff85d784 100644 --- a/Source/Trends/MAMA_Series.cs +++ b/Calculations/Trends/MAMA_Series.cs @@ -1,118 +1,118 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TSeries_Indicator -{ - public MAMA_Series(TSeries source, double fastlimit = 0.5, double slowlimit = 0.05, bool useNaN = false) : base(source, period: 5, useNaN) - { - fastl = fastlimit; - slowl = slowlimit; - Fama = new(); - if (base._data.Count > 0) { base.Add(base._data); } - } - - private double sumPr, jI, jQ, 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; } - - public override void Add((System.DateTime t, double v) TValue, bool 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; - } - int i = base.Count; - pr.i = TValue.v; - if (i > 5) { - double 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 - jI = ((0.0962 * i1.i) + (0.5769 * i1.i2) - (0.5769 * i1.i4) - (0.0962 * i1.i6)) * adj; - 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 - double delta = Math.Max(ph.i1 - ph.i, 1d); - - // adaptive alpha value - double alpha = Math.Max(fastl / delta, slowl); - - // final indicators - mama.i = ((alpha * pr.i) + ((1d - alpha) * mama.i1)); - fama.i = ((0.5d * alpha * mama.i) + ((1d - (0.5d * alpha)) * 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); - } - - base.Add((TValue.t, mama.i), update, _NaN); - var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : fama.i); - Fama.Add(result, update); - } -} +namespace QuanTAlib; +using System; + +/* +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 : Single_TSeries_Indicator +{ + public MAMA_Series(TSeries source, double fastlimit = 0.5, double slowlimit = 0.05, bool useNaN = false) : base(source, period: 5, useNaN) + { + fastl = fastlimit; + slowl = slowlimit; + Fama = new(); + if (base._data.Count > 0) { base.Add(base._data); } + } + + private double sumPr, jI, jQ, 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; } + + public override void Add((System.DateTime t, double v) TValue, bool 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; + } + int i = base.Count; + pr.i = TValue.v; + if (i > 5) { + double 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 + jI = ((0.0962 * i1.i) + (0.5769 * i1.i2) - (0.5769 * i1.i4) - (0.0962 * i1.i6)) * adj; + 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 + double delta = Math.Max(ph.i1 - ph.i, 1d); + + // adaptive alpha value + double alpha = Math.Max(fastl / delta, slowl); + + // final indicators + mama.i = ((alpha * pr.i) + ((1d - alpha) * mama.i1)); + fama.i = ((0.5d * alpha * mama.i) + ((1d - (0.5d * alpha)) * 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); + } + + base.Add((TValue.t, mama.i), update, _NaN); + var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : fama.i); + Fama.Add(result, update); + } +} diff --git a/Source/Trends/RMA_Series.cs b/Calculations/Trends/RMA_Series.cs similarity index 97% rename from Source/Trends/RMA_Series.cs rename to Calculations/Trends/RMA_Series.cs index e8b1ef63..f7059c51 100644 --- a/Source/Trends/RMA_Series.cs +++ b/Calculations/Trends/RMA_Series.cs @@ -1,56 +1,56 @@ -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 : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k, _k1m; - private double _lastema, _lastlastema; - - public RMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - this._k = 1.0 / (double)(this._p); - this._k1m = 1.0 - this._k; - this._lastema = this._lastlastema = double.NaN; - if (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - double _ema; - if (update) { this._lastema = this._lastlastema; } - - if (this.Count < this._p) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - _ema = _buffer.Average(); - } - else - { - _ema = (TValue.v * _k) + (_lastema * _k1m); - } - - this._lastlastema = this._lastema; - this._lastema = _ema; - - base.Add((TValue.t, _ema), update, _NaN); - } +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 : Single_TSeries_Indicator +{ + private readonly System.Collections.Generic.List _buffer = new(); + private readonly double _k, _k1m; + private double _lastema, _lastlastema; + + public RMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + this._k = 1.0 / (double)(this._p); + this._k1m = 1.0 - this._k; + this._lastema = this._lastlastema = double.NaN; + if (_data.Count > 0) { base.Add(_data); } + } + + public override void Add((DateTime t, double v) TValue, bool update) + { + double _ema; + if (update) { this._lastema = this._lastlastema; } + + if (this.Count < this._p) + { + Add_Replace_Trim(_buffer, TValue.v, _p, update); + _ema = _buffer.Average(); + } + else + { + _ema = (TValue.v * _k) + (_lastema * _k1m); + } + + this._lastlastema = this._lastema; + this._lastema = _ema; + + base.Add((TValue.t, _ema), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/SMA_Series.cs b/Calculations/Trends/SMA_Series.cs similarity index 96% rename from Source/Trends/SMA_Series.cs rename to Calculations/Trends/SMA_Series.cs index 9c23f298..84c8395d 100644 --- a/Source/Trends/SMA_Series.cs +++ b/Calculations/Trends/SMA_Series.cs @@ -1,44 +1,44 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TSeries_Indicator { - private double _sum, _oldsum; - private int _len; - - public SMA_Series(TSeries source, int period = 0, bool useNaN = false) : base(source, period, false) { - _sum = _oldsum = 0; - _len = 0; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - if (update) { _sum = _oldsum; } - else { _oldsum = _sum; _len++; } - - _sum += TValue.v; - if (_period != 0 && _len > _period) { - _sum -= (_data[base.Count - _period - (update ? 1 : 0)].v); - } - double _div = (_period == 0) ? _len : Math.Min(_len, _period); - base.Add((TValue.t, _sum / _div), update, _NaN); - } - public void Reset() { - _sum = _oldsum = 0; - _len = 0; - } -} +namespace QuanTAlib; +using System; + +/* +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 : Single_TSeries_Indicator { + private double _sum, _oldsum; + private int _len; + + public SMA_Series(TSeries source, int period = 0, bool useNaN = false) : base(source, period, false) { + _sum = _oldsum = 0; + _len = 0; + if (this._data.Count > 0) { base.Add(this._data); } + } + + public override void Add((DateTime t, double v) TValue, bool update) { + if (update) { _sum = _oldsum; } + else { _oldsum = _sum; _len++; } + + _sum += TValue.v; + if (_period != 0 && _len > _period) { + _sum -= (_data[base.Count - _period - (update ? 1 : 0)].v); + } + double _div = (_period == 0) ? _len : Math.Min(_len, _period); + base.Add((TValue.t, _sum / _div), update, _NaN); + } + public void Reset() { + _sum = _oldsum = 0; + _len = 0; + } +} diff --git a/Source/Trends/SMMA_Series.cs b/Calculations/Trends/SMMA_Series.cs similarity index 97% rename from Source/Trends/SMMA_Series.cs rename to Calculations/Trends/SMMA_Series.cs index 08a22068..27d3bfcd 100644 --- a/Source/Trends/SMMA_Series.cs +++ b/Calculations/Trends/SMMA_Series.cs @@ -1,51 +1,51 @@ -namespace QuanTAlib; -using System; -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 : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private double _lastsmma, _lastlastsmma; - - public SMMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - this._lastsmma = this._lastlastsmma = double.NaN; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - double _smma = 0; - if (update) { this._lastsmma = this._lastlastsmma; } - - if (this.Count < this._p) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - _smma = _buffer.Average(); - } - else - { - _smma = ((_lastsmma * (_p-1)) + TValue.v) / _p ; - } - - this._lastlastsmma = this._lastsmma; - this._lastsmma = _smma; - - base.Add((TValue.t, _smma), update, _NaN); - } +namespace QuanTAlib; +using System; +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 : Single_TSeries_Indicator +{ + private readonly System.Collections.Generic.List _buffer = new(); + private double _lastsmma, _lastlastsmma; + + public SMMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + this._lastsmma = this._lastlastsmma = double.NaN; + if (this._data.Count > 0) { base.Add(this._data); } + } + + public override void Add((DateTime t, double v) TValue, bool update) + { + double _smma = 0; + if (update) { this._lastsmma = this._lastlastsmma; } + + if (this.Count < this._p) + { + Add_Replace_Trim(_buffer, TValue.v, _p, update); + _smma = _buffer.Average(); + } + else + { + _smma = ((_lastsmma * (_p-1)) + TValue.v) / _p ; + } + + this._lastlastsmma = this._lastsmma; + this._lastsmma = _smma; + + base.Add((TValue.t, _smma), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/T3_Series.cs b/Calculations/Trends/T3_Series.cs similarity index 97% rename from Source/Trends/T3_Series.cs rename to Calculations/Trends/T3_Series.cs index 12479ceb..304fc200 100644 --- a/Source/Trends/T3_Series.cs +++ b/Calculations/Trends/T3_Series.cs @@ -1,110 +1,110 @@ -namespace QuanTAlib; -using System; -using System.Linq; -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/ - -Calculation: - Volume Factor is typically 0.7 (but also 0.618); - Ema1 = Ema (Close); - Ema2 = Ema (Ema1); - Ema3 = Ema (Ema2); - Ema4 = Ema (Ema3); - Ema5 = Ema (Ema4); - Ema6 = Ema (Ema5); - T3 = –(a*a*a) * Ema6 + (3*a*a + 3*a*a*a) * Ema5 + (–6*a*a – 3*a – 3*a*a*a) * Ema4 + (1 + 3*a + a*a*a + 3*a*a) * Ema3 - - */ -public class T3_Series : Single_TSeries_Indicator { - 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 double _lastema1, _lastema2, _lastema3, _lastema4, _lastema5, _lastema6; - private double _llastema1, _llastema2, _llastema3, _llastema4, _llastema5, _llastema6; - private bool _useSMA; - - public T3_Series(TSeries source, int period, double vfactor = 0.7, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) { - 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 / (_p + 1); - _k1m = 1.0 - _k; - _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0; - _useSMA = useSMA; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - double _ema1, _ema2, _ema3, _ema4, _ema5, _ema6; - 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 (this.Count == 0) { _lastema1 = _lastema2 = _lastema3 = _lastema4 = _lastema5 = _lastema6 = TValue.v; } - - if ((this.Count < _p) && _useSMA) { - Add_Replace(_buffer1, TValue.v, update); - _ema1 = 0; - for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; } - _ema1 /= _buffer1.Count; - - Add_Replace(_buffer2, _ema1, update); - _ema2 = 0; - for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } - _ema2 /= _buffer2.Count; - - Add_Replace(_buffer3, _ema2, update); - _ema3 = 0; - for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; } - _ema3 /= _buffer3.Count; - - Add_Replace(_buffer4, _ema3, update); - _ema4 = 0; - for (int i = 0; i < _buffer4.Count; i++) { _ema4 += _buffer4[i]; } - _ema4 /= _buffer4.Count; - - Add_Replace(_buffer5, _ema4, update); - _ema5 = 0; - for (int i = 0; i < _buffer5.Count; i++) { _ema5 += _buffer5[i]; } - _ema5 /= _buffer5.Count; - - Add_Replace(_buffer6, _ema5, 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); - } - _lastema1 = _ema1; - _lastema2 = _ema2; - _lastema3 = _ema3; - _lastema4 = _ema4; - _lastema5 = _ema5; - _lastema6 = _ema6; - - double _T3 = _c1 * _ema6 + _c2 * _ema5 + _c3 * _ema4 + _c4 * _ema3; - base.Add((TValue.t, _T3), update, _NaN); - } +namespace QuanTAlib; +using System; +using System.Linq; +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/ + +Calculation: + Volume Factor is typically 0.7 (but also 0.618); + Ema1 = Ema (Close); + Ema2 = Ema (Ema1); + Ema3 = Ema (Ema2); + Ema4 = Ema (Ema3); + Ema5 = Ema (Ema4); + Ema6 = Ema (Ema5); + T3 = –(a*a*a) * Ema6 + (3*a*a + 3*a*a*a) * Ema5 + (–6*a*a – 3*a – 3*a*a*a) * Ema4 + (1 + 3*a + a*a*a + 3*a*a) * Ema3 + + */ +public class T3_Series : Single_TSeries_Indicator { + 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 double _lastema1, _lastema2, _lastema3, _lastema4, _lastema5, _lastema6; + private double _llastema1, _llastema2, _llastema3, _llastema4, _llastema5, _llastema6; + private bool _useSMA; + + public T3_Series(TSeries source, int period, double vfactor = 0.7, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) { + 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 / (_p + 1); + _k1m = 1.0 - _k; + _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0; + _useSMA = useSMA; + if (this._data.Count > 0) { base.Add(this._data); } + } + + public override void Add((DateTime t, double v) TValue, bool update) { + double _ema1, _ema2, _ema3, _ema4, _ema5, _ema6; + 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 (this.Count == 0) { _lastema1 = _lastema2 = _lastema3 = _lastema4 = _lastema5 = _lastema6 = TValue.v; } + + if ((this.Count < _p) && _useSMA) { + Add_Replace(_buffer1, TValue.v, update); + _ema1 = 0; + for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; } + _ema1 /= _buffer1.Count; + + Add_Replace(_buffer2, _ema1, update); + _ema2 = 0; + for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } + _ema2 /= _buffer2.Count; + + Add_Replace(_buffer3, _ema2, update); + _ema3 = 0; + for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; } + _ema3 /= _buffer3.Count; + + Add_Replace(_buffer4, _ema3, update); + _ema4 = 0; + for (int i = 0; i < _buffer4.Count; i++) { _ema4 += _buffer4[i]; } + _ema4 /= _buffer4.Count; + + Add_Replace(_buffer5, _ema4, update); + _ema5 = 0; + for (int i = 0; i < _buffer5.Count; i++) { _ema5 += _buffer5[i]; } + _ema5 /= _buffer5.Count; + + Add_Replace(_buffer6, _ema5, 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); + } + _lastema1 = _ema1; + _lastema2 = _ema2; + _lastema3 = _ema3; + _lastema4 = _ema4; + _lastema5 = _ema5; + _lastema6 = _ema6; + + double _T3 = _c1 * _ema6 + _c2 * _ema5 + _c3 * _ema4 + _c4 * _ema3; + base.Add((TValue.t, _T3), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/TEMA_Series.cs b/Calculations/Trends/TEMA_Series.cs similarity index 96% rename from Source/Trends/TEMA_Series.cs rename to Calculations/Trends/TEMA_Series.cs index 3cb1aafc..71f84698 100644 --- a/Source/Trends/TEMA_Series.cs +++ b/Calculations/Trends/TEMA_Series.cs @@ -1,70 +1,70 @@ -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 : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k, _k1m; - private double _lastema1, _lastlastema1; - private double _lastema2, _lastlastema2; - private double _lastema3, _lastlastema3; - - public TEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - this._k = 2.0 / (this._p + 1); - this._k1m = 1.0 - this._k; - if (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - if (update) - { - this._lastema1 = this._lastlastema1; - this._lastema2 = this._lastlastema2; - this._lastema3 = this._lastlastema3; - } - - double _ema1, _ema2, _ema3; - - if (this.Count < this._p) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - _ema1 = _ema2 = _ema3 = _sma; - } - 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); - } - - double _tema = (3 * (_ema1 - _ema2)) + _ema3; - - this._lastlastema1 = this._lastema1; - this._lastlastema2 = this._lastema2; - this._lastlastema3 = this._lastema3; - this._lastema1 = _ema1; - this._lastema2 = _ema2; - this._lastema3 = _ema3; - - base.Add((TValue.t, _tema), update, _NaN); - } +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 : Single_TSeries_Indicator +{ + private readonly System.Collections.Generic.List _buffer = new(); + private readonly double _k, _k1m; + private double _lastema1, _lastlastema1; + private double _lastema2, _lastlastema2; + private double _lastema3, _lastlastema3; + + public TEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + this._k = 2.0 / (this._p + 1); + this._k1m = 1.0 - this._k; + if (_data.Count > 0) { base.Add(_data); } + } + + public override void Add((DateTime t, double v) TValue, bool update) + { + if (update) + { + this._lastema1 = this._lastlastema1; + this._lastema2 = this._lastlastema2; + this._lastema3 = this._lastlastema3; + } + + double _ema1, _ema2, _ema3; + + if (this.Count < this._p) + { + Add_Replace_Trim(_buffer, TValue.v, _p, update); + double _sma = _buffer.Average(); + _ema1 = _ema2 = _ema3 = _sma; + } + 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); + } + + double _tema = (3 * (_ema1 - _ema2)) + _ema3; + + this._lastlastema1 = this._lastema1; + this._lastlastema2 = this._lastema2; + this._lastlastema3 = this._lastema3; + this._lastema1 = _ema1; + this._lastema2 = _ema2; + this._lastema3 = _ema3; + + base.Add((TValue.t, _tema), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/TRIMA_Series.cs b/Calculations/Trends/TRIMA_Series.cs similarity index 97% rename from Source/Trends/TRIMA_Series.cs rename to Calculations/Trends/TRIMA_Series.cs index d0276359..7a082b7e 100644 --- a/Source/Trends/TRIMA_Series.cs +++ b/Calculations/Trends/TRIMA_Series.cs @@ -1,43 +1,43 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer1 = new(); - private readonly System.Collections.Generic.List _buffer2 = new(); - private readonly int _p1a, _p1b; - - public TRIMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - _p1a = (int) Math.Floor((period * 0.5) + 1); - _p1b = (int) Math.Ceiling(0.5 * period); - if (base._data.Count > 0) { base.Add(base._data); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - if (update) { _buffer1[_buffer1.Count - 1] = TValue.v; } else { _buffer1.Add(TValue.v); } - if (_buffer1.Count > this._p1b && this._p1b != 0) { _buffer1.RemoveAt(0); } - double _sma1 = _buffer1.Average(); - - if (update) { _buffer2[_buffer2.Count - 1] = _sma1; } else { _buffer2.Add(_sma1); } - if (_buffer2.Count > this._p1a && this._p1a != 0) { _buffer2.RemoveAt(0); } - double _trima = _buffer2.Average(); - - base.Add((TValue.t, _trima), update, _NaN); - } +namespace QuanTAlib; +using System; +using System.Linq; + +/* +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 : Single_TSeries_Indicator +{ + private readonly System.Collections.Generic.List _buffer1 = new(); + private readonly System.Collections.Generic.List _buffer2 = new(); + private readonly int _p1a, _p1b; + + public TRIMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + _p1a = (int) Math.Floor((period * 0.5) + 1); + _p1b = (int) Math.Ceiling(0.5 * period); + if (base._data.Count > 0) { base.Add(base._data); } + } + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + if (update) { _buffer1[_buffer1.Count - 1] = TValue.v; } else { _buffer1.Add(TValue.v); } + if (_buffer1.Count > this._p1b && this._p1b != 0) { _buffer1.RemoveAt(0); } + double _sma1 = _buffer1.Average(); + + if (update) { _buffer2[_buffer2.Count - 1] = _sma1; } else { _buffer2.Add(_sma1); } + if (_buffer2.Count > this._p1a && this._p1a != 0) { _buffer2.RemoveAt(0); } + double _trima = _buffer2.Average(); + + base.Add((TValue.t, _trima), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/TRIX_Series.cs b/Calculations/Trends/TRIX_Series.cs similarity index 99% rename from Source/Trends/TRIX_Series.cs rename to Calculations/Trends/TRIX_Series.cs index d557bc56..36c97fdb 100644 --- a/Source/Trends/TRIX_Series.cs +++ b/Calculations/Trends/TRIX_Series.cs @@ -1,25 +1,25 @@ -namespace QuanTAlib; -using System; -using System.Linq; -using System.Numerics; - -/* -TRIX: Triple Exponential Average - 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. - - -Calculation: - Ema1 = Ema (Close); - Ema2 = Ema (Ema1); - Ema3 = Ema (Ema2); - TRIX = (Ema3-Ema3[1]) / Ema3[1] - -Sources: - https://www.investopedia.com/terms/t/trix.asp - - */ +namespace QuanTAlib; +using System; +using System.Linq; +using System.Numerics; + +/* +TRIX: Triple Exponential Average + 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. + + +Calculation: + Ema1 = Ema (Close); + Ema2 = Ema (Ema1); + Ema3 = Ema (Ema2); + TRIX = (Ema3-Ema3[1]) / Ema3[1] + +Sources: + https://www.investopedia.com/terms/t/trix.asp + + */ public class TRIX_Series : Single_TSeries_Indicator { private readonly double _k, _k1m; @@ -78,5 +78,5 @@ public class TRIX_Series : Single_TSeries_Indicator _lastema3 = _ema3; base.Add((TValue.t, _trix), update, _NaN); - } + } } \ No newline at end of file diff --git a/Source/Trends/WMA_Series.cs b/Calculations/Trends/WMA_Series.cs similarity index 97% rename from Source/Trends/WMA_Series.cs rename to Calculations/Trends/WMA_Series.cs index a6c4a1aa..2b835b7f 100644 --- a/Source/Trends/WMA_Series.cs +++ b/Calculations/Trends/WMA_Series.cs @@ -1,35 +1,35 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TSeries_Indicator -{ - public WMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - for (int i = 0; i < this._p; i++) { this._weights.Add(i + 1); } - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - private readonly System.Collections.Generic.List _weights = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _wma = 0; - for (int i = 0; i < _buffer.Count; i++) { _wma += _buffer[i] * this._weights[i]; } - _wma /= (this._buffer.Count * (this._buffer.Count + 1)) * 0.5; - - base.Add((TValue.t, _wma), update, _NaN); - } +namespace QuanTAlib; +using System; + +/* +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 : Single_TSeries_Indicator +{ + public WMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + for (int i = 0; i < this._p; i++) { this._weights.Add(i + 1); } + if (base._data.Count > 0) { base.Add(base._data); } + } + private readonly System.Collections.Generic.List _buffer = new(); + private readonly System.Collections.Generic.List _weights = new(); + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + Add_Replace_Trim(_buffer, TValue.v, _p, update); + + double _wma = 0; + for (int i = 0; i < _buffer.Count; i++) { _wma += _buffer[i] * this._weights[i]; } + _wma /= (this._buffer.Count * (this._buffer.Count + 1)) * 0.5; + + base.Add((TValue.t, _wma), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Trends/ZLEMA_Series.cs b/Calculations/Trends/ZLEMA_Series.cs similarity index 96% rename from Source/Trends/ZLEMA_Series.cs rename to Calculations/Trends/ZLEMA_Series.cs index 2f4276d3..a72da3ce 100644 --- a/Source/Trends/ZLEMA_Series.cs +++ b/Calculations/Trends/ZLEMA_Series.cs @@ -1,62 +1,62 @@ -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 : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k, _k1m; - private double _lastema, _lastema_o; - private int _llag; - private readonly bool _useSMA; - - public ZLEMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) - { - this._k = 2.0 / (this._p + 1); - this._k1m = 1.0 - this._k; - this._lastema = this._lastema_o = double.NaN; - _llag = (int)((_p-1) * 0.5); - _useSMA = useSMA; - if (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - int _lag = Math.Max(this.Count-_llag, 0); - if (update) { - _lastema = _lastema_o; _lag--; - } else { - _lastema_o = _lastema; - } - double _zl = TValue.v + (TValue.v - _data[_lag].v); - double _ema = 0; - - if (this.Count < this._p && _useSMA) { - Add_Replace_Trim(_buffer, _zl, _p, update); - _ema = _buffer.Average(); - } else { - _ema = (_zl * _k) + (_lastema * _k1m); - } - _lastema = _ema; - - base.Add((TValue.t, _ema), update, _NaN); - } +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 : Single_TSeries_Indicator +{ + private readonly System.Collections.Generic.List _buffer = new(); + private readonly double _k, _k1m; + private double _lastema, _lastema_o; + private int _llag; + private readonly bool _useSMA; + + public ZLEMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) + { + this._k = 2.0 / (this._p + 1); + this._k1m = 1.0 - this._k; + this._lastema = this._lastema_o = double.NaN; + _llag = (int)((_p-1) * 0.5); + _useSMA = useSMA; + if (_data.Count > 0) { base.Add(_data); } + } + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + int _lag = Math.Max(this.Count-_llag, 0); + if (update) { + _lastema = _lastema_o; _lag--; + } else { + _lastema_o = _lastema; + } + double _zl = TValue.v + (TValue.v - _data[_lag].v); + double _ema = 0; + + if (this.Count < this._p && _useSMA) { + Add_Replace_Trim(_buffer, _zl, _p, update); + _ema = _buffer.Average(); + } else { + _ema = (_zl * _k) + (_lastema * _k1m); + } + _lastema = _ema; + + base.Add((TValue.t, _ema), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Volatility/ADL_Series.cs b/Calculations/Volatility/ADL_Series.cs similarity index 96% rename from Source/Volatility/ADL_Series.cs rename to Calculations/Volatility/ADL_Series.cs index 7e0a962f..0eb43ec2 100644 --- a/Source/Volatility/ADL_Series.cs +++ b/Calculations/Volatility/ADL_Series.cs @@ -1,40 +1,40 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TBars_Indicator -{ - private double _lastadl, _lastlastadl; - - public ADL_Series(TBars source, bool useNaN = false) : base(source, 0, useNaN) - { - _lastadl = _lastlastadl = 0; - if (_bars.Count > 0) { base.Add(_bars); } - } - - public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) - { - if (update) { this._lastadl = this._lastlastadl; } - - 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); } - - this._lastlastadl = this._lastadl; - this._lastadl = _adl; - - base.Add((TBar.t, _adl), update, _NaN); - } +namespace QuanTAlib; +using System; + +/* +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 : Single_TBars_Indicator +{ + private double _lastadl, _lastlastadl; + + public ADL_Series(TBars source, bool useNaN = false) : base(source, 0, useNaN) + { + _lastadl = _lastlastadl = 0; + if (_bars.Count > 0) { base.Add(_bars); } + } + + public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) + { + if (update) { this._lastadl = this._lastlastadl; } + + 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); } + + this._lastlastadl = this._lastadl; + this._lastadl = _adl; + + base.Add((TBar.t, _adl), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Volatility/ADOSC_Series.cs b/Calculations/Volatility/ADOSC_Series.cs similarity index 96% rename from Source/Volatility/ADOSC_Series.cs rename to Calculations/Volatility/ADOSC_Series.cs index e5b279bb..9fca7e30 100644 --- a/Source/Volatility/ADOSC_Series.cs +++ b/Calculations/Volatility/ADOSC_Series.cs @@ -1,87 +1,87 @@ -namespace QuanTAlib; -using System; - -/* -ADO: 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 = (3-day EMA of ADL) - (10-day EMA of ADL) - -Sources: - https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_oscillator - - */ - - -public class ADOSC_Series : Single_TBars_Indicator -{ - private readonly double _k1, _k2; - private double _lastema1, _lastlastema1, _lastema2, _lastlastema2; - private double _lastadl, _lastlastadl; - - public ADOSC_Series(TBars source, int shortPeriod = 3, int longPeriod =10, bool useNaN = false) : base(source, period: 0, useNaN) - { - _k1 = 2.0 / (shortPeriod + 1); - _k2 = 2.0 / (longPeriod + 1); - _lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0; - if (_bars.Count > 0) { base.Add(_bars); } - } - - public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) - { - 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; - base.Add((TBar.t, _adosc), update, _NaN); - } - -} -/* -public class ADOSC_Series : Single_TBars_Indicator -{ - private readonly ADL_Series _TSadl; - - private readonly EMA_Series _TSslow; - private readonly EMA_Series _TSfast; - private readonly SUB_Series _TSado; - - public ADOSC_Series(TBars source, bool useNaN = false) : base(source, period: 0, useNaN) - { - _TSadl = new(source: source, useNaN: false); - _TSslow = new(source: _TSadl, period: 10, useNaN: false); - _TSfast = new(source: _TSadl, period: 3, useNaN: false); - _TSado = new(_TSfast, _TSslow); - - if (source.Count > 0) - { base.Add(_TSado); } - Console.WriteLine(base.Count); - } - - public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) - { - if (update) - { _TSadl.Add(TBar, true); } - - double _ado = this._TSado[(this.Count < this._TSado.Count) ? this.Count : this._TSado.Count - 1].v; - var result = (TBar.t, _ado); - base.Add(result, update); - } -} +namespace QuanTAlib; +using System; + +/* +ADO: 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 = (3-day EMA of ADL) - (10-day EMA of ADL) + +Sources: + https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_oscillator + + */ + + +public class ADOSC_Series : Single_TBars_Indicator +{ + private readonly double _k1, _k2; + private double _lastema1, _lastlastema1, _lastema2, _lastlastema2; + private double _lastadl, _lastlastadl; + + public ADOSC_Series(TBars source, int shortPeriod = 3, int longPeriod =10, bool useNaN = false) : base(source, period: 0, useNaN) + { + _k1 = 2.0 / (shortPeriod + 1); + _k2 = 2.0 / (longPeriod + 1); + _lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0; + if (_bars.Count > 0) { base.Add(_bars); } + } + + public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) + { + 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; + base.Add((TBar.t, _adosc), update, _NaN); + } + +} +/* +public class ADOSC_Series : Single_TBars_Indicator +{ + private readonly ADL_Series _TSadl; + + private readonly EMA_Series _TSslow; + private readonly EMA_Series _TSfast; + private readonly SUB_Series _TSado; + + public ADOSC_Series(TBars source, bool useNaN = false) : base(source, period: 0, useNaN) + { + _TSadl = new(source: source, useNaN: false); + _TSslow = new(source: _TSadl, period: 10, useNaN: false); + _TSfast = new(source: _TSadl, period: 3, useNaN: false); + _TSado = new(_TSfast, _TSslow); + + if (source.Count > 0) + { base.Add(_TSado); } + Console.WriteLine(base.Count); + } + + public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) + { + if (update) + { _TSadl.Add(TBar, true); } + + double _ado = this._TSado[(this.Count < this._TSado.Count) ? this.Count : this._TSado.Count - 1].v; + var result = (TBar.t, _ado); + base.Add(result, update); + } +} */ \ No newline at end of file diff --git a/Source/Volatility/ATRP_Series.cs b/Calculations/Volatility/ATRP_Series.cs similarity index 97% rename from Source/Volatility/ATRP_Series.cs rename to Calculations/Volatility/ATRP_Series.cs index 72fdcd48..086db3db 100644 --- a/Source/Volatility/ATRP_Series.cs +++ b/Calculations/Volatility/ATRP_Series.cs @@ -1,48 +1,48 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TBars_Indicator { - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k; - private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum; - private readonly int _period; - - public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) { - _period = period; - _k = 1.0 / (double)(_p); - _lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0; - if (this._bars.Count > 0) { base.Add(this._bars); } - } - - public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) { - if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; } - else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; } - - if (this.Count == 0) { _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 < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); } - else { _atr = _k * (d.v - _lastatr) + _lastatr; } - _lastatr = _atr; - - double _atrp = 100 * (_atr / TBar.c); - var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atrp); - base.Add(ret, update); - } -} +namespace QuanTAlib; +using System; + +/* +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 : Single_TBars_Indicator { + private readonly System.Collections.Generic.List _buffer = new(); + private readonly double _k; + private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum; + private readonly int _period; + + public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) { + _period = period; + _k = 1.0 / (double)(_p); + _lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0; + if (this._bars.Count > 0) { base.Add(this._bars); } + } + + public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) { + if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; } + else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; } + + if (this.Count == 0) { _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 < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); } + else { _atr = _k * (d.v - _lastatr) + _lastatr; } + _lastatr = _atr; + + double _atrp = 100 * (_atr / TBar.c); + var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atrp); + base.Add(ret, update); + } +} diff --git a/Source/Volatility/ATR_Series.cs b/Calculations/Volatility/ATR_Series.cs similarity index 97% rename from Source/Volatility/ATR_Series.cs rename to Calculations/Volatility/ATR_Series.cs index cd99885f..bc641e92 100644 --- a/Source/Volatility/ATR_Series.cs +++ b/Calculations/Volatility/ATR_Series.cs @@ -1,49 +1,49 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TBars_Indicator { - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k; - private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum; - private readonly int _period; - - public ATR_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) { - _period = period; - _k = 1.0 / (double)(_p); - _lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0; - if (this._bars.Count > 0) { base.Add(this._bars); } - } - - public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) { - if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; } - else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; } - - if (this.Count == 0) { _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 < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); } - else { _atr = _k * (d.v - _lastatr) + _lastatr; } - _lastatr = _atr; - - var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atr); - base.Add(ret, update); - } +namespace QuanTAlib; +using System; + +/* +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 : Single_TBars_Indicator { + private readonly System.Collections.Generic.List _buffer = new(); + private readonly double _k; + private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum; + private readonly int _period; + + public ATR_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) { + _period = period; + _k = 1.0 / (double)(_p); + _lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0; + if (this._bars.Count > 0) { base.Add(this._bars); } + } + + public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) { + if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; } + else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; } + + if (this.Count == 0) { _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 < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); } + else { _atr = _k * (d.v - _lastatr) + _lastatr; } + _lastatr = _atr; + + var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atr); + base.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/Volatility/BBANDS_Series.cs b/Calculations/Volatility/BBANDS_Series.cs similarity index 97% rename from Source/Volatility/BBANDS_Series.cs rename to Calculations/Volatility/BBANDS_Series.cs index 499fba44..169f8f35 100644 --- a/Source/Volatility/BBANDS_Series.cs +++ b/Calculations/Volatility/BBANDS_Series.cs @@ -1,73 +1,73 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TSeries_Indicator -{ - public SMA_Series Mid { get; } - public ADD_Series Upper { get; } - public SUB_Series Lower { get; } - public DIV_Series PercentB { get; } - public DIV_Series Bandwidth { get; } - public DIV_Series Zscore { get; } - - private readonly SDEV_Series _sdev; - private readonly MUL_Series _mulsdev; - private readonly SUB_Series _pbdnd; - private readonly SUB_Series _pbdvr; - private readonly SUB_Series _zdnd; - - public BBANDS_Series(TSeries source, int period = 26, double multiplier = 2.0, bool useNaN = false) - : base(source, period: 0, useNaN) - { - this.Mid = new(source: source, period: period, useNaN: useNaN); - - _sdev = new(source, period, useNaN: useNaN); - _mulsdev = new(_sdev, multiplier); - this.Upper = new(Mid, _mulsdev); - this.Lower = new(Mid, _mulsdev); - - _pbdnd = new(source, Lower); - _pbdvr = new(Upper, Lower); - - this.PercentB = new(_pbdnd, _pbdvr); - this.Bandwidth = new(_pbdvr, Mid); - - _zdnd = new(source, Mid); - this.Zscore = new(_zdnd, _sdev); - - if (source.Count > 0) - { base.Add(this.Bandwidth); } - } - public override void Add((System.DateTime t, double v) TValue, bool update) - { - double _bbandwidth; - if (update) - { _sdev.Add(TValue, true); } - _bbandwidth = this.Bandwidth[(this.Count < this.Bandwidth.Count) ? this.Count : this.Bandwidth.Count - 1].v; - var result = (TValue.t, _bbandwidth); - base.Add(result, update); - } +namespace QuanTAlib; +using System; + +/* +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 : Single_TSeries_Indicator +{ + public SMA_Series Mid { get; } + public ADD_Series Upper { get; } + public SUB_Series Lower { get; } + public DIV_Series PercentB { get; } + public DIV_Series Bandwidth { get; } + public DIV_Series Zscore { get; } + + private readonly SDEV_Series _sdev; + private readonly MUL_Series _mulsdev; + private readonly SUB_Series _pbdnd; + private readonly SUB_Series _pbdvr; + private readonly SUB_Series _zdnd; + + public BBANDS_Series(TSeries source, int period = 26, double multiplier = 2.0, bool useNaN = false) + : base(source, period: 0, useNaN) + { + this.Mid = new(source: source, period: period, useNaN: useNaN); + + _sdev = new(source, period, useNaN: useNaN); + _mulsdev = new(_sdev, multiplier); + this.Upper = new(Mid, _mulsdev); + this.Lower = new(Mid, _mulsdev); + + _pbdnd = new(source, Lower); + _pbdvr = new(Upper, Lower); + + this.PercentB = new(_pbdnd, _pbdvr); + this.Bandwidth = new(_pbdvr, Mid); + + _zdnd = new(source, Mid); + this.Zscore = new(_zdnd, _sdev); + + if (source.Count > 0) + { base.Add(this.Bandwidth); } + } + public override void Add((System.DateTime t, double v) TValue, bool update) + { + double _bbandwidth; + if (update) + { _sdev.Add(TValue, true); } + _bbandwidth = this.Bandwidth[(this.Count < this.Bandwidth.Count) ? this.Count : this.Bandwidth.Count - 1].v; + var result = (TValue.t, _bbandwidth); + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Volatility/CMO_Series.cs b/Calculations/Volatility/CMO_Series.cs similarity index 97% rename from Source/Volatility/CMO_Series.cs rename to Calculations/Volatility/CMO_Series.cs index 9a47b469..9295dfa5 100644 --- a/Source/Volatility/CMO_Series.cs +++ b/Calculations/Volatility/CMO_Series.cs @@ -1,47 +1,47 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TSeries_Indicator { - private readonly System.Collections.Generic.List _buff_up = new(); - private readonly System.Collections.Generic.List _buff_dn = new(); - private double _plast_value, _last_value; - - public CMO_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) { - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - if (this.Count == 0) { _plast_value = _last_value = TValue.v; } - if (update) _last_value = _plast_value; else _plast_value = _last_value; - - Add_Replace_Trim(_buff_up, (TValue.v > _last_value) ? TValue.v-_last_value : 0, _p, update); - Add_Replace_Trim(_buff_dn, (TValue.v < _last_value) ? _last_value-TValue.v : 0, _p, 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; - base.Add((TValue.t, _cmo), update, _NaN); - } +namespace QuanTAlib; +using System; + +/* +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 : Single_TSeries_Indicator { + private readonly System.Collections.Generic.List _buff_up = new(); + private readonly System.Collections.Generic.List _buff_dn = new(); + private double _plast_value, _last_value; + + public CMO_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) { + if (this._data.Count > 0) { base.Add(this._data); } + } + + public override void Add((DateTime t, double v) TValue, bool update) { + if (this.Count == 0) { _plast_value = _last_value = TValue.v; } + if (update) _last_value = _plast_value; else _plast_value = _last_value; + + Add_Replace_Trim(_buff_up, (TValue.v > _last_value) ? TValue.v-_last_value : 0, _p, update); + Add_Replace_Trim(_buff_dn, (TValue.v < _last_value) ? _last_value-TValue.v : 0, _p, 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; + base.Add((TValue.t, _cmo), update, _NaN); + } } \ No newline at end of file diff --git a/Source/Volatility/RSI_Series.cs b/Calculations/Volatility/RSI_Series.cs similarity index 97% rename from Source/Volatility/RSI_Series.cs rename to Calculations/Volatility/RSI_Series.cs index e4f6a350..0805df35 100644 --- a/Source/Volatility/RSI_Series.cs +++ b/Calculations/Volatility/RSI_Series.cs @@ -1,78 +1,78 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _gain = new(); - private readonly System.Collections.Generic.List _loss = new(); - private double _avgGain, _avgLoss, _lastValue; - private double _avgGain_o, _avgLoss_o, _lastValue_o; - private int i; - - public RSI_Series(TSeries source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) { - i = 0; - if (source.Count > 0) { base.Add(source); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) { - 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; - Add_Replace_Trim(_gain, _gainval, _p, update); - double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0; - Add_Replace_Trim(_loss, _lossval, _p, update); - _lastValue = TValue.v; - - // calculate RSI - if (i > _p) - { - _avgGain = ((_avgGain * (_p - 1)) + _gain[_gain.Count - 1]) / _p; - _avgLoss = ((_avgLoss * (_p - 1)) + _loss[_loss.Count - 1]) / _p; - 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 result = (TValue.t, (this.Count < this._p && this._NaN) ? double.NaN : _rsi); - base.Add(result, update); - } +namespace QuanTAlib; +using System; + +/* +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 : Single_TSeries_Indicator +{ + private readonly System.Collections.Generic.List _gain = new(); + private readonly System.Collections.Generic.List _loss = new(); + private double _avgGain, _avgLoss, _lastValue; + private double _avgGain_o, _avgLoss_o, _lastValue_o; + private int i; + + public RSI_Series(TSeries source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) { + i = 0; + if (source.Count > 0) { base.Add(source); } + } + + public override void Add((System.DateTime t, double v) TValue, bool update) { + 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; + Add_Replace_Trim(_gain, _gainval, _p, update); + double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0; + Add_Replace_Trim(_loss, _lossval, _p, update); + _lastValue = TValue.v; + + // calculate RSI + if (i > _p) + { + _avgGain = ((_avgGain * (_p - 1)) + _gain[_gain.Count - 1]) / _p; + _avgLoss = ((_avgLoss * (_p - 1)) + _loss[_loss.Count - 1]) / _p; + 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 result = (TValue.t, (this.Count < this._p && this._NaN) ? double.NaN : _rsi); + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Volume/OBV_Series.cs b/Calculations/Volume/OBV_Series.cs similarity index 97% rename from Source/Volume/OBV_Series.cs rename to Calculations/Volume/OBV_Series.cs index c77570a8..73d4e327 100644 --- a/Source/Volume/OBV_Series.cs +++ b/Calculations/Volume/OBV_Series.cs @@ -1,59 +1,59 @@ -namespace QuanTAlib; -using System; - -/* -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 : Single_TBars_Indicator -{ - private double _lastobv, _lastlastobv; - private double _lastclose, _lastlastclose; - public OBV_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) - { - this._lastobv = this._lastlastobv = 0; - this._lastclose = this._lastlastclose = 0; - if (_bars.Count > 0) { base.Add(_bars); } - } - - public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) - { - 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 result = (TBar.t, (this.Count < this._p && this._NaN) ? double.NaN : _obv); - base.Add(result, update); - } -} +namespace QuanTAlib; +using System; + +/* +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 : Single_TBars_Indicator +{ + private double _lastobv, _lastlastobv; + private double _lastclose, _lastlastclose; + public OBV_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) + { + this._lastobv = this._lastlastobv = 0; + this._lastclose = this._lastlastclose = 0; + if (_bars.Count > 0) { base.Add(_bars); } + } + + public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) + { + 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 result = (TBar.t, (this.Count < this._p && this._NaN) ? double.NaN : _obv); + base.Add(result, update); + } +} diff --git a/Indicators/Basics/QuanTAlib_Indicator.cs b/Indicators/Basics/QuanTAlib_Indicator.cs new file mode 100644 index 00000000..ea2644a6 --- /dev/null +++ b/Indicators/Basics/QuanTAlib_Indicator.cs @@ -0,0 +1,40 @@ +using TradingPlatform.BusinessLayer; +using System.Drawing; +using QuanTAlib; +using System; +using TradingPlatform.BusinessLayer.Chart; + +namespace QuanTAlib; + +public class QuanTAlib_Indicator : Indicator { + protected TBars bars; + protected IChartWindow mainWindow; + protected Graphics graphics; + protected int firstOnScreenBarIndex, lastOnScreenBarIndex; + + protected override void OnInit() { + base.OnInit(); + bars = new(); + } + + 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)); + } + 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)); + } +} \ No newline at end of file diff --git a/Indicators/Charts/ATR_chart.cs b/Indicators/Charts/ATR_chart.cs new file mode 100644 index 00000000..c8fd76f9 --- /dev/null +++ b/Indicators/Charts/ATR_chart.cs @@ -0,0 +1,32 @@ +using System.Drawing; +using TradingPlatform.BusinessLayer; +namespace QuanTAlib; + +public class ATR_chart : QuanTAlib_Indicator { + #region Parameters + + [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] + private readonly int Period = 10; + + #endregion Parameters + + private ATR_Series indicator; + + public ATR_chart() + { + this.SeparateWindow = true; + this.Name = "ATR - Average True Range"; + this.Description = "Average True Range description"; + this.AddLineSeries("ATR", Color.RoyalBlue, 3, LineStyle.Solid); + } + + protected override void OnInit() { base.OnInit(); + indicator = new(source: bars, period: Period, useNaN: false); + } + + protected override void OnUpdate(UpdateArgs args) { + base.OnUpdate(args); + this.SetValue(indicator[^1].v, lineIndex: 0); + } + +} diff --git a/Quantower/Indicators/BIAS_chart.cs b/Indicators/Charts/BIAS_chart.cs similarity index 100% rename from Quantower/Indicators/BIAS_chart.cs rename to Indicators/Charts/BIAS_chart.cs diff --git a/Quantower/Indicators/CCI_chart.cs b/Indicators/Charts/CCI_chart.cs similarity index 96% rename from Quantower/Indicators/CCI_chart.cs rename to Indicators/Charts/CCI_chart.cs index 38d5ec7e..748828f5 100644 --- a/Quantower/Indicators/CCI_chart.cs +++ b/Indicators/Charts/CCI_chart.cs @@ -1,43 +1,43 @@ -using System.Diagnostics; -using System.Drawing; -using TradingPlatform.BusinessLayer; -namespace QuanTAlib; - -public class CCI_chart : Indicator -{ - #region Parameters - - [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] - private readonly int Period = 10; - - #endregion Parameters - - private TBars bars; - - /////// - private CCI_Series indicator; - /////// - - public CCI_chart() - { - this.SeparateWindow = true; - this.Name = "CCI - Commodity Channel Index"; - this.Description = "CCI description"; - this.AddLineSeries("CCI", Color.RoyalBlue, 3, LineStyle.Solid); - } - - protected override void OnInit() - { - this.bars = new(); - this.indicator = new(source: bars, period: this.Period, useNaN: false); - } - - 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); - double result = this.indicator[this.indicator.Count - 1].v; - this.SetValue(result); - } -} +using System.Diagnostics; +using System.Drawing; +using TradingPlatform.BusinessLayer; +namespace QuanTAlib; + +public class CCI_chart : Indicator +{ + #region Parameters + + [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] + private readonly int Period = 10; + + #endregion Parameters + + private TBars bars; + + /////// + private CCI_Series indicator; + /////// + + public CCI_chart() + { + this.SeparateWindow = true; + this.Name = "CCI - Commodity Channel Index"; + this.Description = "CCI description"; + this.AddLineSeries("CCI", Color.RoyalBlue, 3, LineStyle.Solid); + } + + protected override void OnInit() + { + this.bars = new(); + this.indicator = new(source: bars, period: this.Period, useNaN: false); + } + + 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); + double result = this.indicator[this.indicator.Count - 1].v; + this.SetValue(result); + } +} diff --git a/Quantower/Indicators/DEMA_chart.cs b/Indicators/Charts/DEMA_chart.cs similarity index 100% rename from Quantower/Indicators/DEMA_chart.cs rename to Indicators/Charts/DEMA_chart.cs diff --git a/Indicators/Charts/DJMA_chart.cs b/Indicators/Charts/DJMA_chart.cs new file mode 100644 index 00000000..b58824f3 --- /dev/null +++ b/Indicators/Charts/DJMA_chart.cs @@ -0,0 +1,78 @@ +using System; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using TradingPlatform.BusinessLayer; +namespace QuanTAlib; + +public class DJMA_chart : Indicator { + #region Parameters + + [InputParameter("Fast 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 FDataSource = 3; + + [InputParameter("Fast Smoothing period", 1, 1, 999, 1, 1)] + private int FPeriod = 12; + + [InputParameter("Fast Volatility short", 2, 3, 50, 1, 1)] + private int FVshort = 10; + + [InputParameter("Fast Volatility long", 3, 20, 500, 5, 1)] + private int FVlong = 65; + + [InputParameter("Fast Phase", 4, -100, 100, 1, 2)] + private double FJphase = 100.0; + + [InputParameter("Slow 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 SDataSource = 3; + + [InputParameter("Slow Smoothing period", 6, 1, 999, 1, 1)] + private int SPeriod = 26; + + [InputParameter("Slow Volatility short", 7, 3, 50, 1, 1)] + private int SVshort = 10; + + [InputParameter("Slow Volatility long", 8, 20, 500, 5, 1)] + private int SVlong = 65; + + [InputParameter("Slow Phase", 9, -100, 100, 1, 2)] + private double SJphase = -100.0; + + + #endregion Parameters + + private TBars bars; + + /////// + private JMA_Series fJma, sJma; + /////// + + public DJMA_chart() { + this.SeparateWindow = false; + this.Name = "DJMA - Two JMAs"; + this.Description = "Jurik Moving Average description"; + this.AddLineSeries("JMA-fast", Color.Blue, 2, LineStyle.Solid); + this.AddLineSeries("JMA-slow", Color.Green, 2, LineStyle.Solid); + } + + + protected override void OnInit() { + this.bars = new(); + this.fJma = new(source: bars.Select(this.FDataSource), period: this.FPeriod, phase: FJphase, vshort: FVshort, vlong: FVlong, useNaN: false); + this.sJma = new(source: bars.Select(this.SDataSource), period: this.SPeriod, phase: SJphase, vshort: SVshort, vlong: SVlong, useNaN: false); + } + + 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.fJma[^1].v, lineIndex: 0); + this.SetValue(this.sJma[^1].v, lineIndex: 1); + } +} \ No newline at end of file diff --git a/Quantower/Indicators/EMA_chart.cs b/Indicators/Charts/EMA_chart.cs similarity index 100% rename from Quantower/Indicators/EMA_chart.cs rename to Indicators/Charts/EMA_chart.cs diff --git a/Quantower/Indicators/ENTP_chart.cs b/Indicators/Charts/ENTP_chart.cs similarity index 100% rename from Quantower/Indicators/ENTP_chart.cs rename to Indicators/Charts/ENTP_chart.cs diff --git a/Quantower/Indicators/HEMA_chart.cs b/Indicators/Charts/HEMA_chart.cs similarity index 100% rename from Quantower/Indicators/HEMA_chart.cs rename to Indicators/Charts/HEMA_chart.cs diff --git a/Quantower/Indicators/HMA_chart.cs b/Indicators/Charts/HMA_chart.cs similarity index 96% rename from Quantower/Indicators/HMA_chart.cs rename to Indicators/Charts/HMA_chart.cs index 93667ef6..72b1e2fa 100644 --- a/Quantower/Indicators/HMA_chart.cs +++ b/Indicators/Charts/HMA_chart.cs @@ -1,52 +1,52 @@ -using System.Diagnostics; -using System.Drawing; -using TradingPlatform.BusinessLayer; -namespace QuanTAlib; - -public class HMA_chart : Indicator -{ - #region Parameters - - [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] - private int Period = 10; - - [InputParameter("Data source", 1, 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; - - #endregion Parameters - - private TBars bars; - - /////// - private HMA_Series indicator; - /////// - - public HMA_chart() - { - this.SeparateWindow = false; - this.Name = "HMA - Hull Moving Average"; - this.Description = "Hull Moving Average description"; - this.AddLineSeries("HMA", Color.RoyalBlue, 3, LineStyle.Solid); - } - - protected override void OnInit() - { - this.bars = new(); - this.indicator = new(source: bars.Select(this.DataSource), - period: this.Period, useNaN: false); - Debug.WriteLine("Send to debug output."); -} - - 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); - double result = this.indicator[this.indicator.Count - 1].v; - this.SetValue(result); - } -} +using System.Diagnostics; +using System.Drawing; +using TradingPlatform.BusinessLayer; +namespace QuanTAlib; + +public class HMA_chart : Indicator +{ + #region Parameters + + [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] + private int Period = 10; + + [InputParameter("Data source", 1, 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; + + #endregion Parameters + + private TBars bars; + + /////// + private HMA_Series indicator; + /////// + + public HMA_chart() + { + this.SeparateWindow = false; + this.Name = "HMA - Hull Moving Average"; + this.Description = "Hull Moving Average description"; + this.AddLineSeries("HMA", Color.RoyalBlue, 3, LineStyle.Solid); + } + + protected override void OnInit() + { + this.bars = new(); + this.indicator = new(source: bars.Select(this.DataSource), + period: this.Period, useNaN: false); + Debug.WriteLine("Send to debug output."); +} + + 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); + double result = this.indicator[this.indicator.Count - 1].v; + this.SetValue(result); + } +} diff --git a/Indicators/Charts/JMA_chart.cs b/Indicators/Charts/JMA_chart.cs new file mode 100644 index 00000000..340c2287 --- /dev/null +++ b/Indicators/Charts/JMA_chart.cs @@ -0,0 +1,53 @@ +using System; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using TradingPlatform.BusinessLayer; +namespace QuanTAlib; + +public class JMA_chart : QuanTAlib_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 = 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 + + /////// + private JMA_Series indicator; + /////// + + public JMA_chart() :base() { + Name = "JMA - Jurik Moving Avg"; + Description = "Jurik Moving Average description"; + AddLineSeries(lineName: "JMA", lineColor: Color.Yellow, lineWidth: 3,lineStyle: LineStyle.Solid); + SeparateWindow = false; + } + + + protected override void OnInit() { + base.OnInit(); + indicator = new(source: bars.Select(DataSource), period: Period, + phase: Jphase, vshort: Vshort, vlong: Vlong, + useNaN: false); + } + + protected override void OnUpdate(UpdateArgs args) { + base.OnUpdate(args); + this.SetValue(indicator[^1].v, lineIndex: 0); + } +} diff --git a/Quantower/Indicators/KAMA_chart.cs b/Indicators/Charts/KAMA_chart.cs similarity index 97% rename from Quantower/Indicators/KAMA_chart.cs rename to Indicators/Charts/KAMA_chart.cs index 88658444..8de883f7 100644 --- a/Quantower/Indicators/KAMA_chart.cs +++ b/Indicators/Charts/KAMA_chart.cs @@ -1,55 +1,55 @@ -using System.Diagnostics; -using System.Drawing; -using TradingPlatform.BusinessLayer; -namespace QuanTAlib; - -public class KAMA_chart : Indicator -{ - #region Parameters - - [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] - private int Period = 10; - [InputParameter("Fastest EMA", 1, 1, 999, 1, 1)] - private int Fast = 2; - [InputParameter("Slowest EMA", 2, 1, 999, 1, 1)] - private int Slow = 30; - - [InputParameter("Data source", 3, 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; - - #endregion Parameters - - private TBars bars; - - /////// - private KAMA_Series indicator; - /////// - - public KAMA_chart() - { - this.SeparateWindow = false; - this.Name = "KAMA - Kaufman's Adaptive Moving Average"; - this.Description = "Kaufman's Adaptive Moving Average description"; - this.AddLineSeries("KAMA", Color.RoyalBlue, 3, LineStyle.Solid); - } - - protected override void OnInit() - { - this.bars = new(); - this.indicator = new(source: bars.Select(this.DataSource), period: this.Period, fast: this.Fast, slow: this.Slow, useNaN: false); - } - - 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); - double result = this.indicator; - this.SetValue(result); - Debug.WriteLine($"{this.indicator[0].v}"); - } -} +using System.Diagnostics; +using System.Drawing; +using TradingPlatform.BusinessLayer; +namespace QuanTAlib; + +public class KAMA_chart : Indicator +{ + #region Parameters + + [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] + private int Period = 10; + [InputParameter("Fastest EMA", 1, 1, 999, 1, 1)] + private int Fast = 2; + [InputParameter("Slowest EMA", 2, 1, 999, 1, 1)] + private int Slow = 30; + + [InputParameter("Data source", 3, 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; + + #endregion Parameters + + private TBars bars; + + /////// + private KAMA_Series indicator; + /////// + + public KAMA_chart() + { + this.SeparateWindow = false; + this.Name = "KAMA - Kaufman's Adaptive Moving Average"; + this.Description = "Kaufman's Adaptive Moving Average description"; + this.AddLineSeries("KAMA", Color.RoyalBlue, 3, LineStyle.Solid); + } + + protected override void OnInit() + { + this.bars = new(); + this.indicator = new(source: bars.Select(this.DataSource), period: this.Period, fast: this.Fast, slow: this.Slow, useNaN: false); + } + + 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); + double result = this.indicator; + this.SetValue(result); + Debug.WriteLine($"{this.indicator[0].v}"); + } +} diff --git a/Quantower/Indicators/KURT_chart.cs b/Indicators/Charts/KURT_chart.cs similarity index 100% rename from Quantower/Indicators/KURT_chart.cs rename to Indicators/Charts/KURT_chart.cs diff --git a/Quantower/Indicators/MAD_chart.cs b/Indicators/Charts/MAD_chart.cs similarity index 100% rename from Quantower/Indicators/MAD_chart.cs rename to Indicators/Charts/MAD_chart.cs diff --git a/Quantower/Indicators/MAPE_chart.cs b/Indicators/Charts/MAPE_chart.cs similarity index 100% rename from Quantower/Indicators/MAPE_chart.cs rename to Indicators/Charts/MAPE_chart.cs diff --git a/Quantower/Indicators/MAX_chart.cs b/Indicators/Charts/MAX_chart.cs similarity index 100% rename from Quantower/Indicators/MAX_chart.cs rename to Indicators/Charts/MAX_chart.cs diff --git a/Quantower/Indicators/MED_chart.cs b/Indicators/Charts/MED_chart.cs similarity index 100% rename from Quantower/Indicators/MED_chart.cs rename to Indicators/Charts/MED_chart.cs diff --git a/Quantower/Indicators/MIN_chart.cs b/Indicators/Charts/MIN_chart.cs similarity index 100% rename from Quantower/Indicators/MIN_chart.cs rename to Indicators/Charts/MIN_chart.cs diff --git a/Quantower/Indicators/MSE_chart.cs b/Indicators/Charts/MSE_chart.cs similarity index 100% rename from Quantower/Indicators/MSE_chart.cs rename to Indicators/Charts/MSE_chart.cs diff --git a/Quantower/Indicators/RMA_chart.cs b/Indicators/Charts/RMA_chart.cs similarity index 100% rename from Quantower/Indicators/RMA_chart.cs rename to Indicators/Charts/RMA_chart.cs diff --git a/Indicators/Charts/RSI_chart.cs b/Indicators/Charts/RSI_chart.cs new file mode 100644 index 00000000..85a5c78d --- /dev/null +++ b/Indicators/Charts/RSI_chart.cs @@ -0,0 +1,56 @@ +using System; +using System.Drawing; +using TradingPlatform.BusinessLayer; +namespace QuanTAlib; + +public class RSI_chart : QuanTAlib_Indicator { + #region Parameters + + [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] + private int Period = 10; + + [InputParameter("Data source", 1, 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 = 8; + + [InputParameter("Overbought level", 2, 1, 100, 1, 1)] + private int Overbought = 70; + + [InputParameter("Oversold level", 2, 1, 100, 1, 1)] + private int Oversold = 30; + + #endregion Parameters + + /////// + private RSI_Series indicator; + /////// + + public RSI_chart() : base() { + this.Name = "RSI - Relative Strength Index"; + this.Description = "RSI description"; + this.AddLineSeries("RSI", Color.RoyalBlue, 3, LineStyle.Solid); + this.SeparateWindow = true; + } + + protected override void OnInit() { + base.OnInit(); + indicator = new(source: bars.Select(this.DataSource), period: this.Period, useNaN: true); + } + + protected override void OnUpdate(UpdateArgs args) { + base.OnUpdate(args); + SetValue(indicator[^1].v, lineIndex: 0); + if (indicator[^1].v >= Overbought) + LinesSeries[0].SetMarker(0, color: Color.Red); + if (indicator[^1].v <= Oversold) + LinesSeries[0].SetMarker(0, color: Color.Red); + } + public override void OnPaintChart(PaintChartEventArgs args) { + base.OnPaintChart(args); + for (int i = firstOnScreenBarIndex; i <= lastOnScreenBarIndex; i++) { + int xLeft = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - i - 1))); + int y = (int)Math.Round((mainWindow.CoordinatesConverter.GetChartY(Overbought))); + } + } +} diff --git a/Quantower/Indicators/SDEV_chart.cs b/Indicators/Charts/SDEV_chart.cs similarity index 96% rename from Quantower/Indicators/SDEV_chart.cs rename to Indicators/Charts/SDEV_chart.cs index 2e6a423d..84778581 100644 --- a/Quantower/Indicators/SDEV_chart.cs +++ b/Indicators/Charts/SDEV_chart.cs @@ -1,51 +1,51 @@ -using System.Drawing; -using TradingPlatform.BusinessLayer; -namespace QuanTAlib; - -public class SDEV_chart : Indicator -{ - #region Parameters - - [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] - private int Period = 10; - - [InputParameter("Data source", 1, 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 = 8; - - #endregion Parameters - - private TBars bars; - - ///////dotnet - private SDEV_Series indicator; - /////// - - public SDEV_chart() - { - this.SeparateWindow = true; - this.Name = "SDEV - Standard Deviation"; - this.Description = "SDEV description"; - this.AddLineSeries("SDEV", Color.RoyalBlue, 3, LineStyle.Solid); - } - - protected override void OnInit() - { - this.bars = new(); - this.indicator = new(source: bars.Select(this.DataSource), - period: this.Period, useNaN: true); - } - 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); - double result = this.indicator[this.indicator.Count - 1].v; - - this.SetValue(result, 0); - } -} +using System.Drawing; +using TradingPlatform.BusinessLayer; +namespace QuanTAlib; + +public class SDEV_chart : Indicator +{ + #region Parameters + + [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] + private int Period = 10; + + [InputParameter("Data source", 1, 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 = 8; + + #endregion Parameters + + private TBars bars; + + ///////dotnet + private SDEV_Series indicator; + /////// + + public SDEV_chart() + { + this.SeparateWindow = true; + this.Name = "SDEV - Standard Deviation"; + this.Description = "SDEV description"; + this.AddLineSeries("SDEV", Color.RoyalBlue, 3, LineStyle.Solid); + } + + protected override void OnInit() + { + this.bars = new(); + this.indicator = new(source: bars.Select(this.DataSource), + period: this.Period, useNaN: true); + } + 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); + double result = this.indicator[this.indicator.Count - 1].v; + + this.SetValue(result, 0); + } +} diff --git a/Quantower/Indicators/SMAPE_chart.cs b/Indicators/Charts/SMAPE_chart.cs similarity index 100% rename from Quantower/Indicators/SMAPE_chart.cs rename to Indicators/Charts/SMAPE_chart.cs diff --git a/Quantower/Indicators/SMA_chart.cs b/Indicators/Charts/SMA_chart.cs similarity index 100% rename from Quantower/Indicators/SMA_chart.cs rename to Indicators/Charts/SMA_chart.cs diff --git a/Quantower/Indicators/SMMA_chart.cs b/Indicators/Charts/SMMA_chart.cs similarity index 100% rename from Quantower/Indicators/SMMA_chart.cs rename to Indicators/Charts/SMMA_chart.cs diff --git a/Quantower/Indicators/TEMA_chart.cs b/Indicators/Charts/TEMA_chart.cs similarity index 100% rename from Quantower/Indicators/TEMA_chart.cs rename to Indicators/Charts/TEMA_chart.cs diff --git a/Quantower/Indicators/VAR_chart.cs b/Indicators/Charts/VAR_chart.cs similarity index 96% rename from Quantower/Indicators/VAR_chart.cs rename to Indicators/Charts/VAR_chart.cs index d16725e8..89573ee7 100644 --- a/Quantower/Indicators/VAR_chart.cs +++ b/Indicators/Charts/VAR_chart.cs @@ -1,52 +1,52 @@ -using System.Drawing; -using TradingPlatform.BusinessLayer; -namespace QuanTAlib; - -public class VAR_chart : Indicator -{ - #region Parameters - - [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] - private int Period = 10; - - [InputParameter("Data source", 1, 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 = 8; - - #endregion Parameters - - private TBars bars; - - ///////dotnet - private VAR_Series indicator; - /////// - - public VAR_chart() - { - this.SeparateWindow = true; - this.Name = "VAR - Variance"; - this.Description = "VAR description"; - this.AddLineSeries("VAR", Color.RoyalBlue, 3, LineStyle.Solid); - } - - protected override void OnInit() - { - this.bars = new(); - this.indicator = new(source: bars.Select(this.DataSource), - period: this.Period, useNaN: true); - } - - 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); - double result = this.indicator[this.indicator.Count - 1].v; - - this.SetValue(result, 0); - } -} +using System.Drawing; +using TradingPlatform.BusinessLayer; +namespace QuanTAlib; + +public class VAR_chart : Indicator +{ + #region Parameters + + [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] + private int Period = 10; + + [InputParameter("Data source", 1, 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 = 8; + + #endregion Parameters + + private TBars bars; + + ///////dotnet + private VAR_Series indicator; + /////// + + public VAR_chart() + { + this.SeparateWindow = true; + this.Name = "VAR - Variance"; + this.Description = "VAR description"; + this.AddLineSeries("VAR", Color.RoyalBlue, 3, LineStyle.Solid); + } + + protected override void OnInit() + { + this.bars = new(); + this.indicator = new(source: bars.Select(this.DataSource), + period: this.Period, useNaN: true); + } + + 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); + double result = this.indicator[this.indicator.Count - 1].v; + + this.SetValue(result, 0); + } +} diff --git a/Quantower/Indicators/WMAPE_chart.cs b/Indicators/Charts/WMAPE_chart.cs similarity index 96% rename from Quantower/Indicators/WMAPE_chart.cs rename to Indicators/Charts/WMAPE_chart.cs index e607561a..bd89c693 100644 --- a/Quantower/Indicators/WMAPE_chart.cs +++ b/Indicators/Charts/WMAPE_chart.cs @@ -1,55 +1,55 @@ -namespace QuanTAlib; -using System.Drawing; -using TradingPlatform.BusinessLayer; - -public class WMAPE_chart : Indicator -{ - #region Parameters - - [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] - private readonly int Period = 10; - - [InputParameter("Data source", 1, 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 readonly int DataSource = 8; - - #endregion Parameters - - private TBars bars; - - ///////dotnet - private QuanTAlib.WMAPE_Series indicator; - /////// - - public WMAPE_chart() - { - this.SeparateWindow = true; - this.Name = "WMAPE - Weighted Mean Absolute Percentage Error"; - this.Description = "WMAPE description"; - this.AddLineSeries("WMAPE", Color.RoyalBlue, 3, LineStyle.Solid); - } - - protected override void OnInit() - { - this.bars = new(); - this.indicator = new(source: this.bars.Select(this.DataSource), period: this.Period, useNaN: true); - } - 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); - double result = this.indicator[this.indicator.Count - 1].v; - - this.SetValue(result, 0); - } -} +namespace QuanTAlib; +using System.Drawing; +using TradingPlatform.BusinessLayer; + +public class WMAPE_chart : Indicator +{ + #region Parameters + + [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] + private readonly int Period = 10; + + [InputParameter("Data source", 1, 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 readonly int DataSource = 8; + + #endregion Parameters + + private TBars bars; + + ///////dotnet + private QuanTAlib.WMAPE_Series indicator; + /////// + + public WMAPE_chart() + { + this.SeparateWindow = true; + this.Name = "WMAPE - Weighted Mean Absolute Percentage Error"; + this.Description = "WMAPE description"; + this.AddLineSeries("WMAPE", Color.RoyalBlue, 3, LineStyle.Solid); + } + + protected override void OnInit() + { + this.bars = new(); + this.indicator = new(source: this.bars.Select(this.DataSource), period: this.Period, useNaN: true); + } + 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); + double result = this.indicator[this.indicator.Count - 1].v; + + this.SetValue(result, 0); + } +} diff --git a/Quantower/Indicators/WMA_chart.cs b/Indicators/Charts/WMA_chart.cs similarity index 100% rename from Quantower/Indicators/WMA_chart.cs rename to Indicators/Charts/WMA_chart.cs diff --git a/Quantower/Quantower.csproj b/Indicators/Indicators.csproj similarity index 75% rename from Quantower/Quantower.csproj rename to Indicators/Indicators.csproj index a1495bc3..547741b9 100644 --- a/Quantower/Quantower.csproj +++ b/Indicators/Indicators.csproj @@ -1,52 +1,47 @@ - - - - net6 - preview - false - AnyCPU - Indicator - Quantower_QTAlib - QuanTAlib - embedded - preview - AnyCPU - disable - False - ..\.sonarlint\mihakralj_quantalibcsharp.ruleset - - - True - 3 - True - anycpu - full - C:\Quantower\TradingPlatform\v1.130.7\..\..\Settings\Scripts\Indicators\Quantower - - - embedded - True - 3 - True - anycpu - C:\Quantower\TradingPlatform\v1.130.7\..\..\Settings\Scripts\Indicators\Quantower - - - - QuanTAlib\%(RecursiveDir)%(Filename)%(Extension) - - - - - - - - - C:\Quantower\TradingPlatform\v1.130.7\bin\TradingPlatform.BusinessLayer.dll - - + + + + net6 + preview + false + AnyCPU + Indicator + Quantower_QTAlib + QuanTAlib + embedded + AnyCPU + disable + False + ..\.sonarlint\mihakralj_quantalibcsharp.ruleset + + + True + 3 + True + anycpu + full + C:\Quantower\TradingPlatform\v1.130.7\..\..\Settings\Scripts\Indicators\QuanTAlib + + + embedded + True + 3 + True + anycpu + C:\Quantower\TradingPlatform\v1.130.7\..\..\Settings\Scripts\Indicators\QuanTAlib + + + + + + + + + + + + + C:\Quantower\TradingPlatform\v1.130.7\bin\TradingPlatform.BusinessLayer.dll + + \ No newline at end of file diff --git a/QuanTAlib.sln b/QuanTAlib.sln index 3242afe2..d0b6ce59 100644 --- a/QuanTAlib.sln +++ b/QuanTAlib.sln @@ -3,11 +3,44 @@ 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}") = "QuanTAlib", "Source\QuanTAlib.csproj", "{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}" +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}") = "Quantower", "Quantower\Quantower.csproj", "{693713F9-F33A-4B33-8F98-63794CA9734C}" +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 EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -23,10 +56,14 @@ Global {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 - {693713F9-F33A-4B33-8F98-63794CA9734C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {693713F9-F33A-4B33-8F98-63794CA9734C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {693713F9-F33A-4B33-8F98-63794CA9734C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {693713F9-F33A-4B33-8F98-63794CA9734C}.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 diff --git a/Quantower/Indicators/ATR_chart.cs b/Quantower/Indicators/ATR_chart.cs deleted file mode 100644 index 5467c3de..00000000 --- a/Quantower/Indicators/ATR_chart.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Drawing; -using TradingPlatform.BusinessLayer; -namespace QuanTAlib; - -public class ATR_chart : Indicator -{ - #region Parameters - - [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] - private readonly int Period = 10; - - #endregion Parameters - - private TBars bars; - - /////// - private ATR_Series indicator; - /////// - - public ATR_chart() - { - this.SeparateWindow = true; - this.Name = "ATR - Average True Range"; - this.Description = "Average True Range description"; - this.AddLineSeries("ATR", Color.RoyalBlue, 3, LineStyle.Solid); - } - - protected override void OnInit() - { - this.bars = new(); -this.indicator = new(source: bars, period: this.Period, useNaN: false); - } - - 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); - double result = this.indicator[this.indicator.Count - 1].v; - this.SetValue(result); - } -} diff --git a/Quantower/Indicators/JMA_chart.cs b/Quantower/Indicators/JMA_chart.cs deleted file mode 100644 index d6c38982..00000000 --- a/Quantower/Indicators/JMA_chart.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Diagnostics; -using System.Drawing; -using System.Linq; -using TradingPlatform.BusinessLayer; -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 = 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 - - private TBars bars; - - /////// - private JMA_Series indicator; - /////// - - public JMA_chart() { - this.SeparateWindow = false; - this.Name = "JMA - Jurik Moving Avg"; - this.Description = "Jurik Moving Average description"; - 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, phase: Jphase, vshort: Vshort, vlong: Vlong, useNaN: false); - } - - 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); - double result = this.indicator[this.indicator.Count - 1].v; - - this.SetValue(result, lineIndex: 0); - } -} diff --git a/Quantower/Indicators/RSI_chart.cs b/Quantower/Indicators/RSI_chart.cs deleted file mode 100644 index ebd9d80b..00000000 --- a/Quantower/Indicators/RSI_chart.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Drawing; -using TradingPlatform.BusinessLayer; -namespace QuanTAlib; - -public class RSI_chart : Indicator -{ - #region Parameters - - [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] - private int Period = 10; - - [InputParameter("Data source", 1, 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 = 8; - - #endregion Parameters - - private TBars bars; - - /////// - private RSI_Series indicator; - /////// - - public RSI_chart() - { - this.SeparateWindow = true; - this.Name = "RSI - Relative Strength Index"; - this.Description = "RSI description"; - this.AddLineSeries("RSI", Color.RoyalBlue, 3, LineStyle.Solid); - } - - protected override void OnInit() - { - this.bars = new(); - this.indicator = new(source: bars.Select(this.DataSource), - period: this.Period, useNaN: true); - } - 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); - double result = this.indicator[this.indicator.Count - 1].v; - - this.SetValue(result, 0); - } -} diff --git a/Quantower/dll/TradingPlatform.BusinessLayer.dll b/Quantower/dll/TradingPlatform.BusinessLayer.dll deleted file mode 100644 index 245e51a7..00000000 Binary files a/Quantower/dll/TradingPlatform.BusinessLayer.dll and /dev/null differ diff --git a/Strategies/SimpleMACross1.cs b/Strategies/SimpleMACross1.cs new file mode 100644 index 00000000..98e14aa2 --- /dev/null +++ b/Strategies/SimpleMACross1.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using TradingPlatform.BusinessLayer; +using QuanTAlib; +using System.Drawing; + +namespace SimpleMACross { + public class SimpleMACross1 : Strategy, ICurrentAccount, ICurrentSymbol { + [InputParameter("Symbol", 0)] + public Symbol CurrentSymbol { get; set; } + + [InputParameter("Account", 1)] + public Account CurrentAccount { get; set; } + + [InputParameter("Fast MA", 2, minimum: 1, maximum: 100, increment: 1, decimalPlaces: 0)] + public int FastMA = 5; + + [InputParameter("Slow MA", 3, minimum: 1, maximum: 100, increment: 1, decimalPlaces: 0)] + public int SlowMA = 10; + + [InputParameter("Quantity", 4, 0.1, 99999, 0.1, 2)] + public double Quantity = 1.0; + + [InputParameter("Period", 5)] + public Period period = Period.MIN1; + + public override string[] MonitoringConnectionsIds => new string[] { this.CurrentSymbol?.ConnectionId, this.CurrentAccount?.ConnectionId }; + + private HistoricalData hdm; + private DateTime prev_time; + private readonly TBars bars = new(); + + public SimpleMACross1() + : base() { + this.Name = "Miha MA Cross strategy 3"; + this.Description = "Raw strategy without any additional functional"; + } + + protected override void OnRun() { + if (this.CurrentAccount != null && this.CurrentAccount.State == BusinessObjectState.Fake) this.CurrentAccount = Core.Instance.GetAccount(this.CurrentAccount.CreateInfo()); + if (this.CurrentSymbol != null && this.CurrentSymbol.State == BusinessObjectState.Fake) this.CurrentSymbol = Core.Instance.GetSymbol(this.CurrentSymbol.CreateInfo()); + if (this.CurrentSymbol == null || this.CurrentAccount == null || this.CurrentSymbol.ConnectionId != this.CurrentAccount.ConnectionId) { + this.Log("Incorrect input parameters... Symbol or Account are not specified or they have different connectionID.", StrategyLoggingLevel.Error); + return; } + + ///////////////////////////////////////////////////// + this.hdm = this.CurrentSymbol.GetHistory(Period.MIN1, this.CurrentSymbol.HistoryType, Core.TimeUtils.DateTimeUtcNow.AddDays(-1)); + //////////////////////////////////////////////////// + + + this.LogInfo($"Symbol: {CurrentSymbol.Name} period: {this.period} :-: {this.CurrentSymbol.HistoryType.ToString()} :-: {this.hdm.Count} bars loaded"); + this.hdm.HistoryItemUpdated += this.Hdm_HistoryItemUpdated; + } + + private void Hdm_HistoryItemUpdated(object sender, HistoryEventArgs e) { + this.OnUpdate(); + } + + private void OnUpdate() { + bool update = hdm.Last().TimeLeft - prev_time < this.period.Duration ? true : false; + if (!update) prev_time = hdm.Last().TimeLeft; + + bars.Add(hdm.Last().TimeLeft, hdm.Last()[PriceType.Open], hdm.Last()[PriceType.High], + hdm.Last()[PriceType.Low], hdm.Last()[PriceType.Close], hdm.Last()[PriceType.Volume], update); + + if (!update) this.LogInfo($"{bars.Close.Last().t} OHLC4:{(double)bars.OHLC4}"); + + } + + protected override List OnGetMetrics() { + var result = base.OnGetMetrics(); + + // An example of adding custom strategy metrics: + result.Add("Bars processed", this.bars.Count.ToString()); + /* + result.Add("Trades [#]", "0"); + result.Add("Long trades [#]", this.longPositionsCount.ToString()); + result.Add("Short trades [#]", this.shortPositionsCount.ToString()); + result.Add("Profitable trades [#]", "0"); + result.Add("Win Rate [%]", "0"); + result.Add("Best Trade [%]", "0"); + result.Add("Worst Trade[%]", "0"); + result.Add("Avg Winning Trade [%]", "0"); + result.Add("Avg Losing Trade [%]", "0"); + result.Add("Profit Factor", "0"); + result.Add("Sharpe Ratio", "0"); + result.Add("Sortino Ratio", "0"); + result.Add("Omega Ratio", "0"); + result.Add("Calmar Ratio", "0"); + result.Add("Beta", "0"); + result.Add("Alpha", "0"); + */ + return result; + } + + protected override void OnStop() { + if (this.hdm != null) { + this.hdm.HistoryItemUpdated -= this.Hdm_HistoryItemUpdated; + this.hdm.Dispose(); + } + + base.OnStop(); + } + } +} + diff --git a/Strategies/Strategies.csproj b/Strategies/Strategies.csproj new file mode 100644 index 00000000..f067f1fa --- /dev/null +++ b/Strategies/Strategies.csproj @@ -0,0 +1,45 @@ + + + net6.0 + preview + false + AnyCPU + Strategy + Strategy + Strategy + AnyCPU + disable + False + Program + C:\Quantower\TradingPlatform\v1.130.7\Console.StarterNew.exe + --address 127.0.0.1 --port 51113 + ..\.sonarlint\mihakralj_quantalibcsharp.ruleset + + + True + 3 + True + anycpu + full + C:\Quantower\TradingPlatform\v1.130.7\..\..\Settings\Scripts\Strategies\QuanTAlib + + + embedded + True + 3 + True + anycpu + C:\Quantower\TradingPlatform\v1.130.7\..\..\Settings\Scripts\Strategies\QuanTAlib + + + + + + + + + + C:\Quantower\TradingPlatform\v1.130.7\bin\TradingPlatform.BusinessLayer.dll + + + \ No newline at end of file diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 38bc8c2b..358c4d94 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -24,7 +24,7 @@ - +