From 59ca5c2395afc3816702ef67364a29346ee4efde Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Sat, 12 Nov 2022 19:00:38 -0800 Subject: [PATCH] GitVersion GitVersion --- .github/workflows/main_automation.yml | 24 +- GitVersion.yml | 17 + QuanTAlib.sln | 20 - Quantower/Indicators/SDEV_chart.cs | 106 ++--- Quantower/Indicators/VAR_chart.cs | 108 ++--- Quantower/Indicators/WMAPE_chart.cs | 112 ++--- Source/Basics/Abstracts.cs | 270 ++++++------ Source/Basics/MAX_Series.cs | 66 +-- Source/Basics/MIN_Series.cs | 66 +-- Source/Basics/TBars.cs | 264 ++++++------ Source/Feeds/RND_Feed.cs | 54 +-- Source/Momentum/CCI_Series.cs | 96 ++--- Source/QuanTAlib.csproj | 143 +++---- Source/Statistics/KURT_Series.cs | 122 +++--- Source/Statistics/MED_Series.cs | 94 ++--- Source/Statistics/SVAR_Series.cs | 84 ++-- Source/Statistics/VAR_Series.cs | 84 ++-- Source/Trends/ALMA_Series.cs | 130 +++--- Source/Trends/DEMA_Series.cs | 142 +++---- Source/Trends/EMA_Series.cs | 126 +++--- Source/Trends/HEMA_Series.cs | 128 +++--- Source/Trends/HMA_Series.cs | 240 +++++------ Source/Trends/JMA_Series.cs | 320 +++++++-------- Source/Trends/KAMA_Series.cs | 128 +++--- Source/Trends/MACD_Series.cs | 90 ++-- Source/Trends/RMA_Series.cs | 124 +++--- Source/Trends/SMA_Series.cs | 82 ++-- Source/Trends/SMMA_Series.cs | 114 +++--- Source/Trends/TEMA_Series.cs | 154 +++---- Source/Trends/TRIMA_Series.cs | 96 ++--- Source/Trends/WMA_Series.cs | 76 ++-- Source/Trends/ZLEMA_Series.cs | 142 +++---- Source/Volatility/ADL_Series.cs | 84 ++-- Source/Volatility/ADOSC_Series.cs | 88 ++-- Source/Volatility/ATRP_Series.cs | 124 +++--- Source/Volatility/ATR_Series.cs | 124 +++--- Source/Volatility/BBANDS_Series.cs | 144 +++---- Source/Volatility/RSI_Series.cs | 144 +++---- Source/Volume/OBV_Series.cs | 124 +++--- Tests/Basics/Abstract_Test.cs | 46 +-- Tests/Basics/TBars_Test.cs | 224 +++++----- Tests/Basics/TSeries_Test.cs | 122 +++--- Tests/MovingAvg/ALMA_Test.cs | 62 +-- Tests/MovingAvg/BBANDS_Test.cs | 112 ++--- Tests/MovingAvg/DEMA_Test.cs | 62 +-- Tests/MovingAvg/EMA_Test.cs | 62 +-- Tests/MovingAvg/HEMA_Test.cs | 62 +-- Tests/MovingAvg/HMA_Test.cs | 62 +-- Tests/MovingAvg/JMA_Test.cs | 62 +-- Tests/MovingAvg/KAMA_Test.cs | 62 +-- Tests/MovingAvg/MACD_Test.cs | 62 +-- Tests/MovingAvg/RMA_Test.cs | 62 +-- Tests/MovingAvg/RSI_Test.cs | 62 +-- Tests/MovingAvg/SMA_Test.cs | 62 +-- Tests/MovingAvg/SMMA_Test.cs | 62 +-- Tests/MovingAvg/TEMA_Test.cs | 62 +-- Tests/MovingAvg/WMA_Test.cs | 62 +-- Tests/MovingAvg/ZLEMA_Test.cs | 62 +-- Tests/Statistics/BIAS_Test.cs | 62 +-- Tests/Statistics/ENTP_Test.cs | 62 +-- Tests/Statistics/KURT_Test.cs | 62 +-- Tests/Statistics/LINREG_Test.cs | 62 +-- Tests/Statistics/MAD_Test.cs | 62 +-- Tests/Statistics/MAPE_Test.cs | 62 +-- Tests/Statistics/MAX_Test.cs | 62 +-- Tests/Statistics/MED_Test.cs | 62 +-- Tests/Statistics/MIN_Test.cs | 62 +-- Tests/Statistics/MSE_Test.cs | 62 +-- Tests/Statistics/PSDEV_Test.cs | 62 +-- Tests/Statistics/PVAR_Test .cs | 62 +-- Tests/Statistics/SDEV_Test .cs | 62 +-- Tests/Statistics/SMAPE_Test.cs | 62 +-- Tests/Statistics/VAR_Test.cs | 62 +-- Tests/Statistics/WMAPE_Test.cs | 62 +-- Tests/Tests.csproj | 30 +- Tests/Validations/Pandas_TA.cs | 243 +++++------ Tests/Validations/Skender_Stock.cs | 564 +++++++++++++------------- Tests/Validations/TA_LIB.cs | 544 ++++++++++++------------- docs/crossovers.ipynb | 31 +- docs/readme.md | 2 +- 80 files changed, 4237 insertions(+), 4257 deletions(-) create mode 100644 GitVersion.yml diff --git a/.github/workflows/main_automation.yml b/.github/workflows/main_automation.yml index f6307300..ca0c0815 100644 --- a/.github/workflows/main_automation.yml +++ b/.github/workflows/main_automation.yml @@ -30,6 +30,8 @@ jobs: with: java-version: 1.11 + - name: Install GitVersion + run: dotnet tool install GitVersion.Tool --global - name: Install JetBrains run: dotnet tool install JetBrains.dotCover.GlobalTool --global - name: Install Sonar Scanner @@ -78,14 +80,14 @@ jobs: project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} coverage-reports: ./coveragereport.xml - - name: Release - uses: marvinpinto/action-automatic-releases@latest - with: - repo_token: "${{ secrets.GITHUB_TOKEN }}" - automatic_release_tag: "latest" - prerelease: true - title: "Latest Build" - files: /Quantower/Settings/Scripts/Indicators/QuanTAlib/*.dll +# - name: Release +# uses: marvinpinto/action-automatic-releases@latest +# with: +# repo_token: "${{ secrets.GITHUB_TOKEN }}" +# automatic_release_tag: "latest" +# prerelease: true +# title: "Latest Build" +# files: /Quantower/Settings/Scripts/Indicators/QuanTAlib/*.dll - name: Authenticate to Github packages source run: dotnet nuget add source @@ -95,14 +97,12 @@ jobs: --name github "https://nuget.pkg.github.com/mihakralj/index.json" - name: Push package to github - if: ${{ github.ref == 'refs/heads/dev' }} run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg' + --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/mihakralj/index.json --skip-duplicate - --no-symbols - - name: Push package to nuget.org - if: ${{ github.ref == 'refs/heads/main' }} + - name: Push package to nuget.org run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg' --api-key ${{ secrets.NUGET_DEPLOY_KEY_QUANTLIB }} --source https://api.nuget.org/v3/index.json diff --git a/GitVersion.yml b/GitVersion.yml new file mode 100644 index 00000000..deb60508 --- /dev/null +++ b/GitVersion.yml @@ -0,0 +1,17 @@ +next-version: 0.1.19 +minor-version-bump-message: \+semver:\s?(feature|new) +branches: + main: + regex: ^main$ + is-release-branch: true + prevent-increment-of-merged-branch-version: true + mode: ContinuousDelivery + tag: '' + increment: Patch + develop: + regex: ^dev(elop)?(ment)?$ + is-release-branch: false + mode: ContinuousDelivery + tag: 'nightly' + increment: Inherit +update-build-number: true \ No newline at end of file diff --git a/QuanTAlib.sln b/QuanTAlib.sln index f57bc1b0..e169574a 100644 --- a/QuanTAlib.sln +++ b/QuanTAlib.sln @@ -5,42 +5,22 @@ VisualStudioVersion = 17.2.32210.308 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuanTAlib", "Source\QuanTAlib.csproj", "{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Quantower", "Quantower\Quantower.csproj", "{5096AEA1-81BC-46E7-9F2B-B408AFAA850C}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Debug|x64.ActiveCfg = Debug|Any CPU - {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Debug|x64.Build.0 = Debug|Any CPU {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Release|Any CPU.ActiveCfg = Release|Any CPU {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Release|Any CPU.Build.0 = Release|Any CPU - {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Release|x64.ActiveCfg = Release|x64 - {AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Release|x64.Build.0 = Release|x64 - {5096AEA1-81BC-46E7-9F2B-B408AFAA850C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5096AEA1-81BC-46E7-9F2B-B408AFAA850C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5096AEA1-81BC-46E7-9F2B-B408AFAA850C}.Debug|x64.ActiveCfg = Release|Any CPU - {5096AEA1-81BC-46E7-9F2B-B408AFAA850C}.Debug|x64.Build.0 = Release|Any CPU - {5096AEA1-81BC-46E7-9F2B-B408AFAA850C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5096AEA1-81BC-46E7-9F2B-B408AFAA850C}.Release|Any CPU.Build.0 = Release|Any CPU - {5096AEA1-81BC-46E7-9F2B-B408AFAA850C}.Release|x64.ActiveCfg = Release|x64 - {5096AEA1-81BC-46E7-9F2B-B408AFAA850C}.Release|x64.Build.0 = Release|x64 {283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Debug|x64.ActiveCfg = Debug|x64 - {283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Debug|x64.Build.0 = Debug|x64 {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 - {283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Release|x64.ActiveCfg = Release|x64 - {283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Quantower/Indicators/SDEV_chart.cs b/Quantower/Indicators/SDEV_chart.cs index 0e220570..a5b956fa 100644 --- a/Quantower/Indicators/SDEV_chart.cs +++ b/Quantower/Indicators/SDEV_chart.cs @@ -1,53 +1,53 @@ -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.ShortName = - "SDEV (" + TBars.SelectStr(this.DataSource) + ", " + this.Period + ")"; - 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.ShortName = + "SDEV (" + TBars.SelectStr(this.DataSource) + ", " + this.Period + ")"; + 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/VAR_chart.cs b/Quantower/Indicators/VAR_chart.cs index 9d22a14d..3a665f01 100644 --- a/Quantower/Indicators/VAR_chart.cs +++ b/Quantower/Indicators/VAR_chart.cs @@ -1,54 +1,54 @@ -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.ShortName = - "VAR (" + TBars.SelectStr(this.DataSource) + ", " + this.Period + ")"; - 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.ShortName = + "VAR (" + TBars.SelectStr(this.DataSource) + ", " + this.Period + ")"; + 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/Quantower/Indicators/WMAPE_chart.cs index 54fb4256..8444fb2e 100644 --- a/Quantower/Indicators/WMAPE_chart.cs +++ b/Quantower/Indicators/WMAPE_chart.cs @@ -1,56 +1,56 @@ -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.ShortName = "WMAPE (" + QuanTAlib.TBars.SelectStr(this.DataSource) + ", " + this.Period + ")"; - 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.ShortName = "WMAPE (" + QuanTAlib.TBars.SelectStr(this.DataSource) + ", " + this.Period + ")"; + 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/Source/Basics/Abstracts.cs b/Source/Basics/Abstracts.cs index 434f3e7a..fc79b46f 100644 --- a/Source/Basics/Abstracts.cs +++ b/Source/Basics/Abstracts.cs @@ -1,135 +1,135 @@ -namespace QuanTAlib; -using System; -/* -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 _p; - protected readonly bool _NaN; - protected readonly TSeries _data; - - // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) - protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN) - { - this._data = source; - this._p = period; - this._NaN = useNaN; - this._data.Pub += this.Sub; - } - - // overridable Add() method to add/update a single item at the end of the list - public new virtual void Add((System.DateTime t, double v) TValue, bool update) => base.Add(TValue, update); - - // potentially overridable Add() method for the whole series (could be replaced with faster bulk algo) - public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { this.Add(TValue: data[i], update: false); }} - - public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false); - 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); -} - -public abstract class Pair_TSeries_Indicator : TSeries -{ - protected readonly TSeries _d1; - protected readonly TSeries _d2; - protected readonly double _dd1, _dd2; - - // Chainable Constructors - add them at the end of primary constructors if needed - protected Pair_TSeries_Indicator(TSeries source1, TSeries source2) - { - this._d1 = source1; - this._d2 = source2; - this._dd1 = double.NaN; - this._dd2 = double.NaN; - this._d1.Pub += this.Sub; - this._d2.Pub += this.Sub; - } - protected Pair_TSeries_Indicator(TSeries source1, double dd2) - { - this._d1 = source1; - this._d2 = new(); - this._dd1 = double.NaN; - this._dd2 = dd2; - this._d1.Pub += this.Sub; - } - protected Pair_TSeries_Indicator(double dd1, TSeries source2) - { - this._d1 = new(); - this._d2 = source2; - this._dd1 = dd1; - this._dd2 = double.NaN; - this._d2.Pub += this.Sub; - } - - // overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list - public virtual void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update) => base.Add(TValue: (TValue1.t, 0), update: update); // default inserts zeros - - // potentially overridable Add() bulk variations (could be replaced with faster bulk algos) - public virtual void Add(TSeries d1, TSeries d2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], d2[i], update: false); }} - public virtual void Add(TSeries d1, double dd2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], (d1[i].t, dd2), update: false); }} - public virtual void Add(double dd1, TSeries d2) { for (int i = 0; i < d2.Count; i++) { this.Add((d2[i].t, dd1), d2[i], update: false); }} - - public void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2) => this.Add(TValue1, TValue2, update: false); - - public void Add(bool update) - { - if ((this._dd1 is double.NaN) && (this._dd2 is double.NaN)) - { - // (Series, Series) - if (update || (this._d1.Count > this.Count && this._d2.Count > this.Count)) - { this.Add(this._d1[this._d1.Count - 1], this._d2[this._d2.Count - 1], update); } - } - else if ((this._dd2 is not double.NaN) && (this._dd1 is double.NaN)) - { - // (Series, Double) - this.Add(TValue1: this._d1[this._d1.Count - 1], TValue2: (this._d1[this._d1.Count - 1].t, this._dd2), update: update); - } - else - { - // (Double, Series) - this.Add(TValue1: (this._d2[this._d2.Count - 1].t, this._dd1), TValue2: this._d2[this._d2.Count - 1], update: update); - } - } - - public void Add() => this.Add(update: false); - public new void Sub(object source, TSeriesEventArgs e) => this.Add(e.update); -} - -public abstract class Single_TBars_Indicator : TSeries -{ - protected readonly int _p; - protected readonly bool _NaN; - protected readonly TBars _bars; - - // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) - protected Single_TBars_Indicator(TBars source, int period, bool useNaN) - { - this._p = period; - this._bars = source; - this._NaN = useNaN; - this._bars.Pub += this.Sub; - } - - // overridable Add() method to add/update a single item at the end of the list - public virtual void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar, bool update) => base.Add((TBar.t, 0.0), update); - - // potentially overridable Add() method for the whole bars or series (could be replaced with faster bulk algo) - public virtual void Add(TBars bars) { for (int i = 0; i < bars.Count; i++) { this.Add(TBar: bars[i], update: false); }} - public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { base.Add(TValue: data[i], update: false); }} - public void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar) => this.Add(TBar: TBar, update: false); - public void Add(bool update) => this.Add(TBar: this._bars[this._bars.Count - 1], update: update); - public void Add() => this.Add(TBar: this._bars[this._bars.Count - 1], update: false); - public new void Sub(object source, TSeriesEventArgs e) => this.Add(TBar: this._bars[this._bars.Count - 1], update: e.update); -} +namespace QuanTAlib; +using System; +/* +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 _p; + protected readonly bool _NaN; + protected readonly TSeries _data; + + // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) + protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN) + { + this._data = source; + this._p = period; + this._NaN = useNaN; + this._data.Pub += this.Sub; + } + + // overridable Add() method to add/update a single item at the end of the list + public new virtual void Add((System.DateTime t, double v) TValue, bool update) => base.Add(TValue, update); + + // potentially overridable Add() method for the whole series (could be replaced with faster bulk algo) + public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { this.Add(TValue: data[i], update: false); }} + + public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false); + 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); +} + +public abstract class Pair_TSeries_Indicator : TSeries +{ + protected readonly TSeries _d1; + protected readonly TSeries _d2; + protected readonly double _dd1, _dd2; + + // Chainable Constructors - add them at the end of primary constructors if needed + protected Pair_TSeries_Indicator(TSeries source1, TSeries source2) + { + this._d1 = source1; + this._d2 = source2; + this._dd1 = double.NaN; + this._dd2 = double.NaN; + this._d1.Pub += this.Sub; + this._d2.Pub += this.Sub; + } + protected Pair_TSeries_Indicator(TSeries source1, double dd2) + { + this._d1 = source1; + this._d2 = new(); + this._dd1 = double.NaN; + this._dd2 = dd2; + this._d1.Pub += this.Sub; + } + protected Pair_TSeries_Indicator(double dd1, TSeries source2) + { + this._d1 = new(); + this._d2 = source2; + this._dd1 = dd1; + this._dd2 = double.NaN; + this._d2.Pub += this.Sub; + } + + // overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list + public virtual void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update) => base.Add(TValue: (TValue1.t, 0), update: update); // default inserts zeros + + // potentially overridable Add() bulk variations (could be replaced with faster bulk algos) + public virtual void Add(TSeries d1, TSeries d2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], d2[i], update: false); }} + public virtual void Add(TSeries d1, double dd2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], (d1[i].t, dd2), update: false); }} + public virtual void Add(double dd1, TSeries d2) { for (int i = 0; i < d2.Count; i++) { this.Add((d2[i].t, dd1), d2[i], update: false); }} + + public void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2) => this.Add(TValue1, TValue2, update: false); + + public void Add(bool update) + { + if ((this._dd1 is double.NaN) && (this._dd2 is double.NaN)) + { + // (Series, Series) + if (update || (this._d1.Count > this.Count && this._d2.Count > this.Count)) + { this.Add(this._d1[this._d1.Count - 1], this._d2[this._d2.Count - 1], update); } + } + else if ((this._dd2 is not double.NaN) && (this._dd1 is double.NaN)) + { + // (Series, Double) + this.Add(TValue1: this._d1[this._d1.Count - 1], TValue2: (this._d1[this._d1.Count - 1].t, this._dd2), update: update); + } + else + { + // (Double, Series) + this.Add(TValue1: (this._d2[this._d2.Count - 1].t, this._dd1), TValue2: this._d2[this._d2.Count - 1], update: update); + } + } + + public void Add() => this.Add(update: false); + public new void Sub(object source, TSeriesEventArgs e) => this.Add(e.update); +} + +public abstract class Single_TBars_Indicator : TSeries +{ + protected readonly int _p; + protected readonly bool _NaN; + protected readonly TBars _bars; + + // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) + protected Single_TBars_Indicator(TBars source, int period, bool useNaN) + { + this._p = period; + this._bars = source; + this._NaN = useNaN; + this._bars.Pub += this.Sub; + } + + // overridable Add() method to add/update a single item at the end of the list + public virtual void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar, bool update) => base.Add((TBar.t, 0.0), update); + + // potentially overridable Add() method for the whole bars or series (could be replaced with faster bulk algo) + public virtual void Add(TBars bars) { for (int i = 0; i < bars.Count; i++) { this.Add(TBar: bars[i], update: false); }} + public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { base.Add(TValue: data[i], update: false); }} + public void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar) => this.Add(TBar: TBar, update: false); + public void Add(bool update) => this.Add(TBar: this._bars[this._bars.Count - 1], update: update); + public void Add() => this.Add(TBar: this._bars[this._bars.Count - 1], update: false); + public new void Sub(object source, TSeriesEventArgs e) => this.Add(TBar: this._bars[this._bars.Count - 1], update: e.update); +} diff --git a/Source/Basics/MAX_Series.cs b/Source/Basics/MAX_Series.cs index 591f6739..1f0af935 100644 --- a/Source/Basics/MAX_Series.cs +++ b/Source/Basics/MAX_Series.cs @@ -1,34 +1,34 @@ -namespace QuanTAlib; -using System; - -/* -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) - { - if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } - else { this._buffer.Add(TValue.v); } - if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } - - double _max = TValue.v; - for (int i = 0; i < this._buffer.Count; i++) - { - //_max = (this._buffer[i] > _max) ? this._buffer[i] : _max; - _max = Math.Max(this._buffer[i], _max); - } - - var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _max); - - base.Add(result, update); - } +namespace QuanTAlib; +using System; + +/* +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) + { + if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } + else { this._buffer.Add(TValue.v); } + if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } + + double _max = TValue.v; + for (int i = 0; i < this._buffer.Count; i++) + { + //_max = (this._buffer[i] > _max) ? this._buffer[i] : _max; + _max = Math.Max(this._buffer[i], _max); + } + + var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _max); + + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Basics/MIN_Series.cs b/Source/Basics/MIN_Series.cs index 4209d0b1..889370e2 100644 --- a/Source/Basics/MIN_Series.cs +++ b/Source/Basics/MIN_Series.cs @@ -1,34 +1,34 @@ -namespace QuanTAlib; -using System; - -/* -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) - { - if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } - else { this._buffer.Add(TValue.v); } - if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } - - double _min = TValue.v; - for (int i = 0; i < this._buffer.Count; i++) - { - //_min = (this._buffer[i] < _min) ? this._buffer[i] : _min; - _min = Math.Min(this._buffer[i], _min); - } - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _min); - - base.Add(result, update); - } +namespace QuanTAlib; +using System; + +/* +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) + { + if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } + else { this._buffer.Add(TValue.v); } + if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } + + double _min = TValue.v; + for (int i = 0; i < this._buffer.Count; i++) + { + //_min = (this._buffer[i] < _min) ? this._buffer[i] : _min; + _min = Math.Min(this._buffer[i], _min); + } + + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _min); + + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Basics/TBars.cs b/Source/Basics/TBars.cs index 31954ef4..850a9db7 100644 --- a/Source/Basics/TBars.cs +++ b/Source/Basics/TBars.cs @@ -1,132 +1,132 @@ -namespace QuanTAlib; -using System; - -/* -TBars class - includes all series for common data used in indicators and other calculations. - Has a bit limited overloading and casting (compared to TSeries) - Includes Select(int) method to simplify choosing the most optimal data source for indicators - Includes the most basic pricing calcs: HL2, OC2, OHL3, HLC3, OHLC4, HLCC4 - (it is 'cheaper' to calculate them once during data capture than each time during data analysis) - - */ - -public class TBars : System.Collections.Generic.List<(DateTime t, double o, double h, double l, double c, double v)> -{ - private readonly TSeries _open = new(); - private readonly TSeries _high = new(); - private readonly TSeries _low = new(); - private readonly TSeries _close = new(); - private readonly TSeries _volume = new(); - private readonly TSeries _hl2 = new(); - private readonly TSeries _oc2 = new(); - private readonly TSeries _ohl3 = new(); - private readonly TSeries _hlc3 = new(); - private readonly TSeries _ohlc4 = new(); - private readonly TSeries _hlcc4 = new(); - - public TSeries Open => this._open; - public TSeries High => this._high; - public TSeries Low => this._low; - public TSeries Close => this._close; - public TSeries Volume => this._volume; - public TSeries HL2 => this._hl2; - public TSeries OC2 => this._oc2; - public TSeries OHL3 => this._ohl3; - public TSeries HLC3 => this._hlc3; - public TSeries OHLC4 => this._ohlc4; - public TSeries HLCC4 => this._hlcc4; - - public TBars Tail(int count=10) { - TBars outBars = new(); - if (count > this.Count) { count = this.Count; } - for (int i = this.Count-count; i _open, - 1 => _high, - 2 => _low, - 3 => _close, - 4 => _hl2, - 5 => _oc2, - 6 => _ohl3, - 7 => _hlc3, - 8 => _ohlc4, - _ => _hlcc4, - }; - } - public static string SelectStr(int source) - { - return source switch - { - 0 => "Open", - 1 => "High", - 2 => "Low", - 3 => "Close", - 4 => "HL2", - 5 => "OC2", - 6 => "OHL3", - 7 => "Typical", - 8 => "Mean", - _ => "Weighted", - }; - } - - public void Add((DateTime t, double o, double h, double l, double c, double v) i, bool update = false) - => Add(i.t, i.o, i.h, i.l, i.c, i.v, update); - - public void Add(DateTime t, decimal o, decimal h, decimal l, decimal c, decimal v, bool update = false) - => Add(t, (double)o, (double)h, (double)l, (double)c, (double)v, update); - - public void Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) - { - if (update) - { - this[this.Count - 1] = (t, o, h, l, c, v); - _open[_open.Count - 1] = (t, o); - _high[_high.Count - 1] = (t, h); - _low[_low.Count - 1] = (t, l); - _close[_close.Count - 1] = (t, c); - _volume[_volume.Count - 1] = (t, v); - _hl2[_hl2.Count - 1] = (t, (h + l) * 0.5); - _oc2[_oc2.Count - 1] = (t, (o + c) * 0.5); - _ohl3[_ohl3.Count - 1] = (t, (o + h + l) * 0.333333333333333); - _hlc3[_hlc3.Count - 1] = (t, (h + l + c) * 0.333333333333333); - _ohlc4[_ohlc4.Count - 1] = (t, (o + h + l + c) * 0.25); - _hlcc4[_hlcc4.Count - 1] = (t, (h + l + c + c) * 0.25); - } - else - { - base.Add((t, o, h, l, c, v)); - _open.Add((t, o)); - _high.Add((t, h)); - _low.Add((t, l)); - _close.Add((t, c)); - _volume.Add((t, v)); - _hl2.Add((t, (h + l) * 0.5)); - _oc2.Add((t, (o + c) * 0.5)); - _ohl3.Add((t, (o + h + l) * 0.333333333333333)); - _hlc3.Add((t, (h + l + c) * 0.333333333333333)); - _ohlc4.Add((t, (o + h + l + c) * 0.25)); - _hlcc4.Add((t, (h + l + c + c) * 0.25)); - } - this.OnEvent(update); - } - - // delegate used by event handler + event handler (Pub == publisher) - public delegate - void NewDataEventHandler(object source, TSeriesEventArgs args); - public event NewDataEventHandler Pub; - - // Broadcast handler - only to valid targets - protected virtual void OnEvent(bool update = false) - { - if (Pub != null && Pub.Target != this) - { - Pub(this, new TSeriesEventArgs { update = update }); - } - } -} +namespace QuanTAlib; +using System; + +/* +TBars class - includes all series for common data used in indicators and other calculations. + Has a bit limited overloading and casting (compared to TSeries) + Includes Select(int) method to simplify choosing the most optimal data source for indicators + Includes the most basic pricing calcs: HL2, OC2, OHL3, HLC3, OHLC4, HLCC4 + (it is 'cheaper' to calculate them once during data capture than each time during data analysis) + + */ + +public class TBars : System.Collections.Generic.List<(DateTime t, double o, double h, double l, double c, double v)> +{ + private readonly TSeries _open = new(); + private readonly TSeries _high = new(); + private readonly TSeries _low = new(); + private readonly TSeries _close = new(); + private readonly TSeries _volume = new(); + private readonly TSeries _hl2 = new(); + private readonly TSeries _oc2 = new(); + private readonly TSeries _ohl3 = new(); + private readonly TSeries _hlc3 = new(); + private readonly TSeries _ohlc4 = new(); + private readonly TSeries _hlcc4 = new(); + + public TSeries Open => this._open; + public TSeries High => this._high; + public TSeries Low => this._low; + public TSeries Close => this._close; + public TSeries Volume => this._volume; + public TSeries HL2 => this._hl2; + public TSeries OC2 => this._oc2; + public TSeries OHL3 => this._ohl3; + public TSeries HLC3 => this._hlc3; + public TSeries OHLC4 => this._ohlc4; + public TSeries HLCC4 => this._hlcc4; + + public TBars Tail(int count=10) { + TBars outBars = new(); + if (count > this.Count) { count = this.Count; } + for (int i = this.Count-count; i _open, + 1 => _high, + 2 => _low, + 3 => _close, + 4 => _hl2, + 5 => _oc2, + 6 => _ohl3, + 7 => _hlc3, + 8 => _ohlc4, + _ => _hlcc4, + }; + } + public static string SelectStr(int source) + { + return source switch + { + 0 => "Open", + 1 => "High", + 2 => "Low", + 3 => "Close", + 4 => "HL2", + 5 => "OC2", + 6 => "OHL3", + 7 => "Typical", + 8 => "Mean", + _ => "Weighted", + }; + } + + public void Add((DateTime t, double o, double h, double l, double c, double v) i, bool update = false) + => Add(i.t, i.o, i.h, i.l, i.c, i.v, update); + + public void Add(DateTime t, decimal o, decimal h, decimal l, decimal c, decimal v, bool update = false) + => Add(t, (double)o, (double)h, (double)l, (double)c, (double)v, update); + + public void Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) + { + if (update) + { + this[this.Count - 1] = (t, o, h, l, c, v); + _open[_open.Count - 1] = (t, o); + _high[_high.Count - 1] = (t, h); + _low[_low.Count - 1] = (t, l); + _close[_close.Count - 1] = (t, c); + _volume[_volume.Count - 1] = (t, v); + _hl2[_hl2.Count - 1] = (t, (h + l) * 0.5); + _oc2[_oc2.Count - 1] = (t, (o + c) * 0.5); + _ohl3[_ohl3.Count - 1] = (t, (o + h + l) * 0.333333333333333); + _hlc3[_hlc3.Count - 1] = (t, (h + l + c) * 0.333333333333333); + _ohlc4[_ohlc4.Count - 1] = (t, (o + h + l + c) * 0.25); + _hlcc4[_hlcc4.Count - 1] = (t, (h + l + c + c) * 0.25); + } + else + { + base.Add((t, o, h, l, c, v)); + _open.Add((t, o)); + _high.Add((t, h)); + _low.Add((t, l)); + _close.Add((t, c)); + _volume.Add((t, v)); + _hl2.Add((t, (h + l) * 0.5)); + _oc2.Add((t, (o + c) * 0.5)); + _ohl3.Add((t, (o + h + l) * 0.333333333333333)); + _hlc3.Add((t, (h + l + c) * 0.333333333333333)); + _ohlc4.Add((t, (o + h + l + c) * 0.25)); + _hlcc4.Add((t, (h + l + c + c) * 0.25)); + } + this.OnEvent(update); + } + + // delegate used by event handler + event handler (Pub == publisher) + public delegate + void NewDataEventHandler(object source, TSeriesEventArgs args); + public event NewDataEventHandler Pub; + + // Broadcast handler - only to valid targets + protected virtual void OnEvent(bool update = false) + { + if (Pub != null && Pub.Target != this) + { + Pub(this, new TSeriesEventArgs { update = update }); + } + } +} diff --git a/Source/Feeds/RND_Feed.cs b/Source/Feeds/RND_Feed.cs index 3105d79f..c30881e7 100644 --- a/Source/Feeds/RND_Feed.cs +++ b/Source/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/Momentum/CCI_Series.cs b/Source/Momentum/CCI_Series.cs index f1f6c737..48511851 100644 --- a/Source/Momentum/CCI_Series.cs +++ b/Source/Momentum/CCI_Series.cs @@ -1,49 +1,49 @@ -namespace QuanTAlib; -using System; - -/* -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 = 0; - for (int i = 0; i < this._tp.Count; i++) { _avgTp+=this._tp[i]; } - _avgTp /= this._tp.Count; - - // 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); - - var result = (TBar.t, (this.Count < this._p && this._NaN) ? double.NaN : _cci); - base.Add(result, update); - } +namespace QuanTAlib; +using System; + +/* +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 = 0; + for (int i = 0; i < this._tp.Count; i++) { _avgTp+=this._tp[i]; } + _avgTp /= this._tp.Count; + + // 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); + + var result = (TBar.t, (this.Count < this._p && this._NaN) ? double.NaN : _cci); + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/QuanTAlib.csproj b/Source/QuanTAlib.csproj index c43aedcb..0559540c 100644 --- a/Source/QuanTAlib.csproj +++ b/Source/QuanTAlib.csproj @@ -1,72 +1,73 @@ - - - - 0.1.18 - - - QuanTAlib - Library of Technical Indicators for .NET - Quantitative Technical Analysis library for both real-time (streaming) and historical data analysis - git - https://github.com/mihakralj/QuanTAlib - true - Miha Kralj - Miha Kralj - readme.md - net7.0;net6.0;netstandard2.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 - - false - - - full - True - 7 - True - anycpu - - - - True - 7 - True - anycpu - - - QuanTAlib2.png - https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png - True - - - - True - - - - True - False - - - - - - + + + + QuanTAlib + Library of Technical Indicators for .NET + Quantitative Technical Analysis library for both real-time (streaming) and historical data analysis + git + https://github.com/mihakralj/QuanTAlib + true + Miha Kralj + Miha Kralj + readme.md + net7.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 + + false + + + full + True + 7 + True + anycpu + + + + True + 7 + True + anycpu + + + QuanTAlib2.png + https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png + True + + + + True + + + + True + False + + + + + + + All + + + \ No newline at end of file diff --git a/Source/Statistics/KURT_Series.cs b/Source/Statistics/KURT_Series.cs index ed0a45c4..10b1242f 100644 --- a/Source/Statistics/KURT_Series.cs +++ b/Source/Statistics/KURT_Series.cs @@ -1,62 +1,62 @@ -namespace QuanTAlib; -using System; - -/* -KURT: Kurtosis of population - Kurtosis characterizes the relative peakedness or flatness of a distribution - compared with the normal distribution. Positive kurtosis indicates a relatively - peaked distribution. Negative kurtosis indicates a relatively flat distribution. - - The normal curve is called Mesokurtic curve. If the curve of a distribution is - more outlier prone (or heavier-tailed) than a normal or mesokurtic curve then - it is referred to as a Leptokurtic curve. If a curve is less outlier prone (or - lighter-tailed) than a normal curve, it is called as a platykurtic curve. - -Calculation: - sum4 = Σ(close-SMA)^4 - sum2 = (Σ(close-SMA)^2)^2 - KURT = length * (sum4/sum2) - -Sources: - https://en.wikipedia.org/wiki/Kurtosis - https://stats.oarc.ucla.edu/other/mult-pkg/faq/general/faq-whats-with-the-different-formulas-for-kurtosis/ - - */ - -public class KURT_Series : Single_TSeries_Indicator -{ - public KURT_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN) - { - this._logbase = logbase; - if (base._data.Count > 0) { base.Add(base._data); } - } - protected double _logbase; - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } - else { this._buffer.Add(TValue.v); } - if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } - - double _n = this._buffer.Count; - - double _avg = 0; - for (int i = 0; i < this._buffer.Count; i++) { _avg += this._buffer[i]; } - _avg /= _n; - - double _s2 = 0; - double _s4 = 0; - for (int i = 0; i < this._buffer.Count; i++) - { - _s2 += (this._buffer[i] - _avg) * (this._buffer[i] - _avg); - _s4 += (this._buffer[i] - _avg) * (this._buffer[i] - _avg) * (this._buffer[i] - _avg) * (this._buffer[i] - _avg); - } - - double _Vx = _s2 / (_n - 1); - double _kurt = (_n > 3) ? ((((_n * (_n + 1)) / (((_n - 1) * (_n - 2)) * (_n - 3))) * (_s4 / (_Vx * _Vx))) - (3 * (((_n - 1) * (_n - 1)) / ((_n - 2) * (_n - 3))))) : Double.NaN; - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? Double.NaN : _kurt); - base.Add(result, update); - } +namespace QuanTAlib; +using System; + +/* +KURT: Kurtosis of population + Kurtosis characterizes the relative peakedness or flatness of a distribution + compared with the normal distribution. Positive kurtosis indicates a relatively + peaked distribution. Negative kurtosis indicates a relatively flat distribution. + + The normal curve is called Mesokurtic curve. If the curve of a distribution is + more outlier prone (or heavier-tailed) than a normal or mesokurtic curve then + it is referred to as a Leptokurtic curve. If a curve is less outlier prone (or + lighter-tailed) than a normal curve, it is called as a platykurtic curve. + +Calculation: + sum4 = Σ(close-SMA)^4 + sum2 = (Σ(close-SMA)^2)^2 + KURT = length * (sum4/sum2) + +Sources: + https://en.wikipedia.org/wiki/Kurtosis + https://stats.oarc.ucla.edu/other/mult-pkg/faq/general/faq-whats-with-the-different-formulas-for-kurtosis/ + + */ + +public class KURT_Series : Single_TSeries_Indicator +{ + public KURT_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN) + { + this._logbase = logbase; + if (base._data.Count > 0) { base.Add(base._data); } + } + protected double _logbase; + private readonly System.Collections.Generic.List _buffer = new(); + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } + else { this._buffer.Add(TValue.v); } + if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } + + double _n = this._buffer.Count; + + double _avg = 0; + for (int i = 0; i < this._buffer.Count; i++) { _avg += this._buffer[i]; } + _avg /= _n; + + double _s2 = 0; + double _s4 = 0; + for (int i = 0; i < this._buffer.Count; i++) + { + _s2 += (this._buffer[i] - _avg) * (this._buffer[i] - _avg); + _s4 += (this._buffer[i] - _avg) * (this._buffer[i] - _avg) * (this._buffer[i] - _avg) * (this._buffer[i] - _avg); + } + + double _Vx = _s2 / (_n - 1); + double _kurt = (_n > 3) ? ((((_n * (_n + 1)) / (((_n - 1) * (_n - 2)) * (_n - 3))) * (_s4 / (_Vx * _Vx))) - (3 * (((_n - 1) * (_n - 1)) / ((_n - 2) * (_n - 3))))) : Double.NaN; + + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? Double.NaN : _kurt); + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Statistics/MED_Series.cs b/Source/Statistics/MED_Series.cs index 8ea91d58..bf5e6586 100644 --- a/Source/Statistics/MED_Series.cs +++ b/Source/Statistics/MED_Series.cs @@ -1,47 +1,47 @@ -namespace QuanTAlib; -using System; - -/* -MED - Median value - Median of numbers is the middlemost value of the given set of numbers. - It separates the higher half and the lower half of a given data sample. - At least half of the observations are smaller than or equal to median - and at least half of the observations are greater than or equal to the median. - - If the number of values is odd, the middlemost observation of the sorted - list is the median of the given data. If the number of values is even, - median is the average of (n/2)th and [(n/2) + 1]th values of the sorted list. - - If period = 0 => period is max - -Sources: - https://corporatefinanceinstitute.com/resources/knowledge/other/median/ - https://en.wikipedia.org/wiki/Median - - */ - -public class MED_Series : Single_TSeries_Indicator -{ - public MED_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) { this._buffer[this._buffer.Count - 1] = TValue.v; } - else { this._buffer.Add(TValue.v); } - if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } - - System.Collections.Generic.List _s = new(this._buffer); - _s.Sort(); - int _p1 = _s.Count / 2; - int _p2 = Math.Max(0, (_s.Count / 2) - 1); - double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2; - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _med); - - base.Add(result, update); - } -} +namespace QuanTAlib; +using System; + +/* +MED - Median value + Median of numbers is the middlemost value of the given set of numbers. + It separates the higher half and the lower half of a given data sample. + At least half of the observations are smaller than or equal to median + and at least half of the observations are greater than or equal to the median. + + If the number of values is odd, the middlemost observation of the sorted + list is the median of the given data. If the number of values is even, + median is the average of (n/2)th and [(n/2) + 1]th values of the sorted list. + + If period = 0 => period is max + +Sources: + https://corporatefinanceinstitute.com/resources/knowledge/other/median/ + https://en.wikipedia.org/wiki/Median + + */ + +public class MED_Series : Single_TSeries_Indicator +{ + public MED_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) { this._buffer[this._buffer.Count - 1] = TValue.v; } + else { this._buffer.Add(TValue.v); } + if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } + + System.Collections.Generic.List _s = new(this._buffer); + _s.Sort(); + int _p1 = _s.Count / 2; + int _p2 = Math.Max(0, (_s.Count / 2) - 1); + double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2; + + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _med); + + base.Add(result, update); + } +} diff --git a/Source/Statistics/SVAR_Series.cs b/Source/Statistics/SVAR_Series.cs index 3d149809..56f6d733 100644 --- a/Source/Statistics/SVAR_Series.cs +++ b/Source/Statistics/SVAR_Series.cs @@ -1,43 +1,43 @@ -namespace QuanTAlib; -using System; - -/* -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) - { - if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } - else { this._buffer.Add(TValue.v); } - if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } - - double _sma = 0; - for (int i = 0; i < this._buffer.Count; i++) { _sma += this._buffer[i]; } - _sma /= this._buffer.Count; - - double _svar = 0; - for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); } - _svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _svar); - base.Add(result, update); - } +namespace QuanTAlib; +using System; + +/* +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) + { + if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } + else { this._buffer.Add(TValue.v); } + if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } + + double _sma = 0; + for (int i = 0; i < this._buffer.Count; i++) { _sma += this._buffer[i]; } + _sma /= this._buffer.Count; + + double _svar = 0; + for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); } + _svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction + + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _svar); + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Statistics/VAR_Series.cs b/Source/Statistics/VAR_Series.cs index 929e8ea7..9c3b3e63 100644 --- a/Source/Statistics/VAR_Series.cs +++ b/Source/Statistics/VAR_Series.cs @@ -1,43 +1,43 @@ -namespace QuanTAlib; -using System; - -/* -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) - { - 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 _sma = 0; - for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } - _sma /= this._buffer.Count; - - double _pvar = 0; - for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } - _pvar /= this._buffer.Count; - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _pvar); - base.Add(result, update); - } +namespace QuanTAlib; +using System; + +/* +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) + { + 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 _sma = 0; + for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } + _sma /= this._buffer.Count; + + double _pvar = 0; + for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _pvar /= this._buffer.Count; + + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _pvar); + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Trends/ALMA_Series.cs b/Source/Trends/ALMA_Series.cs index ab3f4593..82072d68 100644 --- a/Source/Trends/ALMA_Series.cs +++ b/Source/Trends/ALMA_Series.cs @@ -1,65 +1,65 @@ -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/ - - */ - -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) - { - if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } - else { this._buffer.Add(TValue.v); } - if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } - - if (this._buffer.Count <= _p) { calc_weights(); } - - double _weightedSum = 0; - for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; } - double _alma = _weightedSum / _norm; - - var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _alma); - base.Add(ret, update); - } - - private void calc_weights() - { - 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; - } - } -} +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/ + + */ + +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) + { + if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } + else { this._buffer.Add(TValue.v); } + if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } + + if (this._buffer.Count <= _p) { calc_weights(); } + + double _weightedSum = 0; + for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; } + double _alma = _weightedSum / _norm; + + var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _alma); + base.Add(ret, update); + } + + private void calc_weights() + { + 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; + } + } +} diff --git a/Source/Trends/DEMA_Series.cs b/Source/Trends/DEMA_Series.cs index d27fc288..5832b8eb 100644 --- a/Source/Trends/DEMA_Series.cs +++ b/Source/Trends/DEMA_Series.cs @@ -1,71 +1,71 @@ -namespace QuanTAlib; -using System; - -/* -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 System.Collections.Generic.List _buffer = new(); - private readonly double _k, _k1m; - private double _lastema1, _lastlastema1; - private double _lastema2, _lastlastema2; - - public DEMA_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; - } - - double _ema1, _ema2; - - if (this.Count < this._p) - { - if (update) { _buffer[_buffer.Count - 1] = TValue.v; } - else - { - _buffer.Add(TValue.v); - } - if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } - - double _sma = 0; - for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } - _sma /= this._buffer.Count; - _ema1 = _ema2 = _sma; - } - else - { - _ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m); - _ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m); - } - - double _dema = (2 * _ema1) - _ema2; - this._lastlastema1 = this._lastema1; - this._lastlastema2 = this._lastema2; - this._lastema1 = _ema1; - this._lastema2 = _ema2; - - var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _dema); - base.Add(ret, update); - } -} +namespace QuanTAlib; +using System; + +/* +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 System.Collections.Generic.List _buffer = new(); + private readonly double _k, _k1m; + private double _lastema1, _lastlastema1; + private double _lastema2, _lastlastema2; + + public DEMA_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; + } + + double _ema1, _ema2; + + if (this.Count < this._p) + { + if (update) { _buffer[_buffer.Count - 1] = TValue.v; } + else + { + _buffer.Add(TValue.v); + } + if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } + + double _sma = 0; + for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } + _sma /= this._buffer.Count; + _ema1 = _ema2 = _sma; + } + else + { + _ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m); + _ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m); + } + + double _dema = (2 * _ema1) - _ema2; + this._lastlastema1 = this._lastema1; + this._lastlastema2 = this._lastema2; + this._lastema1 = _ema1; + this._lastema2 = _ema2; + + var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _dema); + base.Add(ret, update); + } +} diff --git a/Source/Trends/EMA_Series.cs b/Source/Trends/EMA_Series.cs index 62256fae..b3be32e4 100644 --- a/Source/Trends/EMA_Series.cs +++ b/Source/Trends/EMA_Series.cs @@ -1,64 +1,64 @@ -namespace QuanTAlib; -using System; - -/* -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 readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k, _k1m; - private double _lastema, _lastlastema; - - public EMA_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; - this._lastema = this._lastlastema = double.NaN; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - double _ema = 0; - if (update) { this._lastema = this._lastlastema; } - - if (this.Count < this._p) - { - if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } - else - { - this._buffer.Add(TValue.v); - } - if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } - - for (int i = 0; i < this._buffer.Count; i++) { _ema += this._buffer[i]; } - _ema /= this._buffer.Count; - } - else - { - _ema = (TValue.v * this._k) + (this._lastema * this._k1m); - } - - this._lastlastema = this._lastema; - this._lastema = _ema; - - var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); - base.Add(ret, update); - } +namespace QuanTAlib; +using System; + +/* +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 readonly System.Collections.Generic.List _buffer = new(); + private readonly double _k, _k1m; + private double _lastema, _lastlastema; + + public EMA_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; + this._lastema = this._lastlastema = double.NaN; + if (this._data.Count > 0) { base.Add(this._data); } + } + + public override void Add((DateTime t, double v) TValue, bool update) + { + double _ema = 0; + if (update) { this._lastema = this._lastlastema; } + + if (this.Count < this._p) + { + if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } + else + { + this._buffer.Add(TValue.v); + } + if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } + + for (int i = 0; i < this._buffer.Count; i++) { _ema += this._buffer[i]; } + _ema /= this._buffer.Count; + } + else + { + _ema = (TValue.v * this._k) + (this._lastema * this._k1m); + } + + this._lastlastema = this._lastema; + this._lastema = _ema; + + var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); + base.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/Trends/HEMA_Series.cs b/Source/Trends/HEMA_Series.cs index 65feba14..0ec45cf7 100644 --- a/Source/Trends/HEMA_Series.cs +++ b/Source/Trends/HEMA_Series.cs @@ -1,65 +1,65 @@ -namespace QuanTAlib; -using System; - -/* -HEMA: Hull-EMA Moving Average - Modified HUll Moving Average; instead of using WMA (Weighted MA) for acalculation, - 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; - - (System.DateTime t, double v) result = - (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _ema3); - base.Add(result, update); - } +namespace QuanTAlib; +using System; + +/* +HEMA: Hull-EMA Moving Average + Modified HUll Moving Average; instead of using WMA (Weighted MA) for acalculation, + 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; + + (System.DateTime t, double v) result = + (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _ema3); + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Trends/HMA_Series.cs b/Source/Trends/HMA_Series.cs index 4b36c0b8..b8acb657 100644 --- a/Source/Trends/HMA_Series.cs +++ b/Source/Trends/HMA_Series.cs @@ -1,120 +1,120 @@ -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/JMA_Series.cs b/Source/Trends/JMA_Series.cs index 7cd05316..b180d79d 100644 --- a/Source/Trends/JMA_Series.cs +++ b/Source/Trends/JMA_Series.cs @@ -1,161 +1,161 @@ -namespace QuanTAlib; -using System; - -/* -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. - - -TODO: buggy - rework -*/ - -public class JMA_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List vbuffer10; - private readonly System.Collections.Generic.List vsum65; - - private double prev_ma1, prev_det0, prev_det1, prev_jma, bsmax, bsmin; - private double o_prev_ma1, o_prev_det0, o_prev_det1, o_prev_jma, o_bsmax, o_bsmin; - - private readonly double pr, pow1, len2, beta, rvolty; - - public JMA_Series(TSeries source, int period, double phase = 0.0, bool useNaN = false) : base(source, period, useNaN) - { - this.vbuffer10 = new(); - this.vsum65 = new(); - - // constants - this.pr = (phase < -100) ? 0.5 : (phase > 100) ? 2.5 : (phase * 0.01) + 1.5; - double len1 = Math.Max((Math.Log(Math.Sqrt(0.5 * (_p - 1))) / Math.Log(2.0)) + 2.0, 0); - this.pow1 = Math.Max(len1 - 2, 0.5); - this.rvolty = Math.Exp((1 / this.pow1) * Math.Log(len1)); - this.len2 = Math.Sqrt(0.5 * (_p - 1)) * len1; - this.beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2); - 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) - { - this.prev_ma1 = this.prev_jma = TValue.v; - this.bsmax = this.bsmin = this.prev_det0 = this.prev_det1 = 0; - } - - if (update) - { - this.prev_jma = this.o_prev_jma; - this.prev_ma1 = this.o_prev_ma1; - this.prev_det0 = this.o_prev_det0; - this.prev_det1 = this.o_prev_det1; - this.bsmax = this.o_bsmax; - this.bsmin = this.o_bsmin; - } - else - { - this.o_prev_jma = this.prev_jma; - this.o_prev_ma1 = this.prev_ma1; - this.o_prev_det0 = this.prev_det0; - this.o_prev_det1 = this.prev_det1; - this.o_bsmax = this.bsmax; - this.o_bsmin = this.bsmin; - } - - double hprice = TValue.v; - double lprice = TValue.v; - for (int i = 0; i <= Math.Min(9, this._data.Count - 1); i++) - { - var _item = this._data[this._data.Count - 1 - i].v; - hprice = (_item > hprice) ? _item : hprice; - lprice = (_item < lprice) ? _item : lprice; - } - double del1 = hprice - this.bsmax; - double del2 = lprice - this.bsmin; - - double volty = (Math.Abs(del1) != Math.Abs(del2)) - ? Math.Max(Math.Abs(del1), Math.Abs(del2)) - : 0; - if (update) - { - this.vbuffer10[this.vbuffer10.Count - 1] = volty; - } - else - { - this.vbuffer10.Add(volty); - } - if (this.vbuffer10.Count > 10) - { - this.vbuffer10.RemoveAt(0); - } - - double prevvsum = - (this.vsum65.Count > 0) ? this.vsum65[this.vsum65.Count - 1] : 0; - double vsumitem = prevvsum + 0.1 * (volty - this.vbuffer10[0]); - if (update) - { - this.vsum65[this.vsum65.Count - 1] = vsumitem; - } - else - { - this.vsum65.Add(vsumitem); - } - if (this.vsum65.Count > 65) - { - this.vsum65.RemoveAt(0); - } - - double avolty = 0; - for (int i = 0; i < this.vsum65.Count; i++) - { - avolty += this.vsum65[i]; - } - - avolty /= this.vsum65.Count; - double dvolty = (avolty > 0) ? volty / avolty : 0; - dvolty = Math.Max((dvolty > this.rvolty) ? this.rvolty : dvolty, 1.0); - - double pow2 = Math.Exp(this.pow1 * Math.Log(dvolty)); - double kv = - Math.Exp(Math.Sqrt(pow2) * Math.Log(this.len2 / (this.len2 + 1))); - - this.bsmax = (del1 > 0) ? hprice : hprice - (kv * del1); - this.bsmin = (del2 < 0) ? lprice : lprice - (kv * del2); - - // adaptive EMA dynamic factor - double pow = Math.Pow(dvolty, this.pow1); - double alpha = Math.Pow(this.beta, pow); - - // 1st stage - preliminary smoothing by adaptive EMA - double ma1 = TValue.v * (1 - alpha) + this.prev_ma1 * alpha; - this.prev_ma1 = ma1; - - // 2nd stage - one more preliminary smoothing by Kalman filter - double det0 = (TValue.v - ma1) * (1 - this.beta) + this.prev_det0 * this.beta; - this.prev_det0 = det0; - double ma2 = ma1 + (this.pr * det0); - - // 3rd stage - final smoothing by Jurik adaptive filter - double det1 = ((ma2 - this.prev_jma) * (1 - alpha) * (1 - alpha)) + - (this.prev_det1 * alpha * alpha); - this.prev_det1 = det1; - var jma = this.prev_jma + det1; - this.prev_jma = jma; - - (System.DateTime t, double v) result = - (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : jma); - base.Add(result, update); - - } +namespace QuanTAlib; +using System; + +/* +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. + + +TODO: buggy - rework +*/ + +public class JMA_Series : Single_TSeries_Indicator +{ + private readonly System.Collections.Generic.List vbuffer10; + private readonly System.Collections.Generic.List vsum65; + + private double prev_ma1, prev_det0, prev_det1, prev_jma, bsmax, bsmin; + private double o_prev_ma1, o_prev_det0, o_prev_det1, o_prev_jma, o_bsmax, o_bsmin; + + private readonly double pr, pow1, len2, beta, rvolty; + + public JMA_Series(TSeries source, int period, double phase = 0.0, bool useNaN = false) : base(source, period, useNaN) + { + this.vbuffer10 = new(); + this.vsum65 = new(); + + // constants + this.pr = (phase < -100) ? 0.5 : (phase > 100) ? 2.5 : (phase * 0.01) + 1.5; + double len1 = Math.Max((Math.Log(Math.Sqrt(0.5 * (_p - 1))) / Math.Log(2.0)) + 2.0, 0); + this.pow1 = Math.Max(len1 - 2, 0.5); + this.rvolty = Math.Exp((1 / this.pow1) * Math.Log(len1)); + this.len2 = Math.Sqrt(0.5 * (_p - 1)) * len1; + this.beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2); + 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) + { + this.prev_ma1 = this.prev_jma = TValue.v; + this.bsmax = this.bsmin = this.prev_det0 = this.prev_det1 = 0; + } + + if (update) + { + this.prev_jma = this.o_prev_jma; + this.prev_ma1 = this.o_prev_ma1; + this.prev_det0 = this.o_prev_det0; + this.prev_det1 = this.o_prev_det1; + this.bsmax = this.o_bsmax; + this.bsmin = this.o_bsmin; + } + else + { + this.o_prev_jma = this.prev_jma; + this.o_prev_ma1 = this.prev_ma1; + this.o_prev_det0 = this.prev_det0; + this.o_prev_det1 = this.prev_det1; + this.o_bsmax = this.bsmax; + this.o_bsmin = this.bsmin; + } + + double hprice = TValue.v; + double lprice = TValue.v; + for (int i = 0; i <= Math.Min(9, this._data.Count - 1); i++) + { + var _item = this._data[this._data.Count - 1 - i].v; + hprice = (_item > hprice) ? _item : hprice; + lprice = (_item < lprice) ? _item : lprice; + } + double del1 = hprice - this.bsmax; + double del2 = lprice - this.bsmin; + + double volty = (Math.Abs(del1) != Math.Abs(del2)) + ? Math.Max(Math.Abs(del1), Math.Abs(del2)) + : 0; + if (update) + { + this.vbuffer10[this.vbuffer10.Count - 1] = volty; + } + else + { + this.vbuffer10.Add(volty); + } + if (this.vbuffer10.Count > 10) + { + this.vbuffer10.RemoveAt(0); + } + + double prevvsum = + (this.vsum65.Count > 0) ? this.vsum65[this.vsum65.Count - 1] : 0; + double vsumitem = prevvsum + 0.1 * (volty - this.vbuffer10[0]); + if (update) + { + this.vsum65[this.vsum65.Count - 1] = vsumitem; + } + else + { + this.vsum65.Add(vsumitem); + } + if (this.vsum65.Count > 65) + { + this.vsum65.RemoveAt(0); + } + + double avolty = 0; + for (int i = 0; i < this.vsum65.Count; i++) + { + avolty += this.vsum65[i]; + } + + avolty /= this.vsum65.Count; + double dvolty = (avolty > 0) ? volty / avolty : 0; + dvolty = Math.Max((dvolty > this.rvolty) ? this.rvolty : dvolty, 1.0); + + double pow2 = Math.Exp(this.pow1 * Math.Log(dvolty)); + double kv = + Math.Exp(Math.Sqrt(pow2) * Math.Log(this.len2 / (this.len2 + 1))); + + this.bsmax = (del1 > 0) ? hprice : hprice - (kv * del1); + this.bsmin = (del2 < 0) ? lprice : lprice - (kv * del2); + + // adaptive EMA dynamic factor + double pow = Math.Pow(dvolty, this.pow1); + double alpha = Math.Pow(this.beta, pow); + + // 1st stage - preliminary smoothing by adaptive EMA + double ma1 = TValue.v * (1 - alpha) + this.prev_ma1 * alpha; + this.prev_ma1 = ma1; + + // 2nd stage - one more preliminary smoothing by Kalman filter + double det0 = (TValue.v - ma1) * (1 - this.beta) + this.prev_det0 * this.beta; + this.prev_det0 = det0; + double ma2 = ma1 + (this.pr * det0); + + // 3rd stage - final smoothing by Jurik adaptive filter + double det1 = ((ma2 - this.prev_jma) * (1 - alpha) * (1 - alpha)) + + (this.prev_det1 * alpha * alpha); + this.prev_det1 = det1; + var jma = this.prev_jma + det1; + this.prev_jma = jma; + + (System.DateTime t, double v) result = + (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : jma); + base.Add(result, update); + + } } \ No newline at end of file diff --git a/Source/Trends/KAMA_Series.cs b/Source/Trends/KAMA_Series.cs index f27d08cd..2f46e25d 100644 --- a/Source/Trends/KAMA_Series.cs +++ b/Source/Trends/KAMA_Series.cs @@ -1,65 +1,65 @@ -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; - this._lastkama = this._lastlastkama; - } else { - _buffer.Add(TValue.v); - } - if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); } - double _kama = 0; - if (this.Count < this._p) { - for (int i = 0; i < this._buffer.Count; i++) { _kama += this._buffer[i]; } - _kama /= this._buffer.Count; - } 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))); - } - _lastlastkama = _lastkama; - _lastkama = _kama; - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _kama); - base.Add(result, update); - } +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; + this._lastkama = this._lastlastkama; + } else { + _buffer.Add(TValue.v); + } + if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); } + double _kama = 0; + if (this.Count < this._p) { + for (int i = 0; i < this._buffer.Count; i++) { _kama += this._buffer[i]; } + _kama /= this._buffer.Count; + } 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))); + } + _lastlastkama = _lastkama; + _lastkama = _kama; + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _kama); + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Trends/MACD_Series.cs b/Source/Trends/MACD_Series.cs index b8172d46..1050cd1f 100644 --- a/Source/Trends/MACD_Series.cs +++ b/Source/Trends/MACD_Series.cs @@ -1,46 +1,46 @@ -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; - var result = (TValue.t, _macd); - base.Add(result, update); - } +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; + var result = (TValue.t, _macd); + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Trends/RMA_Series.cs b/Source/Trends/RMA_Series.cs index a93accc1..66009437 100644 --- a/Source/Trends/RMA_Series.cs +++ b/Source/Trends/RMA_Series.cs @@ -1,63 +1,63 @@ -namespace QuanTAlib; -using System; - -/* -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 = 0; - if (update) { this._lastema = this._lastlastema; } - - if (this.Count < this._p) - { - if (update) { _buffer[_buffer.Count - 1] = TValue.v; } - else - { - _buffer.Add(TValue.v); - } - if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } - - for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } - _ema /= this._buffer.Count; - } - else - { - _ema = (TValue.v * _k) + (_lastema * _k1m); - } - - this._lastlastema = this._lastema; - this._lastema = _ema; - - var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); - base.Add(ret, update); - } +namespace QuanTAlib; +using System; + +/* +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 = 0; + if (update) { this._lastema = this._lastlastema; } + + if (this.Count < this._p) + { + if (update) { _buffer[_buffer.Count - 1] = TValue.v; } + else + { + _buffer.Add(TValue.v); + } + if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } + + for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } + _ema /= this._buffer.Count; + } + else + { + _ema = (TValue.v * _k) + (_lastema * _k1m); + } + + this._lastlastema = this._lastema; + this._lastema = _ema; + + var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); + base.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/Trends/SMA_Series.cs b/Source/Trends/SMA_Series.cs index 032c15b5..6bbeb1fb 100644 --- a/Source/Trends/SMA_Series.cs +++ b/Source/Trends/SMA_Series.cs @@ -1,41 +1,41 @@ -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 -{ - public SMA_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 _sma = 0; - for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } - _sma /= this._buffer.Count; - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _sma); - - base.Add(result, update); - } -} +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 +{ + public SMA_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 _sma = 0; + for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } + _sma /= this._buffer.Count; + + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _sma); + + base.Add(result, update); + } +} diff --git a/Source/Trends/SMMA_Series.cs b/Source/Trends/SMMA_Series.cs index 7bcec3d8..2f31e824 100644 --- a/Source/Trends/SMMA_Series.cs +++ b/Source/Trends/SMMA_Series.cs @@ -1,58 +1,58 @@ -namespace QuanTAlib; -using System; - -/* -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) - { - if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } - else - { - this._buffer.Add(TValue.v); - } - if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } - - for (int i = 0; i < this._buffer.Count; i++) { _smma += this._buffer[i]; } - _smma /= this._buffer.Count; - } - else - { - _smma = ((_lastsmma * (_p-1)) + TValue.v) / _p ; - } - - this._lastlastsmma = this._lastsmma; - this._lastsmma = _smma; - - var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _smma); - base.Add(ret, update); - } +namespace QuanTAlib; +using System; + +/* +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) + { + if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } + else + { + this._buffer.Add(TValue.v); + } + if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } + + for (int i = 0; i < this._buffer.Count; i++) { _smma += this._buffer[i]; } + _smma /= this._buffer.Count; + } + else + { + _smma = ((_lastsmma * (_p-1)) + TValue.v) / _p ; + } + + this._lastlastsmma = this._lastsmma; + this._lastsmma = _smma; + + var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _smma); + base.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/Trends/TEMA_Series.cs b/Source/Trends/TEMA_Series.cs index 90aacfe2..ba61d6a0 100644 --- a/Source/Trends/TEMA_Series.cs +++ b/Source/Trends/TEMA_Series.cs @@ -1,78 +1,78 @@ -namespace QuanTAlib; -using System; - -/* -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) - { - if (update) { _buffer[_buffer.Count - 1] = TValue.v; } - else - { - _buffer.Add(TValue.v); - } - if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } - - double _sma = 0; - for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } - _sma /= this._buffer.Count; - _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; - - var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _tema); - base.Add(ret, update); - } +namespace QuanTAlib; +using System; + +/* +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) + { + if (update) { _buffer[_buffer.Count - 1] = TValue.v; } + else + { + _buffer.Add(TValue.v); + } + if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } + + double _sma = 0; + for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } + _sma /= this._buffer.Count; + _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; + + var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _tema); + base.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/Trends/TRIMA_Series.cs b/Source/Trends/TRIMA_Series.cs index 78304982..e0fe6e9b 100644 --- a/Source/Trends/TRIMA_Series.cs +++ b/Source/Trends/TRIMA_Series.cs @@ -1,49 +1,49 @@ -namespace QuanTAlib; -using System; - -/* -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 = 0; - for (int i = 0; i < _buffer1.Count; i++) { _sma1 += _buffer1[i]; } - _sma1 /= this._buffer1.Count; - - if (update) { _buffer2[_buffer2.Count - 1] = _sma1; } else { _buffer2.Add(_sma1); } - if (_buffer2.Count > this._p1a && this._p1a != 0) { _buffer2.RemoveAt(0); } - - double _trima = 0; - for (int i = 0; i < _buffer2.Count; i++) { _trima += _buffer2[i]; } - _trima /= this._buffer2.Count; - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _trima); - base.Add(result, update); - } +namespace QuanTAlib; +using System; + +/* +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 = 0; + for (int i = 0; i < _buffer1.Count; i++) { _sma1 += _buffer1[i]; } + _sma1 /= this._buffer1.Count; + + if (update) { _buffer2[_buffer2.Count - 1] = _sma1; } else { _buffer2.Add(_sma1); } + if (_buffer2.Count > this._p1a && this._p1a != 0) { _buffer2.RemoveAt(0); } + + double _trima = 0; + for (int i = 0; i < _buffer2.Count; i++) { _trima += _buffer2[i]; } + _trima /= this._buffer2.Count; + + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _trima); + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Trends/WMA_Series.cs b/Source/Trends/WMA_Series.cs index 0c8b51ed..6b182741 100644 --- a/Source/Trends/WMA_Series.cs +++ b/Source/Trends/WMA_Series.cs @@ -1,39 +1,39 @@ -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) - { - 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 _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; - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _wma); - - base.Add(result, update); - } +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) + { + 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 _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; + + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _wma); + + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Trends/ZLEMA_Series.cs b/Source/Trends/ZLEMA_Series.cs index fdc53877..ae4fef30 100644 --- a/Source/Trends/ZLEMA_Series.cs +++ b/Source/Trends/ZLEMA_Series.cs @@ -1,72 +1,72 @@ -namespace QuanTAlib; -using System; - -/* -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, _lastlastema; - - public ZLEMA_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; - this._lastema = this._lastlastema = double.NaN; - if (base._data.Count > 0) - { base.Add(base._data); } - } - - public override void Add((System.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); - - double _ema = 0; - if (update) - { this._lastema = this._lastlastema; } - if (this.Count < this._p) - { - if (update) - { this._buffer[this._buffer.Count - 1] = _zl; } - else - { - this._buffer.Add(_zl); - } - if (this._buffer.Count > this._p) - { this._buffer.RemoveAt(0); } - - for (int i = 0; i < this._buffer.Count; i++) - { _ema += this._buffer[i]; } - _ema /= this._buffer.Count; - } - else - { - _ema = (_zl * this._k) + (this._lastema * this._k1m); - } - - this._lastlastema = this._lastema; - this._lastema = _ema; - - var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); - base.Add(ret, update); - } +namespace QuanTAlib; +using System; + +/* +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, _lastlastema; + + public ZLEMA_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; + this._lastema = this._lastlastema = double.NaN; + if (base._data.Count > 0) + { base.Add(base._data); } + } + + public override void Add((System.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); + + double _ema = 0; + if (update) + { this._lastema = this._lastlastema; } + if (this.Count < this._p) + { + if (update) + { this._buffer[this._buffer.Count - 1] = _zl; } + else + { + this._buffer.Add(_zl); + } + if (this._buffer.Count > this._p) + { this._buffer.RemoveAt(0); } + + for (int i = 0; i < this._buffer.Count; i++) + { _ema += this._buffer[i]; } + _ema /= this._buffer.Count; + } + else + { + _ema = (_zl * this._k) + (this._lastema * this._k1m); + } + + this._lastlastema = this._lastema; + this._lastema = _ema; + + var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); + base.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/Volatility/ADL_Series.cs b/Source/Volatility/ADL_Series.cs index 15822ba5..c2ae0cc4 100644 --- a/Source/Volatility/ADL_Series.cs +++ b/Source/Volatility/ADL_Series.cs @@ -1,43 +1,43 @@ -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) - { - this._lastadl = this._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 _mfm = ((TBar.c - TBar.l) - (TBar.h - TBar.c)) / (TBar.h - TBar.l); - double _mfv = _mfm * TBar.v; - double _adl = this._lastadl + _mfv; - - this._lastlastadl = this._lastadl; - this._lastadl = _adl; - - var ret = (TBar.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _adl); - base.Add(ret, update); - } +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) + { + this._lastadl = this._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 _mfm = ((TBar.c - TBar.l) - (TBar.h - TBar.c)) / (TBar.h - TBar.l); + double _mfv = _mfm * TBar.v; + double _adl = this._lastadl + _mfv; + + this._lastlastadl = this._lastadl; + this._lastadl = _adl; + + var ret = (TBar.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _adl); + base.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/Volatility/ADOSC_Series.cs b/Source/Volatility/ADOSC_Series.cs index 08c4750a..f8f219d0 100644 --- a/Source/Volatility/ADOSC_Series.cs +++ b/Source/Volatility/ADOSC_Series.cs @@ -1,45 +1,45 @@ -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 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 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/Source/Volatility/ATRP_Series.cs index 2bb6f1b1..884e92a2 100644 --- a/Source/Volatility/ATRP_Series.cs +++ b/Source/Volatility/ATRP_Series.cs @@ -1,63 +1,63 @@ -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, _k1m; - private double _lastema, _lastlastema, _lastcm1; - private double _cm1 = double.NaN; - - public ATRP_Series(TBars 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 (_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._lastema = this._lastlastema; - this._cm1 = this._lastcm1; - } - - if (_cm1 is double.NaN) { _cm1 = TBar.c; } - double d1 = Math.Abs(TBar.h - TBar.l); - double d2 = Math.Abs(_cm1 - TBar.h); - double d3 = Math.Abs(_cm1 - TBar.l); - (DateTime t, double v)d = (TBar.t, Math.Max(d1,Math.Max(d2,d3))); //TR value for RMA below - _lastcm1 = _cm1; - _cm1 = TBar.c; - - double _ema = 0; - if (this.Count < this._p) - { - if (update) { _buffer[_buffer.Count - 1] = d.v; } - else { _buffer.Add(d.v); } - if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } - for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } - _ema /= this._buffer.Count; - } - else { _ema = (d.v * _k) + (_lastema * _k1m); } - - this._lastlastema = this._lastema; - this._lastema = _ema; - - double _atrp = 100 * (_ema / 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, _k1m; + private double _lastema, _lastlastema, _lastcm1; + private double _cm1 = double.NaN; + + public ATRP_Series(TBars 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 (_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._lastema = this._lastlastema; + this._cm1 = this._lastcm1; + } + + if (_cm1 is double.NaN) { _cm1 = TBar.c; } + double d1 = Math.Abs(TBar.h - TBar.l); + double d2 = Math.Abs(_cm1 - TBar.h); + double d3 = Math.Abs(_cm1 - TBar.l); + (DateTime t, double v)d = (TBar.t, Math.Max(d1,Math.Max(d2,d3))); //TR value for RMA below + _lastcm1 = _cm1; + _cm1 = TBar.c; + + double _ema = 0; + if (this.Count < this._p) + { + if (update) { _buffer[_buffer.Count - 1] = d.v; } + else { _buffer.Add(d.v); } + if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } + for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } + _ema /= this._buffer.Count; + } + else { _ema = (d.v * _k) + (_lastema * _k1m); } + + this._lastlastema = this._lastema; + this._lastema = _ema; + + double _atrp = 100 * (_ema / TBar.c); + + var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atrp); + base.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/Volatility/ATR_Series.cs b/Source/Volatility/ATR_Series.cs index 75740a1c..365e00e4 100644 --- a/Source/Volatility/ATR_Series.cs +++ b/Source/Volatility/ATR_Series.cs @@ -1,63 +1,63 @@ -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, _k1m; - private double _lastema, _lastlastema, _lastcm1; - private double _cm1 = double.NaN; - - public ATR_Series(TBars 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 (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) { - this._lastema = this._lastlastema; - this._cm1 = this._lastcm1; - } - - if (this._cm1 is double.NaN) { this._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))); //TR value for RMA below - _lastcm1 = _cm1; - _cm1 = TBar.c; - - double _ema = 0; - if (this.Count < this._p) - { - if (update) { _buffer[_buffer.Count - 1] = d.v; } - else { _buffer.Add(d.v); } - if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } - for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } - _ema /= this._buffer.Count; - } - else { _ema = (d.v * _k) + (_lastema * _k1m); } - - this._lastlastema = this._lastema; - this._lastema = _ema; - - var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); - 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, _k1m; + private double _lastema, _lastlastema, _lastcm1; + private double _cm1 = double.NaN; + + public ATR_Series(TBars 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 (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) { + this._lastema = this._lastlastema; + this._cm1 = this._lastcm1; + } + + if (this._cm1 is double.NaN) { this._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))); //TR value for RMA below + _lastcm1 = _cm1; + _cm1 = TBar.c; + + double _ema = 0; + if (this.Count < this._p) + { + if (update) { _buffer[_buffer.Count - 1] = d.v; } + else { _buffer.Add(d.v); } + if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } + for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } + _ema /= this._buffer.Count; + } + else { _ema = (d.v * _k) + (_lastema * _k1m); } + + this._lastlastema = this._lastema; + this._lastema = _ema; + + var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); + base.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/Volatility/BBANDS_Series.cs b/Source/Volatility/BBANDS_Series.cs index 169f8f35..499fba44 100644 --- a/Source/Volatility/BBANDS_Series.cs +++ b/Source/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/RSI_Series.cs b/Source/Volatility/RSI_Series.cs index 5cec4d88..f5717f73 100644 --- a/Source/Volatility/RSI_Series.cs +++ b/Source/Volatility/RSI_Series.cs @@ -1,73 +1,73 @@ -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; - private double _avgLoss; - private double _lastValue; - private double _lastlastValue; - - public RSI_Series(TSeries source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) - { if (source.Count > 0) { base.Add(source); } } - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - int i = this.Count; - double _rsi = 0; - if (update) { _lastValue = _lastlastValue; } - if (i == 0) { _lastValue = TValue.v; } - - double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0; - if (update) { _gain[_gain.Count - 1] = _gainval; } else { _gain.Add(_gainval); } - if (_gain.Count > this._p) { _gain.RemoveAt(0); } - - double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0; - if (update) { _loss[_loss.Count - 1] = _lossval; } else { _loss.Add(_lossval); } - if (_loss.Count > this._p) { _loss.RemoveAt(0); } - - _lastlastValue = _lastValue; - _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; - } - - 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; + private double _avgLoss; + private double _lastValue; + private double _lastlastValue; + + public RSI_Series(TSeries source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) + { if (source.Count > 0) { base.Add(source); } } + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + int i = this.Count; + double _rsi = 0; + if (update) { _lastValue = _lastlastValue; } + if (i == 0) { _lastValue = TValue.v; } + + double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0; + if (update) { _gain[_gain.Count - 1] = _gainval; } else { _gain.Add(_gainval); } + if (_gain.Count > this._p) { _gain.RemoveAt(0); } + + double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0; + if (update) { _loss[_loss.Count - 1] = _lossval; } else { _loss.Add(_lossval); } + if (_loss.Count > this._p) { _loss.RemoveAt(0); } + + _lastlastValue = _lastValue; + _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; + } + + 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/Source/Volume/OBV_Series.cs index 30758e9f..bc4bd3ee 100644 --- a/Source/Volume/OBV_Series.cs +++ b/Source/Volume/OBV_Series.cs @@ -1,62 +1,62 @@ -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; } - - // Unclear what the first value in OBV series is - currently set to volume[0] - // if (this.Count == 0) { _obv = 0; } - - 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; } + + // Unclear what the first value in OBV series is - currently set to volume[0] + // if (this.Count == 0) { _obv = 0; } + + 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/Tests/Basics/Abstract_Test.cs b/Tests/Basics/Abstract_Test.cs index afd51407..b2ffb9a3 100644 --- a/Tests/Basics/Abstract_Test.cs +++ b/Tests/Basics/Abstract_Test.cs @@ -1,23 +1,23 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Basics; -public class Abstract_Test -{ - [Fact] - public void Single_Add_variations() - { - TSeries s = new() { 1,2,3,4,5 }; - SMA_Series a = new(s, 3) - { - { (DateTime.Today, 10), true } - }; - Assert.Equal(s.Length, a.Length); - a.Add(true); - Assert.Equal(s.Length, a.Length); - a.Add(); - Assert.Equal(s.Length+1, a.Length); - } - -} +using Xunit; +using System; +using QuanTAlib; + +namespace Basics; +public class Abstract_Test +{ + [Fact] + public void Single_Add_variations() + { + TSeries s = new() { 1,2,3,4,5 }; + SMA_Series a = new(s, 3) + { + { (DateTime.Today, 10), true } + }; + Assert.Equal(s.Length, a.Length); + a.Add(true); + Assert.Equal(s.Length, a.Length); + a.Add(); + Assert.Equal(s.Length+1, a.Length); + } + +} diff --git a/Tests/Basics/TBars_Test.cs b/Tests/Basics/TBars_Test.cs index c5f869a0..bc49e764 100644 --- a/Tests/Basics/TBars_Test.cs +++ b/Tests/Basics/TBars_Test.cs @@ -1,112 +1,112 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Basics; -public class TBars_Test -{ - [Fact] - public void InsertingTuple() - { - TBars s = new() { (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, c: Double.NegativeInfinity, v: Double.PositiveInfinity) }; - var tup = (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, - c: Double.NegativeInfinity, v: Double.PositiveInfinity); - Assert.Equal(tup, s[^1]); - } - - [Fact] - public void Casting_Parameters() - { - TBars s = new() - { - { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false } - }; - Assert.Equal(0.1, s[^1].o); - Assert.Equal(1.1, s[^1].h); - Assert.Equal(2.1, s[^1].l); - Assert.Equal(3.1, s[^1].c); - Assert.Equal(4.1, s[^1].v); - Assert.Equal(DateTime.Today, s[^1].t); - Assert.Single(s); - } - - [Fact] - public void Updating_Value() - { - TBars s = new() - { - { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 } - }; - s.Add(DateTime.Today, 1.0, 1.0, 1.0, 1.0, 1.0, update: false); - s.Add(DateTime.Today, 0.0, 0.0, 0.0, 0.0, 0.0, update: true); - Assert.Equal(0.0, s[^1].o); - Assert.Equal(0.0, s[^1].h); - Assert.Equal(0.0, s[^1].l); - Assert.Equal(0.0, s[^1].c); - Assert.Equal(0.0, s[^1].v); - Assert.Equal(2, s.Count); - } - [Fact] - public void Extracting_TSeries() - { - TBars s = new() - { - { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 }, - { DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1 } - }; - - TSeries t = s.Open; - Assert.Equal(t.t, s.Open.t); - Assert.Equal(t.v, s.Open.v); - - t = s.High; - Assert.Equal(t.t, s.High.t); - Assert.Equal(t.v, s.High.v); - - t = s.Low; - Assert.Equal(t.t, s.Low.t); - Assert.Equal(t.v, s.Low.v); - - t = s.Close; - Assert.Equal(t.t, s.Close.t); - Assert.Equal(t.v, s.Close.v); - - t = s.Volume; - Assert.Equal(t.t, s.Volume.t); - Assert.Equal(t.v, s.Volume.v); - - t = s.HL2; - Assert.Equal(t.t, s.HL2.t); - Assert.Equal(t.v, s.HL2.v); - - t = s.OC2; - Assert.Equal(t.t, s.OC2.t); - Assert.Equal(t.v, s.OC2.v); - - t = s.OHL3; - Assert.Equal(t.t, s.OHL3.t); - Assert.Equal(t.v, s.OHL3.v); - - t = s.HLC3; - Assert.Equal(t.t, s.HLC3.t); - Assert.Equal(t.v, s.HLC3.v); - - t = s.OHLC4; - Assert.Equal(t.t, s.OHLC4.t); - Assert.Equal(t.v, s.OHLC4.v); - - t = s.HLCC4; - Assert.Equal(t.t, s.HLCC4.t); - Assert.Equal(t.v, s.HLCC4.v); - } - [Fact] - public void Broadcasting_Events() - { - TBars s = new() { (DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1) }; - TSeries t = new(); - s.Close.Pub += t.Sub; - s.Add(DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false); - Assert.Equal(s.Close.v, t.v); - Assert.Equal(s.Close.Count, t.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Basics; +public class TBars_Test +{ + [Fact] + public void InsertingTuple() + { + TBars s = new() { (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, c: Double.NegativeInfinity, v: Double.PositiveInfinity) }; + var tup = (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, + c: Double.NegativeInfinity, v: Double.PositiveInfinity); + Assert.Equal(tup, s[^1]); + } + + [Fact] + public void Casting_Parameters() + { + TBars s = new() + { + { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false } + }; + Assert.Equal(0.1, s[^1].o); + Assert.Equal(1.1, s[^1].h); + Assert.Equal(2.1, s[^1].l); + Assert.Equal(3.1, s[^1].c); + Assert.Equal(4.1, s[^1].v); + Assert.Equal(DateTime.Today, s[^1].t); + Assert.Single(s); + } + + [Fact] + public void Updating_Value() + { + TBars s = new() + { + { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 } + }; + s.Add(DateTime.Today, 1.0, 1.0, 1.0, 1.0, 1.0, update: false); + s.Add(DateTime.Today, 0.0, 0.0, 0.0, 0.0, 0.0, update: true); + Assert.Equal(0.0, s[^1].o); + Assert.Equal(0.0, s[^1].h); + Assert.Equal(0.0, s[^1].l); + Assert.Equal(0.0, s[^1].c); + Assert.Equal(0.0, s[^1].v); + Assert.Equal(2, s.Count); + } + [Fact] + public void Extracting_TSeries() + { + TBars s = new() + { + { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 }, + { DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1 } + }; + + TSeries t = s.Open; + Assert.Equal(t.t, s.Open.t); + Assert.Equal(t.v, s.Open.v); + + t = s.High; + Assert.Equal(t.t, s.High.t); + Assert.Equal(t.v, s.High.v); + + t = s.Low; + Assert.Equal(t.t, s.Low.t); + Assert.Equal(t.v, s.Low.v); + + t = s.Close; + Assert.Equal(t.t, s.Close.t); + Assert.Equal(t.v, s.Close.v); + + t = s.Volume; + Assert.Equal(t.t, s.Volume.t); + Assert.Equal(t.v, s.Volume.v); + + t = s.HL2; + Assert.Equal(t.t, s.HL2.t); + Assert.Equal(t.v, s.HL2.v); + + t = s.OC2; + Assert.Equal(t.t, s.OC2.t); + Assert.Equal(t.v, s.OC2.v); + + t = s.OHL3; + Assert.Equal(t.t, s.OHL3.t); + Assert.Equal(t.v, s.OHL3.v); + + t = s.HLC3; + Assert.Equal(t.t, s.HLC3.t); + Assert.Equal(t.v, s.HLC3.v); + + t = s.OHLC4; + Assert.Equal(t.t, s.OHLC4.t); + Assert.Equal(t.v, s.OHLC4.v); + + t = s.HLCC4; + Assert.Equal(t.t, s.HLCC4.t); + Assert.Equal(t.v, s.HLCC4.v); + } + [Fact] + public void Broadcasting_Events() + { + TBars s = new() { (DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1) }; + TSeries t = new(); + s.Close.Pub += t.Sub; + s.Add(DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false); + Assert.Equal(s.Close.v, t.v); + Assert.Equal(s.Close.Count, t.Count); + } +} diff --git a/Tests/Basics/TSeries_Test.cs b/Tests/Basics/TSeries_Test.cs index 32357071..84bf9d42 100644 --- a/Tests/Basics/TSeries_Test.cs +++ b/Tests/Basics/TSeries_Test.cs @@ -1,61 +1,61 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Basics; -public class TSeries_Test -{ - [Fact] - public void InsertingTuple() - { - TSeries s = new() { (t: DateTime.Today, v: double.Epsilon) }; - Assert.Equal((DateTime.Today, double.Epsilon), s); - } - - [Fact] - public void CastingTwoParameters() - { - TSeries s = new() - { - { DateTime.Today, 0.0 } - }; - Assert.Equal(0.0, s[s.Count - 1].v); - Assert.Equal(DateTime.Today, s[s.Count - 1].t); - } - - [Fact] - public void CastingOneParameter() - { - TSeries s = new() - { - double.PositiveInfinity - }; - Assert.Equal(double.PositiveInfinity, (double)s); - } - - [Fact] - public void UpdatingValue() - { - TSeries s = new() { 1, 2, 3, 4, 5 }; - s.Add(0.0, update: true); - Assert.Equal(0.0, (double)s); - Assert.Equal(5, s.Count); - } - [Fact] - public void ReflectingSeries() - { - TSeries s = new() { 1, 2, 3, 4, 5 }; - TSeries t = s; - Assert.Equal(5, (double)t); - Assert.Equal(5, t.Count); - } - [Fact] - public void BroadcastingEvents() - { - TSeries s = new() { 1, 2, 3, 4, 5 }; - TSeries t = new(); - s.Pub += t.Sub; - s.Add(0.0, update: true); - Assert.Equal(0.0, (double)t); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Basics; +public class TSeries_Test +{ + [Fact] + public void InsertingTuple() + { + TSeries s = new() { (t: DateTime.Today, v: double.Epsilon) }; + Assert.Equal((DateTime.Today, double.Epsilon), s); + } + + [Fact] + public void CastingTwoParameters() + { + TSeries s = new() + { + { DateTime.Today, 0.0 } + }; + Assert.Equal(0.0, s[s.Count - 1].v); + Assert.Equal(DateTime.Today, s[s.Count - 1].t); + } + + [Fact] + public void CastingOneParameter() + { + TSeries s = new() + { + double.PositiveInfinity + }; + Assert.Equal(double.PositiveInfinity, (double)s); + } + + [Fact] + public void UpdatingValue() + { + TSeries s = new() { 1, 2, 3, 4, 5 }; + s.Add(0.0, update: true); + Assert.Equal(0.0, (double)s); + Assert.Equal(5, s.Count); + } + [Fact] + public void ReflectingSeries() + { + TSeries s = new() { 1, 2, 3, 4, 5 }; + TSeries t = s; + Assert.Equal(5, (double)t); + Assert.Equal(5, t.Count); + } + [Fact] + public void BroadcastingEvents() + { + TSeries s = new() { 1, 2, 3, 4, 5 }; + TSeries t = new(); + s.Pub += t.Sub; + s.Add(0.0, update: true); + Assert.Equal(0.0, (double)t); + } +} diff --git a/Tests/MovingAvg/ALMA_Test.cs b/Tests/MovingAvg/ALMA_Test.cs index 75ac5eed..b0b2c297 100644 --- a/Tests/MovingAvg/ALMA_Test.cs +++ b/Tests/MovingAvg/ALMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class ALMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - ALMA_Series c = new(a, 4); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(10, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - ALMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class ALMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + ALMA_Series c = new(a, 4); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(10, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + ALMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/BBANDS_Test.cs b/Tests/MovingAvg/BBANDS_Test.cs index b843a361..842caacf 100644 --- a/Tests/MovingAvg/BBANDS_Test.cs +++ b/Tests/MovingAvg/BBANDS_Test.cs @@ -1,56 +1,56 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class BBANDS_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - BBANDS_Series c = new(a, 4,2.5); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - Assert.Equal(a.Count, c.PercentB.Count); - Assert.Equal(a.Count, c.Zscore.Count); - Assert.Equal(a.Count, c.Bandwidth.Count); - - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - Assert.Equal(a.Count, c.PercentB.Count); - Assert.Equal(a.Count, c.Zscore.Count); - Assert.Equal(a.Count, c.Bandwidth.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - BBANDS_Series c = new(a, 4, 2.5); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - Assert.Equal(a.Count, c.PercentB.Count); - Assert.Equal(a.Count, c.Zscore.Count); - Assert.Equal(a.Count, c.Bandwidth.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - Assert.Equal(a.Count, c.PercentB.Count); - Assert.Equal(a.Count, c.Zscore.Count); - Assert.Equal(a.Count, c.Bandwidth.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class BBANDS_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + BBANDS_Series c = new(a, 4,2.5); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + Assert.Equal(a.Count, c.Mid.Count); + Assert.Equal(a.Count, c.Upper.Count); + Assert.Equal(a.Count, c.Lower.Count); + Assert.Equal(a.Count, c.PercentB.Count); + Assert.Equal(a.Count, c.Zscore.Count); + Assert.Equal(a.Count, c.Bandwidth.Count); + + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + Assert.Equal(a.Count, c.Mid.Count); + Assert.Equal(a.Count, c.Upper.Count); + Assert.Equal(a.Count, c.Lower.Count); + Assert.Equal(a.Count, c.PercentB.Count); + Assert.Equal(a.Count, c.Zscore.Count); + Assert.Equal(a.Count, c.Bandwidth.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + BBANDS_Series c = new(a, 4, 2.5); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + Assert.Equal(a.Count, c.Mid.Count); + Assert.Equal(a.Count, c.Upper.Count); + Assert.Equal(a.Count, c.Lower.Count); + Assert.Equal(a.Count, c.PercentB.Count); + Assert.Equal(a.Count, c.Zscore.Count); + Assert.Equal(a.Count, c.Bandwidth.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + Assert.Equal(a.Count, c.Mid.Count); + Assert.Equal(a.Count, c.Upper.Count); + Assert.Equal(a.Count, c.Lower.Count); + Assert.Equal(a.Count, c.PercentB.Count); + Assert.Equal(a.Count, c.Zscore.Count); + Assert.Equal(a.Count, c.Bandwidth.Count); + } +} diff --git a/Tests/MovingAvg/DEMA_Test.cs b/Tests/MovingAvg/DEMA_Test.cs index 0120be62..7ce76446 100644 --- a/Tests/MovingAvg/DEMA_Test.cs +++ b/Tests/MovingAvg/DEMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class DEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - DEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - DEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class DEMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + DEMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + DEMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/EMA_Test.cs b/Tests/MovingAvg/EMA_Test.cs index 5d07b34d..dbba9ac8 100644 --- a/Tests/MovingAvg/EMA_Test.cs +++ b/Tests/MovingAvg/EMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class EMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - EMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - EMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class EMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + EMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + EMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/HEMA_Test.cs b/Tests/MovingAvg/HEMA_Test.cs index 8ad02f3c..eaed9490 100644 --- a/Tests/MovingAvg/HEMA_Test.cs +++ b/Tests/MovingAvg/HEMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class HEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - HEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - HEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class HEMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + HEMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + HEMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/HMA_Test.cs b/Tests/MovingAvg/HMA_Test.cs index 0096e3a8..e2cd00dc 100644 --- a/Tests/MovingAvg/HMA_Test.cs +++ b/Tests/MovingAvg/HMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class HMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - HMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - HMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class HMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + HMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + HMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/JMA_Test.cs b/Tests/MovingAvg/JMA_Test.cs index 27115e00..2623d325 100644 --- a/Tests/MovingAvg/JMA_Test.cs +++ b/Tests/MovingAvg/JMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class JMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - JMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - JMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class JMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + JMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + JMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/KAMA_Test.cs b/Tests/MovingAvg/KAMA_Test.cs index a7541b71..87714240 100644 --- a/Tests/MovingAvg/KAMA_Test.cs +++ b/Tests/MovingAvg/KAMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class KAMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - KAMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - KAMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class KAMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + KAMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + KAMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/MACD_Test.cs b/Tests/MovingAvg/MACD_Test.cs index fd13cd88..dd0ee4ad 100644 --- a/Tests/MovingAvg/MACD_Test.cs +++ b/Tests/MovingAvg/MACD_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class MACD_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MACD_Series c = new(a, 26,12,9); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MACD_Series c = new(a, 26,12,9); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class MACD_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + MACD_Series c = new(a, 26,12,9); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + MACD_Series c = new(a, 26,12,9); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/RMA_Test.cs b/Tests/MovingAvg/RMA_Test.cs index 88becfac..6bdea4ff 100644 --- a/Tests/MovingAvg/RMA_Test.cs +++ b/Tests/MovingAvg/RMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class RMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - RMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - RMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class RMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + RMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + RMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/RSI_Test.cs b/Tests/MovingAvg/RSI_Test.cs index 3c89fab6..016c0391 100644 --- a/Tests/MovingAvg/RSI_Test.cs +++ b/Tests/MovingAvg/RSI_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class RSI_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - RSI_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - RSI_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class RSI_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + RSI_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + RSI_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/SMA_Test.cs b/Tests/MovingAvg/SMA_Test.cs index d40e4842..b08b268f 100644 --- a/Tests/MovingAvg/SMA_Test.cs +++ b/Tests/MovingAvg/SMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class SMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class SMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + SMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + SMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/SMMA_Test.cs b/Tests/MovingAvg/SMMA_Test.cs index 7c4fa58c..418fe695 100644 --- a/Tests/MovingAvg/SMMA_Test.cs +++ b/Tests/MovingAvg/SMMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class SMMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SMMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SMMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class SMMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + SMMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + SMMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/TEMA_Test.cs b/Tests/MovingAvg/TEMA_Test.cs index 9553e346..af7b0df9 100644 --- a/Tests/MovingAvg/TEMA_Test.cs +++ b/Tests/MovingAvg/TEMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class TEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - TEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - TEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class TEMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + TEMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + TEMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/WMA_Test.cs b/Tests/MovingAvg/WMA_Test.cs index c3ab3569..52e12045 100644 --- a/Tests/MovingAvg/WMA_Test.cs +++ b/Tests/MovingAvg/WMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class WMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - WMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - WMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class WMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + WMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + WMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/MovingAvg/ZLEMA_Test.cs b/Tests/MovingAvg/ZLEMA_Test.cs index 14af9e12..dad74ec0 100644 --- a/Tests/MovingAvg/ZLEMA_Test.cs +++ b/Tests/MovingAvg/ZLEMA_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class ZLEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - ZLEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - ZLEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace MovingAvg; +public class ZLEMA_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + ZLEMA_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + ZLEMA_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/BIAS_Test.cs b/Tests/Statistics/BIAS_Test.cs index c0370128..2b46429c 100644 --- a/Tests/Statistics/BIAS_Test.cs +++ b/Tests/Statistics/BIAS_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class BIAS_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - BIAS_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - BIAS_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class BIAS_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + BIAS_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + BIAS_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/ENTP_Test.cs b/Tests/Statistics/ENTP_Test.cs index 8fd086b7..12098a8a 100644 --- a/Tests/Statistics/ENTP_Test.cs +++ b/Tests/Statistics/ENTP_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class KURT_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - KURT_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - KURT_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class KURT_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + KURT_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + KURT_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/KURT_Test.cs b/Tests/Statistics/KURT_Test.cs index da1a1cfa..93b5220c 100644 --- a/Tests/Statistics/KURT_Test.cs +++ b/Tests/Statistics/KURT_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class ENTP_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - ENTP_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - ENTP_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class ENTP_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + ENTP_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + ENTP_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/LINREG_Test.cs b/Tests/Statistics/LINREG_Test.cs index 89a8bb61..19cbf086 100644 --- a/Tests/Statistics/LINREG_Test.cs +++ b/Tests/Statistics/LINREG_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class LINREG_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - LINREG_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - LINREG_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class LINREG_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + LINREG_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + LINREG_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/MAD_Test.cs b/Tests/Statistics/MAD_Test.cs index a2d3cb5a..fcc11764 100644 --- a/Tests/Statistics/MAD_Test.cs +++ b/Tests/Statistics/MAD_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MAD_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MAD_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MAD_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class MAD_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + MAD_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + MAD_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/MAPE_Test.cs b/Tests/Statistics/MAPE_Test.cs index 64170230..1052f136 100644 --- a/Tests/Statistics/MAPE_Test.cs +++ b/Tests/Statistics/MAPE_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MAPE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MAPE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MAPE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class MAPE_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + MAPE_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + MAPE_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/MAX_Test.cs b/Tests/Statistics/MAX_Test.cs index b12e205d..785af747 100644 --- a/Tests/Statistics/MAX_Test.cs +++ b/Tests/Statistics/MAX_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MAX_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MAX_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MAX_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class MAX_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + MAX_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + MAX_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/MED_Test.cs b/Tests/Statistics/MED_Test.cs index e9eafb15..778811a4 100644 --- a/Tests/Statistics/MED_Test.cs +++ b/Tests/Statistics/MED_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MED_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MED_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MED_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class MED_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + MED_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + MED_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/MIN_Test.cs b/Tests/Statistics/MIN_Test.cs index bebd4144..917879d8 100644 --- a/Tests/Statistics/MIN_Test.cs +++ b/Tests/Statistics/MIN_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MIN_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MIN_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MIN_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class MIN_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + MIN_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + MIN_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/MSE_Test.cs b/Tests/Statistics/MSE_Test.cs index 379f9145..4c8374b7 100644 --- a/Tests/Statistics/MSE_Test.cs +++ b/Tests/Statistics/MSE_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MSE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MSE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MSE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class MSE_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + MSE_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + MSE_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/PSDEV_Test.cs b/Tests/Statistics/PSDEV_Test.cs index ce85da27..fa871ddb 100644 --- a/Tests/Statistics/PSDEV_Test.cs +++ b/Tests/Statistics/PSDEV_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class PSDEV_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SDEV_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SDEV_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class PSDEV_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + SDEV_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + SDEV_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/PVAR_Test .cs b/Tests/Statistics/PVAR_Test .cs index 67852e10..ef3880b4 100644 --- a/Tests/Statistics/PVAR_Test .cs +++ b/Tests/Statistics/PVAR_Test .cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class PVAR_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SVAR_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SVAR_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class PVAR_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + SVAR_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + SVAR_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/SDEV_Test .cs b/Tests/Statistics/SDEV_Test .cs index 40c45af0..e8b76a5d 100644 --- a/Tests/Statistics/SDEV_Test .cs +++ b/Tests/Statistics/SDEV_Test .cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class SDEV_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SSDEV_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SSDEV_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class SDEV_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + SSDEV_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + SSDEV_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/SMAPE_Test.cs b/Tests/Statistics/SMAPE_Test.cs index 4bef6373..fcc01a44 100644 --- a/Tests/Statistics/SMAPE_Test.cs +++ b/Tests/Statistics/SMAPE_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class SMAPE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SMAPE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SMAPE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class SMAPE_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + SMAPE_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + SMAPE_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/VAR_Test.cs b/Tests/Statistics/VAR_Test.cs index db7e92f0..329cd1f5 100644 --- a/Tests/Statistics/VAR_Test.cs +++ b/Tests/Statistics/VAR_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class VAR_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SVAR_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SVAR_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class VAR_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + SVAR_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + SVAR_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Statistics/WMAPE_Test.cs b/Tests/Statistics/WMAPE_Test.cs index 36024557..54acfbe5 100644 --- a/Tests/Statistics/WMAPE_Test.cs +++ b/Tests/Statistics/WMAPE_Test.cs @@ -1,31 +1,31 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class WMAPE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - WMAPE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - WMAPE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Statistics; +public class WMAPE_Test +{ + [Fact] + public void Add_Test() + { + TSeries a = new() { 0, 1, 2, 3, 4, 5 }; + WMAPE_Series c = new(a, 3); + Assert.Equal(6, c.Count); + a.Add(5); + Assert.Equal(a.Count, c.Count); + a.Add(0, update: true); + Assert.Equal(a.Count, c.Count); + } + + [Fact] + public void Edge_Test() + { + TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; + WMAPE_Series c = new(a, 3); + Assert.Equal(a.Count, c.Count); + a.Add(double.NaN); + Assert.Equal(a.Count, c.Count); + a.Add(double.PositiveInfinity); + Assert.Equal(a.Count, c.Count); + } +} diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index b73a43f1..c003a812 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -5,42 +5,22 @@ preview enable enable - false - AnyCPU;x64 - - - 1701;1702;MSB3270 - - - - 1701;1702;MSB3270 - - - - 1701;1702;MSB3270 - - - - 1701;1702;MSB3270 - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - diff --git a/Tests/Validations/Pandas_TA.cs b/Tests/Validations/Pandas_TA.cs index 0fd37fdc..be060152 100644 --- a/Tests/Validations/Pandas_TA.cs +++ b/Tests/Validations/Pandas_TA.cs @@ -1,121 +1,122 @@ -using Xunit; -using System; -using QuanTAlib; -using Python.Runtime; -using Python.Included; - -namespace Validation; -public class PandasTA -{ - private readonly RND_Feed bars; - private readonly Random rnd = new(); - private readonly int period; - private readonly dynamic ta; - private readonly dynamic df; - - public PandasTA() - { - this.bars = new(1000); - this.period = this.rnd.Next(28) + 3; - - Runtime.PythonDLL = @"python310.dll"; - Installer.InstallPath = Path.GetFullPath("."); - Installer.SetupPython().Wait(); - Installer.TryInstallPip(); - Installer.PipInstallModule("numpy"); - Installer.PipInstallModule("pandas"); - Installer.PipInstallModule("pandas-ta"); - PythonEngine.Initialize(); - this.ta = Py.Import("pandas_ta"); - this.df = this.ta.DataFrame(this.bars.Close.v); - } - - ~PandasTA() - { - PythonEngine.Shutdown(); - } - /* - [Fact] - void SMA() - { - SMA_Series QL = new(this.bars.Close, this.period, false); - var pta = this.ta.sma(close: this.df[0], length: this.period); - - Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); - } - - [Fact] - void EMA() - { - EMA_Series QL = new(this.bars.Close, this.period, false); - var pta = this.ta.ema(close: this.df[0], length: this.period); - - Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); - } - - - [Fact] - void TEMA() - { - TEMA_Series QL = new(this.bars.Close, this.period, false); - var pta = this.ta.tema(close: this.df[0], length: this.period); - - Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); - } - - [Fact] - void ENTP() - { - ENTP_Series QL = new(this.bars.Close, this.period, useNaN:false); - var pta = this.ta.entropy(close: this.df[0], length: this.period); - - Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); - } - - - [Fact] - void WMA() - { - WMA_Series QL = new(this.bars.Close, this.period, false); - var pta = this.ta.wma(close: this.df[0], length: this.period); - - Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); - } - - [Fact] - void DEMA() - { - DEMA_Series QL = new(this.bars.Close, this.period, false); - var pta = this.ta.dema(close: this.df[0], length: this.period); - - Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); - } - - [Fact] - void BIAS() - { - BIAS_Series QL = new(this.bars.Close, this.period, false); - var pta = this.ta.bias(close: this.df[0], length: this.period); - - Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); - } - - [Fact] - void KURT() - { - KURT_Series QL = new(this.bars.Close, this.period, useNaN: false); - var pta = this.ta.kurtosis(close: this.df[0], length: this.period); - - Assert.Equal(System.Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void MAD() - { - MAD_Series QL = new(this.bars.Close, this.period, useNaN: false); - var pta = this.ta.mad(close: this.df[0], length: this.period); - - Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); - } - */ -} \ No newline at end of file +/* +using Xunit; +using System; +using QuanTAlib; +using Python.Runtime; +using Python.Included; + +namespace Validation; +public class PandasTA +{ + private readonly RND_Feed bars; + private readonly Random rnd = new(); + private readonly int period; + private readonly dynamic ta; + private readonly dynamic df; + + public PandasTA() + { + this.bars = new(1000); + this.period = this.rnd.Next(28) + 3; + + Runtime.PythonDLL = @"python310.dll"; + Installer.InstallPath = Path.GetFullPath("."); + Installer.SetupPython().Wait(); + Installer.TryInstallPip(); + Installer.PipInstallModule("numpy"); + Installer.PipInstallModule("pandas"); + Installer.PipInstallModule("pandas-ta"); + PythonEngine.Initialize(); + this.ta = Py.Import("pandas_ta"); + this.df = this.ta.DataFrame(this.bars.Close.v); + } + + ~PandasTA() + { + PythonEngine.Shutdown(); + } + + [Fact] + void SMA() + { + SMA_Series QL = new(this.bars.Close, this.period, false); + var pta = this.ta.sma(close: this.df[0], length: this.period); + + Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); + } + + [Fact] + void EMA() + { + EMA_Series QL = new(this.bars.Close, this.period, false); + var pta = this.ta.ema(close: this.df[0], length: this.period); + + Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); + } + + + [Fact] + void TEMA() + { + TEMA_Series QL = new(this.bars.Close, this.period, false); + var pta = this.ta.tema(close: this.df[0], length: this.period); + + Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); + } + + [Fact] + void ENTP() + { + ENTP_Series QL = new(this.bars.Close, this.period, useNaN:false); + var pta = this.ta.entropy(close: this.df[0], length: this.period); + + Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); + } + + + [Fact] + void WMA() + { + WMA_Series QL = new(this.bars.Close, this.period, false); + var pta = this.ta.wma(close: this.df[0], length: this.period); + + Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); + } + + [Fact] + void DEMA() + { + DEMA_Series QL = new(this.bars.Close, this.period, false); + var pta = this.ta.dema(close: this.df[0], length: this.period); + + Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); + } + + [Fact] + void BIAS() + { + BIAS_Series QL = new(this.bars.Close, this.period, false); + var pta = this.ta.bias(close: this.df[0], length: this.period); + + Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); + } + + [Fact] + void KURT() + { + KURT_Series QL = new(this.bars.Close, this.period, useNaN: false); + var pta = this.ta.kurtosis(close: this.df[0], length: this.period); + + Assert.Equal(System.Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + } + + [Fact] + void MAD() + { + MAD_Series QL = new(this.bars.Close, this.period, useNaN: false); + var pta = this.ta.mad(close: this.df[0], length: this.period); + + Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); + } +} +*/ \ No newline at end of file diff --git a/Tests/Validations/Skender_Stock.cs b/Tests/Validations/Skender_Stock.cs index 7ba9ff82..56d29da1 100644 --- a/Tests/Validations/Skender_Stock.cs +++ b/Tests/Validations/Skender_Stock.cs @@ -1,282 +1,282 @@ -using System; -using QuanTAlib; -using Skender.Stock.Indicators; -using Xunit; - -namespace Validation; -public class Skender_Stock -{ - private readonly GBM_Feed bars; - private readonly Random rnd = new(); - private readonly int period; - private readonly IEnumerable quotes; - - public Skender_Stock() - { - this.bars = new(Bars: 5000, Volatility:0.7, Drift:0.0); - this.period = this.rnd.Next(28) + 3; - this.quotes = this.bars.Select( - q => new Quote - { - Date = q.t, - Open = (decimal)q.o, - High = (decimal)q.h, - Low = (decimal)q.l, - Close = (decimal)q.c, - Volume = (decimal)q.v - }); - } - - [Fact] - public void SMA() - { - SMA_Series QL = new(this.bars.Close, this.period, false); - var SK = this.quotes.GetSma(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void EMA() - { - EMA_Series QL = new(this.bars.Close, this.period, false); - var SK = this.quotes.GetEma(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Ema!, 6), Math.Round(QL.Last().v, 6)); - } - [Fact] - public void WMA() - { - WMA_Series QL = new(this.bars.Close, this.period, false); - var SK = this.quotes.GetWma(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Wma!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void DEMA() - { - DEMA_Series QL = new(this.bars.Close, this.period, false); - var SK = this.quotes.GetDema(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Dema!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void TEMA() - { - TEMA_Series QL = new(this.bars.Close, this.period, false); - var SK = this.quotes.GetTema(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Tema!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void MAD() - { - MAD_Series QL = new(this.bars.Close, this.period, false); - var SK = this.quotes.GetSmaAnalysis(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Mad!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void MAPE() - { - MAPE_Series QL = new(this.bars.Close, this.period, false); - var SK = this.quotes.GetSmaAnalysis(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Mape!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void ATR() - { - ATR_Series QL = new(this.bars, this.period, false); - var SK = this.quotes.GetAtr(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Atr!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void OBV() - { - OBV_Series QL = new(this.bars, this.period, false); - var SK = this.quotes.GetObv(this.period); - - // adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB - Assert.Equal(Math.Round((double)SK.Last().Obv!, 6) + Math.Round((double)this.quotes.First().Volume!, 6), - Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void ADL() - { - ADL_Series QL = new(this.bars, false); - var SK = this.quotes.GetAdl(); - - Assert.Equal(Math.Round((double)SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5)); - } - - [Fact] - public void CCI() - { - CCI_Series QL = new(this.bars, this.period, false); - var SK = this.quotes.GetCci(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Cci!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void ATRP() - { - ATRP_Series QL = new(this.bars, this.period, false); - var SK = this.quotes.GetAtr(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Atrp!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void KAMA() - { - KAMA_Series QL = new(this.bars.Close, this.period, useNaN: false); - var SK = this.quotes.GetKama(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Kama!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void HMA() - { - HMA_Series QL = new(this.bars.Close, this.period, useNaN: false); - var SK = this.quotes.GetHma(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Hma!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void SMMA() - { - SMMA_Series QL = new(this.bars.Close, this.period, useNaN: false); - var SK = this.quotes.GetSmma(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Smma!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void MACD() - { - MACD_Series QL = new(this.bars.Close, 26,12,9, useNaN: false); - var SK = this.quotes.GetMacd(12,26,9); - - Assert.Equal(Math.Round((double)SK.Last().Macd!, 6), Math.Round(QL.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().Signal!, 6), Math.Round(QL.Signal.Last().v, 6)); - } - - [Fact] - public void BBANDS() - { - BBANDS_Series QL = new(this.bars.Close, this.period, 2.0, useNaN: false); - var SK = this.quotes.GetBollingerBands(this.period, 2.0); - - Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Mid.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().UpperBand!, 6), Math.Round(QL.Upper.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().LowerBand!, 6), Math.Round(QL.Lower.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().Width!, 6), Math.Round(QL.Bandwidth.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().PercentB!, 6), Math.Round(QL.PercentB.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Zscore.Last().v, 6)); - } - - [Fact] - public void RSI() - { - RSI_Series QL = new(this.bars.Close, this.period, useNaN: false); - var SK = this.quotes.GetRsi(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Rsi!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void ALMA() - { - ALMA_Series QL = new(this.bars.Close, this.period, useNaN: false); - var SK = this.quotes.GetAlma(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Alma!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void SDEV() - { - SDEV_Series QL = new(this.bars.Close, this.period, useNaN: false); - var SK = this.quotes.GetStdDev(this.period); - - Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void LINREG() - { - LINREG_Series QL = new(this.bars.Close, this.period, useNaN: false); - var SK = this.quotes.GetSlope(this.period); - - Assert.Equal(Math.Round((double)SK.Last().Slope!, 6), Math.Round(QL.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().Intercept!, 6), Math.Round(QL.Intercept.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().RSquared!, 6), Math.Round(QL.RSquared.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.StdDev.Last().v, 6)); - } - - [Fact] - public void TR() - { - TR_Series QL = new(this.bars, useNaN: false); - var SK = this.quotes.GetTr(); - - Assert.Equal(Math.Round((double)SK.Last().Tr!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void HL2() - { - TSeries QL = this.bars.HL2; - var SK = this.quotes.GetBaseQuote(CandlePart.HL2); - - Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void OC2() - { - TSeries QL = this.bars.OC2; - var SK = this.quotes.GetBaseQuote(CandlePart.OC2); - - Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void HLC3() - { - TSeries QL = this.bars.HLC3; - var SK = this.quotes.GetBaseQuote(CandlePart.HLC3); - - Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void OHL3() - { - TSeries QL = this.bars.OHL3; - var SK = this.quotes.GetBaseQuote(CandlePart.OHL3); - - Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void OHLC4() - { - TSeries QL = this.bars.OHLC4; - var SK = this.quotes.GetBaseQuote(CandlePart.OHLC4); - - Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); - } -} +using System; +using QuanTAlib; +using Skender.Stock.Indicators; +using Xunit; + +namespace Validation; +public class Skender_Stock +{ + private readonly GBM_Feed bars; + private readonly Random rnd = new(); + private readonly int period; + private readonly IEnumerable quotes; + + public Skender_Stock() + { + this.bars = new(Bars: 5000, Volatility:0.7, Drift:0.0); + this.period = this.rnd.Next(28) + 3; + this.quotes = this.bars.Select( + q => new Quote + { + Date = q.t, + Open = (decimal)q.o, + High = (decimal)q.h, + Low = (decimal)q.l, + Close = (decimal)q.c, + Volume = (decimal)q.v + }); + } + + [Fact] + public void SMA() + { + SMA_Series QL = new(this.bars.Close, this.period, false); + var SK = this.quotes.GetSma(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void EMA() + { + EMA_Series QL = new(this.bars.Close, this.period, false); + var SK = this.quotes.GetEma(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Ema!, 6), Math.Round(QL.Last().v, 6)); + } + [Fact] + public void WMA() + { + WMA_Series QL = new(this.bars.Close, this.period, false); + var SK = this.quotes.GetWma(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Wma!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void DEMA() + { + DEMA_Series QL = new(this.bars.Close, this.period, false); + var SK = this.quotes.GetDema(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Dema!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void TEMA() + { + TEMA_Series QL = new(this.bars.Close, this.period, false); + var SK = this.quotes.GetTema(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Tema!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void MAD() + { + MAD_Series QL = new(this.bars.Close, this.period, false); + var SK = this.quotes.GetSmaAnalysis(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Mad!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void MAPE() + { + MAPE_Series QL = new(this.bars.Close, this.period, false); + var SK = this.quotes.GetSmaAnalysis(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Mape!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void ATR() + { + ATR_Series QL = new(this.bars, this.period, false); + var SK = this.quotes.GetAtr(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Atr!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void OBV() + { + OBV_Series QL = new(this.bars, this.period, false); + var SK = this.quotes.GetObv(this.period); + + // adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB + Assert.Equal(Math.Round(SK.Last().Obv! + (double)this.quotes.First().Volume!, 5), + Math.Round(QL.Last().v, 5)); + } + + [Fact] + public void ADL() + { + ADL_Series QL = new(this.bars, false); + var SK = this.quotes.GetAdl(); + + Assert.Equal(Math.Round((double)SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5)); + } + + [Fact] + public void CCI() + { + CCI_Series QL = new(this.bars, this.period, false); + var SK = this.quotes.GetCci(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Cci!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void ATRP() + { + ATRP_Series QL = new(this.bars, this.period, false); + var SK = this.quotes.GetAtr(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Atrp!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void KAMA() + { + KAMA_Series QL = new(this.bars.Close, this.period, useNaN: false); + var SK = this.quotes.GetKama(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Kama!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void HMA() + { + HMA_Series QL = new(this.bars.Close, this.period, useNaN: false); + var SK = this.quotes.GetHma(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Hma!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void SMMA() + { + SMMA_Series QL = new(this.bars.Close, this.period, useNaN: false); + var SK = this.quotes.GetSmma(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Smma!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void MACD() + { + MACD_Series QL = new(this.bars.Close, 26,12,9, useNaN: false); + var SK = this.quotes.GetMacd(12,26,9); + + Assert.Equal(Math.Round((double)SK.Last().Macd!, 6), Math.Round(QL.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().Signal!, 6), Math.Round(QL.Signal.Last().v, 6)); + } + + [Fact] + public void BBANDS() + { + BBANDS_Series QL = new(this.bars.Close, this.period, 2.0, useNaN: false); + var SK = this.quotes.GetBollingerBands(this.period, 2.0); + + Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Mid.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().UpperBand!, 6), Math.Round(QL.Upper.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().LowerBand!, 6), Math.Round(QL.Lower.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().Width!, 6), Math.Round(QL.Bandwidth.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().PercentB!, 6), Math.Round(QL.PercentB.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Zscore.Last().v, 6)); + } + + [Fact] + public void RSI() + { + RSI_Series QL = new(this.bars.Close, this.period, useNaN: false); + var SK = this.quotes.GetRsi(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Rsi!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void ALMA() + { + ALMA_Series QL = new(this.bars.Close, this.period, useNaN: false); + var SK = this.quotes.GetAlma(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Alma!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void SDEV() + { + SDEV_Series QL = new(this.bars.Close, this.period, useNaN: false); + var SK = this.quotes.GetStdDev(this.period); + + Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void LINREG() + { + LINREG_Series QL = new(this.bars.Close, this.period, useNaN: false); + var SK = this.quotes.GetSlope(this.period); + + Assert.Equal(Math.Round((double)SK.Last().Slope!, 6), Math.Round(QL.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().Intercept!, 6), Math.Round(QL.Intercept.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().RSquared!, 6), Math.Round(QL.RSquared.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.StdDev.Last().v, 6)); + } + + [Fact] + public void TR() + { + TR_Series QL = new(this.bars, useNaN: false); + var SK = this.quotes.GetTr(); + + Assert.Equal(Math.Round((double)SK.Last().Tr!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void HL2() + { + TSeries QL = this.bars.HL2; + var SK = this.quotes.GetBaseQuote(CandlePart.HL2); + + Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void OC2() + { + TSeries QL = this.bars.OC2; + var SK = this.quotes.GetBaseQuote(CandlePart.OC2); + + Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void HLC3() + { + TSeries QL = this.bars.HLC3; + var SK = this.quotes.GetBaseQuote(CandlePart.HLC3); + + Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void OHL3() + { + TSeries QL = this.bars.OHL3; + var SK = this.quotes.GetBaseQuote(CandlePart.OHL3); + + Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void OHLC4() + { + TSeries QL = this.bars.OHLC4; + var SK = this.quotes.GetBaseQuote(CandlePart.OHLC4); + + Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); + } +} diff --git a/Tests/Validations/TA_LIB.cs b/Tests/Validations/TA_LIB.cs index 4680de66..b8f2f7ce 100644 --- a/Tests/Validations/TA_LIB.cs +++ b/Tests/Validations/TA_LIB.cs @@ -1,272 +1,272 @@ -using Xunit; -using System; -using TALib; -using QuanTAlib; - -namespace Validation; -public class TA_LIB -{ - private readonly GBM_Feed bars; - private readonly Random rnd = new(); - private readonly int period; - private readonly double[] TALIB; - private readonly double[] inopen; - private readonly double[] inhigh; - private readonly double[] inlow; - private readonly double[] inclose; - private readonly double[] involume; - - public TA_LIB() - { - this.bars = new(5000); - this.period = this.rnd.Next(28) + 3; - this.TALIB = new double[this.bars.Count]; - this.inopen = this.bars.Open.v.ToArray(); - this.inhigh = this.bars.High.v.ToArray(); - this.inlow = this.bars.Low.v.ToArray(); - this.inclose = this.bars.Close.v.ToArray(); - this.involume = this.bars.Volume.v.ToArray(); - } - - ///////////////////////////////////////// - - [Fact] - public void ADD() - { - ADD_Series QL = new(this.bars.Open, this.bars.Close); - Core.Add(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void SUB() - { - SUB_Series QL = new(this.bars.Open, this.bars.Close); - Core.Sub(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void MUL() - { - MUL_Series QL = new(this.bars.Open, this.bars.Close); - Core.Mult(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void DIV() - { - DIV_Series QL = new(this.bars.Open, this.bars.Close); - Core.Div(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void SDEV() - { - SDEV_Series QL = new(this.bars.Close, this.period, false); - Core.StdDev(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void SMA() - { - SMA_Series QL = new(this.bars.Close, this.period, false); - Core.Sma(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void TRIMA() - { - TRIMA_Series QL = new(this.bars.Close, this.period, false); - Core.Trima(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void EMA() - { - EMA_Series QL = new(this.bars.Close, this.period, false); - Core.Ema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void WMA() - { - WMA_Series QL = new(this.bars.Close, this.period, false); - Core.Wma(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void DEMA() - { - DEMA_Series QL = new(this.bars.Close, this.period, false); - Core.Dema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void TEMA() - { - TEMA_Series QL = new(this.bars.Close, this.period, false); - Core.Tema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void MAX() - { - MAX_Series QL = new(this.bars.Close, this.period, false); - Core.Max(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void MIN() - { - MIN_Series QL = new(this.bars.Close, this.period, false); - Core.Min(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void ADL() - { - ADL_Series QL = new(this.bars, false); - Core.Ad(this.inhigh, this.inlow, this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void OBV() - { - OBV_Series QL = new(this.bars, this.period, false); - Core.Obv(this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void ADOSC() - { - ADOSC_Series QL = new(this.bars, false); - Core.AdOsc(this.inhigh, this.inlow, this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void ATR() - { - ATR_Series QL = new(this.bars, this.period, false); - Core.Atr(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void CCI() - { - CCI_Series QL = new(this.bars, this.period, false); - Core.Cci(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void RSI() - { - RSI_Series QL = new(this.bars.Close, this.period, false); - Core.Rsi(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void TR() - { - TR_Series QL = new(this.bars, false); - Core.TRange(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void MACD() - { - double[] macdSignal = new double[this.bars.Count]; - double[] macdHist = new double[this.bars.Count]; - MACD_Series QL = new(this.bars.Close, slow: 26, fast: 12, signal: 9, false); - Core.Macd(this.inclose, 0, this.bars.Count - 1, outMacd: this.TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Signal.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void BBANDS() - { - double[] outMiddle = new double[this.bars.Count]; - double[] outUpper = new double[this.bars.Count]; - double[] outLower = new double[this.bars.Count]; - BBANDS_Series QL = new(this.bars.Close, period:26, multiplier:2.0, false); - Core.Bbands(this.inclose, 0, this.bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod:26, optInNbDevUp:2.0, optInNbDevDn:2.0); - Assert.Equal(Math.Round(outUpper[outUpper.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Upper.Last().v, 6, MidpointRounding.AwayFromZero)); - Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Mid.Last().v, 6, MidpointRounding.AwayFromZero)); - Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Lower.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void HL2() - { - TSeries QL = this.bars.HL2; - Core.MedPrice(this.inhigh, this.inlow, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void HLC3() - { - TSeries QL = this.bars.HLC3; - Core.TypPrice(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void OHLC4() - { - TSeries QL = this.bars.OHLC4; - Core.AvgPrice(this.inopen, this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void HLCC4() - { - TSeries QL = this.bars.HLCC4; - Core.WclPrice( this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } -} +using Xunit; +using System; +using TALib; +using QuanTAlib; + +namespace Validation; +public class TA_LIB +{ + private readonly GBM_Feed bars; + private readonly Random rnd = new(); + private readonly int period; + private readonly double[] TALIB; + private readonly double[] inopen; + private readonly double[] inhigh; + private readonly double[] inlow; + private readonly double[] inclose; + private readonly double[] involume; + + public TA_LIB() + { + this.bars = new(5000); + this.period = this.rnd.Next(28) + 3; + this.TALIB = new double[this.bars.Count]; + this.inopen = this.bars.Open.v.ToArray(); + this.inhigh = this.bars.High.v.ToArray(); + this.inlow = this.bars.Low.v.ToArray(); + this.inclose = this.bars.Close.v.ToArray(); + this.involume = this.bars.Volume.v.ToArray(); + } + + ///////////////////////////////////////// + + [Fact] + public void ADD() + { + ADD_Series QL = new(this.bars.Open, this.bars.Close); + Core.Add(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void SUB() + { + SUB_Series QL = new(this.bars.Open, this.bars.Close); + Core.Sub(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void MUL() + { + MUL_Series QL = new(this.bars.Open, this.bars.Close); + Core.Mult(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void DIV() + { + DIV_Series QL = new(this.bars.Open, this.bars.Close); + Core.Div(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void SDEV() + { + SDEV_Series QL = new(this.bars.Close, this.period, false); + Core.StdDev(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void SMA() + { + SMA_Series QL = new(this.bars.Close, this.period, false); + Core.Sma(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void TRIMA() + { + TRIMA_Series QL = new(this.bars.Close, this.period, false); + Core.Trima(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void EMA() + { + EMA_Series QL = new(this.bars.Close, this.period, false); + Core.Ema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void WMA() + { + WMA_Series QL = new(this.bars.Close, this.period, false); + Core.Wma(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void DEMA() + { + DEMA_Series QL = new(this.bars.Close, this.period, false); + Core.Dema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void TEMA() + { + TEMA_Series QL = new(this.bars.Close, this.period, false); + Core.Tema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void MAX() + { + MAX_Series QL = new(this.bars.Close, this.period, false); + Core.Max(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void MIN() + { + MIN_Series QL = new(this.bars.Close, this.period, false); + Core.Min(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void ADL() + { + ADL_Series QL = new(this.bars, false); + Core.Ad(this.inhigh, this.inlow, this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void OBV() + { + OBV_Series QL = new(this.bars, this.period, false); + Core.Obv(this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void ADOSC() + { + ADOSC_Series QL = new(this.bars, false); + Core.AdOsc(this.inhigh, this.inlow, this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void ATR() + { + ATR_Series QL = new(this.bars, this.period, false); + Core.Atr(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void CCI() + { + CCI_Series QL = new(this.bars, this.period, false); + Core.Cci(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void RSI() + { + RSI_Series QL = new(this.bars.Close, this.period, false); + Core.Rsi(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void TR() + { + TR_Series QL = new(this.bars, false); + Core.TRange(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void MACD() + { + double[] macdSignal = new double[this.bars.Count]; + double[] macdHist = new double[this.bars.Count]; + MACD_Series QL = new(this.bars.Close, slow: 26, fast: 12, signal: 9, false); + Core.Macd(this.inclose, 0, this.bars.Count - 1, outMacd: this.TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Signal.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void BBANDS() + { + double[] outMiddle = new double[this.bars.Count]; + double[] outUpper = new double[this.bars.Count]; + double[] outLower = new double[this.bars.Count]; + BBANDS_Series QL = new(this.bars.Close, period:26, multiplier:2.0, false); + Core.Bbands(this.inclose, 0, this.bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod:26, optInNbDevUp:2.0, optInNbDevDn:2.0); + Assert.Equal(Math.Round(outUpper[outUpper.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Upper.Last().v, 6, MidpointRounding.AwayFromZero)); + Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Mid.Last().v, 6, MidpointRounding.AwayFromZero)); + Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Lower.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void HL2() + { + TSeries QL = this.bars.HL2; + Core.MedPrice(this.inhigh, this.inlow, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void HLC3() + { + TSeries QL = this.bars.HLC3; + Core.TypPrice(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void OHLC4() + { + TSeries QL = this.bars.OHLC4; + Core.AvgPrice(this.inopen, this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void HLCC4() + { + TSeries QL = this.bars.HLCC4; + Core.WclPrice( this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } +} diff --git a/docs/crossovers.ipynb b/docs/crossovers.ipynb index 304d3013..62f4583d 100644 --- a/docs/crossovers.ipynb +++ b/docs/crossovers.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 35, + "execution_count": 11, "metadata": { "dotnet_interactive": { "language": "csharp" @@ -34,7 +34,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 12, "metadata": { "dotnet_interactive": { "language": "csharp" @@ -45,7 +45,8 @@ }, "outputs": [], "source": [ - "Yahoo_Feed data = new(Symbol: \"MSFT\", Period: 200);\n", + "String Sym = \"IBM\";\n", + "Alphavantage_Feed data = new(Symbol: Sym);\n", "ZLEMA_Series calc1 = new(data.OHLC4,20);\n", "HMA_Series calc2 = new(data.OHLC4,20);\n", "HEMA_Series calc3 = new(data.OHLC4,20);" @@ -53,7 +54,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 17, "metadata": { "dotnet_interactive": { "language": "csharp" @@ -68,29 +69,29 @@ "text/html": [ "\n", "
\n", - "
\r\n", + "
\r\n", "\r\n", "\n", @@ -112,16 +113,16 @@ " GridColor:Color.fromString(\"#252525\")); \n", "\n", "var candles = Chart2D.Chart.Candlestick(data.Open.v, data.High.v, data.Low.v, data.Close.v, data.Open.t, \"\");\n", - "var line1 = Chart2D.Chart.Line(calc1.t, calc1.v,false,\"\").WithLineStyle(Width: 2, Color: Color.fromString(\"yellow\"));\n", - "var line2 = Chart2D.Chart.Line(calc2.t, calc2.v, false,\"\").WithLineStyle(Width: 3, Color: Color.fromString(\"red\"));\n", - "var line3 = Chart2D.Chart.Line(calc3.t, calc3.v, false,\"\").WithLineStyle(Width: 2, Color: Color.fromString(\"blue\"));\n", + "var line1 = Chart2D.Chart.Line(calc1.t, calc1.v, false, calc1.GetType().Name).WithLineStyle(Width: 2, Color: Color.fromString(\"yellow\"));\n", + "var line2 = Chart2D.Chart.Line(calc2.t, calc2.v, false, calc2.GetType().Name).WithLineStyle(Width: 3, Color: Color.fromString(\"red\"));\n", + "var line3 = Chart2D.Chart.Line(calc3.t, calc3.v, false, calc3.GetType().Name).WithLineStyle(Width: 2, Color: Color.fromString(\"blue\"));\n", "var chart = Chart.Combine(new []{candles, line1, line2, line3})\n", " .WithSize(1200,600)\n", " .WithMargin(Margin.init(30,10,40,30,1,false))\n", " .WithXAxisRangeSlider(RangeSlider.init(Visible:false))\n", " .WithYAxis(yAxis)\n", " .WithXAxis(yAxis)\n", - " .WithTitle(\"MSFT\")\n", + " .WithTitle(Sym)\n", " .WithLayout(layout);\n", "\n", "chart" diff --git a/docs/readme.md b/docs/readme.md index ce7c2fcf..e455846a 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -181,7 +181,7 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett | ⛔ AOBV - Archer On-Balance Volume |||| | ⛔ CMF - Chaikin Money Flow |||| | ⛔ EOM - Ease of Movement |||| -| ⭐ OBV - On-Balance Volume | `OBV_Series` | OBV | GetObv | +| ⭐ OBV - On-Balance Volume | ` OBV_Series` | OBV | GetObv | | ⛔ PRS - Price Relative Strength ||| | ⛔ PVOL - Price-Volume |||| | ⛔ PVO - Percentage Volume Oscillator ||||