Übertragen eines Indikator Code in einen Expert Advisor Code. Abschluss
Einführung
In den vorherigen Artikeln (Übertragen eines Indikator Code in einen Expert Advisor Code. Indikator-Strukturund Übertragen eines Indikator Code in einen Expert Advisor Code. Allgemeine Strukturelle Regelungen von Expert Advisor und Anzeigefunktionen) haben wir das allgemeine Schema des Schreibens einer Anzeigefunktion auf der Basis eines fertigen Indikator Codes analysiert und seine Korrelation mit einem Expert Advisor definiert. Nun ist es an der Zeit, den Code eines richtigen Expert Advisor zu schreiben. Also, lassen Sie uns beginnen.
EA Quellcode
Also, wir haben den folgenden 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); } //+------------------------------------------------------------------+
Zunächst müssen wir diesen Expert Advisor analysieren. Der Expert Advisor ist für den Handel auf Basis von 4-Stunden und Tages-Chart gedacht, auf einen Währungspaar, das von dem Trader ausgewählt wird. Der EA kann nur eine Position von einem Währungspaar in eine Handelsrichtung öffnen. Der EA verfügt über zwei unabhängige Berechnungsalgorithmen zur Ausführung von Sell und Buy Trades, weshalb er entgegengesetzte Positionen öffnen kann.
Für eine schnellere Optimierung des EA im Strategietester, enthält er eine externe Variable Buy_Sell_Custom - wen sie gleich Null ist, berechnet der EA nur Buy-Signale. Wenn die Variable Buy_Sell_Custom gleich Eins ist, werden nur Sell-Signale berechnet. Wenn wir beide Berechnungen benötigen, muss die externe Variable Buy_Sell_Custom gleich Zwei sein. Andere externe Variablen sind in zwei Gruppen unterteilt: für Buy und Sell Trades.
Die Handelssignale sind Änderungen in der Bewegungsrichtung des benutzerdefinierten Indikators RAVI.mq4, der Filter für falsche Signale ist die Trendrichtung, bestimmt durch den benutzerdefinierten Indikator ASCTrend1.mq4. Der Expert Advisor verfügt über zwei Aufrufe des Indikators ASCTrend1.mq4 für den Erhalt des Null- und der ersten Anzeigepuffer Quellwerte. Das Zeichen ihrer Differenz bestimmt die Trendrichtung. Der EA verfügt außerdem über zwei Aufrufe des Indikators RAVI.mq4, für den Empfang von zwei Varianten (Buy und Sell) von Quellwerten für die zwei Berechnungsalgorithmen.
Ich nehme an, die Mehrheit der Eingabeparameter sollte durch ihre Namen verständlich sein. Die Variablen MA_Metod_Up und MA_Metod_Dn bestimmen die Methode der Mittelwertbestimmung. Sie müssen unterschiedliche Werte von Null bis Drei haben. Die Variablen Price_Up und Price_Dn haben Werte von Preis-Konstanten, Grenzen ihrer Änderung sind von Null bis Sechs.
Dieser Expert Advisor ist eindeutig kein verlierender, und trotz seiner Einfachheit, zeigt er ziemlich gute Ergebnisse bei einer guten Optimierung. Also ist es etwas Mühe wert, ihn von einem Satz an Dateien in eine einzelne autarke Datei zu wandeln. Der Ea Code verwendet die Datei Lite_Expert.mqh, die eigentlich zwei benutzerdefinierte Funktionen sind, durch deren Aufruf der EA Trades ausführt:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Ich nehme an, diese Funktionen sind ziemlich einfach, und es sollte keine Schwierigkeiten mit ihnen geben. Hier ist der Algorithmus, der auf die Funktionen verweist:
OpenBuyOrder(BUY_Sign, Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up);
OpenSellOrder(SELL_Sign, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn);
Wenn hier BUY_Sign=true öffnet die Funktion OpenBuyOrder() eine Long-Position, wenn SELL_Sign=true, öffnet die Funktion OpenSellOrder() eine Short-Position. Bedeutung von Parametern: Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn ist verständlich durch deren Namen!
Schreiben einer Anzeigefunktion Get_ASCTrend1Series()
Am Ende des vorherigen Artikels (Übertragen eines Indikator Code in einen Expert Advisor Code. Allgemeine Strukturelle Regelungen von Expert Advisor und Anzeigefunktionen) stellte ich die Anzeigefunktion Get_RAVISeries() vor. Sie wäre jetzt ziemlich nützlich. Alles, was wir brauchen, ist eine analoge Funktion für den Indikator ASCTrend1.mq4 zu schreiben. Nun werden wir auf der Basis des Indikator-Codes die Funktion Get_ASCTrend1Series() schreiben. Werfen wir also einen Blick auf den Indikator-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); } //+------------------------------------------------------------------+
Ich habe diesen Indikator optimiert. Die Originalversion ist in der angehängten Datei ASCTrend1_Old!. mq4. Nun wollen wir die Funktion Get_ASCTrend1Series() vorbereiten. Zu diesem Zweck verändern wir den Code des Indikators ASCTrend1.mq4 entsprechend dem Schema seiner Code-Verbesserungen, beschrieben in dem vorherigen Artikel. Als Ergebnis erhalten wir die folgende benutzerdefinierte Funktion:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Natürlich ist diese Funktion schwieriger als die am Ende des vorherigen Artikels beschriebene. Aber während der Indikator-Quellcode geschrieben und ohne Fehler optimiert wurde, ist der Vorgang der Erstellung dieser Funktion nicht sehr problematisch!
Danach muss die Funktion auf die Übereinstimmung ihrer Werte mit den Indikatorwerten getestet werden. Zu diese Zweck sollten wir noch einmal einen Tester Expert Advisor für die Funktion Get_ASCTrend1Series() erstellen:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Starten Sie das Testen dieses Expert Advisors im Strategietester und danach prüfen Sie die Protokolldatei, um sicherzustellen, dass die Werte unserer Funktion vollständig identisch mit denen des Indikators sind, in Bezug auf das Füllen der emulierten Anzeigepuffer-Werte!
Letzte Änderung des anfänglichen Expert Advisor Code
Und jetzt können wir endlich den EA-Code umwandeln, ersetzen benutzerdefinierte Indikator-Aufrufe durch benutzerdefinierte Anzeigefunktion-Aufrufe:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Natürlich benötigt die letzte Umwandlung des EA-Code einige Änderungen innerhalb der Funktion start() in dem Teil "DEFINING SIGNALS FOR TRADES" wegen der verwendeten Änderungen in den Positionen von Zellen in emulierten Anzeigepuffern, im Vergleich zu Quellpuffern.
Testergebnisse des Endgültigen und des Quell-Expert-Advisor
Jetzt können wir den endgültigen EA in den Strategietester laden, und seine Ergebnisse des Betriebs mit historischen Daten mit den Ergebnissen des EA vor der Umwandlung vergleichen. Und wir sehen in beiden Fällen keinen Unterschied in den Handelsergebnissen beim Testen des EA mit der Historie. Beide EA Varianten erzielen absolut identische Testergebnisse, wenn der Testzeitraum identisch ist, die gleichen Werte der externen Variablen in die EAs geladen werden und die gleiche Testmethode verwendet wird.
Was aber auf den ersten Blick klar ist, dass in allen Situationen der endgültige Expert Advisor langsamer arbeitet als der Quell-EA!
Was ist der Grund für die längere EA-Testzeit? Wir können annehmen, dass es irgendwie mit der verwendeten Emulation des Anzeigemodus des Pufferbetriebs und zurückgegebenen Werten durch Anzeigefunktionen in Puffer durch Verweis verbunden ist. Natürlich kann all dies weiterentwickelt werden, durch Weglassen der Emulation des Anzeigemodus des Pufferbetriebs. Sie können einen Blick auf den EA FastNewASCTrend1RAVI_Expert. mq4 werfen und ihn testen. Aber in diesem Fall sind die Situationen absolut die gleichen - dieser EA arbeitet so langsam wie der vorherige. Also, das folgende Fazit ist offensichtlich: in unserem ziemlich einfachen Fall der Code-Umwandlung unter Verwendung absolut Ressourcen-schonender Indikatoren, ist ihr Ersatz durch benutzerdefinierte Funktionen für schnelleren EA-Betrieb absolut unvernünftig!
Fazit
Für Expert Advisors die Verweise zu sehr Ressourcen-schonenden Indikatoren, ist die Aufgabe sie schneller zu machen mit dem Ersatz von benutzerdefinierten Indikator-Aufrufen durch benutzerdefinierte Funktionsaufrufe in der Regel unlösbar! Allerdings, wenn jemand das große Verlangen hat einen absolut unabhängigen Expert Advisor zu entwickeln, bestehend aus einer einzigen Datei und dem Weglassen von Aufrufen benutzerdefinierter Indikatoren, kann man dies machen. Es wird aber viel Mühe erfordern, weil diese Aufgabe nicht vereinfacht werden kann. Also muss dieses Verlangen von sehr schwerwiegenden Gründen unterstützt werden.
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1463
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.