There are quite a few subtle difference between how MQL5 and MQL4 handle data.
I did not take a hard look at your code, and only skimmed it, but the first thing I noticed in your code, is that in your MQL5 code you are still treating the buffers and data arrays as "series" (current data is at index [0]), like how MQL4 does it, but in MQL5 they are treated ad normal arrays (current data is at the end [last]).
Either change the ordering of how you process the data, or simply use the "ArraySetAsSeries()" function to set all the buffer and data arrays so they are treated as "series", like in MQL4.
Fix that first, then come back with whatever other difficulties you face!
- www.mql5.com
The corrected Code is below. The results are better, but nevertheless not the same. By the way, the Indicator is called "qoutient transformation"
#property link "www.forex-tsd.com" #property copyright "www.forex-tsd.com" #property indicator_separate_window #property indicator_buffers 5 #property indicator_color1 clrDeepSkyBlue #property indicator_color2 clrSandyBrown #property indicator_width1 2 #property indicator_width2 2 #property indicator_plots 2 #property strict #define Pi 3.14159265358979323846264338327950288 #property indicator_style1 STYLE_SOLID #property indicator_type1 DRAW_LINE #property indicator_label1 "Quotient1" #property indicator_style2 STYLE_SOLID #property indicator_type2 DRAW_LINE #property indicator_label2 "Quotient2" double workSsm[][2]; #define _tprice 0 #define _ssm 1 double workSsmCoeffs[][4]; #define _speriod 0 #define _sc1 1 #define _sc2 2 #define _sc3 3 enum enPrices { pr_close, // Close pr_open, // Open pr_high, // High pr_low, // Low pr_median, // Median pr_typical, // Typical pr_weighted, // Weighted pr_average, // Average (high+low+open+close)/4 pr_medianb, // Average median body (open+close)/2 pr_tbiased, // Trend biased price pr_haclose, // Heiken ashi close pr_haopen , // Heiken ashi open pr_hahigh, // Heiken ashi high pr_halow, // Heiken ashi low pr_hamedian, // Heiken ashi median pr_hatypical, // Heiken ashi typical pr_haweighted, // Heiken ashi weighted pr_haaverage, // Heiken ashi average pr_hamedianb, // Heiken ashi median body pr_hatbiased // Heiken ashi trend biased price }; input int CalcPeriod = 20; // Calculation period input enPrices Price = pr_close; // Price input double Q1 = 0.8; // K for entries input double Q2 = 0.4; // K for exits double quot1[]; double quot2[],hp[],peak[],prices[]; int OnInit() { SetIndexBuffer(0,quot1); SetIndexBuffer(1,quot2); SetIndexBuffer(2,hp); SetIndexBuffer(3,prices); SetIndexBuffer(4,peak); ArraySetAsSeries(quot1,true); ArraySetAsSeries(quot2,true); ArraySetAsSeries(hp,true); ArraySetAsSeries(prices,true); ArraySetAsSeries(peak,true); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { int counted_bars=IndicatorCountedMQL4(prev_calculated); if(counted_bars<0) return(-1); if(counted_bars>0) counted_bars--; int limit = MathMin(Bars(_Symbol,PERIOD_CURRENT)-counted_bars,Bars(_Symbol,PERIOD_CURRENT)-1); // // // // // double angle = 0.707 * 2.0 * Pi /100; double alpha = (cos(angle)+sin(angle)-1.0)/cos(angle); for(int i=limit; i>=0; i--) { prices[i] = getPrice(Price,open,close,high,low,i); if (i>=Bars(_Symbol,PERIOD_CURRENT)-2) { hp[i] = prices[i]; peak[i] = prices[i]; continue; } // // // // // hp[i] = (1-alpha/2.0)*(1-alpha/2.0)*(prices[i]-2.0*prices[i+1]+prices[i+2]) + 2.0*(1-alpha)*hp[i+1] - (1-alpha)*(1-alpha)*hp[i+2]; peak[i] = 0.991*peak[i+1]; double hps = iSsm(hp[i],CalcPeriod,i); if (MathAbs(hps)>peak[i]) peak[i] = MathAbs(hps); double x = 0; if (peak[i] != 0) x=hps/peak[i]; // // // // // quot1[i] = (x+Q1)/(Q1*x+1.0); quot2[i] = (x+Q2)/(Q2*x+1.0); } ; return(rates_total); } double iSsm(double price, double period, int i, int instanceNo=0) { if (period<=1) return(price); if (ArrayRange(workSsm,0) !=Bars(_Symbol,PERIOD_CURRENT)) ArrayResize(workSsm,Bars(_Symbol,PERIOD_CURRENT)); if (ArrayRange(workSsmCoeffs,0) < (instanceNo+1)) ArrayResize(workSsmCoeffs,instanceNo+1); if (workSsmCoeffs[instanceNo][_speriod] != period) { workSsmCoeffs[instanceNo][_speriod] = period; double a1 = MathExp(-1.414*Pi/period); double b1 = 2.0*a1*MathCos(1.414*Pi/period); workSsmCoeffs[instanceNo][_sc2] = b1; workSsmCoeffs[instanceNo][_sc3] = -a1*a1; workSsmCoeffs[instanceNo][_sc1] = 1.0 - workSsmCoeffs[instanceNo][_sc2] - workSsmCoeffs[instanceNo][_sc3]; } // // // // // int s = instanceNo*2; i = Bars(_Symbol,PERIOD_CURRENT)-i-1; workSsm[i][s+_ssm] = price; workSsm[i][s+_tprice] = price; if (i>1) { workSsm[i][s+_ssm] = workSsmCoeffs[instanceNo][_sc1]*(workSsm[i][s+_tprice]+workSsm[i-1][s+_tprice])/2.0 + workSsmCoeffs[instanceNo][_sc2]*workSsm[i-1][s+_ssm] + workSsmCoeffs[instanceNo][_sc3]*workSsm[i-2][s+_ssm]; } return(workSsm[i][s+_ssm]); } //------------------------------------------------------------------ // //------------------------------------------------------------------ // // // // // // #define priceInstances 1 double workHa[][priceInstances*4]; double getPrice(int tprice, const double& open[], const double& close[], const double& high[], const double& low[], int i, int instanceNo=0) { if (tprice>=pr_haclose) { if (ArrayRange(workHa,0)!= Bars(_Symbol,PERIOD_CURRENT)) ArrayResize(workHa,Bars(_Symbol,PERIOD_CURRENT)); instanceNo*=4; int r = Bars(_Symbol,PERIOD_CURRENT)-i-1; // // // // // double haOpen; if (r>0) haOpen = (workHa[r-1][instanceNo+2] + workHa[r-1][instanceNo+3])/2.0; else haOpen = (open[i]+close[i])/2; double haClose = (open[i] + high[i] + low[i] + close[i]) / 4.0; double haHigh = MathMax(high[i], MathMax(haOpen,haClose)); double haLow = MathMin(low[i] , MathMin(haOpen,haClose)); if(haOpen <haClose) { workHa[r][instanceNo+0] = haLow; workHa[r][instanceNo+1] = haHigh; } else { workHa[r][instanceNo+0] = haHigh; workHa[r][instanceNo+1] = haLow; } workHa[r][instanceNo+2] = haOpen; workHa[r][instanceNo+3] = haClose; // // // // // switch (tprice) { case pr_haclose: return(haClose); case pr_haopen: return(haOpen); case pr_hahigh: return(haHigh); case pr_halow: return(haLow); case pr_hamedian: return((haHigh+haLow)/2.0); case pr_hamedianb: return((haOpen+haClose)/2.0); case pr_hatypical: return((haHigh+haLow+haClose)/3.0); case pr_haweighted: return((haHigh+haLow+haClose+haClose)/4.0); case pr_haaverage: return((haHigh+haLow+haClose+haOpen)/4.0); case pr_hatbiased: if (haClose>haOpen) return((haHigh+haClose)/2.0); else return((haLow+haClose)/2.0); } } // // // // // switch (tprice) { case pr_close: return(close[i]); case pr_open: return(open[i]); case pr_high: return(high[i]); case pr_low: return(low[i]); case pr_median: return((high[i]+low[i])/2.0); case pr_medianb: return((open[i]+close[i])/2.0); case pr_typical: return((high[i]+low[i]+close[i])/3.0); case pr_weighted: return((high[i]+low[i]+close[i]+close[i])/4.0); case pr_average: return((high[i]+low[i]+close[i]+open[i])/4.0); case pr_tbiased: if (close[i]>open[i]) return((high[i]+close[i])/2.0); else return((low[i]+close[i])/2.0); } return(0); } int IndicatorCountedMQL4(int prev_calculated) { if(prev_calculated>0) return(prev_calculated-1); if(prev_calculated==0) return(0); return(0); }
You also have to the e "ArraySetAsSeries()" for the data arrays at the beginning of the OnCalculate() function:
// Set Arrays as Series (example) ArraySetAsSeries( time, true ); ArraySetAsSeries( open, true ); ArraySetAsSeries( high, true ); ArraySetAsSeries( low, true ); ArraySetAsSeries( close, true ); ArraySetAsSeries( tick_volume, true );
Also, don't use the "Bars(_Symbol,PERIOD_CURRENT)", use the "rates_total" returned by the OnCalculate() function.
EDIT: and pass down the "rates_total" value to sub functions called so that they don't use "Bars()" either.
- www.mql5.com
You also have to the e "ArraySetAsSeries()" for the data arrays at the beginning of the OnCalculate() function:
Also, don't use the "Bars(_Symbol,PERIOD_CURRENT)", use the "rates_total" returned by the OnCalculate() function.
EDIT: and pass down the "rates_total" value to sub functions called so that they don't use "Bars()" either.
I have all OnCalculate() parameters SetAsSeries. The Indicator seems to work after this little changing and I am very happy now.
Now i also understand, what rates_total mean..
Here is the code and by the way. it´s a very good trend Indicator:
#property link "www.forex-tsd.com" #property copyright "www.forex-tsd.com" #property indicator_separate_window #property indicator_buffers 5 #property indicator_color1 clrDeepSkyBlue #property indicator_color2 clrSandyBrown #property indicator_width1 2 #property indicator_width2 2 #property indicator_plots 2 #property strict #define Pi 3.14159265358979323846264338327950288 #property indicator_style1 STYLE_SOLID #property indicator_type1 DRAW_LINE #property indicator_label1 "Quotient1" #property indicator_style2 STYLE_SOLID #property indicator_type2 DRAW_LINE #property indicator_label2 "Quotient2" double workSsm[][2]; #define _tprice 0 #define _ssm 1 double workSsmCoeffs[][4]; #define _speriod 0 #define _sc1 1 #define _sc2 2 #define _sc3 3 enum enPrices { pr_close, // Close pr_open, // Open pr_high, // High pr_low, // Low pr_median, // Median pr_typical, // Typical pr_weighted, // Weighted pr_average, // Average (high+low+open+close)/4 pr_medianb, // Average median body (open+close)/2 pr_tbiased, // Trend biased price pr_haclose, // Heiken ashi close pr_haopen , // Heiken ashi open pr_hahigh, // Heiken ashi high pr_halow, // Heiken ashi low pr_hamedian, // Heiken ashi median pr_hatypical, // Heiken ashi typical pr_haweighted, // Heiken ashi weighted pr_haaverage, // Heiken ashi average pr_hamedianb, // Heiken ashi median body pr_hatbiased // Heiken ashi trend biased price }; input int CalcPeriod = 20; // Calculation period input enPrices Price = pr_close; // Price input double Q1 = 0.8; // K for entries input double Q2 = 0.4; // K for exits double quot1[]; double quot2[],hp[],peak[],prices[]; int OnInit() { SetIndexBuffer(0,quot1); SetIndexBuffer(1,quot2); SetIndexBuffer(2,hp); SetIndexBuffer(3,prices); SetIndexBuffer(4,peak); ArraySetAsSeries(quot1,true); ArraySetAsSeries(quot2,true); ArraySetAsSeries(hp,true); ArraySetAsSeries(prices,true); ArraySetAsSeries(peak,true); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { ArraySetAsSeries( time, true ); ArraySetAsSeries( open, true ); ArraySetAsSeries( high, true ); ArraySetAsSeries( low, true ); ArraySetAsSeries( close, true ); ArraySetAsSeries( tick_volume, true ); int counted_bars=IndicatorCountedMQL4(prev_calculated); if(counted_bars<0) return(-1); if(counted_bars>0) counted_bars--; int limit = MathMin(rates_total-counted_bars,rates_total-1); // // // // // double angle = 0.707 * 2.0 * Pi /100; double alpha = (cos(angle)+sin(angle)-1.0)/cos(angle); for(int i=limit; i>=0; i--) { prices[i] = getPrice(rates_total,Price,open,close,high,low,i); if (i>=rates_total-2) { hp[i] = prices[i]; peak[i] = prices[i]; continue; } // // // // // hp[i] = (1-alpha/2.0)*(1-alpha/2.0)*(prices[i]-2.0*prices[i+1]+prices[i+2]) + 2.0*(1-alpha)*hp[i+1] - (1-alpha)*(1-alpha)*hp[i+2]; peak[i] = 0.991*peak[i+1]; double hps = iSsm(rates_total,hp[i],CalcPeriod,i); if (MathAbs(hps)>peak[i]) peak[i] = MathAbs(hps); double x = 0; if (peak[i] != 0) x=hps/peak[i]; // // // // // quot1[i] = (x+Q1)/(Q1*x+1.0); quot2[i] = (x+Q2)/(Q2*x+1.0); } ; return(rates_total); } double iSsm(int rates_total, double price, double period, int i, int instanceNo=0) { if (period<=1) return(price); if (ArrayRange(workSsm,0) !=Bars(_Symbol,PERIOD_CURRENT)) ArrayResize(workSsm,Bars(_Symbol,PERIOD_CURRENT)); if (ArrayRange(workSsmCoeffs,0) < (instanceNo+1)) ArrayResize(workSsmCoeffs,instanceNo+1); if (workSsmCoeffs[instanceNo][_speriod] != period) { workSsmCoeffs[instanceNo][_speriod] = period; double a1 = MathExp(-1.414*Pi/period); double b1 = 2.0*a1*MathCos(1.414*Pi/period); workSsmCoeffs[instanceNo][_sc2] = b1; workSsmCoeffs[instanceNo][_sc3] = -a1*a1; workSsmCoeffs[instanceNo][_sc1] = 1.0 - workSsmCoeffs[instanceNo][_sc2] - workSsmCoeffs[instanceNo][_sc3]; } // // // // // int s = instanceNo*2; i = rates_total-i-1; workSsm[i][s+_ssm] = price; workSsm[i][s+_tprice] = price; if (i>1) { workSsm[i][s+_ssm] = workSsmCoeffs[instanceNo][_sc1]*(workSsm[i][s+_tprice]+workSsm[i-1][s+_tprice])/2.0 + workSsmCoeffs[instanceNo][_sc2]*workSsm[i-1][s+_ssm] + workSsmCoeffs[instanceNo][_sc3]*workSsm[i-2][s+_ssm]; } return(workSsm[i][s+_ssm]); } //------------------------------------------------------------------ // //------------------------------------------------------------------ // // // // // // #define priceInstances 1 double workHa[][priceInstances*4]; double getPrice(int rates_total, int tprice, const double& open[], const double& close[], const double& high[], const double& low[], int i, int instanceNo=0) { if (tprice>=pr_haclose) { if (ArrayRange(workHa,0)!= rates_total) ArrayResize(workHa,rates_total); instanceNo*=4; int r = rates_total-i-1; // // // // // double haOpen; if (r>0) haOpen = (workHa[r-1][instanceNo+2] + workHa[r-1][instanceNo+3])/2.0; else haOpen = (open[i]+close[i])/2; double haClose = (open[i] + high[i] + low[i] + close[i]) / 4.0; double haHigh = MathMax(high[i], MathMax(haOpen,haClose)); double haLow = MathMin(low[i] , MathMin(haOpen,haClose)); if(haOpen <haClose) { workHa[r][instanceNo+0] = haLow; workHa[r][instanceNo+1] = haHigh; } else { workHa[r][instanceNo+0] = haHigh; workHa[r][instanceNo+1] = haLow; } workHa[r][instanceNo+2] = haOpen; workHa[r][instanceNo+3] = haClose; // // // // // switch (tprice) { case pr_haclose: return(haClose); case pr_haopen: return(haOpen); case pr_hahigh: return(haHigh); case pr_halow: return(haLow); case pr_hamedian: return((haHigh+haLow)/2.0); case pr_hamedianb: return((haOpen+haClose)/2.0); case pr_hatypical: return((haHigh+haLow+haClose)/3.0); case pr_haweighted: return((haHigh+haLow+haClose+haClose)/4.0); case pr_haaverage: return((haHigh+haLow+haClose+haOpen)/4.0); case pr_hatbiased: if (haClose>haOpen) return((haHigh+haClose)/2.0); else return((haLow+haClose)/2.0); } } // // // // // switch (tprice) { case pr_close: return(close[i]); case pr_open: return(open[i]); case pr_high: return(high[i]); case pr_low: return(low[i]); case pr_median: return((high[i]+low[i])/2.0); case pr_medianb: return((open[i]+close[i])/2.0); case pr_typical: return((high[i]+low[i]+close[i])/3.0); case pr_weighted: return((high[i]+low[i]+close[i]+close[i])/4.0); case pr_average: return((high[i]+low[i]+close[i]+open[i])/4.0); case pr_tbiased: if (close[i]>open[i]) return((high[i]+close[i])/2.0); else return((low[i]+close[i])/2.0); } return(0); } int IndicatorCountedMQL4(int prev_calculated) { if(prev_calculated>0) return(prev_calculated-1); if(prev_calculated==0) return(0); return(0); }
Please note that Ehler´s Quotient Transform, is used for Up-Trends and going Long or Buying. It is not designed for Down-Trends or going Short or Selling. It was invented mostly for stocks and other instruments which have a tendency to trend up.
Forex (and other similar instruments) are more bidirectional for which this indicator is not designed. You would have to reverse the logic in order to have an Indicator for working with Down-Trends, Shorting or Selling.
I don't think that it is a good idea to convert metatrader 4 indicator to metatrader 5 and trying to keep the metatrader 4 "way of working" (a lot of reasons not to do that)
So posted one "pure metatrader 5 version" here : https://www.mql5.com/en/forum/368391
- 2021.05.01
- www.mql5.com
I don't think that it is a good idea to convert metatrader 4 indicator to metatrader 5 and trying to keep the metatrader 4 "way of working" (a lot of reasons not to do that)
So posted one "pure metatrader 5 version" here : https://www.mql5.com/en/forum/368391
Please note that Ehler´s Quotient Transform, is used for Up-Trends and going Long or Buying. It is not designed for Down-Trends or going Short or Selling. It was invented mostly for stocks and other instruments which have a tendency to trend up.
Forex (and other similar instruments) are more bidirectional for which this indicator is not designed. You would have to reverse the logic in order to have an Indicator for working with Down-Trends, Shorting or Selling.
Nevertheless, thank you both!
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
I want to convert this indicator into mql5.
It´s really difficult written and i don´t know what possibly could be wrong. It draws the lines, but when i am going to compare it with the mql4 version, i can see differences between the plots.
Is there anyone who could help me further?
Here is the mql5 file:
and here the mql5 code:
Thanks for your help!