Category Trend  Published on 19/09/2021

Pseudo Point and Figure

Description

This is a pseudo point anf figure indicator which can be plotted on normal time charts. The box size can either be a fix number in pips or fluctuate based on volatility (ATR). The reversal amount is typically three times the box size but can also be set to any other number. It is also possible to use high and lows prices for calculating the movement while using only closing prices there will be less movement.


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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class PseudoPointandFigure : Indicator
    {
        [Parameter("Source", Group = "Source", DefaultValue = PriceType.OHLC4)]
        public PriceType Source { get; set; }

        [Parameter("Use High/Low", Group = "Source", DefaultValue = false)]
        public bool UseHL { get; set; }

        [Parameter("Use ATR", Group = "Box", DefaultValue = false)]
        public bool UseAtr { get; set; }

        [Parameter("ATR Period", Group = "Box", DefaultValue = 14)]
        public int AtrPeriod { get; set; }

        [Parameter("ATR Multi", Group = "Box", DefaultValue = 1.0)]
        public double AtrMulti { get; set; }

        [Parameter("Box Size (Pips) without ATR", Group = "Box", DefaultValue = 10.0)]
        public double BoxSize { get; set; }

        [Parameter("Reversal Size (# Boxes)", Group = "Box", DefaultValue = 3.0, Step = 1.0)]
        public double Reversal { get; set; }



        [Output("Main", LineColor = "LightBlue", Thickness = 1)]
        public IndicatorDataSeries Result { get; set; }

        [Output("Rising", LineColor = "FF0FFF00", PlotType = PlotType.Points, Thickness = 8)]
        public IndicatorDataSeries Rising { get; set; }

        [Output("Falling", LineColor = "FFFF006B", PlotType = PlotType.Points, Thickness = 8)]
        public IndicatorDataSeries Falling { get; set; }



        private AverageTrueRange ATR;
        private int direction;
        private double nextLevel, reverse;
        private DataSeries priceSource;

        public enum PriceType
        {
            Close,
            Weighted,
            Typical,
            Median,
            OHLC4
        }


        protected override void Initialize()
        {
            if (UseAtr)
            {
                ATR = Indicators.AverageTrueRange(AtrPeriod, MovingAverageType.Simple);
            }

            switch (Source)
            {
                default:
                case PriceType.Close:
                    priceSource = Bars.ClosePrices;
                    break;
                case PriceType.Weighted:
                    priceSource = Bars.WeightedPrices;
                    break;
                case PriceType.Typical:
                    priceSource = Bars.TypicalPrices;
                    break;
                case PriceType.Median:
                    priceSource = Bars.MedianPrices;
                    break;
                case PriceType.OHLC4:
                    priceSource = null;
                    break;
            }
        }

        public override void Calculate(int index)
        {
            if (index < (UseAtr ? AtrPeriod : 1))
            {
                Result[index] = Bars.ClosePrices[index];
                direction = 1;
                nextLevel = Bars.ClosePrices[index] + BoxSize * Symbol.PipSize;
                reverse = Bars.ClosePrices[index] - BoxSize * Symbol.PipSize * Reversal;
            }
            else
            {
                double price = priceSource != null ? priceSource[index] : (Bars.OpenPrices[index] + Bars.HighPrices[index] + Bars.LowPrices[index] + Bars.ClosePrices[index]) / 4.0;
                double high = UseHL ? Bars.HighPrices[index] : price;
                double low = UseHL ? Bars.LowPrices[index] : price;
                double box = UseAtr ? AtrMulti * ATR.Result[index] : BoxSize * Symbol.PipSize;

                if (direction > 0)
                {
                    if (high >= nextLevel)
                    {
                        while (high >= nextLevel)
                        {
                            Result[index] = nextLevel;
                            nextLevel += box;
                            reverse += box;
                        }
                    }
                    else if (low <= reverse)
                    {
                        Result[index] = reverse;
                        direction = -1;
                        nextLevel -= (Reversal + 2.0) * box;
                        reverse += box * Reversal;
                        while (low <= nextLevel)
                        {
                            Result[index] = nextLevel;
                            nextLevel -= box;
                            reverse -= box;
                        }
                    }
                    else
                    {
                        Result[index] = !double.IsNaN(Result[index]) ? Result[index] : Result[index - 1];
                    }
                }
                else
                {
                    if (low <= nextLevel)
                    {
                        while (low <= nextLevel)
                        {
                            Result[index] = nextLevel;
                            nextLevel -= box;
                            reverse -= box;
                        }
                    }
                    else if (high >= reverse)
                    {
                        Result[index] = reverse;
                        direction = 1;
                        nextLevel += (Reversal + 2.0) * box;
                        reverse -= box * Reversal;
                        while (high >= nextLevel)
                        {
                            Result[index] = nextLevel;
                            nextLevel += box;
                            reverse += box;
                        }
                    }
                    else
                    {
                        Result[index] = !double.IsNaN(Result[index]) ? Result[index] : Result[index - 1];
                    }
                }

                Rising[index] = double.NaN;
                Falling[index] = double.NaN;

                if (direction > 0)
                {
                    Rising[index] = Result[index];
                }
                else
                {
                    Falling[index] = Result[index];
                }
            }
        }
    }
}


CW
cW22Trader

Joined on 16.03.2021

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: Pseudo Point and Figure.algo
  • Rating: 0
  • Installs: 1579
  • Modified: 13/10/2021 09:54
Comments
Log in to add a comment.
77
77suns · 2 years ago

Nice work. Please improve it to have a alert function when the color dotes changes.

CW
cW22Trader · 3 years ago

Improved version with some bug-fixes and calculaton method more like point & figure or Renk.