Files
QuanTAlib/lib/volatility/Atr.cs
T

124 lines
3.4 KiB
C#
Raw Normal View History

2024-10-27 09:38:53 -07:00
using System;
2024-09-30 06:46:07 -07:00
namespace QuanTAlib;
2024-10-05 15:20:13 -07:00
/// <summary>
2024-10-27 09:38:53 -07:00
/// ATR: Average True Range
/// A technical indicator that measures market volatility by decomposing the entire
/// range of an asset's price for a period. ATR accounts for gaps between periods
/// and provides a comprehensive view of price volatility.
2024-10-05 15:20:13 -07:00
/// </summary>
/// <remarks>
2024-10-27 09:38:53 -07:00
/// The ATR calculation process:
/// 1. Calculates True Range (TR) as maximum of:
/// - Current High - Current Low
/// - |Current High - Previous Close|
/// - |Current Low - Previous Close|
/// 2. Applies RMA smoothing to TR values
/// 3. Updates with each new price bar
/// 4. Adapts to changing volatility
///
/// Key characteristics:
/// - Absolute price measure
/// - Gap-inclusive calculation
/// - Trend independent
/// - Volatility focused
/// - Smoothed output
///
/// Formula:
/// TR = max(high-low, |high-prevClose|, |low-prevClose|)
/// ATR = RMA(TR, period)
///
/// Market Applications:
/// - Position sizing
/// - Stop loss placement
/// - Volatility breakouts
/// - Risk assessment
/// - Entry/exit timing
///
/// Sources:
/// J. Welles Wilder - "New Concepts in Technical Trading Systems"
/// https://www.investopedia.com/terms/a/atr.asp
///
/// Note: Higher ATR indicates higher volatility
2024-10-05 15:20:13 -07:00
/// </remarks>
2024-10-27 09:38:53 -07:00
2024-10-08 17:31:29 +00:00
public class Atr : AbstractBase
2024-10-06 06:59:26 +00:00
{
2024-10-21 16:06:47 -07:00
public double Tr { get; private set; }
private readonly Rma _ma;
2024-09-30 06:46:07 -07:00
private double _prevClose, _p_prevClose;
2024-10-27 09:38:53 -07:00
/// <param name="period">The number of periods for ATR calculation.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
2024-10-06 06:59:26 +00:00
public Atr(int period)
{
if (period < 1)
{
2024-10-27 09:38:53 -07:00
throw new ArgumentOutOfRangeException(nameof(period),
"Period must be greater than or equal to 1.");
2024-09-30 06:46:07 -07:00
}
2024-10-21 16:06:47 -07:00
_ma = new(period, useSma: true);
2024-09-30 06:46:07 -07:00
WarmupPeriod = _ma.WarmupPeriod;
2024-09-30 07:30:27 -07:00
Name = $"ATR({period})";
2024-09-30 06:46:07 -07:00
}
2024-10-27 09:38:53 -07:00
/// <param name="source">The data source object that publishes updates.</param>
/// <param name="period">The number of periods for ATR calculation.</param>
2024-10-06 06:59:26 +00:00
public Atr(object source, int period) : this(period)
{
2024-09-30 06:46:07 -07:00
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
}
2024-10-06 06:59:26 +00:00
public override void Init()
{
2024-09-30 06:46:07 -07:00
base.Init();
_ma.Init();
_prevClose = double.NaN;
2024-10-21 16:06:47 -07:00
Tr = 0;
2024-09-30 06:46:07 -07:00
}
2024-10-06 06:59:26 +00:00
protected override void ManageState(bool isNew)
{
if (isNew)
{
2024-09-30 06:46:07 -07:00
_index++;
_p_prevClose = _prevClose;
2024-10-06 06:59:26 +00:00
}
else
{
2024-09-30 06:46:07 -07:00
_prevClose = _p_prevClose;
}
}
2024-10-06 06:59:26 +00:00
protected override double Calculation()
{
2024-10-07 21:41:26 -07:00
ManageState(BarInput.IsNew);
2024-09-30 06:46:07 -07:00
2024-10-21 16:06:47 -07:00
if (_index == 1)
2024-10-06 06:59:26 +00:00
{
2024-10-27 09:38:53 -07:00
// First bar uses simple high-low range
2024-10-21 16:06:47 -07:00
Tr = BarInput.High - BarInput.Low;
_prevClose = BarInput.Close;
2024-09-30 06:46:07 -07:00
}
2024-10-21 16:06:47 -07:00
else
{
2024-10-27 09:38:53 -07:00
// Calculate True Range as maximum of three measures
2024-10-21 16:06:47 -07:00
Tr = Math.Max(
BarInput.High - BarInput.Low,
Math.Max(
Math.Abs(BarInput.High - _prevClose),
Math.Abs(BarInput.Low - _prevClose)
)
);
}
2024-10-27 09:38:53 -07:00
// Apply RMA smoothing to True Range
2024-10-21 16:06:47 -07:00
_ma.Calc(new TValue(Input.Time, Tr, BarInput.IsNew));
2024-09-30 06:46:07 -07:00
IsHot = _ma.IsHot;
2024-10-07 21:41:26 -07:00
_prevClose = BarInput.Close;
2024-10-21 16:06:47 -07:00
return _ma.Value;
2024-09-30 06:46:07 -07:00
}
}