I've converted the AFIRMA indicator from MQL4
to C#
. It outputs the first series correctly (FIRMA) but the second one is stuck somewhere in the code (ARMA). Any ideas where or what keeps it from outputting? It seems like it's stuck somewhere.
Thank you for your time.
namespace cAlgo.Indicators
{
[Indicator(ScalePrecision = 5, AutoRescale = true, IsOverlay = true, AccessRights = AccessRights.None)]
public class AFIRMA : Indicator
{
[Parameter("Periods", DefaultValue = 12)]
public int Periods { get; set; }
[Parameter("Taps", DefaultValue = 25)]
public int Taps { get; set; }
[Parameter("Window", DefaultValue = 4)]
public int Window { get; set; }
[Output("FIRMA", Color = Colors.Blue, PlotType = PlotType.DiscontinuousLine)]
public IndicatorDataSeries FIRMA { get; set; }
[Output("ARMA", Color = Colors.Red, PlotType = PlotType.DiscontinuousLine)]
public IndicatorDataSeries ARMA { get; set; }
int n;
double den;
double sx6;
double sx5;
double sx4;
double sx3;
double sx2;
double wsum;
double[] w;
protected override void Initialize()
{
//Calculate weights
Array.Resize(ref w, Taps);
wsum = 0.0;
for (int k = 0; k < Taps; k++)
{
switch (Window)
{
case 1:
w[k] = 1.0;
break;
case 2:
w[k] = 0.5 - 0.5 * Math.Cos(2.0 * Math.PI * k / Taps);
break;
case 3:
w[k] = 0.54 - 0.46 * Math.Cos(2.0 * Math.PI * k / Taps);
break;
case 4:
w[k] = 0.42 - 0.5 * Math.Cos(2.0 * Math.PI * k / Taps) + 0.08 * Math.Cos(4.0 * Math.PI * k / Taps);
break;
case 5:
w[k] = 0.35875 - 0.48829 * Math.Cos(2.0 * Math.PI * k / Taps) + 0.14128 * Math.Cos(4.0 * Math.PI * k / Taps) - 0.01168 * Math.Cos(6.0 * Math.PI * k / Taps);
break;
default:
w[k] = 1;
break;
}
if (k != Taps / 2.0)
w[k] = w[k] * Math.Sin(Math.PI * (k - Taps / 2.0) / Periods) / Math.PI / (k - Taps / 2.0);
wsum += w[k];
}
//Calculate sums for the least-squares method
n = (Taps - 1) / 2;
sx2 = (2 * n + 1) / 3.0;
sx3 = n * (n + 1) / 2.0;
sx4 = sx2 * (3 * n * n + 3 * n - 1) / 5.0;
sx5 = sx3 * (2 * n * n + 2 * n - 1) / 3.0;
sx6 = sx2 * (3 * n * n * n * (n + 2) - 3 * n + 1) / 7.0;
den = sx6 * sx4 / sx5 - sx5;
}
public override void Calculate(int index)
{
//Calculate FIR MA for all bars except for the last n bars
for (int i = 0; i <= Bars - Taps; i++)
{
FIRMA[i + n] = 0.0;
for (int k = 0; k < Taps; k++)
FIRMA[i + n] += MarketSeries.Close[i + k] * w[k] / wsum;
}
//Calculate regressive MA for the remaining n bars
double a0 = FIRMA[n];
double a1 = FIRMA[n] - FIRMA[n + 1];
double sx2y = 0.0;
double sx3y = 0.0;
for (int i = 0; i <= n; i++)
{
sx2y += i * i * MarketSeries.Close[n - i];
sx3y += i * i * i * MarketSeries.Close[n - i];
}
sx2y = 2.0 * sx2y / n / (n + 1);
sx3y = 2.0 * sx3y / n / (n + 1);
double p = sx2y - a0 * sx2 - a1 * sx3;
double q = sx3y - a0 * sx3 - a1 * sx4;
double a2 = (p * sx6 / sx5 - q) / den;
double a3 = (q * sx4 / sx5 - p) / den;
for (int i = 0; i <= n; i++)
{
ARMA[n - i] = a0 + i * a1 + i * i * a2 + i * i * i * a3;
return;
}
}
private int Bars
{
get { return MarketSeries.Close.Count; }
}
}
}
MQL4 reference code:
#property copyright "Copyright © 2006, gpwr."
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Blue
#property indicator_color2 Red
#property indicator_width1 2
#property indicator_width2 2
//Global constants
#define pi 3.141592653589793238462643383279502884197169399375105820974944592
//Input parameters
extern int Periods = 4; // 1/(2*Periods) sets the filter bandwidth
extern int Taps = 21; // must be an odd number
extern int Window = 4; // selects windowing function
//Global variables
double w[], wsum, sx2, sx3, sx4, sx5, sx6, den;
int n;
//Indicator buffers
double FIRMA[];
double ARMA[];
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int init()
{
//Calculate weights
ArrayResize(w, Taps);
wsum = 0.0;
for(int k = 0; k < Taps; k++)
{
switch(Window)
{
case 1: w[k] = 1.0; // Rectangular window
break;
case 2: w[k] = 0.50 - 0.50*MathCos(2.0*pi*k / Taps); // Hanning window
break;
case 3: w[k] = 0.54 - 0.46*MathCos(2.0*pi*k / Taps); // Hamming window
break;
case 4: w[k] = 0.42 - 0.50*MathCos(2.0*pi*k / Taps) +
0.08*MathCos(4.0*pi*k / Taps); // Blackman window
break;
case 5: w[k] = 0.35875 - 0.48829*MathCos(2.0*pi*k / Taps) +
0.14128*MathCos(4.0*pi*k / Taps) -
0.01168*MathCos(6.0*pi*k / Taps); // Blackman - Harris window
break;
default: w[k] = 1; //Rectangular window
break;
}
if(k != Taps / 2.0)
w[k] = w[k]*MathSin(pi*(k - Taps / 2.0) / Periods) / pi / (k - Taps / 2.0);
wsum += w[k];
}
//Calculate sums for the least-squares method
n = (Taps - 1) / 2;
sx2 = (2*n + 1) / 3.0;
sx3 = n*(n + 1) / 2.0;
sx4 = sx2*(3*n*n+3*n - 1) / 5.0;
sx5 = sx3*(2*n*n+2*n - 1) / 3.0;
sx6 = sx2*(3*n*n*n*(n + 2) - 3*n+1) / 7.0;
den = sx6*sx4 / sx5 - sx5;
//Initialize indicator
IndicatorBuffers(2);
SetIndexBuffer(0, FIRMA);
SetIndexBuffer(1, ARMA);
SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2);
SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 2);
IndicatorShortName("AFIRMA");
return(0);
}
int deinit()
{
return(0);
}
int start()
{
//Calculate FIR MA for all bars except for the last n bars
ArrayInitialize(FIRMA, EMPTY_VALUE);
for(int i = 0; i <= Bars - Taps; i++)
{
FIRMA[i+n] = 0.0;
for(int k = 0; k < Taps; k++)
FIRMA[i+n] += Close[i+k]*w[k] / wsum;
}
//Calculate regressive MA for the remaining n bars
double a0 = FIRMA[n];
double a1 = FIRMA[n] - FIRMA[n+1];
double sx2y = 0.0;
double sx3y = 0.0;
for(i = 0; i <= n; i++)
{
sx2y += i*i*Close[n-i];
sx3y += i*i*i*Close[n-i];
}
sx2y = 2.0*sx2y / n / (n + 1);
sx3y = 2.0*sx3y / n / (n + 1);
double p = sx2y - a0*sx2 - a1*sx3;
double q = sx3y - a0*sx3 - a1*sx4;
double a2 = (p*sx6 / sx5 - q) / den;
double a3 = (q*sx4 / sx5 - p) / den;
ArrayInitialize(ARMA, EMPTY_VALUE);
for(i = 0; i <= n; i++)
ARMA[n-i] = a0 + i*a1 + i*i*a2 + i*i*i*a3;
return(0);
}
Indicator Copyright: Vladimir (Copyright © 2006, gpwr) Link: https://www.mql5.com/ru/code/11186
How it should look:
Dark Blue and Dark Red lines: Original and proper way the indicator should Output. Bright Blue line: How this specific code is outputting and Orange line which does not output at all.
Addendum from a comment below:
All the values of variables used:
The output seems to have everything it needs in order to render but still, something is preventing it to do so. Even with an offsetted output it should still render something on the chart. That's why I chose to set an Autoscale to see if anything pops up anytime.
Update: Almost Done!
I've managed to fix the Outputting problem for ARMA. It was a problem of indexing. But on a new bar, I see, some variables don't render anymore and the output completely disappears. If i go hit build for the indicator code it renders again for 1 bar(dynamic fluctuations within the variables during the present candle are happening, so it works just fine, up until the new bar). This should be the last issue to fix and we can call it a solved case. Anyone? Any ideas?
namespace cAlgo.Indicators
{
[Indicator(ScalePrecision = 5, AutoRescale = true, IsOverlay = true, AccessRights = AccessRights.None)]
public class AFIRMA: Indicator
{
[Parameter("Periods", DefaultValue = 15)]
public int Periods { get; set; }
[Parameter("Taps", DefaultValue = 31)]
public int Taps { get; set; }
[Parameter("Window", DefaultValue = 4)]
public int Window { get; set; }
[Output("FIRMA", Color = Colors.Blue, PlotType = PlotType.DiscontinuousLine)]
public IndicatorDataSeries FIRMA { get; set; }
[Output("ARMA", Color = Colors.Red, PlotType = PlotType.DiscontinuousLine)]
public IndicatorDataSeries ARMA { get; set; }
int n;
double den;
double sx6;
double sx5;
double sx4;
double sx3;
double sx2;
double wsum;
double[] w;
protected override void Initialize()
{
//Calculate weights
Array.Resize(ref w, Taps);
wsum = 0.0;
for (int k = 0; k < Taps; k++)
{
switch (Window)
{
case 1:
w[k] = 1.0;
break;
case 2:
w[k] = 0.5 - 0.5 * Math.Cos(2.0 * Math.PI * k / Taps);
break;
case 3:
w[k] = 0.54 - 0.46 * Math.Cos(2.0 * Math.PI * k / Taps);
break;
case 4:
w[k] = 0.42 - 0.5 * Math.Cos(2.0 * Math.PI * k / Taps) + 0.08 * Math.Cos(4.0 * Math.PI * k / Taps);
break;
case 5:
w[k] = 0.35875 - 0.48829 * Math.Cos(2.0 * Math.PI * k / Taps) + 0.14128 * Math.Cos(4.0 * Math.PI * k / Taps) - 0.01168 * Math.Cos(6.0 * Math.PI * k / Taps);
break;
default:
w[k] = 1;
break;
}
if (k != Taps / 2.0)
w[k] = w[k] * Math.Sin(Math.PI * (k - Taps / 2.0) / Periods) / Math.PI / (k - Taps / 2.0);
wsum += w[k];
}
//Calculate sums for the least-squares method
n = (Taps - 1) / 2;
sx2 = (2 * n + 1) / 3.0;
sx3 = n * (n + 1) / 2.0;
sx4 = sx2 * (3 * n * n + 3 * n - 1) / 5.0;
sx5 = sx3 * (2 * n * n + 2 * n - 1) / 3.0;
sx6 = sx2 * (3 * n * n * n * (n + 2) - 3 * n + 1) / 7.0;
den = sx6 * sx4 / sx5 - sx5;
//Calculate FIR MA for all bars except for the last n bars
for (int i = 0; i <= Bars - Taps; i++)
{
FIRMA[i + n] = 0.0;
for (int k = 0; k < Taps; k++)
FIRMA[i + n] += MarketSeries.Close[i + k] * w[k] / wsum;
}
}
public override void Calculate(int index)
{
//Calculate regressive MA for the remaining n bars
double a0 = FIRMA[index - n];
double a1 = FIRMA[index - n] - FIRMA[index - n - 1];
double sx2y = 0.0;
double sx3y = 0.0;
for (int i = 0; i <= n; i++)
{
sx2y += i * i * MarketSeries.Close[index + i - n];
sx3y += i * i * i * MarketSeries.Close[index + i - n];
}
sx2y = 2.0 * sx2y / n / (n + 1);
sx3y = 2.0 * sx3y / n / (n + 1);
double p = sx2y - a0 * sx2 - a1 * sx3;
double q = sx3y - a0 * sx3 - a1 * sx4;
double a2 = (p * sx6 / sx5 - q) / den;
double a3 = (q * sx4 / sx5 - p) / den;
for (int i = 0; i <= n; i++)
{
ARMA[index + i - n] = a0 + i * a1 + i * i * a2 + i * i * i * a3;
//ChartObjects.DrawText("test", "ARMA: " + ARMA[index + i - n] + "\na0: " + a0 + "\na1: " + a1 + "\na2: " + a2 + "\na3: " + a3 + "\nn: " + n + "\ni: " + i + "\np: " + p + "\nq: " + q + "\nsx2y: " + sx2y + "\nsx3y: " + sx3y + "\nsx2: " + sx2 + "\nsx3: " + sx3 + "\nsx4: " + sx4 + "\nsx5: " + sx5 + "\nsx6: " + sx6 + "\nden: " + den, StaticPosition.TopRight);
}
}
private int Bars
{
get { return MarketSeries.Close.Count; }
}
}
}