mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-15 00:58:04 +00:00
feat: Dpo, Tsi, Vortex, Bpp, Cci, Cfo, Tr, Ui, Vc, Vov, Vr, Vs, Mfi, Nvi, Obv, Pvi, Pvo, Pvol, Pvr, Pvt, Tvi
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// MFI: Money Flow Index
|
||||
/// A volume-weighted momentum indicator that measures the inflow and outflow of money into an asset
|
||||
/// over a specific period of time. It's sometimes referred to as volume-weighted RSI.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The MFI calculation process:
|
||||
/// 1. Calculate Typical Price:
|
||||
/// TP = (High + Low + Close) / 3
|
||||
/// 2. Calculate Raw Money Flow:
|
||||
/// RMF = TP * Volume
|
||||
/// 3. Determine Positive/Negative Money Flow:
|
||||
/// If TP > Previous TP: Positive Money Flow
|
||||
/// If TP < Previous TP: Negative Money Flow
|
||||
/// 4. Calculate Money Flow Ratio:
|
||||
/// MFR = (14-period Positive Money Flow Sum) / (14-period Negative Money Flow Sum)
|
||||
/// 5. Calculate Money Flow Index:
|
||||
/// MFI = 100 - (100 / (1 + MFR))
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Oscillates between 0 and 100
|
||||
/// - Default period is 14 days
|
||||
/// - Overbought level typically at 80
|
||||
/// - Oversold level typically at 20
|
||||
/// - Volume-weighted measure
|
||||
///
|
||||
/// Formula:
|
||||
/// TP = (High + Low + Close) / 3
|
||||
/// RMF = TP * Volume
|
||||
/// MFR = ΣPositive Money Flow / ΣNegative Money Flow
|
||||
/// MFI = 100 - (100 / (1 + MFR))
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Overbought/Oversold conditions
|
||||
/// - Divergence analysis
|
||||
/// - Trend confirmation
|
||||
/// - Price reversals
|
||||
/// - Volume flow analysis
|
||||
///
|
||||
/// Sources:
|
||||
/// Gene Quong and Avrum Soudack - Original development
|
||||
/// https://www.investopedia.com/terms/m/mfi.asp
|
||||
///
|
||||
/// Note: Values above 80 indicate overbought conditions, while values below 20 indicate oversold conditions
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Mfi : AbstractBase
|
||||
{
|
||||
private readonly CircularBuffer _posMf;
|
||||
private readonly CircularBuffer _negMf;
|
||||
private double _prevTp;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Mfi(int period = 14)
|
||||
{
|
||||
WarmupPeriod = period + 1; // Need one extra period for previous TP
|
||||
Name = $"MFI({period})";
|
||||
_posMf = new CircularBuffer(period);
|
||||
_negMf = new CircularBuffer(period);
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Mfi(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();
|
||||
_prevTp = 0;
|
||||
_posMf.Clear();
|
||||
_negMf.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);
|
||||
|
||||
// Calculate Typical Price
|
||||
double tp = (BarInput.High + BarInput.Low + BarInput.Close) / 3;
|
||||
|
||||
// Skip first period to establish previous TP
|
||||
if (_index == 1)
|
||||
{
|
||||
_prevTp = tp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate Raw Money Flow
|
||||
double rmf = tp * BarInput.Volume;
|
||||
|
||||
// Determine Positive/Negative Money Flow
|
||||
if (tp > _prevTp)
|
||||
{
|
||||
_posMf.Add(rmf);
|
||||
_negMf.Add(0);
|
||||
}
|
||||
else if (tp < _prevTp)
|
||||
{
|
||||
_posMf.Add(0);
|
||||
_negMf.Add(rmf);
|
||||
}
|
||||
else
|
||||
{
|
||||
_posMf.Add(0);
|
||||
_negMf.Add(0);
|
||||
}
|
||||
|
||||
// Store current TP for next calculation
|
||||
_prevTp = tp;
|
||||
|
||||
// Calculate Money Flow Ratio and Index
|
||||
double posMfSum = _posMf.Sum();
|
||||
double negMfSum = _negMf.Sum();
|
||||
|
||||
double mfi = Math.Abs(negMfSum) < double.Epsilon ? 100 : 100 - (100 / (1 + (posMfSum / negMfSum)));
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return mfi;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// NVI: Negative Volume Index
|
||||
/// A cumulative indicator that focuses on days when volume decreases from the previous day.
|
||||
/// It is based on the premise that smart money is active on days with lower volume.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The NVI calculation process:
|
||||
/// 1. Compare current volume with previous volume
|
||||
/// 2. If current volume is less than previous volume:
|
||||
/// NVI = Previous NVI + (((Close - Previous Close) / Previous Close) * Previous NVI)
|
||||
/// 3. If current volume is greater than or equal to previous volume:
|
||||
/// NVI = Previous NVI
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Cumulative indicator
|
||||
/// - Only updates on lower volume days
|
||||
/// - Starts at base value of 1000
|
||||
/// - Focuses on smart money activity
|
||||
/// - Volume-driven measure
|
||||
///
|
||||
/// Formula:
|
||||
/// If Volume < Previous Volume:
|
||||
/// NVI = Previous NVI + (Price % Change * Previous NVI)
|
||||
/// Else:
|
||||
/// NVI = Previous NVI
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Smart money tracking
|
||||
/// - Trend identification
|
||||
/// - Market timing
|
||||
/// - Volume analysis
|
||||
/// - Price confirmation
|
||||
///
|
||||
/// Sources:
|
||||
/// Paul Dysart - Original development (1930s)
|
||||
/// Norman Fosback - Further development
|
||||
/// https://www.investopedia.com/terms/n/nvi.asp
|
||||
///
|
||||
/// Note: Rising NVI suggests smart money is buying, while falling NVI suggests smart money is selling
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Nvi : AbstractBase
|
||||
{
|
||||
private double _prevClose;
|
||||
private double _prevVolume;
|
||||
private double _prevNvi;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Nvi()
|
||||
{
|
||||
WarmupPeriod = 2; // Need previous volume and close
|
||||
Name = "NVI";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Nvi(object source) : this()
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevClose = 0;
|
||||
_prevVolume = 0;
|
||||
_prevNvi = 1000; // Standard starting value
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
_prevClose = BarInput.Close;
|
||||
_prevVolume = BarInput.Volume;
|
||||
return _prevNvi;
|
||||
}
|
||||
|
||||
// Calculate NVI
|
||||
if (BarInput.Volume < _prevVolume)
|
||||
{
|
||||
double priceChange = ((BarInput.Close - _prevClose) / _prevClose);
|
||||
_prevNvi += priceChange * _prevNvi;
|
||||
}
|
||||
|
||||
// Store current values for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
_prevVolume = BarInput.Volume;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return _prevNvi;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// OBV: On-Balance Volume
|
||||
/// A momentum indicator that uses volume flow to predict changes in stock price.
|
||||
/// It accumulates volume on up days and subtracts volume on down days.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The OBV calculation process:
|
||||
/// 1. Compare current close with previous close
|
||||
/// 2. If current close is higher:
|
||||
/// OBV = Previous OBV + Current Volume
|
||||
/// 3. If current close is lower:
|
||||
/// OBV = Previous OBV - Current Volume
|
||||
/// 4. If current close equals previous close:
|
||||
/// OBV = Previous OBV
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Cumulative indicator
|
||||
/// - Volume-based momentum measure
|
||||
/// - Leading indicator
|
||||
/// - No upper or lower bounds
|
||||
/// - Focuses on volume flow
|
||||
///
|
||||
/// Formula:
|
||||
/// If Close > Previous Close:
|
||||
/// OBV = Previous OBV + Volume
|
||||
/// If Close < Previous Close:
|
||||
/// OBV = Previous OBV - Volume
|
||||
/// If Close = Previous Close:
|
||||
/// OBV = Previous OBV
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend confirmation
|
||||
/// - Potential breakouts
|
||||
/// - Divergence analysis
|
||||
/// - Volume flow analysis
|
||||
/// - Price movement prediction
|
||||
///
|
||||
/// Sources:
|
||||
/// Joe Granville - Original development (1963)
|
||||
/// https://www.investopedia.com/terms/o/onbalancevolume.asp
|
||||
///
|
||||
/// Note: Rising OBV suggests buying pressure, while falling OBV suggests selling pressure
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Obv : AbstractBase
|
||||
{
|
||||
private double _prevClose;
|
||||
private double _prevObv;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Obv()
|
||||
{
|
||||
WarmupPeriod = 2; // Need previous close
|
||||
Name = "OBV";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Obv(object source) : this()
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevClose = 0;
|
||||
_prevObv = 0;
|
||||
}
|
||||
|
||||
[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 close
|
||||
if (_index == 1)
|
||||
{
|
||||
_prevClose = BarInput.Close;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate OBV
|
||||
if (BarInput.Close > _prevClose)
|
||||
{
|
||||
_prevObv += BarInput.Volume;
|
||||
}
|
||||
else if (BarInput.Close < _prevClose)
|
||||
{
|
||||
_prevObv -= BarInput.Volume;
|
||||
}
|
||||
// If prices equal, OBV remains the same
|
||||
|
||||
// Store current close for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return _prevObv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// PVI: Positive Volume Index
|
||||
/// A cumulative indicator that focuses on days when volume increases from the previous day.
|
||||
/// It is based on the premise that the public is active on days with higher volume.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The PVI calculation process:
|
||||
/// 1. Compare current volume with previous volume
|
||||
/// 2. If current volume is greater than previous volume:
|
||||
/// PVI = Previous PVI + (((Close - Previous Close) / Previous Close) * Previous PVI)
|
||||
/// 3. If current volume is less than or equal to previous volume:
|
||||
/// PVI = Previous PVI
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Cumulative indicator
|
||||
/// - Only updates on higher volume days
|
||||
/// - Starts at base value of 1000
|
||||
/// - Focuses on public activity
|
||||
/// - Volume-driven measure
|
||||
///
|
||||
/// Formula:
|
||||
/// If Volume > Previous Volume:
|
||||
/// PVI = Previous PVI + (Price % Change * Previous PVI)
|
||||
/// Else:
|
||||
/// PVI = Previous PVI
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Public participation tracking
|
||||
/// - Trend identification
|
||||
/// - Market timing
|
||||
/// - Volume analysis
|
||||
/// - Price confirmation
|
||||
///
|
||||
/// Sources:
|
||||
/// Norman Fosback - Original development
|
||||
/// https://www.investopedia.com/terms/p/pvi.asp
|
||||
///
|
||||
/// Note: Rising PVI suggests public buying pressure, while falling PVI suggests public selling pressure
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Pvi : AbstractBase
|
||||
{
|
||||
private double _prevClose;
|
||||
private double _prevVolume;
|
||||
private double _prevPvi;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pvi()
|
||||
{
|
||||
WarmupPeriod = 2; // Need previous volume and close
|
||||
Name = "PVI";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pvi(object source) : this()
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevClose = 0;
|
||||
_prevVolume = 0;
|
||||
_prevPvi = 1000; // Standard starting value
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
_prevClose = BarInput.Close;
|
||||
_prevVolume = BarInput.Volume;
|
||||
return _prevPvi;
|
||||
}
|
||||
|
||||
// Calculate PVI
|
||||
if (BarInput.Volume > _prevVolume)
|
||||
{
|
||||
double priceChange = ((BarInput.Close - _prevClose) / _prevClose);
|
||||
_prevPvi += priceChange * _prevPvi;
|
||||
}
|
||||
|
||||
// Store current values for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
_prevVolume = BarInput.Volume;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return _prevPvi;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// PVO: Percentage Volume Oscillator
|
||||
/// A momentum indicator for volume that shows the relationship between two volume moving averages
|
||||
/// as a percentage. Similar to the Price Oscillator but uses volume instead of price.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The PVO calculation process:
|
||||
/// 1. Calculate short-term EMA of volume
|
||||
/// 2. Calculate long-term EMA of volume
|
||||
/// 3. Calculate PVO:
|
||||
/// PVO = ((Short EMA - Long EMA) / Long EMA) * 100
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Volume-based momentum indicator
|
||||
/// - Oscillates around zero
|
||||
/// - Shows volume trends
|
||||
/// - Default periods are 12 and 26 days
|
||||
/// - Percentage-based measure
|
||||
///
|
||||
/// Formula:
|
||||
/// Short EMA = EMA(Volume, shortPeriod)
|
||||
/// Long EMA = EMA(Volume, longPeriod)
|
||||
/// PVO = ((Short EMA - Long EMA) / Long EMA) * 100
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Volume trend analysis
|
||||
/// - Divergence identification
|
||||
/// - Volume momentum measurement
|
||||
/// - Market tops and bottoms
|
||||
/// - Trading volume patterns
|
||||
///
|
||||
/// Sources:
|
||||
/// https://www.investopedia.com/terms/p/pvo.asp
|
||||
///
|
||||
/// Note: Positive values indicate higher short-term volume, while negative values indicate higher long-term volume
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Pvo : AbstractBase
|
||||
{
|
||||
private readonly int _longPeriod;
|
||||
private double _shortEma;
|
||||
private double _longEma;
|
||||
private readonly double _shortAlpha;
|
||||
private readonly double _longAlpha;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pvo(int shortPeriod = 12, int longPeriod = 26)
|
||||
{
|
||||
_longPeriod = longPeriod;
|
||||
WarmupPeriod = longPeriod;
|
||||
Name = $"PVO({shortPeriod},{_longPeriod})";
|
||||
_shortAlpha = 2.0 / (shortPeriod + 1);
|
||||
_longAlpha = 2.0 / (longPeriod + 1);
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pvo(object source, int shortPeriod = 12, int longPeriod = 26) : this(shortPeriod, longPeriod)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_shortEma = 0;
|
||||
_longEma = 0;
|
||||
}
|
||||
|
||||
[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);
|
||||
|
||||
// Initialize or update EMAs
|
||||
if (_index <= _longPeriod)
|
||||
{
|
||||
_shortEma = BarInput.Volume;
|
||||
_longEma = BarInput.Volume;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Update EMAs
|
||||
_shortEma = (_shortAlpha * BarInput.Volume) + ((1 - _shortAlpha) * _shortEma);
|
||||
_longEma = (_longAlpha * BarInput.Volume) + ((1 - _longAlpha) * _longEma);
|
||||
|
||||
// Calculate PVO
|
||||
|
||||
double pvo = Math.Abs(_longEma) >= double.Epsilon ? ((_shortEma - _longEma) / _longEma) * 100 : 0;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return pvo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// PVOL: Price-Volume
|
||||
/// A technical indicator that measures the relationship between price and volume changes,
|
||||
/// helping to identify the strength of price movements.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The PVOL calculation process:
|
||||
/// 1. Calculate price change:
|
||||
/// Price Change = (Close - Previous Close) / Previous Close
|
||||
/// 2. Calculate volume change:
|
||||
/// Volume Change = (Volume - Previous Volume) / Previous Volume
|
||||
/// 3. Calculate PVOL:
|
||||
/// PVOL = Price Change * Volume Change * 100
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Measures price-volume relationship
|
||||
/// - Oscillates around zero
|
||||
/// - Shows momentum strength
|
||||
/// - Identifies volume-supported moves
|
||||
/// - No specific boundaries
|
||||
///
|
||||
/// Formula:
|
||||
/// Price Change = (Close - Previous Close) / Previous Close
|
||||
/// Volume Change = (Volume - Previous Volume) / Previous Volume
|
||||
/// PVOL = Price Change * Volume Change * 100
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Price movement confirmation
|
||||
/// - Volume analysis
|
||||
/// - Trend strength assessment
|
||||
/// - Divergence identification
|
||||
/// - Market momentum analysis
|
||||
///
|
||||
/// Note: High positive values indicate strong upward momentum with volume support,
|
||||
/// while high negative values indicate strong downward momentum with volume support
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Pvol : AbstractBase
|
||||
{
|
||||
private double _prevClose;
|
||||
private double _prevVolume;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pvol()
|
||||
{
|
||||
WarmupPeriod = 2; // Need previous close and volume
|
||||
Name = "PVOL";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pvol(object source) : this()
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevClose = 0;
|
||||
_prevVolume = 0;
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
_prevClose = BarInput.Close;
|
||||
_prevVolume = BarInput.Volume;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate price and volume changes
|
||||
double priceChange = (Math.Abs(_prevClose) >= double.Epsilon) ? (BarInput.Close - _prevClose) / _prevClose : 0;
|
||||
double volumeChange = (Math.Abs(_prevVolume) >= double.Epsilon) ? (BarInput.Volume - _prevVolume) / _prevVolume : 0;
|
||||
|
||||
// Store current values for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
_prevVolume = BarInput.Volume;
|
||||
|
||||
// Calculate PVOL
|
||||
double pvol = priceChange * volumeChange * 100;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return pvol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// PVR: Price Volume Rank
|
||||
/// A technical indicator that ranks price and volume movements to identify
|
||||
/// significant market moves based on their combined strength.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The PVR calculation process:
|
||||
/// 1. Calculate price change percentage:
|
||||
/// Price Change = ((Close - Previous Close) / Previous Close) * 100
|
||||
/// 2. Calculate volume ratio:
|
||||
/// Volume Ratio = Current Volume / Previous Volume
|
||||
/// 3. Calculate PVR:
|
||||
/// PVR = Price Change * Volume Ratio
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Combines price and volume analysis
|
||||
/// - No specific boundaries
|
||||
/// - Measures movement significance
|
||||
/// - Volume-weighted price change
|
||||
/// - Identifies strong moves
|
||||
///
|
||||
/// Formula:
|
||||
/// Price Change = ((Close - Previous Close) / Previous Close) * 100
|
||||
/// Volume Ratio = Volume / Previous Volume
|
||||
/// PVR = Price Change * Volume Ratio
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Significant move identification
|
||||
/// - Volume-supported moves
|
||||
/// - Trend strength analysis
|
||||
/// - Breakout confirmation
|
||||
/// - Market momentum measurement
|
||||
///
|
||||
/// Note: Higher absolute values indicate more significant price moves with volume support
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Pvr : AbstractBase
|
||||
{
|
||||
private double _prevClose;
|
||||
private double _prevVolume;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pvr()
|
||||
{
|
||||
WarmupPeriod = 2; // Need previous close and volume
|
||||
Name = "PVR";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pvr(object source) : this()
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevClose = 0;
|
||||
_prevVolume = 0;
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
_prevClose = BarInput.Close;
|
||||
_prevVolume = BarInput.Volume;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate price change percentage
|
||||
double priceChange = (Math.Abs(_prevClose) > double.Epsilon) ? ((BarInput.Close - _prevClose) / _prevClose) * 100 : 0;
|
||||
|
||||
// Calculate volume ratio
|
||||
double volumeRatio = (Math.Abs(_prevVolume) > double.Epsilon) ? BarInput.Volume / _prevVolume : 1;
|
||||
|
||||
// Store current values for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
_prevVolume = BarInput.Volume;
|
||||
|
||||
// Calculate PVR
|
||||
double pvr = priceChange * volumeRatio;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return pvr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// PVT: Price Volume Trend
|
||||
/// A momentum indicator that combines price and volume to determine the strength of a trend.
|
||||
/// Similar to OBV but uses percentage price changes in its calculation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The PVT calculation process:
|
||||
/// 1. Calculate price change percentage:
|
||||
/// Price Change = (Close - Previous Close) / Previous Close
|
||||
/// 2. Calculate PVT:
|
||||
/// PVT = Previous PVT + (Price Change * Volume)
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Cumulative indicator
|
||||
/// - Volume-weighted price changes
|
||||
/// - No upper or lower bounds
|
||||
/// - Trend strength measure
|
||||
/// - More sensitive than OBV
|
||||
///
|
||||
/// Formula:
|
||||
/// Price Change = (Close - Previous Close) / Previous Close
|
||||
/// PVT = Previous PVT + (Price Change * Volume)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend confirmation
|
||||
/// - Divergence analysis
|
||||
/// - Volume-price relationships
|
||||
/// - Support/resistance levels
|
||||
/// - Market momentum
|
||||
///
|
||||
/// Sources:
|
||||
/// Norman Fosback - Original development
|
||||
/// https://www.investopedia.com/terms/p/pvt.asp
|
||||
///
|
||||
/// Note: Rising PVT suggests buying pressure, while falling PVT suggests selling pressure
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Pvt : AbstractBase
|
||||
{
|
||||
private double _prevClose;
|
||||
private double _prevPvt;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pvt()
|
||||
{
|
||||
WarmupPeriod = 2; // Need previous close
|
||||
Name = "PVT";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Pvt(object source) : this()
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevClose = 0;
|
||||
_prevPvt = 0;
|
||||
}
|
||||
|
||||
[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 close
|
||||
if (_index == 1)
|
||||
{
|
||||
_prevClose = BarInput.Close;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate price change percentage
|
||||
double priceChange = (Math.Abs(_prevClose) > double.Epsilon) ? (BarInput.Close - _prevClose) / _prevClose : 0;
|
||||
|
||||
// Calculate PVT
|
||||
_prevPvt += priceChange * BarInput.Volume;
|
||||
|
||||
// Store current close for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return _prevPvt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// TVI: Trade Volume Index
|
||||
/// A technical indicator that determines whether a security is being accumulated or distributed
|
||||
/// based on price changes relative to a minimum tick value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The TVI calculation process:
|
||||
/// 1. Calculate price change:
|
||||
/// Price Change = Close - Previous Close
|
||||
/// 2. Compare price change to minimum tick value:
|
||||
/// If |Price Change| >= Minimum Tick:
|
||||
/// Add/Subtract volume based on price direction
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Volume-based trend indicator
|
||||
/// - Uses minimum tick value
|
||||
/// - Cumulative measure
|
||||
/// - No upper or lower bounds
|
||||
/// - Focuses on significant moves
|
||||
///
|
||||
/// Formula:
|
||||
/// If |Close - Previous Close| >= Minimum Tick:
|
||||
/// If Close > Previous Close:
|
||||
/// TVI = Previous TVI + Volume
|
||||
/// If Close < Previous Close:
|
||||
/// TVI = Previous TVI - Volume
|
||||
/// Else:
|
||||
/// TVI = Previous TVI
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend identification
|
||||
/// - Volume analysis
|
||||
/// - Accumulation/distribution
|
||||
/// - Price movement significance
|
||||
/// - Trading signal generation
|
||||
///
|
||||
/// Note: Rising TVI suggests accumulation, while falling TVI suggests distribution
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Tvi : AbstractBase
|
||||
{
|
||||
private readonly double _minTick;
|
||||
private double _prevClose;
|
||||
private double _prevTvi;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Tvi(double minTick = 0.5)
|
||||
{
|
||||
_minTick = minTick;
|
||||
WarmupPeriod = 2; // Need previous close
|
||||
Name = $"TVI({_minTick})";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Tvi(object source, double minTick = 0.5) : this(minTick)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevClose = 0;
|
||||
_prevTvi = 0;
|
||||
}
|
||||
|
||||
[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 close
|
||||
if (_index == 1)
|
||||
{
|
||||
_prevClose = BarInput.Close;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate price change
|
||||
double priceChange = BarInput.Close - _prevClose;
|
||||
|
||||
// Update TVI if price change exceeds minimum tick
|
||||
if (Math.Abs(priceChange) >= _minTick)
|
||||
{
|
||||
_prevTvi += priceChange > 0 ? BarInput.Volume : -BarInput.Volume;
|
||||
}
|
||||
|
||||
// Store current close for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return _prevTvi;
|
||||
}
|
||||
}
|
||||
+11
-10
@@ -1,5 +1,5 @@
|
||||
# Volume indicators
|
||||
Done: 6, Todo: 12
|
||||
Done: 15, Todo: 3
|
||||
|
||||
✔️ ADL - Chaikin Accumulation Distribution Line
|
||||
✔️ ADOSC - Chaikin Accumulation Distribution Oscillator
|
||||
@@ -7,15 +7,16 @@ Done: 6, Todo: 12
|
||||
✔️ CMF - Chaikin Money Flow
|
||||
✔️ EOM - Ease of Movement
|
||||
✔️ KVO - Klinger Volume Oscillator
|
||||
MFI - Money Flow Index
|
||||
NVI - Negative Volume Index
|
||||
OBV - On-Balance Volume
|
||||
PVI - Positive Volume Index
|
||||
PVOL - Price-Volume
|
||||
PVO - Percentage Volume Oscillator
|
||||
PVR - Price Volume Rank
|
||||
PVT - Price Volume Trend
|
||||
TVI - Trade Volume Index
|
||||
✔️ MFI - Money Flow Index
|
||||
✔️ NVI - Negative Volume Index
|
||||
✔️ OBV - On-Balance Volume
|
||||
✔️ PVI - Positive Volume Index
|
||||
✔️ PVOL - Price-Volume
|
||||
✔️ PVO - Percentage Volume Oscillator
|
||||
✔️ PVR - Price Volume Rank
|
||||
✔️ PVT - Price Volume Trend
|
||||
✔️ TVI - Trade Volume Index
|
||||
VF - Volume Force
|
||||
VP - Volume Profile
|
||||
VWAP - Volume Weighted Average Price
|
||||
VWMA - Volume Weighted Moving Average
|
||||
|
||||
Reference in New Issue
Block a user