mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-16 17:48:05 +00:00
for dev branch
This commit is contained in:
@@ -13,6 +13,8 @@ Alphavantage - Free API to collect quotes for stock, Forex and crypto. It requir
|
||||
|
||||
</summary> */
|
||||
|
||||
/* TODO: refactor into three feeds: FX, Crypto, Stock */
|
||||
|
||||
public class Alphavantage_Feed : TBars
|
||||
{
|
||||
public enum Interval { Month, Week, Day, Hour, Min30, Min15, Min5, Min1}
|
||||
@@ -113,7 +115,7 @@ public class Alphavantage_Feed : TBars
|
||||
{
|
||||
Interval.Month => "_MONTHLY",
|
||||
Interval.Week => "_WEEKLY",
|
||||
Interval.Day => "_DAILY",
|
||||
Interval.Day => "_DAILY_ADJUSTED",
|
||||
Interval.Hour => "_INTRADAY&interval=60min",
|
||||
Interval.Min30 => "_INTRADAY&interval=30min",
|
||||
Interval.Min15 => "_INTRADAY&interval=15min",
|
||||
|
||||
+164
-159
@@ -1,159 +1,164 @@
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
|
||||
/* <summary>
|
||||
JMA: Jurik Moving Average
|
||||
Mark Jurik's Moving Average (JMA) attempts to eliminate noise to see the
|
||||
underlying activity. It has extremely low lag, is very smooth and is responsive
|
||||
to market gaps.
|
||||
|
||||
Sources:
|
||||
https://c.mql5.com/forextsd/forum/164/jurik_1.pdf
|
||||
https://www.prorealcode.com/prorealtime-indicators/jurik-volatility-bands/
|
||||
|
||||
Issues:
|
||||
Real JMA algorithm is not published and this formula is derived through
|
||||
deduction and reverse analysis of JMA behavior. It is really close, but not
|
||||
exact - published JMA tests against JMA.CSV fail with small deviation. The
|
||||
original algo is slightly different, yet this approximation is close enough.
|
||||
|
||||
</summary> */
|
||||
|
||||
public class JMA_Series : Single_TSeries_Indicator
|
||||
{
|
||||
private readonly System.Collections.Generic.List<double> vbuffer10;
|
||||
private readonly System.Collections.Generic.List<double> vsum65;
|
||||
|
||||
private double prev_ma1, prev_det0, prev_det1, prev_jma, bsmax, bsmin;
|
||||
private double o_prev_ma1, o_prev_det0, o_prev_det1, o_prev_jma, o_bsmax, o_bsmin;
|
||||
|
||||
private readonly double pr, pow1, len2, beta, rvolty;
|
||||
|
||||
public JMA_Series(TSeries source, int period, double phase = 0.0, bool useNaN = false) : base(source, period, useNaN)
|
||||
{
|
||||
this.vbuffer10 = new();
|
||||
this.vsum65 = new();
|
||||
|
||||
// constants
|
||||
this.pr = (phase < -100) ? 0.5 : (phase > 100) ? 2.5 : (phase * 0.01) + 1.5;
|
||||
double len1 = Math.Max((Math.Log(Math.Sqrt(0.5 * (_p - 1))) / Math.Log(2.0)) + 2.0, 0);
|
||||
this.pow1 = Math.Max(len1 - 2, 0.5);
|
||||
this.rvolty = Math.Exp((1 / this.pow1) * Math.Log(len1));
|
||||
this.len2 = Math.Sqrt(0.5 * (_p - 1)) * len1;
|
||||
this.beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2);
|
||||
if (base._data.Count > 0) { base.Add(base._data); }
|
||||
}
|
||||
|
||||
public override void Add((System.DateTime t, double v) TValue, bool update)
|
||||
{
|
||||
if (this.Count == 0)
|
||||
{
|
||||
this.prev_ma1 = this.prev_jma = TValue.v;
|
||||
this.bsmax = this.bsmin = this.prev_det0 = this.prev_det1 = 0;
|
||||
}
|
||||
|
||||
if (update)
|
||||
{
|
||||
this.prev_jma = this.o_prev_jma;
|
||||
this.prev_ma1 = this.o_prev_ma1;
|
||||
this.prev_det0 = this.o_prev_det0;
|
||||
this.prev_det1 = this.o_prev_det1;
|
||||
this.bsmax = this.o_bsmax;
|
||||
this.bsmin = this.o_bsmin;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.o_prev_jma = this.prev_jma;
|
||||
this.o_prev_ma1 = this.prev_ma1;
|
||||
this.o_prev_det0 = this.prev_det0;
|
||||
this.o_prev_det1 = this.prev_det1;
|
||||
this.o_bsmax = this.bsmax;
|
||||
this.o_bsmin = this.bsmin;
|
||||
}
|
||||
|
||||
double hprice = TValue.v;
|
||||
double lprice = TValue.v;
|
||||
for (int i = 0; i <= Math.Min(9, this._data.Count - 1); i++)
|
||||
{
|
||||
var _item = this._data[this._data.Count - 1 - i].v;
|
||||
hprice = (_item > hprice) ? _item : hprice;
|
||||
lprice = (_item < lprice) ? _item : lprice;
|
||||
}
|
||||
double del1 = hprice - this.bsmax;
|
||||
double del2 = lprice - this.bsmin;
|
||||
|
||||
double volty = (Math.Abs(del1) != Math.Abs(del2))
|
||||
? Math.Max(Math.Abs(del1), Math.Abs(del2))
|
||||
: 0;
|
||||
if (update)
|
||||
{
|
||||
this.vbuffer10[this.vbuffer10.Count - 1] = volty;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.vbuffer10.Add(volty);
|
||||
}
|
||||
if (this.vbuffer10.Count > 10)
|
||||
{
|
||||
this.vbuffer10.RemoveAt(0);
|
||||
}
|
||||
|
||||
double prevvsum =
|
||||
(this.vsum65.Count > 0) ? this.vsum65[this.vsum65.Count - 1] : 0;
|
||||
double vsumitem = prevvsum + 0.1 * (volty - this.vbuffer10[0]);
|
||||
if (update)
|
||||
{
|
||||
this.vsum65[this.vsum65.Count - 1] = vsumitem;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.vsum65.Add(vsumitem);
|
||||
}
|
||||
if (this.vsum65.Count > 65)
|
||||
{
|
||||
this.vsum65.RemoveAt(0);
|
||||
}
|
||||
|
||||
double avolty = 0;
|
||||
for (int i = 0; i < this.vsum65.Count; i++)
|
||||
{
|
||||
avolty += this.vsum65[i];
|
||||
}
|
||||
|
||||
avolty /= this.vsum65.Count;
|
||||
double dvolty = (avolty > 0) ? volty / avolty : 0;
|
||||
dvolty = Math.Max((dvolty > this.rvolty) ? this.rvolty : dvolty, 1.0);
|
||||
|
||||
double pow2 = Math.Exp(this.pow1 * Math.Log(dvolty));
|
||||
double kv =
|
||||
Math.Exp(Math.Sqrt(pow2) * Math.Log(this.len2 / (this.len2 + 1)));
|
||||
|
||||
this.bsmax = (del1 > 0) ? hprice : hprice - (kv * del1);
|
||||
this.bsmin = (del2 < 0) ? lprice : lprice - (kv * del2);
|
||||
|
||||
// adaptive EMA dynamic factor
|
||||
double pow = Math.Pow(dvolty, this.pow1);
|
||||
double alpha = Math.Pow(this.beta, pow);
|
||||
|
||||
// 1st stage - preliminary smoothing by adaptive EMA
|
||||
double ma1 = TValue.v * (1 - alpha) + this.prev_ma1 * alpha;
|
||||
this.prev_ma1 = ma1;
|
||||
|
||||
// 2nd stage - one more preliminary smoothing by Kalman filter
|
||||
double det0 = (TValue.v - ma1) * (1 - this.beta) + this.prev_det0 * this.beta;
|
||||
this.prev_det0 = det0;
|
||||
double ma2 = ma1 + (this.pr * det0);
|
||||
|
||||
// 3rd stage - final smoothing by Jurik adaptive filter
|
||||
double det1 = ((ma2 - this.prev_jma) * (1 - alpha) * (1 - alpha)) +
|
||||
(this.prev_det1 * alpha * alpha);
|
||||
this.prev_det1 = det1;
|
||||
var jma = this.prev_jma + det1;
|
||||
this.prev_jma = jma;
|
||||
|
||||
(System.DateTime t, double v) result =
|
||||
(TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : jma);
|
||||
base.Add(result, update);
|
||||
|
||||
}
|
||||
}
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
|
||||
/* <summary>
|
||||
JMA: Jurik Moving Average
|
||||
Mark Jurik's Moving Average (JMA) attempts to eliminate noise to see the
|
||||
underlying activity. It has extremely low lag, is very smooth and is responsive
|
||||
to market gaps.
|
||||
|
||||
Sources:
|
||||
https://c.mql5.com/forextsd/forum/164/jurik_1.pdf
|
||||
https://www.prorealcode.com/prorealtime-indicators/jurik-volatility-bands/
|
||||
|
||||
Issues:
|
||||
Real JMA algorithm is not published and this formula is derived through
|
||||
deduction and reverse analysis of JMA behavior. It is really close, but not
|
||||
exact - published JMA tests against JMA.CSV fail with small deviation. The
|
||||
original algo is slightly different, yet this approximation is close enough.
|
||||
|
||||
</summary> */
|
||||
|
||||
/* TODO: This indicator is not calculating results correctly - needs to be debugged */
|
||||
|
||||
/*
|
||||
public class JMA_Series : Single_TSeries_Indicator
|
||||
{
|
||||
private readonly System.Collections.Generic.List<double> vbuffer10;
|
||||
private readonly System.Collections.Generic.List<double> vsum65;
|
||||
|
||||
private double prev_ma1, prev_det0, prev_det1, prev_jma, bsmax, bsmin;
|
||||
private double o_prev_ma1, o_prev_det0, o_prev_det1, o_prev_jma, o_bsmax, o_bsmin;
|
||||
|
||||
private readonly double pr, pow1, len2, beta, rvolty;
|
||||
|
||||
public JMA_Series(TSeries source, int period, double phase = 0.0, bool useNaN = false) : base(source, period, useNaN)
|
||||
{
|
||||
this.vbuffer10 = new();
|
||||
this.vsum65 = new();
|
||||
|
||||
// constants
|
||||
this.pr = (phase < -100) ? 0.5 : (phase > 100) ? 2.5 : (phase * 0.01) + 1.5;
|
||||
double len1 = Math.Max((Math.Log(Math.Sqrt(0.5 * (_p - 1))) / Math.Log(2.0)) + 2.0, 0);
|
||||
this.pow1 = Math.Max(len1 - 2, 0.5);
|
||||
this.rvolty = Math.Exp((1 / this.pow1) * Math.Log(len1));
|
||||
this.len2 = Math.Sqrt(0.5 * (_p - 1)) * len1;
|
||||
this.beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2);
|
||||
if (base._data.Count > 0) { base.Add(base._data); }
|
||||
}
|
||||
|
||||
public override void Add((System.DateTime t, double v) TValue, bool update)
|
||||
{
|
||||
if (this.Count == 0)
|
||||
{
|
||||
this.prev_ma1 = this.prev_jma = TValue.v;
|
||||
this.bsmax = this.bsmin = this.prev_det0 = this.prev_det1 = 0;
|
||||
}
|
||||
|
||||
if (update)
|
||||
{
|
||||
this.prev_jma = this.o_prev_jma;
|
||||
this.prev_ma1 = this.o_prev_ma1;
|
||||
this.prev_det0 = this.o_prev_det0;
|
||||
this.prev_det1 = this.o_prev_det1;
|
||||
this.bsmax = this.o_bsmax;
|
||||
this.bsmin = this.o_bsmin;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.o_prev_jma = this.prev_jma;
|
||||
this.o_prev_ma1 = this.prev_ma1;
|
||||
this.o_prev_det0 = this.prev_det0;
|
||||
this.o_prev_det1 = this.prev_det1;
|
||||
this.o_bsmax = this.bsmax;
|
||||
this.o_bsmin = this.bsmin;
|
||||
}
|
||||
|
||||
double hprice = TValue.v;
|
||||
double lprice = TValue.v;
|
||||
for (int i = 0; i <= Math.Min(9, this._data.Count - 1); i++)
|
||||
{
|
||||
var _item = this._data[this._data.Count - 1 - i].v;
|
||||
hprice = (_item > hprice) ? _item : hprice;
|
||||
lprice = (_item < lprice) ? _item : lprice;
|
||||
}
|
||||
double del1 = hprice - this.bsmax;
|
||||
double del2 = lprice - this.bsmin;
|
||||
|
||||
double volty = (Math.Abs(del1) != Math.Abs(del2))
|
||||
? Math.Max(Math.Abs(del1), Math.Abs(del2))
|
||||
: 0;
|
||||
if (update)
|
||||
{
|
||||
this.vbuffer10[this.vbuffer10.Count - 1] = volty;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.vbuffer10.Add(volty);
|
||||
}
|
||||
if (this.vbuffer10.Count > 10)
|
||||
{
|
||||
this.vbuffer10.RemoveAt(0);
|
||||
}
|
||||
|
||||
double prevvsum =
|
||||
(this.vsum65.Count > 0) ? this.vsum65[this.vsum65.Count - 1] : 0;
|
||||
double vsumitem = prevvsum + 0.1 * (volty - this.vbuffer10[0]);
|
||||
if (update)
|
||||
{
|
||||
this.vsum65[this.vsum65.Count - 1] = vsumitem;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.vsum65.Add(vsumitem);
|
||||
}
|
||||
if (this.vsum65.Count > 65)
|
||||
{
|
||||
this.vsum65.RemoveAt(0);
|
||||
}
|
||||
|
||||
double avolty = 0;
|
||||
for (int i = 0; i < this.vsum65.Count; i++)
|
||||
{
|
||||
avolty += this.vsum65[i];
|
||||
}
|
||||
|
||||
avolty /= this.vsum65.Count;
|
||||
double dvolty = (avolty > 0) ? volty / avolty : 0;
|
||||
dvolty = Math.Max((dvolty > this.rvolty) ? this.rvolty : dvolty, 1.0);
|
||||
|
||||
double pow2 = Math.Exp(this.pow1 * Math.Log(dvolty));
|
||||
double kv =
|
||||
Math.Exp(Math.Sqrt(pow2) * Math.Log(this.len2 / (this.len2 + 1)));
|
||||
|
||||
this.bsmax = (del1 > 0) ? hprice : hprice - (kv * del1);
|
||||
this.bsmin = (del2 < 0) ? lprice : lprice - (kv * del2);
|
||||
|
||||
// adaptive EMA dynamic factor
|
||||
double pow = Math.Pow(dvolty, this.pow1);
|
||||
double alpha = Math.Pow(this.beta, pow);
|
||||
|
||||
// 1st stage - preliminary smoothing by adaptive EMA
|
||||
double ma1 = TValue.v * (1 - alpha) + this.prev_ma1 * alpha;
|
||||
this.prev_ma1 = ma1;
|
||||
|
||||
// 2nd stage - one more preliminary smoothing by Kalman filter
|
||||
double det0 = (TValue.v - ma1) * (1 - this.beta) + this.prev_det0 * this.beta;
|
||||
this.prev_det0 = det0;
|
||||
double ma2 = ma1 + (this.pr * det0);
|
||||
|
||||
// 3rd stage - final smoothing by Jurik adaptive filter
|
||||
double det1 = ((ma2 - this.prev_jma) * (1 - alpha) * (1 - alpha)) +
|
||||
(this.prev_det1 * alpha * alpha);
|
||||
this.prev_det1 = det1;
|
||||
var jma = this.prev_jma + det1;
|
||||
this.prev_jma = jma;
|
||||
|
||||
(System.DateTime t, double v) result =
|
||||
(TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : jma);
|
||||
base.Add(result, update);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -13,7 +13,7 @@
|
||||
<Authors>Miha Kralj</Authors>
|
||||
<Copyright>Miha Kralj</Copyright>
|
||||
<PackageReadmeFile>readme.md</PackageReadmeFile>
|
||||
<TargetFrameworks>net7.0;net6.0;netstandard2.0</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<Nullable>disable</Nullable>
|
||||
@@ -67,6 +67,6 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Json" Version="7.0.0-preview.4.22229.4" />
|
||||
<PackageReference Include="System.Text.Json" Version="7.0.0-rc.2.22472.3" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,44 +0,0 @@
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
|
||||
/* <summary>
|
||||
PSDEV: Population Standard Deviation
|
||||
Population Standard Deviation is the square root of the biased variance, also knons as
|
||||
Uncorrected Sample Standard Deviation
|
||||
|
||||
Sources:
|
||||
https://en.wikipedia.org/wiki/Standard_deviation#Uncorrected_sample_standard_deviation
|
||||
|
||||
Remark:
|
||||
PSDEV (Population Standard Deviation) is also known as a biased/uncorrected Standard Deviation.
|
||||
For unbiased version that uses Bessel's correction, use SDEV instead.
|
||||
|
||||
</summary> */
|
||||
|
||||
public class PSDEV_Series : Single_TSeries_Indicator
|
||||
{
|
||||
public PSDEV_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
|
||||
{
|
||||
if (base._data.Count > 0) { base.Add(base._data); }
|
||||
}
|
||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||
|
||||
public override void Add((System.DateTime t, double v) TValue, bool update)
|
||||
{
|
||||
if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
|
||||
else { _buffer.Add(TValue.v); }
|
||||
if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
|
||||
|
||||
double _sma = 0;
|
||||
for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
|
||||
_sma /= this._buffer.Count;
|
||||
|
||||
double _pvar = 0;
|
||||
for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
|
||||
_pvar /= this._buffer.Count;
|
||||
double _psdev = Math.Sqrt(_pvar);
|
||||
|
||||
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _psdev);
|
||||
base.Add(result, update);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
|
||||
/* <summary>
|
||||
SDEV: (Corrected) Sample Standard Deviation
|
||||
Sample Standard Deviaton uses Bessel's correction to correct the bias in the variance.
|
||||
|
||||
Sources:
|
||||
https://en.wikipedia.org/wiki/Standard_deviation#Corrected_sample_standard_deviation
|
||||
Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction
|
||||
|
||||
Remark:
|
||||
SSDEV (Sample Standard Deviation) is also known as a unbiased/corrected Standard Deviation.
|
||||
For a population/biased/uncorrected Standard Deviation, use PSDEV instead
|
||||
|
||||
</summary> */
|
||||
|
||||
public class SDEV_Series : Single_TSeries_Indicator
|
||||
{
|
||||
public SDEV_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
|
||||
{
|
||||
if (base._data.Count > 0) { base.Add(base._data); }
|
||||
}
|
||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||
|
||||
public override void Add((System.DateTime t, double v) TValue, bool update)
|
||||
{
|
||||
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
|
||||
else { this._buffer.Add(TValue.v); }
|
||||
if (this._buffer.Count > this._p && this._p != 0) { this._buffer.RemoveAt(0); }
|
||||
|
||||
double _sma = 0;
|
||||
for (int i = 0; i < this._buffer.Count; i++) { _sma += this._buffer[i]; }
|
||||
_sma /= this._buffer.Count;
|
||||
|
||||
double _svar = 0;
|
||||
for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); }
|
||||
_svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction
|
||||
double _ssdev = Math.Sqrt(_svar);
|
||||
|
||||
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _ssdev);
|
||||
base.Add(result, update);
|
||||
}
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
|
||||
/* <summary>
|
||||
SDEV: Population Standard Deviation
|
||||
Population Standard Deviation is the square root of the biased variance, also known as
|
||||
Uncorrected Sample Standard Deviation
|
||||
|
||||
Sources:
|
||||
https://en.wikipedia.org/wiki/Standard_deviation#Uncorrected_sample_standard_deviation
|
||||
|
||||
Remark:
|
||||
SDEV (Population Standard Deviation) is also known as a biased/uncorrected Standard Deviation.
|
||||
For unbiased version that uses Bessel's correction, use SDEV instead.
|
||||
|
||||
</summary> */
|
||||
|
||||
public class SDEV_Series : Single_TSeries_Indicator
|
||||
{
|
||||
public SDEV_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
|
||||
{
|
||||
if (base._data.Count > 0) { base.Add(base._data); }
|
||||
}
|
||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||
|
||||
public override void Add((System.DateTime t, double v) TValue, bool update)
|
||||
{
|
||||
if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
|
||||
else { _buffer.Add(TValue.v); }
|
||||
if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
|
||||
|
||||
double _sma = 0;
|
||||
for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
|
||||
_sma /= this._buffer.Count;
|
||||
|
||||
double _pvar = 0;
|
||||
for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
|
||||
_pvar /= this._buffer.Count;
|
||||
double _psdev = Math.Sqrt(_pvar);
|
||||
|
||||
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _psdev);
|
||||
base.Add(result, update);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user