From 7c6b698c9a2630dc0d5317f2f9bf15ec8fe5c0e1 Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Fri, 1 Nov 2024 17:54:03 -0700 Subject: [PATCH] Chop & Cog --- Tests/test_eventing.cs | 5 +- Tests/test_updates_oscillators.cs | 31 +++++++ docs/Progress.csv | 134 ------------------------------ docs/indicators/indicators.md | 16 ++-- lib/momentum/_list.md | 2 +- lib/oscillators/Chop.cs | 111 +++++++++++++++++++++++++ lib/oscillators/Cog.cs | 101 ++++++++++++++++++++++ lib/oscillators/_list.md | 12 +-- 8 files changed, 262 insertions(+), 150 deletions(-) delete mode 100644 docs/Progress.csv create mode 100644 lib/oscillators/Chop.cs create mode 100644 lib/oscillators/Cog.cs diff --git a/Tests/test_eventing.cs b/Tests/test_eventing.cs index 45f49a3d..78ad4f8e 100644 --- a/Tests/test_eventing.cs +++ b/Tests/test_eventing.cs @@ -62,6 +62,7 @@ public class EventingTests ("Rsi", new Rsi(p), new Rsi(input, p)), ("Rsx", new Rsx(p), new Rsx(input, p)), ("Cmo", new Cmo(p), new Cmo(input, p)), + ("Cog", new Cog(p), new Cog(input, p)), ("Curvature", new Curvature(p), new Curvature(input, p)), ("Entropy", new Entropy(p), new Entropy(input, p)), ("Kurtosis", new Kurtosis(p), new Kurtosis(input, p)), @@ -110,7 +111,9 @@ public class EventingTests ("Eom", new Eom(14), new Eom(barInput, 14)), ("Kvo", new Kvo(34, 55), new Kvo(barInput, 34, 55)), // Volatility indicators (bar-based) - ("Atr", new Atr(14), new Atr(barInput, 14)) + ("Atr", new Atr(14), new Atr(barInput, 14)), + // Oscillators (bar-based) + ("Chop", new Chop(14), new Chop(barInput, 14)) }; // Generate 200 random values and feed them to indicators diff --git a/Tests/test_updates_oscillators.cs b/Tests/test_updates_oscillators.cs index ba552e4e..a9d74a8e 100644 --- a/Tests/test_updates_oscillators.cs +++ b/Tests/test_updates_oscillators.cs @@ -156,4 +156,35 @@ public class OscillatorsUpdateTests Assert.Equal(initialValue, finalValue, precision); } + + [Fact] + public void Chop_Update() + { + var indicator = new Chop(period: 14); + 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); + } + + [Fact] + public void Cog_Update() + { + var indicator = new Cog(period: 10); + 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(), IsNew: false)); + } + double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false)); + + Assert.Equal(initialValue, finalValue, precision); + } } diff --git a/docs/Progress.csv b/docs/Progress.csv deleted file mode 100644 index 7ea5a50e..00000000 --- a/docs/Progress.csv +++ /dev/null @@ -1,134 +0,0 @@ -AC,Acceleration Oscillator -AD,Chaikin A/D Line -ADOSC,Chaikin A/D Oscillator -ADL,Accumulation / Distribution Line -ADX,Average Directional Movement Index -ADXR,Average Directional Movement Index Rating -Alligator,Alligator Indicator -ALMA,Arnaud Legoux Moving Average -AO,Awesome Oscillator -APO,Absolute Price Oscillator -AROON,Aroon Indicator -AROONOSC,Aroon Oscillator -ATS,ATR Trailing Stop -ATR,Average True Range -AVGPRICE,Average Price -BB,Bollinger Bands -BBF,Bollinger Bands Flat -BBP,Bull and Bear Power -BC,Beta Coefficient -BETA,Beta -BOP,Balance of Power -CCI,Commodity Channel Index -CE,Chandelier Exit -Channel,Price Channel -CI,Choppiness Index -CMF,Chaikin Money Flow -CMO,Chande Momentum Oscillator -CORREL,Pearson's Correlation Coefficient -CRSI,ConnorsRSI -DC,Donchian Channels -DCP,Dominant Cycle Periods -DEMA,Double Exponential Moving Average -DMI,Directional Movement Index -DPO,Detrended Price Oscillator -DX,Directional Movement Index -EMA,Exponential Moving Average -EPMA,Endpoint Moving Average -ERI,Elder-ray Index -FCB,Fractal Chaos Bands -FI,Force Index -GO,Gator Oscillator -HE,Hurst Exponent -HMA,Hull Moving Average -HT_TRENDLINE,Hilbert Transform - Instantaneous Trendline -HT_TRENDMODE,Hilbert Transform - Trend vs Cycle Mode -HV,Historical Volatility -IC,Ichimoku Cloud -KAMA,Kaufman Adaptive Moving Average -KDJ,KDJ Index -Keltner,Keltner Channel -KVO,Klinger Volume Oscillator -LINEARREG,Linear Regression -LINEARREG_ANGLE,Linear Regression Angle -LINEARREG_INTERCEPT,Linear Regression Intercept -LINEARREG_SLOPE,Linear Regression Slope -LSMA,Least Squares Moving Average -LWMA,Linearly Weighted Moving Average -MACDEXT,MACD with controllable MA type -MACDFIX,Moving Average Convergence Divergence Fix 12/26 -MAD,Mean absolute deviation -MAE,Moving Average Envelope -MAMA,MESA Adaptive Moving Average -MAPE,Mean absolute percentage error -MAX,Highest value over a specified period -MAXINDEX,Index of highest value over a specified period -MD,McGinley Dynamic -MEDPRICE,Median Price -MFI,Money Flow Index -MIN,Lowest value over a specified period -MININDEX,Index of lowest value over a specified period -MINMAX,Lowest and highest values over a specified period -MINMAXINDEX,Indexes of lowest and highest values over a period -MMA,Modified Moving Average -MOM,Momentum -MSE,Mean square error -NATR,Normalized Average True Range -OBV,On Balance Volume -OsMA,Moving Average of Oscillator -PAZ,Price Action Zones -Pivots,Pivots -PMO,Price Momentum Oscillator -PP,Pivot Points -PPO,Percentage Price Oscillator -PPMA,Pivot Point Moving Average -PRS,Price Relative Strength -PVI,Positive Volume Index -PVO,Percentage Volume Oscillator -Qstick,Qstick Indicator -R2,R-Squared (Coefficient of Determination) -Regression,Regression Line Indicator -RLW,%R Larry Williams -RMA,Running Moving Average -ROC,Rate of Change -ROCB,ROC with Bands -RPP,Rolling Pivot Points -RRA,Rescaled Range Analysis -RSI,Relative Strength Index -SAR,Parabolic SAR -SAREXT,Parabolic SAR - Extended -SDC,Standard Deviation Channels -SI,Swing Index -SLR,Slope and Linear Regression -SMA,Simple Moving Average -SMI,Stochastic Momentum Index -SMMA,Smoothed Moving Average -ST,SuperTrend -STARC,STARC Bands -STC,Schaff Trend Cycle -STDDEV,Standard Deviation -STOCH,Stochastic -STOCHF,Stochastic Fast -STOCHRSI,Stochastic Relative Strength Index -SUM,Summation -T3,Triple Exponential Moving Average (T3) -TEMA,Triple Exponential Moving Average -TRANGE,True Range -TRIMA,Triangular Moving Average -TRIX,1-day Rate-Of-Change (ROC) of a Triple Smooth EMA -TSI,True Strength Index -TYPPRICE,Typical Price -UI,Ulcer Index -ULTOSC,Ultimate Oscillator -VAR,Variance -VI,Vortex Indicator -Volume,Volume Indicator -VS,Volatility Stop -VWAP,Volume Weighted Average Price -VWMA,Volume Weighted Moving Average -WA,Williams Alligator -WCLPRICE,Weighted Close Price -WF,Williams Fractal -WMA,Weighted Moving Average -ZS,Z-Score -ZZ,ZigZag Indicator diff --git a/docs/indicators/indicators.md b/docs/indicators/indicators.md index abdc6468..81cfc570 100644 --- a/docs/indicators/indicators.md +++ b/docs/indicators/indicators.md @@ -5,13 +5,13 @@ **Implementation Status:** - Basic Transforms: 6 of 6 complete - Averages & Trends: 33 of 33 complete -- Momentum: 16 of 17 complete -- Oscillators: 6 of 29 complete +- Momentum: 17 of 17 complete +- Oscillators: 11 of 29 complete - Volatility: 11 of 35 complete - Volume: 15 of 19 complete - Numerical Analysis: 13 of 20 complete - Errors: 16 of 16 complete -- Total: 116 of 175 indicators implemented (66%) +- Total: 122 of 175 indicators implemented (70%) |**BASIC TRANSFORMS**|**Class Name**| @@ -67,7 +67,7 @@ |DMI* - Directional Movement Index (DI+, DI-)|`Dmi`| |DMX - Jurik Directional Movement Index|`Dmx`| |DPO - Detrended Price Oscillator|`Dpo`| -|🚧 MACD* - Moving Average Convergence/Divergence|`Macd`| +|MACD* - Moving Average Convergence/Divergence|`Macd`| |MOM - Momentum|`Mom`| |PMO - Price Momentum Oscillator|`Pmo`| |PO - Price Oscillator|`Po`| @@ -85,11 +85,11 @@ |AO - Awesome Oscillator|`Ao`| |AROON* - Aroon oscillator (Up, Down)|`Aroon`| |🚧 BOP - Balance of Power|`Bop`| -|🚧 CCI - Commodity Channel Index|`Cci`| -|🚧 CFO - Chande Forcast Oscillator|`Cfo`| +|CCI - Commodity Channel Index|`Cci`| +|CFO - Chande Forcast Oscillator|`Cfo`| |CMO - Chande Momentum Oscillator|`Cmo`| -|🚧 CHOP - Choppiness Index|`Chop`| -|🚧 COG - Ehler's Center of Gravity|`Cog`| +|CHOP - Choppiness Index|`Chop`| +|COG - Ehler's Center of Gravity|`Cog`| |🚧 COPPOCK - Coppock Curve|`Coppock`| |🚧 CRSI - Connor RSI|`Crsi`| |🚧 CTI - Ehler's Correlation Trend Indicator|`Cti`| diff --git a/lib/momentum/_list.md b/lib/momentum/_list.md index e141b879..1d01f144 100644 --- a/lib/momentum/_list.md +++ b/lib/momentum/_list.md @@ -7,7 +7,7 @@ Done: 15, Todo: 2 ✔️ *DMI - Directional Movement Index (DI+, DI-) ✔️ DMX - Jurik Directional Movement Index ✔️ DPO - Detrended Price Oscillator -*MACD - Moving Average Convergence/Divergence (MACD, Signal, Histogram) +✔️ *MACD - Moving Average Convergence/Divergence (MACD, Signal, Histogram) ✔️ MOM - Momentum ✔️ PMO - Price Momentum Oscillator ✔️ PO - Price Oscillator diff --git a/lib/oscillators/Chop.cs b/lib/oscillators/Chop.cs new file mode 100644 index 00000000..f58ef0c6 --- /dev/null +++ b/lib/oscillators/Chop.cs @@ -0,0 +1,111 @@ +using System.Runtime.CompilerServices; +namespace QuanTAlib; + +/// +/// CHOP: Choppiness Index +/// A technical indicator that measures the market's trendiness versus choppiness. +/// It helps determine if the market is trending or moving sideways by comparing +/// the total movement to the net directional movement over a period. +/// +/// +/// The CHOP calculation process: +/// 1. Calculate ATR sum over period +/// 2. Calculate total price range over period +/// 3. Scale result to oscillate between 0 and 100 +/// +/// Key characteristics: +/// - Oscillates between 0 and 100 +/// - Values above 61.8 indicate choppy market +/// - Values below 38.2 indicate trending market +/// - Based on ATR and price range +/// - Higher values = more choppy/sideways +/// - Lower values = more trending +/// +/// Formula: +/// CHOP = 100 * LOG10(SUM(ATR,n)/(HIGH(n)-LOW(n))) / LOG10(n) +/// where: +/// n = period +/// ATR = Average True Range +/// HIGH(n) = Highest high over period n +/// LOW(n) = Lowest low over period n +/// +/// Sources: +/// E.W. Dreiss +/// https://www.tradingview.com/support/solutions/43000501980-choppiness-index/ +/// +/// Note: Default period is 14 +/// + +[SkipLocalsInit] +public sealed class Chop : AbstractBase +{ + private readonly Atr _atr; + private readonly CircularBuffer _highs; + private readonly CircularBuffer _lows; + private readonly CircularBuffer _atrValues; + private readonly double _logPeriod; + private const int DefaultPeriod = 14; + private const double ScalingFactor = 100.0; + + /// The number of periods used in the CHOP calculation (default 14). + /// Thrown when period is less than 1. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Chop(int period = DefaultPeriod) + { + if (period < 1) + throw new ArgumentOutOfRangeException(nameof(period)); + + _atr = new(period); + _highs = new(period); + _lows = new(period); + _atrValues = new(period); + _logPeriod = Math.Log10(period); + WarmupPeriod = period; + Name = $"CHOP({period})"; + } + + /// The data source object that publishes updates. + /// The number of periods used in the CHOP calculation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Chop(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 ATR and store it + double atr = _atr.Calc(BarInput); + _atrValues.Add(atr, BarInput.IsNew); + + // Store high and low prices + _highs.Add(BarInput.High, BarInput.IsNew); + _lows.Add(BarInput.Low, BarInput.IsNew); + + // Calculate highest high and lowest low over period + double highestHigh = _highs.Max(); + double lowestLow = _lows.Min(); + double range = highestHigh - lowestLow; + + // Calculate sum of ATR values + double atrSum = _atrValues.Sum(); + + // Avoid division by zero + if (range < double.Epsilon || _logPeriod < double.Epsilon) + return 0.0; + + // Calculate CHOP + return ScalingFactor * Math.Log10(atrSum / range) / _logPeriod; + } +} diff --git a/lib/oscillators/Cog.cs b/lib/oscillators/Cog.cs new file mode 100644 index 00000000..0c9aec23 --- /dev/null +++ b/lib/oscillators/Cog.cs @@ -0,0 +1,101 @@ +using System.Runtime.CompilerServices; +namespace QuanTAlib; + +/// +/// COG: Ehler's Center of Gravity Oscillator +/// A momentum oscillator that uses the concept of center of gravity from physics +/// to measure price momentum. It calculates a weighted sum where more recent +/// prices have higher weights. +/// +/// +/// The COG calculation process: +/// 1. Calculate weighted sum of prices (numerator) +/// 2. Calculate sum of weights (denominator) +/// 3. Divide to get center of gravity +/// 4. Invert and normalize result +/// +/// Key characteristics: +/// - Oscillates around zero +/// - Leading indicator (less lag than traditional momentum) +/// - Positive values indicate upward momentum +/// - Negative values indicate downward momentum +/// - Zero line crossovers signal trend changes +/// +/// Formula: +/// COG = -((Σ(Price(i) * i)) / (Σ(Price(i))) - (period + 1)/2) +/// where: +/// i = position in period (1 to period) +/// Price(i) = price at position i +/// +/// Sources: +/// John F. Ehlers - "Cybernetic Analysis for Stocks and Futures" +/// https://www.mesasoftware.com/papers/CenterOfGravity.pdf +/// +/// Note: Default period is 10 +/// + +[SkipLocalsInit] +public sealed class Cog : AbstractBase +{ + private readonly CircularBuffer _prices; + private readonly int _period; + private const int DefaultPeriod = 10; + + /// The number of periods used in the COG calculation (default 10). + /// Thrown when period is less than 1. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Cog(int period = DefaultPeriod) + { + if (period < 1) + throw new ArgumentOutOfRangeException(nameof(period)); + + _period = period; + _prices = new(period); + WarmupPeriod = period; + Name = $"COG({period})"; + } + + /// The data source object that publishes updates. + /// The number of periods used in the COG calculation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Cog(object source, int period = DefaultPeriod) : 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) + _index++; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + protected override double Calculation() + { + ManageState(Input.IsNew); + + // Add new price to buffer + _prices.Add(Input.Value, Input.IsNew); + + double numerator = 0.0; + double denominator = 0.0; + + // Calculate weighted sums + for (int i = 0; i < _prices.Count; i++) + { + double price = _prices[i]; + double weight = i + 1; + numerator += price * weight; + denominator += price; + } + + // Avoid division by zero + if (Math.Abs(denominator) < double.Epsilon) + return 0.0; + + // Calculate center of gravity and normalize + return -((numerator / denominator) - (_period + 1.0) / 2.0); + } +} diff --git a/lib/oscillators/_list.md b/lib/oscillators/_list.md index b49e2385..e4cf7f2a 100644 --- a/lib/oscillators/_list.md +++ b/lib/oscillators/_list.md @@ -1,15 +1,15 @@ # Oscillators indicators -Done: 6, Todo: 23 +Done: 11, Todo: 18 ✔️ AC - Acceleration Oscillator ✔️ AO - Awesome Oscillator ✔️ *AROON - Aroon oscillator (Up, Down) -, -CCI - Commodity Channel Index -CFO - Chande Forcast Oscillator +BOP - Balance of Power +✔️ CCI - Commodity Channel Index +✔️ CFO - Chande Forcast Oscillator ✔️ CMO - Chande Momentum Oscillator -CHOP - Choppiness Index -COG - Ehler's Center of Gravity +✔️ CHOP - Choppiness Index +✔️ COG - Ehler's Center of Gravity COPPOCK - Coppock Curve CRSI - Connor RSI CTI - Ehler's Correlation Trend Indicator