Category Oscilators  Published on 21/09/2021

KC Oscillator % Mod v1.2

Description

This indicator is inspired by the idea of the "Ten-Day Moving Average Trading Rule" introduced by Chester W. Keltner in 1960. It calculates the %d between the price and the 10 periods MA using typical price. The histogram uses a MA of the high/low prices as a filter. I added an adicional filter of %level (it can be turned off with 0 value). This filter must be adjusted according to the volatility of the timeframe and asset.

Log:

Tue Sep 21, 2021: Added two signal types for the arrows.

Tue Sep 21, 2021: Added Smoothing.

 

 

KC Oscillator % No Smoothing

 

KC Oscillator % Smoothed


using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class KCOscillatorModv1 : Indicator
    {
        [Parameter("MA Period", DefaultValue = 10, MinValue = 2, Step = 1)]
        public int maPeriod { get; set; }

        [Parameter("MA Type", DefaultValue = MovingAverageType.Simple)]
        public MovingAverageType maType { get; set; }

        [Parameter("%D Filter", DefaultValue = 0.2, MinValue = 0)]
        public double percDFilter { get; set; }

        [Parameter("Smoothing", DefaultValue = 1, MinValue = 1)]
        public int smoothing { get; set; }

        [Parameter("Arrows", DefaultValue = true)]
        public bool arrows { get; set; }

        [Parameter("Arrow Distance", DefaultValue = 1)]
        public double arrowDistance { get; set; }

        [Parameter("H/L MA Crossing Signal", DefaultValue = true)]
        public bool hlSignal { get; set; }

        [Parameter("%D Crossing Signal", DefaultValue = true)]
        public bool percDSignal { get; set; }


        [Output("Up Histogram 1", LineColor = "FF008080", PlotType = PlotType.Histogram, Thickness = 4)]
        public IndicatorDataSeries up1 { get; set; }

        [Output("Up Histogram 2", LineColor = "FF77B0B2", PlotType = PlotType.Histogram, Thickness = 4)]
        public IndicatorDataSeries up2 { get; set; }

        [Output("Down Histogram 1", LineColor = "FFA52A2A", PlotType = PlotType.Histogram, Thickness = 4)]
        public IndicatorDataSeries down1 { get; set; }

        [Output("Down Histogram 2", LineColor = "FFC4898A", PlotType = PlotType.Histogram, Thickness = 4)]
        public IndicatorDataSeries down2 { get; set; }

        [Output("Neutral Histogram", LineColor = "FFC0C0C0", PlotType = PlotType.Histogram, Thickness = 4)]
        public IndicatorDataSeries neutral { get; set; }

        [Output("Difference Line", LineColor = "FFC0C0C0", LineStyle = LineStyle.Solid, PlotType = PlotType.Line, Thickness = 2)]
        public IndicatorDataSeries diff { get; set; }

        [Output("Highfilter", LineColor = "FFC0C0C0", LineStyle = LineStyle.DotsRare, Thickness = 1)]
        public IndicatorDataSeries highFilter { get; set; }

        [Output("Lowfilter", LineColor = "FFC0C0C0", LineStyle = LineStyle.DotsRare, Thickness = 1)]
        public IndicatorDataSeries lowFilter { get; set; }


        private IndicatorDataSeries source, source2, source3, priceDiff, maHigh, maLow, range;
        private MovingAverage maTypical, smooth11, smooth21, smooth31, smooth12, smooth22, smooth32;
        private AverageTrueRange atr;


        protected override void Initialize()
        {
            source = CreateDataSeries();
            source2 = CreateDataSeries();
            source3 = CreateDataSeries();
            maHigh = CreateDataSeries();
            maLow = CreateDataSeries();
            range = CreateDataSeries();
            priceDiff = CreateDataSeries();

            smooth11 = Indicators.MovingAverage(source2, smoothing, MovingAverageType.WilderSmoothing);
            smooth21 = Indicators.MovingAverage(smooth11.Result, smoothing, MovingAverageType.WilderSmoothing);
            smooth31 = Indicators.MovingAverage(smooth21.Result, smoothing, MovingAverageType.WilderSmoothing);

            smooth12 = Indicators.MovingAverage(source3, smoothing, MovingAverageType.WilderSmoothing);
            smooth22 = Indicators.MovingAverage(smooth12.Result, smoothing, MovingAverageType.WilderSmoothing);
            smooth32 = Indicators.MovingAverage(smooth22.Result, smoothing, MovingAverageType.WilderSmoothing);


            maTypical = Indicators.MovingAverage(source, maPeriod, maType);
            atr = Indicators.AverageTrueRange(27, MovingAverageType.Simple);
        }

        public override void Calculate(int index)
        {
            // Indicator
            source[index] = (Bars.HighPrices[index] + Bars.LowPrices[index] + Bars.ClosePrices[index]) / 3;
            source2[index] = maTypical.Result[index];
            source3[index] = ((Bars.ClosePrices[index] - smooth31.Result[index]) / ((Bars.ClosePrices[index] + smooth31.Result[index]) / 2)) * 100;
            range[index] = (Bars.HighPrices[index] - Bars.LowPrices[index]) / 2;
            maHigh[index] = smooth31.Result[index] + range[index];
            maLow[index] = smooth31.Result[index] - range[index];
            priceDiff[index] = smooth32.Result[index];

            if (priceDiff[index] > percDFilter && Bars.ClosePrices[index] > maHigh[index])
            {
                if (priceDiff[index] >= priceDiff[index - 1])
                {
                    up1[index] = priceDiff[index];
                    up2[index] = double.NaN;
                    down1[index] = double.NaN;
                    down2[index] = double.NaN;
                    neutral[index] = double.NaN;
                }
                else
                {
                    up1[index] = double.NaN;
                    up2[index] = priceDiff[index];
                    down1[index] = double.NaN;
                    down2[index] = double.NaN;
                    neutral[index] = double.NaN;
                }
            }
            else if (priceDiff[index] < -percDFilter && Bars.ClosePrices[index] < maLow[index])
            {
                if (priceDiff[index] <= priceDiff[index - 1])
                {
                    down1[index] = priceDiff[index];
                    down2[index] = double.NaN;
                    up1[index] = double.NaN;
                    up2[index] = double.NaN;
                    neutral[index] = double.NaN;
                }
                else
                {
                    down1[index] = double.NaN;
                    down2[index] = priceDiff[index];
                    up1[index] = double.NaN;
                    up2[index] = double.NaN;
                    neutral[index] = double.NaN;
                }
            }
            else
            {
                neutral[index] = priceDiff[index];
                up1[index] = double.NaN;
                up2[index] = double.NaN;
                down1[index] = double.NaN;
                down2[index] = double.NaN;
            }
            diff[index] = priceDiff[index];
            highFilter[index] = percDFilter;
            lowFilter[index] = percDFilter * -1;

            if (arrows)
            {
                if ((percDSignal && priceDiff[index] > percDFilter && priceDiff[index - 1] < percDFilter) || (hlSignal && Bars.ClosePrices[index] > maHigh[index] && Bars.ClosePrices[index - 1] < maHigh[index - 1]))
                {
                    Chart.DrawIcon("KO Oscillator % Up" + Bars.OpenTimes.Last(0).ToString(), ChartIconType.UpArrow, Bars.OpenTimes.Last(0), Bars.LowPrices.Last(0) - (arrowDistance * atr.Result.Last(1)), "Teal");
                }
                else
                {
                    Chart.RemoveObject("KO Oscillator % Up" + Bars.OpenTimes.Last(0).ToString());
                }
                if ((percDSignal && priceDiff[index] < -percDFilter && priceDiff[index - 1] > -percDFilter) || (hlSignal && Bars.ClosePrices[index] < maLow[index] && Bars.ClosePrices[index - 1] > maLow[index - 1]))
                {
                    Chart.DrawIcon("KO Oscillator % Down" + Bars.OpenTimes.Last(0).ToString(), ChartIconType.DownArrow, Bars.OpenTimes.Last(0), Bars.HighPrices.Last(0) + (arrowDistance * atr.Result.Last(1)), "Brown");
                }
                else
                {
                    Chart.RemoveObject("KO Oscillator % Down" + Bars.OpenTimes.Last(0).ToString());
                }
            }
        }
    }
}


danieljclsilva's avatar
danieljclsilva

Joined on 15.03.2019

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: KC Oscillator % Mod v1.2.algo
  • Rating: 5
  • Installs: 1534
  • Modified: 13/10/2021 09:54
Comments
Log in to add a comment.
No comments found.