mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-03 03:47:42 +00:00
Merge branch 'dev' into main
This commit is contained in:
@@ -87,6 +87,20 @@ jobs:
|
||||
title: "Latest Build"
|
||||
files: /Quantower/Settings/Scripts/Indicators/QuanTAlib/*.dll
|
||||
|
||||
- name: Authenticate to Github packages source
|
||||
run: dotnet nuget add source
|
||||
--username mihakralj
|
||||
--password ${{ secrets.GITHUB_TOKEN }}
|
||||
--store-password-in-clear-text
|
||||
--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'
|
||||
--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' }}
|
||||
run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg'
|
||||
|
||||
@@ -30,8 +30,8 @@ public class ATR_chart : Indicator
|
||||
this.ShortName = "ATR (" + this.Period + ")";
|
||||
this.bars = new();
|
||||
this.indicator = new(source: bars, period: this.Period, useNaN: false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void OnUpdate(UpdateArgs args)
|
||||
{
|
||||
bool update = !(args.Reason == UpdateReason.NewBar ||
|
||||
|
||||
@@ -51,11 +51,6 @@ public class WMAPE_chart : Indicator
|
||||
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);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Text;
|
||||
using TradingPlatform.BusinessLayer;
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class ZLMA_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 = 3;
|
||||
|
||||
[InputParameter("MA algorithm", 2, variants: new object[]
|
||||
{ "SMA", 0,
|
||||
"WMA", 1,
|
||||
"EMA", 2,
|
||||
"DEMA", 3,
|
||||
"TEMA", 4,
|
||||
"HMA", 5,
|
||||
"KAMA", 6,
|
||||
"JMA", 7,
|
||||
"SMMA", 8
|
||||
})]
|
||||
private readonly int matype = 2;
|
||||
|
||||
#endregion Parameters
|
||||
|
||||
private TBars bars;
|
||||
///////
|
||||
private TSeries indicator;
|
||||
///////
|
||||
|
||||
public ZLMA_chart()
|
||||
{
|
||||
this.SeparateWindow = false;
|
||||
this.Name = "ZLMA - Zero-lag Moving Average";
|
||||
this.Description = "Zero-Lag Moving Average description";
|
||||
this.AddLineSeries("ZLMA", Color.RoyalBlue, 3, LineStyle.Solid);
|
||||
}
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
this.bars = new();
|
||||
string maname = matype switch
|
||||
{
|
||||
0 => "SMA",
|
||||
1 => "WMA",
|
||||
2 => "EMA",
|
||||
3 => "DEMA",
|
||||
4 => "TEMA",
|
||||
5 => "HMA",
|
||||
6 => "KAMA",
|
||||
7 => "JMA",
|
||||
8 => "SMMA",
|
||||
_ => "???"
|
||||
};
|
||||
|
||||
this.ShortName = "ZLMA (" + maname + ", " + TBars.SelectStr(this.DataSource) + ", " + this.Period + ")";
|
||||
ZL_Series zerolag = new(source: bars.Select(this.DataSource), period: this.Period, useNaN: false);
|
||||
this.indicator = matype switch
|
||||
{
|
||||
0 => new SMA_Series(source: zerolag, period: this.Period, useNaN: false),
|
||||
1 => new WMA_Series(source: zerolag, period: this.Period, useNaN: false),
|
||||
2 => new EMA_Series(source: zerolag, period: this.Period, useNaN: false),
|
||||
3 => new DEMA_Series(source: zerolag, period: this.Period, useNaN: false),
|
||||
4 => new TEMA_Series(source: zerolag, period: this.Period, useNaN: false),
|
||||
5 => new HMA_Series(source: zerolag, period: this.Period, useNaN: false),
|
||||
6 => new KAMA_Series(source: zerolag, period: this.Period, useNaN: false),
|
||||
7 => new JMA_Series(source: zerolag, period: this.Period, useNaN: false),
|
||||
8 => new SMMA_Series(source: zerolag, period: this.Period, useNaN: false),
|
||||
_ => new EMA_Series(source: zerolag, period: this.Period, useNaN: false)
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnUpdate(UpdateArgs args)
|
||||
{
|
||||
bool update = !(args.Reason == UpdateReason.NewBar ||
|
||||
args.Reason == UpdateReason.HistoricalBar);
|
||||
this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
|
||||
this.GetPrice(PriceType.High), this.GetPrice(PriceType.Low),
|
||||
this.GetPrice(PriceType.Close),
|
||||
this.GetPrice(PriceType.Volume), update);
|
||||
|
||||
double result = this.indicator[this.indicator.Count-1].v;
|
||||
this.SetValue(result);
|
||||
}
|
||||
}
|
||||
+17
-51
@@ -32,23 +32,14 @@ public abstract class Single_TSeries_Indicator : TSeries
|
||||
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 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 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;
|
||||
@@ -83,24 +74,14 @@ public abstract class Pair_TSeries_Indicator : TSeries
|
||||
}
|
||||
|
||||
// overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list
|
||||
public virtual void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update)
|
||||
=> base.Add(TValue: (TValue1.t, 0), update: update); // default inserts zeros
|
||||
|
||||
public virtual void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update) => base.Add(TValue: (TValue1.t, 0), update: update); // default inserts zeros
|
||||
|
||||
// potentially overridable Add() bulk variations (could be replaced with faster bulk algos)
|
||||
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 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((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2) => this.Add(TValue1, TValue2, update: false);
|
||||
|
||||
public void Add(bool update)
|
||||
{
|
||||
@@ -123,12 +104,9 @@ public abstract class Pair_TSeries_Indicator : TSeries
|
||||
}
|
||||
|
||||
public void Add() => this.Add(update: false);
|
||||
|
||||
public new void Sub(object source, TSeriesEventArgs e)
|
||||
=> this.Add(e.update);
|
||||
public new void Sub(object source, TSeriesEventArgs e) => this.Add(e.update);
|
||||
}
|
||||
|
||||
|
||||
public abstract class Single_TBars_Indicator : TSeries
|
||||
{
|
||||
protected readonly int _p;
|
||||
@@ -148,22 +126,10 @@ public abstract class Single_TBars_Indicator : TSeries
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,10 @@ public class MAX_Series : Single_TSeries_Indicator
|
||||
|
||||
double _max = TValue.v;
|
||||
for (int i = 0; i < this._buffer.Count; i++)
|
||||
{ _max = (this._buffer[i] > _max) ? this._buffer[i] : _max; }
|
||||
{
|
||||
//_max = (this._buffer[i] > _max) ? this._buffer[i] : _max;
|
||||
_max = Math.Max(this._buffer[i], _max);
|
||||
}
|
||||
|
||||
var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _max);
|
||||
|
||||
|
||||
@@ -22,7 +22,10 @@ public class MIN_Series : Single_TSeries_Indicator
|
||||
|
||||
double _min = TValue.v;
|
||||
for (int i = 0; i < this._buffer.Count; i++)
|
||||
{ _min = (this._buffer[i] < _min) ? this._buffer[i] : _min; }
|
||||
{
|
||||
//_min = (this._buffer[i] < _min) ? this._buffer[i] : _min;
|
||||
_min = Math.Min(this._buffer[i], _min);
|
||||
}
|
||||
|
||||
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _min);
|
||||
|
||||
|
||||
@@ -75,7 +75,6 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
@@ -130,6 +129,4 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub
|
||||
Pub(this, new TSeriesEventArgs { update = update });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,5 @@ public class ZL_Series : Single_TSeries_Indicator
|
||||
|
||||
var ret = (TValue.t, (base.Count==0 && base._NaN) ? double.NaN : _zl );
|
||||
base.Add(ret, update);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -55,4 +55,3 @@ public class Alphavantage_Feed : TBars
|
||||
return (date, o, h, l, c, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,11 +38,11 @@ public class GBM_Feed : TBars
|
||||
|
||||
double OCMax = Math.Max(Open,Close);
|
||||
double High = (GBM_value(seed, volatility*0.5, 0));
|
||||
High = (High<OCMax)? 2*OCMax-High : High;
|
||||
High = (High<OCMax)? (2 * OCMax) - High : High;
|
||||
|
||||
double OCMin = Math.Min(Open,Close);
|
||||
double Low = (GBM_value(seed, volatility*0.5, 0));
|
||||
Low = (Low>OCMin)? 2*OCMin-Low : Low;
|
||||
Low = (Low>OCMin)? (2 * OCMin) - Low : Low;
|
||||
|
||||
double Volume = GBM_value(seed*10, volatility*2, Drift:0);
|
||||
|
||||
@@ -55,6 +55,6 @@ public class GBM_Feed : TBars
|
||||
double U1 = 1.0-rnd.NextDouble();
|
||||
double U2 = 1.0-rnd.NextDouble();
|
||||
double Z = Math.Sqrt(-2.0 * Math.Log(U1)) * Math.Sin(2.0 * Math.PI * U2);
|
||||
return Seed * Math.Exp( Drift - (Volatility*Volatility*0.5) + Volatility * Z);
|
||||
return Seed * Math.Exp( Drift - (Volatility*Volatility*0.5) + (Volatility * Z));
|
||||
}
|
||||
}
|
||||
@@ -17,10 +17,10 @@ public class RND_Feed : TBars
|
||||
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 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);
|
||||
}
|
||||
|
||||
@@ -20,14 +20,13 @@ 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) {
|
||||
|
||||
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) {
|
||||
|
||||
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); }
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Version>0.1.17</Version>
|
||||
<Version>0.1.18</Version>
|
||||
<releaseNotes>
|
||||
</releaseNotes>
|
||||
<Title>QuanTAlib</Title>
|
||||
|
||||
@@ -54,7 +54,7 @@ public class KURT_Series : Single_TSeries_Indicator
|
||||
}
|
||||
|
||||
double _Vx = _s2 / (_n - 1);
|
||||
double _kurt = (_n > 3) ? (((_n * (_n + 1)) / ((_n - 1) * (_n - 2) * (_n - 3))) * (_s4 / (_Vx * _Vx)) - (3 * ((_n - 1) * (_n - 1) / ((_n - 2) * (_n - 3))))) : Double.NaN;
|
||||
double _kurt = (_n > 3) ? ((((_n * (_n + 1)) / (((_n - 1) * (_n - 2)) * (_n - 3))) * (_s4 / (_Vx * _Vx))) - (3 * (((_n - 1) * (_n - 1)) / ((_n - 2) * (_n - 3))))) : Double.NaN;
|
||||
|
||||
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? Double.NaN : _kurt);
|
||||
base.Add(result, update);
|
||||
|
||||
@@ -37,7 +37,7 @@ public class MED_Series : Single_TSeries_Indicator
|
||||
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);
|
||||
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);
|
||||
|
||||
@@ -1,68 +1,65 @@
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
_offset = offset;
|
||||
_sigma = sigma;
|
||||
_weight = new double[period];
|
||||
|
||||
if (this._data.Count > 0) { base.Add(this._data); }
|
||||
}
|
||||
|
||||
public override void Add((System.DateTime t, double v) TValue, bool update)
|
||||
{
|
||||
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
|
||||
else { this._buffer.Add(TValue.v); }
|
||||
if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); }
|
||||
|
||||
if (this._buffer.Count <= _p) { calc_weights(); }
|
||||
|
||||
double _weightedSum = 0;
|
||||
for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; }
|
||||
double _alma = _weightedSum / _norm;
|
||||
|
||||
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _alma);
|
||||
base.Add(ret, update);
|
||||
}
|
||||
|
||||
private void calc_weights()
|
||||
{
|
||||
int _len = this._buffer.Count;
|
||||
_norm = 0;
|
||||
double _m = _offset * (_len - 1);
|
||||
double _s = _len / _sigma;
|
||||
for (int i = 0; i < _len; i++)
|
||||
{
|
||||
double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
|
||||
_weight[i] = _wt;
|
||||
_norm += _wt;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
|
||||
/* <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
|
||||
{
|
||||
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)
|
||||
{
|
||||
_offset = offset;
|
||||
_sigma = sigma;
|
||||
_weight = new double[period];
|
||||
|
||||
if (this._data.Count > 0) { base.Add(this._data); }
|
||||
}
|
||||
|
||||
public override void Add((System.DateTime t, double v) TValue, bool update)
|
||||
{
|
||||
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
|
||||
else { this._buffer.Add(TValue.v); }
|
||||
if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); }
|
||||
|
||||
if (this._buffer.Count <= _p) { calc_weights(); }
|
||||
|
||||
double _weightedSum = 0;
|
||||
for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; }
|
||||
double _alma = _weightedSum / _norm;
|
||||
|
||||
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _alma);
|
||||
base.Add(ret, update);
|
||||
}
|
||||
|
||||
private void calc_weights()
|
||||
{
|
||||
int _len = this._buffer.Count;
|
||||
_norm = 0;
|
||||
double _m = _offset * (_len - 1);
|
||||
double _s = _len / _sigma;
|
||||
for (int i = 0; i < _len; i++)
|
||||
{
|
||||
double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
|
||||
_weight[i] = _wt;
|
||||
_norm += _wt;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@ public class DEMA_Series : Single_TSeries_Indicator
|
||||
|
||||
public override void Add((DateTime t, double v) TValue, bool update)
|
||||
{
|
||||
|
||||
if (update)
|
||||
{
|
||||
this._lastema1 = this._lastlastema1;
|
||||
@@ -53,15 +52,14 @@ public class DEMA_Series : Single_TSeries_Indicator
|
||||
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;
|
||||
_ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m);
|
||||
_ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m);
|
||||
}
|
||||
|
||||
double _dema = 2 * _ema1 - _ema2;
|
||||
double _dema = (2 * _ema1) - _ema2;
|
||||
this._lastlastema1 = this._lastema1;
|
||||
this._lastlastema2 = this._lastema2;
|
||||
this._lastema1 = _ema1;
|
||||
@@ -52,7 +52,7 @@ public class EMA_Series : Single_TSeries_Indicator
|
||||
}
|
||||
else
|
||||
{
|
||||
_ema = TValue.v * this._k + this._lastema * this._k1m;
|
||||
_ema = (TValue.v * this._k) + (this._lastema * this._k1m);
|
||||
}
|
||||
|
||||
this._lastlastema = this._lastema;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public class RMA_Series : Single_TSeries_Indicator
|
||||
}
|
||||
else
|
||||
{
|
||||
_ema = TValue.v * _k + _lastema * _k1m;
|
||||
_ema = (TValue.v * _k) + (_lastema * _k1m);
|
||||
}
|
||||
|
||||
this._lastlastema = this._lastema;
|
||||
@@ -33,7 +33,6 @@ public class TEMA_Series : Single_TSeries_Indicator
|
||||
|
||||
public override void Add((DateTime t, double v) TValue, bool update)
|
||||
{
|
||||
|
||||
if (update)
|
||||
{
|
||||
this._lastema1 = this._lastlastema1;
|
||||
@@ -59,12 +58,12 @@ public class TEMA_Series : Single_TSeries_Indicator
|
||||
}
|
||||
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;
|
||||
_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;
|
||||
double _tema = (3 * (_ema1 - _ema2)) + _ema3;
|
||||
|
||||
this._lastlastema1 = this._lastema1;
|
||||
this._lastlastema2 = this._lastema2;
|
||||
@@ -0,0 +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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ public class ATRP_Series : Single_TBars_Indicator
|
||||
for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; }
|
||||
_ema /= this._buffer.Count;
|
||||
}
|
||||
else { _ema = d.v * _k + _lastema * _k1m; }
|
||||
else { _ema = (d.v * _k) + (_lastema * _k1m); }
|
||||
|
||||
this._lastlastema = this._lastema;
|
||||
this._lastema = _ema;
|
||||
@@ -13,7 +13,6 @@ Sources:
|
||||
|
||||
</summary> */
|
||||
|
||||
|
||||
public class ATR_Series : Single_TBars_Indicator
|
||||
{
|
||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||
@@ -53,7 +52,7 @@ public class ATR_Series : Single_TBars_Indicator
|
||||
for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; }
|
||||
_ema /= this._buffer.Count;
|
||||
}
|
||||
else { _ema = d.v * _k + _lastema * _k1m; }
|
||||
else { _ema = (d.v * _k) + (_lastema * _k1m); }
|
||||
|
||||
this._lastlastema = this._lastema;
|
||||
this._lastema = _ema;
|
||||
@@ -0,0 +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);
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,5 @@ public class TBars_Test
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ public class TSeries_Test
|
||||
TSeries t = s;
|
||||
Assert.Equal(5, (double)t);
|
||||
Assert.Equal(5, t.Count);
|
||||
|
||||
}
|
||||
[Fact]
|
||||
public void BroadcastingEvents()
|
||||
@@ -58,6 +57,5 @@ public class TSeries_Test
|
||||
s.Pub += t.Sub;
|
||||
s.Add(0.0, update: true);
|
||||
Assert.Equal(0.0, (double)t);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class ALMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,7 +52,5 @@ public class BBANDS_Test
|
||||
Assert.Equal(a.Count, c.PercentB.Count);
|
||||
Assert.Equal(a.Count, c.Zscore.Count);
|
||||
Assert.Equal(a.Count, c.Bandwidth.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class DEMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class EMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class HEMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class HMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class JMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class KAMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class MACD_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class RMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class RSI_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class SMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class SMMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class TEMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class WMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class ZLEMA_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class BIAS_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class KURT_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class ENTP_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class LINREG_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class MAD_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class MAPE_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class MAX_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class MED_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class MIN_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class MSE_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class PSDEV_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class PVAR_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class SDEV_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class SMAPE_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class VAR_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,5 @@ public class WMAPE_Test
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
using Xunit;
|
||||
using System;
|
||||
using QuanTAlib;
|
||||
@@ -120,5 +118,4 @@ public class PandasTA
|
||||
Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using QuanTAlib;
|
||||
using Skender.Stock.Indicators;
|
||||
using Xunit;
|
||||
|
||||
|
||||
namespace Validation;
|
||||
public class Skender_Stock
|
||||
{
|
||||
@@ -14,7 +13,7 @@ public class Skender_Stock
|
||||
|
||||
public Skender_Stock()
|
||||
{
|
||||
this.bars = new(1000);
|
||||
this.bars = new(Bars: 1, Volatility:0.7, Drift:0.0);
|
||||
this.period = this.rnd.Next(28) + 3;
|
||||
this.quotes = this.bars.Select(
|
||||
q => new Quote
|
||||
@@ -34,7 +33,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -43,7 +42,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Ema!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
[Fact]
|
||||
public void WMA()
|
||||
@@ -51,7 +50,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Wma!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -60,7 +59,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Dema!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -69,7 +68,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Tema!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -78,7 +77,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Mad!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -87,7 +86,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Mape!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -96,7 +95,18 @@ public class Skender_Stock
|
||||
ATR_Series QL = new(this.bars, this.period, false);
|
||||
var SK = this.quotes.GetAtr(this.period);
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Atr!, 8), Math.Round(QL.Last().v, 8));
|
||||
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]
|
||||
@@ -105,7 +115,7 @@ public class Skender_Stock
|
||||
ADL_Series QL = new(this.bars, false);
|
||||
var SK = this.quotes.GetAdl();
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Adl!, 6), Math.Round(QL.Last().v, 6));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -114,7 +124,7 @@ public class Skender_Stock
|
||||
CCI_Series QL = new(this.bars, this.period, false);
|
||||
var SK = this.quotes.GetCci(this.period);
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Cci!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Cci!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -123,7 +133,7 @@ public class Skender_Stock
|
||||
ATRP_Series QL = new(this.bars, this.period, false);
|
||||
var SK = this.quotes.GetAtr(this.period);
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Atrp!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Atrp!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -132,7 +142,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Kama!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -141,7 +151,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Hma!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -150,7 +160,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Smma!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -159,8 +169,8 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Signal!, 8), Math.Round(QL.Signal.Last().v, 8));
|
||||
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]
|
||||
@@ -169,22 +179,21 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Mid.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().UpperBand!, 8), Math.Round(QL.Upper.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().LowerBand!, 8), Math.Round(QL.Lower.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Width!, 8), Math.Round(QL.Bandwidth.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().PercentB!, 8), Math.Round(QL.PercentB.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().ZScore!, 8), Math.Round(QL.Zscore.Last().v, 8));
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Rsi!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -193,7 +202,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Alma!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -202,7 +211,7 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -211,10 +220,10 @@ public class Skender_Stock
|
||||
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!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Intercept!, 8), Math.Round(QL.Intercept.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().RSquared!, 8), Math.Round(QL.RSquared.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().StdDev!, 8), Math.Round(QL.StdDev.Last().v, 8));
|
||||
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]
|
||||
@@ -223,7 +232,7 @@ public class Skender_Stock
|
||||
TR_Series QL = new(this.bars, useNaN: false);
|
||||
var SK = this.quotes.GetTr();
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Tr!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Tr!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -232,7 +241,7 @@ public class Skender_Stock
|
||||
TSeries QL = this.bars.HL2;
|
||||
var SK = this.quotes.GetBaseQuote(CandlePart.HL2);
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -241,7 +250,7 @@ public class Skender_Stock
|
||||
TSeries QL = this.bars.OC2;
|
||||
var SK = this.quotes.GetBaseQuote(CandlePart.OC2);
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -250,7 +259,7 @@ public class Skender_Stock
|
||||
TSeries QL = this.bars.HLC3;
|
||||
var SK = this.quotes.GetBaseQuote(CandlePart.HLC3);
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -259,7 +268,7 @@ public class Skender_Stock
|
||||
TSeries QL = this.bars.OHL3;
|
||||
var SK = this.quotes.GetBaseQuote(CandlePart.OHL3);
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -268,6 +277,6 @@ public class Skender_Stock
|
||||
TSeries QL = this.bars.OHLC4;
|
||||
var SK = this.quotes.GetBaseQuote(CandlePart.OHLC4);
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
|
||||
}
|
||||
}
|
||||
|
||||
+47
-34
@@ -18,7 +18,7 @@ public class TA_LIB
|
||||
|
||||
public TA_LIB()
|
||||
{
|
||||
this.bars = new(1000);
|
||||
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();
|
||||
@@ -36,7 +36,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -45,7 +45,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -54,7 +54,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -63,7 +63,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -72,17 +72,25 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
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]
|
||||
@@ -91,7 +99,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -99,8 +107,8 @@ public class TA_LIB
|
||||
{
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -109,7 +117,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -118,7 +126,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -127,7 +135,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -136,7 +144,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -145,7 +153,16 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
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]
|
||||
@@ -154,7 +171,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -163,7 +180,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -172,7 +189,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -181,7 +198,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -190,7 +207,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -200,8 +217,8 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 8), Math.Round(QL.Signal.Last().v, 8));
|
||||
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]
|
||||
@@ -212,21 +229,18 @@ public class TA_LIB
|
||||
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], 7), Math.Round(QL.Upper.Last().v, 7));
|
||||
Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], 7), Math.Round(QL.Mid.Last().v, 7));
|
||||
Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 7), Math.Round(QL.Lower.Last().v, 7));
|
||||
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -235,7 +249,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -244,7 +258,7 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -253,7 +267,6 @@ public class TA_LIB
|
||||
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], 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-21
File diff suppressed because one or more lines are too long
+73
-74
@@ -37,84 +37,91 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
|
||||
|
||||
| **BASIC TRANSFORMS** | **QuanTAlib** | **TA-LIB** | **Skender** |
|
||||
|--|:--:|:--:|:--:|
|
||||
| ✔️ OC2 - (Open+Close)/2 |️ `.OC2` || ️`GetBaseQuote` |
|
||||
| ⭐ HL2 - Median Price | `.HL2` | `MEDPRICE` | ️`GetBaseQuote` |
|
||||
| ⭐ HLC3 - Typical Price | `.HLC3` | `TYPPRICE` ||
|
||||
| ✔️ OC2 - (Open+Close)/2 |️ `.OC2` || ️GetBaseQuote |
|
||||
| ⭐ HL2 - Median Price | `.HL2` | MEDPRICE | ️GetBaseQuote |
|
||||
| ⭐ HLC3 - Typical Price | `.HLC3` | TYPPRICE ||
|
||||
| ✔️ OHL3 - (Open+High+Low)/3 | `.OHL3` |||
|
||||
| ⭐ OHLC4 - Average Price | `.OHLC4` | `AVGPRICE` |️ `GetBaseQuote` |
|
||||
| ⭐ HLCC4 - Weighted Price | `.HLCC4` | `WCLPRICE` ||
|
||||
| ✔️ ZL - De-lagged price (Zero-Lag) | `ZL_Series` |||
|
||||
| ⭐ MAX - Max value | `MAX_Series` | `MAX` ||
|
||||
| ⛔ MID - Midpoint value || `MIDPOINT` ||
|
||||
| ⛔ MIDP - Midpoint price || `MIDPRICE` ||
|
||||
| ⭐ MIN - Min value | `MIN_Series` | `MIN` ||
|
||||
| ⭐ ADD - Addition | `ADD_Series` | `ADD` ||
|
||||
| ⭐ SUB - Subtraction | `SUB_Series` | `SUB` ||
|
||||
| ⭐ MUL - Multiplication | `MUL_Series` | `MUL` ||
|
||||
| ⭐ DIV - Division | `DIV_Series` | `DIV` ||
|
||||
| ⭐ OHLC4 - Average Price | `.OHLC4` | AVGPRICE |️ GetBaseQuote |
|
||||
| ⭐ HLCC4 - Weighted Price | `.HLCC4` | WCLPRICE ||
|
||||
| ⭐ MAX - Max value | `MAX_Series` | MAX ||
|
||||
| ⭐ MIN - Min value | `MIN_Series` | MIN ||
|
||||
| ⛔ MID - Midpoint value || MIDPOINT ||
|
||||
| ⛔ MIDP - Midpoint price || MIDPRICE ||
|
||||
| ⛔ SUM - Summation || SUM ||
|
||||
| ⭐ ADD - Addition | `ADD_Series` | ADD ||
|
||||
| ⭐ SUB - Subtraction | `SUB_Series` | SUB ||
|
||||
| ⭐ MUL - Multiplication | `MUL_Series` | MUL ||
|
||||
| ⭐ DIV - Division | `DIV_Series` | DIV ||
|
||||
|||||
|
||||
| **STATISTICS & NUMERICAL ANALYSIS** | **QuanTAlib** | **TA-LIB** | **Skender** |
|
||||
| ✔️ BIAS - Bias | BIAS_Series |||
|
||||
| ✔️ BIAS - Bias | `BIAS_Series` |||
|
||||
| ⛔ CORREL - Pearson's Correlation Coefficient || CORREL | GetCorrelation |
|
||||
| ⛔ COVAR - Covariance ||| GetCorrelation |
|
||||
| ✔️ ENTP - Entropy | ENTP_Series |||
|
||||
| ✔️ KURT - Kurtosis | KURT_Series |||
|
||||
| ⭐ LINREG - Linear Regression | LINREG_Series || GetSlope |
|
||||
| ⭐ MAD - Mean Absolute Deviation | MAD_Series || GetSma |
|
||||
| ⭐ MAPE - Mean Absolute Percent Error | MAPE_Series || GetSma |
|
||||
| ✔️ MED - Median value | MED_Series |||
|
||||
| ✔️ MSE - Mean Squared Error | MSE_Series || GetSma |
|
||||
| ✔️ ENTP - Entropy | `ENTP_Series` |||
|
||||
| ✔️ KURT - Kurtosis | `KURT_Series` |||
|
||||
| ⭐ LINREG - Linear Regression | `LINREG_Series` || GetSlope |
|
||||
| ⭐ MAD - Mean Absolute Deviation | `MAD_Series` || GetSma |
|
||||
| ⭐ MAPE - Mean Absolute Percent Error | `MAPE_Series` || GetSma |
|
||||
| ✔️ MED - Median value | `MED_Series` |||
|
||||
| ✔️ MSE - Mean Squared Error | `MSE_Series` || GetSma |
|
||||
| ⛔ SKEW - Skewness ||||
|
||||
| ⭐ SDEV - Standard Deviation (Volatility) | SDEV_Series |||
|
||||
| ✔️ SSDEV - Sample Standard Deviation | SSDEV_Series |||
|
||||
| ✔️ SMAPE - Symmetric Mean Absolute Percent Error | SMAPE_Series |||
|
||||
| ✔️ VAR - Population Variance | VAR_Series |||
|
||||
| ✔️ SVAR - Sample Variance | SVAR_Series |||
|
||||
| ⭐ SDEV - Standard Deviation (Volatility) | `SDEV_Series` | STDDEV ||
|
||||
| ✔️ SSDEV - Sample Standard Deviation | `SSDEV_Series` |||
|
||||
| ✔️ SMAPE - Symmetric Mean Absolute Percent Error | `SMAPE_Series` |||
|
||||
| ✔️ VAR - Population Variance | `VAR_Series` | VAR ||
|
||||
| ✔️ SVAR - Sample Variance | `SVAR_Series` |||
|
||||
| ⛔ QUANT - Quantile ||||
|
||||
| ✔️ WMAPE - Weighted Mean Absolute Percent Error | WMAPE_Series |||
|
||||
| ✔️ WMAPE - Weighted Mean Absolute Percent Error | `WMAPE_Series` |||
|
||||
| ⛔ ZSCORE - Number of standard deviations from mean ||||
|
||||
|||||
|
||||
| **TREND INDICATORS & AVERAGES** | **QuanTAlib** | **TA-LIB** | **Skender** |
|
||||
| ⛔ AFIRMA - Autoregressive Finite Impulse Response Moving Average ||||
|
||||
| ⭐ ALMA - Arnaud Legoux Moving Average | ALMA_Series || GetAlma |
|
||||
| ⭐ ALMA - Arnaud Legoux Moving Average | `ALMA_Series` || GetAlma |
|
||||
| ⛔ ARIMA - Autoregressive Integrated Moving Average ||||
|
||||
| ⭐ DEMA - Double EMA Average | DEMA_Series | DEMA | GetDema |
|
||||
| ⭐ EMA - Exponential Moving Average | EMA_Series || GetEma |
|
||||
| ⭐ DEMA - Double EMA Average | `DEMA_Series` | DEMA | GetDema |
|
||||
| ⭐ EMA - Exponential Moving Average | `EMA_Series` || GetEma |
|
||||
| ⛔ EPMA - Endpoint Moving Average ||| GetEpma |
|
||||
| ⛔ FRAMA - Fractal Adaptive Moving Average ||||
|
||||
| ⛔ FWMA - Fibonacci's Weighted Moving Average ||||
|
||||
| ✔️ HEMA - Hull/EMA Average | HEMA_Series |||
|
||||
| ⛔ HILO - Gann High-Low Activator ||||
|
||||
| ✔️ HEMA - Hull/EMA Average | `HEMA_Series` |||
|
||||
| ⛔ Hilbert Transform Instantaneous Trendline || HT_TRENDLINE | GetHtTrendline |
|
||||
| ⭐ HMA - Hull Moving Average | HMA_Series || GetHma |
|
||||
| ⭐ HMA - Hull Moving Average | `HMA_Series` || GetHma |
|
||||
| ⛔ HWMA - Holt-Winter Moving Average ||||
|
||||
| ✔️ JMA - Jurik Moving Average | JMA_Series |||
|
||||
| ⭐ KAMA - Kaufman's Adaptive Moving Average | KAMA_Series | KAMA | GetKama |
|
||||
| ✔️ JMA - Jurik Moving Average | `JMA_Series` |||
|
||||
| ⭐ KAMA - Kaufman's Adaptive Moving Average | `KAMA_Series` | KAMA | GetKama |
|
||||
| ⛔ KDJ - KDJ Indicator (trend reversal) ||||
|
||||
| ⛔ LSMA - Least Squares Moving Average ||||
|
||||
| ⭐ MACD - Moving Average Convergence/Divergence | MACD_Series | MACD | GetMacd |
|
||||
| ⭐ MACD - Moving Average Convergence/Divergence | `MACD_Series` | MACD | GetMacd |
|
||||
| ⛔ MAMA - MESA Adaptive Moving Average || MAMA | GetMama |
|
||||
| ⛔ MCGD - McGinley Dynamic ||||
|
||||
| ⛔ MMA - Modified Moving Average ||||
|
||||
| ⛔ PPMA - Pivot Point Moving Average ||||
|
||||
| ⛔ PWMA - Pascal's Weighted Moving Average ||||
|
||||
| ✔️ RMA - WildeR's Moving Average | RMA__Series |||
|
||||
| ✔️ RMA - WildeR's Moving Average | `RMA_Series` |||
|
||||
| ⛔ SINWMA - Sine Weighted Moving Average ||||
|
||||
| ⭐ SMA - Simple Moving Average | SMA_Series |||
|
||||
| ⭐ SMMA - Smoothed Moving Average | SMMA_Series |||
|
||||
| ⭐ SMA - Simple Moving Average | `SMA_Series` | SMA | GetSma |
|
||||
| ⭐ SMMA - Smoothed Moving Average | `SMMA_Series` |||
|
||||
| ⛔ SSF - Ehler's Super Smoother Filter ||||
|
||||
| ⛔ SUP - Supertrend ||||
|
||||
| ⛔ SWMA - Symmetric Weighted Moving Average ||||
|
||||
| ⛔ T3 - Tillson T3 Moving Average ||||
|
||||
| ⭐ TEMA - Triple EMA Average | TEMA_Series |||
|
||||
| ⛔ TRIMA - Triangular Moving Average ||||
|
||||
| ⛔ T3 - Tillson T3 Moving Average || T3 | GetT3 |
|
||||
| ⭐ TEMA - Triple EMA Average | `TEMA_Series` | TEMA | GetTema |
|
||||
| ⭐ TRIMA - Triangular Moving Average | `TRIMA_Series` | TRIMA ||
|
||||
| ⛔ TSF - Time Series Forecast || TSF ||
|
||||
| ⛔ VIDYA - Variable Index Dynamic Average ||||
|
||||
| ⭐ WMA - Weighted Moving Average | WMA_Series |||
|
||||
| ✔️ ZLEMA - Zero Lag EMA Average | ZLEMA_Series |||
|
||||
| ⛔ VOR - Vortex Indicator ||||
|
||||
| ⭐ WMA - Weighted Moving Average | `WMA_Series` | WMA | GetWma |
|
||||
| ✔️ ZLEMA - Zero Lag EMA Average | `ZLEMA_Series` |||
|
||||
|||||
|
||||
| **VOLATILITY INDICATORS** | **QuanTAlib** | **TA-LIB** | **Skender** |
|
||||
| ⭐ ADL - Chaikin Accumulation Distribution Line | ADL_Series | AD | GetAdl |
|
||||
| ⭐ ADOSC - Chaikin Accumulation Distribution Oscillator | ADOSC_Series | ADOSC| GetAdl |
|
||||
| ⭐ ATR - Average True Range | ATR_Series | ATR | GetAtr |
|
||||
| ⭐ ATRP - Average True Range Percent | ATRP_Series || GetAtr |
|
||||
| ✔️ BETA - Beta coefficient || BETA | GetBeta |
|
||||
| ⭐ BBANDS - Bollinger Bands® | BBANDS_Series | BBANDS | GetBollingerBands |
|
||||
| ⭐ ADL - Chaikin Accumulation Distribution Line | `ADL_Series` | AD | GetAdl |
|
||||
| ⭐ ADOSC - Chaikin Accumulation Distribution Oscillator | `ADOSC_Series` | ADOSC| GetAdl |
|
||||
| ⭐ ATR - Average True Range | `ATR_Series` | ATR | GetAtr |
|
||||
| ⭐ ATRP - Average True Range Percent | `ATRP_Series` || GetAtr |
|
||||
| ⛔ BETA - Beta coefficient || BETA | GetBeta |
|
||||
| ⭐ BBANDS - Bollinger Bands® | `BBANDS_Series` | BBANDS | GetBollingerBands |
|
||||
| ⛔ CHAND - Chandelier Exit ||| GetChandelier |
|
||||
| ⛔ CRSI - Connor RSI ||| GetConnorsRsi |
|
||||
| ⛔ DON - Donchian Channels ||| GetDonchian |
|
||||
| ⛔ FCB - Fractal Chaos Bands ||| GetFcb |
|
||||
@@ -122,11 +129,12 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
|
||||
| ⛔ ICH - Ichimoku ||| GetIchimoku |
|
||||
| ⛔ KEL - Keltner Channels ||| GetKeltner |
|
||||
| ⛔ NATR - Normalized Average True Range || NATR | GetAtr |
|
||||
| ⭐ RSI - Relative Strength Index | RSI_Series ||
|
||||
| ⛔ CHN - Price Channel Indicator ||||
|
||||
| ⭐ RSI - Relative Strength Index | `RSI_Series` | RSI | GetRsi |
|
||||
| ⛔ SAR - Parabolic Stop and Reverse || SAR | GetParabolicSar |
|
||||
| ⛔ SRSI - Stochastic RSI ||||
|
||||
| ⛔ SRSI - Stochastic RSI || STOCHRSI | GetStochRsi |
|
||||
| ⛔ STARC - Starc Bands ||||
|
||||
| ⭐ TR - True Range | TR_Series |||
|
||||
| ⭐ TR - True Range | `TR_Series` | TRANGE | GetTr |
|
||||
| ⛔ UI - Ulcer Index ||||
|
||||
| ⛔ VSTOP - Volatility Stop ||||
|
||||
|||||
|
||||
@@ -138,11 +146,11 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
|
||||
| ⛔ APO - Absolute Price Oscillator || APO ||
|
||||
| ⛔ AROON - Aroon oscillator || AROON | GetAroon |
|
||||
| ⛔ BOP - Balance of Power || BOP | GetBop |
|
||||
| ⭐ CCI - Commodity Channel Index | CCI_Series | CCI | GetCci |
|
||||
| ⭐ CCI - Commodity Channel Index | `CCI_Series` | CCI | GetCci |
|
||||
| ⛔ CFO - Chande Forcast Oscillator ||||
|
||||
| ⛔ CMF - Chaikin Money Flow ||||
|
||||
| ⛔ CMO - Chande Momentum Oscillator || CMO | GetCmo |
|
||||
| ⛔ COG - Center of Gravity ||||
|
||||
| ⛔ COPPOCK - Coppock Curve ||||
|
||||
| ⛔ CTI - Ehler's Correlation Trend Indicator ||||
|
||||
| ⛔ DPO - Detrended Price Oscillator ||| GetDpo |
|
||||
| ⛔ DMI - Directional Movement Index || DX | GetAdx |
|
||||
@@ -152,23 +160,28 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
|
||||
| ⛔ KRI - Kairi Relative Index ||||
|
||||
| ⛔ KVO - Klinger Volume Oscillator ||||
|
||||
| ⛔ MFI - Money Flow Index || MFI | GetMfi |
|
||||
| ⛔ ROC - Rate of Change (Momentum) || MOM | GetRoc |
|
||||
| ⛔ MOM - Momentum || MOM ||
|
||||
| ⛔ NVI - Negative Volume Index ||||
|
||||
| ⛔ PO - Price Oscillator ||||
|
||||
| ⛔ PPO - Percentage Price Oscillator || PPO ||
|
||||
| ⛔ PMO - Price Momentum Oscillator ||||
|
||||
| ⛔ PVI - Positive Volume Index ||||
|
||||
| ⛔ ROC - Rate of Change || MOM | GetRoc |
|
||||
| ⛔ RVGI - Relative Vigor Index ||||
|
||||
| ⛔ SMI - Stochastic Momentum Index ||||
|
||||
| ⛔ STOCH - Stochastic Oscillator ||||
|
||||
| ⛔ TRIX - 1-day ROC of TEMA ||||
|
||||
| ⛔ STC - Schaff Trend Cycle ||||
|
||||
| ⛔ STOCH - Stochastic Oscillator || STOCH | GetStoch |
|
||||
| ⛔ TRIX - 1-day ROC of TEMA || TRIX | GetTrix |
|
||||
| ⛔ TSI - True Strength Index ||||
|
||||
| ⛔ UO - Ultimate Oscillator ||||
|
||||
| ⛔ UO - Ultimate Oscillator || ULTOSC | GetUltimate |
|
||||
| ⛔ WILLR - Larry Williams' %R || WILLR | GetWilliamsR |
|
||||
| ⛔ WGAT - Williams Alligator ||||
|
||||
|||||
|
||||
| **VOLUME INDICATORS** | **QuanTAlib** | **TA-LIB** | **Skender** |
|
||||
| ⛔ AOBV - Archer On-Balance Volume ||||
|
||||
| ⛔ OBV - On-Balance Volume || OBV | GetObv |
|
||||
| ⛔ CMF - Chaikin Money Flow ||||
|
||||
| ⛔ EOM - Ease of Movement ||||
|
||||
| ⭐ OBV - On-Balance Volume | `OBV_Series` | OBV | GetObv |
|
||||
| ⛔ PRS - Price Relative Strength |||
|
||||
| ⛔ PVOL - Price-Volume ||||
|
||||
| ⛔ PVO - Percentage Volume Oscillator ||||
|
||||
@@ -177,17 +190,3 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
|
||||
| ⛔ VP - Volume Profile ||||
|
||||
| ⛔ VWAP - Volume Weighted Average Price ||||
|
||||
| ⛔ VWMA - Volume Weighted Moving Average ||||
|
||||
|||||
|
||||
|**Unsorted** | **QuanTAlib** | **TA-LIB** | **Skender** |
|
||||
| ⛔ CHN - Price Channel ||||
|
||||
| ⛔ COPPOCK - Coppock Curve ||||
|
||||
| ⛔ EOM - Ease of Movement ||||
|
||||
| ⛔ HILO - Gann High-Low Activator ||||
|
||||
| ⛔ HT - HT Trendline ||||
|
||||
| ⛔ MCGD - McGinley Dynamic ||||
|
||||
| ⛔ STC - Schaff Trend Cycle ||||
|
||||
| ⛔ WILLR - Larry Williams' %R ||||
|
||||
| ⛔ VOR - Vortex Indicator ||||
|
||||
| ⛔ PVT - Pivot Points ||||
|
||||
| ⛔ KDJ - KDJ Index ||||
|
||||
| ⛔ CHAND - Chandelier Exit ||||
|
||||
|
||||
Reference in New Issue
Block a user