diff --git a/Tests/test_updates_oscillators.cs b/Tests/test_updates_oscillators.cs
index 297f0ebd..ae2574a5 100644
--- a/Tests/test_updates_oscillators.cs
+++ b/Tests/test_updates_oscillators.cs
@@ -61,4 +61,36 @@ public class OscillatorsUpdateTests
Assert.Equal(initialValue, finalValue, precision);
}
+
+ [Fact]
+ public void Ao_Update()
+ {
+ var indicator = new Ao();
+ 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 Ac_Update()
+ {
+ var indicator = new Ac();
+ 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/oscillators/Ac.cs b/lib/oscillators/Ac.cs
new file mode 100644
index 00000000..f298d560
--- /dev/null
+++ b/lib/oscillators/Ac.cs
@@ -0,0 +1,71 @@
+using System.Runtime.CompilerServices;
+namespace QuanTAlib;
+
+///
+/// AC: Acceleration/Deceleration Oscillator
+/// A momentum indicator that measures the acceleration and deceleration of the current driving force.
+/// It is derived from the Awesome Oscillator (AO) and helps identify potential trend reversals.
+///
+///
+/// The AC calculation process:
+/// 1. Calculate the Awesome Oscillator (AO)
+/// 2. Calculate a 5-period simple moving average of the AO
+/// 3. Subtract the 5-period SMA from the current AO value
+///
+/// Key characteristics:
+/// - Oscillates above and below zero
+/// - Measures the acceleration/deceleration of market driving force
+/// - Positive values indicate increasing momentum
+/// - Negative values indicate decreasing momentum
+/// - Can be used to identify potential trend reversals
+///
+/// Formula:
+/// AC = AO - SMA(AO, 5)
+///
+/// Sources:
+/// Bill Williams - "Trading Chaos" (1995)
+/// https://www.investopedia.com/terms/a/ac.asp
+///
+
+[SkipLocalsInit]
+public sealed class Ac : AbstractBase
+{
+ private readonly Ao _ao;
+ private readonly Sma _sma5;
+
+ /// The data source object that publishes updates.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Ac(object source) : this()
+ {
+ var pubEvent = source.GetType().GetEvent("Pub");
+ pubEvent?.AddEventHandler(source, new BarSignal(Sub));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Ac()
+ {
+ _ao = new Ao();
+ _sma5 = new Sma(5);
+ WarmupPeriod = 39; // AO requires 34 periods + 5 for AC's SMA
+ Name = "AC";
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected override void ManageState(bool isNew)
+ {
+ if (isNew)
+ {
+ _index++;
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected override double Calculation()
+ {
+ ManageState(BarInput.IsNew);
+ var ao = _ao.Calc(BarInput, BarInput.IsNew);
+ _sma5.Calc(ao, BarInput.IsNew);
+
+ return ao - _sma5.Value;
+ }
+}
diff --git a/lib/oscillators/Ao.cs b/lib/oscillators/Ao.cs
new file mode 100644
index 00000000..97c39ea0
--- /dev/null
+++ b/lib/oscillators/Ao.cs
@@ -0,0 +1,71 @@
+using System.Runtime.CompilerServices;
+namespace QuanTAlib;
+
+///
+/// AO: Awesome Oscillator
+/// A momentum indicator that reflects the precise changes in the market driving force.
+/// It is used to affirm trends or to anticipate possible reversals.
+///
+///
+/// The AO calculation process:
+/// 1. Calculates the 5-period simple moving average of the HL2 (High+Low)/2 values.
+/// 2. Calculates the 34-period simple moving average of the HL2 (High+Low)/2 values.
+/// 3. Subtracts the 34-period SMA from the 5-period SMA.
+///
+/// Key characteristics:
+/// - Oscillates above and below zero
+/// - Positive values indicate bullish momentum
+/// - Negative values indicate bearish momentum
+/// - Crosses above zero suggest buying opportunities
+/// - Crosses below zero suggest selling opportunities
+///
+/// Formula:
+/// AO = SMA(HL2, 5) - SMA(HL2, 34)
+///
+/// Sources:
+/// Bill Williams - "Trading Chaos" (1995)
+/// https://www.investopedia.com/terms/a/awesomeoscillator.asp
+///
+
+[SkipLocalsInit]
+public sealed class Ao : AbstractBase
+{
+ private readonly Sma _sma5;
+ private readonly Sma _sma34;
+
+ /// The data source object that publishes updates.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Ao(object source) : this()
+ {
+ var pubEvent = source.GetType().GetEvent("Pub");
+ pubEvent?.AddEventHandler(source, new BarSignal(Sub));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Ao()
+ {
+ _sma5 = new Sma(5);
+ _sma34 = new Sma(34);
+ WarmupPeriod = 34;
+ Name = "AO";
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected override void ManageState(bool isNew)
+ {
+ if (isNew)
+ {
+ _index++;
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected override double Calculation()
+ {
+ ManageState(BarInput.IsNew);
+ _sma5.Calc(BarInput.HL2, BarInput.IsNew);
+ _sma34.Calc(BarInput.HL2, BarInput.IsNew);
+
+ return _sma5.Value - _sma34.Value;
+ }
+}
diff --git a/lib/oscillators/_list.md b/lib/oscillators/_list.md
index 618c07b3..b779856e 100644
--- a/lib/oscillators/_list.md
+++ b/lib/oscillators/_list.md
@@ -1,7 +1,7 @@
# Oscillators indicators
-AC - Acceleration Oscillator
-AO - Awesome Oscillator
+✔️ AC - Acceleration Oscillator
+✔️ AO - Awesome Oscillator
AROON - Aroon oscillator
BOP - Balance of Power
CCI - Commodity Channel Index