mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-24 13:38:05 +00:00
Refactoring the structure, upgrading to .NET 6.0/7.0/8.0
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user