using System.Runtime.CompilerServices;
namespace QuanTAlib;
///
/// ADR: Average Daily Range
/// A volatility indicator that measures the average range of price movement over
/// a specified period. It helps identify normal trading ranges and potential
/// breakout levels.
///
///
/// The ADR calculation process:
/// 1. Calculate daily range (High - Low)
/// 2. Apply SMA to daily ranges
/// 3. Updates with each new price bar
///
/// Key characteristics:
/// - Simple volatility measure
/// - Period-based average
/// - Trend independent
/// - Absolute price measure
/// - Support/resistance aid
///
/// Formula:
/// Daily Range = High - Low
/// ADR = SMA(Daily Range, period)
///
/// Market Applications:
/// - Position sizing
/// - Volatility analysis
/// - Support/resistance levels
/// - Breakout identification
/// - Risk assessment
///
/// Note: Simpler alternative to ATR, doesn't consider gaps
///
[SkipLocalsInit]
public sealed class Adr : AbstractBase
{
private readonly Sma _ma;
private const int DefaultPeriod = 14;
/// The number of periods for ADR calculation (default 14).
/// Thrown when period is less than 1.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Adr(int period = DefaultPeriod)
{
if (period < 1)
throw new ArgumentOutOfRangeException(nameof(period));
_ma = new(period);
WarmupPeriod = period;
Name = $"ADR({period})";
}
/// The data source object that publishes updates.
/// The number of periods for ADR calculation.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Adr(object source, int period = DefaultPeriod) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override void ManageState(bool isNew)
{
if (isNew)
_index++;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
protected override double Calculation()
{
ManageState(BarInput.IsNew);
// Calculate daily range
double range = BarInput.High - BarInput.Low;
// Apply SMA smoothing
return _ma.Calc(range, BarInput.IsNew);
}
}