Merge branch 'dev' into main

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