This is another oscillator developed by Ali from StatOasis. Instead of using average gains and losses, it calculates the average rate of change. Check out the next video for more details.
More information on indicator and use.
https://www.youtube.com/watch?v=V6DL5Hkf3Ms&ab_channel=StatOasis%7CAliCasey
Code:
namespace CC.Indicators.CaseyCP;
public sealed partial class CaseyCP_Oscillator : Indicator
{
[Parameter("Lookback"), NumericRange(1)]
public int Lookback { get; set; } = 4;
[Parameter("SmoothLookback"), NumericRange(1)]
public int SmoothLookback { get; set; } = 3;
[Plot("Result")]
public PlotSeries Result { get; set; } = new(Color.Blue);
[Plot("Overbought Level")]
public PlotLevel OverboughtLevel { get; set; } = new(75, Color.Red, LineStyle.Dash, 1);
[Plot("Oversold Level")]
public PlotLevel OversoldLevel { get; set; } = new(25, Color.Green, LineStyle.Dash, 1);
private int _barsRequiredToCalculate;
private DataSeries _caseyC = null!;
private DataSeries _value1 = null!;
public CaseyCP_Oscillator()
{
Name = "Casey C% Oscillator";
ShortName = "CC.CCO";
ScalePrecision = 1;
IsOverlay = false;
IsPercentage = true;
}
protected override void Initialize()
{
_caseyC = new DataSeries();
_value1 = new DataSeries();
_barsRequiredToCalculate = Math.Max(Lookback, SmoothLookback);
}
protected override void Calculate(int index)
{
if (index <= _barsRequiredToCalculate)
{
Result[index] = 0;
return;
}
double value2 = 0;
if (Bars[index - 1].Close != 0) _value1[index] = (Bars[index].Close - Bars[index - 1].Close) / Bars[index - 1].Close;
double highest = HighestT(index, Lookback);
double lowest = LowestT(index, Lookback);
if ((highest - lowest) == 0) value2 = 0;
else value2 = (_value1[index] - lowest) / (highest - lowest) * 100;
_caseyC[index] = value2;
Result[index] = SMA(index,SmoothLookback);
Result.Colors[index] = (Result[index] > OverboughtLevel.Value && Result[index - 1] > OverboughtLevel.Value) ? Color.Red
: (Result[index] < OversoldLevel.Value && Result[index - 1] < OversoldLevel.Value) ? Color.Green
: Result.Color;
}
private double SMA(int index,int period)
{
var per = Math.Min(period, index + 1);
var sum = 0.0;
for (var i = 0; i < per; i++)
{
sum += _caseyC[index - i];
}
return(sum / per);
}
private double HighestT(int index, int period)
{
double highest = double.MinValue;
int per = Math.Min(period, index + 1);
for (int i = 0; i < per; i++)
{
if (_value1[index-i] > highest) highest = _value1[index-i];
}
return highest;
}
private double LowestT(int index, int period)
{
double lowest = double.MaxValue;
int per = Math.Min(period, index + 1);
for (int i = 0; i < per; i++)
{
if (_value1[index-i] < lowest) lowest = _value1[index-i];
}
return lowest;
}
}