diff --git a/Tests/test_updates_momentum.cs b/Tests/test_updates_momentum.cs index 3ca93dcc..7bfe4a92 100644 --- a/Tests/test_updates_momentum.cs +++ b/Tests/test_updates_momentum.cs @@ -199,6 +199,21 @@ public class MomentumUpdateTests Assert.Equal(initialValue, finalValue, precision); } + [Fact] + public void Trix_Update() + { + var indicator = new Trix(period: 18); + double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true)); + + for (int i = 0; i < RandomUpdates; i++) + { + indicator.Calc(new TValue(DateTime.Now, GetRandomDouble() + 100, IsNew: false)); // Ensure positive prices + } + double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false)); + + Assert.Equal(initialValue, finalValue, precision); + } + [Fact] public void Vel_Update() { diff --git a/Tests/test_updates_oscillators.cs b/Tests/test_updates_oscillators.cs index ae2574a5..56cdbe93 100644 --- a/Tests/test_updates_oscillators.cs +++ b/Tests/test_updates_oscillators.cs @@ -93,4 +93,20 @@ public class OscillatorsUpdateTests Assert.Equal(initialValue, finalValue, precision); } + + [Fact] + public void Aroon_Update() + { + var indicator = new Aroon(period: 25); + TBar r = new(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true); + double initialValue = indicator.Calc(r); + + for (int i = 0; i < RandomUpdates; i++) + { + indicator.Calc(new TBar(DateTime.Now, GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), GetRandomDouble(), 1000, IsNew: false)); + } + double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false)); + + Assert.Equal(initialValue, finalValue, precision); + } } diff --git a/lib/_todolist.md b/lib/_todolist.md new file mode 100644 index 00000000..035ce46b --- /dev/null +++ b/lib/_todolist.md @@ -0,0 +1,142 @@ +# Stock Indicators List + +## Common Indicators (Both Libraries) + +| Indicator Name | Skender Method | QuanTAlib Class | +|---------------|----------------|-----------------| +| ADL - Accumulation/Distribution Line | GetAdl | Adl | +| ADOSC - Accumulation/Distribution Oscillator | GetAdo | Adosc | +| ALMA - Arnaud Legoux Moving Average | GetAlma | Alma | +| AROON - Aroon Oscillator | GetAroon | Aroon | +| ADX - Average Directional Index | GetAdx | Adx | +| ATR - Average True Range | GetAtr | Atr | +| AO - Awesome Oscillator | GetAwesome | Ao | +| CMF - Chaikin Money Flow | GetCmf | Cmf | +| CMO - Chande Momentum Oscillator | GetCmo | Cmo | +| DEMA - Double Exponential Moving Average | GetDema | Dema | +| EOM - Ease of Movement | GetEom | Eom | +| EPMA - Endpoint Moving Average | GetEpma | Epma | +| EMA - Exponential Moving Average | GetEma | Ema | +| HTIT - Hilbert Transform Instantaneous Trendline | GetHtTrendline | Htit | +| HMA - Hull Moving Average | GetHma | Hma | +| KVO - Klinger Volume Oscillator | GetKvo | Kvo | +| OBV - On-Balance Volume | GetObv | Aobv | +| PMO - Price Momentum Oscillator | GetPmo | Pmo | +| PRS - Price Relative Strength | GetPrs | Prs | +| ROC - Rate of Change | GetRoc | Roc | +| RSI - Relative Strength Index | GetRsi | Rsi | +| SMA - Simple Moving Average | GetSma | Sma | +| SMMA - Smoothed Moving Average | GetSmma | Smma | +| SLOPE - Slope and Linear Regression | GetSlope | Slope | +| STDEV - Standard Deviation | GetStdDev | Stddev | +| TRIX - Triple EMA Oscillator | GetTrix | Trix | +| TEMA - Triple Exponential Moving Average | GetTema | Tema | +| WMA - Weighted Moving Average | GetWma | Wma | + +## Skender-Only Indicators + +| Indicator Name | Skender Method | +|---------------|----------------| +| ATRS - ATR Trailing Stop | GetAtrStop | +| BOP - Balance of Power | GetBop | +| BETA - Beta Coefficient | GetBeta | +| BB - Bollinger Bands | GetBollingerBands | +| CE - Chandelier Exit | GetChandelier | +| CHOP - Choppiness Index | GetChop | +| CCI - Commodity Channel Index | GetCci | +| CRSI - Connors RSI | GetConnorsRsi | +| CORR - Correlation Coefficient | GetCorrelation | +| DPO - Detrended Price Oscillator | GetDpo | +| DOJI - Doji Pattern | GetDoji | +| DC - Donchian Channel | GetDonchian | +| ER - Elder-Ray | GetElderRay | +| FISH - Fisher Transform | GetFisherTransform | +| FI - Force Index | GetForceIndex | +| FCB - Fractal Chaos Bands | GetFcb | +| GATOR - Gator Oscillator | GetGator | +| HA - Heikin-Ashi | GetHeikinAshi | +| HURST - Hurst Exponent | GetHurst | +| ICH - Ichimoku Cloud | GetIchimoku | +| KC - Keltner Channels | GetKeltner | +| MARU - Marubozu Pattern | GetMarubozu | +| MFI - Money Flow Index | GetMfi | +| MAE - Moving Average Envelopes | GetMaEnvelopes | +| PSAR - Parabolic SAR | GetParabolicSar | +| PP - Pivot Points | GetPivotPoints | +| PIV - Pivots | GetPivots | +| PVO - Price Volume Oscillator | GetPvo | +| RENKO-ATR - Renko Chart ATR | GetRenkoAtr | +| RENKO - Renko Chart Standard | GetRenko | +| RPP - Rolling Pivot Points | GetRollingPivots | +| STC - Schaff Trend Cycle | GetStc | +| SDC - Standard Deviation Channels | GetStdDevChannels | +| STARC - Starc Bands | GetStarcBands | +| SMI - Stochastic Momentum Index | GetSmi | +| STOCH - Stochastic Oscillator | GetStoch | +| STOCH-RSI - Stochastic RSI | GetStochRsi | +| ST - Supertrend | GetSuperTrend | +| TR - True Range | GetTr | +| TSI - True Strength Index | GetTsi | +| UI - Ulcer Index | GetUlcerIndex | +| UO - Ultimate Oscillator | GetUltimate | +| VSS - Volatility System/Stop | GetVolatilityStop | +| VWAP - Volume Weighted Average Price | GetVwap | +| VWMA - Volume Weighted Moving Average | GetVwma | +| VTX - Vortex Indicator | GetVortex | +| WAG - Williams Alligator | GetAlligator | +| WF - Williams Fractal | GetFractal | +| ZZ - Zig Zag | GetZigZag | + +## QuanTAlib-Only Indicators + +| Indicator Name | QuanTAlib Class | +|---------------|-----------------| +| AC - Acceleration Oscillator | Ac | +| AFIRMA - Adaptive Firman Moving Average | Afirma | +| APO - Absolute Price Oscillator | Apo | +| ADXR - ADX Rating | Adxr | +| CONV - Convolution Moving Average | Convolution | +| CURV - Curvature | Curvature | +| DMI - Directional Movement Index | Dmi | +| DMX - Directional Movement Extended | Dmx | +| DSMA - Double Smoothed Moving Average | Dsma | +| DWMA - Dynamic Weighted Moving Average | Dwma | +| ENT - Entropy | Entropy | +| FRAMA - Fractal Adaptive Moving Average | Frama | +| FWMA - Fibonacci Weighted Moving Average | Fwma | +| GMA - Gaussian Moving Average | Gma | +| HV - Historical Volatility | Hv | +| HWMA - Hybrid Weighted Moving Average | Hwma | +| JMA - Jurik Moving Average | Jma | +| JVOL - Jurik Volatility | Jvolty | +| KURT - Kurtosis | Kurtosis | +| KAMA - Kaufman Adaptive Moving Average | Kama | +| LTMA - Laguerre Time Moving Average | Ltma | +| MAX - Maximum Value | Max | +| MAAF - Median Adaptive Antifractal | Maaf | +| MAMA - Mesa Adaptive Moving Average | Mama | +| MGDI - McGinley Dynamic Indicator | Mgdi | +| MEDIAN - Median Value | Median | +| MIN - Minimum Value | Min | +| MMA - Modified Moving Average | Mma | +| MODE - Mode Value | Mode | +| MOM - Momentum | Mom | +| PCTL - Percentile | Percentile | +| PO - Price Oscillator | Po | +| PPO - Price Percentage Oscillator | Ppo | +| PWMA - Polynomial Weighted Moving Average | Pwma | +| QEMA - Quadratic Exponential Moving Average | Qema | +| REMA - Range-Normalized Exponential Moving Average | Rema | +| RSX - Relative Strength Extended | Rsx | +| RV - Realized Volatility | Rv | +| RVI - Relative Volatility Index | Rvi | +| RMA - Rolling Moving Average | Rma | +| SINEMA - Sine-Wave Exponential Moving Average | Sinema | +| SKEW - Skewness | Skew | +| T3 - Tillson T3 Moving Average | T3 | +| TRIMA - Triangular Moving Average | Trima | +| VAR - Variance | Variance | +| VIDYA - Variable Index Dynamic Average | Vidya | +| VEL - Velocity | Vel | +| ZLEMA - Zero-Lag Exponential Moving Average | Zlema | +| ZSCORE - Z-Score | Zscore | diff --git a/lib/momentum/Trix.cs b/lib/momentum/Trix.cs new file mode 100644 index 00000000..aa744ab6 --- /dev/null +++ b/lib/momentum/Trix.cs @@ -0,0 +1,87 @@ +using System.Runtime.CompilerServices; +namespace QuanTAlib; + +/// +/// TRIX: Triple Exponential Average Rate of Change +/// A momentum oscillator that shows the percentage rate of change of a triple exponentially +/// smoothed moving average. TRIX filters out insignificant price movements and helps identify +/// overbought/oversold conditions and divergences. +/// +/// +/// The TRIX calculation process: +/// 1. Calculate Triple Exponential Moving Average (TEMA) +/// 2. Calculate 1-day Rate of Change (ROC) of the TEMA +/// +/// Key characteristics: +/// - Combines trend-following and momentum in one indicator +/// - Filters out price movements deemed insignificant +/// - Oscillates around zero line +/// - Useful for identifying divergences +/// - Helps spot overbought/oversold conditions +/// +/// Formula: +/// TEMA = 3*EMA1 - 3*EMA2 + EMA3 +/// TRIX = ROC(TEMA, 1) = ((TEMA - TEMA_prev) / TEMA_prev) * 100 +/// +/// Sources: +/// Jack Hutson - "Technical Analysis of Stocks and Commodities" magazine, 1983 +/// John J. Murphy - "Technical Analysis of the Financial Markets" +/// + +[SkipLocalsInit] +public sealed class Trix : AbstractBase +{ + private readonly Tema _tema; + private readonly CircularBuffer _temaBuffer; + private const double ScalingFactor = 100.0; + private const int DefaultPeriod = 18; + + /// The lookback period for TEMA calculation (default 18). + /// Thrown when period is less than 1. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Trix(int period = DefaultPeriod) + { + if (period < 1) + throw new ArgumentOutOfRangeException(nameof(period)); + + _tema = new(period); + _temaBuffer = new(2); // We only need current and previous TEMA values + WarmupPeriod = period + 1; // TEMA period + 1 for ROC + Name = $"TRIX({period})"; + } + + /// The data source object that publishes updates. + /// The lookback period for TEMA calculation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Trix(object source, int period) : this(period) + { + var pubEvent = source.GetType().GetEvent("Pub"); + pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override void ManageState(bool isNew) + { + if (isNew) + { + double temaValue = _tema.Calc(Input); + _temaBuffer.Add(temaValue); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + protected override double Calculation() + { + ManageState(Input.IsNew); + + if (_temaBuffer.Count < _temaBuffer.Capacity) + return 0.0; + + double oldTema = _temaBuffer[0]; + if (oldTema <= double.Epsilon) + return 0.0; + + double currentTema = _temaBuffer[^1]; + return ((currentTema - oldTema) / oldTema) * ScalingFactor; + } +} diff --git a/lib/momentum/_list.md b/lib/momentum/_list.md index 1928a3d8..fe0e04cc 100644 --- a/lib/momentum/_list.md +++ b/lib/momentum/_list.md @@ -1,4 +1,5 @@ # Momentum indicators +Done: 12, Todo: 5 ✔️ ADX - Average Directional Movement Index ✔️ ADXR - Average Directional Movement Index Rating @@ -13,6 +14,7 @@ MACD - Moving Average Convergence/Divergence ✔️ PPO - Percentage Price Oscillator ✔️ PRS - Price Relative Strength ✔️ ROC - Rate of Change -TRIX - 1-day ROC of TEMA +TSI - True Strength Index +✔️ TRIX - 1-day ROC of TEMA ✔️ VEL - Jurik Signal Velocity VORTEX - Vortex Indicator diff --git a/lib/oscillators/Aroon.cs b/lib/oscillators/Aroon.cs new file mode 100644 index 00000000..cb1f6c20 --- /dev/null +++ b/lib/oscillators/Aroon.cs @@ -0,0 +1,120 @@ +using System.Runtime.CompilerServices; +namespace QuanTAlib; + +/// +/// AROON: Aroon Oscillator +/// A trend-following indicator that measures the strength of a trend and the likelihood +/// that the trend will continue. It consists of two lines (Aroon Up and Aroon Down) and +/// their difference forms the Aroon Oscillator. +/// +/// +/// The Aroon calculation process: +/// 1. Tracks the number of periods since the last highest high (Aroon Up) +/// 2. Tracks the number of periods since the last lowest low (Aroon Down) +/// 3. Normalizes both values to a 0-100 scale +/// 4. Calculates the difference (Aroon Oscillator) +/// +/// Key characteristics: +/// - Oscillates between -100 and +100 +/// - Positive values indicate uptrend +/// - Negative values indicate downtrend +/// - Zero line crossovers signal trend changes +/// - Extreme readings suggest strong trends +/// +/// Formula: +/// Aroon Up = ((period - days since highest high) / period) × 100 +/// Aroon Down = ((period - days since lowest low) / period) × 100 +/// Aroon Oscillator = Aroon Up - Aroon Down +/// +/// Sources: +/// Tushar Chande - "The New Technical Trader" (1994) +/// https://www.investopedia.com/terms/a/aroonoscillator.asp +/// +/// Note: Default period of 25 was recommended by Chande +/// + +[SkipLocalsInit] +public sealed class Aroon : AbstractBarBase +{ + private readonly CircularBuffer _highPrices; + private readonly CircularBuffer _lowPrices; + private const double ScalingFactor = 100.0; + private const int DefaultPeriod = 25; + + /// The number of periods used in the Aroon calculation (default 25). + /// Thrown when period is less than 1. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Aroon(int period = DefaultPeriod) + { + if (period < 1) + throw new ArgumentOutOfRangeException(nameof(period)); + + _highPrices = new(period); + _lowPrices = new(period); + _index = 0; + WarmupPeriod = period; + Name = $"AROON({period})"; + } + + /// The data source object that publishes updates. + /// The number of periods used in the Aroon calculation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Aroon(object source, int period) : 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++; + _highPrices.Add(Input.High); + _lowPrices.Add(Input.Low); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + private static double CalculateAroonLine(int period, int daysSince) + { + return ((period - daysSince) * ScalingFactor) / period; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + protected override double Calculation() + { + ManageState(Input.IsNew); + + if (_index < WarmupPeriod) + return double.NaN; + + // Find highest high and lowest low positions + int highestIndex = 0; + int lowestIndex = 0; + double highestHigh = _highPrices[0]; + double lowestLow = _lowPrices[0]; + + for (int i = 1; i < _highPrices.Count; i++) + { + if (_highPrices[i] > highestHigh) + { + highestHigh = _highPrices[i]; + highestIndex = i; + } + if (_lowPrices[i] < lowestLow) + { + lowestLow = _lowPrices[i]; + lowestIndex = i; + } + } + + // Calculate Aroon Up and Down + double aroonUp = CalculateAroonLine(_highPrices.Count, highestIndex); + double aroonDown = CalculateAroonLine(_lowPrices.Count, lowestIndex); + + // Return Aroon Oscillator + return aroonUp - aroonDown; + } +} diff --git a/lib/oscillators/_list.md b/lib/oscillators/_list.md index b779856e..99e19436 100644 --- a/lib/oscillators/_list.md +++ b/lib/oscillators/_list.md @@ -1,8 +1,9 @@ # Oscillators indicators +Done: 6, Todo: 23 ✔️ AC - Acceleration Oscillator ✔️ AO - Awesome Oscillator -AROON - Aroon oscillator +✔️ AROON - Aroon oscillator BOP - Balance of Power CCI - Commodity Channel Index CFO - Chande Forcast Oscillator diff --git a/lib/patterns/_list.md b/lib/patterns/_list.md new file mode 100644 index 00000000..8b54056f --- /dev/null +++ b/lib/patterns/_list.md @@ -0,0 +1,11 @@ +# Pattern indicators +Done: 0, Todo: 8 + +DOJI - Doji Candlestick Pattern +ER - Elder Ray Pattern +MARU - Marubozu Candlestick Pattern +PIV - Pivot Points +PP - Price Pivots +RPP - Rolling Pivot Points +WF - Williams Fractal +ZZ - Zig Zag Pattern diff --git a/lib/statistics/_list.md b/lib/statistics/_list.md index 84fa4b37..627de7c8 100644 --- a/lib/statistics/_list.md +++ b/lib/statistics/_list.md @@ -1,4 +1,5 @@ # Statistics indicators +Done: 13, Todo: 6 BETA - Beta coefficient CORR - Correlation Coefficient diff --git a/lib/volatility/_list.md b/lib/volatility/_list.md index 1ec6089e..93598c02 100644 --- a/lib/volatility/_list.md +++ b/lib/volatility/_list.md @@ -1,4 +1,5 @@ # Volatility indicators +Done: 6, Todo: 25 ADR - Average Daily Range AP - Andrew's Pitchfork @@ -33,4 +34,4 @@ VC - Volatility Cone VOV - Volatility of Volatility VR - Volatility Ratio VS - Volatility Stop -YZV - Yang-Zhang Volatility \ No newline at end of file +YZV - Yang-Zhang Volatility diff --git a/lib/volume/_list.md b/lib/volume/_list.md index 86ec2225..54149915 100644 --- a/lib/volume/_list.md +++ b/lib/volume/_list.md @@ -1,4 +1,5 @@ # Volume indicators +Done: 6, Todo: 12 ✔️ ADL - Chaikin Accumulation Distribution Line ✔️ ADOSC - Chaikin Accumulation Distribution Oscillator