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