mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-21 12:08:05 +00:00
Atr, FlowIndicator and fixes
This commit is contained in:
@@ -90,6 +90,7 @@ public class Ema : AbstractBase
|
||||
_k = alpha;
|
||||
_useSma = false;
|
||||
_sma = new(1);
|
||||
Name = "Ema";
|
||||
_period = 1;
|
||||
WarmupPeriod = (int)Math.Ceiling(Math.Log(0.05) / Math.Log(1 - _k)); //95th percentile
|
||||
Init();
|
||||
|
||||
+12
-9
@@ -6,7 +6,7 @@ namespace QuanTAlib;
|
||||
|
||||
public class Jma : AbstractBase
|
||||
{
|
||||
private readonly int _period;
|
||||
private readonly double _period;
|
||||
private readonly double _phase;
|
||||
private readonly CircularBuffer _vsumBuff;
|
||||
private readonly CircularBuffer _avoltyBuff;
|
||||
@@ -22,6 +22,7 @@ public class Jma : AbstractBase
|
||||
public double UpperBand { get; set; }
|
||||
public double LowerBand { get; set; }
|
||||
public double Volty { get; set; }
|
||||
public double Factor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Jma class with the specified parameters.
|
||||
@@ -31,18 +32,19 @@ public class Jma : AbstractBase
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 1.
|
||||
/// </exception>
|
||||
public Jma(int period, int phase = 0)
|
||||
public Jma(int period, int phase = 0, double factor = 0.45)
|
||||
{
|
||||
if (period < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
||||
}
|
||||
Factor = factor;
|
||||
_period = period;
|
||||
_phase = Math.Clamp((phase * 0.01) + 1.5, 0.5, 2.5);
|
||||
|
||||
_vsumBuff = new CircularBuffer(10);
|
||||
_avoltyBuff = new CircularBuffer(65);
|
||||
_beta = 0.45 * (period - 1) / (0.45 * (period - 1) + 2);
|
||||
_beta = factor * (_period - 1) / (factor * (_period - 1) + 2);
|
||||
|
||||
WarmupPeriod = period * 2;
|
||||
Name = $"JMA({period})";
|
||||
@@ -114,9 +116,10 @@ public class Jma : AbstractBase
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
double price = Input.Value;
|
||||
if (_index == 1)
|
||||
if (_index <= 1)
|
||||
{
|
||||
_upperBand = _lowerBand = price;
|
||||
_prevMa1 = _prevJma = price;
|
||||
}
|
||||
|
||||
double del1 = price - _upperBand;
|
||||
@@ -124,7 +127,7 @@ public class Jma : AbstractBase
|
||||
double volty = Math.Max(Math.Abs(del1), Math.Abs(del2));
|
||||
|
||||
_vsumBuff.Add(volty, Input.IsNew);
|
||||
_vSum += (_vsumBuff[^1] - _vsumBuff[0]) / 10;
|
||||
_vSum += (_vsumBuff[^1] - _vsumBuff[0]) / _vsumBuff.Count;
|
||||
_avoltyBuff.Add(_vSum, Input.IsNew);
|
||||
double avgvolty = _avoltyBuff.Average();
|
||||
|
||||
@@ -137,15 +140,15 @@ public class Jma : AbstractBase
|
||||
_upperBand = (del1 >= 0) ? price : price - (Kv * del1);
|
||||
_lowerBand = (del2 <= 0) ? price : price - (Kv * del2);
|
||||
|
||||
double alpha = Math.Pow(_beta, pow2);
|
||||
double ma1 = (1 - alpha) * Input.Value + alpha * _prevMa1;
|
||||
double _alpha = Math.Pow(_beta, pow2);
|
||||
double ma1 = Input.Value + _alpha * (_prevMa1 - Input.Value); //original: (1 - _alpha) * Input.Value + _alpha * _prevMa1;
|
||||
_prevMa1 = ma1;
|
||||
|
||||
double det0 = (price - ma1) * (1 - _beta) + _beta * _prevDet0;
|
||||
double det0 = price + _beta * (_prevDet0 - price + ma1) - ma1; //original: (price - ma1) * (1 - _beta) + _beta * _prevDet0;
|
||||
_prevDet0 = det0;
|
||||
double ma2 = ma1 + _phase * det0;
|
||||
|
||||
double det1 = ((ma2 - _prevJma) * (1 - alpha) * (1 - alpha) ) + (alpha * alpha * _prevDet1);
|
||||
double det1 = ((ma2 - _prevJma) * (1 - _alpha) * (1 - _alpha) ) + (_alpha * _alpha * _prevDet1);
|
||||
_prevDet1 = det1;
|
||||
double jma = _prevJma + det1;
|
||||
_prevJma = jma;
|
||||
|
||||
+101
-33
@@ -1,18 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// RMA: Relative Moving Average (also known as Wilder's Moving Average)
|
||||
/// RMA is similar to EMA but uses a different smoothing factor.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// RMA is similar to EMA but uses a different smoothing factor.
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Uses no buffer, relying only on the previous RMA value.
|
||||
/// - The weight of new data points (alpha) is calculated as 1 / period.
|
||||
/// - Provides a smoother curve compared to SMA and EMA, reacting more slowly to price changes.
|
||||
///
|
||||
/// Calculation method:
|
||||
/// RMA = (Previous RMA * (period - 1) + New Data) / period
|
||||
/// This implementation can use SMA for the first Period bars as a seeding value for RMA when useSma is true.
|
||||
///
|
||||
/// Sources:
|
||||
/// - https://www.tradingview.com/pine-script-reference/v5/#fun_ta{dot}rma
|
||||
@@ -20,75 +20,143 @@ namespace QuanTAlib;
|
||||
/// </remarks>
|
||||
public class Rma : AbstractBase
|
||||
{
|
||||
private readonly int _period;
|
||||
private double _lastRma;
|
||||
private readonly double _alpha;
|
||||
private double _savedLastRma;
|
||||
// inherited _index
|
||||
// inherited _value
|
||||
|
||||
public Rma(int period)
|
||||
/// <summary>
|
||||
/// The period for the RMA calculation.
|
||||
/// </summary>
|
||||
private readonly int _period;
|
||||
|
||||
/// <summary>
|
||||
/// Circular buffer for SMA calculation.
|
||||
/// </summary>
|
||||
private CircularBuffer _sma;
|
||||
|
||||
/// <summary>
|
||||
/// The last calculated RMA value.
|
||||
/// </summary>
|
||||
private double _lastRma, _p_lastRma;
|
||||
|
||||
/// <summary>
|
||||
/// Compensator for early RMA values.
|
||||
/// </summary>
|
||||
private double _e, _p_e;
|
||||
|
||||
/// <summary>
|
||||
/// The smoothing factor for RMA calculation.
|
||||
/// </summary>
|
||||
private readonly double _k;
|
||||
|
||||
/// <summary>
|
||||
/// Flags to track initialization status.
|
||||
/// </summary>
|
||||
private bool _isInit, _p_isInit;
|
||||
|
||||
/// <summary>
|
||||
/// Flag to determine whether to use SMA for initial values.
|
||||
/// </summary>
|
||||
private readonly bool _useSma;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Rma class with a specified period.
|
||||
/// </summary>
|
||||
/// <param name="period">The period for RMA calculation.</param>
|
||||
/// <param name="useSma">Whether to use SMA for initial values. Default is true.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
public Rma(int period, bool useSma = true)
|
||||
{
|
||||
if (period < 1)
|
||||
{
|
||||
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
||||
}
|
||||
_period = period;
|
||||
WarmupPeriod = period * 2;
|
||||
_alpha = 1.0 / _period; // Wilder's smoothing factor
|
||||
Name = $"Rma({_period})";
|
||||
_k = 1.0 / _period; // Wilder's smoothing factor
|
||||
_useSma = useSma;
|
||||
_sma = new(period);
|
||||
Name = "Rma";
|
||||
WarmupPeriod = _period * 2; // RMA typically needs more warmup periods
|
||||
Init();
|
||||
}
|
||||
|
||||
public Rma(object source, int period) : this(period)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Rma class with a specified source and period.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object for event subscription.</param>
|
||||
/// <param name="period">The period for RMA calculation.</param>
|
||||
/// <param name="useSma">Whether to use SMA for initial values. Default is true.</param>
|
||||
public Rma(object source, int period, bool useSma = true) : this(period, useSma)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Rma instance.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_e = 1.0;
|
||||
_lastRma = 0;
|
||||
_savedLastRma = 0;
|
||||
_isInit = false;
|
||||
_p_isInit = false;
|
||||
_sma = new(_period);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Rma instance.
|
||||
/// </summary>
|
||||
/// <param name="isNew">Indicates whether the input is new.</param>
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_savedLastRma = _lastRma;
|
||||
_lastValidValue = Input.Value;
|
||||
_p_lastRma = _lastRma;
|
||||
_p_isInit = _isInit;
|
||||
_p_e = _e;
|
||||
_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastRma = _savedLastRma;
|
||||
_lastRma = _p_lastRma;
|
||||
_isInit = _p_isInit;
|
||||
_e = _p_e;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the RMA calculation.
|
||||
/// </summary>
|
||||
/// <returns>The calculated RMA value.</returns>
|
||||
protected override double Calculation()
|
||||
{
|
||||
double result, _rma;
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
double rma;
|
||||
|
||||
if (_index == 1)
|
||||
// when _UseSma == true, use SMA calculation until we have enough data points
|
||||
if (!_isInit && _useSma)
|
||||
{
|
||||
rma = Input.Value;
|
||||
}
|
||||
else if (_index <= _period)
|
||||
{
|
||||
// Simple average during initial period
|
||||
rma = (_lastRma * (_index - 1) + Input.Value) / _index;
|
||||
_sma.Add(Input.Value, Input.IsNew);
|
||||
_rma = _sma.Average();
|
||||
result = _rma;
|
||||
if (_index >= _period)
|
||||
{
|
||||
_isInit = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wilder's smoothing method
|
||||
rma = _alpha * (_lastRma - Input.Value) + _lastRma;
|
||||
// compensator for early rma values
|
||||
_e = (_e > 1e-10) ? (1 - _k) * _e : 0;
|
||||
|
||||
_rma = _k * Input.Value + (1 - _k) * _lastRma;
|
||||
|
||||
// _useSma decides if we use compensator or not
|
||||
result = (_useSma || _e <= double.Epsilon) ? _rma : _rma / (1 - _e);
|
||||
}
|
||||
|
||||
_lastRma = rma;
|
||||
_lastRma = _rma;
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
|
||||
return rma;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user