Category Trend  Published on 21/07/2019

Fourier Transform

Description

Follow my cTrader Telegram group at https://t.me/cTraderCommunity; everyone can talk about cTrader indicators and algorithm without restrictions, though it is not allowed to spam commercial indicators to sell them. There's also a Discord Server now @ https://discord.gg/5GAPMtp and an Instagram page https://www.instagram.com/ctrader_community/

This is the Fourier Transform converted from metatrader.

Unlike its original version, this indicator can be backtested by setting starting and ending points for the calculation and it can even take in sources different from the closing price.

To set starting and ending points, use, as usual, Shift + Click for the starting point and Ctrl + Click for the endpoint.

If you're applying this on another indicator, remember you should click on the main chart anyway to set the interval.

Have fun!

Do not expect this to be the holy grail btw, it's super hard to make fourier analysis work on markets.

For any bug report or suggestion, follow my telegram group or comment below


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 FourierTransform : Indicator
    {
        [Parameter("Period", DefaultValue = 300)]
        public int Npast { get; set; }
        [Parameter("Projection", DefaultValue = 50)]
        public int Nfut { get; set; }
        [Parameter("N° Harmonics", DefaultValue = 20)]
        public int Nharm { get; set; }
        [Parameter("Tolerance in Hz", DefaultValue = 1E-05)]
        public double FreqTOL { get; set; }
        [Parameter("Source")]
        public DataSeries src { get; set; }
        [Parameter("Show Starting and Ending Points", DefaultValue = true)]
        public bool points { get; set; }

        private int N;
        private IndicatorDataSeries ym, xm;
        private double w = 0, m = 0, a = 0, b = 0;
        public int end, start;
        private bool preview = false;

        [Output("Projection", LineColor = "Orange", PlotType = PlotType.DiscontinuousLine)]
        public IndicatorDataSeries proj { get; set; }
        [Output("Fit", LineColor = "RoyalBlue")]
        public IndicatorDataSeries fit { get; set; }

        protected override void Initialize()
        {
            ym = CreateDataSeries();
            xm = CreateDataSeries();
            N = Math.Max(Npast, Nfut + 1);
            if (Chart.BarsTotal < Npast)
                Chart.DrawStaticText("error", "Load more bars", VerticalAlignment.Center, HorizontalAlignment.Center, Color.Red);
            end = Chart.BarsTotal;
            start = Chart.BarsTotal - Npast;
            Chart.MouseDown += OnChartMouseDown;
        }

        void OnChartMouseDown(ChartMouseEventArgs obj)
        {
            if (obj.CtrlKey && !obj.AltKey && !obj.ShiftKey)
            {
                end = (int)obj.BarIndex;

                if (start < end)
                {
                    if (points)
                        Chart.DrawVerticalLine("end", end, Color.White);
                    Npast = (int)(end - start);
                    N = Math.Max(Npast, Nfut + 1);
                    _Calculate(end);
                }
            }
            if (!obj.CtrlKey && !obj.AltKey && obj.ShiftKey)
            {
                if ((int)obj.BarIndex < end)
                {
                    start = (int)obj.BarIndex;
                    if (points)
                        Chart.DrawVerticalLine("start", start, Color.Yellow);
                    Npast = (int)(end - start);
                    N = Math.Max(Npast, Nfut + 1);
                    _Calculate(end);
                }
                else
                {
                    Nfut = (int)obj.BarIndex - end;
                    N = Math.Max(Npast, Nfut + 1);
                    _Calculate(end);
                }
            }
        }

        public override void Calculate(int index)
        {
            if (IsLastBar && !preview)
            {
                _Calculate(index);
                preview = true;
            }
        }

        public void _Calculate(int index)
        {
            for (int i = 0; i < Chart.BarsTotal + 500; i++)
            {
                fit[i] = double.NaN;
                proj[i] = double.NaN;
            }
            double[] x = new double[Npast];
            double av = 0;

            //prepare input data
            for (int i = 0; i < Npast; i++)
            {
                x[i] = src[index - i];
                av += x[i];
            }
            av /= Npast;

            //initialize model output
            for (int i = index; i > index - N; i--)
            {
                xm[i] = av;
                ym[i] = av;
            }

            //fit trigonometric model and calculate predictions
            for (int harm = 1; harm <= Nharm; harm++)
            {
                w = 0;
                m = 0;
                a = 0;
                b = 0;
                Freq(x, Npast, index);
                for (int i = 0; i < N; i++)
                {
                    xm[index - i] += m + a * Math.Cos(w * i) + b * Math.Sin(w * i);
                    if (i <= Nfut)
                        ym[index - Nfut + i] += m + a * Math.Cos(w * i) - b * Math.Sin(w * i);
                }
            }
            for (int i = 0; i < N; i++)
            {
                if (i <= Npast)
                    fit[index - i] = xm[index - i];
                if (i <= Nfut)
                    proj[index + i] = ym[index - Nfut + i];
            }


        }

        private void Freq(double[] x, int n, int index)
        {
            double[] z = new double[n];
            double alpha = 0;
            double beta = 2;
            z[0] = x[0] - xm[index];
            while (Math.Abs(alpha - beta) > FreqTOL)
            {
                alpha = beta;
                z[1] = x[1] - xm[index - 1] + alpha * z[0];
                double num = z[0] * z[1];
                double den = z[0] * z[0];
                for (int i = 2; i < n; i++)
                {
                    z[i] = x[i] - xm[index - i] + alpha * z[i - 1] - z[i - 2];
                    num += z[i - 1] * (z[i] + z[i - 2]);
                    den += z[i - 1] * z[i - 1];
                }
                beta = num / den;
            }
            w = Math.Acos(beta / 2.0);
            TrigFit(x, n, index);
        }

        private void TrigFit(double[] x, int n, int index)
        {
            double Sc = 0.0;
            double Ss = 0.0;
            double Scc = 0.0;
            double Sss = 0.0;
            double Scs = 0.0;
            double Sx = 0.0;
            double Sxc = 0.0;
            double Sxs = 0.0;

            for (int i = 0; i < n; i++)
            {
                double c = Math.Cos(w * i);
                double s = Math.Sin(w * i);
                double dx = x[i] - xm[index - i];
                Sc += c;
                Ss += s;
                Scc += c * c;
                Sss += s * s;
                Scs += c * s;
                Sx += dx;
                Sxc += dx * c;
                Sxs += dx * s;
            }
            Sc /= n;
            Ss /= n;
            Scc /= n;
            Sss /= n;
            Scs /= n;
            Sx /= n;
            Sxc /= n;
            Sxs /= n;
            if (w == 0.0)
            {
                m = Sx;
                a = 0.0;
                b = 0.0;
            }
            else
            {
                double den = Math.Pow(Scs - Sc * Ss, 2) - (Scc - Sc * Sc) * (Sss - Ss * Ss);
                a = ((Sxs - Sx * Ss) * (Scs - Sc * Ss) - (Sxc - Sx * Sc) * (Sss - Ss * Ss)) / den;
                b = ((Sxc - Sx * Sc) * (Scs - Sc * Ss) - (Sxs - Sx * Ss) * (Scc - Sc * Sc)) / den;
                m = Sx - a * Sc - b * Ss;
            }

        }
    }
}


