Refactoring the structure, upgrading to .NET 6.0/7.0/8.0

This commit is contained in:
Miha Kralj
2023-04-01 17:05:05 -07:00
parent 468ea7a0af
commit 05f423c965
108 changed files with 3370 additions and 3080 deletions
+40
View File
@@ -0,0 +1,40 @@
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)
{
_lastadl = _lastlastadl = 0;
if (_bars.Count > 0) { base.Add(_bars); }
}
public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
{
if (update) { this._lastadl = this._lastlastadl; }
double _adl = 0;
double tmp = TBar.h - TBar.l;
if (tmp > 0.0 ) { _adl = _lastadl + ((2*TBar.c - TBar.l - TBar.h) / tmp * TBar.v); }
this._lastlastadl = this._lastadl;
this._lastadl = _adl;
base.Add((TBar.t, _adl), update, _NaN);
}
}
+87
View File
@@ -0,0 +1,87 @@
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 double _k1, _k2;
private double _lastema1, _lastlastema1, _lastema2, _lastlastema2;
private double _lastadl, _lastlastadl;
public ADOSC_Series(TBars source, int shortPeriod = 3, int longPeriod =10, bool useNaN = false) : base(source, period: 0, useNaN)
{
_k1 = 2.0 / (shortPeriod + 1);
_k2 = 2.0 / (longPeriod + 1);
_lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
if (_bars.Count > 0) { base.Add(_bars); }
}
public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
{
if (update) {
_lastadl = _lastlastadl;
_lastema1 = _lastlastema1;
_lastema2 = _lastlastema2;
}
double _adl = 0;
double tmp = TBar.h - TBar.l;
if (tmp > 0.0) { _adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v); }
if (this.Count == 0) { _lastema1 = _lastema2 = _adl; }
double _ema1 = (_adl - _lastema1) * _k1 + _lastema1;
double _ema2 = (_adl - _lastema2) * _k2 + _lastema2;
_lastlastadl = _lastadl; _lastadl = _adl;
_lastlastema1 = _lastema1; _lastema1 = _ema1;
_lastlastema2 = _lastema2; _lastema2 = _ema2;
double _adosc = _ema1 - _ema2;
base.Add((TBar.t, _adosc), update, _NaN);
}
}
/*
public class ADOSC_Series : Single_TBars_Indicator
{
private readonly ADL_Series _TSadl;
private readonly EMA_Series _TSslow;
private readonly EMA_Series _TSfast;
private readonly SUB_Series _TSado;
public ADOSC_Series(TBars source, bool useNaN = false) : base(source, period: 0, useNaN)
{
_TSadl = new(source: source, useNaN: false);
_TSslow = new(source: _TSadl, period: 10, useNaN: false);
_TSfast = new(source: _TSadl, period: 3, useNaN: false);
_TSado = new(_TSfast, _TSslow);
if (source.Count > 0)
{ base.Add(_TSado); }
Console.WriteLine(base.Count);
}
public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
{
if (update)
{ _TSadl.Add(TBar, true); }
double _ado = this._TSado[(this.Count < this._TSado.Count) ? this.Count : this._TSado.Count - 1].v;
var result = (TBar.t, _ado);
base.Add(result, update);
}
}
*/
+48
View File
@@ -0,0 +1,48 @@
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;
private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
private readonly int _period;
public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) {
_period = period;
_k = 1.0 / (double)(_p);
_lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0;
if (this._bars.Count > 0) { base.Add(this._bars); }
}
public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) {
if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; }
if (this.Count == 0) { _cm1 = TBar.c; }
double d1 = Math.Abs(TBar.h - TBar.l);
double d2 = Math.Abs(_cm1 - TBar.h);
double d3 = Math.Abs(_cm1 - TBar.l);
(DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
_cm1 = TBar.c;
double _atr = 0;
if (this.Count == 0) { _atr = d.v; }
else if (this.Count < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); }
else { _atr = _k * (d.v - _lastatr) + _lastatr; }
_lastatr = _atr;
double _atrp = 100 * (_atr / TBar.c);
var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atrp);
base.Add(ret, update);
}
}
+49
View File
@@ -0,0 +1,49 @@
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;
private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
private readonly int _period;
public ATR_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) {
_period = period;
_k = 1.0 / (double)(_p);
_lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0;
if (this._bars.Count > 0) { base.Add(this._bars); }
}
public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) {
if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; }
if (this.Count == 0) { _cm1 = TBar.c; }
double d1 = Math.Abs(TBar.h - TBar.l);
double d2 = Math.Abs(_cm1 - TBar.h);
double d3 = Math.Abs(_cm1 - TBar.l);
(DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
_cm1 = TBar.c;
double _atr = 0;
if (this.Count == 0) { _atr = d.v; }
else if (this.Count < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); }
else { _atr = _k * (d.v - _lastatr) + _lastatr; }
_lastatr = _atr;
var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atr);
base.Add(ret, update);
}
}
+73
View File
@@ -0,0 +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);
}
}
+47
View File
@@ -0,0 +1,47 @@
namespace QuanTAlib;
using System;
/* <summary>
CMO: Chande Momentum Oscillator
Chande Momentum Oscillator (also known as CMO indicator) was developed by Tushar S. Chande
CMO is similar to other momentum oscillators (e.g. RSI or Stochastics). Alike RSI oscillator,
the CMO values move in the range from -100 to +100 points and its aim is to detect the
overbought and oversold market conditions. CMO calculates the price momentum on both the up
days as well as the down days. The CMO calculation is based on non-smoothed price values
meaning that it can reach its extremes more frequently and the short-time swings are more visible.
Sources:
https://www.technicalindicators.net/indicators-technical-analysis/144-cmo-chande-momentum-oscillator
</summary> */
public class CMO_Series : Single_TSeries_Indicator {
private readonly System.Collections.Generic.List<double> _buff_up = new();
private readonly System.Collections.Generic.List<double> _buff_dn = new();
private double _plast_value, _last_value;
public CMO_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) {
if (this._data.Count > 0) { base.Add(this._data); }
}
public override void Add((DateTime t, double v) TValue, bool update) {
if (this.Count == 0) { _plast_value = _last_value = TValue.v; }
if (update) _last_value = _plast_value; else _plast_value = _last_value;
Add_Replace_Trim(_buff_up, (TValue.v > _last_value) ? TValue.v-_last_value : 0, _p, update);
Add_Replace_Trim(_buff_dn, (TValue.v < _last_value) ? _last_value-TValue.v : 0, _p, update);
_last_value = TValue.v;
double _cmo_up = 0;
double _cmo_dn = 0;
for (int i = 0; i < Math.Min(_buff_up.Count, _buff_dn.Count); i++) {
_cmo_up += _buff_up[i];
_cmo_dn += _buff_dn[i];
}
double _cmo = 100 * (_cmo_up - _cmo_dn) / (_cmo_up + _cmo_dn);
if (_cmo_up + _cmo_dn == 0)
_cmo = 0;
base.Add((TValue.t, _cmo), update, _NaN);
}
}
+78
View File
@@ -0,0 +1,78 @@
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, _avgLoss, _lastValue;
private double _avgGain_o, _avgLoss_o, _lastValue_o;
private int i;
public RSI_Series(TSeries source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) {
i = 0;
if (source.Count > 0) { base.Add(source); }
}
public override void Add((System.DateTime t, double v) TValue, bool update) {
double _rsi = 0;
if (update) {
_lastValue = _lastValue_o;
_avgGain = _avgGain_o;
_avgLoss = _avgLoss_o;
}
else {
_lastValue_o = _lastValue;
_avgGain_o = _avgGain;
_avgLoss_o = _avgLoss;
}
if (i == 0) { _lastValue = TValue.v; }
double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0;
Add_Replace_Trim(_gain, _gainval, _p, update);
double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0;
Add_Replace_Trim(_loss, _lossval, _p, update);
_lastValue = TValue.v;
// calculate RSI
if (i > _p)
{
_avgGain = ((_avgGain * (_p - 1)) + _gain[_gain.Count - 1]) / _p;
_avgLoss = ((_avgLoss * (_p - 1)) + _loss[_loss.Count - 1]) / _p;
if (_avgLoss > 0) {
double rs = _avgGain / _avgLoss;
_rsi = 100 - (100 / (1 + rs));
}
else { _rsi = 100; }
}
// initialize average gain
else
{
double _sumGain = 0;
for (int p = 0; p < _gain.Count; p++) { _sumGain += _gain[p]; }
double _sumLoss = 0;
for (int p = 0; p < _loss.Count; p++) { _sumLoss += _loss[p]; }
_avgGain = _sumGain / _gain.Count;
_avgLoss = _sumLoss / _loss.Count;
_rsi = (_avgLoss > 0) ? 100 - (100 / (1 + (_avgGain / _avgLoss))) : 100;
}
if (!update) { i++; }
var result = (TValue.t, (this.Count < this._p && this._NaN) ? double.NaN : _rsi);
base.Add(result, update);
}
}