This commit is contained in:
Miha Kralj
2024-10-04 21:31:25 -07:00
parent 99a3785d72
commit 30d93e724d
10 changed files with 413 additions and 1 deletions
+85
View File
@@ -0,0 +1,85 @@
namespace QuanTAlib;
public class Historical : AbstractBase
{
private readonly int Period;
private readonly bool IsAnnualized;
private readonly CircularBuffer _buffer;
private readonly CircularBuffer _logReturns;
private double _previousClose;
public Historical(int period, bool isAnnualized = true) : base()
{
if (period < 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
_buffer = new CircularBuffer(period + 1);
_logReturns = new CircularBuffer(period);
Name = $"Historical(period={period}, annualized={isAnnualized})";
Init();
}
public Historical(object source, int period, bool isAnnualized = true) : this(period, isAnnualized)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
public override void Init()
{
base.Init();
_buffer.Clear();
_logReturns.Clear();
_previousClose = 0;
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
_buffer.Add(Input.Value, Input.IsNew);
double volatility = 0;
if (_buffer.Count > 1)
{
if (_previousClose != 0)
{
double logReturn = Math.Log(Input.Value / _previousClose);
_logReturns.Add(logReturn, Input.IsNew);
}
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
volatility = Math.Sqrt(variance);
if (IsAnnualized)
{
// Assuming 252 trading days in a year. Adjust as needed.
volatility *= Math.Sqrt(252);
}
}
}
_previousClose = Input.Value;
IsHot = _index >= WarmupPeriod;
return volatility;
}
}
+76
View File
@@ -0,0 +1,76 @@
namespace QuanTAlib;
public class Realized : AbstractBase
{
private readonly int Period;
private readonly bool IsAnnualized;
private readonly CircularBuffer _returns;
private double _previousClose;
private double _sumSquaredReturns;
public Realized(int period, bool isAnnualized = true) : base()
{
if (period < 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
_returns = new CircularBuffer(period);
Name = $"Realized(period={period}, annualized={isAnnualized})";
Init();
}
public override void Init()
{
base.Init();
_returns.Clear();
_previousClose = 0;
_sumSquaredReturns = 0;
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
double volatility = 0;
if (_previousClose != 0)
{
double logReturn = Math.Log(Input.Value / _previousClose);
if (_returns.Count == Period)
{
// Remove the oldest squared return from the sum
_sumSquaredReturns -= Math.Pow(_returns[0], 2);
}
_returns.Add(logReturn, Input.IsNew);
_sumSquaredReturns += Math.Pow(logReturn, 2);
if (_returns.Count == Period)
{
double variance = _sumSquaredReturns / Period;
volatility = Math.Sqrt(variance);
if (IsAnnualized)
{
// Assuming 252 trading days in a year. Adjust as needed.
volatility *= Math.Sqrt(252);
}
}
}
_previousClose = Input.Value;
IsHot = _index >= WarmupPeriod;
return volatility;
}
}
+87
View File
@@ -0,0 +1,87 @@
/*
Reference:
Donald Dorsey, who introduced the concept in the 1993 issue of Technical Analysis
of Stocks & Commodities Magazine. He designed the RVI to focus on the direction of
price movements in relation to volatility. Dorseys methodology is often cited in
technical analysis literature and further elaborated on in various technical analysis
guides and platforms.
*/
using System;
namespace QuanTAlib
{
public class Rvi : AbstractBase
{
private readonly int Period;
private Stddev _upStdDev, _downStdDev;
private Sma _upSma, _downSma;
private double _previousClose;
public Rvi(int period) : base()
{
if (period < 2)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2.");
}
Period = period;
WarmupPeriod = period;
Name = $"RVI(period={period})";
_upStdDev = new Stddev(Period);
_downStdDev = new Stddev(Period);
_upSma = new(Period);
_downSma = new(Period);
Init();
}
public Rvi(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
public override void Init()
{
base.Init();
_previousClose = 0;
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Value;
_index++;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
double close = Input.Value;
double change = close - _previousClose;
double upMove = Math.Max(change, 0);
double downMove = Math.Max(-change, 0);
_upSma.Calc(_upStdDev.Calc(new TValue(Input.Time, upMove, Input.IsNew)));
_downSma.Calc(_downStdDev.Calc(new TValue(Input.Time, downMove, Input.IsNew)));
double rvi;
if (_upSma.Value + _downSma.Value != 0)
{
rvi = 100 * _upSma.Value / (_upSma.Value + _downSma.Value);
}
else
{
rvi = 0;
}
_previousClose = close;
IsHot = _index >= WarmupPeriod;
return rvi;
}
}
}
+28
View File
@@ -0,0 +1,28 @@
Single Value Input (Typically Closing Prices)
Jurik Volatility (Volty)
**Standard Deviation**
**Relative Volatility Index (RVI)**
Ulcer Index
ARCH/GARCH Models
Exponential Weighted Moving Average (EWMA) Volatility
Conditional Volatility
Volatility Ratio
Close-to-Close Volatility
Volatility of Volatility (VOV)
Volatility Cone
Bollinger Bands
Stochastic Volatility: Typically modeled using closing prices, but can incorporate other price information
OHLC Input (Open, High, Low, Close)
Garman-Klass Volatility
Rogers-Satchell Volatility
Yang-Zhang Volatility
Parkinson Volatility (High, Low)
Average True Range (ATR) (High, Low, Close)
Chaikin Volatility (High, Low)
Keltner Channels (typically Close, High, Low)
High-Low Volatility (High, Low)