GitVersion

GitVersion
This commit is contained in:
Miha Kralj
2022-11-12 20:06:54 -08:00
parent 97fb428147
commit 59ca5c2395
80 changed files with 4237 additions and 4257 deletions
+12 -12
View File
@@ -30,6 +30,8 @@ jobs:
with: with:
java-version: 1.11 java-version: 1.11
- name: Install GitVersion
run: dotnet tool install GitVersion.Tool --global
- name: Install JetBrains - name: Install JetBrains
run: dotnet tool install JetBrains.dotCover.GlobalTool --global run: dotnet tool install JetBrains.dotCover.GlobalTool --global
- name: Install Sonar Scanner - name: Install Sonar Scanner
@@ -78,14 +80,14 @@ jobs:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: ./coveragereport.xml coverage-reports: ./coveragereport.xml
- name: Release # - name: Release
uses: marvinpinto/action-automatic-releases@latest # uses: marvinpinto/action-automatic-releases@latest
with: # with:
repo_token: "${{ secrets.GITHUB_TOKEN }}" # repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "latest" # automatic_release_tag: "latest"
prerelease: true # prerelease: true
title: "Latest Build" # title: "Latest Build"
files: /Quantower/Settings/Scripts/Indicators/QuanTAlib/*.dll # files: /Quantower/Settings/Scripts/Indicators/QuanTAlib/*.dll
- name: Authenticate to Github packages source - name: Authenticate to Github packages source
run: dotnet nuget add source run: dotnet nuget add source
@@ -95,14 +97,12 @@ jobs:
--name github "https://nuget.pkg.github.com/mihakralj/index.json" --name github "https://nuget.pkg.github.com/mihakralj/index.json"
- name: Push package to github - name: Push package to github
if: ${{ github.ref == 'refs/heads/dev' }}
run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg' run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg'
--api-key ${{ secrets.GITHUB_TOKEN }}
--source https://nuget.pkg.github.com/mihakralj/index.json --source https://nuget.pkg.github.com/mihakralj/index.json
--skip-duplicate --skip-duplicate
--no-symbols
- name: Push package to nuget.org - name: Push package to nuget.org
if: ${{ github.ref == 'refs/heads/main' }}
run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg' run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg'
--api-key ${{ secrets.NUGET_DEPLOY_KEY_QUANTLIB }} --api-key ${{ secrets.NUGET_DEPLOY_KEY_QUANTLIB }}
--source https://api.nuget.org/v3/index.json --source https://api.nuget.org/v3/index.json
+17
View File
@@ -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
-20
View File
@@ -5,42 +5,22 @@ VisualStudioVersion = 17.2.32210.308
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuanTAlib", "Source\QuanTAlib.csproj", "{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuanTAlib", "Source\QuanTAlib.csproj", "{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}"
EndProject 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}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {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|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.ActiveCfg = Release|Any CPU
{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
+53 -53
View File
@@ -1,53 +1,53 @@
using System.Drawing; using System.Drawing;
using TradingPlatform.BusinessLayer; using TradingPlatform.BusinessLayer;
namespace QuanTAlib; namespace QuanTAlib;
public class SDEV_chart : Indicator public class SDEV_chart : Indicator
{ {
#region Parameters #region Parameters
[InputParameter("Smoothing period", 0, 1, 999, 1, 1)] [InputParameter("Smoothing period", 0, 1, 999, 1, 1)]
private int Period = 10; private int Period = 10;
[InputParameter("Data source", 1, variants: new object[] [InputParameter("Data source", 1, variants: new object[]
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5, { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })] "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
private int DataSource = 8; private int DataSource = 8;
#endregion Parameters #endregion Parameters
private TBars bars; private TBars bars;
///////dotnet ///////dotnet
private SDEV_Series indicator; private SDEV_Series indicator;
/////// ///////
public SDEV_chart() public SDEV_chart()
{ {
this.SeparateWindow = true; this.SeparateWindow = true;
this.Name = "SDEV - Standard Deviation"; this.Name = "SDEV - Standard Deviation";
this.Description = "SDEV description"; this.Description = "SDEV description";
this.AddLineSeries("SDEV", Color.RoyalBlue, 3, LineStyle.Solid); this.AddLineSeries("SDEV", Color.RoyalBlue, 3, LineStyle.Solid);
} }
protected override void OnInit() protected override void OnInit()
{ {
this.bars = new(); this.bars = new();
this.ShortName = this.ShortName =
"SDEV (" + TBars.SelectStr(this.DataSource) + ", " + this.Period + ")"; "SDEV (" + TBars.SelectStr(this.DataSource) + ", " + this.Period + ")";
this.indicator = new(source: bars.Select(this.DataSource), this.indicator = new(source: bars.Select(this.DataSource),
period: this.Period, useNaN: true); period: this.Period, useNaN: true);
} }
protected override void OnUpdate(UpdateArgs args) protected override void OnUpdate(UpdateArgs args)
{ {
bool update = !(args.Reason == UpdateReason.NewBar || bool update = !(args.Reason == UpdateReason.NewBar ||
args.Reason == UpdateReason.HistoricalBar); args.Reason == UpdateReason.HistoricalBar);
this.bars.Add(this.Time(), this.GetPrice(PriceType.Open), this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
this.GetPrice(PriceType.High), this.GetPrice(PriceType.Low), this.GetPrice(PriceType.High), this.GetPrice(PriceType.Low),
this.GetPrice(PriceType.Close), this.GetPrice(PriceType.Close),
this.GetPrice(PriceType.Volume), update); this.GetPrice(PriceType.Volume), update);
double result = this.indicator[this.indicator.Count - 1].v; double result = this.indicator[this.indicator.Count - 1].v;
this.SetValue(result, 0); this.SetValue(result, 0);
} }
} }
+54 -54
View File
@@ -1,54 +1,54 @@
using System.Drawing; using System.Drawing;
using TradingPlatform.BusinessLayer; using TradingPlatform.BusinessLayer;
namespace QuanTAlib; namespace QuanTAlib;
public class VAR_chart : Indicator public class VAR_chart : Indicator
{ {
#region Parameters #region Parameters
[InputParameter("Smoothing period", 0, 1, 999, 1, 1)] [InputParameter("Smoothing period", 0, 1, 999, 1, 1)]
private int Period = 10; private int Period = 10;
[InputParameter("Data source", 1, variants: new object[] [InputParameter("Data source", 1, variants: new object[]
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5, { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })] "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
private int DataSource = 8; private int DataSource = 8;
#endregion Parameters #endregion Parameters
private TBars bars; private TBars bars;
///////dotnet ///////dotnet
private VAR_Series indicator; private VAR_Series indicator;
/////// ///////
public VAR_chart() public VAR_chart()
{ {
this.SeparateWindow = true; this.SeparateWindow = true;
this.Name = "VAR - Variance"; this.Name = "VAR - Variance";
this.Description = "VAR description"; this.Description = "VAR description";
this.AddLineSeries("VAR", Color.RoyalBlue, 3, LineStyle.Solid); this.AddLineSeries("VAR", Color.RoyalBlue, 3, LineStyle.Solid);
} }
protected override void OnInit() protected override void OnInit()
{ {
this.bars = new(); this.bars = new();
this.ShortName = this.ShortName =
"VAR (" + TBars.SelectStr(this.DataSource) + ", " + this.Period + ")"; "VAR (" + TBars.SelectStr(this.DataSource) + ", " + this.Period + ")";
this.indicator = new(source: bars.Select(this.DataSource), this.indicator = new(source: bars.Select(this.DataSource),
period: this.Period, useNaN: true); period: this.Period, useNaN: true);
} }
protected override void OnUpdate(UpdateArgs args) protected override void OnUpdate(UpdateArgs args)
{ {
bool update = !(args.Reason == UpdateReason.NewBar || bool update = !(args.Reason == UpdateReason.NewBar ||
args.Reason == UpdateReason.HistoricalBar); args.Reason == UpdateReason.HistoricalBar);
this.bars.Add(this.Time(), this.GetPrice(PriceType.Open), this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
this.GetPrice(PriceType.High), this.GetPrice(PriceType.Low), this.GetPrice(PriceType.High), this.GetPrice(PriceType.Low),
this.GetPrice(PriceType.Close), this.GetPrice(PriceType.Close),
this.GetPrice(PriceType.Volume), update); this.GetPrice(PriceType.Volume), update);
double result = this.indicator[this.indicator.Count - 1].v; double result = this.indicator[this.indicator.Count - 1].v;
this.SetValue(result, 0); this.SetValue(result, 0);
} }
} }
+56 -56
View File
@@ -1,56 +1,56 @@
namespace QuanTAlib; namespace QuanTAlib;
using System.Drawing; using System.Drawing;
using TradingPlatform.BusinessLayer; using TradingPlatform.BusinessLayer;
public class WMAPE_chart : Indicator public class WMAPE_chart : Indicator
{ {
#region Parameters #region Parameters
[InputParameter("Smoothing period", 0, 1, 999, 1, 1)] [InputParameter("Smoothing period", 0, 1, 999, 1, 1)]
private readonly int Period = 10; private readonly int Period = 10;
[InputParameter("Data source", 1, variants: new object[]{ [InputParameter("Data source", 1, variants: new object[]{
"Open", 0, "Open", 0,
"High", 1, "High", 1,
"Low", 2, "Low", 2,
"Close", 3, "Close", 3,
"HL2", 4, "HL2", 4,
"OC2", 5, "OC2", 5,
"OHL3", 6, "OHL3", 6,
"HLC3", 7, "HLC3", 7,
"OHLC4", 8, "OHLC4", 8,
"Weighted (HLCC4)", 9 "Weighted (HLCC4)", 9
})] })]
private readonly int DataSource = 8; private readonly int DataSource = 8;
#endregion Parameters #endregion Parameters
private TBars bars; private TBars bars;
///////dotnet ///////dotnet
private QuanTAlib.WMAPE_Series indicator; private QuanTAlib.WMAPE_Series indicator;
/////// ///////
public WMAPE_chart() public WMAPE_chart()
{ {
this.SeparateWindow = true; this.SeparateWindow = true;
this.Name = "WMAPE - Weighted Mean Absolute Percentage Error"; this.Name = "WMAPE - Weighted Mean Absolute Percentage Error";
this.Description = "WMAPE description"; this.Description = "WMAPE description";
this.AddLineSeries("WMAPE", Color.RoyalBlue, 3, LineStyle.Solid); this.AddLineSeries("WMAPE", Color.RoyalBlue, 3, LineStyle.Solid);
} }
protected override void OnInit() protected override void OnInit()
{ {
this.bars = new(); this.bars = new();
this.ShortName = "WMAPE (" + QuanTAlib.TBars.SelectStr(this.DataSource) + ", " + this.Period + ")"; this.ShortName = "WMAPE (" + QuanTAlib.TBars.SelectStr(this.DataSource) + ", " + this.Period + ")";
this.indicator = new(source: this.bars.Select(this.DataSource), period: this.Period, useNaN: true); this.indicator = new(source: this.bars.Select(this.DataSource), period: this.Period, useNaN: true);
} }
protected override void OnUpdate(UpdateArgs args) protected override void OnUpdate(UpdateArgs args)
{ {
bool update = !(args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar); bool update = !(args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar);
this.bars.Add(this.Time(), this.GetPrice(PriceType.Open), this.GetPrice(PriceType.High), this.GetPrice(PriceType.Low), this.GetPrice(PriceType.Close), this.GetPrice(PriceType.Volume), update); this.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; double result = this.indicator[this.indicator.Count - 1].v;
this.SetValue(result, 0); this.SetValue(result, 0);
} }
} }
+135 -135
View File
@@ -1,135 +1,135 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
Abstract classes with all scaffolding required to build indicators. Abstract classes with all scaffolding required to build indicators.
All abstracts support period, NaN, and all permutations of Add() methods. All abstracts support period, NaN, and all permutations of Add() methods.
Indicator classess need to implement: Indicator classess need to implement:
- Chaining constructor (Abstract's constructor executes first) - Chaining constructor (Abstract's constructor executes first)
- Default Add(value) class - Default Add(value) class
- optional Add(series) bulk insert class (for optimization of historical analysis) - optional Add(series) bulk insert class (for optimization of historical analysis)
Single_TSeries_Indicator - one single-value TSeries in, one TSeries out. Single_TSeries_Indicator - one single-value TSeries in, one TSeries out.
Pair_TSeries_Indicator - Two TSeries in, one TSeries out. (includes simple semaphoring) Pair_TSeries_Indicator - Two TSeries in, one TSeries out. (includes simple semaphoring)
Single_TBars_Indicator - One OHLCV TBars in, one TSeries out. Single_TBars_Indicator - One OHLCV TBars in, one TSeries out.
</summary> */ </summary> */
public abstract class Single_TSeries_Indicator : TSeries public abstract class Single_TSeries_Indicator : TSeries
{ {
protected readonly int _p; protected readonly int _p;
protected readonly bool _NaN; protected readonly bool _NaN;
protected readonly TSeries _data; protected readonly TSeries _data;
// Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) // 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) protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN)
{ {
this._data = source; this._data = source;
this._p = period; this._p = period;
this._NaN = useNaN; this._NaN = useNaN;
this._data.Pub += this.Sub; this._data.Pub += this.Sub;
} }
// overridable Add() method to add/update a single item at the end of the list // overridable Add() method to add/update a single item at the end of the list
public new virtual void Add((System.DateTime t, double v) TValue, bool update) => base.Add(TValue, update); 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) // 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 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 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(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 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 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 public abstract class Pair_TSeries_Indicator : TSeries
{ {
protected readonly TSeries _d1; protected readonly TSeries _d1;
protected readonly TSeries _d2; protected readonly TSeries _d2;
protected readonly double _dd1, _dd2; protected readonly double _dd1, _dd2;
// Chainable Constructors - add them at the end of primary constructors if needed // Chainable Constructors - add them at the end of primary constructors if needed
protected Pair_TSeries_Indicator(TSeries source1, TSeries source2) protected Pair_TSeries_Indicator(TSeries source1, TSeries source2)
{ {
this._d1 = source1; this._d1 = source1;
this._d2 = source2; this._d2 = source2;
this._dd1 = double.NaN; this._dd1 = double.NaN;
this._dd2 = double.NaN; this._dd2 = double.NaN;
this._d1.Pub += this.Sub; this._d1.Pub += this.Sub;
this._d2.Pub += this.Sub; this._d2.Pub += this.Sub;
} }
protected Pair_TSeries_Indicator(TSeries source1, double dd2) protected Pair_TSeries_Indicator(TSeries source1, double dd2)
{ {
this._d1 = source1; this._d1 = source1;
this._d2 = new(); this._d2 = new();
this._dd1 = double.NaN; this._dd1 = double.NaN;
this._dd2 = dd2; this._dd2 = dd2;
this._d1.Pub += this.Sub; this._d1.Pub += this.Sub;
} }
protected Pair_TSeries_Indicator(double dd1, TSeries source2) protected Pair_TSeries_Indicator(double dd1, TSeries source2)
{ {
this._d1 = new(); this._d1 = new();
this._d2 = source2; this._d2 = source2;
this._dd1 = dd1; this._dd1 = dd1;
this._dd2 = double.NaN; this._dd2 = double.NaN;
this._d2.Pub += this.Sub; this._d2.Pub += this.Sub;
} }
// overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list // 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 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) // 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, 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(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 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((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2) => this.Add(TValue1, TValue2, update: false);
public void Add(bool update) public void Add(bool update)
{ {
if ((this._dd1 is double.NaN) && (this._dd2 is double.NaN)) if ((this._dd1 is double.NaN) && (this._dd2 is double.NaN))
{ {
// (Series, Series) // (Series, Series)
if (update || (this._d1.Count > this.Count && this._d2.Count > this.Count)) 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); } { 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)) else if ((this._dd2 is not double.NaN) && (this._dd1 is double.NaN))
{ {
// (Series, Double) // (Series, Double)
this.Add(TValue1: this._d1[this._d1.Count - 1], TValue2: (this._d1[this._d1.Count - 1].t, this._dd2), update: update); this.Add(TValue1: this._d1[this._d1.Count - 1], TValue2: (this._d1[this._d1.Count - 1].t, this._dd2), update: update);
} }
else else
{ {
// (Double, Series) // (Double, Series)
this.Add(TValue1: (this._d2[this._d2.Count - 1].t, this._dd1), TValue2: this._d2[this._d2.Count - 1], update: update); 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 void Add() => this.Add(update: false);
public new void Sub(object source, TSeriesEventArgs e) => this.Add(e.update); public new void Sub(object source, TSeriesEventArgs e) => this.Add(e.update);
} }
public abstract class Single_TBars_Indicator : TSeries public abstract class Single_TBars_Indicator : TSeries
{ {
protected readonly int _p; protected readonly int _p;
protected readonly bool _NaN; protected readonly bool _NaN;
protected readonly TBars _bars; protected readonly TBars _bars;
// Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) // 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) protected Single_TBars_Indicator(TBars source, int period, bool useNaN)
{ {
this._p = period; this._p = period;
this._bars = source; this._bars = source;
this._NaN = useNaN; this._NaN = useNaN;
this._bars.Pub += this.Sub; this._bars.Pub += this.Sub;
} }
// overridable Add() method to add/update a single item at the end of the list // overridable Add() method to add/update a single item at the end of the list
public virtual void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar, bool update) => base.Add((TBar.t, 0.0), update); 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) // 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(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 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((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(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 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); public new void Sub(object source, TSeriesEventArgs e) => this.Add(TBar: this._bars[this._bars.Count - 1], update: e.update);
} }
+33 -33
View File
@@ -1,34 +1,34 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
MAX - Maximum value in the given period in the series. MAX - Maximum value in the given period in the series.
If period = 0 => period = full length of the series If period = 0 => period = full length of the series
</summary> */ </summary> */
public class MAX_Series : Single_TSeries_Indicator public class MAX_Series : Single_TSeries_Indicator
{ {
public MAX_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public MAX_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
public override void Add((DateTime t, double v) TValue, bool update) public override void Add((DateTime t, double v) TValue, bool update)
{ {
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
else { this._buffer.Add(TValue.v); } else { this._buffer.Add(TValue.v); }
if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); }
double _max = TValue.v; double _max = TValue.v;
for (int i = 0; i < this._buffer.Count; i++) for (int i = 0; i < this._buffer.Count; i++)
{ {
//_max = (this._buffer[i] > _max) ? this._buffer[i] : _max; //_max = (this._buffer[i] > _max) ? this._buffer[i] : _max;
_max = Math.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); var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _max);
base.Add(result, update); base.Add(result, update);
} }
} }
+33 -33
View File
@@ -1,34 +1,34 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
MIN - Minimum value in the given period in the series. MIN - Minimum value in the given period in the series.
If period = 0 => period = full length of the series If period = 0 => period = full length of the series
</summary> */ </summary> */
public class MIN_Series : Single_TSeries_Indicator public class MIN_Series : Single_TSeries_Indicator
{ {
public MIN_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public MIN_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
else { this._buffer.Add(TValue.v); } else { this._buffer.Add(TValue.v); }
if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); }
double _min = TValue.v; double _min = TValue.v;
for (int i = 0; i < this._buffer.Count; i++) for (int i = 0; i < this._buffer.Count; i++)
{ {
//_min = (this._buffer[i] < _min) ? this._buffer[i] : _min; //_min = (this._buffer[i] < _min) ? this._buffer[i] : _min;
_min = Math.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); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _min);
base.Add(result, update); base.Add(result, update);
} }
} }
+132 -132
View File
@@ -1,132 +1,132 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
TBars class - includes all series for common data used in indicators and other calculations. TBars class - includes all series for common data used in indicators and other calculations.
Has a bit limited overloading and casting (compared to TSeries) 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 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 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) (it is 'cheaper' to calculate them once during data capture than each time during data analysis)
</summary> */ </summary> */
public class TBars : System.Collections.Generic.List<(DateTime t, double o, double h, double l, double c, double v)> 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 _open = new();
private readonly TSeries _high = new(); private readonly TSeries _high = new();
private readonly TSeries _low = new(); private readonly TSeries _low = new();
private readonly TSeries _close = new(); private readonly TSeries _close = new();
private readonly TSeries _volume = new(); private readonly TSeries _volume = new();
private readonly TSeries _hl2 = new(); private readonly TSeries _hl2 = new();
private readonly TSeries _oc2 = new(); private readonly TSeries _oc2 = new();
private readonly TSeries _ohl3 = new(); private readonly TSeries _ohl3 = new();
private readonly TSeries _hlc3 = new(); private readonly TSeries _hlc3 = new();
private readonly TSeries _ohlc4 = new(); private readonly TSeries _ohlc4 = new();
private readonly TSeries _hlcc4 = new(); private readonly TSeries _hlcc4 = new();
public TSeries Open => this._open; public TSeries Open => this._open;
public TSeries High => this._high; public TSeries High => this._high;
public TSeries Low => this._low; public TSeries Low => this._low;
public TSeries Close => this._close; public TSeries Close => this._close;
public TSeries Volume => this._volume; public TSeries Volume => this._volume;
public TSeries HL2 => this._hl2; public TSeries HL2 => this._hl2;
public TSeries OC2 => this._oc2; public TSeries OC2 => this._oc2;
public TSeries OHL3 => this._ohl3; public TSeries OHL3 => this._ohl3;
public TSeries HLC3 => this._hlc3; public TSeries HLC3 => this._hlc3;
public TSeries OHLC4 => this._ohlc4; public TSeries OHLC4 => this._ohlc4;
public TSeries HLCC4 => this._hlcc4; public TSeries HLCC4 => this._hlcc4;
public TBars Tail(int count=10) { public TBars Tail(int count=10) {
TBars outBars = new(); TBars outBars = new();
if (count > this.Count) { count = this.Count; } if (count > this.Count) { count = this.Count; }
for (int i = this.Count-count; i<this.Count; i++) { outBars.Add(this[i]); } for (int i = this.Count-count; i<this.Count; i++) { outBars.Add(this[i]); }
return outBars; return outBars;
} }
public TSeries Select(int source) public TSeries Select(int source)
{ {
return source switch return source switch
{ {
0 => _open, 0 => _open,
1 => _high, 1 => _high,
2 => _low, 2 => _low,
3 => _close, 3 => _close,
4 => _hl2, 4 => _hl2,
5 => _oc2, 5 => _oc2,
6 => _ohl3, 6 => _ohl3,
7 => _hlc3, 7 => _hlc3,
8 => _ohlc4, 8 => _ohlc4,
_ => _hlcc4, _ => _hlcc4,
}; };
} }
public static string SelectStr(int source) public static string SelectStr(int source)
{ {
return source switch return source switch
{ {
0 => "Open", 0 => "Open",
1 => "High", 1 => "High",
2 => "Low", 2 => "Low",
3 => "Close", 3 => "Close",
4 => "HL2", 4 => "HL2",
5 => "OC2", 5 => "OC2",
6 => "OHL3", 6 => "OHL3",
7 => "Typical", 7 => "Typical",
8 => "Mean", 8 => "Mean",
_ => "Weighted", _ => "Weighted",
}; };
} }
public void Add((DateTime t, double o, double h, double l, double c, double v) i, bool update = false) 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); => 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) 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); => 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) public void Add(DateTime t, double o, double h, double l, double c, double v, bool update = false)
{ {
if (update) if (update)
{ {
this[this.Count - 1] = (t, o, h, l, c, v); this[this.Count - 1] = (t, o, h, l, c, v);
_open[_open.Count - 1] = (t, o); _open[_open.Count - 1] = (t, o);
_high[_high.Count - 1] = (t, h); _high[_high.Count - 1] = (t, h);
_low[_low.Count - 1] = (t, l); _low[_low.Count - 1] = (t, l);
_close[_close.Count - 1] = (t, c); _close[_close.Count - 1] = (t, c);
_volume[_volume.Count - 1] = (t, v); _volume[_volume.Count - 1] = (t, v);
_hl2[_hl2.Count - 1] = (t, (h + l) * 0.5); _hl2[_hl2.Count - 1] = (t, (h + l) * 0.5);
_oc2[_oc2.Count - 1] = (t, (o + c) * 0.5); _oc2[_oc2.Count - 1] = (t, (o + c) * 0.5);
_ohl3[_ohl3.Count - 1] = (t, (o + h + l) * 0.333333333333333); _ohl3[_ohl3.Count - 1] = (t, (o + h + l) * 0.333333333333333);
_hlc3[_hlc3.Count - 1] = (t, (h + l + c) * 0.333333333333333); _hlc3[_hlc3.Count - 1] = (t, (h + l + c) * 0.333333333333333);
_ohlc4[_ohlc4.Count - 1] = (t, (o + h + l + c) * 0.25); _ohlc4[_ohlc4.Count - 1] = (t, (o + h + l + c) * 0.25);
_hlcc4[_hlcc4.Count - 1] = (t, (h + l + c + c) * 0.25); _hlcc4[_hlcc4.Count - 1] = (t, (h + l + c + c) * 0.25);
} }
else else
{ {
base.Add((t, o, h, l, c, v)); base.Add((t, o, h, l, c, v));
_open.Add((t, o)); _open.Add((t, o));
_high.Add((t, h)); _high.Add((t, h));
_low.Add((t, l)); _low.Add((t, l));
_close.Add((t, c)); _close.Add((t, c));
_volume.Add((t, v)); _volume.Add((t, v));
_hl2.Add((t, (h + l) * 0.5)); _hl2.Add((t, (h + l) * 0.5));
_oc2.Add((t, (o + c) * 0.5)); _oc2.Add((t, (o + c) * 0.5));
_ohl3.Add((t, (o + h + l) * 0.333333333333333)); _ohl3.Add((t, (o + h + l) * 0.333333333333333));
_hlc3.Add((t, (h + l + c) * 0.333333333333333)); _hlc3.Add((t, (h + l + c) * 0.333333333333333));
_ohlc4.Add((t, (o + h + l + c) * 0.25)); _ohlc4.Add((t, (o + h + l + c) * 0.25));
_hlcc4.Add((t, (h + l + c + c) * 0.25)); _hlcc4.Add((t, (h + l + c + c) * 0.25));
} }
this.OnEvent(update); this.OnEvent(update);
} }
// delegate used by event handler + event handler (Pub == publisher) // delegate used by event handler + event handler (Pub == publisher)
public delegate public delegate
void NewDataEventHandler(object source, TSeriesEventArgs args); void NewDataEventHandler(object source, TSeriesEventArgs args);
public event NewDataEventHandler Pub; public event NewDataEventHandler Pub;
// Broadcast handler - only to valid targets // Broadcast handler - only to valid targets
protected virtual void OnEvent(bool update = false) protected virtual void OnEvent(bool update = false)
{ {
if (Pub != null && Pub.Target != this) if (Pub != null && Pub.Target != this)
{ {
Pub(this, new TSeriesEventArgs { update = update }); Pub(this, new TSeriesEventArgs { update = update });
} }
} }
} }
+27 -27
View File
@@ -1,28 +1,28 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
Random Bars generator - used for testing, validation and fun Random Bars generator - used for testing, validation and fun
Returns 'bars' number of candles that follow common market movement. Returns 'bars' number of candles that follow common market movement.
volatility defines how 'jumpy' is the series of volatility defines how 'jumpy' is the series of
startvalue defines beginning closing price that then guides the rest of series startvalue defines beginning closing price that then guides the rest of series
</summary> */ </summary> */
public class RND_Feed : TBars public class RND_Feed : TBars
{ {
public RND_Feed(int bars, double volatility = 0.05, double startvalue = 100.0) public RND_Feed(int bars, double volatility = 0.05, double startvalue = 100.0)
{ {
Random rnd = new(); Random rnd = new();
double c = startvalue; double c = startvalue;
for (int i = 0; i < bars; i++) for (int i = 0; i < bars; i++)
{ {
double o = Math.Round(c + (c * (((volatility * 0.1) * rnd.NextDouble()) - 0.005)), 2); 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 h = Math.Round(o + (c * volatility * rnd.NextDouble()), 2);
double l = 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); c = Math.Round(l + ((h - l) * rnd.NextDouble()), 2);
double v = Math.Round(1000 * rnd.NextDouble(), 2); double v = Math.Round(1000 * rnd.NextDouble(), 2);
this.Add(DateTime.Today.AddDays(i - bars), o, h, l, c, v); this.Add(DateTime.Today.AddDays(i - bars), o, h, l, c, v);
} }
} }
} }
+48 -48
View File
@@ -1,49 +1,49 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
CCI: Commodity Channel Index CCI: Commodity Channel Index
Commodity Channel Index is a momentum oscillator used to primarily identify overbought 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 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: 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 high when prices are far above their average.
- CCI is relatively low when prices are far below 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. Using this method, CCI can be used to identify overbought and oversold levels.
Sources: Sources:
https://www.investopedia.com/terms/c/commoditychannelindex.asp https://www.investopedia.com/terms/c/commoditychannelindex.asp
https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/cci https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/cci
</summary> */ </summary> */
public class CCI_Series : Single_TBars_Indicator public class CCI_Series : Single_TBars_Indicator
{ {
private readonly System.Collections.Generic.List<double> _tp = new(); private readonly System.Collections.Generic.List<double> _tp = new();
public CCI_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) public CCI_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN)
{ {
if (_bars.Count > 0) { base.Add(_bars); } 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) 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; 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 (update) { this._tp[this._tp.Count - 1] = _tpItem; } else { this._tp.Add(_tpItem); }
if (this._tp.Count > this._p) { this._tp.RemoveAt(0); } if (this._tp.Count > this._p) { this._tp.RemoveAt(0); }
// average TP over _tp buffer // average TP over _tp buffer
double _avgTp = 0; double _avgTp = 0;
for (int i = 0; i < this._tp.Count; i++) { _avgTp+=this._tp[i]; } for (int i = 0; i < this._tp.Count; i++) { _avgTp+=this._tp[i]; }
_avgTp /= this._tp.Count; _avgTp /= this._tp.Count;
// average Deviation over _tp buffer // average Deviation over _tp buffer
double _avgDv = 0; double _avgDv = 0;
for (int i = 0; i < this._tp.Count; i++) { _avgDv += Math.Abs(_avgTp - this._tp[i]); } for (int i = 0; i < this._tp.Count; i++) { _avgDv += Math.Abs(_avgTp - this._tp[i]); }
_avgDv /= this._tp.Count; _avgDv /= this._tp.Count;
double _cci = (_avgDv == 0) ? double.NaN : (this._tp[this._tp.Count-1] - _avgTp) / (0.015 * _avgDv); 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); var result = (TBar.t, (this.Count < this._p && this._NaN) ? double.NaN : _cci);
base.Add(result, update); base.Add(result, update);
} }
} }
+72 -71
View File
@@ -1,72 +1,73 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Version>0.1.18</Version> <Title>QuanTAlib</Title>
<releaseNotes> <Product>Library of Technical Indicators for .NET</Product>
</releaseNotes> <Description>Quantitative Technical Analysis library for both real-time (streaming) and historical data analysis</Description>
<Title>QuanTAlib</Title> <RepositoryType>git</RepositoryType>
<Product>Library of Technical Indicators for .NET</Product> <RepositoryUrl>https://github.com/mihakralj/QuanTAlib</RepositoryUrl>
<Description>Quantitative Technical Analysis library for both real-time (streaming) and historical data analysis</Description> <PublishRepositoryUrl>true</PublishRepositoryUrl>
<RepositoryType>git</RepositoryType> <Authors>Miha Kralj</Authors>
<RepositoryUrl>https://github.com/mihakralj/QuanTAlib</RepositoryUrl> <Copyright>Miha Kralj</Copyright>
<PublishRepositoryUrl>true</PublishRepositoryUrl> <PackageReadmeFile>readme.md</PackageReadmeFile>
<Authors>Miha Kralj</Authors> <TargetFrameworks>net7.0;</TargetFrameworks>
<Copyright>Miha Kralj</Copyright> <ImplicitUsings>disable</ImplicitUsings>
<PackageReadmeFile>readme.md</PackageReadmeFile> <LangVersion>preview</LangVersion>
<TargetFrameworks>net7.0;net6.0;netstandard2.0</TargetFrameworks> <Nullable>disable</Nullable>
<ImplicitUsings>disable</ImplicitUsings> <DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>
<LangVersion>preview</LangVersion> <NeutralLanguage>en-US</NeutralLanguage>
<Nullable>disable</Nullable> <RootNamespace>QuanTAlib</RootNamespace>
<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports> <AssemblyName>QuanTAlib</AssemblyName>
<NeutralLanguage>en-US</NeutralLanguage> <IsPublishable>True</IsPublishable>
<RootNamespace>QuanTAlib</RootNamespace> <PlatformTarget>AnyCPU</PlatformTarget>
<AssemblyName>QuanTAlib</AssemblyName> <AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<IsPublishable>True</IsPublishable> <DebugType>embedded</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget> <ProduceReferenceAssembly>True</ProduceReferenceAssembly>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<DebugType>embedded</DebugType> <PackageTags>
<ProduceReferenceAssembly>True</ProduceReferenceAssembly> Indicators;Stock;Market;Technical;Analysis;Algorithmic;Trading;Trade;Trend;Momentum;Finance;Algorithm;Algo;
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> AlgoTrading;Financial;Strategy;Chart;Charting;Oscillator;Overlay;Equity;Bitcoin;Crypto;Cryptocurrency;Forex;
<PackageTags> Quantitative;Historical;Quotes;
Indicators;Stock;Market;Technical;Analysis;Algorithmic;Trading;Trade;Trend;Momentum;Finance;Algorithm;Algo; </PackageTags>
AlgoTrading;Financial;Strategy;Chart;Charting;Oscillator;Overlay;Equity;Bitcoin;Crypto;Cryptocurrency;Forex; <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
Quantitative;Historical;Quotes; <PackageLicenseFile></PackageLicenseFile>
</PackageTags> <SynchReleaseVersion>false</SynchReleaseVersion>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression> </PropertyGroup>
<PackageLicenseFile></PackageLicenseFile> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<SynchReleaseVersion>false</SynchReleaseVersion> <DebugType>full</DebugType>
</PropertyGroup> <Optimize>True</Optimize>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <WarningLevel>7</WarningLevel>
<DebugType>full</DebugType> <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<Optimize>True</Optimize> <PlatformTarget>anycpu</PlatformTarget>
<WarningLevel>7</WarningLevel> </PropertyGroup>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<PlatformTarget>anycpu</PlatformTarget> <DebugType></DebugType>
</PropertyGroup> <Optimize>True</Optimize>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <WarningLevel>7</WarningLevel>
<DebugType></DebugType> <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<Optimize>True</Optimize> <PlatformTarget>anycpu</PlatformTarget>
<WarningLevel>7</WarningLevel> </PropertyGroup>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> <PropertyGroup>
<PlatformTarget>anycpu</PlatformTarget> <PackageIcon>QuanTAlib2.png</PackageIcon>
</PropertyGroup> <PackageIconUrl>https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png</PackageIconUrl>
<PropertyGroup> <EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<PackageIcon>QuanTAlib2.png</PackageIcon> </PropertyGroup>
<PackageIconUrl>https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png</PackageIconUrl> <ItemGroup>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild> <None Include="..\Docs\readme.md">
</PropertyGroup> <Pack>True</Pack>
<ItemGroup> <PackagePath></PackagePath>
<None Include="..\Docs\readme.md"> </None>
<Pack>True</Pack> <None Include="..\.github\QuanTAlib2.png">
<PackagePath></PackagePath> <Pack>True</Pack>
</None> <Visible>False</Visible>
<None Include="..\.github\QuanTAlib2.png"> <PackagePath></PackagePath>
<Pack>True</Pack> </None>
<Visible>False</Visible> </ItemGroup>
<PackagePath></PackagePath> <ItemGroup>
</None> <PackageReference Include="System.Text.Json" Version="6.0.6" />
</ItemGroup> <PackageReference Include="GitVersion.MsBuild" Version="5.6.10*">
<ItemGroup> <PrivateAssets>All</PrivateAssets>
<PackageReference Include="System.Text.Json" Version="6.0.6" /> </PackageReference>
</ItemGroup> </ItemGroup>
</Project> </Project>
+61 -61
View File
@@ -1,62 +1,62 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
KURT: Kurtosis of population KURT: Kurtosis of population
Kurtosis characterizes the relative peakedness or flatness of a distribution Kurtosis characterizes the relative peakedness or flatness of a distribution
compared with the normal distribution. Positive kurtosis indicates a relatively compared with the normal distribution. Positive kurtosis indicates a relatively
peaked distribution. Negative kurtosis indicates a relatively flat distribution. peaked distribution. Negative kurtosis indicates a relatively flat distribution.
The normal curve is called Mesokurtic curve. If the curve of a distribution is 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 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 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. lighter-tailed) than a normal curve, it is called as a platykurtic curve.
Calculation: Calculation:
sum4 = Σ(close-SMA)^4 sum4 = Σ(close-SMA)^4
sum2 = (Σ(close-SMA)^2)^2 sum2 = (Σ(close-SMA)^2)^2
KURT = length * (sum4/sum2) KURT = length * (sum4/sum2)
Sources: Sources:
https://en.wikipedia.org/wiki/Kurtosis https://en.wikipedia.org/wiki/Kurtosis
https://stats.oarc.ucla.edu/other/mult-pkg/faq/general/faq-whats-with-the-different-formulas-for-kurtosis/ https://stats.oarc.ucla.edu/other/mult-pkg/faq/general/faq-whats-with-the-different-formulas-for-kurtosis/
</summary> */ </summary> */
public class KURT_Series : Single_TSeries_Indicator 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) public KURT_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN)
{ {
this._logbase = logbase; this._logbase = logbase;
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
protected double _logbase; protected double _logbase;
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
else { this._buffer.Add(TValue.v); } else { this._buffer.Add(TValue.v); }
if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); }
double _n = this._buffer.Count; double _n = this._buffer.Count;
double _avg = 0; double _avg = 0;
for (int i = 0; i < this._buffer.Count; i++) { _avg += this._buffer[i]; } for (int i = 0; i < this._buffer.Count; i++) { _avg += this._buffer[i]; }
_avg /= _n; _avg /= _n;
double _s2 = 0; double _s2 = 0;
double _s4 = 0; double _s4 = 0;
for (int i = 0; i < this._buffer.Count; i++) for (int i = 0; i < this._buffer.Count; i++)
{ {
_s2 += (this._buffer[i] - _avg) * (this._buffer[i] - _avg); _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); _s4 += (this._buffer[i] - _avg) * (this._buffer[i] - _avg) * (this._buffer[i] - _avg) * (this._buffer[i] - _avg);
} }
double _Vx = _s2 / (_n - 1); 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; 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); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? Double.NaN : _kurt);
base.Add(result, update); base.Add(result, update);
} }
} }
+47 -47
View File
@@ -1,47 +1,47 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
MED - Median value MED - Median value
Median of numbers is the middlemost value of the given set of numbers. 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. 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 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. 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 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, 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. median is the average of (n/2)th and [(n/2) + 1]th values of the sorted list.
If period = 0 => period is max If period = 0 => period is max
Sources: Sources:
https://corporatefinanceinstitute.com/resources/knowledge/other/median/ https://corporatefinanceinstitute.com/resources/knowledge/other/median/
https://en.wikipedia.org/wiki/Median https://en.wikipedia.org/wiki/Median
</summary> */ </summary> */
public class MED_Series : Single_TSeries_Indicator public class MED_Series : Single_TSeries_Indicator
{ {
public MED_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public MED_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
else { this._buffer.Add(TValue.v); } else { this._buffer.Add(TValue.v); }
if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); }
System.Collections.Generic.List<double> _s = new(this._buffer); System.Collections.Generic.List<double> _s = new(this._buffer);
_s.Sort(); _s.Sort();
int _p1 = _s.Count / 2; int _p1 = _s.Count / 2;
int _p2 = Math.Max(0, (_s.Count / 2) - 1); int _p2 = Math.Max(0, (_s.Count / 2) - 1);
double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2; 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); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _med);
base.Add(result, update); base.Add(result, update);
} }
} }
+42 -42
View File
@@ -1,43 +1,43 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
SVAR: Sample Variance SVAR: Sample Variance
Sample variance uses Bessel's correction to correct the bias in the estimation of population variance. Sample variance uses Bessel's correction to correct the bias in the estimation of population variance.
Sources: Sources:
https://en.wikipedia.org/wiki/Variance https://en.wikipedia.org/wiki/Variance
Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
Remark: Remark:
SVAR is also known as the Unbiased Sample Variance, while VAR (Population Variance) is known as SVAR is also known as the Unbiased Sample Variance, while VAR (Population Variance) is known as
the Biased Sample Variance. the Biased Sample Variance.
</summary> */ </summary> */
public class SVAR_Series : Single_TSeries_Indicator public class SVAR_Series : Single_TSeries_Indicator
{ {
public SVAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public SVAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
else { this._buffer.Add(TValue.v); } else { this._buffer.Add(TValue.v); }
if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); } if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); }
double _sma = 0; double _sma = 0;
for (int i = 0; i < this._buffer.Count; i++) { _sma += this._buffer[i]; } for (int i = 0; i < this._buffer.Count; i++) { _sma += this._buffer[i]; }
_sma /= this._buffer.Count; _sma /= this._buffer.Count;
double _svar = 0; double _svar = 0;
for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); } 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 _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); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _svar);
base.Add(result, update); base.Add(result, update);
} }
} }
+42 -42
View File
@@ -1,43 +1,43 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
VAR: Population Variance VAR: Population Variance
Population variance without Bessel's correction Population variance without Bessel's correction
Sources: Sources:
https://en.wikipedia.org/wiki/Variance https://en.wikipedia.org/wiki/Variance
Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
Remark: Remark:
VAR (Population Variance) is also known as a biased Sample Variance. For unbiased VAR (Population Variance) is also known as a biased Sample Variance. For unbiased
sample variance use SVAR instead. sample variance use SVAR instead.
</summary> */ </summary> */
public class VAR_Series : Single_TSeries_Indicator public class VAR_Series : Single_TSeries_Indicator
{ {
public VAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public VAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update) { _buffer[_buffer.Count - 1] = TValue.v; } if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
else { _buffer.Add(TValue.v); } else { _buffer.Add(TValue.v); }
if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); } if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
double _sma = 0; double _sma = 0;
for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
_sma /= this._buffer.Count; _sma /= this._buffer.Count;
double _pvar = 0; double _pvar = 0;
for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
_pvar /= this._buffer.Count; _pvar /= this._buffer.Count;
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _pvar); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _pvar);
base.Add(result, update); base.Add(result, update);
} }
} }
+65 -65
View File
@@ -1,65 +1,65 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
ALMA: Arnaud Legoux Moving Average ALMA: Arnaud Legoux Moving Average
The ALMA moving average uses the curve of the Normal (Gauss) distribution, which 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 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 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 the shape of the curve coefficients. This moving average reduces lag of the data
in conjunction with smoothing to reduce noise. in conjunction with smoothing to reduce noise.
Sources: Sources:
https://phemex.com/academy/what-is-arnaud-legoux-moving-averages https://phemex.com/academy/what-is-arnaud-legoux-moving-averages
https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/ https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/
</summary> */ </summary> */
public class ALMA_Series : Single_TSeries_Indicator public class ALMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly double[] _weight; private readonly double[] _weight;
private double _norm; private double _norm;
private readonly double _offset, _sigma; private readonly double _offset, _sigma;
public ALMA_Series(TSeries source, int period, double offset = 0.85, double sigma = 6.0, bool useNaN = false) public ALMA_Series(TSeries source, int period, double offset = 0.85, double sigma = 6.0, bool useNaN = false)
: base(source, period, useNaN) : base(source, period, useNaN)
{ {
_offset = offset; _offset = offset;
_sigma = sigma; _sigma = sigma;
_weight = new double[period]; _weight = new double[period];
if (this._data.Count > 0) { base.Add(this._data); } if (this._data.Count > 0) { base.Add(this._data); }
} }
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
else { this._buffer.Add(TValue.v); } else { this._buffer.Add(TValue.v); }
if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); }
if (this._buffer.Count <= _p) { calc_weights(); } if (this._buffer.Count <= _p) { calc_weights(); }
double _weightedSum = 0; double _weightedSum = 0;
for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; } for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; }
double _alma = _weightedSum / _norm; double _alma = _weightedSum / _norm;
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _alma); var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _alma);
base.Add(ret, update); base.Add(ret, update);
} }
private void calc_weights() private void calc_weights()
{ {
int _len = this._buffer.Count; int _len = this._buffer.Count;
_norm = 0; _norm = 0;
double _m = _offset * (_len - 1); double _m = _offset * (_len - 1);
double _s = _len / _sigma; double _s = _len / _sigma;
for (int i = 0; i < _len; i++) for (int i = 0; i < _len; i++)
{ {
double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s)); double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
_weight[i] = _wt; _weight[i] = _wt;
_norm += _wt; _norm += _wt;
} }
} }
} }
+71 -71
View File
@@ -1,71 +1,71 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
DEMA: Double Exponential Moving Average DEMA: Double Exponential Moving Average
DEMA uses EMA(EMA()) to calculate smoother Exponential moving average. DEMA uses EMA(EMA()) to calculate smoother Exponential moving average.
Sources: Sources:
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/double-exponential-moving-average-dema/ https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/double-exponential-moving-average-dema/
Remark: Remark:
ema1 = EMA(close, length) ema1 = EMA(close, length)
ema2 = EMA(ema1, length) ema2 = EMA(ema1, length)
DEMA = 2 * ema1 - ema2 DEMA = 2 * ema1 - ema2
</summary> */ </summary> */
public class DEMA_Series : Single_TSeries_Indicator public class DEMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly double _k, _k1m; private readonly double _k, _k1m;
private double _lastema1, _lastlastema1; private double _lastema1, _lastlastema1;
private double _lastema2, _lastlastema2; private double _lastema2, _lastlastema2;
public DEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public DEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
this._k = 2.0 / (this._p + 1); this._k = 2.0 / (this._p + 1);
this._k1m = 1.0 - this._k; this._k1m = 1.0 - this._k;
if (_data.Count > 0) { base.Add(_data); } if (_data.Count > 0) { base.Add(_data); }
} }
public override void Add((DateTime t, double v) TValue, bool update) public override void Add((DateTime t, double v) TValue, bool update)
{ {
if (update) if (update)
{ {
this._lastema1 = this._lastlastema1; this._lastema1 = this._lastlastema1;
this._lastema2 = this._lastlastema2; this._lastema2 = this._lastlastema2;
} }
double _ema1, _ema2; double _ema1, _ema2;
if (this.Count < this._p) if (this.Count < this._p)
{ {
if (update) { _buffer[_buffer.Count - 1] = TValue.v; } if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
else else
{ {
_buffer.Add(TValue.v); _buffer.Add(TValue.v);
} }
if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } if (_buffer.Count > this._p) { _buffer.RemoveAt(0); }
double _sma = 0; double _sma = 0;
for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
_sma /= this._buffer.Count; _sma /= this._buffer.Count;
_ema1 = _ema2 = _sma; _ema1 = _ema2 = _sma;
} }
else else
{ {
_ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m); _ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m);
_ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m); _ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m);
} }
double _dema = (2 * _ema1) - _ema2; double _dema = (2 * _ema1) - _ema2;
this._lastlastema1 = this._lastema1; this._lastlastema1 = this._lastema1;
this._lastlastema2 = this._lastema2; this._lastlastema2 = this._lastema2;
this._lastema1 = _ema1; this._lastema1 = _ema1;
this._lastema2 = _ema2; this._lastema2 = _ema2;
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _dema); var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _dema);
base.Add(ret, update); base.Add(ret, update);
} }
} }
+63 -63
View File
@@ -1,64 +1,64 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
EMA: Exponential Moving Average EMA: Exponential Moving Average
EMA needs very short history buffer and calculates the EMA value using just the 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) previous EMA value. The weight of the new datapoint (k) is k = 2 / (period-1)
Sources: Sources:
https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages 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://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 https://blog.fugue88.ws/archives/2017-01/The-correct-way-to-start-an-Exponential-Moving-Average-EMA
Issues: Issues:
There is no consensus what the first EMA value should be - a zero, a first 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 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) 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. use SMA() for the first Period bars as a seeding value for EMA.
</summary> */ </summary> */
public class EMA_Series : Single_TSeries_Indicator public class EMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly double _k, _k1m; private readonly double _k, _k1m;
private double _lastema, _lastlastema; private double _lastema, _lastlastema;
public EMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public EMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
this._k = 2.0 / (this._p + 1); this._k = 2.0 / (this._p + 1);
this._k1m = 1.0 - this._k; this._k1m = 1.0 - this._k;
this._lastema = this._lastlastema = double.NaN; this._lastema = this._lastlastema = double.NaN;
if (this._data.Count > 0) { base.Add(this._data); } if (this._data.Count > 0) { base.Add(this._data); }
} }
public override void Add((DateTime t, double v) TValue, bool update) public override void Add((DateTime t, double v) TValue, bool update)
{ {
double _ema = 0; double _ema = 0;
if (update) { this._lastema = this._lastlastema; } if (update) { this._lastema = this._lastlastema; }
if (this.Count < this._p) if (this.Count < this._p)
{ {
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
else else
{ {
this._buffer.Add(TValue.v); this._buffer.Add(TValue.v);
} }
if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); }
for (int i = 0; i < this._buffer.Count; i++) { _ema += this._buffer[i]; } for (int i = 0; i < this._buffer.Count; i++) { _ema += this._buffer[i]; }
_ema /= this._buffer.Count; _ema /= this._buffer.Count;
} }
else else
{ {
_ema = (TValue.v * this._k) + (this._lastema * this._k1m); _ema = (TValue.v * this._k) + (this._lastema * this._k1m);
} }
this._lastlastema = this._lastema; this._lastlastema = this._lastema;
this._lastema = _ema; this._lastema = _ema;
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema);
base.Add(ret, update); base.Add(ret, update);
} }
} }
+64 -64
View File
@@ -1,65 +1,65 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
HEMA: Hull-EMA Moving Average HEMA: Hull-EMA Moving Average
Modified HUll Moving Average; instead of using WMA (Weighted MA) for acalculation, Modified HUll Moving Average; instead of using WMA (Weighted MA) for acalculation,
HEMA uses EMA for Hull's formula: HEMA uses EMA for Hull's formula:
EMA1 = EMA(n/2) of price - where k = 4/(n/2 +1) EMA1 = EMA(n/2) of price - where k = 4/(n/2 +1)
EMA2 = EMA(n) of price - where k = 3/(n+1) EMA2 = EMA(n) of price - where k = 3/(n+1)
Raw HMA = (2 * EMA1) - EMA2 Raw HMA = (2 * EMA1) - EMA2
EMA3 = EMA(sqrt(n)) of Raw HMA - where k = 2/(sqrt(n)+1) EMA3 = EMA(sqrt(n)) of Raw HMA - where k = 2/(sqrt(n)+1)
</summary> */ </summary> */
public class HEMA_Series : Single_TSeries_Indicator public class HEMA_Series : Single_TSeries_Indicator
{ {
public HEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public HEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
this._k1 = 4 / ((period * 0.5) + 1); this._k1 = 4 / ((period * 0.5) + 1);
this._k2 = 3 / (double)(period + 1); this._k2 = 3 / (double)(period + 1);
this._k3 = 2 / (Math.Sqrt(period) + 1); this._k3 = 2 / (Math.Sqrt(period) + 1);
this._lastema1 = this._lastlastema1 = double.NaN; this._lastema1 = this._lastlastema1 = double.NaN;
this._lastema2 = this._lastlastema2 = double.NaN; this._lastema2 = this._lastlastema2 = double.NaN;
this._lastema3 = this._lastlastema3 = double.NaN; this._lastema3 = this._lastlastema3 = double.NaN;
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
private readonly double _k1, _k2, _k3; private readonly double _k1, _k2, _k3;
private double _lastema1, _lastlastema1; private double _lastema1, _lastlastema1;
private double _lastema2, _lastlastema2; private double _lastema2, _lastlastema2;
private double _lastema3, _lastlastema3; private double _lastema3, _lastlastema3;
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update) if (update)
{ {
this._lastema1 = this._lastlastema1; this._lastema1 = this._lastlastema1;
this._lastema2 = this._lastlastema2; this._lastema2 = this._lastlastema2;
this._lastema3 = this._lastlastema3; this._lastema3 = this._lastlastema3;
} }
double _ema1 = System.Double.IsNaN(this._lastema1) double _ema1 = System.Double.IsNaN(this._lastema1)
? TValue.v ? TValue.v
: TValue.v * this._k1 + this._lastema1 * (1 - this._k1); : TValue.v * this._k1 + this._lastema1 * (1 - this._k1);
double _ema2 = System.Double.IsNaN(this._lastema2) double _ema2 = System.Double.IsNaN(this._lastema2)
? TValue.v ? TValue.v
: TValue.v * this._k2 + this._lastema2 * (1 - this._k2); : TValue.v * this._k2 + this._lastema2 * (1 - this._k2);
double _rawhema = (2 * _ema1) - _ema2; double _rawhema = (2 * _ema1) - _ema2;
double _ema3 = System.Double.IsNaN(this._lastema3) double _ema3 = System.Double.IsNaN(this._lastema3)
? _rawhema ? _rawhema
: _rawhema * this._k3 + this._lastema3 * (1 - this._k3); : _rawhema * this._k3 + this._lastema3 * (1 - this._k3);
this._lastlastema1 = this._lastema1; this._lastlastema1 = this._lastema1;
this._lastlastema2 = this._lastema2; this._lastlastema2 = this._lastema2;
this._lastlastema3 = this._lastema3; this._lastlastema3 = this._lastema3;
this._lastema1 = _ema1; this._lastema1 = _ema1;
this._lastema2 = _ema2; this._lastema2 = _ema2;
this._lastema3 = _ema3; this._lastema3 = _ema3;
(System.DateTime t, double v) result = (System.DateTime t, double v) result =
(TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _ema3); (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _ema3);
base.Add(result, update); base.Add(result, update);
} }
} }
+120 -120
View File
@@ -1,120 +1,120 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
HMA: Hull Moving Average HMA: Hull Moving Average
Developed by Alan Hull, an extremely fast and smooth moving average; almost Developed by Alan Hull, an extremely fast and smooth moving average; almost
eliminates lag altogether and manages to improve smoothing at the same time. eliminates lag altogether and manages to improve smoothing at the same time.
Sources: Sources:
https://alanhull.com/hull-moving-average https://alanhull.com/hull-moving-average
https://school.stockcharts.com/doku.php?id=technical_indicators:hull_moving_average https://school.stockcharts.com/doku.php?id=technical_indicators:hull_moving_average
WMA1 = WMA(n/2) of price WMA1 = WMA(n/2) of price
WMA2 = WMA(n) of price WMA2 = WMA(n) of price
Raw HMA = (2 * WMA1) - WMA2 Raw HMA = (2 * WMA1) - WMA2
HMA = WMA(sqrt(n)) of Raw HMA HMA = WMA(sqrt(n)) of Raw HMA
</summary> */ </summary> */
public class HMA_Series : TSeries public class HMA_Series : TSeries
{ {
private readonly int _p; private readonly int _p;
private readonly bool _NaN; private readonly bool _NaN;
private readonly TSeries _data; private readonly TSeries _data;
private double _wma1, _wma2; private double _wma1, _wma2;
private readonly System.Collections.Generic.List<double> _buf1 = new(); private readonly System.Collections.Generic.List<double> _buf1 = new();
private readonly System.Collections.Generic.List<double> _buf2 = new(); private readonly System.Collections.Generic.List<double> _buf2 = new();
private readonly System.Collections.Generic.List<double> _buf3 = new(); private readonly System.Collections.Generic.List<double> _buf3 = new();
private readonly System.Collections.Generic.List<double> _weights = new(); private readonly System.Collections.Generic.List<double> _weights = new();
public HMA_Series(TSeries source, int period, bool useNaN = false) public HMA_Series(TSeries source, int period, bool useNaN = false)
{ {
this._p = period; this._p = period;
this._data = source; this._data = source;
this._NaN = useNaN; this._NaN = useNaN;
for (int i = 0; i < this._p; i++) for (int i = 0; i < this._p; i++)
{ {
this._weights.Add(i + 1); this._weights.Add(i + 1);
} }
source.Pub += this.Sub; source.Pub += this.Sub;
if (source.Count > 0) if (source.Count > 0)
{ {
for (int i = 0; i < source.Count; i++) for (int i = 0; i < source.Count; i++)
{ {
this.Add(source[i], false); this.Add(source[i], false);
} }
} }
} }
public new void Add((System.DateTime t, double v) data, bool update = false) public new void Add((System.DateTime t, double v) data, bool update = false)
{ {
if (update) if (update)
{ {
this._buf1[this._buf1.Count - 1] = data.v; this._buf1[this._buf1.Count - 1] = data.v;
this._buf2[this._buf2.Count - 1] = data.v; this._buf2[this._buf2.Count - 1] = data.v;
} }
else else
{ {
this._buf1.Add(data.v); this._buf1.Add(data.v);
this._buf2.Add(data.v); this._buf2.Add(data.v);
} }
if (this._buf1.Count > (int)((double)this._p / 2)) if (this._buf1.Count > (int)((double)this._p / 2))
{ {
this._buf1.RemoveAt(0); this._buf1.RemoveAt(0);
} }
if (this._buf2.Count > this._p) if (this._buf2.Count > this._p)
{ {
this._buf2.RemoveAt(0); this._buf2.RemoveAt(0);
} }
this._wma1 = 0; this._wma1 = 0;
for (int i = 0; i < this._buf1.Count; i++) for (int i = 0; i < this._buf1.Count; i++)
{ {
this._wma1 += this._buf1[i] * this._weights[i]; this._wma1 += this._buf1[i] * this._weights[i];
} }
this._wma1 /= (this._buf1.Count * (this._buf1.Count + 1)) * 0.5; this._wma1 /= (this._buf1.Count * (this._buf1.Count + 1)) * 0.5;
this._wma2 = 0; this._wma2 = 0;
for (int i = 0; i < this._buf2.Count; i++) for (int i = 0; i < this._buf2.Count; i++)
{ {
this._wma2 += this._buf2[i] * this._weights[i]; this._wma2 += this._buf2[i] * this._weights[i];
} }
this._wma2 /= (this._buf2.Count * (this._buf2.Count + 1)) * 0.5; this._wma2 /= (this._buf2.Count * (this._buf2.Count + 1)) * 0.5;
if (update) if (update)
{ {
this._buf3[this._buf3.Count - 1] = 2 * this._wma1 - this._wma2; this._buf3[this._buf3.Count - 1] = 2 * this._wma1 - this._wma2;
} }
else else
{ {
this._buf3.Add(2 * this._wma1 - this._wma2); this._buf3.Add(2 * this._wma1 - this._wma2);
} }
if (this._buf3.Count > (int)Math.Sqrt(this._p)) if (this._buf3.Count > (int)Math.Sqrt(this._p))
{ {
this._buf3.RemoveAt(0); this._buf3.RemoveAt(0);
} }
double _hma = 0; double _hma = 0;
for (int i = 0; i < this._buf3.Count; i++) for (int i = 0; i < this._buf3.Count; i++)
{ {
_hma += this._buf3[i] * this._weights[i]; _hma += this._buf3[i] * this._weights[i];
} }
_hma /= (this._buf3.Count * (this._buf3.Count + 1)) * 0.5; _hma /= (this._buf3.Count * (this._buf3.Count + 1)) * 0.5;
(System.DateTime t, double v) result = (System.DateTime t, double v) result =
(data.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _hma); (data.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _hma);
base.Add(result, update); base.Add(result, update);
} }
public void Add(bool update = false) public void Add(bool update = false)
{ {
this.Add(this._data[this._data.Count - 1], update); this.Add(this._data[this._data.Count - 1], update);
} }
public new void Sub(object source, TSeriesEventArgs e) public new void Sub(object source, TSeriesEventArgs e)
{ {
this.Add(this._data[this._data.Count - 1], e.update); this.Add(this._data[this._data.Count - 1], e.update);
} }
} }
+160 -160
View File
@@ -1,161 +1,161 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
JMA: Jurik Moving Average JMA: Jurik Moving Average
Mark Jurik's Moving Average (JMA) attempts to eliminate noise to see the 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 underlying activity. It has extremely low lag, is very smooth and is responsive
to market gaps. to market gaps.
Sources: Sources:
https://c.mql5.com/forextsd/forum/164/jurik_1.pdf https://c.mql5.com/forextsd/forum/164/jurik_1.pdf
https://www.prorealcode.com/prorealtime-indicators/jurik-volatility-bands/ https://www.prorealcode.com/prorealtime-indicators/jurik-volatility-bands/
Issues: Issues:
Real JMA algorithm is not published and this formula is derived through 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 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 exact - published JMA tests against JMA.CSV fail with small deviation. The
original algo is slightly different, yet this approximation is close enough. original algo is slightly different, yet this approximation is close enough.
</summary> </summary>
TODO: buggy - rework TODO: buggy - rework
*/ */
public class JMA_Series : Single_TSeries_Indicator public class JMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> vbuffer10; private readonly System.Collections.Generic.List<double> vbuffer10;
private readonly System.Collections.Generic.List<double> vsum65; private readonly System.Collections.Generic.List<double> vsum65;
private double prev_ma1, prev_det0, prev_det1, prev_jma, bsmax, bsmin; 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 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; 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) public JMA_Series(TSeries source, int period, double phase = 0.0, bool useNaN = false) : base(source, period, useNaN)
{ {
this.vbuffer10 = new(); this.vbuffer10 = new();
this.vsum65 = new(); this.vsum65 = new();
// constants // constants
this.pr = (phase < -100) ? 0.5 : (phase > 100) ? 2.5 : (phase * 0.01) + 1.5; 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); 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.pow1 = Math.Max(len1 - 2, 0.5);
this.rvolty = Math.Exp((1 / this.pow1) * Math.Log(len1)); this.rvolty = Math.Exp((1 / this.pow1) * Math.Log(len1));
this.len2 = Math.Sqrt(0.5 * (_p - 1)) * len1; this.len2 = Math.Sqrt(0.5 * (_p - 1)) * len1;
this.beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2); this.beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2);
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (this.Count == 0) if (this.Count == 0)
{ {
this.prev_ma1 = this.prev_jma = TValue.v; this.prev_ma1 = this.prev_jma = TValue.v;
this.bsmax = this.bsmin = this.prev_det0 = this.prev_det1 = 0; this.bsmax = this.bsmin = this.prev_det0 = this.prev_det1 = 0;
} }
if (update) if (update)
{ {
this.prev_jma = this.o_prev_jma; this.prev_jma = this.o_prev_jma;
this.prev_ma1 = this.o_prev_ma1; this.prev_ma1 = this.o_prev_ma1;
this.prev_det0 = this.o_prev_det0; this.prev_det0 = this.o_prev_det0;
this.prev_det1 = this.o_prev_det1; this.prev_det1 = this.o_prev_det1;
this.bsmax = this.o_bsmax; this.bsmax = this.o_bsmax;
this.bsmin = this.o_bsmin; this.bsmin = this.o_bsmin;
} }
else else
{ {
this.o_prev_jma = this.prev_jma; this.o_prev_jma = this.prev_jma;
this.o_prev_ma1 = this.prev_ma1; this.o_prev_ma1 = this.prev_ma1;
this.o_prev_det0 = this.prev_det0; this.o_prev_det0 = this.prev_det0;
this.o_prev_det1 = this.prev_det1; this.o_prev_det1 = this.prev_det1;
this.o_bsmax = this.bsmax; this.o_bsmax = this.bsmax;
this.o_bsmin = this.bsmin; this.o_bsmin = this.bsmin;
} }
double hprice = TValue.v; double hprice = TValue.v;
double lprice = TValue.v; double lprice = TValue.v;
for (int i = 0; i <= Math.Min(9, this._data.Count - 1); i++) for (int i = 0; i <= Math.Min(9, this._data.Count - 1); i++)
{ {
var _item = this._data[this._data.Count - 1 - i].v; var _item = this._data[this._data.Count - 1 - i].v;
hprice = (_item > hprice) ? _item : hprice; hprice = (_item > hprice) ? _item : hprice;
lprice = (_item < lprice) ? _item : lprice; lprice = (_item < lprice) ? _item : lprice;
} }
double del1 = hprice - this.bsmax; double del1 = hprice - this.bsmax;
double del2 = lprice - this.bsmin; double del2 = lprice - this.bsmin;
double volty = (Math.Abs(del1) != Math.Abs(del2)) double volty = (Math.Abs(del1) != Math.Abs(del2))
? Math.Max(Math.Abs(del1), Math.Abs(del2)) ? Math.Max(Math.Abs(del1), Math.Abs(del2))
: 0; : 0;
if (update) if (update)
{ {
this.vbuffer10[this.vbuffer10.Count - 1] = volty; this.vbuffer10[this.vbuffer10.Count - 1] = volty;
} }
else else
{ {
this.vbuffer10.Add(volty); this.vbuffer10.Add(volty);
} }
if (this.vbuffer10.Count > 10) if (this.vbuffer10.Count > 10)
{ {
this.vbuffer10.RemoveAt(0); this.vbuffer10.RemoveAt(0);
} }
double prevvsum = double prevvsum =
(this.vsum65.Count > 0) ? this.vsum65[this.vsum65.Count - 1] : 0; (this.vsum65.Count > 0) ? this.vsum65[this.vsum65.Count - 1] : 0;
double vsumitem = prevvsum + 0.1 * (volty - this.vbuffer10[0]); double vsumitem = prevvsum + 0.1 * (volty - this.vbuffer10[0]);
if (update) if (update)
{ {
this.vsum65[this.vsum65.Count - 1] = vsumitem; this.vsum65[this.vsum65.Count - 1] = vsumitem;
} }
else else
{ {
this.vsum65.Add(vsumitem); this.vsum65.Add(vsumitem);
} }
if (this.vsum65.Count > 65) if (this.vsum65.Count > 65)
{ {
this.vsum65.RemoveAt(0); this.vsum65.RemoveAt(0);
} }
double avolty = 0; double avolty = 0;
for (int i = 0; i < this.vsum65.Count; i++) for (int i = 0; i < this.vsum65.Count; i++)
{ {
avolty += this.vsum65[i]; avolty += this.vsum65[i];
} }
avolty /= this.vsum65.Count; avolty /= this.vsum65.Count;
double dvolty = (avolty > 0) ? volty / avolty : 0; double dvolty = (avolty > 0) ? volty / avolty : 0;
dvolty = Math.Max((dvolty > this.rvolty) ? this.rvolty : dvolty, 1.0); dvolty = Math.Max((dvolty > this.rvolty) ? this.rvolty : dvolty, 1.0);
double pow2 = Math.Exp(this.pow1 * Math.Log(dvolty)); double pow2 = Math.Exp(this.pow1 * Math.Log(dvolty));
double kv = double kv =
Math.Exp(Math.Sqrt(pow2) * Math.Log(this.len2 / (this.len2 + 1))); Math.Exp(Math.Sqrt(pow2) * Math.Log(this.len2 / (this.len2 + 1)));
this.bsmax = (del1 > 0) ? hprice : hprice - (kv * del1); this.bsmax = (del1 > 0) ? hprice : hprice - (kv * del1);
this.bsmin = (del2 < 0) ? lprice : lprice - (kv * del2); this.bsmin = (del2 < 0) ? lprice : lprice - (kv * del2);
// adaptive EMA dynamic factor // adaptive EMA dynamic factor
double pow = Math.Pow(dvolty, this.pow1); double pow = Math.Pow(dvolty, this.pow1);
double alpha = Math.Pow(this.beta, pow); double alpha = Math.Pow(this.beta, pow);
// 1st stage - preliminary smoothing by adaptive EMA // 1st stage - preliminary smoothing by adaptive EMA
double ma1 = TValue.v * (1 - alpha) + this.prev_ma1 * alpha; double ma1 = TValue.v * (1 - alpha) + this.prev_ma1 * alpha;
this.prev_ma1 = ma1; this.prev_ma1 = ma1;
// 2nd stage - one more preliminary smoothing by Kalman filter // 2nd stage - one more preliminary smoothing by Kalman filter
double det0 = (TValue.v - ma1) * (1 - this.beta) + this.prev_det0 * this.beta; double det0 = (TValue.v - ma1) * (1 - this.beta) + this.prev_det0 * this.beta;
this.prev_det0 = det0; this.prev_det0 = det0;
double ma2 = ma1 + (this.pr * det0); double ma2 = ma1 + (this.pr * det0);
// 3rd stage - final smoothing by Jurik adaptive filter // 3rd stage - final smoothing by Jurik adaptive filter
double det1 = ((ma2 - this.prev_jma) * (1 - alpha) * (1 - alpha)) + double det1 = ((ma2 - this.prev_jma) * (1 - alpha) * (1 - alpha)) +
(this.prev_det1 * alpha * alpha); (this.prev_det1 * alpha * alpha);
this.prev_det1 = det1; this.prev_det1 = det1;
var jma = this.prev_jma + det1; var jma = this.prev_jma + det1;
this.prev_jma = jma; this.prev_jma = jma;
(System.DateTime t, double v) result = (System.DateTime t, double v) result =
(TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : jma); (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : jma);
base.Add(result, update); base.Add(result, update);
} }
} }
+64 -64
View File
@@ -1,65 +1,65 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
KAMA: Kaufman's Adaptive Moving Average KAMA: Kaufman's Adaptive Moving Average
Created in 1988 by American quantitative finance theorist Perry J. Kaufman and is known as 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, 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 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 available to the public. Unlike other conventional moving averages systems, the Kaufman's Adaptive
Moving Average, considers market volatility apart from price fluctuations. Moving Average, considers market volatility apart from price fluctuations.
KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 ) KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 )
Sources: Sources:
https://www.tutorialspoint.com/kaufman-s-adaptive-moving-average-kama-formula-and-how-does-it-work 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://corporatefinanceinstitute.com/resources/knowledge/trading-investing/kaufmans-adaptive-moving-average-kama/
https://www.technicalindicators.net/indicators-technical-analysis/152-kama-kaufman-adaptive-moving-average https://www.technicalindicators.net/indicators-technical-analysis/152-kama-kaufman-adaptive-moving-average
Remark: Remark:
If useNaN:true argument is provided, KAMA starts calculating values from [period] bar onwards. 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 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. slightly different results for the first 50 bars - and then converges with the other one.
</summary> */ </summary> */
public class KAMA_Series : Single_TSeries_Indicator public class KAMA_Series : Single_TSeries_Indicator
{ {
private readonly double _scFast, _scSlow; private readonly double _scFast, _scSlow;
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private double _lastkama = double.NaN; private double _lastkama = double.NaN;
private double _lastlastkama; private double _lastlastkama;
public KAMA_Series(TSeries source, int period, int fast = 2, int slow= 30, bool useNaN = false) : base(source, period, useNaN) { 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); _scFast = 2.0 / (fast+1);
_scSlow = 2.0 / (slow+1); _scSlow = 2.0 / (slow+1);
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update){ if (update){
_buffer[_buffer.Count - 1] = TValue.v; _buffer[_buffer.Count - 1] = TValue.v;
this._lastkama = this._lastlastkama; this._lastkama = this._lastlastkama;
} else { } else {
_buffer.Add(TValue.v); _buffer.Add(TValue.v);
} }
if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); } if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); }
double _kama = 0; double _kama = 0;
if (this.Count < this._p) { if (this.Count < this._p) {
for (int i = 0; i < this._buffer.Count; i++) { _kama += this._buffer[i]; } for (int i = 0; i < this._buffer.Count; i++) { _kama += this._buffer[i]; }
_kama /= this._buffer.Count; _kama /= this._buffer.Count;
} else { } else {
double _change = Math.Abs(_buffer[_buffer.Count - 1] - _buffer[(_buffer.Count > _p + 1) ? 1 : 0]); double _change = Math.Abs(_buffer[_buffer.Count - 1] - _buffer[(_buffer.Count > _p + 1) ? 1 : 0]);
double _sumpv = 0; double _sumpv = 0;
for (int i = 1; i < _buffer.Count; i++) for (int i = 1; i < _buffer.Count; i++)
{ _sumpv += Math.Abs(_buffer[(_buffer.Count > 0) ? i : 0] - _buffer[i - 1]); } { _sumpv += Math.Abs(_buffer[(_buffer.Count > 0) ? i : 0] - _buffer[i - 1]); }
double _er = (_sumpv == 0) ? 0 : _change / _sumpv; double _er = (_sumpv == 0) ? 0 : _change / _sumpv;
double _sc = (_er * (_scFast - _scSlow)) + _scSlow; double _sc = (_er * (_scFast - _scSlow)) + _scSlow;
_kama = (_lastkama + (_sc * _sc * (TValue.v - _lastkama))); _kama = (_lastkama + (_sc * _sc * (TValue.v - _lastkama)));
} }
_lastlastkama = _lastkama; _lastlastkama = _lastkama;
_lastkama = _kama; _lastkama = _kama;
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _kama); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _kama);
base.Add(result, update); base.Add(result, update);
} }
} }
+45 -45
View File
@@ -1,46 +1,46 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
MACD: Moving Average Convergence/Divergence MACD: Moving Average Convergence/Divergence
Moving average convergence divergence (MACD) is a trend-following momentum Moving average convergence divergence (MACD) is a trend-following momentum
indicator that shows the relationship between two moving averages of a series. 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) 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. from the 12-period EMA. MACD Signal is 9-day EMA of MACD.
Sources: Sources:
https://www.investopedia.com/terms/m/macd.asp https://www.investopedia.com/terms/m/macd.asp
https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/macd https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/macd
</summary> */ </summary> */
public class MACD_Series : Single_TSeries_Indicator public class MACD_Series : Single_TSeries_Indicator
{ {
private readonly EMA_Series _TSslow; private readonly EMA_Series _TSslow;
private readonly EMA_Series _TSfast; private readonly EMA_Series _TSfast;
private readonly SUB_Series _TSmacd; private readonly SUB_Series _TSmacd;
public EMA_Series Signal { get; } public EMA_Series Signal { get; }
public MACD_Series(TSeries source, int slow = 26, int fast = 12, int signal = 9, bool useNaN = false) public MACD_Series(TSeries source, int slow = 26, int fast = 12, int signal = 9, bool useNaN = false)
: base(source, period: 0, useNaN) : base(source, period: 0, useNaN)
{ {
_TSslow = new(source: source, period: slow, useNaN: false); _TSslow = new(source: source, period: slow, useNaN: false);
_TSfast = new(source: source, period: fast, useNaN: false); _TSfast = new(source: source, period: fast, useNaN: false);
_TSmacd = new(_TSfast, _TSslow); _TSmacd = new(_TSfast, _TSslow);
this.Signal = new(source: _TSmacd, period: signal, useNaN: useNaN); this.Signal = new(source: _TSmacd, period: signal, useNaN: useNaN);
if (source.Count > 0) { base.Add(_TSmacd); } if (source.Count > 0) { base.Add(_TSmacd); }
} }
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
double _macd; double _macd;
if (update) if (update)
{ {
_TSslow.Add(TValue, true); _TSslow.Add(TValue, true);
_TSfast.Add(TValue, true); _TSfast.Add(TValue, true);
} }
_macd = this._TSmacd[(this.Count < this._TSmacd.Count) ? this.Count : this._TSmacd.Count - 1].v; _macd = this._TSmacd[(this.Count < this._TSmacd.Count) ? this.Count : this._TSmacd.Count - 1].v;
var result = (TValue.t, _macd); var result = (TValue.t, _macd);
base.Add(result, update); base.Add(result, update);
} }
} }
+62 -62
View File
@@ -1,63 +1,63 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
RMA: wildeR Moving Average RMA: wildeR Moving Average
J. Welles Wilder introduced RMA as an alternative to EMA. RMA's weight (k) is 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. set as 1/period, giving less weight to the new data compared to EMA.
Sources: Sources:
https://archive.org/details/newconceptsintec00wild/page/23/mode/2up https://archive.org/details/newconceptsintec00wild/page/23/mode/2up
https://tlc.thinkorswim.com/center/reference/Tech-Indicators/studies-library/V-Z/WildersSmoothing https://tlc.thinkorswim.com/center/reference/Tech-Indicators/studies-library/V-Z/WildersSmoothing
https://www.incrediblecharts.com/indicators/wilder_moving_average.php https://www.incrediblecharts.com/indicators/wilder_moving_average.php
Issues: Issues:
Pandas-TA library calculates RMA using straight Exponential Weighted Mean: Pandas-TA library calculates RMA using straight Exponential Weighted Mean:
pandas.ewm().mean() and returns incorrect first (period) of bars compared to pandas.ewm().mean() and returns incorrect first (period) of bars compared to
published formula. This implementation passess the validation test in Wilder's book. published formula. This implementation passess the validation test in Wilder's book.
</summary> */ </summary> */
public class RMA_Series : Single_TSeries_Indicator public class RMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly double _k, _k1m; private readonly double _k, _k1m;
private double _lastema, _lastlastema; private double _lastema, _lastlastema;
public RMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public RMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
this._k = 1.0 / (double)(this._p); this._k = 1.0 / (double)(this._p);
this._k1m = 1.0 - this._k; this._k1m = 1.0 - this._k;
this._lastema = this._lastlastema = double.NaN; this._lastema = this._lastlastema = double.NaN;
if (_data.Count > 0) { base.Add(_data); } if (_data.Count > 0) { base.Add(_data); }
} }
public override void Add((DateTime t, double v) TValue, bool update) public override void Add((DateTime t, double v) TValue, bool update)
{ {
double _ema = 0; double _ema = 0;
if (update) { this._lastema = this._lastlastema; } if (update) { this._lastema = this._lastlastema; }
if (this.Count < this._p) if (this.Count < this._p)
{ {
if (update) { _buffer[_buffer.Count - 1] = TValue.v; } if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
else else
{ {
_buffer.Add(TValue.v); _buffer.Add(TValue.v);
} }
if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } if (_buffer.Count > this._p) { _buffer.RemoveAt(0); }
for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; }
_ema /= this._buffer.Count; _ema /= this._buffer.Count;
} }
else else
{ {
_ema = (TValue.v * _k) + (_lastema * _k1m); _ema = (TValue.v * _k) + (_lastema * _k1m);
} }
this._lastlastema = this._lastema; this._lastlastema = this._lastema;
this._lastema = _ema; this._lastema = _ema;
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema);
base.Add(ret, update); base.Add(ret, update);
} }
} }
+41 -41
View File
@@ -1,41 +1,41 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
SMA: Simple Moving Average SMA: Simple Moving Average
The weights are equally distributed across the period, resulting in a mean() of The weights are equally distributed across the period, resulting in a mean() of
the data within the period/ the data within the period/
Sources: Sources:
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/simple-moving-average-sma/ https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/simple-moving-average-sma/
https://stats.stackexchange.com/a/24739 https://stats.stackexchange.com/a/24739
Remark: Remark:
This calc doesn't use LINQ or SUM() or any of (slow) iterative methods. It is not as fast as TA-LIB 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() implementation, but it does allow incremental additions of inputs and real-time calculations of SMA()
</summary> */ </summary> */
public class SMA_Series : Single_TSeries_Indicator public class SMA_Series : Single_TSeries_Indicator
{ {
public SMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public SMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update) { _buffer[_buffer.Count - 1] = TValue.v; } if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
else { _buffer.Add(TValue.v); } else { _buffer.Add(TValue.v); }
if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); } if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
double _sma = 0; double _sma = 0;
for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
_sma /= this._buffer.Count; _sma /= this._buffer.Count;
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _sma); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _sma);
base.Add(result, update); base.Add(result, update);
} }
} }
+57 -57
View File
@@ -1,58 +1,58 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
SMMA: Smoothed Moving Average SMMA: Smoothed Moving Average
The Smoothed Moving Average (SMMA) is a combination of a SMA and an EMA. It gives the recent prices 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. 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. The main advantage of a smoothed moving average is that it removes short-term fluctuations.
SMMA(i) = (SMMA-1*(N-1) + CLOSE (i)) / N SMMA(i) = (SMMA-1*(N-1) + CLOSE (i)) / N
Sources: Sources:
https://blog.earn2trade.com/smoothed-moving-average 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://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 https://www.chartmill.com/documentation/technical-analysis-indicators/217-MOVING-AVERAGES-%7C-The-Smoothed-Moving-Average-%28SMMA%29
</summary> */ </summary> */
public class SMMA_Series : Single_TSeries_Indicator public class SMMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private double _lastsmma, _lastlastsmma; private double _lastsmma, _lastlastsmma;
public SMMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public SMMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
this._lastsmma = this._lastlastsmma = double.NaN; this._lastsmma = this._lastlastsmma = double.NaN;
if (this._data.Count > 0) { base.Add(this._data); } if (this._data.Count > 0) { base.Add(this._data); }
} }
public override void Add((DateTime t, double v) TValue, bool update) public override void Add((DateTime t, double v) TValue, bool update)
{ {
double _smma = 0; double _smma = 0;
if (update) { this._lastsmma = this._lastlastsmma; } if (update) { this._lastsmma = this._lastlastsmma; }
if (this.Count < this._p) if (this.Count < this._p)
{ {
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
else else
{ {
this._buffer.Add(TValue.v); this._buffer.Add(TValue.v);
} }
if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); }
for (int i = 0; i < this._buffer.Count; i++) { _smma += this._buffer[i]; } for (int i = 0; i < this._buffer.Count; i++) { _smma += this._buffer[i]; }
_smma /= this._buffer.Count; _smma /= this._buffer.Count;
} }
else else
{ {
_smma = ((_lastsmma * (_p-1)) + TValue.v) / _p ; _smma = ((_lastsmma * (_p-1)) + TValue.v) / _p ;
} }
this._lastlastsmma = this._lastsmma; this._lastlastsmma = this._lastsmma;
this._lastsmma = _smma; this._lastsmma = _smma;
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _smma); var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _smma);
base.Add(ret, update); base.Add(ret, update);
} }
} }
+77 -77
View File
@@ -1,78 +1,78 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
TEMA: Triple Exponential Moving Average TEMA: Triple Exponential Moving Average
TEMA uses EMA(EMA(EMA())) to calculate less laggy Exponential moving average. TEMA uses EMA(EMA(EMA())) to calculate less laggy Exponential moving average.
Sources: Sources:
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triple-exponential-moving-average-tema/ https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triple-exponential-moving-average-tema/
Remark: Remark:
ema1 = EMA(close, length) ema1 = EMA(close, length)
ema2 = EMA(ema1, length) ema2 = EMA(ema1, length)
ema3 = EMA(ema2, length) ema3 = EMA(ema2, length)
TEMA = 3 * (ema1 - ema2) + ema3 TEMA = 3 * (ema1 - ema2) + ema3
</summary> */ </summary> */
public class TEMA_Series : Single_TSeries_Indicator public class TEMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly double _k, _k1m; private readonly double _k, _k1m;
private double _lastema1, _lastlastema1; private double _lastema1, _lastlastema1;
private double _lastema2, _lastlastema2; private double _lastema2, _lastlastema2;
private double _lastema3, _lastlastema3; private double _lastema3, _lastlastema3;
public TEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public TEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
this._k = 2.0 / (this._p + 1); this._k = 2.0 / (this._p + 1);
this._k1m = 1.0 - this._k; this._k1m = 1.0 - this._k;
if (_data.Count > 0) { base.Add(_data); } if (_data.Count > 0) { base.Add(_data); }
} }
public override void Add((DateTime t, double v) TValue, bool update) public override void Add((DateTime t, double v) TValue, bool update)
{ {
if (update) if (update)
{ {
this._lastema1 = this._lastlastema1; this._lastema1 = this._lastlastema1;
this._lastema2 = this._lastlastema2; this._lastema2 = this._lastlastema2;
this._lastema3 = this._lastlastema3; this._lastema3 = this._lastlastema3;
} }
double _ema1, _ema2, _ema3; double _ema1, _ema2, _ema3;
if (this.Count < this._p) if (this.Count < this._p)
{ {
if (update) { _buffer[_buffer.Count - 1] = TValue.v; } if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
else else
{ {
_buffer.Add(TValue.v); _buffer.Add(TValue.v);
} }
if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } if (_buffer.Count > this._p) { _buffer.RemoveAt(0); }
double _sma = 0; double _sma = 0;
for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
_sma /= this._buffer.Count; _sma /= this._buffer.Count;
_ema1 = _ema2 = _ema3 = _sma; _ema1 = _ema2 = _ema3 = _sma;
} }
else else
{ {
_ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m); _ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m);
_ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m); _ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m);
_ema3 = (_ema2 * this._k) + (this._lastema3 * this._k1m); _ema3 = (_ema2 * this._k) + (this._lastema3 * this._k1m);
} }
double _tema = (3 * (_ema1 - _ema2)) + _ema3; double _tema = (3 * (_ema1 - _ema2)) + _ema3;
this._lastlastema1 = this._lastema1; this._lastlastema1 = this._lastema1;
this._lastlastema2 = this._lastema2; this._lastlastema2 = this._lastema2;
this._lastlastema3 = this._lastema3; this._lastlastema3 = this._lastema3;
this._lastema1 = _ema1; this._lastema1 = _ema1;
this._lastema2 = _ema2; this._lastema2 = _ema2;
this._lastema3 = _ema3; this._lastema3 = _ema3;
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _tema); var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _tema);
base.Add(ret, update); base.Add(ret, update);
} }
} }
+48 -48
View File
@@ -1,49 +1,49 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
TRIMA: Triangular Moving Average TRIMA: Triangular Moving Average
A weighted moving average where the shape of the weights are triangular and the greatest A weighted moving average where the shape of the weights are triangular and the greatest
weight is in the middle of the period, weight is in the middle of the period,
Sources: Sources:
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triangular-moving-average-trima/ https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triangular-moving-average-trima/
Remark: Remark:
trima = sma(sma(signal, n/2), n/2) trima = sma(sma(signal, n/2), n/2)
</summary> */ </summary> */
public class TRIMA_Series : Single_TSeries_Indicator public class TRIMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer1 = new(); private readonly System.Collections.Generic.List<double> _buffer1 = new();
private readonly System.Collections.Generic.List<double> _buffer2 = new(); private readonly System.Collections.Generic.List<double> _buffer2 = new();
private readonly int _p1a, _p1b; private readonly int _p1a, _p1b;
public TRIMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public TRIMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
_p1a = (int) Math.Floor((period * 0.5) + 1); _p1a = (int) Math.Floor((period * 0.5) + 1);
_p1b = (int) Math.Ceiling(0.5 * period); _p1b = (int) Math.Ceiling(0.5 * period);
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
public override void Add((System.DateTime t, double v) TValue, bool update) 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 (update) { _buffer1[_buffer1.Count - 1] = TValue.v; } else { _buffer1.Add(TValue.v); }
if (_buffer1.Count > this._p1b && this._p1b != 0) { _buffer1.RemoveAt(0); } if (_buffer1.Count > this._p1b && this._p1b != 0) { _buffer1.RemoveAt(0); }
double _sma1 = 0; double _sma1 = 0;
for (int i = 0; i < _buffer1.Count; i++) { _sma1 += _buffer1[i]; } for (int i = 0; i < _buffer1.Count; i++) { _sma1 += _buffer1[i]; }
_sma1 /= this._buffer1.Count; _sma1 /= this._buffer1.Count;
if (update) { _buffer2[_buffer2.Count - 1] = _sma1; } else { _buffer2.Add(_sma1); } if (update) { _buffer2[_buffer2.Count - 1] = _sma1; } else { _buffer2.Add(_sma1); }
if (_buffer2.Count > this._p1a && this._p1a != 0) { _buffer2.RemoveAt(0); } if (_buffer2.Count > this._p1a && this._p1a != 0) { _buffer2.RemoveAt(0); }
double _trima = 0; double _trima = 0;
for (int i = 0; i < _buffer2.Count; i++) { _trima += _buffer2[i]; } for (int i = 0; i < _buffer2.Count; i++) { _trima += _buffer2[i]; }
_trima /= this._buffer2.Count; _trima /= this._buffer2.Count;
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _trima); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _trima);
base.Add(result, update); base.Add(result, update);
} }
} }
+38 -38
View File
@@ -1,39 +1,39 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
WMA: (linearly) Weighted Moving Average WMA: (linearly) Weighted Moving Average
The weights are linearly decreasing over the period and the most recent data has The weights are linearly decreasing over the period and the most recent data has
the heaviest weight. the heaviest weight.
Sources: Sources:
https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/weighted-moving-average-wma/ https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/weighted-moving-average-wma/
https://www.technicalindicators.net/indicators-technical-analysis/83-moving-averages-simple-exponential-weighted https://www.technicalindicators.net/indicators-technical-analysis/83-moving-averages-simple-exponential-weighted
</summary> */ </summary> */
public class WMA_Series : Single_TSeries_Indicator public class WMA_Series : Single_TSeries_Indicator
{ {
public WMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) 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); } for (int i = 0; i < this._p; i++) { this._weights.Add(i + 1); }
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly System.Collections.Generic.List<double> _weights = new(); private readonly System.Collections.Generic.List<double> _weights = new();
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update) { _buffer[_buffer.Count - 1] = TValue.v; } if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
else { _buffer.Add(TValue.v); } else { _buffer.Add(TValue.v); }
if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); } if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
double _wma = 0; double _wma = 0;
for (int i = 0; i < _buffer.Count; i++) { _wma += _buffer[i] * this._weights[i]; } for (int i = 0; i < _buffer.Count; i++) { _wma += _buffer[i] * this._weights[i]; }
_wma /= (this._buffer.Count * (this._buffer.Count + 1)) * 0.5; _wma /= (this._buffer.Count * (this._buffer.Count + 1)) * 0.5;
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _wma); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _wma);
base.Add(result, update); base.Add(result, update);
} }
} }
+71 -71
View File
@@ -1,72 +1,72 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
ZLEMA: Zero Lag Exponential Moving Average ZLEMA: Zero Lag Exponential Moving Average
The Zero lag exponential moving average (ZLEMA) indicator was created by John The Zero lag exponential moving average (ZLEMA) indicator was created by John
Ehlers and Ric Way. Ehlers and Ric Way.
The formula for a given N-Day period and for a given Data series is: The formula for a given N-Day period and for a given Data series is:
Lag = (Period-1)/2 Lag = (Period-1)/2
Ema Data = {Data+(Data-Data(Lag days ago)) Ema Data = {Data+(Data-Data(Lag days ago))
ZLEMA = EMA (EmaData,Period) ZLEMA = EMA (EmaData,Period)
Remark: Remark:
The idea is do a regular exponential moving average (EMA) calculation but on a 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 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) removing the data from "lag" days ago thus removing (or attempting to remove)
the cumulative lag effect of the moving average. the cumulative lag effect of the moving average.
</summary> */ </summary> */
public class ZLEMA_Series : Single_TSeries_Indicator public class ZLEMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly double _k, _k1m; private readonly double _k, _k1m;
private double _lastema, _lastlastema; private double _lastema, _lastlastema;
public ZLEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public ZLEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
this._k = 2.0 / (this._p + 1); this._k = 2.0 / (this._p + 1);
this._k1m = 1.0 - this._k; this._k1m = 1.0 - this._k;
this._lastema = this._lastlastema = double.NaN; this._lastema = this._lastlastema = double.NaN;
if (base._data.Count > 0) if (base._data.Count > 0)
{ base.Add(base._data); } { base.Add(base._data); }
} }
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
int _lag = (int)((_p-1) * 0.5); int _lag = (int)((_p-1) * 0.5);
_lag = (this.Count-_lag < 0) ? 0 : this.Count-_lag; _lag = (this.Count-_lag < 0) ? 0 : this.Count-_lag;
double _zl = TValue.v + (TValue.v - _data[_lag].v); double _zl = TValue.v + (TValue.v - _data[_lag].v);
double _ema = 0; double _ema = 0;
if (update) if (update)
{ this._lastema = this._lastlastema; } { this._lastema = this._lastlastema; }
if (this.Count < this._p) if (this.Count < this._p)
{ {
if (update) if (update)
{ this._buffer[this._buffer.Count - 1] = _zl; } { this._buffer[this._buffer.Count - 1] = _zl; }
else else
{ {
this._buffer.Add(_zl); this._buffer.Add(_zl);
} }
if (this._buffer.Count > this._p) if (this._buffer.Count > this._p)
{ this._buffer.RemoveAt(0); } { this._buffer.RemoveAt(0); }
for (int i = 0; i < this._buffer.Count; i++) for (int i = 0; i < this._buffer.Count; i++)
{ _ema += this._buffer[i]; } { _ema += this._buffer[i]; }
_ema /= this._buffer.Count; _ema /= this._buffer.Count;
} }
else else
{ {
_ema = (_zl * this._k) + (this._lastema * this._k1m); _ema = (_zl * this._k) + (this._lastema * this._k1m);
} }
this._lastlastema = this._lastema; this._lastlastema = this._lastema;
this._lastema = _ema; this._lastema = _ema;
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema);
base.Add(ret, update); base.Add(ret, update);
} }
} }
+42 -42
View File
@@ -1,43 +1,43 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
ADL: Chaikin Accumulation/Distribution Line ADL: Chaikin Accumulation/Distribution Line
ADL is a volume-based indicator that measures the cumulative Money Flow Volume: ADL is a volume-based indicator that measures the cumulative Money Flow Volume:
1. Money Flow Multiplier = [(Close - Low) - (High - Close)] /(High - Low) 1. Money Flow Multiplier = [(Close - Low) - (High - Close)] /(High - Low)
2. Money Flow Volume = Money Flow Multiplier x Volume for the Period 2. Money Flow Volume = Money Flow Multiplier x Volume for the Period
3. ADL = Previous ADL + Current Period's Money Flow Volume 3. ADL = Previous ADL + Current Period's Money Flow Volume
Sources: Sources:
https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line
</summary> */ </summary> */
public class ADL_Series : Single_TBars_Indicator public class ADL_Series : Single_TBars_Indicator
{ {
private double _lastadl, _lastlastadl; private double _lastadl, _lastlastadl;
public ADL_Series(TBars source, bool useNaN = false) : base(source, 0, useNaN) public ADL_Series(TBars source, bool useNaN = false) : base(source, 0, useNaN)
{ {
this._lastadl = this._lastlastadl = 0; this._lastadl = this._lastlastadl = 0;
if (_bars.Count > 0) if (_bars.Count > 0)
{ base.Add(_bars); } { base.Add(_bars); }
} }
public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
{ {
if (update) if (update)
{ this._lastadl = this._lastlastadl; } { this._lastadl = this._lastlastadl; }
double _mfm = ((TBar.c - TBar.l) - (TBar.h - TBar.c)) / (TBar.h - TBar.l); double _mfm = ((TBar.c - TBar.l) - (TBar.h - TBar.c)) / (TBar.h - TBar.l);
double _mfv = _mfm * TBar.v; double _mfv = _mfm * TBar.v;
double _adl = this._lastadl + _mfv; double _adl = this._lastadl + _mfv;
this._lastlastadl = this._lastadl; this._lastlastadl = this._lastadl;
this._lastadl = _adl; this._lastadl = _adl;
var ret = (TBar.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _adl); var ret = (TBar.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _adl);
base.Add(ret, update); base.Add(ret, update);
} }
} }
+44 -44
View File
@@ -1,45 +1,45 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
ADO: Chaikin Accumulation/Distribution Oscillator ADO: Chaikin Accumulation/Distribution Oscillator
ADO measures the momentum of ADL using the difference between slow (10-day) EMA(ADL) ADO measures the momentum of ADL using the difference between slow (10-day) EMA(ADL)
and fast (3-day) EMA(ADL): and fast (3-day) EMA(ADL):
Chaikin A/D Oscillator = (3-day EMA of ADL) - (10-day EMA of ADL) Chaikin A/D Oscillator = (3-day EMA of ADL) - (10-day EMA of ADL)
Sources: Sources:
https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_oscillator https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_oscillator
</summary> */ </summary> */
public class ADOSC_Series : Single_TBars_Indicator public class ADOSC_Series : Single_TBars_Indicator
{ {
private readonly ADL_Series _TSadl; private readonly ADL_Series _TSadl;
private readonly EMA_Series _TSslow; private readonly EMA_Series _TSslow;
private readonly EMA_Series _TSfast; private readonly EMA_Series _TSfast;
private readonly SUB_Series _TSado; private readonly SUB_Series _TSado;
public ADOSC_Series(TBars source, bool useNaN = false) : base(source, period: 0, useNaN) public ADOSC_Series(TBars source, bool useNaN = false) : base(source, period: 0, useNaN)
{ {
_TSadl = new(source: source, useNaN: false); _TSadl = new(source: source, useNaN: false);
_TSslow = new(source: _TSadl, period: 10, useNaN: false); _TSslow = new(source: _TSadl, period: 10, useNaN: false);
_TSfast = new(source: _TSadl, period: 3, useNaN: false); _TSfast = new(source: _TSadl, period: 3, useNaN: false);
_TSado = new(_TSfast, _TSslow); _TSado = new(_TSfast, _TSslow);
if (source.Count > 0) if (source.Count > 0)
{ base.Add(_TSado); } { base.Add(_TSado); }
Console.WriteLine(base.Count); Console.WriteLine(base.Count);
} }
public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
{ {
if (update) if (update)
{ _TSadl.Add(TBar, true); } { _TSadl.Add(TBar, true); }
double _ado = this._TSado[(this.Count < this._TSado.Count) ? this.Count : this._TSado.Count - 1].v; double _ado = this._TSado[(this.Count < this._TSado.Count) ? this.Count : this._TSado.Count - 1].v;
var result = (TBar.t, _ado); var result = (TBar.t, _ado);
base.Add(result, update); base.Add(result, update);
} }
} }
+62 -62
View File
@@ -1,63 +1,63 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
ATRP: Average True Range Percent ATRP: Average True Range Percent
Average True Range Percent is (ATR/Close Price)*100. Average True Range Percent is (ATR/Close Price)*100.
This normalizes so it can be compared to other stocks. This normalizes so it can be compared to other stocks.
Sources: Sources:
https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/atrp https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/atrp
</summary> */ </summary> */
public class ATRP_Series : Single_TBars_Indicator public class ATRP_Series : Single_TBars_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly double _k, _k1m; private readonly double _k, _k1m;
private double _lastema, _lastlastema, _lastcm1; private double _lastema, _lastlastema, _lastcm1;
private double _cm1 = double.NaN; private double _cm1 = double.NaN;
public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
this._k = 1.0 / (double)(this._p); this._k = 1.0 / (double)(this._p);
this._k1m = 1.0 - this._k; this._k1m = 1.0 - this._k;
this._lastema = this._lastlastema = double.NaN; this._lastema = this._lastlastema = double.NaN;
if (_bars.Count > 0) { base.Add(_bars); } 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) public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
{ {
if (update) { if (update) {
this._lastema = this._lastlastema; this._lastema = this._lastlastema;
this._cm1 = this._lastcm1; this._cm1 = this._lastcm1;
} }
if (_cm1 is double.NaN) { _cm1 = TBar.c; } if (_cm1 is double.NaN) { _cm1 = TBar.c; }
double d1 = Math.Abs(TBar.h - TBar.l); double d1 = Math.Abs(TBar.h - TBar.l);
double d2 = Math.Abs(_cm1 - TBar.h); double d2 = Math.Abs(_cm1 - TBar.h);
double d3 = Math.Abs(_cm1 - TBar.l); 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 (DateTime t, double v)d = (TBar.t, Math.Max(d1,Math.Max(d2,d3))); //TR value for RMA below
_lastcm1 = _cm1; _lastcm1 = _cm1;
_cm1 = TBar.c; _cm1 = TBar.c;
double _ema = 0; double _ema = 0;
if (this.Count < this._p) if (this.Count < this._p)
{ {
if (update) { _buffer[_buffer.Count - 1] = d.v; } if (update) { _buffer[_buffer.Count - 1] = d.v; }
else { _buffer.Add(d.v); } else { _buffer.Add(d.v); }
if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } if (_buffer.Count > this._p) { _buffer.RemoveAt(0); }
for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; }
_ema /= this._buffer.Count; _ema /= this._buffer.Count;
} }
else { _ema = (d.v * _k) + (_lastema * _k1m); } else { _ema = (d.v * _k) + (_lastema * _k1m); }
this._lastlastema = this._lastema; this._lastlastema = this._lastema;
this._lastema = _ema; this._lastema = _ema;
double _atrp = 100 * (_ema / TBar.c); double _atrp = 100 * (_ema / TBar.c);
var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atrp); var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atrp);
base.Add(ret, update); base.Add(ret, update);
} }
} }
+62 -62
View File
@@ -1,63 +1,63 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
ATR: wildeR Moving Average ATR: wildeR Moving Average
The average true range (ATR) is a price volatility indicator The average true range (ATR) is a price volatility indicator
showing the average price variation of assets within a given time period. showing the average price variation of assets within a given time period.
Sources: Sources:
https://en.wikipedia.org/wiki/Average_true_range https://en.wikipedia.org/wiki/Average_true_range
https://www.tradingview.com/wiki/Average_True_Range_(ATR) https://www.tradingview.com/wiki/Average_True_Range_(ATR)
https://www.investopedia.com/terms/a/atr.asp https://www.investopedia.com/terms/a/atr.asp
</summary> */ </summary> */
public class ATR_Series : Single_TBars_Indicator public class ATR_Series : Single_TBars_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly double _k, _k1m; private readonly double _k, _k1m;
private double _lastema, _lastlastema, _lastcm1; private double _lastema, _lastlastema, _lastcm1;
private double _cm1 = double.NaN; private double _cm1 = double.NaN;
public ATR_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) public ATR_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
this._k = 1.0 / (double)(this._p); this._k = 1.0 / (double)(this._p);
this._k1m = 1.0 - this._k; this._k1m = 1.0 - this._k;
this._lastema = this._lastlastema = double.NaN; this._lastema = this._lastlastema = double.NaN;
if (this._bars.Count > 0) { base.Add(this._bars); } 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) public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
{ {
if (update) { if (update) {
this._lastema = this._lastlastema; this._lastema = this._lastlastema;
this._cm1 = this._lastcm1; this._cm1 = this._lastcm1;
} }
if (this._cm1 is double.NaN) { this._cm1 = TBar.c; } if (this._cm1 is double.NaN) { this._cm1 = TBar.c; }
double d1 = Math.Abs(TBar.h - TBar.l); double d1 = Math.Abs(TBar.h - TBar.l);
double d2 = Math.Abs(_cm1 - TBar.h); double d2 = Math.Abs(_cm1 - TBar.h);
double d3 = Math.Abs(_cm1 - TBar.l); 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 (DateTime t, double v)d = (TBar.t, Math.Max(d1,Math.Max(d2,d3))); //TR value for RMA below
_lastcm1 = _cm1; _lastcm1 = _cm1;
_cm1 = TBar.c; _cm1 = TBar.c;
double _ema = 0; double _ema = 0;
if (this.Count < this._p) if (this.Count < this._p)
{ {
if (update) { _buffer[_buffer.Count - 1] = d.v; } if (update) { _buffer[_buffer.Count - 1] = d.v; }
else { _buffer.Add(d.v); } else { _buffer.Add(d.v); }
if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } if (_buffer.Count > this._p) { _buffer.RemoveAt(0); }
for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; }
_ema /= this._buffer.Count; _ema /= this._buffer.Count;
} }
else { _ema = (d.v * _k) + (_lastema * _k1m); } else { _ema = (d.v * _k) + (_lastema * _k1m); }
this._lastlastema = this._lastema; this._lastlastema = this._lastema;
this._lastema = _ema; this._lastema = _ema;
var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema);
base.Add(ret, update); base.Add(ret, update);
} }
} }
+72 -72
View File
@@ -1,73 +1,73 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
BBANDS: Bollinger Bands® BBANDS: Bollinger Bands®
Price channels created by John Bollinger, depict volatility as standard deviation boundary 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 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 increases and contract when volatility decreases. Their dynamic nature allows them to be
used on different securities with the standard settings. used on different securities with the standard settings.
Mid Band = simple moving average (SMA) Mid Band = simple moving average (SMA)
Upper Band = SMA + (standard deviation of price x multiplier) Upper Band = SMA + (standard deviation of price x multiplier)
Lower 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 Bandwidth = Width of the channel: (Upper-Lower)/SMA
%B = The location of the data point within the channel: (Price-Lower)/(Upper/Lower) %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 Z-Score = number of standard deviations of the data point from SMA
Sources: Sources:
https://www.investopedia.com/terms/b/bollingerbands.asp https://www.investopedia.com/terms/b/bollingerbands.asp
https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands
Note: Note:
Bollinger Bands® is a registered trademark of John A. Bollinger. Bollinger Bands® is a registered trademark of John A. Bollinger.
</summary> */ </summary> */
public class BBANDS_Series : Single_TSeries_Indicator public class BBANDS_Series : Single_TSeries_Indicator
{ {
public SMA_Series Mid { get; } public SMA_Series Mid { get; }
public ADD_Series Upper { get; } public ADD_Series Upper { get; }
public SUB_Series Lower { get; } public SUB_Series Lower { get; }
public DIV_Series PercentB { get; } public DIV_Series PercentB { get; }
public DIV_Series Bandwidth { get; } public DIV_Series Bandwidth { get; }
public DIV_Series Zscore { get; } public DIV_Series Zscore { get; }
private readonly SDEV_Series _sdev; private readonly SDEV_Series _sdev;
private readonly MUL_Series _mulsdev; private readonly MUL_Series _mulsdev;
private readonly SUB_Series _pbdnd; private readonly SUB_Series _pbdnd;
private readonly SUB_Series _pbdvr; private readonly SUB_Series _pbdvr;
private readonly SUB_Series _zdnd; private readonly SUB_Series _zdnd;
public BBANDS_Series(TSeries source, int period = 26, double multiplier = 2.0, bool useNaN = false) public BBANDS_Series(TSeries source, int period = 26, double multiplier = 2.0, bool useNaN = false)
: base(source, period: 0, useNaN) : base(source, period: 0, useNaN)
{ {
this.Mid = new(source: source, period: period, useNaN: useNaN); this.Mid = new(source: source, period: period, useNaN: useNaN);
_sdev = new(source, period, useNaN: useNaN); _sdev = new(source, period, useNaN: useNaN);
_mulsdev = new(_sdev, multiplier); _mulsdev = new(_sdev, multiplier);
this.Upper = new(Mid, _mulsdev); this.Upper = new(Mid, _mulsdev);
this.Lower = new(Mid, _mulsdev); this.Lower = new(Mid, _mulsdev);
_pbdnd = new(source, Lower); _pbdnd = new(source, Lower);
_pbdvr = new(Upper, Lower); _pbdvr = new(Upper, Lower);
this.PercentB = new(_pbdnd, _pbdvr); this.PercentB = new(_pbdnd, _pbdvr);
this.Bandwidth = new(_pbdvr, Mid); this.Bandwidth = new(_pbdvr, Mid);
_zdnd = new(source, Mid); _zdnd = new(source, Mid);
this.Zscore = new(_zdnd, _sdev); this.Zscore = new(_zdnd, _sdev);
if (source.Count > 0) if (source.Count > 0)
{ base.Add(this.Bandwidth); } { base.Add(this.Bandwidth); }
} }
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
double _bbandwidth; double _bbandwidth;
if (update) if (update)
{ _sdev.Add(TValue, true); } { _sdev.Add(TValue, true); }
_bbandwidth = this.Bandwidth[(this.Count < this.Bandwidth.Count) ? this.Count : this.Bandwidth.Count - 1].v; _bbandwidth = this.Bandwidth[(this.Count < this.Bandwidth.Count) ? this.Count : this.Bandwidth.Count - 1].v;
var result = (TValue.t, _bbandwidth); var result = (TValue.t, _bbandwidth);
base.Add(result, update); base.Add(result, update);
} }
} }
+72 -72
View File
@@ -1,73 +1,73 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
RSI: Relative Strength Index RSI: Relative Strength Index
Created by J. Welles Wilder, the Relative Strength Index measures strength 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, of the winning/losing streak over N lookback periods on a scale of 0 to 100,
to depict overbought and oversold conditions. to depict overbought and oversold conditions.
Sources: Sources:
https://www.investopedia.com/terms/r/rsi.asp https://www.investopedia.com/terms/r/rsi.asp
</summary> */ </summary> */
public class RSI_Series : Single_TSeries_Indicator public class RSI_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _gain = new(); private readonly System.Collections.Generic.List<double> _gain = new();
private readonly System.Collections.Generic.List<double> _loss = new(); private readonly System.Collections.Generic.List<double> _loss = new();
private double _avgGain; private double _avgGain;
private double _avgLoss; private double _avgLoss;
private double _lastValue; private double _lastValue;
private double _lastlastValue; private double _lastlastValue;
public RSI_Series(TSeries source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) public RSI_Series(TSeries source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN)
{ if (source.Count > 0) { base.Add(source); } } { if (source.Count > 0) { base.Add(source); } }
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
int i = this.Count; int i = this.Count;
double _rsi = 0; double _rsi = 0;
if (update) { _lastValue = _lastlastValue; } if (update) { _lastValue = _lastlastValue; }
if (i == 0) { _lastValue = TValue.v; } if (i == 0) { _lastValue = TValue.v; }
double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0; double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0;
if (update) { _gain[_gain.Count - 1] = _gainval; } else { _gain.Add(_gainval); } if (update) { _gain[_gain.Count - 1] = _gainval; } else { _gain.Add(_gainval); }
if (_gain.Count > this._p) { _gain.RemoveAt(0); } if (_gain.Count > this._p) { _gain.RemoveAt(0); }
double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0; double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0;
if (update) { _loss[_loss.Count - 1] = _lossval; } else { _loss.Add(_lossval); } if (update) { _loss[_loss.Count - 1] = _lossval; } else { _loss.Add(_lossval); }
if (_loss.Count > this._p) { _loss.RemoveAt(0); } if (_loss.Count > this._p) { _loss.RemoveAt(0); }
_lastlastValue = _lastValue; _lastlastValue = _lastValue;
_lastValue = TValue.v; _lastValue = TValue.v;
// calculate RSI // calculate RSI
if (i > _p) if (i > _p)
{ {
_avgGain = ((_avgGain * (_p - 1)) + _gain[_gain.Count - 1]) / _p; _avgGain = ((_avgGain * (_p - 1)) + _gain[_gain.Count - 1]) / _p;
_avgLoss = ((_avgLoss * (_p - 1)) + _loss[_loss.Count - 1]) / _p; _avgLoss = ((_avgLoss * (_p - 1)) + _loss[_loss.Count - 1]) / _p;
if (_avgLoss > 0) { if (_avgLoss > 0) {
double rs = _avgGain / _avgLoss; double rs = _avgGain / _avgLoss;
_rsi = 100 - (100 / (1 + rs)); _rsi = 100 - (100 / (1 + rs));
} }
else { _rsi = 100; } else { _rsi = 100; }
} }
// initialize average gain // initialize average gain
else else
{ {
double _sumGain = 0; double _sumGain = 0;
for (int p = 0; p < _gain.Count; p++) { _sumGain += _gain[p]; } for (int p = 0; p < _gain.Count; p++) { _sumGain += _gain[p]; }
double _sumLoss = 0; double _sumLoss = 0;
for (int p = 0; p < _loss.Count; p++) { _sumLoss += _loss[p]; } for (int p = 0; p < _loss.Count; p++) { _sumLoss += _loss[p]; }
_avgGain = _sumGain / _gain.Count; _avgGain = _sumGain / _gain.Count;
_avgLoss = _sumLoss / _loss.Count; _avgLoss = _sumLoss / _loss.Count;
_rsi = (_avgLoss > 0) ? 100 - (100 / (1 + (_avgGain / _avgLoss))) : 100; _rsi = (_avgLoss > 0) ? 100 - (100 / (1 + (_avgGain / _avgLoss))) : 100;
} }
var result = (TValue.t, (this.Count < this._p && this._NaN) ? double.NaN : _rsi); var result = (TValue.t, (this.Count < this._p && this._NaN) ? double.NaN : _rsi);
base.Add(result, update); base.Add(result, update);
} }
} }
+62 -62
View File
@@ -1,62 +1,62 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
OBV: On-Balance Volume OBV: On-Balance Volume
On-balance volume (OBV) is a technical trading momentum indicator that uses volume flow to predict 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 changes in stock price. Joseph Granville first developed the OBV metric in the 1963 book
Granville's New Key to Stock Market Profits. Granville's New Key to Stock Market Profits.
| +volume; if close > close[previous] | +volume; if close > close[previous]
OBV = OBV[previous] + | 0; if close = close[previous] OBV = OBV[previous] + | 0; if close = close[previous]
| -volume; if close < close[previous] | -volume; if close < close[previous]
Sources: Sources:
https://www.investopedia.com/terms/o/onbalancevolume.asp https://www.investopedia.com/terms/o/onbalancevolume.asp
https://www.tradingview.com/wiki/On_Balance_Volume_(OBV) 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.tradingtechnologies.com/help/x-study/technical-indicator-definitions/on-balance-volume-obv/
https://www.motivewave.com/studies/on_balance_volume.htm https://www.motivewave.com/studies/on_balance_volume.htm
Note: Note:
There is no consensus on what is the first OBV value in the series: There is no consensus on what is the first OBV value in the series:
- TA-LIB uses the first volume: OBV[0] = volume[0] - TA-LIB uses the first volume: OBV[0] = volume[0]
- Skender stock library uses 0: OBV[0] = 0 - Skender stock library uses 0: OBV[0] = 0
</summary> */ </summary> */
public class OBV_Series : Single_TBars_Indicator public class OBV_Series : Single_TBars_Indicator
{ {
private double _lastobv, _lastlastobv; private double _lastobv, _lastlastobv;
private double _lastclose, _lastlastclose; private double _lastclose, _lastlastclose;
public OBV_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) public OBV_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN)
{ {
this._lastobv = this._lastlastobv = 0; this._lastobv = this._lastlastobv = 0;
this._lastclose = this._lastlastclose = 0; this._lastclose = this._lastlastclose = 0;
if (_bars.Count > 0) { base.Add(_bars); } 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) public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
{ {
if (update) if (update)
{ {
this._lastobv = this._lastlastobv; this._lastobv = this._lastlastobv;
this._lastclose = this._lastlastclose; this._lastclose = this._lastlastclose;
} }
double _obv = this._lastobv; double _obv = this._lastobv;
if (TBar.c > this._lastclose) { _obv += TBar.v; } if (TBar.c > this._lastclose) { _obv += TBar.v; }
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] // Unclear what the first value in OBV series is - currently set to volume[0]
// if (this.Count == 0) { _obv = 0; } // if (this.Count == 0) { _obv = 0; }
this._lastlastobv = this._lastobv; this._lastlastobv = this._lastobv;
this._lastobv = _obv; this._lastobv = _obv;
this._lastlastclose = this._lastclose; this._lastlastclose = this._lastclose;
this._lastclose = TBar.c; this._lastclose = TBar.c;
var result = (TBar.t, (this.Count < this._p && this._NaN) ? double.NaN : _obv); var result = (TBar.t, (this.Count < this._p && this._NaN) ? double.NaN : _obv);
base.Add(result, update); base.Add(result, update);
} }
} }
+23 -23
View File
@@ -1,23 +1,23 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Basics; namespace Basics;
public class Abstract_Test public class Abstract_Test
{ {
[Fact] [Fact]
public void Single_Add_variations() public void Single_Add_variations()
{ {
TSeries s = new() { 1,2,3,4,5 }; TSeries s = new() { 1,2,3,4,5 };
SMA_Series a = new(s, 3) SMA_Series a = new(s, 3)
{ {
{ (DateTime.Today, 10), true } { (DateTime.Today, 10), true }
}; };
Assert.Equal(s.Length, a.Length); Assert.Equal(s.Length, a.Length);
a.Add(true); a.Add(true);
Assert.Equal(s.Length, a.Length); Assert.Equal(s.Length, a.Length);
a.Add(); a.Add();
Assert.Equal(s.Length+1, a.Length); Assert.Equal(s.Length+1, a.Length);
} }
} }
+112 -112
View File
@@ -1,112 +1,112 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Basics; namespace Basics;
public class TBars_Test public class TBars_Test
{ {
[Fact] [Fact]
public void InsertingTuple() public void InsertingTuple()
{ {
TBars s = new() { (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, c: Double.NegativeInfinity, v: Double.PositiveInfinity) }; 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, var tup = (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue,
c: Double.NegativeInfinity, v: Double.PositiveInfinity); c: Double.NegativeInfinity, v: Double.PositiveInfinity);
Assert.Equal(tup, s[^1]); Assert.Equal(tup, s[^1]);
} }
[Fact] [Fact]
public void Casting_Parameters() public void Casting_Parameters()
{ {
TBars s = new() TBars s = new()
{ {
{ DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false } { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false }
}; };
Assert.Equal(0.1, s[^1].o); Assert.Equal(0.1, s[^1].o);
Assert.Equal(1.1, s[^1].h); Assert.Equal(1.1, s[^1].h);
Assert.Equal(2.1, s[^1].l); Assert.Equal(2.1, s[^1].l);
Assert.Equal(3.1, s[^1].c); Assert.Equal(3.1, s[^1].c);
Assert.Equal(4.1, s[^1].v); Assert.Equal(4.1, s[^1].v);
Assert.Equal(DateTime.Today, s[^1].t); Assert.Equal(DateTime.Today, s[^1].t);
Assert.Single(s); Assert.Single(s);
} }
[Fact] [Fact]
public void Updating_Value() public void Updating_Value()
{ {
TBars s = new() TBars s = new()
{ {
{ DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 } { 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, 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); 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].o);
Assert.Equal(0.0, s[^1].h); Assert.Equal(0.0, s[^1].h);
Assert.Equal(0.0, s[^1].l); Assert.Equal(0.0, s[^1].l);
Assert.Equal(0.0, s[^1].c); Assert.Equal(0.0, s[^1].c);
Assert.Equal(0.0, s[^1].v); Assert.Equal(0.0, s[^1].v);
Assert.Equal(2, s.Count); Assert.Equal(2, s.Count);
} }
[Fact] [Fact]
public void Extracting_TSeries() public void Extracting_TSeries()
{ {
TBars s = new() TBars s = new()
{ {
{ DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 }, { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 },
{ DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1 } { DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1 }
}; };
TSeries t = s.Open; TSeries t = s.Open;
Assert.Equal(t.t, s.Open.t); Assert.Equal(t.t, s.Open.t);
Assert.Equal(t.v, s.Open.v); Assert.Equal(t.v, s.Open.v);
t = s.High; t = s.High;
Assert.Equal(t.t, s.High.t); Assert.Equal(t.t, s.High.t);
Assert.Equal(t.v, s.High.v); Assert.Equal(t.v, s.High.v);
t = s.Low; t = s.Low;
Assert.Equal(t.t, s.Low.t); Assert.Equal(t.t, s.Low.t);
Assert.Equal(t.v, s.Low.v); Assert.Equal(t.v, s.Low.v);
t = s.Close; t = s.Close;
Assert.Equal(t.t, s.Close.t); Assert.Equal(t.t, s.Close.t);
Assert.Equal(t.v, s.Close.v); Assert.Equal(t.v, s.Close.v);
t = s.Volume; t = s.Volume;
Assert.Equal(t.t, s.Volume.t); Assert.Equal(t.t, s.Volume.t);
Assert.Equal(t.v, s.Volume.v); Assert.Equal(t.v, s.Volume.v);
t = s.HL2; t = s.HL2;
Assert.Equal(t.t, s.HL2.t); Assert.Equal(t.t, s.HL2.t);
Assert.Equal(t.v, s.HL2.v); Assert.Equal(t.v, s.HL2.v);
t = s.OC2; t = s.OC2;
Assert.Equal(t.t, s.OC2.t); Assert.Equal(t.t, s.OC2.t);
Assert.Equal(t.v, s.OC2.v); Assert.Equal(t.v, s.OC2.v);
t = s.OHL3; t = s.OHL3;
Assert.Equal(t.t, s.OHL3.t); Assert.Equal(t.t, s.OHL3.t);
Assert.Equal(t.v, s.OHL3.v); Assert.Equal(t.v, s.OHL3.v);
t = s.HLC3; t = s.HLC3;
Assert.Equal(t.t, s.HLC3.t); Assert.Equal(t.t, s.HLC3.t);
Assert.Equal(t.v, s.HLC3.v); Assert.Equal(t.v, s.HLC3.v);
t = s.OHLC4; t = s.OHLC4;
Assert.Equal(t.t, s.OHLC4.t); Assert.Equal(t.t, s.OHLC4.t);
Assert.Equal(t.v, s.OHLC4.v); Assert.Equal(t.v, s.OHLC4.v);
t = s.HLCC4; t = s.HLCC4;
Assert.Equal(t.t, s.HLCC4.t); Assert.Equal(t.t, s.HLCC4.t);
Assert.Equal(t.v, s.HLCC4.v); Assert.Equal(t.v, s.HLCC4.v);
} }
[Fact] [Fact]
public void Broadcasting_Events() public void Broadcasting_Events()
{ {
TBars s = new() { (DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1) }; TBars s = new() { (DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1) };
TSeries t = new(); TSeries t = new();
s.Close.Pub += t.Sub; s.Close.Pub += t.Sub;
s.Add(DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false); 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.v, t.v);
Assert.Equal(s.Close.Count, t.Count); Assert.Equal(s.Close.Count, t.Count);
} }
} }
+61 -61
View File
@@ -1,61 +1,61 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Basics; namespace Basics;
public class TSeries_Test public class TSeries_Test
{ {
[Fact] [Fact]
public void InsertingTuple() public void InsertingTuple()
{ {
TSeries s = new() { (t: DateTime.Today, v: double.Epsilon) }; TSeries s = new() { (t: DateTime.Today, v: double.Epsilon) };
Assert.Equal((DateTime.Today, double.Epsilon), s); Assert.Equal((DateTime.Today, double.Epsilon), s);
} }
[Fact] [Fact]
public void CastingTwoParameters() public void CastingTwoParameters()
{ {
TSeries s = new() TSeries s = new()
{ {
{ DateTime.Today, 0.0 } { DateTime.Today, 0.0 }
}; };
Assert.Equal(0.0, s[s.Count - 1].v); Assert.Equal(0.0, s[s.Count - 1].v);
Assert.Equal(DateTime.Today, s[s.Count - 1].t); Assert.Equal(DateTime.Today, s[s.Count - 1].t);
} }
[Fact] [Fact]
public void CastingOneParameter() public void CastingOneParameter()
{ {
TSeries s = new() TSeries s = new()
{ {
double.PositiveInfinity double.PositiveInfinity
}; };
Assert.Equal(double.PositiveInfinity, (double)s); Assert.Equal(double.PositiveInfinity, (double)s);
} }
[Fact] [Fact]
public void UpdatingValue() public void UpdatingValue()
{ {
TSeries s = new() { 1, 2, 3, 4, 5 }; TSeries s = new() { 1, 2, 3, 4, 5 };
s.Add(0.0, update: true); s.Add(0.0, update: true);
Assert.Equal(0.0, (double)s); Assert.Equal(0.0, (double)s);
Assert.Equal(5, s.Count); Assert.Equal(5, s.Count);
} }
[Fact] [Fact]
public void ReflectingSeries() public void ReflectingSeries()
{ {
TSeries s = new() { 1, 2, 3, 4, 5 }; TSeries s = new() { 1, 2, 3, 4, 5 };
TSeries t = s; TSeries t = s;
Assert.Equal(5, (double)t); Assert.Equal(5, (double)t);
Assert.Equal(5, t.Count); Assert.Equal(5, t.Count);
} }
[Fact] [Fact]
public void BroadcastingEvents() public void BroadcastingEvents()
{ {
TSeries s = new() { 1, 2, 3, 4, 5 }; TSeries s = new() { 1, 2, 3, 4, 5 };
TSeries t = new(); TSeries t = new();
s.Pub += t.Sub; s.Pub += t.Sub;
s.Add(0.0, update: true); s.Add(0.0, update: true);
Assert.Equal(0.0, (double)t); Assert.Equal(0.0, (double)t);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class ALMA_Test public class ALMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
ALMA_Series c = new(a, 4); ALMA_Series c = new(a, 4);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(10, update: true); a.Add(10, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
ALMA_Series c = new(a, 3); ALMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+56 -56
View File
@@ -1,56 +1,56 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class BBANDS_Test public class BBANDS_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
BBANDS_Series c = new(a, 4,2.5); BBANDS_Series c = new(a, 4,2.5);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
Assert.Equal(a.Count, c.Mid.Count); Assert.Equal(a.Count, c.Mid.Count);
Assert.Equal(a.Count, c.Upper.Count); Assert.Equal(a.Count, c.Upper.Count);
Assert.Equal(a.Count, c.Lower.Count); Assert.Equal(a.Count, c.Lower.Count);
Assert.Equal(a.Count, c.PercentB.Count); Assert.Equal(a.Count, c.PercentB.Count);
Assert.Equal(a.Count, c.Zscore.Count); Assert.Equal(a.Count, c.Zscore.Count);
Assert.Equal(a.Count, c.Bandwidth.Count); Assert.Equal(a.Count, c.Bandwidth.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
Assert.Equal(a.Count, c.Mid.Count); Assert.Equal(a.Count, c.Mid.Count);
Assert.Equal(a.Count, c.Upper.Count); Assert.Equal(a.Count, c.Upper.Count);
Assert.Equal(a.Count, c.Lower.Count); Assert.Equal(a.Count, c.Lower.Count);
Assert.Equal(a.Count, c.PercentB.Count); Assert.Equal(a.Count, c.PercentB.Count);
Assert.Equal(a.Count, c.Zscore.Count); Assert.Equal(a.Count, c.Zscore.Count);
Assert.Equal(a.Count, c.Bandwidth.Count); Assert.Equal(a.Count, c.Bandwidth.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
BBANDS_Series c = new(a, 4, 2.5); BBANDS_Series c = new(a, 4, 2.5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
Assert.Equal(a.Count, c.Mid.Count); Assert.Equal(a.Count, c.Mid.Count);
Assert.Equal(a.Count, c.Upper.Count); Assert.Equal(a.Count, c.Upper.Count);
Assert.Equal(a.Count, c.Lower.Count); Assert.Equal(a.Count, c.Lower.Count);
Assert.Equal(a.Count, c.PercentB.Count); Assert.Equal(a.Count, c.PercentB.Count);
Assert.Equal(a.Count, c.Zscore.Count); Assert.Equal(a.Count, c.Zscore.Count);
Assert.Equal(a.Count, c.Bandwidth.Count); Assert.Equal(a.Count, c.Bandwidth.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
Assert.Equal(a.Count, c.Mid.Count); Assert.Equal(a.Count, c.Mid.Count);
Assert.Equal(a.Count, c.Upper.Count); Assert.Equal(a.Count, c.Upper.Count);
Assert.Equal(a.Count, c.Lower.Count); Assert.Equal(a.Count, c.Lower.Count);
Assert.Equal(a.Count, c.PercentB.Count); Assert.Equal(a.Count, c.PercentB.Count);
Assert.Equal(a.Count, c.Zscore.Count); Assert.Equal(a.Count, c.Zscore.Count);
Assert.Equal(a.Count, c.Bandwidth.Count); Assert.Equal(a.Count, c.Bandwidth.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class DEMA_Test public class DEMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
DEMA_Series c = new(a, 3); DEMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
DEMA_Series c = new(a, 3); DEMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class EMA_Test public class EMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
EMA_Series c = new(a, 3); EMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
EMA_Series c = new(a, 3); EMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class HEMA_Test public class HEMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
HEMA_Series c = new(a, 3); HEMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
HEMA_Series c = new(a, 3); HEMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class HMA_Test public class HMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
HMA_Series c = new(a, 3); HMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
HMA_Series c = new(a, 3); HMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class JMA_Test public class JMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
JMA_Series c = new(a, 3); JMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
JMA_Series c = new(a, 3); JMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class KAMA_Test public class KAMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
KAMA_Series c = new(a, 3); KAMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
KAMA_Series c = new(a, 3); KAMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class MACD_Test public class MACD_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
MACD_Series c = new(a, 26,12,9); MACD_Series c = new(a, 26,12,9);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
MACD_Series c = new(a, 26,12,9); MACD_Series c = new(a, 26,12,9);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class RMA_Test public class RMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
RMA_Series c = new(a, 3); RMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
RMA_Series c = new(a, 3); RMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class RSI_Test public class RSI_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
RSI_Series c = new(a, 3); RSI_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
RSI_Series c = new(a, 3); RSI_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class SMA_Test public class SMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
SMA_Series c = new(a, 3); SMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
SMA_Series c = new(a, 3); SMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class SMMA_Test public class SMMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
SMMA_Series c = new(a, 3); SMMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
SMMA_Series c = new(a, 3); SMMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class TEMA_Test public class TEMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
TEMA_Series c = new(a, 3); TEMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
TEMA_Series c = new(a, 3); TEMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class WMA_Test public class WMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
WMA_Series c = new(a, 3); WMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
WMA_Series c = new(a, 3); WMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace MovingAvg; namespace MovingAvg;
public class ZLEMA_Test public class ZLEMA_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
ZLEMA_Series c = new(a, 3); ZLEMA_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
ZLEMA_Series c = new(a, 3); ZLEMA_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class BIAS_Test public class BIAS_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
BIAS_Series c = new(a, 3); BIAS_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
BIAS_Series c = new(a, 3); BIAS_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class KURT_Test public class KURT_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
KURT_Series c = new(a, 3); KURT_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
KURT_Series c = new(a, 3); KURT_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class ENTP_Test public class ENTP_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
ENTP_Series c = new(a, 3); ENTP_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
ENTP_Series c = new(a, 3); ENTP_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class LINREG_Test public class LINREG_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
LINREG_Series c = new(a, 3); LINREG_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
LINREG_Series c = new(a, 3); LINREG_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class MAD_Test public class MAD_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
MAD_Series c = new(a, 3); MAD_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
MAD_Series c = new(a, 3); MAD_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class MAPE_Test public class MAPE_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
MAPE_Series c = new(a, 3); MAPE_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
MAPE_Series c = new(a, 3); MAPE_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class MAX_Test public class MAX_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
MAX_Series c = new(a, 3); MAX_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
MAX_Series c = new(a, 3); MAX_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class MED_Test public class MED_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
MED_Series c = new(a, 3); MED_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
MED_Series c = new(a, 3); MED_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class MIN_Test public class MIN_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
MIN_Series c = new(a, 3); MIN_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
MIN_Series c = new(a, 3); MIN_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class MSE_Test public class MSE_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
MSE_Series c = new(a, 3); MSE_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
MSE_Series c = new(a, 3); MSE_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class PSDEV_Test public class PSDEV_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
SDEV_Series c = new(a, 3); SDEV_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
SDEV_Series c = new(a, 3); SDEV_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class PVAR_Test public class PVAR_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
SVAR_Series c = new(a, 3); SVAR_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
SVAR_Series c = new(a, 3); SVAR_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class SDEV_Test public class SDEV_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
SSDEV_Series c = new(a, 3); SSDEV_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
SSDEV_Series c = new(a, 3); SSDEV_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class SMAPE_Test public class SMAPE_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
SMAPE_Series c = new(a, 3); SMAPE_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
SMAPE_Series c = new(a, 3); SMAPE_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class VAR_Test public class VAR_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
SVAR_Series c = new(a, 3); SVAR_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
SVAR_Series c = new(a, 3); SVAR_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+31 -31
View File
@@ -1,31 +1,31 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
namespace Statistics; namespace Statistics;
public class WMAPE_Test public class WMAPE_Test
{ {
[Fact] [Fact]
public void Add_Test() public void Add_Test()
{ {
TSeries a = new() { 0, 1, 2, 3, 4, 5 }; TSeries a = new() { 0, 1, 2, 3, 4, 5 };
WMAPE_Series c = new(a, 3); WMAPE_Series c = new(a, 3);
Assert.Equal(6, c.Count); Assert.Equal(6, c.Count);
a.Add(5); a.Add(5);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(0, update: true); a.Add(0, update: true);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
[Fact] [Fact]
public void Edge_Test() public void Edge_Test()
{ {
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
WMAPE_Series c = new(a, 3); WMAPE_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.NaN); a.Add(double.NaN);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
+5 -25
View File
@@ -5,42 +5,22 @@
<LangVersion>preview</LangVersion> <LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;MSB3270</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1701;1702;MSB3270</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NoWarn>1701;1702;MSB3270</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NoWarn>1701;1702;MSB3270</NoWarn>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="JetBrains.dotCover.CommandLineTools" Version="2022.3.0-eap07"> <PackageReference Include="JetBrains.dotCover.CommandLineTools" Version="2022.3.0-eap07">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0-preview-20221003-04" />
<PackageReference Include="Python.Included" Version="3.10.0-preview5" />
<PackageReference Include="TALib.NETCore" Version="0.4.4" /> <PackageReference Include="TALib.NETCore" Version="0.4.4" />
<PackageReference Include="Skender.Stock.Indicators" Version="2.4.0" /> <PackageReference Include="Skender.Stock.Indicators" Version="2.4.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+122 -121
View File
@@ -1,121 +1,122 @@
using Xunit; /*
using System; using Xunit;
using QuanTAlib; using System;
using Python.Runtime; using QuanTAlib;
using Python.Included; using Python.Runtime;
using Python.Included;
namespace Validation;
public class PandasTA namespace Validation;
{ public class PandasTA
private readonly RND_Feed bars; {
private readonly Random rnd = new(); private readonly RND_Feed bars;
private readonly int period; private readonly Random rnd = new();
private readonly dynamic ta; private readonly int period;
private readonly dynamic df; private readonly dynamic ta;
private readonly dynamic df;
public PandasTA()
{ public PandasTA()
this.bars = new(1000); {
this.period = this.rnd.Next(28) + 3; this.bars = new(1000);
this.period = this.rnd.Next(28) + 3;
Runtime.PythonDLL = @"python310.dll";
Installer.InstallPath = Path.GetFullPath("."); Runtime.PythonDLL = @"python310.dll";
Installer.SetupPython().Wait(); Installer.InstallPath = Path.GetFullPath(".");
Installer.TryInstallPip(); Installer.SetupPython().Wait();
Installer.PipInstallModule("numpy"); Installer.TryInstallPip();
Installer.PipInstallModule("pandas"); Installer.PipInstallModule("numpy");
Installer.PipInstallModule("pandas-ta"); Installer.PipInstallModule("pandas");
PythonEngine.Initialize(); Installer.PipInstallModule("pandas-ta");
this.ta = Py.Import("pandas_ta"); PythonEngine.Initialize();
this.df = this.ta.DataFrame(this.bars.Close.v); this.ta = Py.Import("pandas_ta");
} this.df = this.ta.DataFrame(this.bars.Close.v);
}
~PandasTA()
{ ~PandasTA()
PythonEngine.Shutdown(); {
} PythonEngine.Shutdown();
/* }
[Fact]
void SMA() [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); 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));
} Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
}
[Fact]
void EMA() [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); 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));
} Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
}
[Fact]
void TEMA() [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); 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));
} Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
}
[Fact]
void ENTP() [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); 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));
} Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
}
[Fact]
void WMA() [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); 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));
} Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
}
[Fact]
void DEMA() [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); 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));
} Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
}
[Fact]
void BIAS() [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); 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));
} Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
}
[Fact]
void KURT() [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); 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));
} Assert.Equal(System.Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
}
[Fact]
void MAD() [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); 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));
} Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
*/ }
} }
*/
+282 -282
View File
@@ -1,282 +1,282 @@
using System; using System;
using QuanTAlib; using QuanTAlib;
using Skender.Stock.Indicators; using Skender.Stock.Indicators;
using Xunit; using Xunit;
namespace Validation; namespace Validation;
public class Skender_Stock public class Skender_Stock
{ {
private readonly GBM_Feed bars; private readonly GBM_Feed bars;
private readonly Random rnd = new(); private readonly Random rnd = new();
private readonly int period; private readonly int period;
private readonly IEnumerable<Quote> quotes; private readonly IEnumerable<Quote> quotes;
public Skender_Stock() public Skender_Stock()
{ {
this.bars = new(Bars: 5000, Volatility:0.7, Drift:0.0); this.bars = new(Bars: 5000, Volatility:0.7, Drift:0.0);
this.period = this.rnd.Next(28) + 3; this.period = this.rnd.Next(28) + 3;
this.quotes = this.bars.Select( this.quotes = this.bars.Select(
q => new Quote q => new Quote
{ {
Date = q.t, Date = q.t,
Open = (decimal)q.o, Open = (decimal)q.o,
High = (decimal)q.h, High = (decimal)q.h,
Low = (decimal)q.l, Low = (decimal)q.l,
Close = (decimal)q.c, Close = (decimal)q.c,
Volume = (decimal)q.v Volume = (decimal)q.v
}); });
} }
[Fact] [Fact]
public void SMA() public void SMA()
{ {
SMA_Series QL = new(this.bars.Close, this.period, false); SMA_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetSma(this.period); var SK = this.quotes.GetSma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void EMA() public void EMA()
{ {
EMA_Series QL = new(this.bars.Close, this.period, false); EMA_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetEma(this.period); var SK = this.quotes.GetEma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Ema!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Ema!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void WMA() public void WMA()
{ {
WMA_Series QL = new(this.bars.Close, this.period, false); WMA_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetWma(this.period); var SK = this.quotes.GetWma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Wma!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Wma!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void DEMA() public void DEMA()
{ {
DEMA_Series QL = new(this.bars.Close, this.period, false); DEMA_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetDema(this.period); var SK = this.quotes.GetDema(this.period);
Assert.Equal(Math.Round((double)SK.Last().Dema!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Dema!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void TEMA() public void TEMA()
{ {
TEMA_Series QL = new(this.bars.Close, this.period, false); TEMA_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetTema(this.period); var SK = this.quotes.GetTema(this.period);
Assert.Equal(Math.Round((double)SK.Last().Tema!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Tema!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void MAD() public void MAD()
{ {
MAD_Series QL = new(this.bars.Close, this.period, false); MAD_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetSmaAnalysis(this.period); var SK = this.quotes.GetSmaAnalysis(this.period);
Assert.Equal(Math.Round((double)SK.Last().Mad!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Mad!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void MAPE() public void MAPE()
{ {
MAPE_Series QL = new(this.bars.Close, this.period, false); MAPE_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetSmaAnalysis(this.period); var SK = this.quotes.GetSmaAnalysis(this.period);
Assert.Equal(Math.Round((double)SK.Last().Mape!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Mape!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void ATR() public void ATR()
{ {
ATR_Series QL = new(this.bars, this.period, false); ATR_Series QL = new(this.bars, this.period, false);
var SK = this.quotes.GetAtr(this.period); var SK = this.quotes.GetAtr(this.period);
Assert.Equal(Math.Round((double)SK.Last().Atr!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Atr!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void OBV() public void OBV()
{ {
OBV_Series QL = new(this.bars, this.period, false); OBV_Series QL = new(this.bars, this.period, false);
var SK = this.quotes.GetObv(this.period); var SK = this.quotes.GetObv(this.period);
// adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB // 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), Assert.Equal(Math.Round(SK.Last().Obv! + (double)this.quotes.First().Volume!, 5),
Math.Round(QL.Last().v, 6)); Math.Round(QL.Last().v, 5));
} }
[Fact] [Fact]
public void ADL() public void ADL()
{ {
ADL_Series QL = new(this.bars, false); ADL_Series QL = new(this.bars, false);
var SK = this.quotes.GetAdl(); var SK = this.quotes.GetAdl();
Assert.Equal(Math.Round((double)SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5)); Assert.Equal(Math.Round((double)SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5));
} }
[Fact] [Fact]
public void CCI() public void CCI()
{ {
CCI_Series QL = new(this.bars, this.period, false); CCI_Series QL = new(this.bars, this.period, false);
var SK = this.quotes.GetCci(this.period); var SK = this.quotes.GetCci(this.period);
Assert.Equal(Math.Round((double)SK.Last().Cci!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Cci!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void ATRP() public void ATRP()
{ {
ATRP_Series QL = new(this.bars, this.period, false); ATRP_Series QL = new(this.bars, this.period, false);
var SK = this.quotes.GetAtr(this.period); var SK = this.quotes.GetAtr(this.period);
Assert.Equal(Math.Round((double)SK.Last().Atrp!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Atrp!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void KAMA() public void KAMA()
{ {
KAMA_Series QL = new(this.bars.Close, this.period, useNaN: false); KAMA_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetKama(this.period); var SK = this.quotes.GetKama(this.period);
Assert.Equal(Math.Round((double)SK.Last().Kama!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Kama!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void HMA() public void HMA()
{ {
HMA_Series QL = new(this.bars.Close, this.period, useNaN: false); HMA_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetHma(this.period); var SK = this.quotes.GetHma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Hma!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Hma!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void SMMA() public void SMMA()
{ {
SMMA_Series QL = new(this.bars.Close, this.period, useNaN: false); SMMA_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetSmma(this.period); var SK = this.quotes.GetSmma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Smma!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Smma!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void MACD() public void MACD()
{ {
MACD_Series QL = new(this.bars.Close, 26,12,9, useNaN: false); MACD_Series QL = new(this.bars.Close, 26,12,9, useNaN: false);
var SK = this.quotes.GetMacd(12,26,9); 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().Macd!, 6), Math.Round(QL.Last().v, 6));
Assert.Equal(Math.Round((double)SK.Last().Signal!, 6), Math.Round(QL.Signal.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Signal!, 6), Math.Round(QL.Signal.Last().v, 6));
} }
[Fact] [Fact]
public void BBANDS() public void BBANDS()
{ {
BBANDS_Series QL = new(this.bars.Close, this.period, 2.0, useNaN: false); BBANDS_Series QL = new(this.bars.Close, this.period, 2.0, useNaN: false);
var SK = this.quotes.GetBollingerBands(this.period, 2.0); 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().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().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().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().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().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)); Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Zscore.Last().v, 6));
} }
[Fact] [Fact]
public void RSI() public void RSI()
{ {
RSI_Series QL = new(this.bars.Close, this.period, useNaN: false); RSI_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetRsi(this.period); var SK = this.quotes.GetRsi(this.period);
Assert.Equal(Math.Round((double)SK.Last().Rsi!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Rsi!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void ALMA() public void ALMA()
{ {
ALMA_Series QL = new(this.bars.Close, this.period, useNaN: false); ALMA_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetAlma(this.period); var SK = this.quotes.GetAlma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Alma!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Alma!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void SDEV() public void SDEV()
{ {
SDEV_Series QL = new(this.bars.Close, this.period, useNaN: false); SDEV_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetStdDev(this.period); var SK = this.quotes.GetStdDev(this.period);
Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void LINREG() public void LINREG()
{ {
LINREG_Series QL = new(this.bars.Close, this.period, useNaN: false); LINREG_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetSlope(this.period); 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().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().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().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)); Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.StdDev.Last().v, 6));
} }
[Fact] [Fact]
public void TR() public void TR()
{ {
TR_Series QL = new(this.bars, useNaN: false); TR_Series QL = new(this.bars, useNaN: false);
var SK = this.quotes.GetTr(); var SK = this.quotes.GetTr();
Assert.Equal(Math.Round((double)SK.Last().Tr!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Tr!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void HL2() public void HL2()
{ {
TSeries QL = this.bars.HL2; TSeries QL = this.bars.HL2;
var SK = this.quotes.GetBaseQuote(CandlePart.HL2); var SK = this.quotes.GetBaseQuote(CandlePart.HL2);
Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void OC2() public void OC2()
{ {
TSeries QL = this.bars.OC2; TSeries QL = this.bars.OC2;
var SK = this.quotes.GetBaseQuote(CandlePart.OC2); var SK = this.quotes.GetBaseQuote(CandlePart.OC2);
Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void HLC3() public void HLC3()
{ {
TSeries QL = this.bars.HLC3; TSeries QL = this.bars.HLC3;
var SK = this.quotes.GetBaseQuote(CandlePart.HLC3); var SK = this.quotes.GetBaseQuote(CandlePart.HLC3);
Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void OHL3() public void OHL3()
{ {
TSeries QL = this.bars.OHL3; TSeries QL = this.bars.OHL3;
var SK = this.quotes.GetBaseQuote(CandlePart.OHL3); var SK = this.quotes.GetBaseQuote(CandlePart.OHL3);
Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void OHLC4() public void OHLC4()
{ {
TSeries QL = this.bars.OHLC4; TSeries QL = this.bars.OHLC4;
var SK = this.quotes.GetBaseQuote(CandlePart.OHLC4); var SK = this.quotes.GetBaseQuote(CandlePart.OHLC4);
Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
} }
} }
+272 -272
View File
@@ -1,272 +1,272 @@
using Xunit; using Xunit;
using System; using System;
using TALib; using TALib;
using QuanTAlib; using QuanTAlib;
namespace Validation; namespace Validation;
public class TA_LIB public class TA_LIB
{ {
private readonly GBM_Feed bars; private readonly GBM_Feed bars;
private readonly Random rnd = new(); private readonly Random rnd = new();
private readonly int period; private readonly int period;
private readonly double[] TALIB; private readonly double[] TALIB;
private readonly double[] inopen; private readonly double[] inopen;
private readonly double[] inhigh; private readonly double[] inhigh;
private readonly double[] inlow; private readonly double[] inlow;
private readonly double[] inclose; private readonly double[] inclose;
private readonly double[] involume; private readonly double[] involume;
public TA_LIB() public TA_LIB()
{ {
this.bars = new(5000); this.bars = new(5000);
this.period = this.rnd.Next(28) + 3; this.period = this.rnd.Next(28) + 3;
this.TALIB = new double[this.bars.Count]; this.TALIB = new double[this.bars.Count];
this.inopen = this.bars.Open.v.ToArray(); this.inopen = this.bars.Open.v.ToArray();
this.inhigh = this.bars.High.v.ToArray(); this.inhigh = this.bars.High.v.ToArray();
this.inlow = this.bars.Low.v.ToArray(); this.inlow = this.bars.Low.v.ToArray();
this.inclose = this.bars.Close.v.ToArray(); this.inclose = this.bars.Close.v.ToArray();
this.involume = this.bars.Volume.v.ToArray(); this.involume = this.bars.Volume.v.ToArray();
} }
///////////////////////////////////////// /////////////////////////////////////////
[Fact] [Fact]
public void ADD() public void ADD()
{ {
ADD_Series QL = new(this.bars.Open, this.bars.Close); 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 _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void SUB() public void SUB()
{ {
SUB_Series QL = new(this.bars.Open, this.bars.Close); 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 _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void MUL() public void MUL()
{ {
MUL_Series QL = new(this.bars.Open, this.bars.Close); 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 _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void DIV() public void DIV()
{ {
DIV_Series QL = new(this.bars.Open, this.bars.Close); 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 _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void SDEV() public void SDEV()
{ {
SDEV_Series QL = new(this.bars.Close, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void SMA() public void SMA()
{ {
SMA_Series QL = new(this.bars.Close, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void TRIMA() public void TRIMA()
{ {
TRIMA_Series QL = new(this.bars.Close, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void EMA() public void EMA()
{ {
EMA_Series QL = new(this.bars.Close, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void WMA() public void WMA()
{ {
WMA_Series QL = new(this.bars.Close, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void DEMA() public void DEMA()
{ {
DEMA_Series QL = new(this.bars.Close, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void TEMA() public void TEMA()
{ {
TEMA_Series QL = new(this.bars.Close, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void MAX() public void MAX()
{ {
MAX_Series QL = new(this.bars.Close, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void MIN() public void MIN()
{ {
MIN_Series QL = new(this.bars.Close, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void ADL() public void ADL()
{ {
ADL_Series QL = new(this.bars, false); 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 _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void OBV() public void OBV()
{ {
OBV_Series QL = new(this.bars, this.period, false); 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 _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void ADOSC() public void ADOSC()
{ {
ADOSC_Series QL = new(this.bars, false); 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 _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void ATR() public void ATR()
{ {
ATR_Series QL = new(this.bars, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void CCI() public void CCI()
{ {
CCI_Series QL = new(this.bars, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void RSI() public void RSI()
{ {
RSI_Series QL = new(this.bars.Close, this.period, false); 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); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void TR() public void TR()
{ {
TR_Series QL = new(this.bars, false); 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 _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void MACD() public void MACD()
{ {
double[] macdSignal = new double[this.bars.Count]; double[] macdSignal = new double[this.bars.Count];
double[] macdHist = 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); 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 _); 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(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)); Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Signal.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void BBANDS() public void BBANDS()
{ {
double[] outMiddle = new double[this.bars.Count]; double[] outMiddle = new double[this.bars.Count];
double[] outUpper = new double[this.bars.Count]; double[] outUpper = new double[this.bars.Count];
double[] outLower = 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); 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); 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(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(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)); Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Lower.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void HL2() public void HL2()
{ {
TSeries QL = this.bars.HL2; TSeries QL = this.bars.HL2;
Core.MedPrice(this.inhigh, this.inlow, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void HLC3() public void HLC3()
{ {
TSeries QL = this.bars.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 _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void OHLC4() public void OHLC4()
{ {
TSeries QL = this.bars.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 _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void HLCC4() public void HLCC4()
{ {
TSeries QL = this.bars.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 _); 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)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
} }
+16 -15
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -181,7 +181,7 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
| ⛔ AOBV - Archer On-Balance Volume |||| | ⛔ AOBV - Archer On-Balance Volume ||||
| ⛔ CMF - Chaikin Money Flow |||| | ⛔ CMF - Chaikin Money Flow ||||
| ⛔ EOM - Ease of Movement |||| | ⛔ EOM - Ease of Movement ||||
| ⭐ OBV - On-Balance Volume | `OBV_Series` | OBV | GetObv | | ⭐ OBV - On-Balance Volume | ` OBV_Series` | OBV | GetObv |
| ⛔ PRS - Price Relative Strength ||| | ⛔ PRS - Price Relative Strength |||
| ⛔ PVOL - Price-Volume |||| | ⛔ PVOL - Price-Volume ||||
| ⛔ PVO - Percentage Volume Oscillator |||| | ⛔ PVO - Percentage Volume Oscillator ||||