mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-13 08:08:05 +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,102 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// TR: True Range
|
||||
/// A basic volatility measure that represents the greatest of three price ranges:
|
||||
/// current high-low, current high-previous close, or current low-previous close.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The TR calculation process:
|
||||
/// 1. Calculate three differences:
|
||||
/// - Current High minus Current Low
|
||||
/// - |Current High minus Previous Close|
|
||||
/// - |Current Low minus Previous Close|
|
||||
/// 2. TR is the maximum of these three values
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Basic volatility measure
|
||||
/// - Accounts for gaps between trading periods
|
||||
/// - Foundation for other indicators (ATR, etc.)
|
||||
/// - No upper bound
|
||||
/// - Always positive
|
||||
///
|
||||
/// Formula:
|
||||
/// TR = max(High - Low, |High - Previous Close|, |Low - Previous Close|)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Volatility measurement
|
||||
/// - Stop loss placement
|
||||
/// - Position sizing
|
||||
/// - Market analysis
|
||||
/// - Risk assessment
|
||||
///
|
||||
/// Sources:
|
||||
/// J. Welles Wilder Jr. - Original development
|
||||
/// https://www.investopedia.com/terms/t/truerange.asp
|
||||
///
|
||||
/// Note: True Range accounts for gaps between periods, making it more accurate than simple high-low range
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Tr : AbstractBase
|
||||
{
|
||||
private double _prevClose;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Tr()
|
||||
{
|
||||
WarmupPeriod = 2; // Need previous close
|
||||
Name = "TR";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Tr(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;
|
||||
}
|
||||
|
||||
[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 BarInput.High - BarInput.Low;
|
||||
}
|
||||
|
||||
// Calculate True Range
|
||||
double tr = Math.Max(BarInput.High - BarInput.Low,
|
||||
Math.Max(Math.Abs(BarInput.High - _prevClose),
|
||||
Math.Abs(BarInput.Low - _prevClose)));
|
||||
|
||||
// Store current close for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return tr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// UI: Ulcer Index
|
||||
/// A technical indicator that measures downside risk by incorporating both
|
||||
/// the depth and duration of price declines over a given period.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The UI calculation process:
|
||||
/// 1. Calculate percentage drawdown from recent high for each period
|
||||
/// 2. Square the drawdowns to emphasize larger declines
|
||||
/// 3. Calculate the average of squared drawdowns
|
||||
/// 4. Take the square root of the average
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Measures downside volatility
|
||||
/// - Emphasizes larger drawdowns
|
||||
/// - Default period is 14 days
|
||||
/// - Always positive
|
||||
/// - No upper bound
|
||||
///
|
||||
/// Formula:
|
||||
/// Drawdown = ((Close - 14-period High) / 14-period High) * 100
|
||||
/// UI = sqrt(sum(Drawdown^2) / period)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Risk assessment
|
||||
/// - Portfolio analysis
|
||||
/// - Trading system evaluation
|
||||
/// - Market timing
|
||||
/// - Trend strength measurement
|
||||
///
|
||||
/// Sources:
|
||||
/// Peter Martin - Original development (1987)
|
||||
/// https://www.investopedia.com/terms/u/ulcerindex.asp
|
||||
///
|
||||
/// Note: Higher values indicate higher risk due to deeper or more frequent drawdowns
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Ui : AbstractBase
|
||||
{
|
||||
private readonly int _period;
|
||||
private readonly CircularBuffer _prices;
|
||||
private readonly CircularBuffer _drawdowns;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Ui(int period = 14)
|
||||
{
|
||||
_period = period;
|
||||
WarmupPeriod = period;
|
||||
Name = $"UI({_period})";
|
||||
_prices = new CircularBuffer(period);
|
||||
_drawdowns = new CircularBuffer(period);
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Ui(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();
|
||||
_prices.Clear();
|
||||
_drawdowns.Clear();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_lastValidValue = Value;
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
// Add current price to buffer
|
||||
_prices.Add(BarInput.Close);
|
||||
|
||||
// Need enough prices for calculation
|
||||
if (_index <= _period)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate maximum price in period
|
||||
double maxPrice = _prices.Max();
|
||||
|
||||
// Calculate percentage drawdown
|
||||
double drawdown = Math.Abs(maxPrice) > double.Epsilon ? ((BarInput.Close - maxPrice) / maxPrice) * 100 : 0;
|
||||
|
||||
// Add squared drawdown to buffer
|
||||
_drawdowns.Add(drawdown * drawdown);
|
||||
|
||||
// Calculate Ulcer Index
|
||||
double ui = Math.Sqrt(_drawdowns.Average());
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return ui;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// VC: Volatility Cone
|
||||
/// A technical indicator that analyzes volatility across different time periods
|
||||
/// to identify normal ranges and extreme values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The VC calculation process:
|
||||
/// 1. Calculate volatility for the specified period
|
||||
/// 2. Track mean and standard deviation of volatility
|
||||
/// 3. Calculate upper and lower bounds:
|
||||
/// Upper = Mean + (deviations * StdDev)
|
||||
/// Lower = Mean - (deviations * StdDev)
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Multi-period volatility analysis
|
||||
/// - Statistical approach
|
||||
/// - Default period is 20 days
|
||||
/// - Returns mean and bounds
|
||||
/// - Adaptive to market conditions
|
||||
///
|
||||
/// Formula:
|
||||
/// Volatility = StdDev(Returns) * sqrt(252) // Annualized
|
||||
/// Upper = Mean(Volatility) + (deviations * StdDev(Volatility))
|
||||
/// Lower = Mean(Volatility) - (deviations * StdDev(Volatility))
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Options trading
|
||||
/// - Risk assessment
|
||||
/// - Volatility forecasting
|
||||
/// - Trading strategy development
|
||||
/// - Market regime analysis
|
||||
///
|
||||
/// Sources:
|
||||
/// https://www.investopedia.com/terms/v/volatility-cone.asp
|
||||
///
|
||||
/// Note: Returns three values: mean volatility and its upper/lower bounds
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Vc : AbstractBase
|
||||
{
|
||||
private readonly int _period;
|
||||
private readonly double _deviations;
|
||||
private readonly CircularBuffer _returns;
|
||||
private readonly CircularBuffer _volatilities;
|
||||
private double _prevClose;
|
||||
private double _upperBound;
|
||||
private double _lowerBound;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vc(int period = 20, double deviations = 2.0)
|
||||
{
|
||||
_period = period;
|
||||
_deviations = deviations;
|
||||
WarmupPeriod = period * 2; // Need enough data for stable statistics
|
||||
Name = $"VC({_period},{_deviations})";
|
||||
_returns = new CircularBuffer(period);
|
||||
_volatilities = new CircularBuffer(period);
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vc(object source, int period = 20, double deviations = 2.0) : this(period, deviations)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevClose = 0;
|
||||
_upperBound = 0;
|
||||
_lowerBound = 0;
|
||||
_returns.Clear();
|
||||
_volatilities.Clear();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_lastValidValue = Value;
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private double CalculateVariance(CircularBuffer buffer)
|
||||
{
|
||||
if (buffer.Count == 0) return 0;
|
||||
double mean = buffer.Average();
|
||||
double sumSquaredDiff = 0;
|
||||
for (int i = 0; i < buffer.Count; i++)
|
||||
{
|
||||
double diff = buffer[i] - mean;
|
||||
sumSquaredDiff += diff * diff;
|
||||
}
|
||||
return sumSquaredDiff / buffer.Count;
|
||||
}
|
||||
|
||||
[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 return
|
||||
double ret = Math.Abs(_prevClose) > double.Epsilon ? Math.Log(BarInput.Close / _prevClose) : 0;
|
||||
_returns.Add(ret);
|
||||
|
||||
// Store current close for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
|
||||
// Need enough returns for volatility calculation
|
||||
if (_index <= _period)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate current volatility (annualized)
|
||||
double vol = Math.Sqrt(CalculateVariance(_returns)) * Math.Sqrt(252);
|
||||
_volatilities.Add(vol);
|
||||
|
||||
// Need enough volatilities for cone calculation
|
||||
if (_index <= WarmupPeriod)
|
||||
{
|
||||
return vol;
|
||||
}
|
||||
|
||||
// Calculate mean and standard deviation of volatilities
|
||||
double meanVol = _volatilities.Average();
|
||||
double stdVol = Math.Sqrt(CalculateVariance(_volatilities));
|
||||
|
||||
// Calculate bounds
|
||||
_upperBound = meanVol + (_deviations * stdVol);
|
||||
_lowerBound = Math.Max(0, meanVol - (_deviations * stdVol));
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return meanVol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the upper bound of the volatility cone
|
||||
/// </summary>
|
||||
public double UpperBound => _upperBound;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the lower bound of the volatility cone
|
||||
/// </summary>
|
||||
public double LowerBound => _lowerBound;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// VOV: Volatility of Volatility
|
||||
/// A technical indicator that measures the volatility of volatility itself,
|
||||
/// providing insight into the stability of market volatility.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The VOV calculation process:
|
||||
/// 1. Calculate primary volatility (e.g., using True Range)
|
||||
/// 2. Calculate standard deviation of primary volatility
|
||||
/// 3. Normalize result for comparison
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Second-order volatility measure
|
||||
/// - Default period is 20 days
|
||||
/// - Always positive
|
||||
/// - No upper bound
|
||||
/// - Measures volatility stability
|
||||
///
|
||||
/// Formula:
|
||||
/// Primary Volatility = TR (True Range)
|
||||
/// VOV = StdDev(Primary Volatility, period) / Average(Primary Volatility, period)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Risk of risk assessment
|
||||
/// - Volatility regime changes
|
||||
/// - Market stability analysis
|
||||
/// - Trading strategy adaptation
|
||||
/// - Risk management
|
||||
///
|
||||
/// Note: Higher values indicate more unstable volatility conditions
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Vov : AbstractBase
|
||||
{
|
||||
private readonly int _period;
|
||||
private readonly CircularBuffer _volatilities;
|
||||
private double _prevClose;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vov(int period = 20)
|
||||
{
|
||||
_period = period;
|
||||
WarmupPeriod = period + 1; // Need extra period for TR calculation
|
||||
Name = $"VOV({_period})";
|
||||
_volatilities = new CircularBuffer(period);
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vov(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();
|
||||
_prevClose = 0;
|
||||
_volatilities.Clear();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_lastValidValue = Value;
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private double CalculateVariance(CircularBuffer buffer)
|
||||
{
|
||||
if (buffer.Count == 0) return 0;
|
||||
double mean = buffer.Average();
|
||||
double sumSquaredDiff = 0;
|
||||
for (int i = 0; i < buffer.Count; i++)
|
||||
{
|
||||
double diff = buffer[i] - mean;
|
||||
sumSquaredDiff += diff * diff;
|
||||
}
|
||||
return sumSquaredDiff / buffer.Count;
|
||||
}
|
||||
|
||||
[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 True Range as primary volatility measure
|
||||
double tr = Math.Max(BarInput.High - BarInput.Low,
|
||||
Math.Max(Math.Abs(BarInput.High - _prevClose),
|
||||
Math.Abs(BarInput.Low - _prevClose)));
|
||||
|
||||
// Store current close for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
|
||||
// Add volatility to buffer
|
||||
_volatilities.Add(tr);
|
||||
|
||||
// Need enough volatilities for VOV calculation
|
||||
if (_index <= _period)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate mean volatility
|
||||
double meanVol = _volatilities.Average();
|
||||
|
||||
// Calculate VOV (normalized standard deviation)
|
||||
double vov = meanVol > double.Epsilon ? Math.Sqrt(CalculateVariance(_volatilities)) / meanVol : 0;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return vov;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// VR: Volatility Ratio
|
||||
/// A technical indicator that compares volatility across different time periods
|
||||
/// to identify changes in market conditions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The VR calculation process:
|
||||
/// 1. Calculate short-term volatility
|
||||
/// 2. Calculate long-term volatility
|
||||
/// 3. Calculate ratio between them
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Relative volatility measure
|
||||
/// - Default periods are 10 and 20 days
|
||||
/// - Values above 1 indicate increasing volatility
|
||||
/// - Values below 1 indicate decreasing volatility
|
||||
/// - Normalized comparison
|
||||
///
|
||||
/// Formula:
|
||||
/// Short Volatility = StdDev(Returns, shortPeriod)
|
||||
/// Long Volatility = StdDev(Returns, longPeriod)
|
||||
/// VR = Short Volatility / Long Volatility
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Volatility regime changes
|
||||
/// - Market condition analysis
|
||||
/// - Risk assessment
|
||||
/// - Trading strategy adaptation
|
||||
/// - Trend confirmation
|
||||
///
|
||||
/// Note: Values significantly different from 1 indicate changing market conditions
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Vr : AbstractBase
|
||||
{
|
||||
private readonly int _longPeriod;
|
||||
private readonly CircularBuffer _shortReturns;
|
||||
private readonly CircularBuffer _longReturns;
|
||||
private double _prevClose;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vr(int shortPeriod = 10, int longPeriod = 20)
|
||||
{
|
||||
_longPeriod = longPeriod;
|
||||
WarmupPeriod = longPeriod + 1; // Need one extra period for returns
|
||||
Name = $"VR({shortPeriod},{_longPeriod})";
|
||||
_shortReturns = new CircularBuffer(shortPeriod);
|
||||
_longReturns = new CircularBuffer(longPeriod);
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vr(object source, int shortPeriod = 10, int longPeriod = 20) : this(shortPeriod, longPeriod)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevClose = 0;
|
||||
_shortReturns.Clear();
|
||||
_longReturns.Clear();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_lastValidValue = Value;
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private double CalculateVariance(CircularBuffer buffer)
|
||||
{
|
||||
if (buffer.Count == 0) return 0;
|
||||
double mean = buffer.Average();
|
||||
double sumSquaredDiff = 0;
|
||||
for (int i = 0; i < buffer.Count; i++)
|
||||
{
|
||||
double diff = buffer[i] - mean;
|
||||
sumSquaredDiff += diff * diff;
|
||||
}
|
||||
return sumSquaredDiff / buffer.Count;
|
||||
}
|
||||
|
||||
[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 return
|
||||
double ret = _prevClose > double.Epsilon ? Math.Log(BarInput.Close / _prevClose) : 0;
|
||||
|
||||
// Add return to buffers
|
||||
_shortReturns.Add(ret);
|
||||
_longReturns.Add(ret);
|
||||
|
||||
// Store current close for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
|
||||
// Need enough returns for both periods
|
||||
if (_index <= _longPeriod)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate volatilities
|
||||
double shortVol = Math.Sqrt(CalculateVariance(_shortReturns));
|
||||
double longVol = Math.Sqrt(CalculateVariance(_longReturns));
|
||||
|
||||
// Calculate ratio
|
||||
double vr = longVol > double.Epsilon ? shortVol / longVol : 1;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return vr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// VS: Volatility Stop
|
||||
/// A technical indicator that uses volatility to determine stop levels,
|
||||
/// adapting to market conditions for dynamic risk management.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The VS calculation process:
|
||||
/// 1. Calculate Average True Range (ATR)
|
||||
/// 2. Calculate stop levels:
|
||||
/// Long Stop = Close - (multiplier * ATR)
|
||||
/// Short Stop = Close + (multiplier * ATR)
|
||||
/// 3. Trail stops based on price movement
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Adaptive stop levels
|
||||
/// - Based on ATR volatility
|
||||
/// - Default period is 14 days
|
||||
/// - Returns both long and short stops
|
||||
/// - Trails with price movement
|
||||
///
|
||||
/// Formula:
|
||||
/// ATR = Average(TR, period)
|
||||
/// Long Stop = Close - (multiplier * ATR)
|
||||
/// Short Stop = Close + (multiplier * ATR)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Stop loss placement
|
||||
/// - Position management
|
||||
/// - Risk control
|
||||
/// - Trend following
|
||||
/// - Exit strategy
|
||||
///
|
||||
/// Sources:
|
||||
/// Adaptation of Volatility-Based Stops concept
|
||||
/// https://www.investopedia.com/terms/v/volatility-stop.asp
|
||||
///
|
||||
/// Note: Returns two values: long stop and short stop levels
|
||||
/// </remarks>
|
||||
|
||||
[SkipLocalsInit]
|
||||
public sealed class Vs : AbstractBase
|
||||
{
|
||||
private readonly int _period;
|
||||
private readonly double _multiplier;
|
||||
private readonly CircularBuffer _tr;
|
||||
private double _prevClose;
|
||||
private double _longStop;
|
||||
private double _shortStop;
|
||||
private double _prevLongStop;
|
||||
private double _prevShortStop;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vs(int period = 14, double multiplier = 2.0)
|
||||
{
|
||||
_period = period;
|
||||
_multiplier = multiplier;
|
||||
WarmupPeriod = period + 1; // Need one extra period for TR
|
||||
Name = $"VS({_period},{_multiplier})";
|
||||
_tr = new CircularBuffer(period);
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vs(object source, int period = 14, double multiplier = 2.0) : this(period, multiplier)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_prevClose = 0;
|
||||
_longStop = 0;
|
||||
_shortStop = 0;
|
||||
_prevLongStop = 0;
|
||||
_prevShortStop = 0;
|
||||
_tr.Clear();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
{
|
||||
_lastValidValue = Value;
|
||||
_index++;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
// Skip first period to establish previous close
|
||||
if (_index == 1)
|
||||
{
|
||||
_prevClose = BarInput.Close;
|
||||
_longStop = BarInput.Close;
|
||||
_shortStop = BarInput.Close;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate True Range
|
||||
double tr = Math.Max(BarInput.High - BarInput.Low,
|
||||
Math.Max(Math.Abs(BarInput.High - _prevClose),
|
||||
Math.Abs(BarInput.Low - _prevClose)));
|
||||
|
||||
// Add TR to buffer
|
||||
_tr.Add(tr);
|
||||
|
||||
// Store current close for next calculation
|
||||
_prevClose = BarInput.Close;
|
||||
|
||||
// Need enough values for ATR calculation
|
||||
if (_index <= _period)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate ATR
|
||||
double atr = _tr.Average();
|
||||
|
||||
// Calculate initial stop levels
|
||||
double potentialLongStop = BarInput.Close - (_multiplier * atr);
|
||||
double potentialShortStop = BarInput.Close + (_multiplier * atr);
|
||||
|
||||
// Trail stops
|
||||
_longStop = BarInput.Close > _prevShortStop ? potentialLongStop : Math.Max(potentialLongStop, _prevLongStop);
|
||||
_shortStop = BarInput.Close < _prevLongStop ? potentialShortStop : Math.Min(potentialShortStop, _prevShortStop);
|
||||
|
||||
// Store current stops for next calculation
|
||||
_prevLongStop = _longStop;
|
||||
_prevShortStop = _shortStop;
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
return _longStop; // Return long stop as primary value
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the long stop level
|
||||
/// </summary>
|
||||
public double LongStop => _longStop;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the short stop level
|
||||
/// </summary>
|
||||
public double ShortStop => _shortStop;
|
||||
}
|
||||
+14
-13
@@ -1,37 +1,38 @@
|
||||
# Volatility indicators
|
||||
Done: 6, Todo: 25
|
||||
Done: 11, Todo: 24
|
||||
|
||||
ADR - Average Daily Range
|
||||
AP - Andrew's Pitchfork
|
||||
✔️ ATR - Average True Range
|
||||
ATRP - Average True Range Percent
|
||||
ATRS - ATR Trailing Stop
|
||||
BB - Bollinger Bands®
|
||||
*BB - Bollinger Bands® (Upper, Middle, Lower)
|
||||
CCV - Close-to-Close Volatility
|
||||
CE - Chandelier Exit
|
||||
CV - Conditional Volatility (ARCH/GARCH)
|
||||
CVI - Chaikin's Volatility
|
||||
DC - Donchian Channels
|
||||
*DC - Donchian Channels (Upper, Middle, Lower)
|
||||
EWMA - Exponential Weighted Moving Average Volatility
|
||||
FCB - Fractal Chaos Bands
|
||||
GKV - Garman-Klass Volatility
|
||||
HLV - High-Low Volatility
|
||||
✔️ HV - Historical Volatility
|
||||
ICH - Ichimoku Cloud
|
||||
*ICH - Ichimoku Cloud (Conversion, Base, Leading Span A, Leading Span B, Lagging Span)
|
||||
✔️ JVOLTY - Jurik Volatility
|
||||
KC - Keltner Channels
|
||||
*KC - Keltner Channels (Upper, Middle, Lower)
|
||||
NATR - Normalized Average True Range
|
||||
PCH - Price Channel Indicator
|
||||
PSAR - Parabolic Stop and Reverse
|
||||
*PSAR - Parabolic Stop and Reverse (Value, Trend)
|
||||
PV - Parkinson Volatility
|
||||
RSV - Rogers-Satchell Volatility
|
||||
✔️ RV - Realized Volatility
|
||||
✔️ RVI - Relative Volatility Index
|
||||
STARC - Starc Bands
|
||||
*STARC - Starc Bands (Upper, Middle, Lower)
|
||||
SV - Stochastic Volatility
|
||||
TR - True Range
|
||||
UI - Ulcer Index
|
||||
VC - Volatility Cone
|
||||
VOV - Volatility of Volatility
|
||||
VR - Volatility Ratio
|
||||
VS - Volatility Stop
|
||||
✔️ TR - True Range
|
||||
✔️ UI - Ulcer Index
|
||||
✔️ *VC - Volatility Cone (Mean, Upper Bound, Lower Bound)
|
||||
✔️ VOV - Volatility of Volatility
|
||||
✔️ VR - Volatility Ratio
|
||||
✔️ *VS - Volatility Stop (Long Stop, Short Stop)
|
||||
YZV - Yang-Zhang Volatility
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
# Volatility Measures
|
||||
|
||||
## Single Value Input (Typically Closing Prices)
|
||||
|
||||
- **Jurik Volatility (Volty)**
|
||||
- **Standard Deviation**
|
||||
- **RVI Relative Volatility Index**
|
||||
- **CMO Chande Momentum Oscillator**
|
||||
- **Historical Volatility**
|
||||
- **Average True Range (ATR) (High, Low, Close)**
|
||||
|
||||
- Normalized ATR
|
||||
- Ulcer Index
|
||||
- ARCH/GARCH Models
|
||||
- Exponential Weighted Moving Average (EWMA) Volatility
|
||||
- Conditional Volatility
|
||||
- Volatility Ratio
|
||||
- Close-to-Close Volatility
|
||||
- Volatility of Volatility (VOV)
|
||||
- Volatility Cone
|
||||
- Bollinger Bands
|
||||
- Stochastic Volatility: Typically modeled using closing prices, but can incorporate other price information
|
||||
- Garman-Klass Volatility
|
||||
- Rogers-Satchell Volatility
|
||||
- Yang-Zhang Volatility
|
||||
- Parkinson Volatility (High, Low)
|
||||
- Chaikin Volatility (High, Low)
|
||||
- Keltner Channels (typically Close, High, Low)
|
||||
- High-Low Volatility (High, Low)
|
||||
Reference in New Issue
Block a user