mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-06 21:17:44 +00:00
xml doc rewrite
This commit is contained in:
+36
-35
@@ -1,15 +1,41 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the rate of change of the slope over a specified period.
|
||||
/// Provides insights into trend acceleration or deceleration.
|
||||
/// Curvature: Second Derivative Rate of Change
|
||||
/// A statistical measure that calculates the rate of change of the slope over time.
|
||||
/// Curvature provides insights into trend acceleration or deceleration by measuring
|
||||
/// how quickly the slope (first derivative) is changing.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Curvature is a second-order derivative that measures how quickly the slope (first-order derivative) is changing.
|
||||
/// Positive curvature indicates accelerating uptrends or decelerating downtrends.
|
||||
/// Negative curvature indicates decelerating uptrends or accelerating downtrends.
|
||||
/// This indicator can be useful for identifying potential trend reversals or confirming trend strength.
|
||||
/// The Curvature calculation process:
|
||||
/// 1. Calculates slope values over the specified period
|
||||
/// 2. Applies least squares regression to slope values
|
||||
/// 3. Provides slope of slopes (curvature)
|
||||
/// 4. Includes additional statistical measures (R², StdDev)
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Measures trend acceleration/deceleration
|
||||
/// - Positive values indicate accelerating uptrends or decelerating downtrends
|
||||
/// - Negative values indicate decelerating uptrends or accelerating downtrends
|
||||
/// - Helps identify potential trend reversals
|
||||
/// - Provides trend momentum information
|
||||
///
|
||||
/// Formula:
|
||||
/// Curvature = Σ((x - x̄)(y - ȳ)) / Σ((x - x̄)²)
|
||||
/// where:
|
||||
/// x = time points
|
||||
/// y = slope values
|
||||
/// x̄, ȳ = respective means
|
||||
///
|
||||
/// Sources:
|
||||
/// https://en.wikipedia.org/wiki/Curvature
|
||||
/// https://www.sciencedirect.com/topics/mathematics/curve-fitting
|
||||
///
|
||||
/// Note: Second-order derivative providing acceleration insights
|
||||
/// </remarks>
|
||||
|
||||
public class Curvature : AbstractBase
|
||||
{
|
||||
private readonly int _period;
|
||||
@@ -36,13 +62,8 @@ public class Curvature : AbstractBase
|
||||
/// </summary>
|
||||
public double? Line { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Curvature class.
|
||||
/// </summary>
|
||||
/// <param name="period">The number of data points to consider for calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the period is 2 or less.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is 2 or less.</exception>
|
||||
public Curvature(int period)
|
||||
{
|
||||
if (period <= 2)
|
||||
@@ -59,20 +80,14 @@ public class Curvature : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Curvature class with a data source.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object that publishes data.</param>
|
||||
/// <param name="period">The number of data points to consider.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for calculation.</param>
|
||||
public Curvature(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the Curvature indicator to its initial state.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
@@ -83,10 +98,6 @@ public class Curvature : AbstractBase
|
||||
Line = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the indicator.
|
||||
/// </summary>
|
||||
/// <param name="isNew">Indicates if the current data point is new.</param>
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
@@ -96,16 +107,6 @@ public class Curvature : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the curvature calculation.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated curvature value. Positive for increasing slope, negative for decreasing.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Uses least squares method for optimal calculation. Also computes additional statistics
|
||||
/// such as Intercept, Standard Deviation, R-Squared, and Line value.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
+46
-47
@@ -1,33 +1,53 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Measures the unpredictability of data using Shannon's Entropy.
|
||||
/// Provides insights into the randomness or information content of the time series.
|
||||
/// Entropy: Information Content Measure
|
||||
/// A statistical measure that quantifies the unpredictability or randomness in
|
||||
/// a time series using Shannon's Entropy. Higher entropy indicates more randomness
|
||||
/// and uncertainty in the data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Shannon's Entropy quantifies the average amount of information contained in a message.
|
||||
/// In the context of time series analysis, it can be used to:
|
||||
/// - Detect regime changes or structural breaks in the data.
|
||||
/// - Assess the complexity or predictability of price movements.
|
||||
/// - Identify periods of high uncertainty or information flow in the market.
|
||||
/// The entropy value is normalized between 0 and 1, where 1 indicates maximum randomness
|
||||
/// and 0 indicates perfect predictability.
|
||||
/// The Entropy calculation process:
|
||||
/// 1. Groups values to calculate probabilities
|
||||
/// 2. Applies Shannon's entropy formula
|
||||
/// 3. Normalizes result to 0-1 range
|
||||
/// 4. Adjusts for number of unique values
|
||||
///
|
||||
/// Key characteristics:
|
||||
/// - Range from 0 (predictable) to 1 (random)
|
||||
/// - Measures information content
|
||||
/// - Detects regime changes
|
||||
/// - Identifies market uncertainty
|
||||
/// - Scale-independent measure
|
||||
///
|
||||
/// Formula:
|
||||
/// H = -Σ(p(x) * log₂(p(x))) / log₂(n)
|
||||
/// where:
|
||||
/// p(x) = probability of value x
|
||||
/// n = number of unique values
|
||||
///
|
||||
/// Applications:
|
||||
/// - Detect market regime changes
|
||||
/// - Assess price movement predictability
|
||||
/// - Identify periods of high uncertainty
|
||||
/// - Measure information flow in markets
|
||||
///
|
||||
/// Sources:
|
||||
/// Claude Shannon - "A Mathematical Theory of Communication" (1948)
|
||||
/// https://en.wikipedia.org/wiki/Entropy_(information_theory)
|
||||
///
|
||||
/// Note: Normalized to [0,1] for easier interpretation
|
||||
/// </remarks>
|
||||
|
||||
public class Entropy : AbstractBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of data points to consider for the entropy calculation.
|
||||
/// </summary>
|
||||
private readonly int Period;
|
||||
private readonly CircularBuffer _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Entropy class.
|
||||
/// </summary>
|
||||
/// <param name="period">The number of data points to consider for calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the period is less than 2.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for entropy calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 2.</exception>
|
||||
public Entropy(int period)
|
||||
{
|
||||
if (period < 2)
|
||||
@@ -42,30 +62,20 @@ public class Entropy : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Entropy class with a data source.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object that publishes data.</param>
|
||||
/// <param name="period">The number of data points to consider.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for entropy calculation.</param>
|
||||
public Entropy(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the Entropy indicator to its initial state.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_buffer.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the indicator.
|
||||
/// </summary>
|
||||
/// <param name="isNew">Indicates if the current data point is new.</param>
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
@@ -75,17 +85,6 @@ public class Entropy : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the entropy calculation.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated entropy value, normalized between 0 and 1.
|
||||
/// 1 indicates maximum randomness, 0 indicates perfect predictability.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Uses Shannon's Entropy formula and normalizes the result based on the
|
||||
/// number of unique values in the current period.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
@@ -93,22 +92,22 @@ public class Entropy : AbstractBase
|
||||
_buffer.Add(Input.Value, Input.IsNew);
|
||||
|
||||
double entropy = 0;
|
||||
if (_index > 1) // We need at least two data points for entropy calculation
|
||||
if (_index > 1) // Need at least two data points for entropy calculation
|
||||
{
|
||||
var values = _buffer.GetSpan().ToArray();
|
||||
int n = values.Length;
|
||||
|
||||
// Calculate probabilities
|
||||
// Calculate probabilities for each unique value
|
||||
var groupedValues = values.GroupBy(x => x).Select(g => new { Value = g.Key, Count = g.Count() });
|
||||
|
||||
// Use the actual count of values for probability calculation
|
||||
// Calculate Shannon's entropy
|
||||
foreach (var group in groupedValues)
|
||||
{
|
||||
double probability = (double)group.Count / n;
|
||||
entropy -= probability * Math.Log2(probability);
|
||||
}
|
||||
|
||||
// Normalize the entropy based on the current number of unique values
|
||||
// Normalize by maximum possible entropy for current unique values
|
||||
int uniqueValueCount = groupedValues.Count();
|
||||
double maxEntropy = Math.Log2(uniqueValueCount);
|
||||
|
||||
@@ -116,7 +115,7 @@ public class Entropy : AbstractBase
|
||||
}
|
||||
else
|
||||
{
|
||||
entropy = 1; // Default to maximum entropy when insufficient data
|
||||
entropy = 1; // Maximum entropy when insufficient data
|
||||
}
|
||||
|
||||
IsHot = _buffer.Count >= Period;
|
||||
|
||||
+45
-54
@@ -1,38 +1,54 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates excess kurtosis using the Sheskin Algorithm.
|
||||
/// Measures the "tailedness" of the probability distribution of a real-valued random variable.
|
||||
/// Kurtosis: Distribution Tail Weight Measure
|
||||
/// A statistical measure that quantifies the "tailedness" of a distribution using
|
||||
/// the Sheskin Algorithm. Kurtosis indicates whether data has heavy tails (more
|
||||
/// outliers) or light tails (fewer outliers) compared to a normal distribution.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Kurtosis is a measure of the combined weight of a distribution's tails relative to the center of the distribution.
|
||||
/// In financial time series analysis, kurtosis can provide insights into:
|
||||
/// - The frequency and magnitude of extreme returns.
|
||||
/// - The potential for outliers or "black swan" events.
|
||||
/// - The shape of the return distribution compared to a normal distribution.
|
||||
/// The Kurtosis calculation process:
|
||||
/// 1. Calculates mean of the data
|
||||
/// 2. Computes squared and fourth power deviations
|
||||
/// 3. Applies Sheskin Algorithm for excess kurtosis
|
||||
/// 4. Adjusts for sample size bias
|
||||
///
|
||||
/// Interpretation:
|
||||
/// - Excess kurtosis > 0: Heavy-tailed distribution (more extreme values than a normal distribution)
|
||||
/// - Excess kurtosis = 0: Normal distribution
|
||||
/// - Excess kurtosis < 0: Light-tailed distribution (fewer extreme values than a normal distribution)
|
||||
/// Key characteristics:
|
||||
/// - Measures tail weight relative to normal distribution
|
||||
/// - Positive values indicate heavy tails
|
||||
/// - Negative values indicate light tails
|
||||
/// - Zero indicates normal distribution
|
||||
/// - Sensitive to extreme values
|
||||
///
|
||||
/// High kurtosis in financial returns may indicate a higher risk of extreme events.
|
||||
/// Formula:
|
||||
/// K = [n(n+1)Σ(x-μ)⁴] / [s⁴(n-1)(n-2)(n-3)] - [3(n-1)²]/[(n-2)(n-3)]
|
||||
/// where:
|
||||
/// n = sample size
|
||||
/// μ = mean
|
||||
/// s = standard deviation
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Identify potential for extreme moves
|
||||
/// - Assess risk of "black swan" events
|
||||
/// - Compare return distributions
|
||||
/// - Risk management tool
|
||||
///
|
||||
/// Sources:
|
||||
/// David J. Sheskin - "Handbook of Parametric and Nonparametric Statistical Procedures"
|
||||
/// https://en.wikipedia.org/wiki/Kurtosis
|
||||
///
|
||||
/// Note: Returns excess kurtosis (normal distribution = 0)
|
||||
/// </remarks>
|
||||
|
||||
public class Kurtosis : AbstractBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of data points to consider for the kurtosis calculation.
|
||||
/// </summary>
|
||||
private readonly int Period;
|
||||
private readonly CircularBuffer _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Kurtosis class.
|
||||
/// </summary>
|
||||
/// <param name="period">The number of data points to consider for calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the period is less than 4.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for kurtosis calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 4.</exception>
|
||||
public Kurtosis(int period)
|
||||
{
|
||||
if (period < 4)
|
||||
@@ -47,30 +63,20 @@ public class Kurtosis : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Kurtosis class with a data source.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object that publishes data.</param>
|
||||
/// <param name="period">The number of data points to consider.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for kurtosis calculation.</param>
|
||||
public Kurtosis(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the Kurtosis indicator to its initial state.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_buffer.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the indicator.
|
||||
/// </summary>
|
||||
/// <param name="isNew">Indicates if the current data point is new.</param>
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
@@ -80,22 +86,6 @@ public class Kurtosis : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the kurtosis calculation.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated excess kurtosis. Positive for heavy-tailed distributions,
|
||||
/// negative for light-tailed distributions.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Uses the Sheskin Algorithm for kurtosis calculation.
|
||||
/// Requires at least 4 data points for a valid calculation.
|
||||
///
|
||||
/// Interpretation of results:
|
||||
/// - Positive values indicate a distribution with heavier tails and a higher peak compared to a normal distribution.
|
||||
/// - Negative values indicate a distribution with lighter tails and a lower peak compared to a normal distribution.
|
||||
/// - A value close to 0 suggests a distribution similar to a normal distribution in terms of tailedness.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
@@ -103,14 +93,15 @@ public class Kurtosis : AbstractBase
|
||||
_buffer.Add(Input.Value, Input.IsNew);
|
||||
|
||||
double kurtosis = 0;
|
||||
if (_buffer.Count > 3)
|
||||
if (_buffer.Count > 3) // Need at least 4 points for valid calculation
|
||||
{
|
||||
var values = _buffer.GetSpan().ToArray();
|
||||
double mean = values.Average();
|
||||
double n = values.Length;
|
||||
|
||||
double s2 = 0;
|
||||
double s4 = 0;
|
||||
// Calculate squared and fourth power deviations
|
||||
double s2 = 0; // Sum of squared deviations
|
||||
double s4 = 0; // Sum of fourth power deviations
|
||||
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
@@ -121,7 +112,7 @@ public class Kurtosis : AbstractBase
|
||||
|
||||
double variance = s2 / (n - 1);
|
||||
|
||||
// Sheskin Algorithm
|
||||
// Sheskin Algorithm for excess kurtosis
|
||||
kurtosis = (n * (n + 1) * s4) / (variance * variance * (n - 3) * (n - 1) * (n - 2))
|
||||
- (3 * (n - 1) * (n - 1) / ((n - 2) * (n - 3)));
|
||||
}
|
||||
|
||||
+45
-66
@@ -1,63 +1,58 @@
|
||||
using System;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the maximum value over a specified period, with an optional decay factor.
|
||||
/// Useful for tracking the highest point in a time series with the ability to gradually forget old peaks.
|
||||
/// MAX: Maximum Value with Decay
|
||||
/// A statistical measure that tracks the highest value over a specified period,
|
||||
/// with an optional decay factor to gradually reduce the influence of older peaks.
|
||||
/// This adaptive approach allows the indicator to respond to changing market conditions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Max indicator is particularly useful in financial analysis for:
|
||||
/// - Identifying resistance levels in price charts.
|
||||
/// - Tracking the highest price over a given period.
|
||||
/// - Implementing trailing stop-loss strategies.
|
||||
/// The MAX calculation process:
|
||||
/// 1. Tracks highest value in current period
|
||||
/// 2. Applies exponential decay to old peaks
|
||||
/// 3. Adjusts decay based on time since last peak
|
||||
/// 4. Caps result at current period's maximum
|
||||
///
|
||||
/// The decay factor allows the indicator to adapt to changing market conditions by
|
||||
/// gradually reducing the influence of older maximum values.
|
||||
/// Key characteristics:
|
||||
/// - Tracks absolute highest values
|
||||
/// - Optional decay for adaptivity
|
||||
/// - Maintains historical context
|
||||
/// - Smooth transitions with decay
|
||||
/// - Period-based windowing
|
||||
///
|
||||
/// Formula:
|
||||
/// decay = 1 - e^(-halfLife * timeSinceMax / period)
|
||||
/// max = max - decay * (max - periodAverage)
|
||||
/// max = min(max, periodMaximum)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Identify resistance levels
|
||||
/// - Track price peaks
|
||||
/// - Implement trailing stops
|
||||
/// - Monitor price extremes
|
||||
/// - Adaptive trend following
|
||||
///
|
||||
/// Sources:
|
||||
/// Technical Analysis of Financial Markets
|
||||
/// https://www.investopedia.com/terms/r/resistance.asp
|
||||
///
|
||||
/// Note: Decay factor allows for adaptive peak tracking
|
||||
/// </remarks>
|
||||
|
||||
public class Max : AbstractBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of data points to consider for the maximum calculation.
|
||||
/// </summary>
|
||||
private readonly int Period;
|
||||
|
||||
/// <summary>
|
||||
/// Circular buffer to store the most recent data points.
|
||||
/// </summary>
|
||||
private readonly CircularBuffer _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// The half-life decay factor used to gradually forget old peaks.
|
||||
/// </summary>
|
||||
private readonly double _halfLife;
|
||||
|
||||
/// <summary>
|
||||
/// The current maximum value.
|
||||
/// </summary>
|
||||
private double _currentMax;
|
||||
|
||||
/// <summary>
|
||||
/// The previous maximum value.
|
||||
/// </summary>
|
||||
private double _p_currentMax;
|
||||
|
||||
/// <summary>
|
||||
/// The number of periods since a new maximum was set.
|
||||
/// </summary>
|
||||
private int _timeSinceNewMax;
|
||||
|
||||
/// <summary>
|
||||
/// The previous value of _timeSinceNewMax.
|
||||
/// </summary>
|
||||
private int _p_timeSinceNewMax;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Max class.
|
||||
/// </summary>
|
||||
/// <param name="period">The number of data points to consider. Must be at least 1.</param>
|
||||
/// <param name="decay">Half-life decay factor. Set to 0 for no decay, higher for faster forgetting of old peaks. Default is 0.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the period is less than 1 or decay is negative.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for maximum calculation.</param>
|
||||
/// <param name="decay">Half-life decay factor (0 for no decay, higher for faster forgetting).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1 or decay is negative.</exception>
|
||||
public Max(int period, double decay = 0)
|
||||
{
|
||||
if (period < 1)
|
||||
@@ -78,21 +73,15 @@ public class Max : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Max class with a data source.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object that publishes data.</param>
|
||||
/// <param name="period">The number of data points to consider.</param>
|
||||
/// <param name="decay">Half-life decay factor. Default is 0.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for maximum calculation.</param>
|
||||
/// <param name="decay">Half-life decay factor (default 0).</param>
|
||||
public Max(object source, int period, double decay = 0) : this(period, decay)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the Max indicator to its initial state.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
@@ -100,10 +89,6 @@ public class Max : AbstractBase
|
||||
_timeSinceNewMax = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the indicator.
|
||||
/// </summary>
|
||||
/// <param name="isNew">Indicates if the current data point is new.</param>
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
@@ -121,29 +106,23 @@ public class Max : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the max calculation.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The current maximum value, potentially adjusted by the decay factor.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Uses a decay factor to gradually forget old peaks. The max value is always
|
||||
/// capped by the highest value in the current period.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
_buffer.Add(Input.Value, Input.IsNew);
|
||||
|
||||
// Update maximum if new value is higher
|
||||
if (Input.Value >= _currentMax)
|
||||
{
|
||||
_currentMax = Input.Value;
|
||||
_timeSinceNewMax = 0;
|
||||
}
|
||||
|
||||
// Apply decay based on time since last maximum
|
||||
double decayRate = 1 - Math.Exp(-_halfLife * _timeSinceNewMax / Period);
|
||||
_currentMax -= decayRate * (_currentMax - _buffer.Average());
|
||||
|
||||
// Ensure maximum doesn't exceed current period's highest value
|
||||
_currentMax = Math.Min(_currentMax, _buffer.Max());
|
||||
|
||||
IsHot = true;
|
||||
|
||||
+44
-41
@@ -1,33 +1,52 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the median value over a specified period.
|
||||
/// Provides a measure of central tendency that is robust to outliers.
|
||||
/// Median: Central Tendency Measure
|
||||
/// A robust statistical measure that finds the middle value in a sorted dataset.
|
||||
/// The median is less sensitive to outliers than the mean, making it particularly
|
||||
/// useful for analyzing price data with extreme values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Median indicator is particularly useful in financial analysis for:
|
||||
/// - Providing a robust measure of central tendency that is less affected by extreme values than the mean.
|
||||
/// - Identifying the middle value in a dataset, which can be helpful in understanding price distributions.
|
||||
/// - Serving as a basis for other indicators or trading strategies that require a stable reference point.
|
||||
/// The Median calculation process:
|
||||
/// 1. Collects values over specified period
|
||||
/// 2. Sorts values in ascending order
|
||||
/// 3. Finds middle value(s)
|
||||
/// 4. Averages two middle values if even count
|
||||
///
|
||||
/// Unlike the mean, the median is not influenced by extreme outliers, making it valuable
|
||||
/// in markets with occasional large price swings or in the presence of data anomalies.
|
||||
/// Key characteristics:
|
||||
/// - Robust to outliers
|
||||
/// - Always represents actual data point
|
||||
/// - Splits dataset in half
|
||||
/// - More stable than mean
|
||||
/// - Maintains data scale
|
||||
///
|
||||
/// Formula:
|
||||
/// For odd n: median = value at position (n+1)/2
|
||||
/// For even n: median = (value at n/2 + value at (n/2)+1) / 2
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Price distribution analysis
|
||||
/// - Trend identification
|
||||
/// - Outlier detection
|
||||
/// - Support/resistance levels
|
||||
/// - Filter extreme movements
|
||||
///
|
||||
/// Sources:
|
||||
/// https://en.wikipedia.org/wiki/Median
|
||||
/// "Statistics for Trading" - Technical Analysis of Financial Markets
|
||||
///
|
||||
/// Note: More robust than mean for non-normal distributions
|
||||
/// </remarks>
|
||||
|
||||
public class Median : AbstractBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of data points to consider for the median calculation.
|
||||
/// </summary>
|
||||
private readonly int Period;
|
||||
private readonly CircularBuffer _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Median class.
|
||||
/// </summary>
|
||||
/// <param name="period">The number of data points to consider. Must be at least 1.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the period is less than 1.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for median calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
public Median(int period)
|
||||
{
|
||||
if (period < 1)
|
||||
@@ -42,30 +61,20 @@ public class Median : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Median class with a data source.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object that publishes data.</param>
|
||||
/// <param name="period">The number of data points to consider.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for median calculation.</param>
|
||||
public Median(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the Median indicator to its initial state.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_buffer.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the indicator.
|
||||
/// </summary>
|
||||
/// <param name="isNew">Indicates if the current data point is new.</param>
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
@@ -75,16 +84,6 @@ public class Median : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the median calculation.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The current median value of the dataset.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Uses a sorting approach to find the median. If there's not enough data,
|
||||
/// it uses the average as a temporary measure.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
@@ -93,11 +92,15 @@ public class Median : AbstractBase
|
||||
double median;
|
||||
if (_index >= Period)
|
||||
{
|
||||
// Get sorted copy of values
|
||||
var sortedValues = _buffer.GetSpan().ToArray();
|
||||
Array.Sort(sortedValues);
|
||||
int middleIndex = sortedValues.Length / 2;
|
||||
|
||||
median = (sortedValues.Length % 2 == 0) ? (sortedValues[middleIndex - 1] + sortedValues[middleIndex]) / 2.0 : sortedValues[middleIndex];
|
||||
// Calculate median based on odd/even count
|
||||
median = (sortedValues.Length % 2 == 0)
|
||||
? (sortedValues[middleIndex - 1] + sortedValues[middleIndex]) / 2.0
|
||||
: sortedValues[middleIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+45
-66
@@ -1,63 +1,58 @@
|
||||
using System;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a minimum value calculator with optional decay over a specified period.
|
||||
/// This class calculates the minimum value within a given period, with the ability to
|
||||
/// apply a decay factor to give more weight to recent values.
|
||||
/// MIN: Minimum Value with Decay
|
||||
/// A statistical measure that tracks the lowest value over a specified period,
|
||||
/// with an optional decay factor to gradually reduce the influence of older lows.
|
||||
/// This adaptive approach allows the indicator to respond to changing market conditions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Min class uses a circular buffer to store values and calculates the minimum
|
||||
/// efficiently. It also implements a decay mechanism to adjust the minimum value over
|
||||
/// time, allowing for a more responsive indicator in changing market conditions.
|
||||
/// The MIN calculation process:
|
||||
/// 1. Tracks lowest value in current period
|
||||
/// 2. Applies exponential decay to old lows
|
||||
/// 3. Adjusts decay based on time since last low
|
||||
/// 4. Caps result at current period's minimum
|
||||
///
|
||||
/// The decay factor allows the indicator to "forget" old minimum values gradually,
|
||||
/// which can be useful in adapting to new price trends or market regimes.
|
||||
/// Key characteristics:
|
||||
/// - Tracks absolute lowest values
|
||||
/// - Optional decay for adaptivity
|
||||
/// - Maintains historical context
|
||||
/// - Smooth transitions with decay
|
||||
/// - Period-based windowing
|
||||
///
|
||||
/// Formula:
|
||||
/// decay = 1 - e^(-halfLife * timeSinceMin / period)
|
||||
/// min = min + decay * (periodAverage - min)
|
||||
/// min = max(min, periodMinimum)
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Identify support levels
|
||||
/// - Track price troughs
|
||||
/// - Implement trailing stops
|
||||
/// - Monitor price extremes
|
||||
/// - Adaptive trend following
|
||||
///
|
||||
/// Sources:
|
||||
/// Technical Analysis of Financial Markets
|
||||
/// https://www.investopedia.com/terms/s/support.asp
|
||||
///
|
||||
/// Note: Decay factor allows for adaptive low tracking
|
||||
/// </remarks>
|
||||
|
||||
public class Min : AbstractBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of data points to consider for the minimum calculation.
|
||||
/// </summary>
|
||||
private readonly int Period;
|
||||
|
||||
/// <summary>
|
||||
/// Circular buffer to store the most recent data points.
|
||||
/// </summary>
|
||||
private readonly CircularBuffer _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// The half-life decay factor used to gradually forget old minimums.
|
||||
/// </summary>
|
||||
private readonly double _halfLife;
|
||||
|
||||
/// <summary>
|
||||
/// The current minimum value.
|
||||
/// </summary>
|
||||
private double _currentMin;
|
||||
|
||||
/// <summary>
|
||||
/// The previous minimum value.
|
||||
/// </summary>
|
||||
private double _p_currentMin;
|
||||
|
||||
/// <summary>
|
||||
/// The number of periods since a new minimum was set.
|
||||
/// </summary>
|
||||
private int _timeSinceNewMin;
|
||||
|
||||
/// <summary>
|
||||
/// The previous value of _timeSinceNewMin.
|
||||
/// </summary>
|
||||
private int _p_timeSinceNewMin;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Min class with the specified period and decay.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate the minimum value.</param>
|
||||
/// <param name="decay">The decay factor to apply to older values. Higher values cause faster forgetting of old minimums. Default is 0 (no decay).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 1 or decay is negative.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for minimum calculation.</param>
|
||||
/// <param name="decay">Half-life decay factor (0 for no decay, higher for faster forgetting).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1 or decay is negative.</exception>
|
||||
public Min(int period, double decay = 0)
|
||||
{
|
||||
if (period < 1)
|
||||
@@ -76,21 +71,15 @@ public class Min : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Min class with the specified source, period, and decay.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object to subscribe to for value updates.</param>
|
||||
/// <param name="period">The period over which to calculate the minimum value.</param>
|
||||
/// <param name="decay">The decay factor to apply to older values. Higher values cause faster forgetting of old minimums. Default is 0 (no decay).</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for minimum calculation.</param>
|
||||
/// <param name="decay">Half-life decay factor (default 0).</param>
|
||||
public Min(object source, int period, double decay = 0) : this(period, decay)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Min instance by setting initial values.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
@@ -98,10 +87,6 @@ public class Min : AbstractBase
|
||||
_timeSinceNewMin = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Min 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)
|
||||
@@ -119,29 +104,23 @@ public class Min : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the minimum value calculation with decay.
|
||||
/// </summary>
|
||||
/// <returns>The calculated minimum value for the current period.</returns>
|
||||
/// <remarks>
|
||||
/// This method updates the current minimum value based on the input, applies the decay
|
||||
/// factor, and ensures the result is not lower than the actual minimum in the buffer.
|
||||
/// The decay rate is calculated using an exponential function based on the time since
|
||||
/// the last new minimum and the specified half-life.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
_buffer.Add(Input.Value, Input.IsNew);
|
||||
|
||||
// Update minimum if new value is lower
|
||||
if (Input.Value <= _currentMin)
|
||||
{
|
||||
_currentMin = Input.Value;
|
||||
_timeSinceNewMin = 0;
|
||||
}
|
||||
|
||||
// Apply decay based on time since last minimum
|
||||
double decayRate = 1 - Math.Exp(-_halfLife * _timeSinceNewMin / Period);
|
||||
_currentMin += decayRate * (_buffer.Average() - _currentMin);
|
||||
|
||||
// Ensure minimum doesn't fall below current period's lowest value
|
||||
_currentMin = Math.Max(_currentMin, _buffer.Min());
|
||||
|
||||
IsHot = true;
|
||||
|
||||
+50
-50
@@ -1,34 +1,52 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a mode calculator that determines the most frequent value in a specified period.
|
||||
/// If multiple values have the same highest frequency, it returns their average.
|
||||
/// MODE: Most Frequent Value Measure
|
||||
/// A statistical measure that identifies the most frequently occurring value(s)
|
||||
/// in a dataset. When multiple values share the highest frequency, it returns
|
||||
/// their average to provide a representative central value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Mode class uses a circular buffer to store values and calculates the mode
|
||||
/// efficiently. Before the specified period is reached, it returns the average of
|
||||
/// the available values as an approximation.
|
||||
/// The Mode calculation process:
|
||||
/// 1. Groups values by frequency
|
||||
/// 2. Identifies highest frequency group(s)
|
||||
/// 3. Averages multiple modes if present
|
||||
/// 4. Uses mean until period filled
|
||||
///
|
||||
/// In financial analysis, the mode can be useful for:
|
||||
/// - Identifying the most common price levels, which could indicate support or resistance.
|
||||
/// - Analyzing the distribution of returns or other financial metrics.
|
||||
/// - Detecting patterns in trading volume or other discrete financial data.
|
||||
/// Key characteristics:
|
||||
/// - Identifies most common values
|
||||
/// - Handles multiple modes
|
||||
/// - Robust to distribution shape
|
||||
/// - Useful for discrete data
|
||||
/// - Returns actual data points
|
||||
///
|
||||
/// Formula:
|
||||
/// mode = value with highest frequency count
|
||||
/// if multiple modes: average of mode values
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Identify common price levels
|
||||
/// - Detect support/resistance zones
|
||||
/// - Analyze volume clusters
|
||||
/// - Find price congestion areas
|
||||
/// - Pattern recognition
|
||||
///
|
||||
/// Sources:
|
||||
/// https://en.wikipedia.org/wiki/Mode_(statistics)
|
||||
/// "Statistical Analysis in Financial Markets"
|
||||
///
|
||||
/// Note: Particularly useful for price level analysis
|
||||
/// </remarks>
|
||||
|
||||
public class Mode : AbstractBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of data points to consider for the mode calculation.
|
||||
/// </summary>
|
||||
private readonly int Period;
|
||||
private readonly CircularBuffer _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Mode class with the specified period.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate the mode.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 1.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for mode calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
|
||||
public Mode(int period)
|
||||
{
|
||||
if (period < 1)
|
||||
@@ -42,30 +60,20 @@ public class Mode : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Mode 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 mode.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for mode calculation.</param>
|
||||
public Mode(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the Mode indicator to its initial state.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_buffer.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Mode 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,18 +83,6 @@ public class Mode : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the mode calculation for the current period.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated mode (most frequent value) for the current period.
|
||||
/// If multiple values have the same highest frequency, returns their average.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Before the specified period is reached, this method returns the average of
|
||||
/// the available values as an approximation of the mode. Once the period is
|
||||
/// reached, it calculates the true mode by grouping and counting the values.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
@@ -95,22 +91,26 @@ public class Mode : AbstractBase
|
||||
double mode;
|
||||
if (_index >= Period)
|
||||
{
|
||||
// Group values by frequency and order by count
|
||||
var values = _buffer.GetSpan().ToArray();
|
||||
var groupedValues = values.GroupBy(v => v)
|
||||
.OrderByDescending(g => g.Count())
|
||||
.ThenBy(g => g.Key)
|
||||
.ToList();
|
||||
.OrderByDescending(g => g.Count())
|
||||
.ThenBy(g => g.Key)
|
||||
.ToList();
|
||||
|
||||
// Find all values with highest frequency
|
||||
int maxCount = groupedValues.First().Count();
|
||||
var modes = groupedValues.TakeWhile(g => g.Count() == maxCount)
|
||||
.Select(g => g.Key)
|
||||
.ToList();
|
||||
.Select(g => g.Key)
|
||||
.ToList();
|
||||
|
||||
mode = modes.Average(); // If there are multiple modes, we return their average
|
||||
// Average multiple modes if present
|
||||
mode = modes.Average();
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = _buffer.Average(); // Use average until we have enough data points
|
||||
// Use average until we have enough data points
|
||||
mode = _buffer.Average();
|
||||
}
|
||||
|
||||
IsHot = _index >= WarmupPeriod;
|
||||
|
||||
@@ -1,40 +1,54 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a percentile calculator that determines the value at a specified percentile
|
||||
/// in a given period of data points.
|
||||
/// Percentile: Distribution Position Measure
|
||||
/// A statistical measure that indicates the value below which a given percentage
|
||||
/// of observations falls. Percentiles provide insights into data distribution
|
||||
/// and are particularly useful for risk assessment and outlier detection.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Percentile class uses a circular buffer to store values and calculates the
|
||||
/// percentile efficiently. It uses linear interpolation when the percentile falls
|
||||
/// between two data points. Before the specified period is reached, it returns the
|
||||
/// average of the available values as an approximation.
|
||||
/// The Percentile calculation process:
|
||||
/// 1. Sorts values in ascending order
|
||||
/// 2. Calculates position based on percentile
|
||||
/// 3. Interpolates between adjacent values
|
||||
/// 4. Uses mean until period filled
|
||||
///
|
||||
/// In financial analysis, percentiles are useful for:
|
||||
/// - Assessing the relative standing of a value within a distribution.
|
||||
/// - Identifying outliers or extreme values in financial data.
|
||||
/// - Creating risk measures, such as Value at Risk (VaR) calculations.
|
||||
/// - Analyzing the distribution of returns, trading volumes, or other financial metrics.
|
||||
/// Key characteristics:
|
||||
/// - Range specific value identification
|
||||
/// - Linear interpolation for precision
|
||||
/// - Distribution independent
|
||||
/// - Robust to outliers
|
||||
/// - Useful for risk metrics
|
||||
///
|
||||
/// Formula:
|
||||
/// position = (percentile/100) * (n-1)
|
||||
/// value = v[floor(pos)] + (v[ceil(pos)] - v[floor(pos)]) * (pos - floor(pos))
|
||||
/// where n = number of observations, v = sorted values
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Value at Risk (VaR) calculation
|
||||
/// - Risk management metrics
|
||||
/// - Performance analysis
|
||||
/// - Volatility assessment
|
||||
/// - Outlier detection
|
||||
///
|
||||
/// Sources:
|
||||
/// https://en.wikipedia.org/wiki/Percentile
|
||||
/// "Risk Management in Trading" - Davis Edwards
|
||||
///
|
||||
/// Note: Particularly useful for risk metrics like VaR
|
||||
/// </remarks>
|
||||
|
||||
public class Percentile : AbstractBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of data points to consider for the percentile calculation.
|
||||
/// </summary>
|
||||
private readonly int Period;
|
||||
|
||||
/// <summary>
|
||||
/// The percentile to calculate (between 0 and 100).
|
||||
/// </summary>
|
||||
private readonly double Percent;
|
||||
|
||||
private readonly CircularBuffer _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Percentile class with the specified period and percentile.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate the percentile.</param>
|
||||
/// <param name="percent">The percentile to calculate (between 0 and 100).</param>
|
||||
/// <param name="period">The number of points to consider for percentile calculation.</param>
|
||||
/// <param name="percent">The percentile to calculate (0-100).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 2 or percent is not between 0 and 100.
|
||||
/// </exception>
|
||||
@@ -42,11 +56,13 @@ public class Percentile : AbstractBase
|
||||
{
|
||||
if (period < 2)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2 for percentile calculation.");
|
||||
throw new ArgumentOutOfRangeException(nameof(period),
|
||||
"Period must be greater than or equal to 2 for percentile calculation.");
|
||||
}
|
||||
if (percent < 0 || percent > 100)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(percent), "Percent must be between 0 and 100.");
|
||||
throw new ArgumentOutOfRangeException(nameof(percent),
|
||||
"Percent must be between 0 and 100.");
|
||||
}
|
||||
Period = period;
|
||||
Percent = percent;
|
||||
@@ -56,31 +72,21 @@ public class Percentile : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Percentile class with the specified source, period, and percentile.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object to subscribe to for value updates.</param>
|
||||
/// <param name="period">The period over which to calculate the percentile.</param>
|
||||
/// <param name="percent">The percentile to calculate (between 0 and 100).</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for percentile calculation.</param>
|
||||
/// <param name="percent">The percentile to calculate (0-100).</param>
|
||||
public Percentile(object source, int period, double percent) : this(period, percent)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Percentile instance by clearing the buffer.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_buffer.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Percentile 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)
|
||||
@@ -90,18 +96,6 @@ public class Percentile : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the percentile calculation for the current period.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated percentile value for the current period.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method uses linear interpolation when the percentile falls between two data points.
|
||||
/// Before the specified period is reached, it returns the average of the available values
|
||||
/// as an approximation. Once the period is reached, it calculates the true percentile by
|
||||
/// sorting the values and interpolating as necessary.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
@@ -110,6 +104,7 @@ public class Percentile : AbstractBase
|
||||
double result;
|
||||
if (_buffer.Count >= Period)
|
||||
{
|
||||
// Sort values and calculate percentile position
|
||||
var values = _buffer.GetSpan().ToArray();
|
||||
Array.Sort(values);
|
||||
|
||||
@@ -123,7 +118,7 @@ public class Percentile : AbstractBase
|
||||
}
|
||||
else
|
||||
{
|
||||
// Interpolate between the two nearest values
|
||||
// Linear interpolation between adjacent values
|
||||
double lowerValue = values[lowerIndex];
|
||||
double upperValue = values[upperIndex];
|
||||
double fraction = position - lowerIndex;
|
||||
@@ -132,7 +127,7 @@ public class Percentile : AbstractBase
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use average for insufficient data, like the Median class
|
||||
// Use average until we have enough data points
|
||||
result = _buffer.Average();
|
||||
}
|
||||
|
||||
|
||||
+50
-59
@@ -1,44 +1,62 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a skewness calculator that measures the asymmetry of the probability
|
||||
/// distribution of a real-valued random variable about its mean.
|
||||
/// SKEW: Distribution Asymmetry Measure
|
||||
/// A statistical measure that quantifies the asymmetry of a probability distribution
|
||||
/// around its mean. Skewness indicates whether deviations from the mean are more
|
||||
/// likely in one direction than the other.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Skew class uses a circular buffer to store values and calculates the skewness
|
||||
/// efficiently. It uses the adjusted Fisher-Pearson standardized moment coefficient
|
||||
/// for sample skewness calculation. A minimum of 3 data points is required for the
|
||||
/// calculation.
|
||||
/// The Skew calculation process:
|
||||
/// 1. Calculates mean of the data
|
||||
/// 2. Computes deviations from mean
|
||||
/// 3. Calculates third moment (cubed deviations)
|
||||
/// 4. Normalizes by standard deviation cubed
|
||||
///
|
||||
/// In financial analysis, skewness is important for:
|
||||
/// - Assessing the asymmetry of returns distribution.
|
||||
/// - Evaluating the risk of extreme events in either direction.
|
||||
/// - Complementing other risk measures like standard deviation.
|
||||
/// - Informing investment decisions and risk management strategies.
|
||||
/// Key characteristics:
|
||||
/// - Measures distribution asymmetry
|
||||
/// - Positive values indicate right skew
|
||||
/// - Negative values indicate left skew
|
||||
/// - Zero indicates symmetry
|
||||
/// - Scale-independent measure
|
||||
///
|
||||
/// Positive skewness indicates a longer tail on the right side of the distribution,
|
||||
/// while negative skewness indicates a longer tail on the left side.
|
||||
/// Formula:
|
||||
/// skew = [√(n(n-1))/(n-2)] * [m₃/s³]
|
||||
/// where:
|
||||
/// m₃ = third moment about the mean
|
||||
/// s = standard deviation
|
||||
/// n = sample size
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Risk assessment in returns
|
||||
/// - Options pricing models
|
||||
/// - Trading strategy development
|
||||
/// - Portfolio risk management
|
||||
/// - Market sentiment analysis
|
||||
///
|
||||
/// Sources:
|
||||
/// Fisher-Pearson standardized moment coefficient
|
||||
/// https://en.wikipedia.org/wiki/Skewness
|
||||
/// "The Analysis of Financial Time Series" - Ruey S. Tsay
|
||||
///
|
||||
/// Note: Requires minimum of 3 data points for calculation
|
||||
/// </remarks>
|
||||
|
||||
public class Skew : AbstractBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of data points to consider for the skewness calculation.
|
||||
/// </summary>
|
||||
private readonly int Period;
|
||||
private readonly CircularBuffer _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Skew class with the specified period.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate the skewness.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 3.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for skewness calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 3.</exception>
|
||||
public Skew(int period)
|
||||
{
|
||||
if (period < 3)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 3 for skewness calculation.");
|
||||
throw new ArgumentOutOfRangeException(nameof(period),
|
||||
"Period must be greater than or equal to 3 for skewness calculation.");
|
||||
}
|
||||
Period = period;
|
||||
WarmupPeriod = 3;
|
||||
@@ -47,30 +65,20 @@ public class Skew : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Skew 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 skewness.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for skewness calculation.</param>
|
||||
public Skew(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Skew instance by clearing the buffer.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_buffer.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Skew 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)
|
||||
@@ -80,36 +88,19 @@ public class Skew : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the skewness calculation for the current period.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated skewness value for the current period.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method uses the adjusted Fisher-Pearson standardized moment coefficient
|
||||
/// to calculate the sample skewness. It requires at least 3 data points for the
|
||||
/// calculation. If there are fewer than 3 data points, or if the standard
|
||||
/// deviation is zero, the method returns 0.
|
||||
///
|
||||
/// Interpretation of results:
|
||||
/// - Positive values indicate right-skewed distribution (longer tail on the right side).
|
||||
/// - Negative values indicate left-skewed distribution (longer tail on the left side).
|
||||
/// - Values close to 0 suggest a relatively symmetric distribution.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
_buffer.Add(Input.Value, Input.IsNew);
|
||||
|
||||
double skew = 0;
|
||||
if (_buffer.Count >= 3)
|
||||
{ // We need at least 3 data points for skewness
|
||||
if (_buffer.Count >= 3) // Need at least 3 points for skewness
|
||||
{
|
||||
var values = _buffer.GetSpan().ToArray();
|
||||
double mean = values.Average();
|
||||
double n = values.Length;
|
||||
|
||||
// Calculate third and second moments
|
||||
double sumCubedDeviations = 0;
|
||||
double sumSquaredDeviations = 0;
|
||||
|
||||
@@ -120,13 +111,13 @@ public class Skew : AbstractBase
|
||||
sumSquaredDeviations += Math.Pow(deviation, 2);
|
||||
}
|
||||
|
||||
// Calculate sample skewness using the adjusted Fisher-Pearson standardized moment coefficient
|
||||
// Fisher-Pearson standardized moment coefficient
|
||||
double m3 = sumCubedDeviations / n;
|
||||
double m2 = sumSquaredDeviations / n;
|
||||
double s3 = Math.Pow(m2, 1.5);
|
||||
|
||||
if (s3 != 0)
|
||||
{ // Avoid division by zero
|
||||
if (s3 != 0) // Avoid division by zero
|
||||
{
|
||||
skew = (Math.Sqrt(n * (n - 1)) / (n - 2)) * (m3 / s3);
|
||||
}
|
||||
}
|
||||
|
||||
+50
-64
@@ -1,52 +1,68 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a slope calculator that performs linear regression on a series of data points.
|
||||
/// SLOPE: Linear Regression Trend Measure
|
||||
/// A statistical measure that calculates the rate of change using linear regression.
|
||||
/// Slope indicates the direction and steepness of a trend, providing insights into
|
||||
/// momentum and potential trend changes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Slope class calculates the slope of a linear regression line, along with other
|
||||
/// statistical measures such as intercept, standard deviation, R-squared, and the last
|
||||
/// point on the regression line. It uses the least squares method for calculation.
|
||||
/// The Slope calculation process:
|
||||
/// 1. Calculates means of x and y values
|
||||
/// 2. Computes deviations from means
|
||||
/// 3. Applies least squares method
|
||||
/// 4. Provides additional regression statistics
|
||||
///
|
||||
/// In financial analysis, slope is important for:
|
||||
/// - Identifying trends in price movements or other financial metrics.
|
||||
/// - Measuring the rate of change in a financial time series.
|
||||
/// - Assessing the strength and direction of relationships between variables.
|
||||
/// - Supporting technical analysis indicators and trading strategies.
|
||||
/// Key characteristics:
|
||||
/// - Measures trend direction and strength
|
||||
/// - Provides rate of change
|
||||
/// - Scale-dependent measure
|
||||
/// - Includes regression statistics
|
||||
/// - Time-weighted calculation
|
||||
///
|
||||
/// Formula:
|
||||
/// slope = Σ((x - x̄)(y - ȳ)) / Σ((x - x̄)²)
|
||||
/// where:
|
||||
/// x = time points
|
||||
/// y = price values
|
||||
/// x̄, ȳ = respective means
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Trend identification
|
||||
/// - Momentum measurement
|
||||
/// - Support/resistance angles
|
||||
/// - Price target projection
|
||||
/// - Trend strength analysis
|
||||
///
|
||||
/// Sources:
|
||||
/// https://en.wikipedia.org/wiki/Simple_linear_regression
|
||||
/// "Technical Analysis of Financial Markets" - John J. Murphy
|
||||
///
|
||||
/// Note: Provides additional regression statistics (R², intercept)
|
||||
/// </remarks>
|
||||
|
||||
public class Slope : AbstractBase
|
||||
{
|
||||
private readonly int _period;
|
||||
private readonly CircularBuffer _buffer;
|
||||
private readonly CircularBuffer _timeBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the y-intercept of the regression line.
|
||||
/// </summary>
|
||||
/// <summary>Gets the y-intercept of the regression line.</summary>
|
||||
public double? Intercept { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the standard deviation of the y-values.
|
||||
/// </summary>
|
||||
/// <summary>Gets the standard deviation of the y-values.</summary>
|
||||
public double? StdDev { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the R-squared value, indicating the goodness of fit of the regression line.
|
||||
/// </summary>
|
||||
/// <summary>Gets the R-squared value, indicating regression fit quality.</summary>
|
||||
public double? RSquared { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the y-value of the last point on the regression line.
|
||||
/// </summary>
|
||||
/// <summary>Gets the last point on the regression line.</summary>
|
||||
public double? Line { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Slope class with the specified period.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate the slope.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than or equal to 1.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for slope calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than or equal to 1.</exception>
|
||||
public Slope(int period)
|
||||
{
|
||||
if (period <= 1)
|
||||
@@ -59,24 +75,17 @@ public class Slope : AbstractBase
|
||||
_buffer = new CircularBuffer(period);
|
||||
_timeBuffer = new CircularBuffer(period);
|
||||
Name = $"Slope(period={period})";
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Slope 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 slope.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for slope calculation.</param>
|
||||
public Slope(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Slope instance by clearing buffers and resetting calculated values.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
@@ -88,10 +97,6 @@ public class Slope : AbstractBase
|
||||
Line = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Slope 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)
|
||||
@@ -101,25 +106,6 @@ public class Slope : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the slope calculation using linear regression for the current period.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated slope value for the current period.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method uses the least squares method to calculate the slope of the regression line.
|
||||
/// It also calculates and updates the Intercept, StdDev, RSquared, and Line properties.
|
||||
/// If there are fewer than 2 data points, or if the sum of squared x deviations is 0,
|
||||
/// the method returns 0 and sets the additional properties to null.
|
||||
///
|
||||
/// Interpretation of results:
|
||||
/// - Positive slope: Indicates an upward trend in the data.
|
||||
/// - Negative slope: Indicates a downward trend in the data.
|
||||
/// - Slope close to 0: Indicates a relatively flat or no clear trend in the data.
|
||||
/// The magnitude of the slope represents the rate of change in the dependent variable
|
||||
/// (y) for each unit change in the independent variable (x).
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
@@ -128,10 +114,9 @@ public class Slope : AbstractBase
|
||||
_timeBuffer.Add(Input.Time.Ticks, Input.IsNew);
|
||||
|
||||
double slope = 0;
|
||||
|
||||
if (_buffer.Count < 2)
|
||||
{
|
||||
return slope; // Return 0 when there are fewer than 2 points
|
||||
return slope; // Need at least 2 points
|
||||
}
|
||||
|
||||
int count = Math.Min(_buffer.Count, _period);
|
||||
@@ -147,7 +132,7 @@ public class Slope : AbstractBase
|
||||
double avgX = sumX / count;
|
||||
double avgY = sumY / count;
|
||||
|
||||
// Least squares method
|
||||
// Least squares regression
|
||||
double sumSqX = 0, sumSqY = 0, sumSqXY = 0;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@@ -160,6 +145,7 @@ public class Slope : AbstractBase
|
||||
|
||||
if (sumSqX > 0)
|
||||
{
|
||||
// Calculate slope and related statistics
|
||||
slope = sumSqXY / sumSqX;
|
||||
Intercept = avgY - (slope * avgX);
|
||||
|
||||
@@ -174,7 +160,7 @@ public class Slope : AbstractBase
|
||||
RSquared = r * r;
|
||||
}
|
||||
|
||||
// Calculate last Line value (y = mx + b)
|
||||
// Calculate regression line endpoint
|
||||
Line = (slope * count) + Intercept;
|
||||
}
|
||||
else
|
||||
|
||||
+50
-64
@@ -1,48 +1,63 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a standard deviation calculator that measures the amount of variation or
|
||||
/// dispersion of a set of values.
|
||||
/// STDDEV: Standard Deviation Volatility Measure
|
||||
/// A statistical measure that quantifies the amount of variation or dispersion
|
||||
/// in a dataset. Standard deviation is widely used in finance as a measure of
|
||||
/// volatility and risk assessment.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Stddev class calculates either the population standard deviation or the sample
|
||||
/// standard deviation based on the isPopulation parameter. It uses a circular buffer
|
||||
/// to efficiently manage the data points within the specified period.
|
||||
/// The StdDev calculation process:
|
||||
/// 1. Calculates mean of the data
|
||||
/// 2. Computes squared deviations from mean
|
||||
/// 3. Averages squared deviations
|
||||
/// 4. Takes square root of average
|
||||
///
|
||||
/// In financial analysis, standard deviation is important for:
|
||||
/// - Measuring volatility of financial instruments or portfolios.
|
||||
/// - Assessing risk in investments.
|
||||
/// - Calculating Sharpe ratios and other risk-adjusted performance measures.
|
||||
/// - Identifying potential outliers or unusual market behavior.
|
||||
/// Key characteristics:
|
||||
/// - Measures data dispersion
|
||||
/// - Same units as input data
|
||||
/// - Sensitive to outliers
|
||||
/// - Population or sample versions
|
||||
/// - Key volatility indicator
|
||||
///
|
||||
/// Formula:
|
||||
/// Population: σ = √(Σ(x - μ)² / N)
|
||||
/// Sample: s = √(Σ(x - x̄)² / (n-1))
|
||||
/// where:
|
||||
/// x = values
|
||||
/// μ, x̄ = mean
|
||||
/// N, n = count
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Volatility measurement
|
||||
/// - Risk assessment
|
||||
/// - Bollinger Bands
|
||||
/// - Option pricing
|
||||
/// - Portfolio management
|
||||
///
|
||||
/// Sources:
|
||||
/// https://en.wikipedia.org/wiki/Standard_deviation
|
||||
/// "Options, Futures, and Other Derivatives" - John C. Hull
|
||||
///
|
||||
/// Note: Foundation for many volatility-based indicators
|
||||
/// </remarks>
|
||||
|
||||
public class Stddev : AbstractBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether to calculate population (true) or sample (false) standard deviation.
|
||||
/// </summary>
|
||||
private readonly bool IsPopulation;
|
||||
|
||||
/// <summary>
|
||||
/// Circular buffer to store the most recent data points.
|
||||
/// </summary>
|
||||
private readonly CircularBuffer _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Stddev class with the specified period and
|
||||
/// population flag.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate the standard deviation.</param>
|
||||
/// <param name="isPopulation">
|
||||
/// A flag indicating whether to calculate population (true) or sample (false) standard deviation.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 2.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for standard deviation calculation.</param>
|
||||
/// <param name="isPopulation">True for population stddev, false for sample stddev (default).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 2.</exception>
|
||||
public Stddev(int period, bool isPopulation = false)
|
||||
{
|
||||
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.");
|
||||
}
|
||||
IsPopulation = isPopulation;
|
||||
WarmupPeriod = 0;
|
||||
@@ -51,34 +66,21 @@ public class Stddev : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Stddev class with the specified source, period,
|
||||
/// and population flag.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object to subscribe to for value updates.</param>
|
||||
/// <param name="period">The period over which to calculate the standard deviation.</param>
|
||||
/// <param name="isPopulation">
|
||||
/// A flag indicating whether to calculate population (true) or sample (false) standard deviation.
|
||||
/// </param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for standard deviation calculation.</param>
|
||||
/// <param name="isPopulation">True for population stddev, false for sample stddev (default).</param>
|
||||
public Stddev(object source, int period, bool isPopulation = false) : this(period, isPopulation)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Stddev instance by clearing the buffer.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_buffer.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Stddev 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)
|
||||
@@ -88,28 +90,9 @@ public class Stddev : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the standard deviation calculation for the current period.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated standard deviation value for the current period.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method calculates the standard deviation using the formula:
|
||||
/// sqrt(sum((x - mean)^2) / n) for population, or
|
||||
/// sqrt(sum((x - mean)^2) / (n - 1)) for sample,
|
||||
/// where x is each value, mean is the average of all values, and n is the number of values.
|
||||
/// If there's only one value in the buffer, the method returns 0.
|
||||
///
|
||||
/// Interpretation of results:
|
||||
/// - A low standard deviation indicates that the values tend to be close to the mean.
|
||||
/// - A high standard deviation indicates that the values are spread out over a wider range.
|
||||
/// - In financial contexts, higher standard deviation often implies higher volatility or risk.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
_buffer.Add(Input.Value, Input.IsNew);
|
||||
|
||||
double stddev = 0;
|
||||
@@ -117,8 +100,11 @@ public class Stddev : AbstractBase
|
||||
{
|
||||
var values = _buffer.GetSpan().ToArray();
|
||||
double mean = values.Average();
|
||||
|
||||
// Calculate sum of squared deviations
|
||||
double sumOfSquaredDifferences = values.Sum(x => Math.Pow(x - mean, 2));
|
||||
|
||||
// Use appropriate divisor based on population/sample calculation
|
||||
double divisor = IsPopulation ? _buffer.Count : _buffer.Count - 1;
|
||||
double variance = sumOfSquaredDifferences / divisor;
|
||||
stddev = Math.Sqrt(variance);
|
||||
|
||||
+50
-65
@@ -1,48 +1,63 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a variance calculator that measures the spread of a set of numbers
|
||||
/// from their average value.
|
||||
/// VARIANCE: Squared Deviation Risk Measure
|
||||
/// A statistical measure that quantifies the spread of data points around their
|
||||
/// mean value. Variance is fundamental to risk assessment and portfolio theory,
|
||||
/// providing the basis for many financial models.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Variance class calculates either the population variance or the sample
|
||||
/// variance based on the isPopulation parameter. It uses a circular buffer
|
||||
/// to efficiently manage the data points within the specified period.
|
||||
/// The Variance calculation process:
|
||||
/// 1. Calculates mean of the data
|
||||
/// 2. Computes squared deviations from mean
|
||||
/// 3. Sums squared deviations
|
||||
/// 4. Divides by n or (n-1)
|
||||
///
|
||||
/// In financial analysis, variance is important for:
|
||||
/// - Measuring the dispersion of returns around the mean.
|
||||
/// - Assessing risk and volatility in financial instruments or portfolios.
|
||||
/// - Serving as a basis for other risk measures like standard deviation and beta.
|
||||
/// - Contributing to portfolio optimization techniques, such as Modern Portfolio Theory.
|
||||
/// Key characteristics:
|
||||
/// - Measures data dispersion
|
||||
/// - Squared units of input data
|
||||
/// - Always non-negative
|
||||
/// - Population or sample versions
|
||||
/// - Foundation for risk metrics
|
||||
///
|
||||
/// Formula:
|
||||
/// Population: σ² = Σ(x - μ)² / N
|
||||
/// Sample: s² = Σ(x - x̄)² / (n-1)
|
||||
/// where:
|
||||
/// x = values
|
||||
/// μ, x̄ = mean
|
||||
/// N, n = count
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Portfolio optimization
|
||||
/// - Risk measurement
|
||||
/// - Modern Portfolio Theory
|
||||
/// - Asset allocation
|
||||
/// - Volatility analysis
|
||||
///
|
||||
/// Sources:
|
||||
/// Harry Markowitz - "Portfolio Selection" (1952)
|
||||
/// https://en.wikipedia.org/wiki/Variance
|
||||
///
|
||||
/// Note: Basis for Modern Portfolio Theory and risk models
|
||||
/// </remarks>
|
||||
|
||||
public class Variance : AbstractBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether to calculate population (true) or sample (false) variance.
|
||||
/// </summary>
|
||||
private readonly bool IsPopulation;
|
||||
|
||||
/// <summary>
|
||||
/// Circular buffer to store the most recent data points.
|
||||
/// </summary>
|
||||
private readonly CircularBuffer _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Variance class with the specified period and
|
||||
/// population flag.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate the variance.</param>
|
||||
/// <param name="isPopulation">
|
||||
/// A flag indicating whether to calculate population (true) or sample (false) variance.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 2.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for variance calculation.</param>
|
||||
/// <param name="isPopulation">True for population variance, false for sample variance (default).</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 2.</exception>
|
||||
public Variance(int period, bool isPopulation = false)
|
||||
{
|
||||
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.");
|
||||
}
|
||||
IsPopulation = isPopulation;
|
||||
WarmupPeriod = 0;
|
||||
@@ -51,34 +66,21 @@ public class Variance : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Variance class with the specified source, period,
|
||||
/// and population flag.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object to subscribe to for value updates.</param>
|
||||
/// <param name="period">The period over which to calculate the variance.</param>
|
||||
/// <param name="isPopulation">
|
||||
/// A flag indicating whether to calculate population (true) or sample (false) variance.
|
||||
/// </param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for variance calculation.</param>
|
||||
/// <param name="isPopulation">True for population variance, false for sample variance (default).</param>
|
||||
public Variance(object source, int period, bool isPopulation = false) : this(period, isPopulation)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Variance instance by clearing the buffer.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_buffer.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Variance 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)
|
||||
@@ -88,29 +90,9 @@ public class Variance : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the variance calculation for the current period.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated variance value for the current period.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method calculates the variance using the formula:
|
||||
/// sum((x - mean)^2) / n for population, or
|
||||
/// sum((x - mean)^2) / (n - 1) for sample,
|
||||
/// where x is each value, mean is the average of all values, and n is the number of values.
|
||||
/// If there's only one value in the buffer, the method returns 0.
|
||||
///
|
||||
/// Interpretation of results:
|
||||
/// - A low variance indicates that the values tend to be close to the mean and to each other.
|
||||
/// - A high variance indicates that the values are spread out over a wider range.
|
||||
/// - In financial contexts, higher variance often implies higher volatility or risk.
|
||||
/// - Variance is always non-negative, and its units are squared units of the original data.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
_buffer.Add(Input.Value, Input.IsNew);
|
||||
|
||||
double variance = 0;
|
||||
@@ -118,8 +100,11 @@ public class Variance : AbstractBase
|
||||
{
|
||||
var values = _buffer.GetSpan().ToArray();
|
||||
double mean = values.Average();
|
||||
|
||||
// Calculate sum of squared deviations
|
||||
double sumOfSquaredDifferences = values.Sum(x => Math.Pow(x - mean, 2));
|
||||
|
||||
// Use appropriate divisor based on population/sample calculation
|
||||
double divisor = IsPopulation ? _buffer.Count : _buffer.Count - 1;
|
||||
variance = sumOfSquaredDifferences / divisor;
|
||||
}
|
||||
|
||||
+50
-63
@@ -1,44 +1,61 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Z-score calculator that measures how many standard deviations
|
||||
/// an element is from the mean of a set of values.
|
||||
/// ZSCORE: Standardized Distance Measure
|
||||
/// A statistical measure that indicates how many standard deviations an observation
|
||||
/// is from the mean. Z-scores normalize data to a standard scale, making it useful
|
||||
/// for comparing values across different distributions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Zscore class calculates the Z-score (also known as standard score) for
|
||||
/// the most recent value in a given period. It uses a circular buffer to
|
||||
/// efficiently manage the data points within the specified period.
|
||||
/// The Zscore calculation process:
|
||||
/// 1. Calculates mean of the period
|
||||
/// 2. Computes standard deviation
|
||||
/// 3. Measures distance from mean
|
||||
/// 4. Normalizes by standard deviation
|
||||
///
|
||||
/// In financial analysis, Z-score is important for:
|
||||
/// - Identifying outliers or unusual price movements.
|
||||
/// - Normalizing data across different scales or time periods.
|
||||
/// - Assessing the relative position of a value within its historical distribution.
|
||||
/// - Supporting trading strategies based on mean reversion or momentum.
|
||||
/// Key characteristics:
|
||||
/// - Scale-independent measure
|
||||
/// - Symmetric around zero
|
||||
/// - Normal distribution context
|
||||
/// - Outlier identification
|
||||
/// - Comparative analysis tool
|
||||
///
|
||||
/// Formula:
|
||||
/// Z = (x - μ) / σ
|
||||
/// where:
|
||||
/// x = current value
|
||||
/// μ = mean
|
||||
/// σ = standard deviation
|
||||
///
|
||||
/// Market Applications:
|
||||
/// - Mean reversion strategies
|
||||
/// - Overbought/oversold signals
|
||||
/// - Volatility breakouts
|
||||
/// - Cross-asset comparison
|
||||
/// - Statistical arbitrage
|
||||
///
|
||||
/// Sources:
|
||||
/// https://en.wikipedia.org/wiki/Standard_score
|
||||
/// "Statistical Analysis in Trading" - Technical Analysis
|
||||
///
|
||||
/// Note: Assumes approximately normal distribution
|
||||
/// </remarks>
|
||||
|
||||
public class Zscore : AbstractBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of data points to consider for the Z-score calculation.
|
||||
/// </summary>
|
||||
private readonly int Period;
|
||||
|
||||
/// <summary>
|
||||
/// Circular buffer to store the most recent data points.
|
||||
/// </summary>
|
||||
private readonly CircularBuffer _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Zscore class with the specified period.
|
||||
/// </summary>
|
||||
/// <param name="period">The period over which to calculate the Z-score.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when period is less than 2.
|
||||
/// </exception>
|
||||
/// <param name="period">The number of points to consider for Z-score calculation.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 2.</exception>
|
||||
public Zscore(int period)
|
||||
{
|
||||
if (period < 2)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2 for Z-score calculation.");
|
||||
throw new ArgumentOutOfRangeException(nameof(period),
|
||||
"Period must be greater than or equal to 2 for Z-score calculation.");
|
||||
}
|
||||
Period = period;
|
||||
WarmupPeriod = 2;
|
||||
@@ -47,30 +64,20 @@ public class Zscore : AbstractBase
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Zscore 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 Z-score.</param>
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="period">The number of points to consider for Z-score calculation.</param>
|
||||
public Zscore(object source, int period) : this(period)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Zscore instance by clearing the buffer.
|
||||
/// </summary>
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_buffer.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the state of the Zscore 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)
|
||||
@@ -80,44 +87,24 @@ public class Zscore : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the Z-score calculation for the current period.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The calculated Z-score value for the most recent input in the current period.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method calculates the Z-score using the formula:
|
||||
/// Z = (x - μ) / σ
|
||||
/// where x is the input value, μ is the mean of the period, and σ is the sample standard deviation.
|
||||
/// If there are fewer than 2 data points or if the standard deviation is 0, the method returns 0.
|
||||
///
|
||||
/// Interpretation of results:
|
||||
/// - A Z-score of 0 indicates that the data point is exactly on the mean.
|
||||
/// - A positive Z-score indicates the data point is above the mean.
|
||||
/// - A negative Z-score indicates the data point is below the mean.
|
||||
/// - The magnitude of the Z-score represents how many standard deviations away from the mean the data point is.
|
||||
/// - In a normal distribution, about 68% of the values have a Z-score between -1 and 1,
|
||||
/// 95% between -2 and 2, and 99.7% between -3 and 3.
|
||||
/// </remarks>
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
|
||||
_buffer.Add(Input.Value, Input.IsNew);
|
||||
|
||||
double zScore = 0;
|
||||
if (_buffer.Count >= 2)
|
||||
{ // We need at least 2 data points for Z-score
|
||||
if (_buffer.Count >= 2) // Need at least 2 points for standard deviation
|
||||
{
|
||||
var values = _buffer.GetSpan().ToArray();
|
||||
double mean = values.Average();
|
||||
double n = values.Length;
|
||||
|
||||
// Calculate sample standard deviation
|
||||
double sumSquaredDeviations = values.Sum(x => Math.Pow(x - mean, 2));
|
||||
double standardDeviation = Math.Sqrt(sumSquaredDeviations / (n - 1)); // Sample standard deviation
|
||||
double standardDeviation = Math.Sqrt(sumSquaredDeviations / (n - 1));
|
||||
|
||||
if (standardDeviation != 0)
|
||||
{ // Avoid division by zero
|
||||
if (standardDeviation != 0) // Avoid division by zero
|
||||
{
|
||||
zScore = (Input.Value - mean) / standardDeviation;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user