CY
cysecsbin.01

Joined on 10.11.2018 Blocked

  • Distribution: Free
  • Language: C#
  • Trading platform: cTrader Automate
  • File name: ! Fourier Transform.algo
  • Rating: 5
  • Installs: 1673
  • Modified: 13/10/2021 09:54
Comments
Log in to add a comment.
SY
sylwester.guzek · 4 years ago

Hello,

I need some help with running this indicator in cBot. The problem is that indicator is executed only one time on the beginning. Later on each new bar indicator values are not updated. I tried to force calculation of indicator calling Calculate() but it does not work.

Below code for problem replication, I will be appreciated for any advice.

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NEWFurierSandbox : Robot
    {

        [Parameter()]
        public DataSeries SourceSeries { get; set; }

        [Parameter(DefaultValue = 1, MinValue = 0)]
        public int Volume { get; set; }

        [Parameter("Period", DefaultValue = 100)]
        public int Npast { get; set; }

        [Parameter("Projection", DefaultValue = 10)]
        public int Nfut { get; set; }

        [Parameter("N° Harmonics", DefaultValue = 15)]
        public int Nharm { get; set; }

        [Parameter("Tolerance in Hz", DefaultValue = 1E-05)]
        public double FreqTOL { get; set; }

        [Parameter("Show Starting and Ending Points", DefaultValue = true)]
        public bool points { get; set; }

        private const string label = "NEW FT Sandbox";
        private FourierTransform ft;

        protected override void OnStart()
        {
            Print("initialization: ", Npast, " ", Nfut, " ", Nharm, " ", FreqTOL, " ", SourceSeries," ", points);
            ft = Indicators.GetIndicator<FourierTransform>(Npast, Nfut, Nharm, FreqTOL, SourceSeries, points);
        }

        protected override void OnBar()
        {
            for (int i = 0; i < 200; i++)
            {
                //ft.Calculate(i);
                Print(i, " >> ", ft.fit[i], " # ", ft.Proj[i], " # ", SourceSeries.Last(i));
                //ft.fit[i] = 0;
            }

        }

    }
}

 

20
2019 · 4 years ago

Интересно! Спасибо за работу!

eivaremir's avatar
eivaremir · 5 years ago

have u got any extra documentation?

HI
hiba7rain · 5 years ago
Hi , just wondering if you have created any indicator that might help spotting impuls moves and alert users