mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-15 00:58:04 +00:00
first iteration
This commit is contained in:
@@ -1,112 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// ADL: Accumulation Distribution Line (Chaikin)
|
||||
/// A volume-based indicator that measures the cumulative flow of money into and out
|
||||
/// of a security. It assesses the relationship between price and volume to determine
|
||||
/// buying/selling pressure.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The ADL calculation process:
|
||||
/// 1. Calculates Money Flow Multiplier (MFM):
|
||||
/// MFM = ((Close - Low) - (High - Close)) / (High - Low)
|
||||
/// 2. Calculates Money Flow Volume (MFV):
|
||||
/// MFV = MFM × Volume
|
||||
/// 3. ADL is cumulative sum of MFV values
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Volume-weighted measure
|
||||
/// - Cumulative indicator
|
||||
/// - No upper/lower bounds
|
||||
/// - Trend confirmation tool
|
||||
/// - Divergence indicator
|
||||
///
|
||||
/// Formula:
|
||||
/// MFM = ((Close - Low) - (High - Close)) / (High - Low)
|
||||
/// MFV = MFM × Volume
|
||||
/// ADL = Previous ADL + MFV
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend confirmation
|
||||
/// - Volume analysis
|
||||
/// - Price/volume divergence
|
||||
/// - Support/resistance levels
|
||||
/// - Market participation
|
||||
///
|
||||
/// Sources:
|
||||
/// Marc Chaikin - Original development
|
||||
/// https://www.investopedia.com/terms/a/accumulationdistribution.asp
|
||||
///
|
||||
/// Note: Focuses on the relationship between price and volume
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Adl : AbstractBase
|
||||
{
|
||||
private double _cumulativeAdl;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Adl()
|
||||
{
|
||||
WarmupPeriod = 1;
|
||||
Name = "ADL";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Adl(object source) : this()
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_cumulativeAdl = 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_lastValidValue = Value;
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static double CalculateMoneyFlowMultiplier(double close, double high, double low)
|
||||
{
|
||||
double range = high - low;
|
||||
if (range > 0)
|
||||
{
|
||||
return ((close - low) - (high - close)) / range;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
// Calculate Money Flow Multiplier
|
||||
double mfm = CalculateMoneyFlowMultiplier(BarInput.Close, BarInput.High, BarInput.Low);
|
||||
|
||||
// Calculate Money Flow Volume
|
||||
double mfv = mfm * BarInput.Volume;
|
||||
|
||||
// Update cumulative ADL only for new bars
|
||||
if (BarInput.IsNew)
|
||||
{
|
||||
_cumulativeAdl += mfv;
|
||||
}
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return _cumulativeAdl;
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// ADOSC: Chaikin Accumulation/Distribution Oscillator
|
||||
/// A momentum indicator that measures the strength of accumulation/distribution by combining
|
||||
/// price and volume with moving averages. It helps identify potential trend reversals and
|
||||
/// buying/selling pressure.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The ADOSC calculation process:
|
||||
/// 1. Calculate ADL (Accumulation/Distribution Line)
|
||||
/// a. Money Flow Multiplier = ((Close - Low) - (High - Close)) / (High - Low)
|
||||
/// b. Money Flow Volume = MFM × Volume
|
||||
/// c. ADL = Previous ADL + MFV
|
||||
/// 2. Calculate two EMAs of ADL values
|
||||
/// 3. Subtract longer EMA from shorter EMA
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Volume-weighted measure
|
||||
/// - Oscillates around zero
|
||||
/// - Uses two different time periods
|
||||
/// - Default periods are 3 and 10 days
|
||||
/// - Shows momentum of money flow
|
||||
///
|
||||
/// Formula:
|
||||
/// MFM = ((Close - Low) - (High - Close)) / (High - Low)
|
||||
/// MFV = MFM × Volume
|
||||
/// ADL = Previous ADL + MFV
|
||||
/// ADOSC = EMA(ADL, shortPeriod) - EMA(ADL, longPeriod)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend confirmation
|
||||
/// - Divergence analysis
|
||||
/// - Volume/price relationship
|
||||
/// - Support/resistance levels
|
||||
/// - Market reversals
|
||||
///
|
||||
/// Sources:
|
||||
/// Marc Chaikin - Original development
|
||||
/// https://www.investopedia.com/terms/c/chaikinoscillator.asp
|
||||
///
|
||||
/// Note: Positive values indicate buying pressure, while negative values indicate selling pressure
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Adosc : AbstractBase
|
||||
{
|
||||
private readonly int _longPeriod;
|
||||
private double _cumulativeAdl;
|
||||
private double _shortEma;
|
||||
private double _longEma;
|
||||
private readonly double _shortAlpha;
|
||||
private readonly double _longAlpha;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Adosc(int shortPeriod = 3, int longPeriod = 10)
|
||||
{
|
||||
_longPeriod = longPeriod;
|
||||
WarmupPeriod = longPeriod; // Need longer period for EMA calculation
|
||||
Name = $"ADOSC({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 Adosc(object source, int shortPeriod = 3, int longPeriod = 10) : this(shortPeriod, longPeriod)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_cumulativeAdl = 0;
|
||||
_shortEma = 0;
|
||||
_longEma = 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_lastValidValue = Value;
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static double CalculateMoneyFlowMultiplier(double close, double high, double low)
|
||||
{
|
||||
double range = high - low;
|
||||
if (range > 0)
|
||||
{
|
||||
return ((close - low) - (high - close)) / range;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
// Calculate Money Flow Multiplier
|
||||
double mfm = CalculateMoneyFlowMultiplier(BarInput.Close, BarInput.High, BarInput.Low);
|
||||
|
||||
// Calculate Money Flow Volume
|
||||
double mfv = mfm * BarInput.Volume;
|
||||
|
||||
// Update cumulative ADL
|
||||
_cumulativeAdl += mfv;
|
||||
|
||||
// Calculate EMAs
|
||||
if (_index <= _longPeriod)
|
||||
{
|
||||
// Initialize EMAs
|
||||
_shortEma = _cumulativeAdl;
|
||||
_longEma = _cumulativeAdl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Update EMAs
|
||||
_shortEma = (_shortAlpha * _cumulativeAdl) + ((1 - _shortAlpha) * _shortEma);
|
||||
_longEma = (_longAlpha * _cumulativeAdl) + ((1 - _longAlpha) * _longEma);
|
||||
|
||||
// Calculate ADOSC
|
||||
double adosc = _shortEma - _longEma;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return adosc;
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// AOBV: Archer On-Balance Volume
|
||||
/// A modified version of the traditional On-Balance Volume (OBV) indicator that uses a more
|
||||
/// sophisticated method to determine buying and selling pressure. It considers both the
|
||||
/// closing price and the price range to provide a more nuanced view of volume flow.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The AOBV calculation process:
|
||||
/// 1. Determine price position within the day's range
|
||||
/// 2. Apply volume based on price position:
|
||||
/// - If close is in upper 1/3 of range: Add full volume
|
||||
/// - If close is in middle 1/3 of range: Add/subtract half volume
|
||||
/// - If close is in lower 1/3 of range: Subtract full volume
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Volume-weighted measure
|
||||
/// - Cumulative indicator
|
||||
/// - No upper/lower bounds
|
||||
/// - More nuanced than traditional OBV
|
||||
/// - Considers price position in range
|
||||
///
|
||||
/// Formula:
|
||||
/// Range = High - Low
|
||||
/// UpperThird = High - (Range / 3)
|
||||
/// LowerThird = Low + (Range / 3)
|
||||
/// If Close >= UpperThird:
|
||||
/// AOBV = Previous AOBV + Volume
|
||||
/// Else if Close <= LowerThird:
|
||||
/// AOBV = Previous AOBV - Volume
|
||||
/// Else:
|
||||
/// If Close > Previous Close:
|
||||
/// AOBV = Previous AOBV + (Volume / 2)
|
||||
/// Else:
|
||||
/// AOBV = Previous AOBV - (Volume / 2)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend confirmation
|
||||
/// - Volume analysis
|
||||
/// - Price/volume divergence
|
||||
/// - Support/resistance levels
|
||||
/// - Market participation
|
||||
///
|
||||
/// Sources:
|
||||
/// Steve Archer - Original development
|
||||
/// Technical Analysis of Stock Trends (Edwards, Magee)
|
||||
///
|
||||
/// Note: Provides a more detailed analysis of volume flow than traditional OBV
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Aobv : AbstractBase
|
||||
{
|
||||
private double _cumulativeAobv;
|
||||
private double _prevClose;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Aobv()
|
||||
{
|
||||
WarmupPeriod = 1;
|
||||
Name = "AOBV";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Aobv(object source) : this()
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_cumulativeAobv = 0;
|
||||
_prevClose = 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;
|
||||
}
|
||||
|
||||
double range = BarInput.High - BarInput.Low;
|
||||
if (range > 0)
|
||||
{
|
||||
double upperThird = BarInput.High - (range / 3);
|
||||
double lowerThird = BarInput.Low + (range / 3);
|
||||
|
||||
// Determine volume flow based on price position
|
||||
if (BarInput.Close >= upperThird)
|
||||
{
|
||||
_cumulativeAobv += BarInput.Volume;
|
||||
}
|
||||
else if (BarInput.Close <= lowerThird)
|
||||
{
|
||||
_cumulativeAobv -= BarInput.Volume;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In middle third, use half volume based on close comparison
|
||||
_cumulativeAobv += (BarInput.Close > _prevClose) ?
|
||||
(BarInput.Volume / 2) : -(BarInput.Volume / 2);
|
||||
}
|
||||
}
|
||||
|
||||
_prevClose = BarInput.Close;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return _cumulativeAobv;
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// CMF: Chaikin Money Flow
|
||||
/// A volume-weighted technical indicator that measures the amount of Money Flow Volume (MFV)
|
||||
/// over a specific period. Unlike ADL which is cumulative, CMF averages the Money Flow
|
||||
/// Volume over a specified period.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The CMF calculation process:
|
||||
/// 1. Calculates Money Flow Multiplier (MFM):
|
||||
/// MFM = ((Close - Low) - (High - Close)) / (High - Low)
|
||||
/// 2. Calculates Money Flow Volume (MFV):
|
||||
/// MFV = MFM × Volume
|
||||
/// 3. CMF = Sum(MFV) / Sum(Volume) over N periods
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Oscillator between -1 and +1
|
||||
/// - Volume-weighted measure
|
||||
/// - Non-cumulative indicator
|
||||
/// - Default period is 20 days
|
||||
///
|
||||
/// Formula:
|
||||
/// MFM = ((Close - Low) - (High - Close)) / (High - Low)
|
||||
/// MFV = MFM × Volume
|
||||
/// CMF = Sum(MFV over N periods) / Sum(Volume over N periods)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend confirmation
|
||||
/// - Volume analysis
|
||||
/// - Price/volume divergence
|
||||
/// - Support/resistance levels
|
||||
/// - Market participation
|
||||
///
|
||||
/// Sources:
|
||||
/// Marc Chaikin - Original development
|
||||
/// https://www.investopedia.com/terms/c/chaikinmoneyflow.asp
|
||||
///
|
||||
/// Note: Values above zero indicate buying pressure, while values below zero indicate selling pressure
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Cmf : AbstractBase
|
||||
{
|
||||
private readonly int _period;
|
||||
private readonly double[] _mfv;
|
||||
private readonly double[] _volume;
|
||||
private int _position;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Cmf(int period = 20)
|
||||
{
|
||||
_period = period;
|
||||
WarmupPeriod = period;
|
||||
Name = $"CMF({_period})";
|
||||
_mfv = new double[period];
|
||||
_volume = new double[period];
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Cmf(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();
|
||||
_position = 0;
|
||||
Array.Clear(_mfv, 0, _mfv.Length);
|
||||
Array.Clear(_volume, 0, _volume.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_lastValidValue = Value;
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static double CalculateMoneyFlowMultiplier(double close, double high, double low)
|
||||
{
|
||||
double range = high - low;
|
||||
if (range > 0)
|
||||
{
|
||||
return ((close - low) - (high - close)) / range;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
// Calculate Money Flow Multiplier
|
||||
double mfm = CalculateMoneyFlowMultiplier(BarInput.Close, BarInput.High, BarInput.Low);
|
||||
|
||||
// Calculate Money Flow Volume
|
||||
double currentMfv = mfm * BarInput.Volume;
|
||||
|
||||
// Update circular buffers
|
||||
_mfv[_position] = currentMfv;
|
||||
_volume[_position] = BarInput.Volume;
|
||||
_position = (_position + 1) % _period;
|
||||
|
||||
// Calculate CMF
|
||||
double sumMfv = 0;
|
||||
double sumVolume = 0;
|
||||
for (int i = 0; i < _period; i++)
|
||||
{
|
||||
sumMfv += _mfv[i];
|
||||
sumVolume += _volume[i];
|
||||
}
|
||||
|
||||
double cmf = Math.Abs(sumVolume) > double.Epsilon ? sumMfv / sumVolume : 0;
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return cmf;
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// EOM: Ease of Movement
|
||||
/// A volume-based technical indicator that relates price change to volume, showing the
|
||||
/// relationship between price change and volume. It emphasizes days where price changes
|
||||
/// are accomplished with minimal volume and minimizes days where large volume generates
|
||||
/// small price changes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The EOM calculation process:
|
||||
/// 1. Calculate the distance moved:
|
||||
/// Distance = ((High + Low)/2 - (Prior High + Prior Low)/2)
|
||||
/// 2. Calculate the Box Ratio:
|
||||
/// BoxRatio = Volume / (High - Low)
|
||||
/// 3. Calculate single-period EMV:
|
||||
/// EMV = Distance / BoxRatio
|
||||
/// 4. Smooth EMV using simple moving average (optional)
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Volume-weighted measure
|
||||
/// - Oscillates around zero
|
||||
/// - Shows ease of price movement
|
||||
/// - Default period is 14 days
|
||||
///
|
||||
/// Formula:
|
||||
/// Distance = ((H + L)/2 - (pH + pL)/2)
|
||||
/// BoxRatio = Volume / (High - Low)
|
||||
/// EMV = Distance / BoxRatio
|
||||
/// EOM = SMA(EMV, period)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend strength analysis
|
||||
/// - Volume/price relationship
|
||||
/// - Support/resistance breakouts
|
||||
/// - Market momentum
|
||||
/// - Divergence identification
|
||||
///
|
||||
/// Sources:
|
||||
/// Richard W. Arms Jr. - Original development
|
||||
/// https://www.investopedia.com/terms/e/easeofmovement.asp
|
||||
///
|
||||
/// Note: Positive values suggest prices are rising with light volume (bullish),
|
||||
/// while negative values suggest prices are falling with light volume (bearish)
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Eom : AbstractBase
|
||||
{
|
||||
private readonly int _period;
|
||||
private readonly double[] _emv;
|
||||
private int _position;
|
||||
private double _prevMidpoint;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Eom(int period = 14)
|
||||
{
|
||||
_period = period;
|
||||
WarmupPeriod = period + 1; // Need one extra period for previous midpoint
|
||||
Name = $"EOM({_period})";
|
||||
_emv = new double[period];
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Eom(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();
|
||||
_position = 0;
|
||||
_prevMidpoint = 0;
|
||||
Array.Clear(_emv, 0, _emv.Length);
|
||||
}
|
||||
|
||||
[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);
|
||||
|
||||
double midpoint = (BarInput.High + BarInput.Low) / 2;
|
||||
double boxRatio = BarInput.Volume / (BarInput.High - BarInput.Low + double.Epsilon); // Avoid division by zero
|
||||
|
||||
// Skip first period to establish previous midpoint
|
||||
if (_index == 1)
|
||||
{
|
||||
_prevMidpoint = midpoint;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate distance moved
|
||||
double distance = midpoint - _prevMidpoint;
|
||||
|
||||
// Calculate EMV for this period
|
||||
double emv = distance / boxRatio * 10000; // Multiply by 10000 to make values more readable
|
||||
|
||||
// Store in circular buffer
|
||||
_emv[_position] = emv;
|
||||
_position = (_position + 1) % _period;
|
||||
|
||||
// Calculate EOM (simple moving average of EMV)
|
||||
double sum = 0;
|
||||
for (int i = 0; i < _period; i++)
|
||||
{
|
||||
sum += _emv[i];
|
||||
}
|
||||
double eom = sum / _period;
|
||||
|
||||
// Store current midpoint for next calculation
|
||||
_prevMidpoint = midpoint;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return eom;
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// KVO: Klinger Volume Oscillator
|
||||
/// A volume-based technical indicator that compares volume to price movement to identify
|
||||
/// long-term trends and potential reversals. It helps determine the long-term money flow
|
||||
/// while remaining sensitive to short-term fluctuations.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The KVO calculation process:
|
||||
/// 1. Calculate Trend:
|
||||
/// Trend = Current DM > Previous DM ? +1 : -1
|
||||
/// 2. Calculate Volume Force (VF):
|
||||
/// VF = Volume * abs(ROC) * Trend * 100
|
||||
/// 3. Calculate two EMAs of VF and their difference:
|
||||
/// Signal = EMA(VF, shortPeriod) - EMA(VF, longPeriod)
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Volume-weighted measure
|
||||
/// - Oscillates around zero
|
||||
/// - Uses two different time periods
|
||||
/// - Default periods are 34 and 55 days
|
||||
/// - Shows volume force and price direction
|
||||
///
|
||||
/// Formula:
|
||||
/// DM = (H + L + C) / 3
|
||||
/// Trend = DM > Previous DM ? +1 : -1
|
||||
/// VF = Volume * abs(ROC) * Trend * 100
|
||||
/// KVO = EMA(VF, shortPeriod) - EMA(VF, longPeriod)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend confirmation
|
||||
/// - Divergence analysis
|
||||
/// - Volume/price relationship
|
||||
/// - Support/resistance levels
|
||||
/// - Market reversals
|
||||
///
|
||||
/// Sources:
|
||||
/// Stephen Klinger - Original development
|
||||
/// https://www.investopedia.com/terms/k/klingeroscillator.asp
|
||||
///
|
||||
/// Note: Positive values indicate buying pressure, while negative values indicate selling pressure
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Kvo : AbstractBase
|
||||
{
|
||||
private readonly int _longPeriod;
|
||||
private double _prevDm;
|
||||
private double _shortEma;
|
||||
private double _longEma;
|
||||
private readonly double _shortAlpha;
|
||||
private readonly double _longAlpha;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Kvo(int shortPeriod = 34, int longPeriod = 55)
|
||||
{
|
||||
_longPeriod = longPeriod;
|
||||
WarmupPeriod = longPeriod + 1; // Need one extra period for previous DM
|
||||
Name = $"KVO({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 Kvo(object source, int shortPeriod = 34, int longPeriod = 55) : this(shortPeriod, longPeriod)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevDm = 0;
|
||||
_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);
|
||||
|
||||
// Calculate Daily Mean
|
||||
double dm = (BarInput.High + BarInput.Low + BarInput.Close) / 3;
|
||||
|
||||
// Skip first period to establish previous DM
|
||||
if (_index == 1)
|
||||
{
|
||||
_prevDm = dm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate Trend
|
||||
int trend = dm > _prevDm ? 1 : -1;
|
||||
|
||||
// Calculate Rate of Change
|
||||
double roc = Math.Abs(dm - _prevDm) / _prevDm;
|
||||
|
||||
// Calculate Volume Force
|
||||
double vf = BarInput.Volume * roc * trend * 100;
|
||||
|
||||
// Calculate EMAs
|
||||
if (_index <= _longPeriod)
|
||||
{
|
||||
// Initialize EMAs
|
||||
_shortEma = vf;
|
||||
_longEma = vf;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update EMAs
|
||||
_shortEma = (_shortAlpha * vf) + ((1 - _shortAlpha) * _shortEma);
|
||||
_longEma = (_longAlpha * vf) + ((1 - _longAlpha) * _longEma);
|
||||
}
|
||||
|
||||
// Store current DM for next calculation
|
||||
_prevDm = dm;
|
||||
|
||||
// Calculate KVO
|
||||
double kvo = _shortEma - _longEma;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return kvo;
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// VF: Volume Force
|
||||
/// A volume-based indicator that measures the strength of volume relative to price
|
||||
/// movement. It helps identify whether volume is supporting or contradicting the
|
||||
/// current price trend.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The VF calculation process:
|
||||
/// 1. Calculate price change
|
||||
/// 2. Calculate volume force as volume * price change
|
||||
/// 3. Optionally smooth the result with EMA
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Volume-weighted measure
|
||||
/// - Trend strength indicator
|
||||
/// - No upper/lower bounds
|
||||
/// - Raw and smoothed versions
|
||||
/// - Divergence indicator
|
||||
///
|
||||
/// Formula:
|
||||
/// VF = Volume * (Close - Close[1])
|
||||
/// Smoothed VF = EMA(VF, period)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Volume analysis
|
||||
/// - Trend confirmation
|
||||
/// - Price/volume divergence
|
||||
/// - Market participation
|
||||
/// - Momentum confirmation
|
||||
///
|
||||
/// Note: Higher values indicate stronger volume force
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Vf : AbstractBase
|
||||
{
|
||||
private readonly Ema _ema;
|
||||
private double _prevClose;
|
||||
private double _p_prevClose;
|
||||
private const int DefaultPeriod = 13;
|
||||
|
||||
/// <param name="period">The smoothing period for EMA calculation (default 13).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vf(int period = DefaultPeriod)
|
||||
{
|
||||
if (period < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(period));
|
||||
|
||||
_ema = new(period);
|
||||
WarmupPeriod = period + 1;
|
||||
Name = $"VF({period})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The smoothing period for EMA calculation.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vf(object source, int period = DefaultPeriod) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_ema.Init();
|
||||
_prevClose = double.NaN;
|
||||
}
|
||||
|
||||
[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(BarInput.IsNew);
|
||||
|
||||
if (_index == 1)
|
||||
{
|
||||
_prevClose = BarInput.Close;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate raw volume force
|
||||
double priceChange = BarInput.Close - _prevClose;
|
||||
double volumeForce = BarInput.Volume * priceChange;
|
||||
|
||||
// Update previous close
|
||||
_prevClose = BarInput.Close;
|
||||
|
||||
// Apply EMA smoothing
|
||||
return _ema.Calc(volumeForce, BarInput.IsNew);
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// VP: Volume Profile
|
||||
/// A volume-based indicator that analyzes volume distribution across price levels.
|
||||
/// It helps identify significant price levels where most trading activity occurs.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The VP calculation process:
|
||||
/// 1. Track volume at each price level within a period
|
||||
/// 2. Calculate Point of Control (POC) - price with highest volume
|
||||
/// 3. Calculate Value Area (70% of total volume)
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Price level analysis
|
||||
/// - Volume distribution
|
||||
/// - Support/resistance identification
|
||||
/// - Trading activity concentration
|
||||
/// - Market structure analysis
|
||||
///
|
||||
/// Formula:
|
||||
/// VP = Σ Volume at each price level
|
||||
/// POC = Price level with max volume
|
||||
/// Value Area = Price range containing 70% of volume
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Support/resistance levels
|
||||
/// - Market structure analysis
|
||||
/// - Trading activity patterns
|
||||
/// - Price level significance
|
||||
/// - Volume concentration
|
||||
///
|
||||
/// Note: Returns Point of Control (price level with highest volume)
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Vp : AbstractBase
|
||||
{
|
||||
private readonly CircularBuffer _volumes;
|
||||
private readonly CircularBuffer _prices;
|
||||
private const int DefaultPeriod = 14;
|
||||
|
||||
/// <param name="period">The number of periods to analyze volume distribution (default 14).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vp(int period = DefaultPeriod)
|
||||
{
|
||||
if (period < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(period));
|
||||
|
||||
_volumes = new(period);
|
||||
_prices = new(period);
|
||||
WarmupPeriod = period;
|
||||
Name = $"VP({period})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of periods to analyze volume distribution.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vp(object source, int period = DefaultPeriod) : 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 | MethodImplOptions.AggressiveOptimization)]
|
||||
private static int FindMaxVolumeIndex(CircularBuffer volumes)
|
||||
{
|
||||
int maxIndex = 0;
|
||||
double maxVolume = volumes[0];
|
||||
|
||||
for (int i = 1; i < volumes.Count; i++)
|
||||
{
|
||||
if (volumes[i] > maxVolume)
|
||||
{
|
||||
maxVolume = volumes[i];
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
return maxIndex;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
// Store volume and price
|
||||
_volumes.Add(BarInput.Volume, BarInput.IsNew);
|
||||
_prices.Add(BarInput.Close, BarInput.IsNew);
|
||||
|
||||
// Find price level with highest volume (Point of Control)
|
||||
int pocIndex = FindMaxVolumeIndex(_volumes);
|
||||
return _prices[pocIndex];
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// VWAP: Volume Weighted Average Price
|
||||
/// A trading benchmark that shows the ratio of the value traded to total volume
|
||||
/// traded over a specific period. VWAP equals the dollar value of all trading
|
||||
/// periods divided by the total trading volume for the current day.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The VWAP calculation process:
|
||||
/// 1. Calculate typical price for each period
|
||||
/// 2. Multiply typical price by volume
|
||||
/// 3. Calculate cumulative values
|
||||
/// 4. Divide cumulative (price * volume) by cumulative volume
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Intraday trading benchmark
|
||||
/// - Volume-weighted measure
|
||||
/// - Institutional trading reference
|
||||
/// - Price momentum indicator
|
||||
/// - Trading efficiency measure
|
||||
///
|
||||
/// Formula:
|
||||
/// VWAP = Σ(Price * Volume) / ΣVolume
|
||||
/// where Price = (High + Low + Close)/3
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Best execution analysis
|
||||
/// - Trading algorithms
|
||||
/// - Price momentum
|
||||
/// - Market impact analysis
|
||||
/// - Order timing
|
||||
///
|
||||
/// Sources:
|
||||
/// https://www.investopedia.com/terms/v/vwap.asp
|
||||
///
|
||||
/// Note: Commonly used by institutional traders
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Vwap : AbstractBase
|
||||
{
|
||||
private double _cumulativeTPV; // Cumulative (Typical Price * Volume)
|
||||
private double _cumulativeVolume;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vwap()
|
||||
{
|
||||
WarmupPeriod = 1;
|
||||
Name = "VWAP";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vwap(object source) : this()
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_cumulativeTPV = 0;
|
||||
_cumulativeVolume = 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
_index++;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
// Update cumulative values only for new bars
|
||||
if (BarInput.IsNew)
|
||||
{
|
||||
_cumulativeTPV += BarInput.HLC3 * BarInput.Volume;
|
||||
_cumulativeVolume += BarInput.Volume;
|
||||
}
|
||||
|
||||
// Calculate VWAP
|
||||
return _cumulativeVolume > 0 ? _cumulativeTPV / _cumulativeVolume : BarInput.HLC3;
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// VWMA: Volume Weighted Moving Average
|
||||
/// A technical indicator that combines price and volume to show the average price
|
||||
/// weighted by volume over a period. It gives more weight to prices with higher
|
||||
/// volume, making it more responsive to high-volume price movements.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The VWMA calculation process:
|
||||
/// 1. Multiply price by volume for each period
|
||||
/// 2. Sum (price * volume) over the period
|
||||
/// 3. Sum volume over the period
|
||||
/// 4. Divide sums to get weighted average
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Volume-sensitive average
|
||||
/// - Trend indicator
|
||||
/// - Support/resistance levels
|
||||
/// - Price momentum
|
||||
/// - Volume emphasis
|
||||
///
|
||||
/// Formula:
|
||||
/// VWMA = Σ(Price * Volume) / ΣVolume
|
||||
/// where sums are taken over the specified period
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend identification
|
||||
/// - Support/resistance levels
|
||||
/// - Volume analysis
|
||||
/// - Price momentum
|
||||
/// - Trading signals
|
||||
///
|
||||
/// Note: More responsive to high-volume price movements
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Vwma : AbstractBase
|
||||
{
|
||||
private readonly CircularBuffer _priceVolume;
|
||||
private readonly CircularBuffer _volume;
|
||||
private const int DefaultPeriod = 20;
|
||||
|
||||
/// <param name="period">The number of periods for VWMA calculation (default 20).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vwma(int period = DefaultPeriod)
|
||||
{
|
||||
if (period < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(period));
|
||||
|
||||
_priceVolume = new(period);
|
||||
_volume = new(period);
|
||||
WarmupPeriod = period;
|
||||
Name = $"VWMA({period})";
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of periods for VWMA calculation.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vwma(object source, int period = DefaultPeriod) : 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 | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
// Calculate and store price * volume
|
||||
double priceVolume = BarInput.Close * BarInput.Volume;
|
||||
_priceVolume.Add(priceVolume, BarInput.IsNew);
|
||||
_volume.Add(BarInput.Volume, BarInput.IsNew);
|
||||
|
||||
// Calculate sums
|
||||
double sumPriceVolume = _priceVolume.Sum();
|
||||
double sumVolume = _volume.Sum();
|
||||
|
||||
// Calculate VWMA
|
||||
return sumVolume > 0 ? sumPriceVolume / sumVolume : BarInput.Close;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
# Volume indicators
|
||||
Done: 19, Todo: 0
|
||||
|
||||
✔️ ADL - Chaikin Accumulation Distribution Line
|
||||
✔️ ADOSC - Chaikin Accumulation Distribution Oscillator
|
||||
✔️ AOBV - Archer On-Balance Volume
|
||||
✔️ 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
|
||||
✔️ VF - Volume Force
|
||||
✔️ VP - Volume Profile
|
||||
✔️ VWAP - Volume Weighted Average Price
|
||||
✔️ VWMA - Volume Weighted Moving Average
|
||||
Reference in New Issue
Block a user