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