mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-05 12:37:43 +00:00
xml doc rewrite
This commit is contained in:
+48
-35
@@ -1,51 +1,75 @@
|
||||
using System;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an Average True Range (ATR) calculator, a measure of market volatility.
|
||||
/// ATR: Average True Range
|
||||
/// A technical indicator that measures market volatility by decomposing the entire
|
||||
/// range of an asset's price for a period. ATR accounts for gaps between periods
|
||||
/// and provides a comprehensive view of price volatility.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The ATR class calculates the average true range using a Relative Moving Average (RMA)
|
||||
/// of the true range. The true range is the greatest of: current high - current low,
|
||||
/// absolute value of current high - previous close, or absolute value of current low - previous close.
|
||||
/// The ATR calculation process:
|
||||
/// 1. Calculates True Range (TR) as maximum of:
|
||||
/// - Current High - Current Low
|
||||
/// - |Current High - Previous Close|
|
||||
/// - |Current Low - Previous Close|
|
||||
/// 2. Applies RMA smoothing to TR values
|
||||
/// 3. Updates with each new price bar
|
||||
/// 4. Adapts to changing volatility
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Absolute price measure
|
||||
/// - Gap-inclusive calculation
|
||||
/// - Trend independent
|
||||
/// - Volatility focused
|
||||
/// - Smoothed output
|
||||
///
|
||||
/// Formula:
|
||||
/// TR = max(high-low, |high-prevClose|, |low-prevClose|)
|
||||
/// ATR = RMA(TR, period)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Position sizing
|
||||
/// - Stop loss placement
|
||||
/// - Volatility breakouts
|
||||
/// - Risk assessment
|
||||
/// - Entry/exit timing
|
||||
///
|
||||
/// Sources:
|
||||
/// J. Welles Wilder - "New Concepts in Technical Trading Systems"
|
||||
/// https://www.investopedia.com/terms/a/atr.asp
|
||||
///
|
||||
/// Note: Higher ATR indicates higher volatility
|
||||
/// </remarks>
|
||||
|
||||
public class Atr : AbstractBase
|
||||
{
|
||||
public double Tr { get; private set; }
|
||||
private readonly Rma _ma;
|
||||
private double _prevClose, _p_prevClose;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Atr class with the specified period.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate the ATR.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 1.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of periods for ATR calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
public Atr(int period)
|
||||
{
|
||||
if (period < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
||||
throw new ArgumentOutOfRangeException(nameof(period),
|
||||
"Period must be greater than or equal to 1.");
|
||||
}
|
||||
_ma = new(period, useSma: true);
|
||||
WarmupPeriod = _ma.WarmupPeriod;
|
||||
Name = $"ATR({period})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Atr class with the specified source and period.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object to subscribe to for bar updates.</param>
|
||||
/// <param name="period">The period over which to calculate the ATR.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of periods for ATR calculation.</param>
|
||||
public Atr(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Atr instance by setting up the initial state.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
@@ -54,10 +78,6 @@ public class Atr : AbstractBase
|
||||
Tr = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Atr instance based on whether a new bar is being processed.
|
||||
/// </summary>
|
||||
/// <param name="isNew">Indicates whether the current input is a new bar.</param>
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
@@ -71,28 +91,19 @@ public class Atr : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the ATR calculation for the current bar.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated ATR value for the current bar.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method calculates the true range for the current bar and then uses an RMA
|
||||
/// to smooth the true range values. For the first bar, it uses the high-low range
|
||||
/// as the true range.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(BarInput.IsNew);
|
||||
|
||||
if (_index == 1)
|
||||
{
|
||||
// First bar uses simple high-low range
|
||||
Tr = BarInput.High - BarInput.Low;
|
||||
_prevClose = BarInput.Close;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate True Range as maximum of three measures
|
||||
Tr = Math.Max(
|
||||
BarInput.High - BarInput.Low,
|
||||
Math.Max(
|
||||
@@ -101,6 +112,8 @@ public class Atr : AbstractBase
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Apply RMA smoothing to True Range
|
||||
_ma.Calc(new TValue(Input.Time, Tr, BarInput.IsNew));
|
||||
|
||||
IsHot = _ma.IsHot;
|
||||
|
||||
+54
-45
@@ -1,14 +1,49 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a historical volatility calculator that measures the dispersion of returns
|
||||
/// for a given security or market index over a specific period.
|
||||
/// HV: Historical Volatility
|
||||
/// A statistical measure that calculates the dispersion of returns over time,
|
||||
/// providing insights into past price variability. Historical volatility is
|
||||
/// fundamental to options pricing and risk assessment.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Historical class calculates volatility based on logarithmic returns. It can provide
|
||||
/// both annualized and non-annualized volatility measures. The calculation uses a sample
|
||||
/// standard deviation formula and assumes 252 trading days in a year for annualization.
|
||||
/// The HV calculation process:
|
||||
/// 1. Computes daily log returns
|
||||
/// 2. Calculates standard deviation
|
||||
/// 3. Annualizes if specified
|
||||
/// 4. Uses sample variance formula
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Backward-looking measure
|
||||
/// - Log-return based
|
||||
/// - Optional annualization
|
||||
/// - Sample-based calculation
|
||||
/// - Trading-day adjusted
|
||||
///
|
||||
/// Formula:
|
||||
/// HV = √[(Σ(ln(P[t]/P[t-1]) - μ)²)/(n-1)] * √252
|
||||
/// where:
|
||||
/// P = price
|
||||
/// μ = mean of log returns
|
||||
/// n = number of observations
|
||||
/// 252 = trading days per year
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Options pricing
|
||||
/// - Risk assessment
|
||||
/// - Trading ranges
|
||||
/// - Portfolio management
|
||||
/// - Volatility trading
|
||||
///
|
||||
/// Sources:
|
||||
/// Black-Scholes Option Pricing Model
|
||||
/// https://en.wikipedia.org/wiki/Volatility_(finance)
|
||||
///
|
||||
/// Note: Assumes 252 trading days for annualization
|
||||
/// </remarks>
|
||||
|
||||
public class Hv : AbstractBase
|
||||
{
|
||||
private readonly int Period;
|
||||
@@ -17,44 +52,34 @@ public class Hv : AbstractBase
|
||||
private readonly CircularBuffer _logReturns;
|
||||
private double _previousClose;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Historical class with the specified period and annualization flag.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate historical volatility.</param>
|
||||
/// <param name="isAnnualized">Whether to annualize the volatility (default is true).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 2.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of periods for volatility calculation.</param>
|
||||
/// <param name="isAnnualized">Whether to annualize the result (default true).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 2.</exception>
|
||||
public Hv(int period, bool isAnnualized = true)
|
||||
{
|
||||
if (period < 2)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2.");
|
||||
throw new ArgumentOutOfRangeException(nameof(period),
|
||||
"Period must be greater than or equal to 2.");
|
||||
}
|
||||
Period = period;
|
||||
IsAnnualized = isAnnualized;
|
||||
WarmupPeriod = period + 1; // We need one extra data point to calculate the first return
|
||||
WarmupPeriod = period + 1; // Need extra point for first return
|
||||
_buffer = new CircularBuffer(period + 1);
|
||||
_logReturns = new CircularBuffer(period);
|
||||
Name = $"Historical(period={period}, annualized={isAnnualized})";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Historical class with the specified source, period, and annualization flag.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object to subscribe to for value updates.</param>
|
||||
/// <param name="period">The period over which to calculate historical volatility.</param>
|
||||
/// <param name="isAnnualized">Whether to annualize the volatility (default is true).</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of periods for volatility calculation.</param>
|
||||
/// <param name="isAnnualized">Whether to annualize the result (default true).</param>
|
||||
public Hv(object source, int period, bool isAnnualized = true) : this(period, isAnnualized)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Historical instance by clearing buffers and resetting the previous close value.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
@@ -63,10 +88,6 @@ public class Hv : AbstractBase
|
||||
_previousClose = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Historical instance based on whether a new value is being processed.
|
||||
/// </summary>
|
||||
/// <param name="isNew">Indicates whether the current input is a new value.</param>
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
@@ -76,47 +97,35 @@ public class Hv : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the historical volatility calculation for the current period.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated historical volatility value for the current period.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method calculates the volatility using the following steps:
|
||||
/// 1. Compute logarithmic returns.
|
||||
/// 2. Calculate the sample standard deviation of the log returns.
|
||||
/// 3. If annualized, multiply by the square root of 252 (assumed trading days in a year).
|
||||
/// The method returns 0 until enough data points are available for the calculation.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
_buffer.Add(Input.Value, Input.IsNew);
|
||||
|
||||
double volatility = 0;
|
||||
if (_buffer.Count > 1)
|
||||
{
|
||||
// Calculate log return if we have previous close
|
||||
if (_previousClose != 0)
|
||||
{
|
||||
double logReturn = Math.Log(Input.Value / _previousClose);
|
||||
_logReturns.Add(logReturn, Input.IsNew);
|
||||
}
|
||||
|
||||
// Calculate volatility when we have enough returns
|
||||
if (_logReturns.Count == Period)
|
||||
{
|
||||
var returns = _logReturns.GetSpan().ToArray();
|
||||
double mean = returns.Average();
|
||||
double sumOfSquaredDifferences = returns.Sum(x => Math.Pow(x - mean, 2));
|
||||
|
||||
double variance = sumOfSquaredDifferences / (Period - 1); // Using sample standard deviation
|
||||
// Sample standard deviation
|
||||
double variance = sumOfSquaredDifferences / (Period - 1);
|
||||
volatility = Math.Sqrt(variance);
|
||||
|
||||
if (IsAnnualized)
|
||||
{
|
||||
// Assuming 252 trading days in a year. Adjust as needed.
|
||||
volatility *= Math.Sqrt(252);
|
||||
volatility *= Math.Sqrt(252); // Annualize using trading days
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+56
-41
@@ -1,9 +1,46 @@
|
||||
/// <summary>
|
||||
/// Represents a Jurik Volatility (Jvolty) calculator, a measure of market volatility based on Jurik Moving Average (JMA) concepts.
|
||||
/// </summary>
|
||||
|
||||
using System;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// JVOLTY: Jurik Volatility
|
||||
/// An advanced volatility measure developed by Mark Jurik that combines adaptive
|
||||
/// bands with JMA smoothing. JVOLTY provides a sophisticated approach to measuring
|
||||
/// market volatility with reduced noise and better responsiveness.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The JVOLTY calculation process:
|
||||
/// 1. Calculates adaptive price bands
|
||||
/// 2. Measures volatility from band distances
|
||||
/// 3. Applies volatility normalization
|
||||
/// 4. Uses JMA-style smoothing
|
||||
/// 5. Provides multiple outputs
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Adaptive measurement
|
||||
/// - Noise reduction
|
||||
/// - Multiple timeframe analysis
|
||||
/// - Price band integration
|
||||
/// - Volatility normalization
|
||||
///
|
||||
/// Formula:
|
||||
/// volty = max(|price - upperBand|, |price - lowerBand|)
|
||||
/// bands = adaptive calculation using Jurik's methods
|
||||
/// final = JMA smoothing of normalized volatility
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Dynamic position sizing
|
||||
/// - Adaptive stop placement
|
||||
/// - Volatility breakout systems
|
||||
/// - Risk management
|
||||
/// - Market regime detection
|
||||
///
|
||||
/// Sources:
|
||||
/// Mark Jurik Research
|
||||
/// https://www.jurikresearch.com/
|
||||
///
|
||||
/// Note: Proprietary enhancement of volatility measurement
|
||||
/// </remarks>
|
||||
|
||||
public class Jvolty : AbstractBase
|
||||
{
|
||||
private readonly int _period;
|
||||
@@ -18,7 +55,6 @@ public class Jvolty : AbstractBase
|
||||
private double _prevMa1, _prevDet0, _prevDet1, _prevJma, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma;
|
||||
private double _vSum, _p_vSum;
|
||||
|
||||
|
||||
public double UpperBand { get; set; }
|
||||
public double LowerBand { get; set; }
|
||||
public double Volty { get; set; }
|
||||
@@ -26,21 +62,15 @@ public class Jvolty : AbstractBase
|
||||
public double Jma { get; set; }
|
||||
public double AvgVolty { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Jvolty class with the specified parameters.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate the Jvolty.</param>
|
||||
/// <param name="phase">The phase parameter for the JMA-style calculation.</param>
|
||||
/// <param name="vshort">The short-term volatility period.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 1.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of periods for volatility calculation.</param>
|
||||
/// <param name="phase">Phase parameter for JMA smoothing (default 0).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
public Jvolty(int period, int phase = 0)
|
||||
{
|
||||
if (period < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
||||
throw new ArgumentOutOfRangeException(nameof(period),
|
||||
"Period must be greater than or equal to 1.");
|
||||
}
|
||||
_period = period;
|
||||
_phase = Math.Clamp((phase * 0.01) + 1.5, 0.5, 2.5);
|
||||
@@ -53,22 +83,15 @@ public class Jvolty : AbstractBase
|
||||
Name = $"JVOLTY({period})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Jvolty class with the specified source and parameters.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object to subscribe to for bar updates.</param>
|
||||
/// <param name="period">The period over which to calculate the Jvolty.</param>
|
||||
/// <param name="phase">The phase parameter for the JMA-style calculation.</param>
|
||||
/// <param name="vshort">The short-term volatility period.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of periods for volatility calculation.</param>
|
||||
/// <param name="phase">Phase parameter for JMA smoothing (default 0).</param>
|
||||
public Jvolty(object source, int period, int phase = 0) : this(period, phase)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Jvolty instance by setting up the initial state.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
@@ -80,10 +103,6 @@ public class Jvolty : AbstractBase
|
||||
_vsumBuff.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Jvolty instance based on whether a new bar is being processed.
|
||||
/// </summary>
|
||||
/// <param name="isNew">Indicates whether the current input is a new bar.</param>
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
@@ -109,12 +128,6 @@ public class Jvolty : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the Jvolty calculation for the current bar.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated Jvolty value for the current bar.
|
||||
/// </returns>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
@@ -125,26 +138,29 @@ public class Jvolty : AbstractBase
|
||||
_upperBand = _lowerBand = price;
|
||||
}
|
||||
|
||||
// Calculate volatility from band distances
|
||||
double del1 = price - _upperBand;
|
||||
double del2 = price - _lowerBand;
|
||||
double volty = Math.Max(Math.Abs(del1), Math.Abs(del2));
|
||||
|
||||
// Calculate moving averages of volatility
|
||||
_vsumBuff.Add(volty, Input.IsNew);
|
||||
_vSum += (_vsumBuff[^1] - _vsumBuff[0]) / 10;
|
||||
_avoltyBuff.Add(_vSum, Input.IsNew);
|
||||
double avgvolty = _avoltyBuff.Average();
|
||||
|
||||
// Normalize and adjust volatility
|
||||
double rvolty = (avgvolty > 0) ? volty / avgvolty : 1;
|
||||
rvolty = Math.Min(Math.Max(rvolty, 1.0), Math.Pow(_len1, 1.0 / _pow1));
|
||||
|
||||
double pow2 = Math.Pow(rvolty, _pow1);
|
||||
double Kv = Math.Pow(_beta, Math.Sqrt(pow2));
|
||||
|
||||
// Update adaptive bands
|
||||
_upperBand = (del1 >= 0) ? price : price - (Kv * del1);
|
||||
_lowerBand = (del2 <= 0) ? price : price - (Kv * del2);
|
||||
|
||||
|
||||
|
||||
// Apply JMA smoothing
|
||||
double alpha = Math.Pow(_beta, pow2);
|
||||
double ma1 = (1 - alpha) * Input.Value + alpha * _prevMa1;
|
||||
_prevMa1 = ma1;
|
||||
@@ -153,11 +169,12 @@ public class Jvolty : AbstractBase
|
||||
_prevDet0 = det0;
|
||||
double ma2 = ma1 + _phase * det0;
|
||||
|
||||
double det1 = ((ma2 - _prevJma) * (1 - alpha) * (1 - alpha) ) + (alpha * alpha * _prevDet1);
|
||||
double det1 = ((ma2 - _prevJma) * (1 - alpha) * (1 - alpha)) + (alpha * alpha * _prevDet1);
|
||||
_prevDet1 = det1;
|
||||
double jma = _prevJma + det1;
|
||||
_prevJma = jma;
|
||||
|
||||
// Update public properties
|
||||
UpperBand = _upperBand;
|
||||
LowerBand = _lowerBand;
|
||||
Volty = volty;
|
||||
@@ -169,5 +186,3 @@ public class Jvolty : AbstractBase
|
||||
return volty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+53
-46
@@ -1,14 +1,48 @@
|
||||
using System;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a realized volatility calculator that measures the actual price fluctuations
|
||||
/// observed in the market over a specific period.
|
||||
/// RV: Realized Volatility
|
||||
/// A precise volatility measure that captures actual observed price fluctuations
|
||||
/// using high-frequency returns. RV provides a more accurate assessment of true
|
||||
/// market volatility compared to traditional estimators.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Realized class calculates volatility based on logarithmic returns. It can provide
|
||||
/// both annualized and non-annualized volatility measures. The calculation uses a rolling
|
||||
/// sum of squared returns for efficiency and assumes 252 trading days in a year for annualization.
|
||||
/// The RV calculation process:
|
||||
/// 1. Computes log returns
|
||||
/// 2. Squares each return
|
||||
/// 3. Maintains rolling sum
|
||||
/// 4. Takes square root of average
|
||||
/// 5. Optionally annualizes
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Model-free measurement
|
||||
/// - High-frequency capable
|
||||
/// - Rolling calculation
|
||||
/// - Memory efficient
|
||||
/// - Optional annualization
|
||||
///
|
||||
/// Formula:
|
||||
/// RV = √(Σ(ln(P[t]/P[t-1]))²/n) * √252
|
||||
/// where:
|
||||
/// P = price
|
||||
/// n = number of observations
|
||||
/// 252 = trading days per year
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - High-frequency trading
|
||||
/// - Options pricing
|
||||
/// - Risk forecasting
|
||||
/// - Market microstructure
|
||||
/// - Volatility trading
|
||||
///
|
||||
/// Sources:
|
||||
/// Andersen, Bollerslev - "Answering the Skeptics"
|
||||
/// https://en.wikipedia.org/wiki/Realized_volatility
|
||||
///
|
||||
/// Note: Efficient implementation using rolling sums
|
||||
/// </remarks>
|
||||
|
||||
public class Rv : AbstractBase
|
||||
{
|
||||
private readonly int Period;
|
||||
@@ -17,43 +51,33 @@ public class Rv : AbstractBase
|
||||
private double _previousClose;
|
||||
private double _sumSquaredReturns;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Realized class with the specified period and annualization flag.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate realized volatility.</param>
|
||||
/// <param name="isAnnualized">Whether to annualize the volatility (default is true).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 2.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of periods for volatility calculation.</param>
|
||||
/// <param name="isAnnualized">Whether to annualize the result (default true).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 2.</exception>
|
||||
public Rv(int period, bool isAnnualized = true)
|
||||
{
|
||||
if (period < 2)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2.");
|
||||
throw new ArgumentOutOfRangeException(nameof(period),
|
||||
"Period must be greater than or equal to 2.");
|
||||
}
|
||||
Period = period;
|
||||
IsAnnualized = isAnnualized;
|
||||
WarmupPeriod = period + 1; // We need one extra data point to calculate the first return
|
||||
WarmupPeriod = period + 1; // Need extra point for first return
|
||||
_returns = new CircularBuffer(period);
|
||||
Name = $"Realized(period={period}, annualized={isAnnualized})";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Realized class with a data source.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object that publishes data.</param>
|
||||
/// <param name="period">The period over which to calculate realized volatility.</param>
|
||||
/// <param name="isAnnualized">Whether to annualize the volatility (default is true).</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of periods for volatility calculation.</param>
|
||||
/// <param name="isAnnualized">Whether to annualize the result (default true).</param>
|
||||
public Rv(object source, int period, bool isAnnualized = true) : this(period, isAnnualized)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Realized instance by clearing buffers and resetting calculation variables.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
@@ -62,10 +86,6 @@ public class Rv : AbstractBase
|
||||
_sumSquaredReturns = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Realized instance based on whether a new value is being processed.
|
||||
/// </summary>
|
||||
/// <param name="isNew">Indicates whether the current input is a new value.</param>
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
@@ -75,21 +95,6 @@ public class Rv : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the realized volatility calculation for the current period.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated realized volatility value for the current period.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method calculates the volatility using the following steps:
|
||||
/// 1. Compute logarithmic returns.
|
||||
/// 2. Maintain a rolling sum of squared returns.
|
||||
/// 3. Calculate the variance using the sum of squared returns.
|
||||
/// 4. Take the square root of the variance to get volatility.
|
||||
/// 5. If annualized, multiply by the square root of 252 (assumed trading days in a year).
|
||||
/// The method returns 0 until enough data points are available for the calculation.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
@@ -97,26 +102,28 @@ public class Rv : AbstractBase
|
||||
double volatility = 0;
|
||||
if (_previousClose != 0)
|
||||
{
|
||||
// Calculate log return
|
||||
double logReturn = Math.Log(Input.Value / _previousClose);
|
||||
|
||||
if (_returns.Count == Period)
|
||||
{
|
||||
// Remove the oldest squared return from the sum
|
||||
// Maintain rolling sum by removing oldest squared return
|
||||
_sumSquaredReturns -= Math.Pow(_returns[0], 2);
|
||||
}
|
||||
|
||||
// Add new return and update sum
|
||||
_returns.Add(logReturn, Input.IsNew);
|
||||
_sumSquaredReturns += Math.Pow(logReturn, 2);
|
||||
|
||||
if (_returns.Count == Period)
|
||||
{
|
||||
// Calculate realized volatility
|
||||
double variance = _sumSquaredReturns / Period;
|
||||
volatility = Math.Sqrt(variance);
|
||||
|
||||
if (IsAnnualized)
|
||||
{
|
||||
// Assuming 252 trading days in a year. Adjust as needed.
|
||||
volatility *= Math.Sqrt(252);
|
||||
volatility *= Math.Sqrt(252); // Annualize using trading days
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+49
-44
@@ -1,36 +1,61 @@
|
||||
using System;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Relative Volatility Index (RVI) calculator, which measures the direction
|
||||
/// of volatility in relation to price movements.
|
||||
/// RVI: Relative Volatility Index
|
||||
/// A technical indicator developed by Donald Dorsey that measures the direction
|
||||
/// of volatility by comparing upward and downward price movements. RVI helps
|
||||
/// identify whether volatility is increasing more in up or down moves.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The RVI was introduced by Donald Dorsey in the 1993 issue of Technical Analysis
|
||||
/// of Stocks & Commodities Magazine. It focuses on the direction of price movements
|
||||
/// in relation to volatility. The indicator uses standard deviation calculations
|
||||
/// to determine whether volatility is increasing more in up moves or down moves.
|
||||
/// The RVI calculation process:
|
||||
/// 1. Separates price changes into up/down moves
|
||||
/// 2. Calculates standard deviation for each
|
||||
/// 3. Applies moving average smoothing
|
||||
/// 4. Computes relative strength ratio
|
||||
/// 5. Scales to percentage (0-100)
|
||||
///
|
||||
/// This implementation uses a combination of Standard Deviation and Simple Moving Average
|
||||
/// calculations to compute the RVI.
|
||||
/// Key characteristics:
|
||||
/// - Oscillator (0-100 range)
|
||||
/// - Directional volatility measure
|
||||
/// - Combines volatility and momentum
|
||||
/// - Uses standard deviation
|
||||
/// - Smoothed output
|
||||
///
|
||||
/// Formula:
|
||||
/// RVI = 100 * SMA(StdDev(upMoves)) / (SMA(StdDev(upMoves)) + SMA(StdDev(downMoves)))
|
||||
/// where:
|
||||
/// upMove = max(close - prevClose, 0)
|
||||
/// downMove = max(prevClose - close, 0)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend confirmation
|
||||
/// - Divergence analysis
|
||||
/// - Volatility breakouts
|
||||
/// - Market reversals
|
||||
/// - Overbought/oversold levels
|
||||
///
|
||||
/// Sources:
|
||||
/// Donald Dorsey - "Technical Analysis of Stocks & Commodities" (1993)
|
||||
/// https://www.investopedia.com/terms/r/relative_volatility_index.asp
|
||||
///
|
||||
/// Note: Similar concept to RSI but using volatility
|
||||
/// </remarks>
|
||||
|
||||
public class Rvi : AbstractBase
|
||||
{
|
||||
private readonly Stddev _upStdDev, _downStdDev;
|
||||
private readonly Sma _upSma, _downSma;
|
||||
private double _previousClose;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Rvi class with the specified period.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate the RVI.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 2.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of periods for RVI calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 2.</exception>
|
||||
public Rvi(int period)
|
||||
{
|
||||
if (period < 2)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2.");
|
||||
throw new ArgumentOutOfRangeException(nameof(period),
|
||||
"Period must be greater than or equal to 2.");
|
||||
}
|
||||
int Period = period;
|
||||
WarmupPeriod = period;
|
||||
@@ -42,30 +67,20 @@ public class Rvi : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Rvi class with the specified source and period.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object to subscribe to for value updates.</param>
|
||||
/// <param name="period">The period over which to calculate the RVI.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of periods for RVI calculation.</param>
|
||||
public Rvi(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Rvi instance by setting up the initial state.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_previousClose = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Rvi instance based on whether a new value is being processed.
|
||||
/// </summary>
|
||||
/// <param name="isNew">Indicates whether the current input is a new value.</param>
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
@@ -75,21 +90,6 @@ public class Rvi : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the RVI calculation for the current input.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated RVI value for the current input.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method calculates the RVI using the following steps:
|
||||
/// 1. Calculate the change in price from the previous close.
|
||||
/// 2. Determine the up move and down move based on the change.
|
||||
/// 3. Calculate standard deviations of up and down moves.
|
||||
/// 4. Apply a simple moving average to the standard deviations.
|
||||
/// 5. Compute the RVI as a percentage of up volatility to total volatility.
|
||||
/// The method returns 0 if the sum of up and down volatility is zero.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
@@ -97,14 +97,19 @@ public class Rvi : AbstractBase
|
||||
double close = Input.Value;
|
||||
double change = close - _previousClose;
|
||||
|
||||
// Separate into up and down moves
|
||||
double upMove = Math.Max(change, 0);
|
||||
double downMove = Math.Max(-change, 0);
|
||||
|
||||
// Calculate standard deviations and apply smoothing
|
||||
_upSma.Calc(_upStdDev.Calc(new TValue(Input.Time, upMove, Input.IsNew)));
|
||||
_downSma.Calc(_downStdDev.Calc(new TValue(Input.Time, downMove, Input.IsNew)));
|
||||
|
||||
// Calculate RVI ratio
|
||||
double rvi;
|
||||
rvi = (_upSma.Value + _downSma.Value != 0) ? 100 * _upSma.Value / (_upSma.Value + _downSma.Value) : 0;
|
||||
rvi = (_upSma.Value + _downSma.Value != 0)
|
||||
? 100 * _upSma.Value / (_upSma.Value + _downSma.Value)
|
||||
: 0;
|
||||
|
||||
_previousClose = close;
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
|
||||
Reference in New Issue
Block a user