mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-16 09:38:05 +00:00
Afirma + documentation
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class Afirma : AbstractBase
|
||||
{
|
||||
private readonly int Period;
|
||||
private readonly CircularBuffer _buffer;
|
||||
private readonly double _alpha; // Adaptive factor
|
||||
private double _lastAfirma, _p_lastAfirma;
|
||||
private double _lastError, _p_lastError;
|
||||
|
||||
public Afirma(int period, double alpha = 0.1)
|
||||
{
|
||||
if (period < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
||||
}
|
||||
if (alpha <= 0 || alpha >= 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(alpha), "Alpha must be between 0 and 1 (exclusive).");
|
||||
}
|
||||
Period = period;
|
||||
WarmupPeriod = period;
|
||||
_buffer = new CircularBuffer(period);
|
||||
_alpha = alpha;
|
||||
Name = "Afirma";
|
||||
WarmupPeriod = period;
|
||||
Init();
|
||||
}
|
||||
|
||||
public Afirma(object source, int period, double alpha = 0.1) : this(period: period, alpha: alpha)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_lastAfirma = 0;
|
||||
_lastError = 0;
|
||||
}
|
||||
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_lastValidValue = Input.Value;
|
||||
_index++;
|
||||
_p_lastAfirma = _lastAfirma;
|
||||
_p_lastError = _lastError;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastAfirma = _p_lastAfirma;
|
||||
_lastError = _p_lastError;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Core AFIRMA calculation
|
||||
/// </summary>
|
||||
protected override double Calculation()
|
||||
{
|
||||
double result;
|
||||
ManageState(IsNew);
|
||||
_buffer.Add(Input.Value, Input.IsNew);
|
||||
|
||||
if (_index < Period)
|
||||
{
|
||||
// Use simple average during warmup period
|
||||
result = _buffer.Average();
|
||||
}
|
||||
else
|
||||
{
|
||||
// AFIRMA calculation
|
||||
double sma = _buffer.Average();
|
||||
double error = Input.Value - _lastAfirma;
|
||||
double denominator = Math.Abs(error) + Math.Abs(_lastError);
|
||||
double adaptiveFactor = denominator != 0 ? _alpha * Math.Abs(error) / denominator : _alpha;
|
||||
result = sma + adaptiveFactor * (Input.Value - sma);
|
||||
|
||||
_lastError = error;
|
||||
}
|
||||
|
||||
_lastAfirma = result;
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -8,11 +8,6 @@ namespace QuanTAlib;
|
||||
/// of the data in conjunction with smoothing to reduce noise.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Smoothness: ★★★★☆ (4/5)
|
||||
/// Sensitivity: ★★★★☆ (4/5)
|
||||
/// Overshooting: ★★★★☆ (4/5)
|
||||
/// Lag: ★★★★★ (5/5)
|
||||
///
|
||||
/// Validation:
|
||||
/// Skender.Stock.Indicators
|
||||
/// </remarks>
|
||||
|
||||
+11
-9
@@ -6,11 +6,6 @@ namespace QuanTAlib;
|
||||
/// It aims to be more responsive during trending periods and more stable during ranging periods.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Smoothness: ★★★★☆ (4/5)
|
||||
/// Sensitivity: ★★★★☆ (4/5)
|
||||
/// Overshooting: ★★★★☆ (4/5)
|
||||
/// Lag: ★★★★☆ (4/5)
|
||||
///
|
||||
/// The DSMA uses a SuperSmoother filter to reduce noise and a dynamic alpha calculation based on the
|
||||
/// scaled deviation of the input data. This allows it to adapt to changing market conditions.
|
||||
///
|
||||
@@ -29,6 +24,7 @@ public class Dsma : AbstractBase
|
||||
private readonly int _period;
|
||||
private readonly CircularBuffer _buffer;
|
||||
private readonly double _c1, _c2, _c3;
|
||||
private readonly double _scaleFactor;
|
||||
private double _lastDsma, _p_lastDsma;
|
||||
private double _filt, _filt1, _filt2, _zeros, _zeros1;
|
||||
private double _p_filt, _p_filt1, _p_filt2, _p_zeros, _p_zeros1;
|
||||
@@ -39,13 +35,18 @@ public class Dsma : AbstractBase
|
||||
/// </summary>
|
||||
/// <param name="period">The number of data points used in the DSMA calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
public Dsma(int period)
|
||||
public Dsma(int period, double scaleFactor = 0.9)
|
||||
{
|
||||
if (period < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
||||
}
|
||||
if (scaleFactor <= 0 || scaleFactor > 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(scaleFactor), "Scale factor must be between 0 and 1 (exclusive).");
|
||||
}
|
||||
_period = period;
|
||||
_scaleFactor = scaleFactor;
|
||||
_buffer = new CircularBuffer(period);
|
||||
|
||||
// SuperSmoother filter coefficients
|
||||
@@ -56,11 +57,11 @@ public class Dsma : AbstractBase
|
||||
_c1 = 1 - _c2 - _c3;
|
||||
|
||||
Name = "Dsma";
|
||||
WarmupPeriod = period * 2; // A conservative estimate
|
||||
WarmupPeriod = (int) (period * 1.5); // A conservative estimate
|
||||
Init();
|
||||
}
|
||||
|
||||
public Dsma(object source, int period) : this(period)
|
||||
public Dsma(object source, int period, double scaleFactor = 0.9) : this(period, scaleFactor)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
@@ -127,7 +128,8 @@ public class Dsma : AbstractBase
|
||||
double scaledFilt = rms != 0 ? _filt / rms : 0;
|
||||
|
||||
// Calculate adaptive alpha
|
||||
double alpha = Math.Abs(scaledFilt) * 5 / _period;
|
||||
double alpha = _scaleFactor * Math.Abs(scaledFilt) * 5 / _period;
|
||||
alpha = Math.Max(0.1, Math.Min(1.0, alpha));
|
||||
|
||||
// DSMA calculation
|
||||
double dsma = alpha * Input.Value + (1 - alpha) * _lastDsma;
|
||||
|
||||
@@ -6,11 +6,6 @@ namespace QuanTAlib;
|
||||
/// previous EMA value. The weight of the new datapoint (alpha) is alpha = 2 / (period + 1)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Smoothness: ★★★☆☆ (3/5)
|
||||
/// Sensitivity: ★★★★☆ (4/5)
|
||||
/// Overshooting: ★★★★★ (5/5)
|
||||
/// Lag: ★★★☆☆ (3/5)
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Uses no buffer, relying only on the previous EMA value.
|
||||
/// - The weight of new data points is calculated as alpha = 2 / (period + 1).
|
||||
|
||||
Reference in New Issue
Block a user