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;
}
}
}
}
cysecsbin.01
Joined on 10.11.2018 Blocked
- Distribution: Free
- Language: C#
- Trading platform: cTrader Automate
- File name: ! Fourier Transform.algo
- Rating: 5
- Installs: 1686
- Modified: 13/10/2021 09:54
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.