
Transferring an Indicator Code into an Expert Advisor Code. Conclusion
Introduction
In previous articles (Transferring an Indicator Code into an Expert Advisor Code. Indicator Structure and Transferring an Indicator Code into an Expert Advisor Code. General Structural Schemes of an Expert Advisor and Indicator Functions) we analyzed a general scheme of writing an indicator function on the basis of a ready indicator code and defined its correlation with an Expert Advisor. Now it is time to rewrite a code of a real Expert Advisor. So, let us begin.
EA Source Code
So, we have the following Expert Advisor Code:
//+------------------------------------------------------------------+ //| ASCTrend1RAVI_Expert.mq4 | //| Copyright © 2006, Nikolay Kositsin | //| Khabarovsk, farria@mail.redcom.ru | //+------------------------------------------------------------------+ #property copyright "Copyright © 2006, Nikolay Kositsin" #property link "farria@mail.redcom.ru" //---- INPUT PARAMETERS extern int RAVI_Timeframe = 240; extern int ASCT_Timeframe = 1440; //---- FILTER OF TRADE CALCULATION DIRECTION extern int Buy_Sell_Custom = 2; //0-Buy, 1-Sell, 2-Buy+Sell //---- INPUT PARAMETERS OF EA FOR BUY TRADES extern double Money_Management_Up=0.1; extern int RISK_Up = 3; extern int Period1_Up = 7; extern int Period2_Up = 65; extern int MA_Metod_Up = 0; extern int PRICE_Up = 0; extern int STOPLOSS_Up = 50; extern int TAKEPROFIT_Up = 100; //---- INPUT PARAMETERS OF EA FOR SELL TRADES extern double Money_Management_Dn = 0.1; extern int RISK_Dn = 3; extern int Period1_Dn = 7; extern int Period2_Dn = 65; extern int MA_Metod_Dn = 0; extern int PRICE_Dn = 0; extern int STOPLOSS_Dn = 50; extern int TAKEPROFIT_Dn = 100; //---- Emulated indicator buffers double RAVI_Up[3]; double RAVI_Dn[3]; double ASCTrend1_Up[2]; double ASCTrend1_Dn[2]; //+------------------------------------------------------------------+ //| Custom Expert functions | //+------------------------------------------------------------------+ #include <Lite_EXPERT.mqh> //+------------------------------------------------------------------+ //| Custom Expert initialization function | //+------------------------------------------------------------------+ int init() { //---- if(RAVI_Timeframe != 1) if(RAVI_Timeframe != 5) if(RAVI_Timeframe != 15) if(RAVI_Timeframe != 30) if(RAVI_Timeframe != 60) if(RAVI_Timeframe != 240) if(RAVI_Timeframe != 1440) Print("Parameter RAVI_Timeframe cannot" + " be equal to " + RAVI_Timeframe+"!!!"); //---- if(ASCT_Timeframe != 1) if(ASCT_Timeframe != 5) if(ASCT_Timeframe != 15) if(ASCT_Timeframe != 30) if(ASCT_Timeframe != 60) if(ASCT_Timeframe != 240) if(ASCT_Timeframe != 1440) Print("Parameter ASCT_Timeframe cannot" + " be equal "+ASCT_Timeframe+"!!!"); //---- if(RAVI_Timeframe > ASCT_Timeframe) Print("Parameter ASCT_Timeframe should not be less" + " than RAVI_Timeframe"); //---- initialization end return(0); } //+------------------------------------------------------------------+ //| Custom Expert iteration function | //+------------------------------------------------------------------+ int start() { //---- Checking whether the bars number is enough for further calculation if(iBars(NULL, ASCT_Timeframe) < 3 + RISK_Up*2 + 1 + 1) return(0); if(iBars(NULL, ASCT_Timeframe) < 3 + RISK_Dn*2 + 1 + 1) return(0); //---- if(iBars(NULL, RAVI_Timeframe) < MathMax(Period1_Up, Period2_Up + 4)) return(0); if(iBars(NULL, RAVI_Timeframe) < MathMax(Period1_Dn, Period2_Dn + 4)) return(0); //---- Declaration of variables static double ASCTrend1_Trend_Up, ASCTrend1_Trend_Dn; static int LastBars; int bar; bool BUY_Sign, SELL_Sign; //---- CALCULATION OF INDICATOR VALUES AND LOADING THEM TO BUFFERS if(LastBars != iBars(NULL, RAVI_Timeframe)) switch(Buy_Sell_Custom) { case 0: { for(bar = 1; bar <= 3; bar++) RAVI_Up[bar-1] = iCustom(NULL, RAVI_Timeframe, "RAVI", Period1_Up, Period2_Up, MA_Metod_Up, PRICE_Up, 0, bar); //----+ ASCTrend1_Up[0] = iCustom(NULL, ASCT_Timeframe, "ASCTrend1", RISK_Up, 0, 1); ASCTrend1_Up[1] = iCustom(NULL, ASCT_Timeframe, "ASCTrend1", RISK_Up, 1, 1); //----+ ASCTrend1_Trend_Up = ASCTrend1_Up[1] - ASCTrend1_Up[0]; break; } //---- case 1: { for(bar = 1; bar <= 3; bar++) RAVI_Dn[bar-1] = iCustom(NULL, RAVI_Timeframe, "RAVI", Period1_Dn, Period2_Dn, MA_Metod_Dn, PRICE_Dn, 0, bar); //----+ ASCTrend1_Dn[0] = iCustom(NULL, ASCT_Timeframe, "ASCTrend1", RISK_Dn, 0, 1); ASCTrend1_Dn[1] = iCustom(NULL, ASCT_Timeframe, "ASCTrend1", RISK_Dn, 1, 1); //----+ ASCTrend1_Trend_Dn =ASCTrend1_Dn[1] - ASCTrend1_Dn[0]; break; } //---- default: { for(bar = 1; bar <= 3; bar++) RAVI_Up[bar-1] = iCustom(NULL, RAVI_Timeframe, "RAVI", Period1_Up, Period2_Up, MA_Metod_Up, PRICE_Up, 0, bar); //----+ ASCTrend1_Up[0] = iCustom(NULL, ASCT_Timeframe, "ASCTrend1", RISK_Up, 0, 1); ASCTrend1_Up[1] = iCustom(NULL, ASCT_Timeframe, "ASCTrend1", RISK_Up, 1, 1); //----+ ASCTrend1_Trend_Up = ASCTrend1_Up[1] - ASCTrend1_Up[0]; //----+ for(bar = 1; bar <= 3; bar++) RAVI_Dn[bar-1] = iCustom(NULL, RAVI_Timeframe, "RAVI", Period1_Dn, Period2_Dn, MA_Metod_Dn, PRICE_Dn, 0, bar); //----+ ASCTrend1_Dn[0] = iCustom(NULL, ASCT_Timeframe, "ASCTrend1", RISK_Dn, 0, 1); ASCTrend1_Dn[1] = iCustom(NULL, ASCT_Timeframe, "ASCTrend1", RISK_Dn, 1, 1); //----+ ASCTrend1_Trend_Dn = ASCTrend1_Dn[1] - ASCTrend1_Dn[0]; } } //---- Variable initialization LastBars = iBars(NULL, RAVI_Timeframe); //---- DEFINING SIGNALS FOR TRADES switch(Buy_Sell_Custom) { //---- case 0: { if(RAVI_Up[1] - RAVI_Up[2] < 0) if(RAVI_Up[0] - RAVI_Up[1] > 0) if(ASCTrend1_Trend_Up > 0) BUY_Sign = true; break; } //----+ +---------------------------+ case 1: { if(RAVI_Dn[1] - RAVI_Dn[2] > 0) if(RAVI_Dn[0] - RAVI_Dn[1] < 0) if(ASCTrend1_Trend_Dn < 0) SELL_Sign = true; break; } //---- default: { if(RAVI_Up[1] - RAVI_Up[2] < 0) if(RAVI_Up[0] - RAVI_Up[1] > 0) if(ASCTrend1_Trend_Up > 0) BUY_Sign = true; //---- if(RAVI_Dn[1] - RAVI_Dn[2] > 0) if(RAVI_Dn[0] - RAVI_Dn[1] < 0) if(ASCTrend1_Trend_Dn < 0) SELL_Sign = true; } } //---- EXECUTING TRADES switch(Buy_Sell_Custom) { //---- case 0: { OpenBuyOrder(BUY_Sign, Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up); break; } //---- case 1: { OpenSellOrder(SELL_Sign, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn); break; } //---- default: { OpenBuyOrder(BUY_Sign, Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up); OpenSellOrder(SELL_Sign, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn); } } return(0); } //+------------------------------------------------------------------+
First we need to analyze this Expert Advisor. The Expert Advisor is intended for trading on the basis of 4-hour and daily charts on a currency pair chosen by a trader. The EA can open only one position on one currency pair in this trading direction. The EA has two independent calculation algorithms for executing buy and sell trades, that is why it can open opposite positions.
For a quicker optimization of the EA in the strategy tester, it contains an external variable Buy_Sell_Custom - if it is equal to zero, the EA calculates only Buy signals. If the variable Buy_Sell_Custom is equal to one, only Sell signals are calculated. If we need both calculations, the external variable Buy_Sell_Custom should be equal to two. Other external variables are divided into two groups: for Buy and Sell trades.
Trade signals are the changes of the movement direction of the custom indicator RAVI.mq4, the filter, cutting off false signals is the trend direction, determined by the custom indicator ASCTrend1.mq4. The Expert Advisor has two calls of the indicator ASCTrend1.mq4 for receiving from the zero and the first indicator buffer source values; the sign of their difference determines the trend direction. The EA also has two calls of the indicator RAVI.mq4, for receiving two variants (Buy and Sell) of source values for the two calculation algorithms.
I suppose the meaning of the majority of the EA input parameters should be understandable from their names. The variables MA_Metod_Up and MA_Metod_Dn determine the method of averaging. They may have different values from zero to three. The variables PRICE_Up and PRICE_Dn have values of price constants, limits of their changing are from zero to six.
This Expert Advisor is unambiguously not a loss one, and despite its simplicity it shows quite good results at a good optimization. So it is worth investing some efforts into transforming it from a set of files into a single self-sufficient file. The EA code uses the file Lite_EXPERT.mqh, which is actually two custom functions, by calling which the EA executes trades:
//+------------------------------------------------------------------+ //| Lite_EXPERT.mqh | //| Version January 7, 2007 Final | //| Copyright © 2006, Nikolay Kositsin | //| Khabarovsk, farria@mail.redcom.ru | //+------------------------------------------------------------------+ //---- Declaring a global variable for remembering the time // of the last reference to a server int LastTime; //+------------------------------------------------------------------+ //| OpenBuyOrder() | //+------------------------------------------------------------------+ int OpenBuyOrder(bool BUY_Signal, double Money_Management, int STOPLOSS, int TAKEPROFIT) { if(!BUY_Signal) return(0); if(TimeLocal() - LastTime < 11) return(0); int total = OrdersTotal(); //---- Checking if there is an open position on this trading // pair in Buy direction for(int ttt = total - 1; ttt >= 0; ttt--) if(OrderSelect(ttt, SELECT_BY_POS, MODE_TRADES)) if((OrderSymbol() == Symbol()) && (OrderType() == 0)) return(0); //---- double ask = NormalizeDouble(Ask, Digits); double bid = NormalizeDouble(Bid, Digits); //---- if(ask == 0.0) return(-1); if(bid == 0.0) return(-1); //---- double LotVel; double tickVel = MarketInfo(Symbol(), MODE_TICKVALUE); if(tickVel == 0) return(-1); //---- if(Money_Management > 0) LotVel = tickVel*AccountEquity()*Money_Management / 10000.0; else LotVel = -tickVel*10000*Money_Management / 10000.0; //---- double Lot = NormalizeDouble(LotVel, 1); if(Lot < 0.1) return(-1); //----+ Open Buy position double Stoploss = NormalizeDouble(bid - STOPLOSS*Point, Digits); double TakeProfit = NormalizeDouble(ask + TAKEPROFIT*Point, Digits); //---- int ticket = OrderSend(Symbol(), OP_BUY, Lot, ask, 3, Stoploss, TakeProfit, NULL, 0, 0, CLR_NONE); //---- LastTime = TimeLocal(); //---- if(ticket > 0) return(1); else return(-1); } //+------------------------------------------------------------------+ //| OpenSellOrder() | //+------------------------------------------------------------------+ int OpenSellOrder(bool SELL_Signal, double Money_Management, int STOPLOSS, int TAKEPROFIT) { if(!SELL_Signal) return(0); if(TimeLocal() - LastTime < 11) return(0); int total = OrdersTotal(); //---- Checking if there is an open position on this trading // pair in Sell direction for(int kkk = total - 1; kkk >= 0; kkk--) if(OrderSelect(kkk, SELECT_BY_POS, MODE_TRADES)) if((OrderSymbol() == Symbol()) && (OrderType() == 1)) return(0); //---- double bid = NormalizeDouble(Bid, Digits); double ask = NormalizeDouble(Ask, Digits); //---- if(bid == 0.0) return(-1); if(ask == 0.0) return(-1); //---- double LotVel; double tickVel = MarketInfo(Symbol(), MODE_TICKVALUE); if(tickVel == 0.0) return(-1); //---- if(Money_Management > 0) LotVel = tickVel*AccountEquity()*Money_Management / 10000.0; else LotVel = -tickVel*10000*Money_Management / 10000.0; //---- double Lot = NormalizeDouble(LotVel, 1); if(Lot < 0.1) return(-1); //----+ Open Sell position double Stoploss = NormalizeDouble(ask + STOPLOSS*Point, Digits); double TakeProfit = NormalizeDouble(bid - TAKEPROFIT*Point, Digits); //---- int ticket = OrderSend(Symbol(), OP_SELL, Lot, bid, 3, Stoploss, TakeProfit, NULL, 0, 0,CLR_NONE); //---- LastTime = TimeLocal(); //---- if(ticket > 0) return(1); else return(-1); } //+------------------------------------------------------------------+
I suppose these functions are quite simple and there should not be any difficulties with them. Here is the algorithm of reference to the functions:
OpenBuyOrder(BUY_Sign, Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up); OpenSellOrder(SELL_Sign, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn);
Here if BUY_Sign=true the function OpenBuyOrder() opens a long position, if SELL_Sign=true, the function OpenSellOrder() opens a short position. Meaning of parameters: Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn is understandable from their names!
Writing an Indicator Function Get_ASCTrend1Series()
At the end of the previous article (Transferring an Indicator Code into an Expert Advisor Code. General Structural Schemes of an Expert Advisor and Indicator Functions) I presented the indicator function Get_RAVISeries(). It will be rather useful now. All we need is write an analogous function for the indicator ASCTrend1.mq4. Now on the basis of this indicator code we will write the function Get_ASCTrend1Series(). So, let us have a look at this indicator code:
//+------------------------------------------------------------------+ //| ASCTrend1 | //| Ramdass - Conversion only | //+------------------------------------------------------------------+ //---- drawing the indicator in the main window #property indicator_chart_window //---- number of indicator buffers #property indicator_buffers 2 //---- indicator color #property indicator_color1 Magenta #property indicator_color2 Aqua //---- width of indicator lines #property indicator_width1 2 #property indicator_width2 2 //---- INPUT PARAMETERS OF THE INDICATOR extern int RISK = 3; //---- indicator buffers double val1[]; double val2[]; //+------------------------------------------------------------------+ //| ASCTrend1 initialization function | //+------------------------------------------------------------------+ int init() { //---- Chart drawing style SetIndexStyle(0, DRAW_HISTOGRAM, 0, 2); SetIndexStyle(1, DRAW_HISTOGRAM, 0, 2); //---- 2 indicator buffers are used for calculation SetIndexBuffer(0, val1); SetIndexBuffer(1, val2); //---- setting indicator values that will be unseen on the chart SetIndexEmptyValue(0, 0.0); SetIndexEmptyValue(1, 0.0); //---- name for data windows and labels for subwindows IndicatorShortName("ASCTrend1"); SetIndexLabel(0, "DownASCTrend1"); SetIndexLabel(1, "UpASCTrend1"); //---- return(0); } //+------------------------------------------------------------------+ //| ASCTrend1 | //+------------------------------------------------------------------+ int start() { //---- introducing memory variables static double x1, x2; //---- Introducing floating point variables double value1, value2, value3, TrueCount, Range, AvgRange, MRO1, MRO2; //---- Introducing integer variables and getting already calculated bars int MaxBar, iii, kkk, bar, value10, value11, counted_bars = IndicatorCounted(); //---- checking for possible errors if(counted_bars < 0) return(-1); //---- the last calculated bar must be recalculated if(counted_bars > 0) counted_bars--; //---- variable initialization value10 = 3 + RISK*2; //---- checking whether the bars number is enough for further calculation if((Bars <= value10) || (Bars < 10)) return(0); //---- defining the number of the oldest bar, // starting from which all bars will be fully recalculated MaxBar = Bars - 1 - value10; //---- defining the number of the oldest bar, // starting from which only new bars will be recalculated bar = Bars - 1 - counted_bars; //---- zero initialization if(bar >= MaxBar) { x1 = 67 + RISK; x2 = 33 - RISK; bar = MaxBar; //---- for(kkk = Bars - 1; kkk >= MaxBar; kkk--) { val1[kkk] = 0.0; val2[kkk] = 0.0; } } //---- THE MAIN CYCLE OF INDICATOR CALCULATION while(bar >= 0) { Range = 0.0; AvgRange = 0.0; for(iii = 0; iii <= 9; iii++) AvgRange += MathAbs(High[bar+iii] - Low[bar+iii]); //---- Range = AvgRange / 10; iii = 0; TrueCount = 0; while(iii < 9 && TrueCount < 1) { if(MathAbs(Open[bar+iii] - Close[bar+iii]) >= Range*2.0) TrueCount++; //---- iii++; } if(TrueCount >= 1) MRO1 = bar + iii; else MRO1 = -1; //---- iii = 0; TrueCount = 0; while(iii < 6 && TrueCount < 1) { if(MathAbs(Close[bar+iii+3] - Close[bar+iii]) >= Range*4.6) TrueCount++; //---- iii++; } if(TrueCount >= 1) MRO2 = bar + iii; else MRO2 = -1; //---- if(MRO1 > -1) value11 = 3; else value11 = value10; //---- if(MRO2 > -1) value11 = 4; else value11 = value10; //---- value2 = 100 - MathAbs(iWPR(NULL, 0, value11, bar)); //---- val1[bar] = 0; val2[bar] = 0; //---- if(value2 > x1) { val1[bar] = Low [bar]; val2[bar] = High[bar]; } //---- if(value2 < x2) { val1[bar] = High[bar]; val2[bar] = Low [bar]; } //---- bar--; } return(0); } //+------------------------------------------------------------------+
I optimized this indicator. The original version is in the attached file ASCTrend1_Old!. mq4. Now let us prepare the function Get_ASCTrend1Series(). For this purpose we will transform the code of the indicator ASCTrend1.mq4 according to the scheme of its code improvement, described in the previous article. As a result we get the following custom function:
//+------------------------------------------------------------------+ //| Get_ASCTrend1Series.mqh | //| Copyright © 2006, Nikolay Kositsin | //| Khabarovsk, farria@mail.redcom.ru | //+------------------------------------------------------------------+ bool Get_ASCTrend1Series(int Number, string symbol,int timeframe, bool NullBarRecount, int RISK, double& InputBuffer[]) { //---- getting the number of all bars of a chart int IBARS = iBars(symbol, timeframe); //---- Checking whether the bars number is enough for further calculation if((IBARS < 3 + RISK*2 + 1)||(IBARS < 10)) return(false); //---- EMULATION OF INDICATOR BUFFERS if(ArraySize(InputBuffer) < IBARS) { ArraySetAsSeries(InputBuffer, false); //---- ArrayResize(InputBuffer, IBARS); //---- ArraySetAsSeries(InputBuffer, true); } //----+ introducing static memory variables static double x1[], x2[]; static int IndCounted[]; //----+ changing size of static variables if(ArraySize(IndCounted) < Number + 1) { ArrayResize(x1, Number + 1); ArrayResize(x2, Number + 1); ArrayResize(IndCounted, Number + 1); } //----+ introducing integer variable int LastCountBar; //----+ Checking whether the zero bar recalculation is allowed if(!NullBarRecount) LastCountBar = 1; //----+ Introducing floating point variables double value1, value2, value3, val1, val2; double TrueCount, Range, AvgRange, MRO1, MRO2; //----+ Introducing integer variables and getting already calculated bars int MaxBar, iii, kkk, bar, value10, value11, counted_bars = IndCounted[Number]; //----+ Remembering the number of all bars of the chart IndCounted[Number] = IBARS - 1; //---- variable initialization value10 = 3 + RISK*2; //---- defining the number of the oldest bar, // starting from which new bars will be recalculated bar = IBARS - counted_bars - 1; //---- defining the number of the oldest bar, // starting from which all bars will be recalculated MaxBar = IBARS - 1 - value10; //---- zero initialization if(bar > MaxBar) { bar = MaxBar; x1[Number] = 67 + RISK; x2[Number] = 33 - RISK; //---- ArrayInitialize(InputBuffer, 0.0); } //---- THE MAIN CYCLE OF INDICATOR CALCULATION while(bar >= LastCountBar) { Range = 0.0; AvgRange = 0.0; for(iii = 0; iii <= 9; iii++) AvgRange += MathAbs(iHigh(symbol, timeframe, bar + iii) - iLow(symbol, timeframe, bar + iii)); //---- Range = AvgRange / 10; iii = 0; TrueCount = 0; while(iii < 9 && TrueCount < 1) { if(MathAbs(iOpen(symbol, timeframe, bar + iii) - iClose(symbol, timeframe, bar + iii)) >= Range*2.0) TrueCount++; //---- iii++; } if(TrueCount >= 1) MRO1 = bar + iii; else MRO1 = -1; //---- iii = 0; TrueCount = 0; while(iii < 6 && TrueCount < 1) { if(MathAbs(iClose(symbol, timeframe, bar + iii + 3) - iClose(symbol, timeframe, bar + iii)) >= Range*4.6) TrueCount++; //---- iii++; } if(TrueCount >= 1) MRO2 = bar + iii; else MRO2 = -1; //---- if(MRO1 > -1) value11 = 3; else value11 = value10; if(MRO2 > -1) value11 = 4; else value11 = value10; //---- value2 = 100 - MathAbs(iWPR(symbol, timeframe, value11, bar)); //---- val1 = 0; val2 = 0; InputBuffer[bar] = 0; //---- if(value2 > x1[Number]) { val1 = iLow (symbol, timeframe, bar); val2 = iHigh(symbol, timeframe, bar); } if(value2 < x2[Number]) { val1 = iHigh(symbol, timeframe, bar); val2 = iLow(symbol, timeframe, bar); } InputBuffer[bar]=val2-val1; bar--; } //----+ return(true); } //+------------------------------------------------------------------+
Of course this function is more difficult than the one described at the end of the previous article. But while the indicator source code was written and optimized without errors, the process of creating this function is not very problematic!
After that the function needs to be tested for the correspondence of its values with the indicator values, based on which the function was developed. For this purpose we should once again create a tester Expert Advisor for the function Get_ASCTrend1Series():
//+------------------------------------------------------------------+ //| Get_ASCTrend1SeriesTest.mq4 | //| Copyright © 2007, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2007, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" //---- INPUT PARAMETERS OF THE EA extern bool NullBarRecount = true; //---- indicator buffers double IndBuffer0[]; double IndBuffer1[]; double IndBuffer2[]; //+------------------------------------------------------------------+ //| Get_ASCTrend1Series() functions | //+------------------------------------------------------------------+ #include <Get_ASCTrend1Series.mqh> //+------------------------------------------------------------------+ //| Custom Expert initialization function | //+------------------------------------------------------------------+ int init() { //---- initialization end return(0); } //+------------------------------------------------------------------+ //| Custom Expert iteration function | //+------------------------------------------------------------------+ int start() { //---- double Ind_Velue,Resalt; //---- if(!Get_ASCTrend1Series(0, Symbol(), 0, NullBarRecount, 1, IndBuffer0)) return(0); if(!Get_ASCTrend1Series(1, Symbol(), 240, NullBarRecount, 3, IndBuffer1)) return(0); if(!Get_ASCTrend1Series(2, Symbol(), 1440, NullBarRecount, 5, IndBuffer2)) return(0); //---- getting indicator values for the test 0 Ind_Velue = iCustom(NULL, 0, "ASCTrend1", 1, 1, 2) - iCustom(NULL, 0, "ASCTrend1", 1, 0, 2); Resalt = IndBuffer0[2] - Ind_Velue; Print("0: " + Ind_Velue + " " + IndBuffer0[2] + " " + Resalt + ""); //---- getting indicator values for the test 1 Ind_Velue = iCustom(NULL, 240, "ASCTrend1", 3, 1, 2) - iCustom(NULL, 240, "ASCTrend1", 3, 0, 2); Resalt = IndBuffer1[2] - Ind_Velue; Print("H4: " + Ind_Velue + " " + IndBuffer1[2] + " " + Resalt + ""); //---- getting indicator values for the test 2 Ind_Velue = iCustom(NULL, 1440, "ASCTrend1", 5, 1, 2) - iCustom(NULL, 1440, "ASCTrend1", 5, 0, 2); Resalt = IndBuffer2[2] - Ind_Velue; Print("Daily: " + Ind_Velue + " " + IndBuffer2[2] + " " + Resalt + ""); //---- return(0); } //+------------------------------------------------------------------+
Start testing this Expert Advisor in the startegy tester and after that check the log-file to make sure that our function's values are fully identical with the indicator's ones in terms of filling with emulated indicator buffer values!
Final Transformation of the Initial Expert Advisor Code
And now finally we can transform the EA code, substituting custom indicator calls for custom indicator function calls:
//+------------------------------------------------------------------+ //| NewASCTrend1RAVI_Expert.mq4 | //| Copyright © 2006, Nikolay Kositsin | //| Khabarovsk, farria@mail.redcom.ru | //+------------------------------------------------------------------+ #property copyright "Copyright © 2006, Nikolay Kositsin" #property link "farria@mail.redcom.ru" //---- INPUT PARAMETERS extern int RAVI_Timeframe = 240; extern int ASCT_Timeframe = 1440; //---- FILTER OF TRADE CALCULATION DIRECTION extern int Buy_Sell_Custom = 2; // 0-Buy, 1-Sell, 2-Buy+Sell //---- INPUT PARAMETERS OF EA FOR BUY TRADES extern double Money_Management_Up = 0.1; extern int RISK_Up = 3; extern int Period1_Up = 7; extern int Period2_Up = 65; extern int MA_Metod_Up = 0; extern int PRICE_Up = 0; extern int STOPLOSS_Up = 50; extern int TAKEPROFIT_Up = 100; //---- INPUT PARAMETERS OF EA FOR SELL TRADES extern double Money_Management_Dn = 0.1; extern int RISK_Dn = 3; extern int Period1_Dn = 7; extern int Period2_Dn = 65; extern int MA_Metod_Dn = 0; extern int PRICE_Dn = 0; extern int STOPLOSS_Dn = 50; extern int TAKEPROFIT_Dn = 100; //---- Emulated indicator buffers double RAVI_Up[]; double RAVI_Dn[]; double ASCTrend1_Up[]; double ASCTrend1_Dn[]; //+------------------------------------------------------------------+ //| Get_ASCTrend1Series functions() | //+------------------------------------------------------------------+ #include <Get_ASCTrend1Series.mqh> //+------------------------------------------------------------------+ //| Get_RAVISeries functions() | //+------------------------------------------------------------------+ #include <Get_RAVISeries.mqh> //+------------------------------------------------------------------+ //| Custom Expert functions | //+------------------------------------------------------------------+ #include <Lite_EXPERT.mqh> //+------------------------------------------------------------------+ //| Custom Expert initialization function | //+------------------------------------------------------------------+ int init() { //---- if(RAVI_Timeframe != 1) if(RAVI_Timeframe != 5) if(RAVI_Timeframe != 15) if(RAVI_Timeframe != 30) if(RAVI_Timeframe != 60) if(RAVI_Timeframe != 240) if(RAVI_Timeframe != 1440) Print("Parameter RAVI_Timeframe cannot" + " be equal to " + RAVI_Timeframe + "!!!"); //---- if(ASCT_Timeframe != 1) if(ASCT_Timeframe != 5) if(ASCT_Timeframe != 15) if(ASCT_Timeframe != 30) if(ASCT_Timeframe != 60) if(ASCT_Timeframe != 240) if(ASCT_Timeframe != 1440) Print("Parameter ASCT_Timeframe cannot" + " be equal to "+ ASCT_Timeframe+"!!!"); //---- if(RAVI_Timeframe > ASCT_Timeframe) Print("Parameter ASCT_Timeframe should not be " + "less than RAVI_Timeframe"); //---- initialization end return(0); } //+------------------------------------------------------------------+ //| Custom Expert iteration function | //+------------------------------------------------------------------+ int start() { //---- Checking whether the bars number is enough for further calculation if(iBars(NULL, ASCT_Timeframe) < 3 + RISK_Up*2 + 1 + 1) return(0); if(iBars(NULL, ASCT_Timeframe) < 3 + RISK_Dn*2 + 1 + 1) return(0); //---- if(iBars(NULL, RAVI_Timeframe) < MathMax(Period1_Up, Period2_Up + 4)) return(0); if(iBars(NULL, RAVI_Timeframe) < MathMax(Period1_Dn, Period2_Dn + 4)) return(0); //---- Declaring variables for blocking zero bar recalculation static int LastBars; //---- Declaring logic variables for trend signals bool BUY_Sign, SELL_Sign; //---- CALCULATION OF INDICATOR VALUES AND LOADING THEM TO BUFFERS if(LastBars != iBars(NULL, RAVI_Timeframe)) switch(Buy_Sell_Custom) { case 0: { Get_RAVISeries(0, Symbol(), RAVI_Timeframe, false, Period1_Up, Period2_Up, MA_Metod_Up, PRICE_Up, RAVI_Up); //---- Get_ASCTrend1Series(0, Symbol(), ASCT_Timeframe, false, RISK_Up, ASCTrend1_Up); break; } case 1: { Get_RAVISeries(1, Symbol(), RAVI_Timeframe, false, Period1_Dn, Period2_Dn, MA_Metod_Dn, PRICE_Dn, RAVI_Dn); //---- Get_ASCTrend1Series(1, Symbol(), ASCT_Timeframe, false, RISK_Dn, ASCTrend1_Dn); break; } default: { Get_RAVISeries(0, Symbol(), RAVI_Timeframe, false, Period1_Up, Period2_Up, MA_Metod_Up, PRICE_Up, RAVI_Up); //---- Get_ASCTrend1Series(0, Symbol(), ASCT_Timeframe, false, RISK_Up, ASCTrend1_Up); //---- Get_RAVISeries(1, Symbol(), RAVI_Timeframe, false, Period1_Dn, Period2_Dn,MA_Metod_Dn, PRICE_Dn,RAVI_Dn); //---- Get_ASCTrend1Series(1, Symbol(), ASCT_Timeframe, false, RISK_Dn, ASCTrend1_Dn); } } //---- Variable initialization LastBars = iBars(NULL, RAVI_Timeframe); //---- DEFINING SIGNALS FOR TRADES switch(Buy_Sell_Custom) { case 0: { if(RAVI_Up[2] - RAVI_Up[3] < 0) if(RAVI_Up[1] - RAVI_Up[2] > 0) if(ASCTrend1_Up[1] > 0) BUY_Sign = true; break; } case 1: { if(RAVI_Dn[2] - RAVI_Dn[3] > 0) if(RAVI_Dn[1] - RAVI_Dn[2] < 0) if(ASCTrend1_Dn[1] < 0) SELL_Sign = true; break; } default: { if(RAVI_Up[2] - RAVI_Up[3] < 0) if(RAVI_Up[1] - RAVI_Up[2] > 0) if(ASCTrend1_Up[1] > 0) BUY_Sign = true; //----+ if(RAVI_Dn[2] - RAVI_Dn[3] > 0) if(RAVI_Dn[1] - RAVI_Dn[2] < 0) if(ASCTrend1_Dn[1] < 0) SELL_Sign = true; } } //---- EXECUTING TRADES switch(Buy_Sell_Custom) { case 0: { OpenBuyOrder(BUY_Sign, Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up); break; } case 1: { OpenSellOrder(SELL_Sign, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn); break; } default: { OpenBuyOrder(BUY_Sign, Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up); OpenSellOrder(SELL_Sign, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn); } } return(0); } //+------------------------------------------------------------------+
Of course the last transformation of the EA code needed some changes inside the function start() in the part "DEFINING SIGNALS FOR TRADES" because of changes in the positions of cells used in emulated indicator buffers as compared to source buffers.
Testing Results of the Final and the Source Expert Advisors
Now we may load the final EA into a strategy tester and compare the results of its operation on history with the same results of the EA before transformation. And we see no difference in trading results in testing the EA by history in both cases. Both EA variants give absolutely identical testing results if the testing periods are the same, the same values of external variables are loaded into EAs and the same testing method is used.
But what is clear at first sight is that in all situations the final Expert Advisor works slower than the source EA!
What is the reason for the larger EA testing time? We may suppose that it is somehow connected with using emulation of the indicator mode of buffers operation and returning values by indicator functions into buffers by reference. Of course all this may be further developed by omitting the emulation of the indicator mode of buffers' operation. You may have a look at the EA FastNewASCTrend1RAVI_Expert. mq4 and test it. But in this case the situation is absolutely the same - this EA operates as slow as the previous one. So, the following conclusion is obvious: in our quite a simple case of code transformation using absolutely resource-unintensive indicators their substitution for custom functions for a quicker EA operation is absolutely unreasonable!
Conclusion
For Expert Advisors that use references to quite resource-unintensive indicators, the task of making them quicker by substituting custom indicator calls for custom function calls is generally unsolvable! However, if one has a great desire to develop an absolutely autonomous Expert Advisor, consisting of a single file and omit calling custom indicators, one can do this. But it will require much effort, because this task cannot be simplified. So this desire must be supported by very serious reasons.
Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/1463





- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
Ваша статья помогла мне прийти к выводам о том, как моя энергия может быть лучше израсходованы. Я по-прежнему занимать высший Поцелуя принципе, ваша работа, которая оказывает поддержку. Очень информативное серии действительно. (Просьба сделать пособие для .RU xlat:)
для вашего здоровья!