mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-23 21:18:04 +00:00
first iteration
This commit is contained in:
@@ -1,177 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// ADX: Average Directional Movement Index
|
||||
/// A technical analysis indicator used to measure the strength of a trend,
|
||||
/// regardless of its direction. ADX combines the Positive and Negative
|
||||
/// Directional Movement Indicators to determine trend strength.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The ADX calculation process:
|
||||
/// 1. Calculate True Range (TR)
|
||||
/// 2. Calculate +DM (Positive Directional Movement)
|
||||
/// 3. Calculate -DM (Negative Directional Movement)
|
||||
/// 4. Smooth TR, +DM, and -DM using Wilder's smoothing
|
||||
/// 5. Calculate +DI and -DI
|
||||
/// 6. Calculate DX (Directional Index)
|
||||
/// 7. Smooth DX to get ADX
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Oscillates between 0 and 100
|
||||
/// - Values above 25 indicate strong trend
|
||||
/// - Values below 20 indicate weak or no trend
|
||||
/// - Can be used with +DI and -DI for trade signals
|
||||
/// - Does not indicate trend direction, only strength
|
||||
///
|
||||
/// Formula:
|
||||
/// TR = max(high-low, abs(high-prevClose), abs(low-prevClose))
|
||||
/// +DM = if(high-prevHigh > prevLow-low) then max(high-prevHigh, 0) else 0
|
||||
/// -DM = if(prevLow-low > high-prevHigh) then max(prevLow-low, 0) else 0
|
||||
/// +DI = 100 * smoothed(+DM) / smoothed(TR)
|
||||
/// -DI = 100 * smoothed(-DM) / smoothed(TR)
|
||||
/// DX = 100 * abs(+DI - -DI) / (+DI + -DI)
|
||||
/// ADX = smoothed(DX)
|
||||
///
|
||||
/// Sources:
|
||||
/// J. Welles Wilder Jr. - "New Concepts in Technical Trading Systems" (1978)
|
||||
/// https://www.investopedia.com/terms/a/adx.asp
|
||||
///
|
||||
/// Note: Default period of 14 was recommended by Wilder
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Adx : AbstractBarBase
|
||||
{
|
||||
private readonly Rma _smoothedTr;
|
||||
private readonly Rma _smoothedPlusDm;
|
||||
private readonly Rma _smoothedMinusDm;
|
||||
private readonly Rma _smoothedDx;
|
||||
private double _prevHigh, _prevLow, _prevClose;
|
||||
private double _p_prevHigh, _p_prevLow, _p_prevClose;
|
||||
private const double ScalingFactor = 100.0;
|
||||
private const int DefaultPeriod = 14;
|
||||
|
||||
/// <param name="period">The number of periods used in the ADX calculation (default 14).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Adx(int period = DefaultPeriod)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(period, 1);
|
||||
_smoothedTr = new(period, useSma: true);
|
||||
_smoothedPlusDm = new(period, useSma: true);
|
||||
_smoothedMinusDm = new(period, useSma: true);
|
||||
_smoothedDx = new(period, useSma: true);
|
||||
_index = 0;
|
||||
WarmupPeriod = period * 2; // Need extra period for DX smoothing
|
||||
Name = $"ADX({period})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of periods used in the ADX calculation.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Adx(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_index++;
|
||||
_p_prevHigh = _prevHigh;
|
||||
_p_prevLow = _prevLow;
|
||||
_p_prevClose = _prevClose;
|
||||
}
|
||||
else
|
||||
{
|
||||
_prevHigh = _p_prevHigh;
|
||||
_prevLow = _p_prevLow;
|
||||
_prevClose = _p_prevClose;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static double CalculateTrueRange(double high, double low, double prevClose)
|
||||
{
|
||||
double hl = high - low;
|
||||
double hpc = Math.Abs(high - prevClose);
|
||||
double lpc = Math.Abs(low - prevClose);
|
||||
return Math.Max(hl, Math.Max(hpc, lpc));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static (double plusDm, double minusDm) CalculateDirectionalMovement(
|
||||
double high, double low, double prevHigh, double prevLow)
|
||||
{
|
||||
double upMove = high - prevHigh;
|
||||
double downMove = prevLow - low;
|
||||
|
||||
double plusDm = 0.0;
|
||||
double minusDm = 0.0;
|
||||
|
||||
if (upMove > downMove && upMove > 0)
|
||||
plusDm = upMove;
|
||||
else if (downMove > upMove && downMove > 0)
|
||||
minusDm = downMove;
|
||||
|
||||
return (plusDm, minusDm);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static double CalculateDx(double plusDi, double minusDi)
|
||||
{
|
||||
double sum = plusDi + minusDi;
|
||||
if (sum > 0)
|
||||
return ScalingFactor * Math.Abs(plusDi - minusDi) / sum;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
if (_index == 1)
|
||||
{
|
||||
_prevHigh = Input.High;
|
||||
_prevLow = Input.Low;
|
||||
_prevClose = Input.Close;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Calculate True Range and Directional Movement
|
||||
double tr = CalculateTrueRange(Input.High, Input.Low, _prevClose);
|
||||
var (plusDm, minusDm) = CalculateDirectionalMovement(
|
||||
Input.High, Input.Low, _prevHigh, _prevLow);
|
||||
|
||||
// Update previous values
|
||||
_prevHigh = Input.High;
|
||||
_prevLow = Input.Low;
|
||||
_prevClose = Input.Close;
|
||||
|
||||
// Smooth the indicators using Wilder's method
|
||||
_smoothedTr.Calc(tr, Input.IsNew);
|
||||
_smoothedPlusDm.Calc(plusDm, Input.IsNew);
|
||||
_smoothedMinusDm.Calc(minusDm, Input.IsNew);
|
||||
|
||||
// Calculate +DI and -DI
|
||||
double smoothedTr = _smoothedTr.Value;
|
||||
if (smoothedTr > 0)
|
||||
{
|
||||
double plusDi = ScalingFactor * _smoothedPlusDm.Value / smoothedTr;
|
||||
double minusDi = ScalingFactor * _smoothedMinusDm.Value / smoothedTr;
|
||||
|
||||
// Calculate DX
|
||||
double dx = CalculateDx(plusDi, minusDi);
|
||||
|
||||
// Smooth DX to get ADX
|
||||
_smoothedDx.Calc(dx, Input.IsNew);
|
||||
return _smoothedDx.Value;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// ADXR: Average Directional Movement Index Rating
|
||||
/// A momentum indicator that measures the strength of a trend by comparing
|
||||
/// the current ADX value with its value from a specified number of periods ago.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The ADXR calculation process:
|
||||
/// 1. Calculate current ADX
|
||||
/// 2. Get ADX value from n periods ago
|
||||
/// 3. Average the two values
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Oscillates between 0 and 100
|
||||
/// - Values above 25 indicate strong trend
|
||||
/// - Values below 20 indicate weak or no trend
|
||||
/// - Can be used to confirm trend strength
|
||||
/// - Helps identify potential trend reversals
|
||||
///
|
||||
/// Formula:
|
||||
/// ADXR = (Current ADX + ADX n periods ago) / 2
|
||||
///
|
||||
/// Sources:
|
||||
/// J. Welles Wilder Jr. - "New Concepts in Technical Trading Systems" (1978)
|
||||
/// https://www.investopedia.com/terms/a/adxr.asp
|
||||
/// </remarks>
|
||||
public sealed class Adxr : AbstractBarBase
|
||||
{
|
||||
private readonly Adx _currentAdx;
|
||||
private readonly CircularBuffer _adxHistory;
|
||||
private readonly int _period;
|
||||
|
||||
/// <param name="period">The number of periods used in the ADXR calculation (default 14).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Adxr(int period = 14)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(period, 1);
|
||||
_currentAdx = new(period);
|
||||
_adxHistory = new(period);
|
||||
_period = period;
|
||||
WarmupPeriod = period * 3; // Need extra periods for ADX calculation and history
|
||||
Name = $"ADXR({period})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of periods used in the ADXR calculation.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Adxr(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
// Calculate current ADX
|
||||
double currentAdx = _currentAdx.Calc(Input);
|
||||
_adxHistory.Add(currentAdx, Input.IsNew);
|
||||
|
||||
// Calculate ADXR once we have enough history
|
||||
if (_index > _period)
|
||||
{
|
||||
return (currentAdx + _adxHistory[^_period]) * 0.5;
|
||||
}
|
||||
|
||||
return currentAdx;
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// APO: Absolute Price Oscillator
|
||||
/// A momentum indicator that measures the difference between two moving averages
|
||||
/// of different periods. Similar to PPO but shows absolute difference instead of percentage.
|
||||
/// </summary>
|
||||
public sealed class Apo : AbstractBase
|
||||
{
|
||||
private readonly AbstractBase _fastMa, _slowMa;
|
||||
|
||||
/// <param name="fastPeriod">The period for the faster moving average.</param>
|
||||
/// <param name="slowPeriod">The period for the slower moving average.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when fastPeriod or slowPeriod is less than 1, or when fastPeriod is greater than or equal to slowPeriod.
|
||||
/// </exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Apo(int fastPeriod = 12, int slowPeriod = 26)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(fastPeriod, 1);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(slowPeriod, 1);
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(fastPeriod, slowPeriod);
|
||||
|
||||
_fastMa = new Ema(fastPeriod);
|
||||
_slowMa = new Ema(slowPeriod);
|
||||
WarmupPeriod = slowPeriod;
|
||||
Name = $"APO({fastPeriod},{slowPeriod})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="fastPeriod">The period for the faster moving average.</param>
|
||||
/// <param name="slowPeriod">The period for the slower moving average.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Apo(object source, int fastPeriod, int slowPeriod) : this(fastPeriod, slowPeriod)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_index++;
|
||||
_lastValidValue = Input.Value;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
_fastMa.Calc(Input);
|
||||
_slowMa.Calc(Input);
|
||||
return _fastMa.Value - _slowMa.Value;
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// DMI: Directional Movement Index
|
||||
/// A technical indicator that identifies the directional movement of price by
|
||||
/// comparing successive highs and lows. DMI consists of two lines: +DI and -DI,
|
||||
/// which help determine trend direction and strength.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The DMI calculation process:
|
||||
/// 1. Calculate True Range (TR)
|
||||
/// 2. Calculate +DM (Positive Directional Movement)
|
||||
/// 3. Calculate -DM (Negative Directional Movement)
|
||||
/// 4. Smooth TR, +DM, and -DM using Wilder's smoothing
|
||||
/// 5. Calculate +DI and -DI as percentages
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Both +DI and -DI oscillate between 0 and 100
|
||||
/// - When +DI > -DI, uptrend is indicated
|
||||
/// - When -DI > +DI, downtrend is indicated
|
||||
/// - Crossovers of +DI and -DI signal potential trend changes
|
||||
/// - Used in conjunction with ADX for trend trading
|
||||
///
|
||||
/// Formula:
|
||||
/// TR = max(high-low, abs(high-prevClose), abs(low-prevClose))
|
||||
/// +DM = if(high-prevHigh > prevLow-low && high-prevHigh > 0) then high-prevHigh else 0
|
||||
/// -DM = if(prevLow-low > high-prevHigh && prevLow-low > 0) then prevLow-low else 0
|
||||
/// Smoothed TR = Wilder's smoothing of TR (ATR)
|
||||
/// Smoothed +DM = Wilder's smoothing of +DM
|
||||
/// Smoothed -DM = Wilder's smoothing of -DM
|
||||
/// +DI = 100 * Smoothed(+DM) / Smoothed(TR)
|
||||
/// -DI = 100 * Smoothed(-DM) / Smoothed(TR)
|
||||
///
|
||||
/// Sources:
|
||||
/// J. Welles Wilder Jr. - "New Concepts in Technical Trading Systems" (1978)
|
||||
/// https://www.investopedia.com/terms/d/dmi.asp
|
||||
///
|
||||
/// Note: Default period of 14 was recommended by Wilder
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Dmi : AbstractBase
|
||||
{
|
||||
private readonly Atr _atr;
|
||||
private readonly Rma _smoothedPlusDm;
|
||||
private readonly Rma _smoothedMinusDm;
|
||||
private double _prevHigh, _prevLow;
|
||||
private double _p_prevHigh, _p_prevLow;
|
||||
private double _plusDi, _minusDi;
|
||||
private const double ScalingFactor = 100.0;
|
||||
private const int DefaultPeriod = 14;
|
||||
|
||||
public double PlusDI => _plusDi;
|
||||
public double MinusDI => _minusDi;
|
||||
|
||||
public Dmi(int period = DefaultPeriod)
|
||||
{
|
||||
if (period < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(period));
|
||||
_atr = new(period);
|
||||
_smoothedPlusDm = new(period);
|
||||
_smoothedMinusDm = new(period);
|
||||
WarmupPeriod = period + 1;
|
||||
Name = $"DMI({period})";
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_atr.Init();
|
||||
_smoothedPlusDm.Init();
|
||||
_smoothedMinusDm.Init();
|
||||
_prevHigh = _prevLow = double.NaN;
|
||||
_p_prevHigh = _p_prevLow = double.NaN;
|
||||
_plusDi = _minusDi = 0;
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_index++;
|
||||
_p_prevHigh = _prevHigh;
|
||||
_p_prevLow = _prevLow;
|
||||
}
|
||||
else
|
||||
{
|
||||
_prevHigh = _p_prevHigh;
|
||||
_prevLow = _p_prevLow;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static (double plusDm, double minusDm) CalculateDirectionalMovement(
|
||||
double high, double low, double prevHigh, double prevLow)
|
||||
{
|
||||
double upMove = high - prevHigh;
|
||||
double downMove = prevLow - low;
|
||||
|
||||
double plusDm = (upMove > downMove && upMove > 0) ? upMove : 0;
|
||||
double minusDm = (downMove > upMove && downMove > 0) ? downMove : 0;
|
||||
|
||||
return (plusDm, minusDm);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
if (double.IsNaN(_prevHigh))
|
||||
{
|
||||
_prevHigh = BarInput.High;
|
||||
_prevLow = BarInput.Low;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Calculate ATR
|
||||
double atr = _atr.Calc(BarInput).Value;
|
||||
|
||||
// Calculate Directional Movement
|
||||
var (plusDm, minusDm) = CalculateDirectionalMovement(
|
||||
BarInput.High, BarInput.Low, _prevHigh, _prevLow);
|
||||
|
||||
// Update previous values for next calculation
|
||||
_prevHigh = BarInput.High;
|
||||
_prevLow = BarInput.Low;
|
||||
|
||||
// Smooth DM values using Wilder's method
|
||||
double smoothedPlusDm = _smoothedPlusDm.Calc(plusDm, BarInput.IsNew).Value;
|
||||
double smoothedMinusDm = _smoothedMinusDm.Calc(minusDm, BarInput.IsNew).Value;
|
||||
|
||||
// Calculate DI values
|
||||
if (atr > 0)
|
||||
{
|
||||
_plusDi = ScalingFactor * smoothedPlusDm / atr;
|
||||
_minusDi = ScalingFactor * smoothedMinusDm / atr;
|
||||
return _plusDi - _minusDi;
|
||||
}
|
||||
|
||||
_plusDi = 0.0;
|
||||
_minusDi = 0.0;
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// DMX: Enhanced Directional Movement Index using JMA smoothing
|
||||
/// An improvement over the traditional DMI indicator that uses Jurik Moving Average (JMA)
|
||||
/// for smoothing. This enhancement provides better noise reduction while maintaining
|
||||
/// responsiveness to significant price movements.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The DMX calculation process:
|
||||
/// 1. Calculate DMI using the standard Dmi class
|
||||
/// 2. Apply JMA smoothing to the +DI and -DI values
|
||||
///
|
||||
/// Key improvements over DMI:
|
||||
/// - Uses JMA's adaptive volatility-based smoothing
|
||||
/// - Better noise reduction in the directional movement signals
|
||||
/// - Maintains responsiveness to significant price movements
|
||||
/// - Reduced lag through JMA's phase-shifting
|
||||
///
|
||||
/// Formula:
|
||||
/// DMI calculation as per standard DMI
|
||||
/// DMX +DI = JMA(DMI +DI)
|
||||
/// DMX -DI = JMA(DMI -DI)
|
||||
///
|
||||
/// Sources:
|
||||
/// Original DMI by J. Welles Wilder Jr. - "New Concepts in Technical Trading Systems" (1978)
|
||||
/// Enhanced with JMA smoothing by Mark Jurik
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Dmx : AbstractBarBase
|
||||
{
|
||||
private readonly Dmi _dmi;
|
||||
private readonly Jma _smoothedPlusDi;
|
||||
private readonly Jma _smoothedMinusDi;
|
||||
private double _plusDi, _minusDi;
|
||||
private const int DefaultDmiPeriod = 14;
|
||||
private const int DefaultJmaPeriod = 7;
|
||||
private const int DefaultPhase = 100;
|
||||
private const double DefaultFactor = 0.25;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the most recent smoothed +DI value
|
||||
/// </summary>
|
||||
public double PlusDI => _plusDi;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the most recent smoothed -DI value
|
||||
/// </summary>
|
||||
public double MinusDI => _minusDi;
|
||||
|
||||
/// <param name="dmiPeriod">The number of periods used in the DMI calculation (default 14).</param>
|
||||
/// <param name="jmaPeriod">The number of periods used in the JMA smoothing (default 10).</param>
|
||||
/// <param name="phase">The phase for the JMA smoothing (default 100).</param>
|
||||
/// <param name="factor">The factor for the JMA smoothing (default 0.25).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Dmx(int period = DefaultDmiPeriod, int jmaPeriod = DefaultJmaPeriod, int phase = DefaultPhase, double factor = DefaultFactor)
|
||||
{
|
||||
if (period < 1 || jmaPeriod < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Periods must be greater than or equal to 1.");
|
||||
_dmi = new(period);
|
||||
_smoothedPlusDi = new(jmaPeriod, phase, factor);
|
||||
_smoothedMinusDi = new(jmaPeriod, phase, factor);
|
||||
WarmupPeriod = period + jmaPeriod;
|
||||
Name = $"DMX({period},{jmaPeriod})";
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
// Calculate DMI
|
||||
_dmi.Calc(Input);
|
||||
|
||||
// Smooth the DMI values using JMA
|
||||
_plusDi = _smoothedPlusDi.Calc(_dmi.PlusDI, Input.IsNew).Value;
|
||||
_minusDi = _smoothedMinusDi.Calc(_dmi.MinusDI, Input.IsNew).Value;
|
||||
|
||||
return _plusDi - _minusDi; // Return the difference as main value
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// DPO: Detrended Price Oscillator
|
||||
/// A momentum indicator that removes the trend from price by comparing the current price
|
||||
/// to a past moving average, helping to identify cycles in the price.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The DPO calculation process:
|
||||
/// 1. Calculate the period shifted back by (period / 2 + 1) days
|
||||
/// 2. Calculate SMA for the shifted period
|
||||
/// 3. DPO = Price - SMA(Price, period) shifted back
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Removes long-term trends
|
||||
/// - Helps identify cycles
|
||||
/// - Oscillates above and below zero
|
||||
/// - Default period is 20 days
|
||||
/// - Uses price displacement
|
||||
///
|
||||
/// Formula:
|
||||
/// DPO = Price - SMA(Price, period) shifted (period/2 + 1) bars back
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Cycle identification
|
||||
/// - Overbought/Oversold conditions
|
||||
/// - Price momentum
|
||||
/// - Trading signals
|
||||
/// - Market timing
|
||||
///
|
||||
/// Sources:
|
||||
/// Donald Dorsey - Original development
|
||||
/// https://www.investopedia.com/terms/d/detrended-price-oscillator-dpo.asp
|
||||
///
|
||||
/// Note: DPO helps identify cycles by removing the trend component from the price data
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Dpo : AbstractBase
|
||||
{
|
||||
private readonly int _shift;
|
||||
private readonly CircularBuffer _prices;
|
||||
private readonly CircularBuffer _sma;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Dpo(int period = 20)
|
||||
{
|
||||
_shift = (period / 2) + 1;
|
||||
WarmupPeriod = period + _shift;
|
||||
Name = $"DPO({period})";
|
||||
_prices = new CircularBuffer(WarmupPeriod);
|
||||
_sma = new CircularBuffer(period);
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Dpo(object source, int period = 20) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prices.Clear();
|
||||
_sma.Clear();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_lastValidValue = Value;
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
// Add current price to buffer
|
||||
_prices.Add(BarInput.Close, BarInput.IsNew);
|
||||
// Need enough prices for the shifted SMA calculation
|
||||
|
||||
if (_index <= _shift)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add price from shift periods ago to SMA buffer
|
||||
_sma.Add(_prices[_shift]);
|
||||
|
||||
// Calculate DPO
|
||||
double dpo = BarInput.Close - _sma.Average();
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return dpo;
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// MACD: Moving Average Convergence Divergence
|
||||
/// A trend-following momentum indicator that shows the relationship between two moving
|
||||
/// averages of an asset's price. MACD is calculated by subtracting the longer-period
|
||||
/// EMA from the shorter-period EMA. The result is then used to calculate a signal line
|
||||
/// (EMA of MACD) and histogram (MACD - Signal).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The MACD calculation process:
|
||||
/// 1. Calculate the fast EMA (default 12 periods)
|
||||
/// 2. Calculate the slow EMA (default 26 periods)
|
||||
/// 3. MACD Line = Fast EMA - Slow EMA
|
||||
/// 4. Signal Line = EMA of MACD Line (default 9 periods)
|
||||
/// 5. MACD Histogram = MACD Line - Signal Line
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Centerline crossovers signal trend changes
|
||||
/// - Signal line crossovers indicate trading opportunities
|
||||
/// - Histogram shows momentum of price movement
|
||||
/// - Divergences can signal potential reversals
|
||||
///
|
||||
/// Formula:
|
||||
/// MACD Line = EMA(fast) - EMA(slow)
|
||||
/// Signal Line = EMA(MACD Line, signal)
|
||||
/// Histogram = MACD Line - Signal Line
|
||||
///
|
||||
/// Sources:
|
||||
/// https://www.investopedia.com/terms/m/macd.asp
|
||||
/// https://school.stockcharts.com/doku.php?id=technical_indicators:macd
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Macd : AbstractBase
|
||||
{
|
||||
private readonly Ema _fastEma;
|
||||
private readonly Ema _slowEma;
|
||||
private readonly Ema _signalEma;
|
||||
private const int DefaultFastPeriod = 12;
|
||||
private const int DefaultSlowPeriod = 26;
|
||||
private const int DefaultSignalPeriod = 9;
|
||||
private double _macdLine;
|
||||
private double _signalLine;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MACD line value (Fast EMA - Slow EMA)
|
||||
/// </summary>
|
||||
public double MacdLine => _macdLine;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Signal line value (EMA of MACD line)
|
||||
/// </summary>
|
||||
public double SignalLine => _signalLine;
|
||||
|
||||
/// <param name="fastPeriod">The number of periods for the fast EMA (default 12).</param>
|
||||
/// <param name="slowPeriod">The number of periods for the slow EMA (default 26).</param>
|
||||
/// <param name="signalPeriod">The number of periods for the signal line EMA (default 9).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when any period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Macd(int fastPeriod = DefaultFastPeriod, int slowPeriod = DefaultSlowPeriod, int signalPeriod = DefaultSignalPeriod)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(fastPeriod, 1);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(slowPeriod, 1);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(signalPeriod, 1);
|
||||
|
||||
if (fastPeriod >= slowPeriod)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(fastPeriod), "Fast period must be less than slow period");
|
||||
}
|
||||
|
||||
_fastEma = new(fastPeriod);
|
||||
_slowEma = new(slowPeriod);
|
||||
_signalEma = new(signalPeriod);
|
||||
WarmupPeriod = slowPeriod + signalPeriod;
|
||||
Name = $"MACD({fastPeriod},{slowPeriod},{signalPeriod})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="fastPeriod">The number of periods for the fast EMA.</param>
|
||||
/// <param name="slowPeriod">The number of periods for the slow EMA.</param>
|
||||
/// <param name="signalPeriod">The number of periods for the signal line EMA.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Macd(object source, int fastPeriod, int slowPeriod, int signalPeriod) : this(fastPeriod, slowPeriod, signalPeriod)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
_index++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
// Calculate MACD line
|
||||
double fastEma = _fastEma.Calc(Input.Value, Input.IsNew);
|
||||
double slowEma = _slowEma.Calc(Input.Value, Input.IsNew);
|
||||
_macdLine = fastEma - slowEma;
|
||||
|
||||
// Calculate Signal line
|
||||
_signalLine = _signalEma.Calc(_macdLine, Input.IsNew);
|
||||
|
||||
// Return histogram
|
||||
return _macdLine - _signalLine;
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Mom: Momentum
|
||||
/// A basic momentum indicator that measures the change in price over a specified
|
||||
/// period, helping identify the strength and speed of price movements.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Momentum calculation process:
|
||||
/// 1. Store historical prices in a circular buffer
|
||||
/// 2. Calculate absolute difference between current and historical price
|
||||
/// 3. No scaling factor applied to maintain raw price difference
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Basic momentum measurement
|
||||
/// - Shows absolute price changes
|
||||
/// - Zero line crossovers signal trend changes
|
||||
/// - Foundation for other momentum indicators
|
||||
///
|
||||
/// Formula:
|
||||
/// Mom = Price - PriceN
|
||||
/// where PriceN is the price N periods ago
|
||||
///
|
||||
/// Sources:
|
||||
/// Technical Analysis of Financial Markets by John J. Murphy
|
||||
/// Technical Analysis Using Multiple Timeframes by Brian Shannon
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Mom : AbstractBase
|
||||
{
|
||||
private readonly CircularBuffer _priceBuffer;
|
||||
private const int DefaultPeriod = 10;
|
||||
|
||||
/// <param name="period">The lookback period for momentum calculation (default 10).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Mom(int period = DefaultPeriod)
|
||||
{
|
||||
if (period < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(period));
|
||||
|
||||
_priceBuffer = new(period + 1);
|
||||
WarmupPeriod = period;
|
||||
Name = $"MOM({period})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The lookback period for momentum calculation.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Mom(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
_priceBuffer.Add(Input.Value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
if (_priceBuffer.Count < _priceBuffer.Capacity)
|
||||
return 0.0;
|
||||
|
||||
return Input.Value - _priceBuffer[0];
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// PMO: Price Momentum Oscillator
|
||||
/// A momentum indicator that uses exponential moving averages of ROC (Rate of Change)
|
||||
/// to identify overbought and oversold conditions in price movements.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The PMO calculation process:
|
||||
/// 1. Calculate ROC (Rate of Change) of closing prices
|
||||
/// 2. Apply a first smoothing EMA to the ROC values
|
||||
/// 3. Apply a second smoothing EMA to the result
|
||||
/// 4. Multiply by a scaling factor for better visualization
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Double-smoothed momentum indicator
|
||||
/// - Helps identify overbought/oversold conditions
|
||||
/// - Useful for trend confirmation and divergence analysis
|
||||
/// - More responsive than traditional momentum oscillators
|
||||
///
|
||||
/// Formula:
|
||||
/// ROC = (Close - PrevClose) / PrevClose
|
||||
/// Signal1 = EMA(ROC, Period1)
|
||||
/// PMO = EMA(Signal1, Period2) * ScalingFactor
|
||||
///
|
||||
/// Sources:
|
||||
/// Developed by Carl Swenlin
|
||||
/// Technical Analysis of Stocks and Commodities magazine
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Pmo : AbstractBase
|
||||
{
|
||||
private readonly Ema _smoothing1;
|
||||
private readonly Ema _smoothing2;
|
||||
private double _prevClose;
|
||||
private double _p_prevClose;
|
||||
private const double ScalingFactor = 100.0;
|
||||
private const int DefaultPeriod1 = 35;
|
||||
private const int DefaultPeriod2 = 20;
|
||||
|
||||
/// <param name="period1">The first smoothing period (default 35).</param>
|
||||
/// <param name="period2">The second smoothing period (default 20).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when either period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pmo(int period1 = DefaultPeriod1, int period2 = DefaultPeriod2)
|
||||
{
|
||||
if (period1 < 1 || period2 < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(period1));
|
||||
|
||||
_smoothing1 = new(period1);
|
||||
_smoothing2 = new(period2);
|
||||
_index = 0;
|
||||
WarmupPeriod = period1 + period2;
|
||||
Name = $"PMO({period1},{period2})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period1">The first smoothing period.</param>
|
||||
/// <param name="period2">The second smoothing period.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pmo(object source, int period1, int period2) : this(period1, period2)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_index++;
|
||||
_p_prevClose = _prevClose;
|
||||
}
|
||||
else
|
||||
{
|
||||
_prevClose = _p_prevClose;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
if (_index == 1)
|
||||
{
|
||||
_prevClose = Input.Value;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Calculate Rate of Change
|
||||
double roc = (Input.Value - _prevClose) / _prevClose;
|
||||
_prevClose = Input.Value;
|
||||
|
||||
// Apply double smoothing
|
||||
double signal1 = _smoothing1.Calc(roc, Input.IsNew);
|
||||
return _smoothing2.Calc(signal1, Input.IsNew) * ScalingFactor;
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// PO: Price Oscillator
|
||||
/// A momentum indicator that measures the difference between two moving averages
|
||||
/// of different periods to identify price momentum and potential trend changes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The PO calculation process:
|
||||
/// 1. Calculate fast EMA of closing prices
|
||||
/// 2. Calculate slow EMA of closing prices
|
||||
/// 3. Calculate the difference between fast and slow EMAs
|
||||
/// 4. Multiply by a scaling factor for better visualization
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Measures momentum through moving average differences
|
||||
/// - Helps identify trend direction and potential reversals
|
||||
/// - Zero line crossovers signal trend changes
|
||||
/// - Similar to MACD but more customizable periods
|
||||
///
|
||||
/// Formula:
|
||||
/// FastMA = EMA(Close, FastPeriod)
|
||||
/// SlowMA = EMA(Close, SlowPeriod)
|
||||
/// PO = (FastMA - SlowMA) * ScalingFactor
|
||||
///
|
||||
/// Sources:
|
||||
/// Technical Analysis of Financial Markets by John J. Murphy
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Po : AbstractBase
|
||||
{
|
||||
private readonly Ema _fastEma;
|
||||
private readonly Ema _slowEma;
|
||||
private const double ScalingFactor = 1.0;
|
||||
private const int DefaultFastPeriod = 10;
|
||||
private const int DefaultSlowPeriod = 21;
|
||||
|
||||
/// <param name="fastPeriod">The fast EMA period (default 10).</param>
|
||||
/// <param name="slowPeriod">The slow EMA period (default 21).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when either period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Po(int fastPeriod = DefaultFastPeriod, int slowPeriod = DefaultSlowPeriod)
|
||||
{
|
||||
if (fastPeriod < 1 || slowPeriod < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(fastPeriod));
|
||||
if (fastPeriod >= slowPeriod)
|
||||
throw new ArgumentException("Fast period must be less than slow period");
|
||||
|
||||
_fastEma = new(fastPeriod);
|
||||
_slowEma = new(slowPeriod);
|
||||
WarmupPeriod = slowPeriod;
|
||||
Name = $"PO({fastPeriod},{slowPeriod})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="fastPeriod">The fast EMA period.</param>
|
||||
/// <param name="slowPeriod">The slow EMA period.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Po(object source, int fastPeriod, int slowPeriod) : this(fastPeriod, slowPeriod)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
// No state management needed for this indicator
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
double fastEma = _fastEma.Calc(Input.Value, Input.IsNew);
|
||||
double slowEma = _slowEma.Calc(Input.Value, Input.IsNew);
|
||||
return (fastEma - slowEma) * ScalingFactor;
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// PPO: Percentage Price Oscillator
|
||||
/// A momentum indicator that shows the percentage difference between two moving averages
|
||||
/// of different periods, helping identify price momentum and potential trend changes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The PPO calculation process:
|
||||
/// 1. Calculate fast EMA of closing prices
|
||||
/// 2. Calculate slow EMA of closing prices
|
||||
/// 3. Calculate the percentage difference between fast and slow EMAs
|
||||
/// 4. Multiply by a scaling factor for better visualization
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Measures momentum through percentage differences
|
||||
/// - Normalized for comparison across different price levels
|
||||
/// - Zero line crossovers signal trend changes
|
||||
/// - Similar to MACD but expressed as a percentage
|
||||
///
|
||||
/// Formula:
|
||||
/// FastMA = EMA(Close, FastPeriod)
|
||||
/// SlowMA = EMA(Close, SlowPeriod)
|
||||
/// PPO = ((FastMA - SlowMA) / SlowMA) * 100
|
||||
///
|
||||
/// Sources:
|
||||
/// Technical Analysis of Financial Markets by John J. Murphy
|
||||
/// StockCharts.com Technical Indicators
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Ppo : AbstractBase
|
||||
{
|
||||
private readonly Ema _fastEma;
|
||||
private readonly Ema _slowEma;
|
||||
private const double ScalingFactor = 100.0;
|
||||
private const int DefaultFastPeriod = 12;
|
||||
private const int DefaultSlowPeriod = 26;
|
||||
|
||||
/// <param name="fastPeriod">The fast EMA period (default 12).</param>
|
||||
/// <param name="slowPeriod">The slow EMA period (default 26).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when either period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Ppo(int fastPeriod = DefaultFastPeriod, int slowPeriod = DefaultSlowPeriod)
|
||||
{
|
||||
if (fastPeriod < 1 || slowPeriod < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(fastPeriod));
|
||||
if (fastPeriod >= slowPeriod)
|
||||
throw new ArgumentException("Fast period must be less than slow period");
|
||||
|
||||
_fastEma = new(fastPeriod);
|
||||
_slowEma = new(slowPeriod);
|
||||
WarmupPeriod = slowPeriod;
|
||||
Name = $"PPO({fastPeriod},{slowPeriod})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="fastPeriod">The fast EMA period.</param>
|
||||
/// <param name="slowPeriod">The slow EMA period.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Ppo(object source, int fastPeriod, int slowPeriod) : this(fastPeriod, slowPeriod)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
// No state management needed for this indicator
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
double fastEma = _fastEma.Calc(Input.Value, Input.IsNew);
|
||||
double slowEma = _slowEma.Calc(Input.Value, Input.IsNew);
|
||||
|
||||
if (Math.Abs(slowEma) <= double.Epsilon)
|
||||
return 0.0;
|
||||
|
||||
return ((fastEma - slowEma) / slowEma) * ScalingFactor;
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// PRS: Price Relative Strength
|
||||
/// A momentum indicator that compares the performance of a security against a benchmark,
|
||||
/// helping identify which is showing stronger relative momentum.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The PRS calculation process:
|
||||
/// 1. Take the current price of the security
|
||||
/// 2. Take the current price of the benchmark
|
||||
/// 3. Calculate the ratio between them
|
||||
/// 4. Multiply by a scaling factor for better visualization
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Measures relative performance against a benchmark
|
||||
/// - Helps identify market leaders and laggards
|
||||
/// - Rising PRS indicates outperformance
|
||||
/// - Falling PRS indicates underperformance
|
||||
///
|
||||
/// Formula:
|
||||
/// PRS = (Price / Benchmark) * 100
|
||||
///
|
||||
/// Sources:
|
||||
/// Technical Analysis of Financial Markets by John J. Murphy
|
||||
/// StockCharts.com Technical Indicators
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Prs : AbstractBase
|
||||
{
|
||||
private const double ScalingFactor = 100.0;
|
||||
private double _benchmark;
|
||||
private double _p_benchmark;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the PRS indicator
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Prs()
|
||||
{
|
||||
WarmupPeriod = 1;
|
||||
Name = "PRS";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Prs(object source) : this()
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current benchmark value
|
||||
/// </summary>
|
||||
/// <param name="benchmark">The benchmark value to compare against</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetBenchmark(double benchmark)
|
||||
{
|
||||
_benchmark = benchmark;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
_p_benchmark = _benchmark;
|
||||
else
|
||||
_benchmark = _p_benchmark;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
if (_benchmark <= double.Epsilon)
|
||||
return 0.0;
|
||||
|
||||
return (Input.Value / _benchmark) * ScalingFactor;
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// ROC: Rate of Change
|
||||
/// A momentum indicator that measures the percentage change in price over a specified
|
||||
/// period, helping identify the speed and strength of price movements.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The ROC calculation process:
|
||||
/// 1. Store historical prices in a circular buffer
|
||||
/// 2. Calculate percentage change between current and historical price
|
||||
/// 3. Multiply by scaling factor for better visualization
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Pure momentum indicator
|
||||
/// - Oscillates around zero line
|
||||
/// - Helps identify overbought/oversold conditions
|
||||
/// - Useful for divergence analysis
|
||||
///
|
||||
/// Formula:
|
||||
/// ROC = ((Price - PriceN) / PriceN) * 100
|
||||
/// where PriceN is the price N periods ago
|
||||
///
|
||||
/// Sources:
|
||||
/// Technical Analysis of Financial Markets by John J. Murphy
|
||||
/// Technical Analysis of Stock Trends by Robert D. Edwards and John Magee
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Roc : AbstractBase
|
||||
{
|
||||
private readonly CircularBuffer _priceBuffer;
|
||||
private const double ScalingFactor = 100.0;
|
||||
private const int DefaultPeriod = 12;
|
||||
|
||||
/// <param name="period">The lookback period for ROC calculation (default 12).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Roc(int period = DefaultPeriod)
|
||||
{
|
||||
if (period < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(period));
|
||||
|
||||
_priceBuffer = new(period + 1);
|
||||
WarmupPeriod = period;
|
||||
Name = $"ROC({period})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The lookback period for ROC calculation.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Roc(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
_priceBuffer.Add(Input.Value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
if (_priceBuffer.Count < _priceBuffer.Capacity)
|
||||
return 0.0;
|
||||
|
||||
double oldPrice = _priceBuffer[0];
|
||||
if (oldPrice <= double.Epsilon)
|
||||
return 0.0;
|
||||
|
||||
return ((Input.Value - oldPrice) / oldPrice) * ScalingFactor;
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// TRIX: Triple Exponential Average Rate of Change
|
||||
/// A momentum oscillator that shows the percentage rate of change of a triple exponentially
|
||||
/// smoothed moving average. TRIX filters out insignificant price movements and helps identify
|
||||
/// overbought/oversold conditions and divergences.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The TRIX calculation process:
|
||||
/// 1. Calculate Triple Exponential Moving Average (TEMA)
|
||||
/// 2. Calculate 1-day Rate of Change (ROC) of the TEMA
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Combines trend-following and momentum in one indicator
|
||||
/// - Filters out price movements deemed insignificant
|
||||
/// - Oscillates around zero line
|
||||
/// - Useful for identifying divergences
|
||||
/// - Helps spot overbought/oversold conditions
|
||||
///
|
||||
/// Formula:
|
||||
/// TEMA = 3*EMA1 - 3*EMA2 + EMA3
|
||||
/// TRIX = ROC(TEMA, 1) = ((TEMA - TEMA_prev) / TEMA_prev) * 100
|
||||
///
|
||||
/// Sources:
|
||||
/// Jack Hutson - "Technical Analysis of Stocks and Commodities" magazine, 1983
|
||||
/// John J. Murphy - "Technical Analysis of the Financial Markets"
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Trix : AbstractBase
|
||||
{
|
||||
private readonly Tema _tema;
|
||||
private readonly CircularBuffer _temaBuffer;
|
||||
private const double ScalingFactor = 100.0;
|
||||
private const int DefaultPeriod = 18;
|
||||
|
||||
/// <param name="period">The lookback period for TEMA calculation (default 18).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Trix(int period = DefaultPeriod)
|
||||
{
|
||||
if (period < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(period));
|
||||
|
||||
_tema = new(period);
|
||||
_temaBuffer = new(2); // We only need current and previous TEMA values
|
||||
WarmupPeriod = period + 1; // TEMA period + 1 for ROC
|
||||
Name = $"TRIX({period})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The lookback period for TEMA calculation.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Trix(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
double temaValue = _tema.Calc(Input);
|
||||
_temaBuffer.Add(temaValue);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
if (_temaBuffer.Count < _temaBuffer.Capacity)
|
||||
return 0.0;
|
||||
|
||||
double oldTema = _temaBuffer[0];
|
||||
if (oldTema <= double.Epsilon)
|
||||
return 0.0;
|
||||
|
||||
double currentTema = _temaBuffer[^1];
|
||||
return ((currentTema - oldTema) / oldTema) * ScalingFactor;
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Vel: Velocity
|
||||
/// An enhanced momentum indicator that applies Jurik Moving Average (JMA) smoothing
|
||||
/// to the basic momentum calculation, providing better noise reduction while
|
||||
/// maintaining responsiveness to significant price movements.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Velocity calculation process:
|
||||
/// 1. Calculate basic momentum (price difference)
|
||||
/// 2. Apply JMA smoothing to the momentum values
|
||||
/// 3. No scaling factor applied to maintain price-based units
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Enhanced momentum measurement with JMA smoothing
|
||||
/// - Better noise reduction than basic momentum
|
||||
/// - Maintains responsiveness to significant moves
|
||||
/// - Reduced lag through JMA's phase-shifting
|
||||
///
|
||||
/// Formula:
|
||||
/// Mom = Price - PriceN
|
||||
/// Vel = JMA(Mom, period)
|
||||
///
|
||||
/// Sources:
|
||||
/// Enhanced with JMA smoothing by Mark Jurik
|
||||
/// Technical Analysis of Financial Markets by John J. Murphy
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Vel : AbstractBase
|
||||
{
|
||||
private readonly CircularBuffer _priceBuffer;
|
||||
private readonly Jma _smoothing;
|
||||
private const int DefaultPeriod = 10;
|
||||
private const int DefaultPhase = 100;
|
||||
private const double DefaultFactor = 0.25;
|
||||
|
||||
/// <param name="period">The lookback period for velocity calculation (default 10).</param>
|
||||
/// <param name="phase">The phase for the JMA smoothing (default 0).</param>
|
||||
/// <param name="power">The power factor for the JMA smoothing (default 2.0).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vel(int period = DefaultPeriod, int phase = DefaultPhase, double factor = DefaultFactor)
|
||||
{
|
||||
if (period < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(period));
|
||||
|
||||
_priceBuffer = new(period + 1);
|
||||
_smoothing = new(period, phase, factor);
|
||||
WarmupPeriod = period * 2; // JMA needs more warmup periods
|
||||
Name = $"VEL({period})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The lookback period for velocity calculation.</param>
|
||||
/// <param name="phase">The phase for the JMA smoothing.</param>
|
||||
/// <param name="power">The power factor for the JMA smoothing.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vel(object source, int period, int phase = DefaultPhase, double power = DefaultFactor)
|
||||
: this(period, phase, power)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
_priceBuffer.Add(Input.Value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
if (_priceBuffer.Count < _priceBuffer.Capacity)
|
||||
return 0.0;
|
||||
|
||||
// Calculate basic momentum
|
||||
double momentum = Input.Value - _priceBuffer[0];
|
||||
|
||||
// Apply JMA smoothing
|
||||
return _smoothing.Calc(momentum, Input.IsNew);
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// VORTEX: Vortex Indicator
|
||||
/// A technical indicator consisting of two oscillating lines that identify trend reversals
|
||||
/// and confirm current trends based on the highs and lows of the previous period.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Vortex calculation process:
|
||||
/// 1. Calculate True Range (TR):
|
||||
/// TR = max(High - Low, |High - Previous Close|, |Low - Previous Close|)
|
||||
/// 2. Calculate +VM (Positive Movement):
|
||||
/// +VM = |Current High - Previous Low|
|
||||
/// 3. Calculate -VM (Negative Movement):
|
||||
/// -VM = |Current Low - Previous High|
|
||||
/// 4. Calculate period sums:
|
||||
/// TR Period Sum = Sum(TR, period)
|
||||
/// +VM Period Sum = Sum(+VM, period)
|
||||
/// -VM Period Sum = Sum(-VM, period)
|
||||
/// 5. Calculate +VI and -VI:
|
||||
/// +VI = +VM Period Sum / TR Period Sum
|
||||
/// -VI = -VM Period Sum / TR Period Sum
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Two oscillating lines (+VI and -VI)
|
||||
/// - No upper or lower bounds
|
||||
/// - Default period is 14 days
|
||||
/// - Crossovers signal trend changes
|
||||
/// - Uses true range normalization
|
||||
///
|
||||
/// Formula:
|
||||
/// +VI = Sum(+VM, period) / Sum(TR, period)
|
||||
/// -VI = Sum(-VM, period) / Sum(TR, period)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend identification
|
||||
/// - Trend reversals
|
||||
/// - Trend confirmation
|
||||
/// - Trading signals
|
||||
/// - Market momentum
|
||||
///
|
||||
/// Sources:
|
||||
/// Etienne Botes and Douglas Siepman - Original development (2010)
|
||||
/// https://www.investopedia.com/terms/v/vortex-indicator-vi.asp
|
||||
///
|
||||
/// Note: When +VI crosses above -VI, it signals a potential uptrend, and vice versa
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Vortex : AbstractBase
|
||||
{
|
||||
private readonly CircularBuffer _tr;
|
||||
private readonly CircularBuffer _vmPlus;
|
||||
private readonly CircularBuffer _vmMinus;
|
||||
private double _prevHigh;
|
||||
private double _prevLow;
|
||||
private double _prevClose;
|
||||
public double _viPlus { get; set; }
|
||||
public double _viMinus { get; set; }
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vortex(int period = 14)
|
||||
{
|
||||
WarmupPeriod = period + 1; // Need one extra period for previous values
|
||||
Name = $"VORTEX({period})";
|
||||
_tr = new CircularBuffer(period);
|
||||
_vmPlus = new CircularBuffer(period);
|
||||
_vmMinus = new CircularBuffer(period);
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vortex(object source, int period = 14) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevHigh = 0;
|
||||
_prevLow = 0;
|
||||
_prevClose = 0;
|
||||
_viPlus = 0;
|
||||
_viMinus = 0;
|
||||
_tr.Clear();
|
||||
_vmPlus.Clear();
|
||||
_vmMinus.Clear();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_lastValidValue = Value;
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
// Skip first period to establish previous values
|
||||
if (_index == 1)
|
||||
{
|
||||
_prevHigh = BarInput.High;
|
||||
_prevLow = BarInput.Low;
|
||||
_prevClose = BarInput.Close;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate True Range
|
||||
double tr = Math.Max(BarInput.High - BarInput.Low,
|
||||
Math.Max(Math.Abs(BarInput.High - _prevClose),
|
||||
Math.Abs(BarInput.Low - _prevClose)));
|
||||
|
||||
// Calculate VM+ and VM-
|
||||
double vmPlus = Math.Abs(BarInput.High - _prevLow);
|
||||
double vmMinus = Math.Abs(BarInput.Low - _prevHigh);
|
||||
|
||||
// Add values to buffers
|
||||
_tr.Add(tr);
|
||||
_vmPlus.Add(vmPlus);
|
||||
_vmMinus.Add(vmMinus);
|
||||
|
||||
// Calculate VI+ and VI-
|
||||
double trSum = _tr.Sum();
|
||||
if (Math.Abs(trSum) > double.Epsilon)
|
||||
{
|
||||
_viPlus = _vmPlus.Sum() / trSum;
|
||||
_viMinus = _vmMinus.Sum() / trSum;
|
||||
}
|
||||
|
||||
// Store current values for next calculation
|
||||
_prevHigh = BarInput.High;
|
||||
_prevLow = BarInput.Low;
|
||||
_prevClose = BarInput.Close;
|
||||
|
||||
// Return the difference between VI+ and VI-
|
||||
double vortex = _viPlus - _viMinus;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return vortex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the positive Vortex line (VI+)
|
||||
/// </summary>
|
||||
public double ViPlus => _viPlus;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the negative Vortex line (VI-)
|
||||
/// </summary>
|
||||
public double ViMinus => _viMinus;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
# Momentum indicators
|
||||
|
||||
✔️ ADX - Average Directional Movement Index
|
||||
✔️ ADXR - Average Directional Movement Index Rating
|
||||
✔️ APO - Absolute Price Oscillator
|
||||
✔️ DMI - Directional Movement Index (DI+, DI-)
|
||||
✔️ DMX - Jurik Directional Movement Index
|
||||
✔️ DPO - Detrended Price Oscillator
|
||||
✔️ MACD - Moving Average Convergence/Divergence (MACD, Signal, Histogram)
|
||||
✔️ MOM - Momentum
|
||||
✔️ PMO - Price Momentum Oscillator
|
||||
✔️ PO - Price Oscillator
|
||||
✔️ PPO - Percentage Price Oscillator
|
||||
✔️ PRS - Price Relative Strength
|
||||
✔️ ROC - Rate of Change
|
||||
✔️ TSI - True Strength Index
|
||||
✔️ TRIX - 1-day ROC of TEMA
|
||||
✔️ VEL - Jurik Signal Velocity
|
||||
✔️ VORTEX - Vortex Indicator (VI+, VI-)
|
||||
Reference in New Issue
Block a user