
Wie man einen einfachen Multi-Currency Expert Advisor mit MQL5 erstellt (Teil 7): Signale von ZigZag und dem Awesome Oszillator
Einführung
Der Multi-Currency Expert Advisor ist ein automatisierter Handelsroboter, der Aufträge für mehr als ein Symbolpaar von einem einzigen Symbolchart aus öffnen, schließen und verwalten kann.
Dieser Artikel konzentriert sich auf den Expert Advisor, der 30 Paare handelt und den ZigZag-Indikator verwendet, der mit dem Awesome Oscillator gefiltert wird oder umgekehrt.
Wie in früheren Artikeln gezeigt wurde, ist der Handel mit mehreren Währungen möglich, wenn man die Leistung, die Fähigkeiten und die Möglichkeiten von MQL5 sowohl im Handelsterminal als auch im Strategietester nutzt.
Um die Bedürfnisse von Händlern zu erfüllen, die einen effizienten und effektiven automatisierten Handel suchen, verlassen wir uns auf die Leistung, die Fähigkeiten und die Möglichkeiten, die das zuverlässige MQL5 bietet. Unser Ziel ist es, einen einfachen Multi-Currency Expert Advisor zu erstellen, der verschiedene Ideen und Strategien verwendet. Dieser Artikel konzentriert sich auf die Verwendung des ZigZag-Indikators, der mit dem Awesome Oscillator oder durch gegenseitiges Filtern der Signale gefiltert wird.
Pläne und Eigenschaften
1. Handel mit Währungspaaren.
Dieser Mehr-Währungs-EA ist für den Handel mit einem der folgenden Symbole oder Paare vorgesehen:
Für Forex:
EURUSD,GBPUSD,AUDUSD,NZDUSD,USDCAD,USDCHF,USDJPY,EURGBP,EURAUD, EURNZD, EURCAD, EURCHF, EURJPY, GBPAUD, GBPNZD,
GBPCAD,GBPCHF,GBPJPY,AUDNZD,AUDCAD,AUDCHF,AUDJPY,NZDCAD,NZDCHF,NZDJPY, CADCHF, CADJPY, CHFJPY = 28 Paare,
Plus 2 Metallpaare: XAUUSD (Gold) und XAGUSD (Silber),
insgesamt sind es 30 Paare.
Um einen reibungslosen Betrieb des in diesem Artikel besprochenen Expert Advisors zu gewährleisten, habe ich eine Funktion implementiert, die automatisch Symbolnamen mit Präfixen und/oder Suffixen behandelt.
Es ist jedoch wichtig zu beachten, dass diese Funktion nur für Forex- und Metall-Symbolpaare im MT5 funktioniert, nicht aber für spezielle Symbole und Indizes.
1.1. Zusätzliche Merkmale:
1.1.1. Single Currency Expert Advisor
Einige Nutzer haben sich erkundigt, ob sie diesen Multi-Currency EA auch als Einzelwährungs-EA oder als Stand-Alone-EA verwenden können.
Um dieses Problem zu lösen, wurde eine Funktion hinzugefügt, die es ermöglicht, diesen Multi-Currency EA als Single-Currency EA zu verwenden.
In den Optionen für die Auswahl des Handelsmodus (Multi oder Single) können Händler zwischen zwei Bedingungen für Handelspaare wählen: Einzelwährung oder Multiwährung.
1. Single Pair (Einzelwährung)
2. Multi Pairs (mehrere Währungen)
Stellen Sie die Experteneingabeparameter wie in der folgenden Abbildung gezeigt ein
Wenn „Single Pair“ (Einzelpaar) ausgewählt ist:
Die Option „SP“ oder „Single-Pair“ beschränkt den Expertenberater auf den Handel mit dem Paar, auf dem er platziert ist.
Wenn beispielsweise ein Expert Advisor auf das Währungspaar EURUSD eingestellt ist, wird er nur mit dem Währungspaar EURUSD handeln.
Wenn „Multi Pairs“ (Mehrwährung) ausgewählt ist:
Die Optionsgruppe „Selected Pairs to Trade“ (Ausgewählte, zu handelnde Paare) enthält 10 Optionspaare, die gehandelt werden sollen.
Eines dieser Paare heißt „Trader's Wishes Pairs“ (des Händlers Wunschpaare), bei dem der Händler die zu handelnden Paare manuell in die Eigenschaft „Expert Input“ eingeben muss.
Es ist jedoch zu beachten, dass der Name des eingegebenen Paares bereits in der Liste der 30 Paare enthalten sein muss.
Die Option „Trader's Wishes Pairs“ kann verwendet werden, um sicherzustellen, dass Expert Advisors nur mit einzelnen Währungen handeln oder als eigenständiger EA arbeiten.
Der Expert Advisor handelt oder arbeitet nur mit dem gewünschten Symbolen. Dies gewährleistet einen konzentrierten Ansatz für den Handel oder die Arbeit an einem einzigen Paar.
Wenn der Händler nur den Namen des Paares XAUUSD eingibt, handelt der Expert Advisor nur mit diesem Paar.
Der Expert Advisor handelt nur mit dem Paar XAUUSD, unabhängig von seiner Platzierung unter den 30 verfügbaren Paaren.
Die Einstellungen für den Parameter Expert Input müssen wie in der Abbildung unten dargestellt konfiguriert werden.
In diesem Artikel gibt es also zwei Möglichkeiten, mit Einzelwährungen zu handeln oder als eigenständiger Expert Advisor mit den Expert Advisors zu arbeiten.
1. Bleiben Sie bei der Multi-Pair- oder „MP“-Option und wählen Sie die Option „Trader's Desired Pairs“. Geben Sie jedoch nur einen Paar-Namen ein, z. B. XAUUSD.
Mit dieser Option wird der Expert Advisor auf den Handel mit dem in „Trader Wishes Pairs“ angegebenen Paar beschränkt. Es wird nicht mit anderen Paaren gehandelt.2. Wählen Sie im Modus „Trading Pairs“ (Handelspaare) die Option „SP“ oder „single-pair“.
Wenn ein Expert Advisor auf das EURUSD-Paar angewendet wird, handelt er ausschließlich mit dem EURUSD-Paar.
1.1.2. Handel zu bestimmten Zeiten
In der Gruppe „Trade on Specific Time“ (Handel zu bestimmten Zeiten) werden Optionen für Händler angeboten, die in der Zeitzone handeln möchten.
Vielleicht möchten viele Händler nach der Zeitzone handeln, sodass die Paare, die gehandelt werden, der Zeit für die Handelssitzung entsprechen können, sodass wir in diesem Expert Advisor noch die Option für die Handelssitzung (Zeitzone) verwenden.
2. Indikatoren.
2.1. Der Indikator ZigZag.
Der ZigZag-Indikator ist eine Methode zur Messung von Kursbewegungen ohne unnötiges Rauschen. Er funktioniert, indem er den Abstand zwischen den Kursschwankungen (Hochs und Tiefs) bestimmt. Anschließend berechnet dieser Indikator den Pullback. Wenn der Pullback einen bestimmten erwarteten Betrag überschreitet, gilt die Kursbewegung als abgeschlossen.
Wie bekannt, ist ZigZag einer der ältesten technischen Indikatoren, der seinen Weg vom Aktienmarkt in den Devisenhandel fand. Sie ermöglicht es den Händlern, die Struktur des Marktes zu visualisieren.
Bei der Beurteilung von Kursveränderungen hilft der ZigZag-Indikator den Händlern dabei, kleinere Kursbewegungen automatisch herauszufiltern.
Die Verwendung des ZigZag-Indikators kann zu einem besseren Verständnis der Marktstruktur beitragen.
Wenn sich die Bedingungen für die Preisbewegung mit den Auswirkungen zufälliger Preisschwankungen verändern, kann der ZigZag-Indikator dazu verwendet werden, Preistrends und Änderungen in Preistrends zu erkennen.
Das sagen die technischen Analysten:
- Der Zig-Zag-Indikator reduziert die Auswirkungen zufälliger Kursschwankungen und wird zur Erkennung von Preistrends und deren Veränderungen verwendet.
- Der Indikator reduziert das Rauschen und hebt die zugrunde liegenden Trends nach oben und unten hervor.
- Der Zig Zag-Indikator funktioniert am besten in Märkten mit starkem Trend.
Einschränkungen des ZigZag-Indikators.
Ähnlich wie bei anderen Trendfolge-Indikatoren werden Kauf- und Verkaufssignale durch die Betrachtung vergangener Kursbewegungen ermittelt, die unter Umständen keine genaue Vorhersage künftiger Kursbewegungen erlauben. So kann zum Beispiel der größte Teil eines Trends bereits stattgefunden haben, wenn eine Zig-Zag-Linie erzeugt wird.
Händler sollten sich bewusst sein, dass die jüngste ZigZag-Linie möglicherweise nicht von Dauer ist. Wenn der Preis seine Richtung ändert, beginnt der Indikator, eine neue Linie zu zeichnen.
Erreicht diese Linie nicht die prozentuale Einstellung des Indikators und der Kurs des Wertpapiers kehrt die Richtung um, wird die Linie entfernt und durch eine verlängerte ZigZag-Linie in der ursprünglichen Trendrichtung ersetzt.
ZigZag-Parametereinstellungen:
Für den ZigZag-Indikator stehen 3 Parameter zur Eingabe zur Verfügung:
1. Depth - mit Standardwert 12.
Depth - (Tiefe) bezieht sich darauf, wie weit hinten in der Balkenreihe des Charts es zu sehen sein wird.
Um die Höhen und Tiefen definieren zu können, müssen Sie sicherstellen, dass Sie genügend „Tiefe“ haben.
Es handelt sich um die Mindestanzahl von Balken ohne ein zweites Maximum oder eine Mindestabweichung des Balkens (Beispiel: Wenn wir ein Maximum in Kerze x haben und die Tiefe 12 beträgt, kann das folgende Maximum erst bei mindestens x+12 Kerzen gezeichnet werden).
2. Deviation - mit Standardwert 5.
Deviation - (Abweichung) bezieht sich auf den Prozentsatz der Preisänderung, der erforderlich ist, um die Trendlinie von positiv zu negativ zu verändern.
3. Backstep - mit Standardwert 3.
Backstep - Rückschritt ist die minimale Anzahl von Balken der Welle zwischen den Höchst- und Tiefstwerten.
Die Formel des ZigZag Indikators:
ZigZag (HL, %change=X, retrace=FALSE, LastExtreme=TRUE)
If %change>=X,plot ZigZag
wobei:
HL = Hoch-Tief-Kursreihe oder Schlusskursreihe
%change = Mindestpreisbewegung in Prozent
Retrace = Handelt es sich bei der Veränderung um ein Rücksetzung der vorherigen Bewegung oder um eine absolute Veränderung vom Höchststand zum Tiefpunkt?
Last Extreme = Wenn der Extrempreis über mehrere Zeiträume hinweg derselbe ist, ist der Extrempreis dann die erste oder die letzte Beobachtung?
Nach meinen Beobachtungen gibt es für den ZigZag-Indikator mindestens 4 Signalalgorithmen, die verwendet werden können.
Und in diesem Expert Advisor habe ich eine Option geschaffen, damit Händler die vier Algorithmus-Signale des ZigZag-Indikators auswählen und ausprobieren können.
2.2. Awesome Oszillator (AO).
Der Awesome Oszillator (AO) ist ein Momentum-Indikator, der von Händlern verwendet wird, um Markttrends und Momentum zu erkennen. Es wurde von Bill Williams, einem bekannten technischen Analysten, entwickelt und hat sich aufgrund seiner Einfachheit und Zuverlässigkeit zu einem beliebten Instrument unter Händlern entwickelt.
Der Awesome Oszillator ist ein Marktmomentum-Indikator, der die jüngsten Marktbewegungen mit den historischen Marktbewegungen vergleicht.
Es verwendet eine Nulllinie in der Mitte, zu deren beiden Seiten die Kursbewegungen entsprechend einem Vergleich zweier verschiedener gleitender Durchschnitte aufgetragen werden.
Der Awesome Oscillator wird berechnet, indem ein einfacher gleitender 34-Perioden-Durchschnitt (SMA) von einem 5-Perioden-SMA des mittleren (H+L)/2-Preises eines Finanzinstruments subtrahiert wird.
Der Mittelwertpreis gilt als genauere Darstellung des tatsächlichen Marktpreises als der Eröffnungs- oder Schlusskurs, da er sowohl den Höchst- als auch den Tiefstpreis eines bestimmten Zeitraums berücksichtigt.
Die AO schwankt zwischen positiven und negativen Werten, wobei positive Werte auf einen Aufwärtstrend und negative Werte auf einen Abwärtstrend hindeuten.
Die Werte des einfachen gleitenden 34-Perioden-Durchschnitts (SMA) und des 5-Perioden-SMA sind im Indikatorcode fest eingestellt und können in den Eigenschaften der Eingabeparameter des Indikators nicht geändert werden.
Awesome Oscillator = 5-Perioden-SMA (Medianpreis, 5-Perioden) - 34-Perioden-SMA (Medianpreis, 34-Perioden)
Wo der Medianpreis liegt: (Höchstkurs einer Sitzungsperiode + Tiefstkurs einer Sitzungsperiode) / 2.
Für den AO-Indikator gibt es mindestens 3 Signalalgorithmen, die verwendet werden können.
Daher habe ich in diesem Expert Advisor eine Option geschaffen, damit Händler die drei Algorithmus-Signale dieses AO-Indikators auswählen und ausprobieren können.
Eine Illustration des ZigZag-Indikators, der mit dem Awesome Oscillator gefiltert wird oder die Signale gegenseitig filtert, ist in der folgenden Abbildung zu sehen.
Die nachstehenden Signalabbildungen sind das ZigZag-Signal der Option Nr. 2 und das AO-Signal der Option Nr. 2
3. Handels- & Auftragsmanagement
Es gibt mehrere Möglichkeiten, die Handelsgeschäfte mit diesem Multi-Währungs-Expertenberater zu verwalten:
3.1. Stop-Loss-Aufträge.
Optionen: Use Order Stop Loss (Yes) or (No)
- Wenn die Option (No) für „Use Order Stop Loss“ für Stop-Loss-Aufträge verwenden ausgewählt ist, werden alle Aufträge ohne Stop Loss eröffnet.
Die Eröffnung eines Auftrags ohne Stop-Loss ist sicher, vorausgesetzt, dass Close Trade By Opposite Signal auf Yes gesetzt ist. Wenn jedoch das Signal „Close Trade By Opposite Signal“ auf „No“ gesetzt ist, besteht ein sehr hohes Risiko für das Kapital. Deshalb habe ich eine Funktion hinzugefügt, die es ermöglicht, den Prozentsatz zwischen Kapital und Saldo zu überprüfen. Wenn in diesem Fall der Prozentsatz des Kapitals kleiner ist als (100% - Prozentuales Kapitalrisiko pro Handelsgeschäft), dann führt der Experte die Funktion CheckLoss() aus (eine Funktion zur Ausführung eines virtuellen Stop-Loss) und schließt Positionen, deren Verlust größer ist als der eingestellte Stop-Loss-Wert.
//-- if(use_sl==No && CheckVSLTP==Yes) { if(!mc.CheckEquityBalance()) if(mc.CloseAllLoss()) mc.Do_Alerts(symbol,"Close order due stop in loss to secure equity."); } //--
bool MCEA::CheckEquityBalance(void) { //--- bool isgood=false; if((mc_account.Equity()/mc_account.Balance()*100) > (100.00-Risk)) isgood=true; //-- return(isgood); //--- } //-end CheckEquityBalance() //---------//
bool MCEA::CheckLoss(const string symbol,ENUM_POSITION_TYPE intype,double slc=0.0) { //--- Pips(symbol); bool inloss=false; double lossval=slc==0.0 ? (SLval*0.5) : slc; double posloss = mc_symbol.NormalizePrice(slc*pip); int ttlorder=PositionsTotal(); // number of open positions //-- for(int x=0; x<arrsymbx; x++) { string symbol=DIRI[x]; //-- for(int i=ttlorder-1; i>=0; i--) { string position_Symbol = PositionGetSymbol(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double posloss = mc_symbol.NormalizePrice(lossval*pip); double pricegab = mc_symbol.NormalizePrice(fabs(price-pos_open)); //--- if(type==intype && pricegab>posloss) inloss=true; } } } //-- return(inloss); //---- } //-end CheckLoss() //---------//
bool MCEA::CloseAllLoss(void) { //---- ResetLastError(); //-- bool orclose=false; string isloss="due stop in loss."; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int ttlorder=PositionsTotal(); // number of open positions //-- for(int x=0; x<arrsymbx; x++) { string symbol=DIRI[x]; Pips(symbol); double posloss=mc_symbol.NormalizePrice(SLval*pip); orclose=false; //-- for(int i=ttlorder-1; i>=0; i--) { string position_Symbol = PositionGetSymbol(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double posloss = mc_symbol.NormalizePrice(SLval*pip); double pricegab = mc_symbol.NormalizePrice(fabs(price-pos_open)); ulong position_ticket = PositionGetTicket(i); //--- if(type==POSITION_TYPE_BUY && pricegab>posloss) { RefreshTick(position_Symbol); orclose = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close Buy %s %s %s",symbol,EnumToString(POSITION_TYPE_BUY),isloss); } if(type==POSITION_TYPE_SELL && pricegab>posloss) { RefreshTick(position_Symbol); orclose = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close Sell %s %s %s",symbol,EnumToString(POSITION_TYPE_BUY),isloss); } } } } //-- return(orclose); //---- } //-end CloseAllLoss() //---------//
- Bei Verwendung der Option Use Order Stop Loss für Aufträge verwenden (Yes): Dann gibt es die weiteren Optionen: Use Automatic Calculation (automatische Berechnung) des Stop Loss verwenden (Yes) oder (No).
- Bei der Option Automatic Calculation Stop Loss (Yes), wird die Stop Loss-Berechnung automatisch durch den Experten durchgeführt.
- Wenn die Option Automatic Calculation Stop Loss (No) gewählt wurde, muss der Händler den Stop Loss-Wert in Pips eingeben.
- Wenn die Option Use Order Stop Loss (No): Dann prüft der Experte für jede offene Position, ob die Signalbedingung noch gut ist und die Order mit Gewinn aufrechterhalten werden kann oder ob sich das Signal abgeschwächt hat und die Position geschlossen werden muss, um den Gewinn zu sichern oder ob sich die Signalbedingung umgekehrt hat und die Position mit Verlust geschlossen werden muss.
Anmerkung: Speziell für Close Trade (Handel schließen) und Save Profit (Gewinn sichern) aufgrund eines schwachen Signals wird eine Option angeboten, ob diese aktiviert werden kann oder nicht.
In einem Teil der Funktion ExpertActionTrade():
//-- if(SaveOnRev==Yes) //-- Close Trade and Save profit due to weak signal (Yes) { mc.CheckOpenPMx(symbol); if(mc.profitb[x]>mc.minprofit && mc.xob[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) { mc.CloseBuyPositions(symbol); mc.Do_Alerts(symbol,"Close BUY order "+symbol+" to save profit due to weak signal."); } if(mc.profits[x]>mc.minprofit && mc.xos[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) { mc.CloseSellPositions(symbol); mc.Do_Alerts(symbol,"Close SELL order "+symbol+" to save profit due to weak signal."); } } //--
Der Code, um den Handel zu schließen und den Gewinn aufgrund eines schwachen Signals zu sichern, lautet wie folgt:
int MCEA::GetCloseInWeakSignal(const string symbol,int exis) // Signal Indicator Position Close in profit { //--- int ret=0; int rise=1, down=-1; //-- int AOdir=AOColorSignal(symbol); int ZZDir=ZigZagSignal(symbol); //-- if(exis==down && (AOdir==rise||ZZDir==rise)) ret=rise; if(exis==rise && (AOdir==down||ZZDir==down)) ret=down; //-- return(ret); //--- } //-end GetCloseInWeakSignal() //---------//
- Wenn nicht aktiviert (No), wird die Position trotz des schwächeren Signals aufrechterhalten oder nicht geschlossen, um den Gewinn zu sichern.
- Wenn aktiviert (Yes), sind die Bedingungen für den ZigZag-Indikator und den AO-Indikator:
Für das Schließen von Kaufpositionen:
Wenn der AO-Indikator seine Farbe von grün auf rot wechselt (Standardfarben) oder wenn der ZigZag-Indikator ein extremes Hoch erreicht und der Preis seine Richtung ändert, wird der Kaufauftrag geschlossen.Für das Schließen von Verkaufspositionen:
Wenn der AO-Indikator von rot auf grün wechselt (Standardfarben) oder wenn der ZigZag-Indikator einen extremen Tiefstand erreicht und der Preis seine Richtung ändert, wird der Verkaufsauftrag geschlossen.Der Code zum Setzen eines Stop-Loss-Auftrags lautet wie folgt:
double MCEA::OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice) { //--- slv=0.0; int x=PairsIdxArray(xsymb); Pips(xsymb); RefreshTick(xsymb); //-- switch(type) { case (ORDER_TYPE_BUY): { if(use_sl==Yes && autosl==Yes) slv=mc_symbol.NormalizePrice(atprice-38*pip); else if(use_sl==Yes && autosl==No) slv=mc_symbol.NormalizePrice(atprice-SLval*pip); else slv=0.0; //-- break; } case (ORDER_TYPE_SELL): { if(use_sl==Yes && autosl==Yes) slv=mc_symbol.NormalizePrice(atprice+38*pip); else if(use_sl==Yes && autosl==No) slv=mc_symbol.NormalizePrice(atprice+SLval*pip); else slv=0.0; } } //--- return(slv); //--- } //-end OrderSLSet() //---------//
3.2. Take Profit-Aufträge.
Optionen: Use Order Take Profit (Yes) oder (No)
- Wenn die Option Use Order Take Profit (No) ausgewählt ist, werden alle Aufträge ohne ein Take Profit, einem Gewinnziel eröffnet.
- Bei Verwendung der Option Use Order Take Profit (Yes): Dann gibt es die weiteren Optionen: Use Automatic Calculation Order Take Profit (Yes) oder (No).
- Bei der Option der automatischen Berechnung von Take Profit (Yes), dann wird die Berechnung der Take Profit Order automatisch vom Experten durchgeführt.
- Wenn die Option der automatischen Berechnung von Take Profit (No), gewählt wurde, muss der Händler den Order-Take Profit-Wert in Pips eingeben.
Der Code zum Festlegen von Take Profit lautet wie folgt:
double MCEA::OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice) { //--- tpv=0.0; int x=PairsIdxArray(xsymb); Pips(xsymb); RefreshTick(xsymb); //-- switch(type) { case (ORDER_TYPE_BUY): { if(use_tp==Yes && autotp==Yes) tpv=mc_symbol.NormalizePrice(atprice+50*pip); else if(use_tp==Yes && autotp==No) tpv=mc_symbol.NormalizePrice(atprice+TPval*pip); else tpv=0.0; //-- break; } case (ORDER_TYPE_SELL): { if(use_tp==Yes && autotp==Yes) tpv=mc_symbol.NormalizePrice(atprice-50*pip); else if(use_tp==Yes && autotp==No) tpv=mc_symbol.NormalizePrice(atprice-TPval*pip); else tpv=0.0; } } //--- return(tpv); //--- } //-end OrderTPSet() //---------//
3.3. Trailing-Stop
Optionen: Use Trailing Stop Loss (Yes) oder (No)
- Wenn die OptionUse Trailing SL (No) ist, wird der Experte keinen Trailing Stop Loss und Trailing Take Profit durchführen.
- Wenn die Option Use Trailing SL (Yes): Die Händler können zwischen 3 Optionen wählen:
1. Trailing by Price
Der Trailing-Stop wird vom Experten anhand der Kursbewegungen und des Wertes in der Eingabeeigenschaft ausgeführt.
2. Trailing By Indicator
Der Trailing-Stop wird vom Experten mithilfe des VIDYA-Indikators ausgeführt.
Meinen Untersuchungen und Experimenten zufolge ist der VIDYA-Indikator etwas besser und ideal für Trailing-Stops im Vergleich zum Parabolic SAR oder verschiedenen Varianten von Moving Average-Indikatoren.
Im Vergleich zum Parabolic SAR-Indikator ist der VIDYA-Indikator näher an den Kursbewegungen, und im Vergleich zu den AMA-, DEMA- und MA-Indikatoren ist der VIDYA-Indikator noch weiter von den Kursbewegungen entfernt.
Daher habe ich in diesem Artikel beschlossen, den VIDYA-Indikator für die auf dem Indikator basierende Trailing-Stop-Funktion zu verwenden.
3. Trailing Stop in HIGH or LOW previous bar
Bei Kaufaufträgen wird der Trailing-Stop auf den LOW-Kurs des vorherigen Balkens (LOW[1]) gesetzt.
Bei Verkaufsaufträgen wird der Trailing-Stop auf den HIGH-Kurs des vorherigen Balkens (HIGH[1]) gesetzt.
Die Funktion „Trailing Stop Price“:
double MCEA::TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type) { //--- int br=2; double pval=0.0; int x=PairsIdxArray(xsymb); Pips(xsymb); //-- switch(TS_type) { case byprice: { RefreshTick(xsymb); if(ptype==POSITION_TYPE_BUY) pval=mc_symbol.NormalizePrice(mc_symbol.Bid()-TSval*pip); if(ptype==POSITION_TYPE_SELL) pval=mc_symbol.NormalizePrice(mc_symbol.Ask()+TSval*pip); break; } case byindi: { double VIDyAv[]; ArrayResize(VIDyAv,br,br); ArraySetAsSeries(VIDyAv,true); CopyBuffer(hVIDyAv[x],0,0,br,VIDyAv); RefreshPrice(xsymb,TFt,br); //-- if(ptype==POSITION_TYPE_BUY && (VIDyAv[0]<mc_symbol.NormalizePrice(mc_symbol.Bid()-TSval*pip))) pval=VIDyAv[0]; if(ptype==POSITION_TYPE_SELL && (VIDyAv[0]>mc_symbol.NormalizePrice(mc_symbol.Ask()+TSval*pip))) pval=VIDyAv[0]; break; } case byHiLo: { UpdatePrice(xsymb,TFt,2); //-- if(ptype==POSITION_TYPE_BUY && (HIGH[0]>HIGH[1])) pval=LOW[1]; if(ptype==POSITION_TYPE_SELL && (LOW[0]<LOW[1])) pval=HIGH[1]; break; } } //-- return(pval); //--- } //-end TSPrice() //---------//
bool MCEA::ModifyOrdersSL(const string symbx,int TS_type) { //--- ResetLastError(); MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int TRSP=TS_type; bool modist=false; int x=PairsIdxArray(symbx); Pips(symbx); //-- int total=PositionsTotal(); //-- for(int i=total-1; i>=0; i--) { string symbol=PositionGetSymbol(i); if(symbol==symbx && mc_position.Magic()==magicEA) { ENUM_POSITION_TYPE opstype = mc_position.PositionType(); if(opstype==POSITION_TYPE_BUY) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double vtrsb = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP)); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_tp = mc_position.TakeProfit(); double pos_profit = mc_position.Profit(); double pos_swap = mc_position.Swap(); double pos_comm = mc_position.Commission(); double netp=pos_profit+pos_swap+pos_comm; double modstart=mc_symbol.NormalizePrice(pos_open+TSmin*pip); double modminsl=mc_symbol.NormalizePrice(vtrsb+((TSmin-1.0)*pip)); double modbuysl=vtrsb; bool modbuy = (price>modminsl && modbuysl>modstart && (pos_stop==0.0||modbuysl>pos_stop)); //-- if(modbuy && netp>minprofit) { modist=mc_trade.PositionModify(symbol,modbuysl,pos_tp); } } if(opstype==POSITION_TYPE_SELL) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double vtrss = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP)); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_tp = mc_position.TakeProfit(); double pos_profit = mc_position.Profit(); double pos_swap = mc_position.Swap(); double pos_comm = mc_position.Commission(); double netp=pos_profit+pos_swap+pos_comm; double modstart=mc_symbol.NormalizePrice(pos_open-TSmin*pip); double modminsl=mc_symbol.NormalizePrice(vtrss-((TSmin+1.0)*pip)); double modselsl=vtrss; bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==0.0||modselsl<pos_stop)); //-- if(modsel && netp>minprofit) { modist=mc_trade.PositionModify(symbol,modselsl,pos_tp); } } } } //-- return(modist); //--- } //-end ModifyOrdersSL() //---------//
3.4. Trailing Take Profit
Optionen: Use Trailing Take Profit (Yes) or (No)
- Wenn die Option Use Trailing TP (No) ist, dann wird der Experte keinen Trailing-Take-Profit durchführen.
- Wenn die Option Use Trailing TP (Yes) ist, dann geben Sie den Wert für den Trailing-Profit in Pips ein (Standardwert 25 Pips) und der Expert Advisor führt den Trailing-Profit auf der Grundlage des variablen Werts TPmin (minimaler Wert für den Trailing-Profit) aus.
bool MCEA::ModifyOrdersTP(const string symbx) { //--- ResetLastError(); MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- bool modist=false; int x=PairsIdxArray(symbx); Pips(symbx); //-- int total=PositionsTotal(); //-- for(int i=total-1; i>=0; i--) { string symbol=PositionGetSymbol(i); if(symbol==symbx && mc_position.Magic()==magicEA) { ENUM_POSITION_TYPE opstype = mc_position.PositionType(); if(opstype==POSITION_TYPE_BUY) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_tp = mc_position.TakeProfit(); double modbuytp = pos_tp==0.0 ? mc_symbol.NormalizePrice(pos_open+TPmin*pip) : pos_tp; double modpostp = mc_symbol.NormalizePrice(price+TPmin*pip); bool modtpb = (price>pos_open && modbuytp-price<TPmin*pip && pos_tp<modpostp); //-- if(modtpb) { modist=mc_trade.PositionModify(symbol,pos_stop,modpostp); } } if(opstype==POSITION_TYPE_SELL) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_tp = mc_position.TakeProfit(); double modseltp = pos_tp==0.0 ? mc_symbol.NormalizePrice(pos_open-TPmin*pip) : pos_tp; double modpostp = mc_symbol.NormalizePrice(price-TPmin*pip); bool modtps = (price<pos_open && price-modseltp<TPmin*pip && pos_tp>modpostp); //-- if(modtps) { modist=mc_trade.PositionModify(symbol,pos_stop,modpostp); } } } } //-- return(modist); //--- } //-end ModifyOrdersTP() //---------//
3.5. Close Trade By Opposite Signal
Optionen: Close Trade By Opposite Signal (Yes) oder (No)
- Wenn Close Trade By Opposite Signal (Yes):
Wenn also zuvor ein Verkaufsauftrag eröffnet wurde und sich das Signal des Indikators umkehrt, wird der Verkaufsauftrag geschlossen und der Expert Advisor eröffnet einen Kaufauftrag. Das Gleiche gilt umgekehrt.
In einem Teil der Funktion ExpertActionTrade():
if(Close_by_Opps==Yes && mc.xos[x]>0) mc.CloseSellPositions(symbol);bool MCEA::CloseSellPositions(const string symbol) { //--- ResetLastError(); bool sellclose=false; int total=PositionsTotal(); // number of open positions ENUM_POSITION_TYPE closetype = POSITION_TYPE_SELL; ENUM_ORDER_TYPE type_req = ORDER_TYPE_BUY; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int x=PairsIdxArray(symbol); //--- iterate over all open positions for(int i=total-1; i>=0; i--) { if(mc_position.SelectByIndex(i)) { //--- Parameters of the order string position_Symbol = PositionGetSymbol(i); ulong position_ticket = PositionGetTicket(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); //--- if the MagicNumber matches if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { //-- if(type==closetype) { RefreshTick(position_Symbol); sellclose=mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close Sell #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); } } } } //--- return(sellclose); //---- } //-end CloseSellPositions() //---------//
In einem Teil der Funktion ExpertActionTrade():
if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol);
bool MCEA::CloseBuyPositions(const string symbol) { //--- //-- ResetLastError(); bool buyclose=false; int total=PositionsTotal(); // number of open positions ENUM_POSITION_TYPE closetype = POSITION_TYPE_BUY; ENUM_ORDER_TYPE type_req = ORDER_TYPE_SELL; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int x=PairsIdxArray(symbol); //--- iterate over all open positions for(int i=total-1; i>=0; i--) { if(mc_position.SelectByIndex(i)) { //--- Parameters of the order string position_Symbol = PositionGetSymbol(i); ulong position_ticket = PositionGetTicket(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); //--- if the MagicNumber matches if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { //-- if(type==closetype) { RefreshTick(position_Symbol); buyclose=mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close Buy #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); } } } } //--- return(buyclose); //---- } //-end CloseBuyPositions() //---------//
Probleme treten auf, wenn Close Trade By Opposite Signal (No) gesetzt wurde:
1. Der Auftrag wird 2 mal die Summe jedes gehandelten Paares sein.
2. In einem Paar gibt es Aufträge, die sich in einer Verlustsituation befinden, und solche, die sich in einer Gewinnsituation befinden.
3. Das Kapital wird durch unausgewogene Verlust- und Gewinnbedingungen aufgezehrt.
Um dieses Problem zu lösen, habe ich mehrere Funktionen entwickelt, um die Bedingungen für Verlust- und Gewinnaufträge zu erkennen.
In einem Teil der Funktion ExpertActionTrade():
//-- mc.CheckOpenPMx(symbol); if(Close_by_Opps==No && (mc.xob[x]+mc.xos[x]>1)) { if(mc.CheckProfitLoss(symbol)) mc.Do_Alerts(symbol,"Close order due stop in loss."); } //--
bool MCEA::CheckProfitLoss(const string symbol) { //---- ResetLastError(); //-- bool closeinloss=false; string isloss="due stop in loss."; //-- int xx=PairsIdxArray(symbol); //-- bool BuyProfitSellLoss=(xob[xx]>0 && CheckProfit(symbol,POSITION_TYPE_BUY)) && (xos[xx]>0 && CheckLoss(symbol,POSITION_TYPE_SELL,0.0)); bool SellProfitBuyLoss=(xos[xx]>0 && CheckProfit(symbol,POSITION_TYPE_SELL)) && (xob[xx]>0 && CheckLoss(symbol,POSITION_TYPE_BUY,0.0)); //-- if(BuyProfitSellLoss && !SellProfitBuyLoss) { if(CloseSellPositions(symbol)) { PrintFormat("Close Sell %s %s %s",symbol,EnumToString(POSITION_TYPE_BUY),isloss); closeinloss=true; } } if(SellProfitBuyLoss && !BuyProfitSellLoss) { if(CloseBuyPositions(symbol)) { PrintFormat("Close Buy %s %s %s",symbol,EnumToString(POSITION_TYPE_SELL),isloss); closeinloss=true; } } //-- return(closeinloss); //---- } //-end CheckProfitLoss() //---------//
Die Funktion CheckProfitLoss() ruft 2 weitere Funktionen auf, die den Auftrag für ein Symbol mit folgenden Bedingungen vergleichen:
Buy Profit and Sell Loss, or Buy Loss and Sell Profit (Gewinn kaufen und Verlust verkaufen, oder Verlust kaufen und Gewinn verkaufen).
- Wenn Gewinn kaufen und Verlust verkaufen, dann wird die Verkaufsposition geschlossen.
- Wenn Verlust kaufen und Gewinn verkaufen, dann wird die Kaufposition geschlossen.
bool MCEA::CheckProfit(const string symbol,ENUM_POSITION_TYPE intype) { //--- Pips(symbol); double posprofit=mc_symbol.NormalizePrice((TPval*0.5)*pip); bool inprofit=false; //-- int ttlorder=PositionsTotal(); // number of open positions //-- for(int x=0; x<arrsymbx; x++) { string symbol=DIRI[x]; //-- for(int i=ttlorder-1; i>=0; i--) { string position_Symbol = PositionGetSymbol(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double posprofit = mc_symbol.NormalizePrice((TPval*0.5)*pip); double pricegab = mc_symbol.NormalizePrice(fabs(price-pos_open)); //--- if(type==intype && posprofit<pricegab) inprofit=true; } } } //-- return(inprofit); //---- } //-end CheckProfit() //---------//
bool MCEA::CheckLoss(const string symbol,ENUM_POSITION_TYPE intype,double slc=0.0) { //--- Pips(symbol); bool inloss=false; double lossval=slc==0.0 ? (SLval*0.5) : slc; double posloss = mc_symbol.NormalizePrice(slc*pip); int ttlorder=PositionsTotal(); // number of open positions //-- for(int x=0; x<arrsymbx; x++) { string symbol=DIRI[x]; //-- for(int i=ttlorder-1; i>=0; i--) { string position_Symbol = PositionGetSymbol(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double posloss = mc_symbol.NormalizePrice(lossval*pip); double pricegab = mc_symbol.NormalizePrice(fabs(price-pos_open)); //--- if(type==intype && pricegab>posloss) inloss=true; } } } //-- return(inloss); //---- } //-end CheckLoss() //---------//
4. Manuelles Handelsmanagement.
In diesem Multi-Currency Expert Advisor wurden mehrere manuelle Schaltflächen hinzugefügt, um die Effizienz und Effektivität für Händler bei der Überwachung der Arbeit des Expert Advisors zu erhöhen.
4.1. SL / TP Alle Aufträge einstellen:
Diese Schaltfläche ist nützlich, wenn der Händler die Parameter „Use Order Stop Loss (No)“ und/oder „Use Order Take Profit (No)“ eingegeben hat, dann aber Stop Loss oder Take Profit für alle Aufträge verwenden möchte, dann werden mit einem einzigen Klick auf die Schaltfläche „Set SL/TP All Orders“ alle Orders geändert und ein Stop Loss und/oder Take Profit angewendet.4.2. Alle Positionen schließen:
Wenn ein Händler alle Positionen schließen möchte, genügt ein einziger Klick auf die Schaltfläche „Close All Orders“, um alle offenen Aufträge zu schließen.
4.3. Alle Positionen mit Gewinn schließen:
Wenn ein Händler alle Aufträge schließen möchte, die bereits profitabel sind, genügt ein einziger Klick auf die Schaltfläche „Close All Orders Profit“, um alle offenen Positionen, die bereits profitabel sind, zu schließen.
5. Management-Befehle und Chartsymbole.
Für Multi-Currency Expert Advisors, die 30 Paare mit nur einem Chart-Symbol handeln, wäre es sehr hilfreich und einfach, wenn ein Schaltflächen-Panel für alle Symbole zur Verfügung gestellt würde, sodass Händler den Chart-Zeitrahmen oder die Symbole mit nur einem Klick ändern können, um die Genauigkeit des Indikatorsignals zu sehen, wenn der Experte eine Order öffnet oder schließt.
Umsetzung der Planung im Programm MQL5
1. Programmkopf und Eingabeeigenschaften.
Header-Datei MQL5 einbinden:
//+------------------------------------------------------------------+ //| Include | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> #include <Trade\PositionInfo.mqh> #include <Trade\SymbolInfo.mqh> #include <Trade\AccountInfo.mqh> //-- CTrade mc_trade; CSymbolInfo mc_symbol; CPositionInfo mc_position; CAccountInfo mc_account; //---
Die Enumeration zur Verwendung der Zeitzone:
//-- enum tm_zone { Cus_Session, // Trading on Custom Session New_Zealand, // Trading on New Zealand Session Australia, // Trading on Autralia Sydney Session Asia_Tokyo, // Trading on Asia Tokyo Session Europe_London, // Trading on Europe London Session US_New_York // Trading on US New York Session }; //--
Die Enumeration zur Auswahl der Zeitstunde:
//-- enum swhour { hr_00=0, // 00:00 hr_01=1, // 01:00 hr_02=2, // 02:00 hr_03=3, // 03:00 hr_04=4, // 04:00 hr_05=5, // 05:00 hr_06=6, // 06:00 hr_07=7, // 07:00 hr_08=8, // 08:00 hr_09=9, // 09:00 hr_10=10, // 10:00 hr_11=11, // 11:00 hr_12=12, // 12:00 hr_13=13, // 13:00 hr_14=14, // 14:00 hr_15=15, // 15:00 hr_16=16, // 16:00 hr_17=17, // 17:00 hr_18=18, // 18:00 hr_19=19, // 19:00 hr_20=20, // 20:00 hr_21=21, // 21:00 hr_22=22, // 22:00 hr_23=23 // 23:00 }; //--
Die Enumeration zur Auswahl von Zeitminuten:
//-- enum inmnt { mn_00=0, // Minute 0 mn_05=5, // Minute 5 mn_10=10, // Minute 10 mn_15=15, // Minute 15 mn_20=20, // Minute 20 mn_25=25, // Minute 25 mn_30=30, // Minute 30 mn_35=35, // Minute 35 mn_40=40, // Minute 40 mn_45=45, // Minute 45 mn_50=50, // Minute 50 mn_55=55 // Minute 55 }; //--
Die Enumeration zur Auswahl von 10 Optionspaaren für den Handel:
//-- enum PairsTrade { All30, // All Forex 30 Pairs TrdWi, // Trader Wishes Pairs Usds, // Forex USD Pairs Eurs, // Forex EUR Pairs Gbps, // Forex GBP Pairs Auds, // Forex AUD Pairs Nzds, // Forex NZD Pairs Cads, // Forex CDD Pairs Chfs, // Forex CHF Pairs Jpys // Forex JPY Pairs }; //--
Die Enumeration YN wird für die Optionen (Yes) oder (No) in der Eigenschaft Experteneingabe verwendet:
//-- enum YN { No, Yes }; //--
Die Enumeration zur Verwendung von Money Management Lot Size:
//-- enum mmt { FixedLot, // Fixed Lot Size DynamLot // Dynamic Lot Size }; //--
Die Enumeration zur Auswahl des Zeitrahmens, der für die Berechnung der Signalindikatoren verwendet werden soll:
//-- enum TFUSE { TFM5, // 00_PERIOD_M5 TFM15, // 01_PERIOD_M15 TFM30, // 02_PERIOD_M30 TFH1, // 03_PERIOD_H1 TFH2, // 04_PERIOD_H2 TFH3, // 05_PERIOD_H3 TFH4, // 06_PERIOD_H4 TFH6, // 07_PERIOD_H6 TFH8, // 08_PERIOD_H8 TFH12, // 09_PERIOD_H12 TFD1 // 10_PERIOD_D1 }; //--
In der Enumeration TFUSE beschränke ich die Verwendung der Zeitrahmenberechnungen für die EAs auf die Bereiche TF-M5 bis TF-D1.
Die Enumeration zur Auswahl des Typs, der für die Berechnung des Trailing-Stops verwendet werden soll:
//-- enum TrType { byprice, // Trailing Stop by Price byindi, // Trailing Stop by Indicator byHiLo // Trailing Stop in HIGH or LOW bar }; //--
Die Enumeration zur Auswahl der Handelsart, mit der der Experte handelt, Einzelwährung oder Mehrfachwährung:
//-- enum MS { SP, // Single Pair MP // Multi Pairs }; //--
Enumeration zur Auswahl des Signalalgorithmus des ZigZag-Indikators:
//-- enum SignalZZ { SZZ1, // ZigZagSignal 1 SZZ2, // ZigZagSignal 2 SZZ3, // ZigZagSignal 3 SZZ4 // ZigZagSignal 4 }; //--
Enumeration zur Auswahl des Signalalgorithmus aus dem AO-Indikator:
//-- enum SignalAO { SAO1, // AOSignal 1 SAO2, // AOSignal 2 SAO3 // AOSignal 3 }; //--
Eingabeeigenschaften des Experten:
//--- input group "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter input TFUSE tfinuse = TFH4; // Select Expert TimeFrame, default PERIOD_H4 //--- input group "=== ZigZag Indicator Input Properties ==="; // ZigZag Indicator Input Properties input int zzDepth = 12; // Input ZigZag Depth, default 12 input int zzDevia = 5; // Input ZigZag Deviation, default 5 input int zzBackS = 3; // Input ZigZag Back Step, default 3 input SignalZZ sigzz = SZZ2; // Select ZigZag Signal to Use input SignalAO sigao = SAO2; // Select AO Signal to Use //--- input group "=== Selected Pairs to Trade ==="; // Selected Pairs to trading input MS trademode = MP; // Select Trading Pairs Mode (Multi or Single) input PairsTrade usepairs = All30; // Select Pairs to Use input string traderwishes = "eg. eurusd,usdchf"; // If Use Trader Wishes Pairs, input pair name here, separate by comma //-- input group "=== Money Management Lot Size Parameter ==="; // Money Management Lot Size Parameter input mmt mmlot = DynamLot; // Money Management Type input double Risk = 10.0; // Percent Equity Risk per Trade (Min=1.0% / Max=10.0%) input double Lots = 0.01; // Input Manual Lot Size FixedLot //--Trade on Specific Time input group "=== Trade on Specific Time ==="; // Trade on Specific Time input YN trd_time_zone = Yes; // Select If You Like to Trade on Specific Time Zone input tm_zone session = Cus_Session; // Select Trading Time Zone input swhour stsescuh = hr_00; // Time Hour to Start Trading Custom Session (0-23) input inmnt stsescum = mn_15; // Time Minute to Start Trading Custom Session (0-55) input swhour clsescuh = hr_23; // Time Hour to Stop Trading Custom Session (0-23) input inmnt clsescum = mn_55; // Time Minute to Stop Trading Custom Session (0-55) //--Day Trading On/Off input group "=== Day Trading On/Off ==="; // Day Trading On/Off input YN ttd0 = No; // Select Trading on Sunday (Yes) or (No) input YN ttd1 = Yes; // Select Trading on Monday (Yes) or (No) input YN ttd2 = Yes; // Select Trading on Tuesday (Yes) or (No) input YN ttd3 = Yes; // Select Trading on Wednesday (Yes) or (No) input YN ttd4 = Yes; // Select Trading on Thursday (Yes) or (No) input YN ttd5 = Yes; // Select Trading on Friday (Yes) or (No) input YN ttd6 = No; // Select Trading on Saturday (Yes) or (No) //--Trade & Order management Parameter input group "=== Trade & Order management Parameter ==="; // Trade & Order management Parameter input YN use_sl = No; // Use Order Stop Loss (Yes) or (No) input YN autosl = Yes; // Use Automatic Calculation Stop Loss (Yes) or (No) input double SLval = 30.0; // If Not Use Automatic SL - Input SL value in Pips input YN use_tp = Yes; // Use Order Take Profit (Yes) or (No) input YN autotp = Yes; // Use Automatic Calculation Take Profit (Yes) or (No) input double TPval = 60.0; // If Not Use Automatic TP - Input TP value in Pips input YN TrailingSL = Yes; // Use Trailing Stop Loss (Yes) or (No) input TrType trlby = byHiLo; // Select Trailing Stop Type input double TSval = 10.0; // If Use Trailing Stop by Price Input value in Pips input double TSmin = 5.0; // Minimum Pips to start Trailing Stop input YN TrailingTP = Yes; // Use Trailing Take Profit (Yes) or (No) input double TPmin = 25.0; // Input Trailing Profit Value in Pips input YN Close_by_Opps = Yes; // Close Trade By Opposite Signal (Yes) or (No) input YN SaveOnRev = Yes; // Close Trade and Save profit due to weak signal (Yes) or (No) input YN CheckVSLTP = Yes; // Check Virtual SL/TP & Close Loss Trade (Yes) or (No) //--Others Expert Advisor Parameter input group "=== Others Expert Advisor Parameter ==="; // Others EA Parameter input YN alerts = Yes; // Display Alerts / Messages (Yes) or (No) input YN UseEmailAlert = No; // Email Alert (Yes) or (No) input YN UseSendnotify = No; // Send Notification (Yes) or (No) input YN trade_info_display = Yes; // Select Display Trading Info on Chart (Yes) or (No) input ulong magicEA = 20240218; // Expert ID (Magic Number) //---
Anmerkung: Wenn die Eingabeeigenschaft der Experten-ID (Magic Number) leer gelassen wird, kann der Expert Advisor manuell eröffnete Aufträge verwalten.
In der Eigenschaftsgruppe Globale Strategie-EA-Parameter für Experteneingaben werden Händler angewiesen, den Expertenzeitrahmen für Indikatorsignalberechnungen mit dem Standardwert PERIOD_H4 auszuwählen.
In der Eigenschaftsgruppe „Select Pairs to Trade“ des Expert Advisors müssen Händler das zu handelnde Paar aus den 10 zur Verfügung stehenden Optionen auswählen; standardmäßig ist „All Forex 30 Pairs“ (alle 30 Paare) eingestellt.
Um das zu handelnde Paar zu konfigurieren, rufen wir die Funktion HandlingSymbolArrays() auf. Mit der FunktionHandlingSymbolArrays() werden wir alle Paare behandeln, die gehandelt werden sollen.
void MCEA::HandlingSymbolArrays(void) { //--- string All30[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY","EURGBP", "EURAUD","EURNZD","EURCAD","EURCHF","EURJPY","GBPAUD","GBPNZD","GBPCAD", "GBPCHF","GBPJPY","AUDNZD","AUDCAD","AUDCHF","AUDJPY","NZDCAD","NZDCHF", "NZDJPY","CADCHF","CADJPY","CHFJPY","XAUUSD","XAGUSD"}; // 30 pairs string USDs[]={"USDCAD","USDCHF","USDJPY","AUDUSD","EURUSD","GBPUSD","NZDUSD","XAUUSD","XAGUSD"}; // USD pairs string EURs[]={"EURAUD","EURCAD","EURCHF","EURGBP","EURJPY","EURNZD","EURUSD"}; // EUR pairs string GBPs[]={"GBPAUD","GBPCAD","GBPCHF","EURGBP","GBPJPY","GBPNZD","GBPUSD"}; // GBP pairs string AUDs[]={"AUDCAD","AUDCHF","EURAUD","GBPAUD","AUDJPY","AUDNZD","AUDUSD"}; // AUD pairs string NZDs[]={"AUDNZD","NZDCAD","NZDCHF","EURNZD","GBPNZD","NZDJPY","NZDUSD"}; // NZD pairs string CADs[]={"AUDCAD","CADCHF","EURCAD","GBPCAD","CADJPY","NZDCAD","USDCAD"}; // CAD pairs string CHFs[]={"AUDCHF","CADCHF","EURCHF","GBPCHF","NZDCHF","CHFJPY","USDCHF"}; // CHF pairs string JPYs[]={"AUDJPY","CADJPY","CHFJPY","EURJPY","GBPJPY","NZDJPY","USDJPY"}; // JPY pairs //-- sall=ArraySize(All30); arusd=ArraySize(USDs); areur=ArraySize(EURs); aretc=ArraySize(JPYs); ArrayResize(VSym,sall,sall); ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY); //-- if(usepairs==TrdWi && StringFind(traderwishes,"eg.",0)<0) { string to_split=traderwishes; // A string to split into substrings pairs name string sep=","; // A separator as a character ushort u_sep; // The code of the separator character //--- Get the separator code u_sep=StringGetCharacter(sep,0); //--- Split the string to substrings int p=StringSplit(to_split,u_sep,SPC); if(p>0) { for(int i=0; i<p; i++) StringToUpper(SPC[i]); //-- for(int i=0; i<p; i++) { if(ValidatePairs(SPC[i])<0) ArrayRemove(SPC,i,1); } } arspc=ArraySize(SPC); } //-- SetSymbolNamePS(); // With this function we will detect whether the Symbol Name has a prefix and/or suffix //-- if(inpre>0 || insuf>0) { if(usepairs==TrdWi && arspc>0) { for(int t=0; t<arspc; t++) { SPC[t]=pre+SPC[t]+suf; } } //-- for(int t=0; t<sall; t++) { All30[t]=pre+All30[t]+suf; } for(int t=0; t<arusd; t++) { USDs[t]=pre+USDs[t]+suf; } for(int t=0; t<areur; t++) { EURs[t]=pre+EURs[t]+suf; } for(int t=0; t<aretc; t++) { GBPs[t]=pre+GBPs[t]+suf; } for(int t=0; t<aretc; t++) { AUDs[t]=pre+AUDs[t]+suf; } for(int t=0; t<aretc; t++) { NZDs[t]=pre+NZDs[t]+suf; } for(int t=0; t<aretc; t++) { CADs[t]=pre+CADs[t]+suf; } for(int t=0; t<aretc; t++) { CHFs[t]=pre+CHFs[t]+suf; } for(int t=0; t<aretc; t++) { JPYs[t]=pre+JPYs[t]+suf; } } //-- ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY); ArrayResize(AS30,sall,sall); ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY); for(int x=0; x<sall; x++) {SymbolSelect(AS30[x],true);} if(ValidatePairs(Symbol())>=0) symbfix=true; if(!symbfix) { Alert("Expert Advisors will not trade on pairs "+Symbol()); Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart."); ExpertRemove(); } //-- switch(usepairs) { case 0: // All Forex & Metal 30 Pairs { ArrayResize(DIRI,sall,sall); arrsymbx=sall; ArraySymbolResize(); ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY); pairs="Multi Currency "+string(sall)+" Pairs"; //-- break; } case 1: // Trader wishes pairs { ArrayResize(DIRI,arspc,arspc); arrsymbx=arspc; ArraySymbolResize(); ArrayCopy(DIRI,SPC,0,0,WHOLE_ARRAY); pairs="("+string(arspc)+") Trader Wishes Pairs"; //-- break; } case 2: // USD pairs { ArrayResize(DIRI,arusd,arusd); arrsymbx=arusd; ArraySymbolResize(); ArrayCopy(DIRI,USDs,0,0,WHOLE_ARRAY); pairs="("+string(arusd)+") Multi Currency USD Pairs"; //-- break; } case 3: // EUR pairs { ArrayResize(DIRI,areur,areur); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,EURs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex EUR Pairs"; //-- break; } case 4: // GBP pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,GBPs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex GBP Pairs"; //-- break; } case 5: // AUD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,AUDs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex AUD Pairs"; //-- break; } case 6: // NZD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,NZDs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex NZD Pairs"; //-- break; } case 7: // CAD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,CADs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex CAD Pairs"; //-- break; } case 8: // CHF pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,CHFs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex CHF Pairs"; //-- break; } case 9: // JPY pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,JPYs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex JPY Pairs"; //-- break; } } //-- return; //--- } //-end HandlingSymbolArrays() //---------//
Innerhalb der Funktion HandlingSymbolArrays() rufen wir die Funktion SetSymbolNamePS() auf. Mit SetSymbolNamePS() werden wir in der Lage sein, Symbolnamen mit Präfixen und/oder Suffixen zu behandeln.
void MCEA::SetSymbolNamePS(void) { //--- int sym_Lenpre=0; int sym_Lensuf=0; string sym_pre=""; string sym_suf=""; SymbolSelect(Symbol(),true); string insymbol=Symbol(); int inlen=StringLen(insymbol); int toseek=-1; string dep=""; string bel=""; string sym_use =""; int pairx=-1; string xcur[]={"EUR","GBP","AUD","NZD","USD","CAD","CHF"}; // 7 major currency int xcar=ArraySize(xcur); //-- for(int x=0; x<xcar; x++) { toseek=StringFind(insymbol,xcur[x],0); if(toseek>=0) { pairx=x; break; } } if(pairx>=0) { int awl=toseek-3 <0 ? 0 : toseek-3; int sd=StringFind(insymbol,"SD",0); if(toseek==0 && sd<4) { dep=StringSubstr(insymbol,toseek,3); bel=StringSubstr(insymbol,toseek+3,3); sym_use=dep+bel; } else if(toseek>0) { dep=StringSubstr(insymbol,toseek,3); bel=StringSubstr(insymbol,toseek+3,3); sym_use=dep+bel; } else { dep=StringSubstr(insymbol,awl,3); bel=StringSubstr(insymbol,awl+3,3); sym_use=dep+bel; } } //-- string sym_nmx=sym_use; int lensx=StringLen(sym_nmx); //-- if(inlen>lensx && lensx==6) { sym_Lenpre=StringFind(insymbol,sym_nmx,0); sym_Lensuf=inlen-lensx-sym_Lenpre; //-- if(sym_Lenpre>0) { sym_pre=StringSubstr(insymbol,0,sym_Lenpre); for(int i=0; i<xcar; i++) if(StringFind(sym_pre,xcur[i],0)>=0) sym_pre=""; } if(sym_Lensuf>0) { sym_suf=StringSubstr(insymbol,sym_Lenpre+lensx,sym_Lensuf); for(int i=0; i<xcar; i++) if(StringFind(sym_suf,xcur[i],0)>=0) sym_suf=""; } } //-- pre=sym_pre; suf=sym_suf; inpre=StringLen(pre); insuf=StringLen(suf); posCur1=inpre; posCur2=posCur1+3; //-- return; //--- } //-end SetSymbolNamePS() //---------//
Anmerkung: Der Experte validiert die Paare. Wenn der Händler bei der Eingabe des Paarnamens einen Fehler macht (Tippfehler) oder wenn die Paarvalidierung fehlschlägt, erhält der Experte eine Warnung und der Expertenberater wird vom Chart entfernt.
In der Experten-Eingabeeigenschaftsgruppe Trade on Specific Time (Handel zu bestimmten Zeiten) kann der Händler wählen, ob er in einer bestimmten Zeitzone handeln möchte (Yes) oder (No).
Wenn die Option „Trade on Specific Time Zone“ (Handel in einer bestimmten Zeitzone) auf „No“ eingestellt ist, handelt der Experte von MT5 00:15 bis 23:59 Uhr.
Wenn Ja, dann wählen Sie die Enumerations-Optionen:
- Trading on Custom Session (Handel während einer nutzerdefinierten Sitzung)
- Trading on New Zealand Session (Handel während der neuseeländischen Sitzung)
- Trading on Australia Sydney Session (Handel während der Australien Sydney Session)
- Trading on Asia Tokyo Session (Handel während der Asien Tokyo Session)
- Trading on Europe London Session (Handel während der Europa London Session)
- Trading on America New York Session (Handel während der Amerika New York Session)
Standardmäßig ist der Handel in bestimmten Zeitzonen auf „Yes“ und auf Handel in nutzerdefinierten Sitzungen eingestellt.
Handel während der Custom Session:
In dieser Sitzung müssen die Händler die Zeit oder die Stunden und Minuten für den Handelsbeginn und die Stunden und Minuten für das Handelsende festlegen. Das bedeutet, dass der EA nur während des angegebenen Zeitraums vom Start bis zum Ende Aktivitäten durchführt.
In der Zwischenzeit wird in der New Zealand Trading Session bis zur New York US Trading Session die Zeit vom Beginn des Handels bis zum Ende des Handels vom EA berechnet.
2. Klasse für funktionierenden Expert Advisor
Um den Expert Advisor-Workflow zu erstellen und zu konfigurieren, haben wir eine Klasse erstellt, die alle Variablen, Objekte und Funktionen deklariert, die für einen Expert Advisor mit mehreren Währungen erforderlich sind.
//+------------------------------------------------------------------+ //| Class for working Expert Advisor | //+------------------------------------------------------------------+ class MCEA { //--- private: //---- int x_year; // Year int x_mon; // Month int x_day; // Day of the month int x_hour; // Hour in a day int x_min; // Minutes int x_sec; // Seconds //-- int oBm, oSm, ldig; //--- Variables used in prefix and suffix symbols int posCur1, posCur2; int inpre, insuf; bool symbfix; string pre,suf; string prefix,suffix; //--- Variables are used in Trading Time Zone int ishour, onhour; int tftrlst, tfcinws; datetime rem, znop, zncl, zntm; datetime SesCuOp, SesCuCl, Ses01Op, Ses01Cl, Ses02Op, Ses02Cl, Ses03Op, Ses03Cl, Ses04Op, Ses04Cl, Ses05Op, Ses05Cl, SesNoOp, SesNoCl; //-- string tz_ses, tz_opn, tz_cls; //-- string tmopcu, tmclcu, tmop01, tmcl01, tmop02, tmcl02, tmop03, tmcl03, tmop04, tmcl04, tmop05, tmcl05, tmopno, tmclno; //---------------------- //-- double LotPS; double point; double slv, tpv, pip, xpip; double SARstep, SARmaxi; double floatprofit, fixclprofit; //-- string pairs, hariini, daytrade, trade_mode; //-- double OPEN[], HIGH[], LOW[], CLOSE[]; datetime TIME[]; datetime closetime; //-- //------------ //------------ void SetSymbolNamePS(void); void HandlingSymbolArrays(void); void Set_Time_Zone(void); void Time_Zone(void); bool Trade_session(void); string PosTimeZone(void); int ThisTime(const int reqmode); int ReqTime(datetime reqtime,const int reqmode); //-- int DirectionMove(const string symbol,const ENUM_TIMEFRAMES stf); int GetIndiSignals(const string symbol); int ZigZagSignal(const string symbol); int AOSignal(const string symbol); int AOColorSignal(const string symbol); int PARSAR05(const string symbol); int PARSAR15(const string symbol); int LotDig(const string symbol); //-- double MLots(const string symbx); double NonZeroDiv(double val1,double val2); double OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice); double OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice); double SetOrderSL(const string xsymb,ENUM_POSITION_TYPE type,double atprice); double SetOrderTP(const string xsymb,ENUM_POSITION_TYPE type,double atprice); double TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type); //-- string ReqDate(int d,int h,int m); string TF2Str(ENUM_TIMEFRAMES period); string timehr(int hr,int mn); string TradingDay(void); string AccountMode(); string GetCommentForOrder(void) { return(expname); } //------------ public: //--- //-- ZigZag_AO_MCEA Config -- string DIRI[], AS30[], VSym[]; string SPC[]; string USD[]; string EUR[]; string GBP[]; string AUD[]; string NZD[]; string CAD[]; string CHF[]; string JPY[]; //-- string expname; string indiname1; //-- //--- Indicators Handle int hZigZag[], hAO[]; int hVIDyAv[]; int hPar05[], hPar15[]; //--- int ALO, dgts, arrsar, arrsymbx; int sall, arusd, areur, aretc, arspc, arper; ulong slip; //-- double profitb[], profits[]; double minprofit; //-- int Buy, Sell; int ccur, psec, xtto, checktml; int OpOr[],xob[],xos[]; //-- int year, // Year mon, // Month day, // Day hour, // Hour min, // Minutes sec, // Seconds dow, // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) doy; // Day number of the year (January 1st is assigned the number value of zero) //-- ENUM_TIMEFRAMES TFt, TFT05, TFT15; //-- bool PanelExtra; //------------ MCEA(void); ~MCEA(void); //------------ //-- virtual void ZigZag_AO_MCEA_Config(void); virtual void ExpertActionTrade(void); //-- void ArraySymbolResize(void); void CurrentSymbolSet(const string symbol); void Pips(const string symbol); void TradeInfo(void); void Do_Alerts(const string symbx,string msgText); void CheckOpenPMx(const string symbx); void SetSLTPOrders(void); void CloseAllOrders(void); void CheckClose(const string symbx); void TodayOrders(void); void UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf); void UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf,int bars); void RefreshPrice(const string symbx,ENUM_TIMEFRAMES xtf,int bars); //-- bool CheckEquityBalance(void); bool RefreshTick(const string symbx); bool TradingToday(void); bool OpenBuy(const string symbol); bool OpenSell(const string symbol); bool ModifyOrderSLTP(double mStop,double ordtp); bool ModifyOrdersSL(const string symbx,int TS_type); bool ModifyOrdersTP(const string symbx); bool CloseAllProfit(void); bool CloseAllLoss(void); bool ManualCloseAllProfit(void); bool CheckProfitLoss(const string symbol); bool CloseBuyPositions(const string symbol); bool CloseSellPositions(const string symbol); bool CheckProfit(const string symbol,ENUM_POSITION_TYPE intype); bool CheckLoss(const string symbol,ENUM_POSITION_TYPE intype,double slc=0.0); //-- int PairsIdxArray(const string symbol); int ValidatePairs(const string symbol); int GetOpenPosition(const string symbol); int GetCloseInWeakSignal(const string symbol,int exis); //-- string getUninitReasonText(int reasonCode); //-- //------------ //--- }; //-end class MCEA //---------// MCEA mc; //---------//
Die erste und wichtigste Funktion im Multi-Currency Expert Advisor-Workflow-Prozess wird von OnInit() aufgerufen, ZigZag_AO_MCEA_Config():
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(void) { //--- mc.ZigZag_AO_MCEA_Config(); //-- return(INIT_SUCCEEDED); //--- } //-end OnInit() //---------//
Die Funktion ZigZag_AO_MCEA_Config() konfiguriert alle zu verwendenden Symbole, alle Zeitrahmen, alle Handle-Indikatoren und einige wichtige Funktionen des Include-Datei-Headers für den Arbeitsablauf des Expert Advisors.
Die Funktion ZigZag_AO_MCEA_Config() beschreibt und implementiert die Handhabung von Zeitrahmen und die Erstellung von Indikator-Handles für alle im Expert Advisor Workflow verwendeten Indikatoren.
//+------------------------------------------------------------------+ //| Expert Configuration | //+------------------------------------------------------------------+ void MCEA::ZigZag_AO_MCEA_Config(void) { //--- //-- HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded //-- TFT05=PERIOD_M5; TFT15=PERIOD_M15; ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1}; int arTFs=ArraySize(TFs); //-- for(int x=0; x<arTFs; x++) if(tfinuse==x) TFt=TFs[x]; // TF for calculation signal //-- //-- Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { hZigZag[x] = iCustom(DIRI[x],TFt,indiname1,zzDepth,zzDevia,zzBackS); //-- Handle for the ZigZag indicator hAO[x] = iAO(DIRI[x],TFt); //-- Handle for the Awesome_Oscillator indicator hVIDyAv[x] = iVIDyA(DIRI[x],TFt,9,12,0,PRICE_WEIGHTED); //-- Handle for the VIDYA indicator for Trailing Stop hPar05[x] = iSAR(DIRI[x],TFT05,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M5 Timeframe hPar15[x] = iSAR(DIRI[x],TFT15,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M15 Timeframe //-- } //-- TesterHideIndicators(true); minprofit=NormalizeDouble(TSmin/100.0,2); //-- ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders(); if(Close_by_Opps==No) { if((int)mc_account.LimitOrders()>=(sall*2)) ALO=sall*2; else ALO=(int)(mc_account.LimitOrders()/2); } //-- LotPS=(double)ALO; //-- mc_trade.SetExpertMagicNumber(magicEA); mc_trade.SetDeviationInPoints(slip); mc_trade.SetMarginMode(); Set_Time_Zone(); //-- return; //--- } //-end ZigZag_AO_MCEA_Config() //---------//
3. OnTick()-Funktion des Experten und der Arbeitsablauf
Innerhalb der Expert Tick Funktion OnTick() werden wir eine der wichtigsten Funktionen in einem Multi-Currency Expert Advisor aufrufen, nämlich die Funktion ExpertActionTrade() .
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(void) { //--- mc.ExpertActionTrade(); //-- return; //--- } //-end OnTick() //---------//
Der gesamte Prozess der EA-Arbeit für den Handel ist in dieser Funktion enthalten.
Das bedeutet, dass die Funktion ExpertActionTrade() alle Aktivitäten durchführt und den automatischen Handel verwaltet, angefangen von Eröffnungs-, Schließaufträgen, Trailing-Stops oder Trailing-Profits und anderen zusätzlichen Aktivitäten.
void MCEA::ExpertActionTrade(void) { //--- //--Check Trading Terminal ResetLastError(); //-- if(!MQLInfoInteger(MQL_TRADE_ALLOWED) && mc.checktml==0) //-- Check whether MT5 Algorithmic trading is Allow or Prohibit { mc.Do_Alerts(Symbol(),"Trading Expert at "+Symbol()+" are NOT Allowed by Setting."); mc.checktml=1; //-- Variable checktml is given a value of 1, so that the alert is only done once. return; } //-- if(!DisplayManualButton("M","C","R")) DisplayManualButton(); //-- Show the expert manual button panel //-- if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart //--- //-- int mcsec=mc.ThisTime(mc.sec); //-- if(fmod((double)mcsec,5.0)==0) mc.ccur=mcsec; //-- if(mc.ccur!=mc.psec) { string symbol; //-- Here we start with the rotation of the name of all symbol or pairs to be traded for(int x=0; x<mc.arrsymbx && !IsStopped(); x++) { //-- switch(trademode) { case SP: { if(mc.DIRI[x]!=Symbol()) continue; symbol=Symbol(); mc.pairs=mc.pairs+" ("+symbol+")"; break; } case MP: { if(mc.DIRI[x]==Symbol()) symbol=Symbol(); else symbol=mc.DIRI[x]; break; } } //-- mc.CurrentSymbolSet(symbol); //-- if(mc.TradingToday() && mc.Trade_session()) { //-- mc.OpOr[x]=mc.GetOpenPosition(symbol); //-- Get trading signals to open positions //-- //-- and store in the variable OpOr[x] if(mc.OpOr[x]==mc.Buy) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Buy" (value=1) { //-- mc.CheckOpenPMx(symbol); //-- if(Close_by_Opps==Yes && mc.xos[x]>0) mc.CloseSellPositions(symbol); //-- if(mc.xob[x]==0 && mc.xtto<mc.ALO) mc.OpenBuy(symbol); else if(mc.xtto>=mc.ALO) { //-- mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+ "\n the limit = "+string(mc.ALO)+" Orders "); //-- mc.CheckOpenPMx(symbol); //-- if(mc.xos[x]>0 && mc.profits[x]<-1.02 && mc.xob[x]==0) {mc.CloseSellPositions(symbol); mc.OpenBuy(symbol);} else mc.CloseAllProfit(); //-- if(mc.xos[x]>0 && use_sl==No && CheckVSLTP==Yes) { if(mc.CheckLoss(symbol,POSITION_TYPE_SELL,SLval)) if(mc.CloseSellPositions(symbol)) mc.Do_Alerts(symbol,"Check Profit Trade and Close order due stop in loss."); } } } if(mc.OpOr[x]==mc.Sell) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Sell" (value=-1) { //-- mc.CheckOpenPMx(symbol); //-- if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol); //-- if(mc.xos[x]==0 && mc.xtto<mc.ALO) mc.OpenSell(symbol); else if(mc.xtto>=mc.ALO) { //-- mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+ "\n the limit = "+string(mc.ALO)+" Orders "); //-- mc.CheckOpenPMx(symbol); //-- if(mc.xob[x]>0 && mc.profitb[x]<-1.02 && mc.xos[x]==0) {mc.CloseBuyPositions(symbol); mc.OpenSell(symbol);} else mc.CloseAllProfit(); //-- if(mc.xob[x]>0 && use_sl==No && CheckVSLTP==Yes) { if(mc.CheckLoss(symbol,POSITION_TYPE_BUY,SLval)) if(mc.CloseBuyPositions(symbol)) mc.Do_Alerts(symbol,"Check Profit Trade and Close order due stop in loss."); } } } } //-- mc.CheckOpenPMx(symbol); //-- if(mc.xtto>0) { //-- if(SaveOnRev==Yes) //-- Close Trade and Save profit due to weak signal (Yes) { mc.CheckOpenPMx(symbol); if(mc.profitb[x]>mc.minprofit && mc.xob[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) { mc.CloseBuyPositions(symbol); mc.Do_Alerts(symbol,"Close BUY order "+symbol+" to save profit due to weak signal."); } if(mc.profits[x]>mc.minprofit && mc.xos[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) { mc.CloseSellPositions(symbol); mc.Do_Alerts(symbol,"Close SELL order "+symbol+" to save profit due to weak signal."); } } //-- if(TrailingSL==Yes) mc.ModifyOrdersSL(symbol,trlby); //-- Use Trailing Stop Loss (Yes) if(TrailingTP==Yes) mc.ModifyOrdersTP(symbol); //-- Use Trailing Take Profit (Yes) } //-- mc.CheckOpenPMx(symbol); if(Close_by_Opps==No && (mc.xob[x]+mc.xos[x]>1)) { if(mc.CheckProfitLoss(symbol)) mc.Do_Alerts(symbol,"Close order due stop in loss."); } //-- if(use_sl==No && CheckVSLTP==Yes) { if(!mc.CheckEquityBalance()) if(mc.CloseAllLoss()) mc.Do_Alerts(symbol,"Close order due stop in loss to secure equity."); } //-- mc.CheckClose(symbol); } //-- mc.psec=mc.ccur; } //-- return; //--- } //-end ExpertActionTrade() //---------//
Die Eigenschaftsgruppe Day Trading On/Off ermöglicht es Händlern, an bestimmten Tagen von Sonntag bis Samstag zu handeln. Hier können Händler mit den Optionen (Yes) oder (No) den Experten für den Handel an einem bestimmten Tag aktivieren oder deaktivieren.
//--Day Trading On/Off input group "=== Day Trading On/Off ==="; // Day Trading On/Off input YN ttd0 = No; // Select Trading on Sunday (Yes) or (No) input YN ttd1 = Yes; // Select Trading on Monday (Yes) or (No) input YN ttd2 = Yes; // Select Trading on Tuesday (Yes) or (No) input YN ttd3 = Yes; // Select Trading on Wednesday (Yes) or (No) input YN ttd4 = Yes; // Select Trading on Thursday (Yes) or (No) input YN ttd5 = Yes; // Select Trading on Friday (Yes) or (No) input YN ttd6 = No; // Select Trading on Saturday (Yes) or (No)
Die Ausführung für den Day Trading On/Off ist wie folgt:
bool MCEA::TradingToday(void) { //--- bool tradetoday=false; int trdday=ThisTime(dow); hariini="No"; //-- int ttd[]; ArrayResize(ttd,7); ttd[0]=ttd0; ttd[1]=ttd1; ttd[2]=ttd2; ttd[3]=ttd3; ttd[4]=ttd4; ttd[5]=ttd5; ttd[6]=ttd6; //-- if(ttd[trdday]==Yes) {tradetoday=true; hariini="Yes";} //-- return(tradetoday); //--- } //-end TradingToday() //---------//
Anmerkungen: Die Bedingungen für den Tageshandel (Day Trading On/Off) werden in der Handelsinfo im Chart angezeigt.
Die wird von der Funktion TradingDay() ausgeführt.
string MCEA::TradingDay(void) { //--- int trdday=ThisTime(dow); switch(trdday) { case 0: daytrade="Sunday"; break; case 1: daytrade="Monday"; break; case 2: daytrade="Tuesday"; break; case 3: daytrade="Wednesday"; break; case 4: daytrade="Thursday"; break; case 5: daytrade="Friday"; break; case 6: daytrade="Saturday"; break; } return(daytrade); //--- } //-end TradingDay() //---------//
Händler haben die Möglichkeit, in der Eigenschaftsgruppe „Trade at Specific Time“ des Expert Advisors nach Zeitzonen zu handeln.
Anmerkungen: Wie oben erläutert, wird im Falle des Handels an der New Zealand Session zum Handel an der US New York Session die Zeit vom Beginn des Handels bis zum Ende des Handels vom EA berechnet.
Daher müssen Händler in den Eigenschaften des Experteneintrags nur die Zeit für die Stunde und Minute des Handelsbeginns und die Zeit für die Stunde und Minute des Handelsendes für die nutzerdefinierte Sitzung festlegen.
Die Funktion ExpertActionTrade() wurde um einen Aufruf der booleschen Funktion Trade_session() speziell für den Zeitzonenhandel erweitert.
Wenn Trade_session() true ist, dann wird der EA-Arbeitsprozess fortgesetzt, bis er beendet ist, aber wenn er false ist, dann wird der EA nur die Aufgaben „Close Trade and Save Profit due to Weak Signal if it is (Yes)“ (Schließen der Position und Sichern des Gewinns aufgrund schwachen Signals, wenn es (Yes) ist) und „Trailing Stop if it is (Yes)“ (Trailing Stop, wenn ja (Yes)) ausführen.
bool MCEA::Trade_session(void) { //--- bool trd_ses=false; ishour=ThisTime(hour); if(ishour!=onhour) Set_Time_Zone(); datetime tcurr=TimeCurrent(); // Server Time //-- switch(session) { case Cus_Session: { if(tcurr>=SesCuOp && tcurr<=SesCuCl) trd_ses=true; break; } case New_Zealand: { if(tcurr>=Ses01Op && tcurr<=Ses01Cl) trd_ses=true; break; } case Australia: { if(tcurr>=Ses02Op && tcurr<=Ses02Cl) trd_ses=true; break; } case Asia_Tokyo: { if(tcurr>=Ses03Op && tcurr<=Ses03Cl) trd_ses=true; break; } case Europe_London: { if(tcurr>=Ses04Op && tcurr<=Ses04Cl) trd_ses=true; break; } case US_New_York: { if(tcurr>=Ses05Op && tcurr<=Ses05Cl) trd_ses=true; break; } } //-- if(trd_time_zone==No) { if(tcurr>=SesNoOp && tcurr<=SesNoCl) trd_ses=true; } //-- onhour=ishour; //-- return(trd_ses); //--- } //-end Trade_session() //---------//
Der Arbeitsablauf in Trade at Specific Time sieht folgendermaßen aus: Zuerst ruft die Funktion ExpertActionTrade() die Funktion Trade_session() auf, dann ruft die Funktion Trade_session() die Funktion Set_Time_Zone() auf, und schließlich ruft die Funktion Set_Time_Zone() die Funktion Time_Zone() auf.
void MCEA::Set_Time_Zone(void) { //--- //-- Server Time==TimeCurrent() datetime TTS=TimeTradeServer(); datetime GMT=TimeGMT(); //-- MqlDateTime svrtm,gmttm; TimeToStruct(TTS,svrtm); TimeToStruct(GMT,gmttm); int svrhr=svrtm.hour; // Server time hour int gmthr=gmttm.hour; // GMT time hour int difhr=svrhr-gmthr; // Time difference Server time to GMT time //-- int NZSGMT=12; // New Zealand Session GMT/UTC+12 int AUSGMT=10; // Australia Sydney Session GMT/UTC+10 int TOKGMT=9; // Asia Tokyo Session GMT/UTC+9 int EURGMT=0; // Europe London Session GMT/UTC 0 int USNGMT=-5; // US New York Session GMT/UTC-5 //-- int NZSStm=8; // New Zealand Session time start: 08:00 Local Time int NZSCtm=17; // New Zealand Session time close: 17:00 Local Time int AUSStm=7; // Australia Sydney Session time start: 07:00 Local Time int AUSCtm=17; // Australia Sydney Session time close: 17:00 Local Time int TOKStm=9; // Asia Tokyo Session time start: 09:00 Local Time int TOKCtm=18; // Asia Tokyo Session time close: 18:00 Local Time int EURStm=9; // Europe London Session time start: 09:00 Local Time int EURCtm=19; // Europe London Session time close: 19:00 Local Time int USNStm=8; // US New York Session time start: 08:00 Local Time int USNCtm=17; // US New York Session time close: 17:00 Local Time //-- int nzo = (NZSStm+difhr-NZSGMT)<0 ? 24+(NZSStm+difhr-NZSGMT) : (NZSStm+difhr-NZSGMT); int nzc = (NZSCtm+difhr-NZSGMT)<0 ? 24+(NZSCtm+difhr-NZSGMT) : (NZSCtm+difhr-NZSGMT); //-- int auo = (AUSStm+difhr-AUSGMT)<0 ? 24+(AUSStm+difhr-AUSGMT) : (AUSStm+difhr-AUSGMT); int auc = (AUSCtm+difhr-AUSGMT)<0 ? 24+(AUSCtm+difhr-AUSGMT) : (AUSCtm+difhr-AUSGMT); //-- int tko = (TOKStm+difhr-TOKGMT)<0 ? 24+(TOKStm+difhr-TOKGMT) : (TOKStm+difhr-TOKGMT); int tkc = (TOKCtm+difhr-TOKGMT)<0 ? 24+(TOKCtm+difhr-TOKGMT) : (TOKCtm+difhr-TOKGMT); //-- int euo = (EURStm+difhr-EURGMT)<0 ? 24+(EURStm+difhr-EURGMT) : (EURStm+difhr-EURGMT); int euc = (EURCtm+difhr-EURGMT)<0 ? 24+(EURCtm+difhr-EURGMT) : (EURCtm+difhr-EURGMT); //-- int uso = (USNStm+difhr-USNGMT)<0 ? 24+(USNStm+difhr-USNGMT) : (USNStm+difhr-USNGMT); int usc = (USNCtm+difhr-USNGMT)<0 ? 24+(USNCtm+difhr-USNGMT) : (USNCtm+difhr-USNGMT); if(usc==0||usc==24) usc=23; //-- //---Trading on Custom Session int _days00=ThisTime(day); int _days10=ThisTime(day); if(stsescuh>clsescuh) _days10=ThisTime(day)+1; tmopcu=ReqDate(_days00,stsescuh,stsescum); tmclcu=ReqDate(_days10,clsescuh,clsescum); //-- //--Trading on New Zealand Session GMT/UTC+12 int _days01=ThisTime(hour)<nzc ? ThisTime(day)-1 : ThisTime(day); int _days11=ThisTime(hour)<nzc ? ThisTime(day) : ThisTime(day)+1; tmop01=ReqDate(_days01,nzo,0); // start: 08:00 Local Time == 20:00 GMT/UTC tmcl01=ReqDate(_days11,nzc-1,59); // close: 17:00 Local Time == 05:00 GMT/UTC //-- //--Trading on Australia Sydney Session GMT/UTC+10 int _days02=ThisTime(hour)<auc ? ThisTime(day)-1 : ThisTime(day); int _days12=ThisTime(hour)<auc ? ThisTime(day) : ThisTime(day)+1; tmop02=ReqDate(_days02,auo,0); // start: 07:00 Local Time == 21:00 GMT/UTC tmcl02=ReqDate(_days12,auc-1,59); // close: 17:00 Local Time == 07:00 GMT/UTC //-- //--Trading on Asia Tokyo Session GMT/UTC+9 int _days03=ThisTime(hour)<tkc ? ThisTime(day) : ThisTime(day)+1; int _days13=ThisTime(hour)<tkc ? ThisTime(day) : ThisTime(day)+1; tmop03=ReqDate(_days03,tko,0); // start: 09:00 Local Time == 00:00 GMT/UTC tmcl03=ReqDate(_days13,tkc-1,59); // close: 18:00 Local Time == 09:00 GMT/UTC //-- //--Trading on Europe London Session GMT/UTC 00:00 int _days04=ThisTime(hour)<euc ? ThisTime(day) : ThisTime(day)+1; int _days14=ThisTime(hour)<euc ? ThisTime(day) : ThisTime(day)+1; tmop04=ReqDate(_days04,euo,0); // start: 09:00 Local Time == 09:00 GMT/UTC tmcl04=ReqDate(_days14,euc-1,59); // close: 19:00 Local Time == 19:00 GMT/UTC //-- //--Trading on US New York Session GMT/UTC-5 int _days05=ThisTime(hour)<usc ? ThisTime(day) : ThisTime(day)+1; int _days15=ThisTime(hour)<=usc ? ThisTime(day) : ThisTime(day)+1; tmop05=ReqDate(_days05,uso,0); // start: 08:00 Local Time == 13:00 GMT/UTC tmcl05=ReqDate(_days15,usc,59); // close: 17:00 Local Time == 22:00 GMT/UTC //-- //--Not Use Trading Time Zone if(trd_time_zone==No) { tmopno=ReqDate(ThisTime(day),0,15); tmclno=ReqDate(ThisTime(day),23,59); } //-- Time_Zone(); //-- return; //--- } //-end Set_Time_Zone() //---------//
void MCEA::Time_Zone(void) { //--- //-- tz_ses=""; //-- switch(session) { case Cus_Session: { SesCuOp=StringToTime(tmopcu); SesCuCl=StringToTime(tmclcu); zntm=SesCuOp; znop=SesCuOp; zncl=SesCuCl; tz_ses="Custom_Session"; tz_opn=timehr(stsescuh,stsescum); tz_cls=timehr(clsescuh,clsescum); break; } case New_Zealand: { Ses01Op=StringToTime(tmop01); Ses01Cl=StringToTime(tmcl01); zntm=Ses01Op; znop=Ses01Op; zncl=Ses01Cl; tz_ses="New_Zealand/Oceania"; tz_opn=timehr(ReqTime(Ses01Op,hour),ReqTime(Ses01Op,min)); tz_cls=timehr(ReqTime(Ses01Cl,hour),ReqTime(Ses01Cl,min)); break; } case Australia: { Ses02Op=StringToTime(tmop02); Ses02Cl=StringToTime(tmcl02); zntm=Ses02Op; znop=Ses02Op; zncl=Ses02Cl; tz_ses="Australia Sydney"; tz_opn=timehr(ReqTime(Ses02Op,hour),ReqTime(Ses02Op,min)); tz_cls=timehr(ReqTime(Ses02Cl,hour),ReqTime(Ses02Cl,min)); break; } case Asia_Tokyo: { Ses03Op=StringToTime(tmop03); Ses03Cl=StringToTime(tmcl03); zntm=Ses03Op; znop=Ses03Op; zncl=Ses03Cl; tz_ses="Asia/Tokyo"; tz_opn=timehr(ReqTime(Ses03Op,hour),ReqTime(Ses03Op,min)); tz_cls=timehr(ReqTime(Ses03Cl,hour),ReqTime(Ses03Cl,min)); break; } case Europe_London: { Ses04Op=StringToTime(tmop04); Ses04Cl=StringToTime(tmcl04); zntm=Ses04Op; znop=Ses04Op; zncl=Ses04Cl; tz_ses="Europe/London"; tz_opn=timehr(ReqTime(Ses04Op,hour),ReqTime(Ses04Op,min)); tz_cls=timehr(ReqTime(Ses04Cl,hour),ReqTime(Ses04Cl,min)); break; } case US_New_York: { Ses05Op=StringToTime(tmop05); Ses05Cl=StringToTime(tmcl05); zntm=Ses05Op; znop=Ses05Op; zncl=Ses05Cl; tz_ses="US/New_York"; tz_opn=timehr(ReqTime(Ses05Op,hour),ReqTime(Ses05Op,min)); tz_cls=timehr(ReqTime(Ses05Cl,hour),ReqTime(Ses05Cl,min)); break; } } //-- if(trd_time_zone==No) { SesNoOp=StringToTime(tmopno); SesNoCl=StringToTime(tmclno); zntm=SesNoOp; znop=SesNoOp; zncl=SesNoCl; tz_ses="Not Use Time Zone"; tz_opn=timehr(ReqTime(SesNoOp,hour),ReqTime(SesNoOp,min)); tz_cls=timehr(ReqTime(SesNoCl,hour),ReqTime(SesNoCl,min)); } //-- return; //--- } //-end Time_Zone() //---------//
4. Wie erhalte ich die Handelssignale zum Eröffnen von Positionen?
Um ein Signal zum Eröffnen einer Position zu erhalten, ruft die Funktion ExpertActionTrade() die Funktion GetOpenPosition() auf.
int MCEA::GetOpenPosition(const string symbol) // Signal Open Position { //--- int ret=0; int rise=1, down=-1; //-- int ZZAOSignal=GetIndiSignals(symbol); int dirmove=DirectionMove(symbol,TFt); int psar15=PARSAR15(symbol); //-- if(ZZAOSignal==rise && dirmove==rise && psar15==rise) ret=rise; if(ZZAOSignal==down && dirmove==down && psar15==down) ret=down; //-- return(ret); //--- } //-end GetOpenPosition() //---------//
Die Funktion GetOpenPosition() wird 3 Funktionen aufrufen:
- GetIndiSignals(symbol)
- DirectionMove(symbol,TFt)
- PARSAR15(symbol)
4.1. Die Funktion GetIndiSignals(symbol) ruft 2 Funktionen auf:
- ZigZagSignal(symbol)
- AOSignal(symbol)
4.1.1. ZigZag-Signal
Innerhalb der Funktion ZigZagSignal() wird 1 Funktion verwendet und aufgerufen, nämlich die FunktionPairsIdxArray().
int xx=PairsIdxArray(symbol)
int MCEA::PairsIdxArray(const string symbol) { //--- int pidx=-1; //-- for(int x=0; x<arrsymbx; x++) { if(DIRI[x]==symbol) { pidx=x; break; } } //-- return(pidx); //--- } //-end PairsIdxArray() //---------//
Die Funktion PairsIdxArray() wird verwendet, um den Namen des gewünschten Symbols und die Handles seiner Indikatoren zu erhalten.
Dann wird das entsprechende Indikator-Handle aufgerufen, um den Pufferwert des ZigZag-Indikators aus diesem Zeitrahmen zu erhalten.
//-- Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { hZigZag[x] = iCustom(DIRI[x],TFt,indiname1,zzDepth,zzDevia,zzBackS); //-- Handle for the ZigZag indicator hAO[x] = iAO(DIRI[x],TFt); //-- Handle for the Awesome_Oscillator indicator hVIDyAv[x] = iVIDyA(DIRI[x],TFt,9,12,0,PRICE_WEIGHTED); //-- Handle for the VIDYA indicator for Trailing Stop hPar05[x] = iSAR(DIRI[x],TFT05,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M5 Timeframe hPar15[x] = iSAR(DIRI[x],TFT15,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M15 Timeframe //-- } //--
Um also den Pufferwert des ZigZag-Indikators zu erhalten, kopieren wir jeden Puffer aus dem Handle des ZigZag-Indikators.
Kopieren des ZigZag-Puffers (Puffer 0) vom ZigZag-Indikator-Handle in das Ziel-Array:
CopyBuffer(hZigZag[x],0,0,barcalc,ZZBuffer);
Außerdem wird die Funktion UpdatePrice() aufgerufen, um den Wert des Höchstpreises und des Tiefstpreises zu erhalten, die verwendet werden, um die Positionen des ZigZag-Puffers Hoch und des ZigZag-Puffers Tief zu ermitteln.
void MCEA::UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf) { //--- //-- ArrayFree(OPEN); ArrayFree(HIGH); ArrayFree(LOW); ArrayFree(CLOSE); ArrayFree(TIME); //-- ArrayResize(OPEN,arper,arper); ArrayResize(HIGH,arper,arper); ArrayResize(LOW,arper,arper); ArrayResize(CLOSE,arper,arper); ArrayResize(TIME,arper,arper); //-- ArraySetAsSeries(OPEN,true); ArraySetAsSeries(HIGH,true); ArraySetAsSeries(LOW,true); ArraySetAsSeries(CLOSE,true); ArraySetAsSeries(TIME,true); //-- ArrayInitialize(OPEN,0.0); ArrayInitialize(HIGH,0.0); ArrayInitialize(LOW,0.0); ArrayInitialize(CLOSE,0.0); ArrayInitialize(TIME,0); //-- RefreshPrice(symbol,xtf,arper); //-- int co=CopyOpen(symbol,xtf,0,arper,OPEN); int ch=CopyHigh(symbol,xtf,0,arper,HIGH); int cl=CopyLow(symbol,xtf,0,arper,LOW); int cc=CopyClose(symbol,xtf,0,arper,CLOSE); int ct=CopyTime(symbol,xtf,0,arper,TIME); //-- return; //--- } //-end UpdatePrice() //---------//
Um die Positionen von ZigZag High und ZigZag Low zu ermitteln, führen wir Iterationen durch und vergleichen sie mit Price High und Price Low.
//-- for(int i=barcalc-1; i>=0; i--) { if(ZZBuffer[i]==HIGH[i]) ZH=i; if(ZZBuffer[i]==LOW[i]) ZL=i; } //--
Nachdem wir die Bar-Positionen von ZigZag High (ZH) und ZigZag Low (ZL) erhalten haben, hängt es nur noch von der Option des Signal-ZigZag-Indikators ab, die in der Eigenschaftseingabe ausgewählt wurde.
Die vollständige Funktion ZigZagSignal() lautet wie folgt:
int MCEA::ZigZagSignal(const string symbol) // ZigZag Signal for Open Position { //--- int ret=0; int rise=1, down=-1; int ZH=-1, ZL=-1; int barcalc=100; bool ZZrise=false; bool ZZdown=false; //-- double ZZBuffer[]; ArrayResize(ZZBuffer,barcalc,barcalc); ArraySetAsSeries(ZZBuffer,true); //-- int x=PairsIdxArray(symbol); UpdatePrice(symbol,TFt); //-- CopyBuffer(hZigZag[x],0,0,barcalc,ZZBuffer); //-- for(int i=barcalc-1; i>=0; i--) { if(ZZBuffer[i]==HIGH[i]) ZH=i; if(ZZBuffer[i]==LOW[i]) ZL=i; } //-- switch(sigzz) { case SZZ1: { ZZrise=((ZH==0 && HIGH[0]>HIGH[1])||(ZL<ZH && ZL>1)); ZZdown=((ZL==0 && LOW[0]<LOW[1])||(ZH<ZL && ZH>1)); //-- break; } case SZZ2: { ZZrise=(ZL<ZH && ZL>1); ZZdown=(ZH<ZL && ZH>1); //-- break; } case SZZ3: { ZZrise=((ZH==0 && HIGH[0]>HIGH[1])||(ZL<ZH && ZL>0)); ZZdown=((ZL==0 && LOW[0]<LOW[1])||(ZH<ZL && ZH>0)); //-- break; } case SZZ4: { ZZrise=(ZL<ZH && ZL>0); ZZdown=(ZH<ZL && ZH>0); //-- break; } }; //-- if(ZZrise) ret=rise; if(ZZdown) ret=down; //-- return(ret); //--- } //-end ZigZagSignal() //---------//
4.1.2. Das AO-Signal
Genau wie bei der Funktion ZigZagSignal() müssen wir auch bei der Funktion AOSignal() die FunktionPairsIdxArray() verwenden, um den Pufferwert des AO-Indikators zu erhalten.
Um also den Pufferwert des AO-Indikators zu erhalten, kopieren wir jeden Puffer aus dem Handle des AO-Indikators.
Kopieren des AO-Puffers (Puffer 0) vom AO-Indikator-Handle in das Ziel-Array:
CopyBuffer(hAO[x],0,0,barcalc,AOValue);
Und dann hängt es nur noch von der in der Eigenschaftseingabe gewählten Signal-AO-Anzeigeoption ab.
Um das Signal des AO-Indikators zu vervollständigen, verwenden wir außerdem die Farbe des AO-Indikators, um das Signal des Pufferwertes zu überprüfen.
Zu diesem Zweck haben wir eine Funktion erstellt, die den Farbwert des AO-Indikators mit dem Funktionsnamen AOColorSignal() ermittelt.
In dieser Funktion wird der Puffer 1 (Farbindexpuffer des Indikators) vom AO-Indikator kopiert:
CopyBuffer(hAO[x],1,0,barcalc,AOColor);
int MCEA::AOColorSignal(const string symbol) { //--- int ret=0; int rise=1, down=-1; int barcalc=9; //-- double AOColor[]; ArrayResize(AOColor,barcalc,barcalc); ArraySetAsSeries(AOColor,true); //-- int x=PairsIdxArray(symbol); UpdatePrice(symbol,TFt,barcalc); //-- CopyBuffer(hAO[x],1,0,barcalc,AOColor); //-- bool AORise=((AOColor[1]==1.0 && AOColor[0]==0.0)||(AOColor[1]==0.0 && AOColor[0]==0.0)); bool AODown=((AOColor[1]==0.0 && AOColor[0]==1.0)||(AOColor[1]==1.0 && AOColor[0]==1.0)); //-- if(AORise) ret=rise; if(AODown) ret=down; //-- return(ret); //--- } //-end AOColorSignal() //---------//
Die vollständige Funktion AOSignal() lautet wie folgt:
int MCEA::AOSignal(const string symbol) { //--- int ret=0; int rise=1, down=-1; int barcalc=9; bool AORValue=false; bool AODValue=false; //-- double AOValue[]; ArrayResize(AOValue,barcalc,barcalc); ArraySetAsSeries(AOValue,true); //-- int x=PairsIdxArray(symbol); UpdatePrice(symbol,TFt,barcalc); //-- CopyBuffer(hAO[x],0,0,barcalc,AOValue); //-- switch(sigao) { case SAO1: { AORValue=(AOValue[2]<=0.0 && AOValue[1]>0.0 && AOValue[0]>AOValue[1])||(AOValue[1]>AOValue[2] && AOValue[0]>AOValue[1]); AODValue=(AOValue[2]>=0.0 && AOValue[1]<0.0 && AOValue[0]<AOValue[1])||(AOValue[1]<AOValue[2] && AOValue[0]<AOValue[1]); //-- break; } case SAO2: { AORValue=(AOValue[1]<=0.0 && AOValue[0]>0.0)||(AOValue[0]>0.0 && AOValue[0]>AOValue[1]); AODValue=(AOValue[1]>=0.0 && AOValue[0]<0.0)||(AOValue[0]<0.0 && AOValue[0]<AOValue[1]); //-- break; } case SAO3: { AORValue=(AOValue[1]<=0.0 && AOValue[0]>0.0)||(AOValue[0]>AOValue[1]); AODValue=(AOValue[1]>=0.0 && AOValue[0]<0.0)||(AOValue[0]<AOValue[1]); //-- break; } }; //-- bool AORise=(AOColorSignal(symbol)==rise); bool AODown=(AOColorSignal(symbol)==down); //-- if(AORValue && AORise) ret=rise; if(AODValue && AODown) ret=down; //-- return(ret); //--- } //-end AOSignal() //---------//
Die Funktion GetIndiSignals() addiert die Rückgabewerte der Funktion ZigZagSignal() und der Funktion AOSignal():
int MCEA::GetIndiSignals(const string symbol) // Get Signal for Open Position { //--- int ret=0; int rise=1, down=-1; int sigrise=2; int sigdown=-2; //-- int ZZSignal=ZigZagSignal(symbol); int AwSignal=AOSignal(symbol); //Print(symbol+" = ZZ="+string(ZZSignal)+" AO="+string(AwSignal)+" Signal="+string(ZZSignal+AwSignal)); //-- if(ZZSignal+AwSignal==sigrise) ret=rise; if(ZZSignal+AwSignal==sigdown) ret=down; //-- return(ret); //--- } //-end GetIndiSignals() //---------//
Die Funktion GetIndiSignals() addiert die Rückgabewerte der Funktion ZigZagSignal() und der Funktion AOSignal:
- Wenn das Ergebnis 2 ist, ist das ein Signal zum Kauf.
- Wenn das Ergebnis -2 ist, ist dies ein Signal zum Verkauf.
4.2. Die Funktion DirectionMove
Die Funktion DirectionMove() ist nützlich, um die Position des Schlusskurses des aktuellen Balkens zu ermitteln, unabhängig davon, ob er über dem Eröffnungskurs (aufwärts) oder unter dem Eröffnungskurs (abwärts) liegt.
int MCEA::DirectionMove(const string symbol,const ENUM_TIMEFRAMES stf) // Bar Price Direction { //--- int ret=0; int rise=1, down=-1; //-- Pips(symbol); double difud=mc_symbol.NormalizePrice(1.5*pip); UpdatePrice(symbol,stf,2); //-- if(CLOSE[0]>OPEN[0]+difud) ret=rise; if(CLOSE[0]<OPEN[0]-difud) ret=down; //-- return(ret); //--- } //-end DirectionMove() //---------//
4.3. Die Funktion PARSAR15()
Die Funktion PARSAR15() ist nützlich, um die Bewegung des ZigZag-Indikators und des AO-Indikators mit dem Parabolic Stop and Reverse System-Indikator (PSAR/iSAR) auf dem M15-Zeitrahmen abzugleichen.
int MCEA::PARSAR15(const string symbol) // formula Parabolic SAR M15 { //--- int ret=0; int rise=1, down=-1; int br=2; //-- double PSAR[]; ArrayResize(PSAR,br,br); ArraySetAsSeries(PSAR,true); int xx=PairsIdxArray(symbol); CopyBuffer(hPar15[xx],0,0,br,PSAR); //-- UpdatePrice(symbol,TFT15,br); //-- if(PSAR[0]<LOW[0]) ret=rise; if(PSAR[0]>HIGH[0]) ret=down; //-- return(ret); //--- } //-end PARSAR15() //---------//
Nach Ausführung der 3 Hauptsignalfunktionen und mehrerer unterstützender Funktionen liefert die Funktion GetOpenPosition() die Werte:
- Wert = 0 ist kein Signal.
- Wert = 1 ist ein Kaufsignal.
- Wert = -1 ist ein Verkaufssignal.
Wenn die Funktion GetOpenPosition() den Wert 1 zurückgibt, ruft der Expert Advisor die Funktion OpenBuy() auf, um eine Kauforder zu eröffnen.
bool MCEA::OpenBuy(const string symbol) { //--- ResetLastError(); //-- bool buyopen = false; string ldComm = GetCommentForOrder()+"_Buy"; double ldLot = MLots(symbol); ENUM_ORDER_TYPE type_req = ORDER_TYPE_BUY; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- structure is set to zero ZeroMemory(req); ZeroMemory(res); ZeroMemory(check); //-- CurrentSymbolSet(symbol); double SL=OrderSLSet(symbol,type_req,mc_symbol.Bid()); double TP=OrderTPSet(symbol,type_req,mc_symbol.Ask()); //-- if(RefreshTick(symbol)) buyopen=mc_trade.Buy(ldLot,symbol,mc_symbol.Ask(),SL,TP,ldComm); //-- int error=GetLastError(); if(buyopen||error==0) { string bsopen="Open BUY Order for "+symbol+" ~ Ticket= ["+(string)mc_trade.ResultOrder()+"] successfully..!"; Do_Alerts(symbol,bsopen); } else { mc_trade.CheckResult(check); Do_Alerts(Symbol(),"Open BUY order for "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); return(false); } //-- return(buyopen); //-- //--- } //-end OpenBuy //---------//
Wenn die Funktion GetOpenPosition() den Wert -1 zurückgibt, ruft der Expert Advisor die Funktion OpenSell() auf, um eine Verkaufsorder zu eröffnen.
bool MCEA::OpenSell(const string symbol) { //--- ResetLastError(); //-- bool selopen = false; string sdComm = GetCommentForOrder()+"_Sell"; double sdLot = MLots(symbol); ENUM_ORDER_TYPE type_req = ORDER_TYPE_SELL; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- structure is set to zero ZeroMemory(req); ZeroMemory(res); ZeroMemory(check); //-- CurrentSymbolSet(symbol); double SL=OrderSLSet(symbol,type_req,mc_symbol.Ask()); double TP=OrderTPSet(symbol,type_req,mc_symbol.Bid()); //-- if(RefreshTick(symbol)) selopen=mc_trade.Sell(sdLot,symbol,mc_symbol.Bid(),SL,TP,sdComm); //-- int error=GetLastError(); if(selopen||error==0) { string bsopen="Open SELL Order for "+symbol+" ~ Ticket= ["+(string)mc_trade.ResultOrder()+"] successfully..!"; Do_Alerts(symbol,bsopen); } else { mc_trade.CheckResult(check); Do_Alerts(Symbol(),"Open SELL order for "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); return(false); } //-- return(selopen); //-- //--- } //-end OpenSell //---------//
5. Die Funktion ChartEvent
Um die Effektivität und Effizienz bei der Verwendung von Multi-Currency Expert Advisors zu unterstützen, wird es als notwendig erachtet, eine oder mehrere manuelle Schaltflächen für die Verwaltung von Aufträgen und die Änderung von Charts, Zeitrahmen oder Symbolen zu erstellen.
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- //--- handling CHARTEVENT_CLICK event ("Clicking the chart") ResetLastError(); //-- ENUM_TIMEFRAMES CCS=mc.TFt; //-- if(id==CHARTEVENT_OBJECT_CLICK) { int lensymbol=StringLen(Symbol()); int lensparam=StringLen(sparam); //-- //--- if "Set SL All Orders" button is click if(sparam=="Set SL/TP All Orders") { mc.SetSLTPOrders(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Set SL/TP All Orders"); //--- unpress the button ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_STATE,false); ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "Close All Order" button is click if(sparam=="Close All Order") { mc.CloseAllOrders(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Orders"); //--- unpress the button ObjectSetInteger(0,"Close All Order",OBJPROP_STATE,false); ObjectSetInteger(0,"Close All Order",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "Close All Profit" button is click if(sparam=="Close All Profit") { mc.ManualCloseAllProfit(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Profit"); //--- unpress the button ObjectSetInteger(0,"Close All Profit",OBJPROP_STATE,false); ObjectSetInteger(0,"Close All Profit",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "X" button is click if(sparam=="X") { ObjectsDeleteAll(0,0,OBJ_BUTTON); ObjectsDeleteAll(0,0,OBJ_LABEL); ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL); //--- unpress the button ObjectSetInteger(0,"X",OBJPROP_STATE,false); ObjectSetInteger(0,"X",OBJPROP_ZORDER,0); //-- DeleteButtonX(); mc.PanelExtra=false; DisplayManualButton(); } //--- if "M" button is click if(sparam=="M") { //--- unpress the button ObjectSetInteger(0,"M",OBJPROP_STATE,false); ObjectSetInteger(0,"M",OBJPROP_ZORDER,0); mc.PanelExtra=true; CreateManualPanel(); } //--- if "C" button is click if(sparam=="C") { //--- unpress the button ObjectSetInteger(0,"C",OBJPROP_STATE,false); ObjectSetInteger(0,"C",OBJPROP_ZORDER,0); mc.PanelExtra=true; CreateSymbolPanel(); } //--- if "R" button is click if(sparam=="R") { Alert("-- "+mc.expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart."); ExpertRemove(); //--- unpress the button ObjectSetInteger(0,"R",OBJPROP_STATE,false); ObjectSetInteger(0,"R",OBJPROP_ZORDER,0); if(!ChartSetSymbolPeriod(0,Symbol(),Period())) ChartSetSymbolPeriod(0,Symbol(),Period()); DeletePanelButton(); ChartRedraw(0); } //--- if Symbol button is click if(lensparam==lensymbol) { int sx=mc.ValidatePairs(sparam); ChangeChartSymbol(mc.AS30[sx],CCS); mc.PanelExtra=false; } //-- } //-- return; //--- } //-end OnChartEvent() //---------//
In der anderen Gruppe der Eingabe-Parameter des Expert Advisors kann der Händler auswählen, ob Handelsinformationen auf dem Chart angezeigt werden sollen (Yes) oder (No).
Wenn diese Option ausgewählt ist (Yes), werden die Handelsinformationen auf dem Chart angezeigt, auf dem der Expert Advisor durch Aufruf der Funktion TradeInfo() läuft.
Wir haben auch eine Funktion hinzugefügt, um die Zeit gemäß den Bedingungen der Handelszeitzone als Teil der Funktion TradeInfo() zu beschreiben.
string MCEA::PosTimeZone(void) { //--- string tzpos=""; //-- if(ReqTime(zntm,day)>ThisTime(day)) { tzpos=tz_opn+ " Next day to " +tz_cls + " Next day"; } else if(TimeCurrent()<znop) { if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)==ReqTime(zncl,day)) tzpos=tz_opn+" to " +tz_cls+ " Today"; //else if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day)) tzpos=tz_opn+ " Today to " +tz_cls+ " Next day"; } else if(TimeCurrent()>=znop && TimeCurrent()<zncl) { if(ThisTime(day)<ReqTime(zncl,day)) tzpos=tz_opn+ " Today to " +tz_cls+ " Next day"; else if(ThisTime(day)==ReqTime(zncl,day)) tzpos=tz_opn+" to " +tz_cls+ " Today"; } else if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day)) { tzpos=tz_opn+" Today to " +tz_cls+ " Next day"; } //-- return(tzpos); //---- } //-end PosTimeZone() //---------//
void MCEA::TradeInfo(void) // function: write comments on the chart { //---- Pips(Symbol()); double spread=SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/xpip; rem=zntm-TimeCurrent(); string postime=PosTimeZone(); string eawait=" - Waiting for active time..!"; //-- string comm=""; TodayOrders(); //-- comm="\n :: Server Date Time : "+string(ThisTime(year))+"."+string(ThisTime(mon))+"."+string(ThisTime(day))+ " "+TimeToString(TimeCurrent(),TIME_SECONDS)+ "\n ------------------------------------------------------------"+ "\n :: Broker : "+ TerminalInfoString(TERMINAL_COMPANY)+ "\n :: Expert Name : "+ expname+ "\n :: Acc. Name : "+ mc_account.Name()+ "\n :: Acc. Number : "+ (string)mc_account.Login()+ "\n :: Acc. TradeMode : "+ AccountMode()+ "\n :: Acc. Leverage : 1 : "+ (string)mc_account.Leverage()+ "\n :: Acc. Equity : "+ DoubleToString(mc_account.Equity(),2)+ "\n :: Margin Mode : "+ (string)mc_account.MarginModeDescription()+ "\n :: Magic Number : "+ string(magicEA)+ "\n :: Trade on TF : "+ EnumToString(TFt)+ "\n :: Today Trading : "+ TradingDay()+" : "+hariini+ "\n :: Trading Session : "+ tz_ses+ "\n :: Trading Time : "+ postime; if(TimeCurrent()<zntm) { comm=comm+ "\n :: Time Remaining : "+(string)ReqTime(rem,hour)+":"+(string)ReqTime(rem,min)+":"+(string)ReqTime(rem,sec) + eawait; } comm=comm+ "\n ------------------------------------------------------------"+ "\n :: Trading Pairs : "+pairs+ "\n :: BUY Market : "+string(oBm)+ "\n :: SELL Market : "+string(oSm)+ "\n :: Total Order : "+string(oBm+oSm)+ "\n :: Order Profit : "+DoubleToString(floatprofit,2)+ "\n :: Fixed Profit : "+DoubleToString(fixclprofit,2)+ "\n :: Float Money : "+DoubleToString(floatprofit,2)+ "\n :: Nett Profit : "+DoubleToString(floatprofit+fixclprofit,2); //-- Comment(comm); ChartRedraw(0); return; //---- } //-end TradeInfo() //---------//
Die Schnittstelle des Multi-Currency Expert Advisor ZigZag_AO_MCEA sieht dann wie folgt aus.
Wie Sie sehen können, befinden sich unter dem Namen des Expert Advisors ZigZag_AO_MCEA die Schaltflächen „M“, „C“ und „R“.
Wenn Sie auf die Schaltfläche „M“ klicken, wird ein Feld mit Schaltflächen zum manuellen Klicken angezeigt (siehe unten).
Der Händler kann Aufträge manuell verwalten, wenn die Schaltfläche für manuelle Klicks angezeigt wird:
5.1. Set SL/TP All Orders (SL/TP für alle Aufträge einstellen)
Wie oben erklärt, wenn der Händler die Parameter Use Order Stop Loss (No) und/oder Use Order Take Profit (No) eingibt, dann aber Stop Loss oder Take Profit auf alle Aufträge anwenden möchte, dann wird ein einziger Klick auf die Schaltfläche „Set SL / TP All Orders“ alle Aufträge ändern und Stop Loss und/oder Take Profit anwenden.
void MCEA::SetSLTPOrders(void) { //--- ResetLastError(); MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- double modbuysl=0; double modselsl=0; double modbuytp=0; double modseltp=0; string position_symbol; int totalorder=PositionsTotal(); //-- for(int i=totalorder-1; i>=0; i--) { string symbol=PositionGetSymbol(i); position_symbol=symbol; if(mc_position.Magic()==magicEA) { ENUM_POSITION_TYPE opstype = mc_position.PositionType(); if(opstype==POSITION_TYPE_BUY) { Pips(symbol); RefreshTick(symbol); double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_take = mc_position.TakeProfit(); modbuysl=SetOrderSL(symbol,opstype,pos_open); if(price<modbuysl) modbuysl=mc_symbol.NormalizePrice(price-slip*pip); modbuytp=SetOrderTP(symbol,opstype,pos_open); if(price>modbuytp) modbuytp=mc_symbol.NormalizePrice(price+slip*pip); //-- if(pos_stop==0.0 || pos_take==0.0) { if(!mc_trade.PositionModify(position_symbol,modbuysl,modbuytp)) { mc_trade.CheckResult(check); Do_Alerts(symbol,"Set SL and TP for "+EnumToString(opstype)+" on "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); } } } if(opstype==POSITION_TYPE_SELL) { Pips(symbol); RefreshTick(symbol); double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_take = mc_position.TakeProfit(); modselsl=SetOrderSL(symbol,opstype,pos_open); if(price>modselsl) modselsl=mc_symbol.NormalizePrice(price+slip*pip); modseltp=SetOrderTP(symbol,opstype,pos_open); if(price<modseltp) modseltp=mc_symbol.NormalizePrice(price-slip*pip); //-- if(pos_stop==0.0 || pos_take==0.0) { if(!mc_trade.PositionModify(position_symbol,modselsl,modseltp)) { mc_trade.CheckResult(check); Do_Alerts(symbol,"Set SL and TP for "+EnumToString(opstype)+" on "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); } } } } } //-- return; //--- } //-end SetSLTPOrders //---------//
5.2. Close All Orders (Alle Aufträge schließen)
Wenn ein Händler alle Positionen schließen möchte, genügt ein einziger Klick auf die Schaltfläche „Close All Orders“, um alle offenen Aufträge zu schließen.
void MCEA::CloseAllOrders(void) //-- function: close all order { //---- ResetLastError(); //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int total=PositionsTotal(); // number of open positions //--- iterate over all open positions for(int i=total-1; i>=0; i--) { //--- if the MagicNumber matches if(mc_position.Magic()==magicEA) { //-- string position_Symbol = PositionGetSymbol(i); // symbol of the position ulong position_ticket = PositionGetTicket(i); // ticket of the the opposite position ENUM_POSITION_TYPE type = mc_position.PositionType(); RefreshTick(position_Symbol); bool closepos = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); //--- } } //--- return; //---- } //-end CloseAllOrders() //---------//
5.3. Close All Profits (Alle Positionen im Gewinn schließen)
Wenn ein Händler alle bereits profitablen Positionen schließen möchte, genügt ein einziger Klick auf die Schaltfläche „Close All Profits“, um alle offenen Positionen, die bereits profitabel sind, zu schließen.
bool MCEA::ManualCloseAllProfit(void) { //---- ResetLastError(); //-- bool orclose=false; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int ttlorder=PositionsTotal(); // number of open positions //-- for(int x=0; x<arrsymbx; x++) { string symbol=DIRI[x]; orclose=false; //-- for(int i=ttlorder-1; i>=0; i--) { string position_Symbol = PositionGetSymbol(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { double pos_profit = mc_position.Profit(); double pos_swap = mc_position.Swap(); double pos_comm = mc_position.Commission(); double cur_profit = NormalizeDouble(pos_profit+pos_swap+pos_comm,2); ulong position_ticket = PositionGetTicket(i); //--- if(type==POSITION_TYPE_BUY && cur_profit>0.02) { RefreshTick(position_Symbol); orclose = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); } if(type==POSITION_TYPE_SELL && cur_profit>0.02) { RefreshTick(position_Symbol); orclose = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); } } } } //-- return(orclose); //---- } //-end ManualCloseAllProfit() //---------//
Wenn Sie auf die Schaltfläche C klicken, wird eine Schaltfläche mit 30 Symbolnamen oder -paaren angezeigt, und die Händler können auf einen der Paarnamen oder Symbolnamen klicken.
Wenn Sie auf einen der Paar- oder Symbolnamen klicken, wird das Chartsymbol sofort durch das Symbol ersetzt, auf dessen Namen Sie geklickt haben.
void CreateSymbolPanel() { //--- //-- ResetLastError(); DeletePanelButton(); int sydis=83; int tsatu=int(mc.sall/2); //-- CreateButtonTemplate(0,"Template",180,367,STYLE_SOLID,5,BORDER_RAISED,clrYellow,clrBurlyWood,clrWhite,CORNER_RIGHT_UPPER,187,45,true); CreateButtonTemplate(0,"TempCCS",167,25,STYLE_SOLID,5,BORDER_RAISED,clrYellow,clrBlue,clrWhite,CORNER_RIGHT_UPPER,181,50,true); CreateButtonClick(0,"X",14,14,"Arial Black",10,BORDER_FLAT,"X",clrWhite,clrWhite,clrRed,ANCHOR_CENTER,CORNER_RIGHT_UPPER,22,48,true,"Close Symbol Panel"); //-- string chsym="Change SYMBOL"; int cspos=int(181/2)+int(StringLen(chsym)/2); CreateButtontLable(0,"CCS","Bodoni MT Black",chsym,11,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,cspos,62,true,"Change Chart Symbol"); //-- for(int i=0; i<tsatu; i++) CreateButtonClick(0,mc.AS30[i],80,17,"Bodoni MT Black",8,BORDER_RAISED,mc.AS30[i],clrYellow,clrBlue,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,180,sydis+(i*22),true,"Change to "+mc.AS30[i]); //-- for(int i=tsatu; i<mc.sall; i++) CreateButtonClick(0,mc.AS30[i],80,17,"Bodoni MT Black",8,BORDER_RAISED,mc.AS30[i],clrYellow,clrBlue,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,94,sydis+((i-tsatu)*22),true,"Change to "+mc.AS30[i]); //-- ChartRedraw(0); //-- return; //--- } //-end CreateSymbolPanel() //---------//
In diesem Fall wird die Funktion OnChartEvent() die Funktion ChangeChartSymbol() aufrufen, wenn einer der Symbolnamen angeklickt wird.
if(id==CHARTEVENT_OBJECT_CLICK) { int lensymbol=StringLen(Symbol()); int lensparam=StringLen(sparam); //--- if Symbol button is click if(lensparam==lensymbol) { int sx=mc.ValidatePairs(sparam); ChangeChartSymbol(mc.AS30[sx],CCS); mc.PanelExtra=false; } //-- }
void ChangeChartSymbol(string c_symbol,ENUM_TIMEFRAMES cstf) { //--- //--- unpress the button ObjectSetInteger(0,c_symbol,OBJPROP_STATE,false); ObjectSetInteger(0,c_symbol,OBJPROP_ZORDER,0); ObjectsDeleteAll(0,0,OBJ_BUTTON); ObjectsDeleteAll(0,0,OBJ_LABEL); ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL); //-- ChartSetSymbolPeriod(0,c_symbol,cstf); //-- ChartRedraw(0); //-- return; //--- } //-end ChangeChartSymbol() //---------//
Wenn Sie schließlich auf die Schaltfläche R klicken, wird der Multi-Currency Expert Advisor ZigZag_AO_MCEA aus dem Diagramm entfernt, sodass die Händler die Experten nicht manuell entfernen müssen.
if(id==CHARTEVENT_OBJECT_CLICK) { //-- //--- if "R" button is click if(sparam=="R") { Alert("-- "+mc.expname+" -- ",Symbol()," -- Expert Advisor will be Remove from the chart."); ExpertRemove(); //--- unpress the button ObjectSetInteger(0,"R",OBJPROP_STATE,false); ObjectSetInteger(0,"R",OBJPROP_ZORDER,0); if(!ChartSetSymbolPeriod(0,Symbol(),Period())) ChartSetSymbolPeriod(0,Symbol(),Period()); DeletePanelButton(); ChartRedraw(0); } //--- }
Strategietester
Der Vorteil des MetaTrader 5 Strategy Testers ist, dass er Strategien unterstützt, die auf mehreren Symbolen handeln oder den automatischen Handel für alle verfügbaren Symbole und auf allen verfügbaren Zeitrahmen testen. Daher werden wir auf der MetaTrader 5 Strategy Tester Plattform den ZigZag_AO_MCEA Multi-Currency Expert Advisor testen.
Im Test haben wir den ZigZag_AO_MCEA auf das Paar XAUUSD und den H4-Zeitrahmen gelegt, mit einer nutzerdefinierten Zeitspanne von 2023.10.01 bis 2024.02.17.
Die Ergebnisse sind in den folgenden Abbildungen dargestellt.
Schlussfolgerung
Die Schlussfolgerung bei der Erstellung eines Multi-Currency Expert Advisor mit Signalen aus dem ZigZag-Indikator, die mit dem Awesome Oscillator gefiltert werden oder sich gegenseitig die Signale für den Forex-Handel mit MQL5 filtern, lautet wie folgt:
- Es stellt sich heraus, dass die Erstellung eines Expert Advisor für mehrere Währungen in MQL5 sehr einfach ist und sich nicht wesentlich von der Erstellung eines Einzelwährungs-Expertenberaters unterscheidet, wobei der Multiwährungs-Expertenberater auch als Einzelwährungs-Expertenberater verwendet werden kann.
- Die Erstellung eines Multiwährungs Expert Advisors erhöht die Effizienz und Effektivität von Händlern, da sie nicht mehr viele Chart-Symbole für den Handel öffnen müssen.
- Die Anwendung der richtigen Handelsstrategie erhöht die Gewinnwahrscheinlichkeit im Vergleich zur Verwendung eines Expert Advisors für eine einzige Währung. Das liegt daran, dass Verluste in einem Paar durch Gewinne in anderen Paaren ausgeglichen werden.
- Dieser ZigZag_AO_MCEA Multi-Currency Expert Advisor ist nur ein Beispiel zum Lernen und zur Ideenfindung. Die Testergebnisse des Strategietesters sind immer noch nicht gut. Daher ist es möglich, durch Experimentieren und Testen mit verschiedenen Zeitrahmen oder verschiedenen Indikatorperioden und verschiedenen ausgewählten Signalen eine bessere Strategie und profitablere Ergebnisse zu erzielen.
- Meiner Meinung nach sollte diese ZigZag mit AO-Indikatoren Strategie mit verschiedenen Experimenten weiter erforscht werden, ausgehend von Zeitrahmen, Differenzierung Wert des ZigZag-Indikator-Parameter-Eingang, und vielleicht können Sie auch andere Algorithmus-Signale für den ZigZag-Indikator und AO-Indikator hinzufügen.
- Basierend auf den Ergebnissen meiner Experimente auf Strategy Tester, auf Zeitrahmen unter H1 die Ergebnisse sind nicht gut, nur auf Zeitrahmen H1 und darüber, die Ergebnisse sind gut mit wenigen offenen Trades, im Vergleich zu kleinen Zeitrahmen mit vielen offenen Trades, aber in Verlust.
Danke fürs Lesen.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/14329





- 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.