Jump to content
Tom Next - Daytrading Community

Analyse MT4 Tutorial Code


claudia m

Recommended Posts

Hallo an alle,

Ich habe mir die Tutorials von Daxsignal angeschaut und den kostenlosen Code aus dem Tutorial2 von der Seite kopiert.

Ich bekomme das ganze nur nicht zum laufen. Wenn ich den Code komplett kopiere und abspeichere kommen beim Backtest nur fehler 2016.01.18 16:52:12.307 2016.01.17 23:59 test GER30,M5: Error opening BUY order : 1319445 oder das gleiche mit SELL.

Im Live betrieb Demokonto das gleiche.

Ich nutze Metatrader4 Build 950 bei IG

Kann es sein das man den Code umschreiben muss weil er in der vorgänger version Bulid "unter 600" geschrieben wurde?
Kann mir bitte jemand weiterhelfen zu verstehen wo der fehler liegt?

Vorab vielen Dank

MfG

Link to comment
Share on other sites

Danke für das Willkommen und Hilfsbereitschaft

Ich denke da hast Du recht an die "Quelle" zu gehen.

Gestern hat mir der kopf geraucht beim versuch den Code aus dem Tutorial zu verstehen.

Erst habe ich den EA garnicht zum laufen gebracht und den Coder angeschrieben, nicht einmal er wusste warum es nicht läuft

und mich leider noch mehr verwirrt mit irgendwelchen punkten.

Irgendwie habe ich dann bemerkt das Stop Limit in GER30 100 ist aber im Code auf 20 festgesetzt.

Nach dem rumgefummele ging es dann aber logisch ist mir da nichts bei dem EA.

Seiner Erklärung nach müsste der EA kaufen wenn die Linie vom Moving Averige steigt und dann verkaufen wenn sie sinkt.

Das macht es aber nicht und ich verstehe leider nicht warum

Link to comment
Share on other sites

Hi,

 

bzgl. dem Stoplimit etc.: das Errorhandling bzw. einhaltung der diversen limits (auch lotsize etc.) ist ein etwas größeres Thema in MT4. Wir haben zu dem Thema einmal die TradeBox gebaut, die das ganze kapselt. Der Code ist für Anfänger vielleicht etwas heftiger Tobak, aber der Nutzen sicher recht hoch.

 

Nochmal die Frage: willst du den Code des Tutorials verstehen oder an einer eigenen Idee basteln? Hat beides seine Berechtigung. Falls es ums verstehen des Tutorialcodes geht, dann sollten wir uns den Code hier im Detail anschauen. ich weiß nicht wie es mit dem copyright aussieht. Du könntest einfach mal den direkten Link posten, damit jeder im Thread auf dem gleichen Stand ist, und dann "zerlegen" wir den Code gemeinsam in die Einzelteile. In dem Fall würde ich die Posts dann in einen eigenen Thread auslagern.

 

Falls es direkt um die eigene Idee geht, machen wir am Besten auch einen neuen Thread auf. Aber jetzt liegt die Entscheidung mal bei dir, was darfs sein?

  • Upvote 1
Link to comment
Share on other sites

Hi Mythos,

 

vielen Dank für die ausführliche Antwort. Ich würde zum einen gerne den Code verstehen, weil das ja die Basis ist. Und dann gerne eine eigene Idee umsetzen.

http://daxsignal.de/tutorial2.mq4

Der Code ist zwar für jedermann frei zum downloaden, da ich aber auch nicht weiß, wie es mit dem Copyright aussieht, hier nur der Link.

Ein gemeinsames "zerlegen" wäre echt super bye2.gif

Da ich arbeite, habe ich leider nur Abends Zeit und davon wenig... Vielleicht könnte man das an einem Wochenende machen oder in ein paar Tagen, da habe ich für längere Zeit frei.

Link to comment
Share on other sites

Hi,

 

der Vorteil vom Forum ist ja, das jeder Schreiben kann wann er Zeit hat, es müssen nit alle gleichzeitig on sein ;)

 

Damit es im weiteren Verlauf für alle klar ist: Wir analysieren hier einen Beispielcode von daxsignal.de copyright liegt bei ihm:

 

#property copyright "Luis Lorenzo"
#property link      "http://www.daxsignal.de"

 

Zum EA:

Praktischerweise ist alles in der start()-Funktion zusammengefasst. Und dort mit Kommentaren in Blöcke unterteilt:

  • Signale ermitteln
  • Einstiegsmarken, Kursziel und Stopp ermitteln
  • Prüfen ob Order oder Pos geöffnet sind
  • Order aufgeben

Ich würde sagen wir gehen es einfach Punkt für Punkt durch. Sicher auch für die stillen Mitleser interessant.

  • Upvote 2
Link to comment
Share on other sites

Punkt 1: Signale ermitteln

 

Zuerst wird mittels der eingebauten Funktion iMA der gleitende Durchschnitt (MODE_SMA) auf das Close (PRICE_CLOSE) der letzten 20 Bars des aktuellen Symbols (erster Parameter = NULL) im aktuellen Timeframe (zweiter Parameter = 0) berechnet.

Hier ist zu beachten das der shift (letzter Parameter) 0 ist, somit wird auch immer der aktuellste Bar mit berücksichtigt. Da sich dieser noch ändert, kann es leicht passieren das ein Signal mitten im Bar existiert (und eine Order auslöst) aber am Ende im Backtest nicht mehr nachvollziehbar ist.

double ma = iMA(NULL,0,20,0,MODE_SMA,PRICE_CLOSE,0);    
Nun wird überprüft ob der Close des letzten Bars über oder unter diesem Mittelwert liegt. Liegt er darüber -> Longsignal, darunter -> Short.

Im Gegensatz zum MA wird hier der aktuellste Bar nicht berücksichtigt, sondern das Close des letzten vollendeten Bars genommen.

if(Close[1]> ma)  {   
  signal = "long";
} 
   
if(Close[1]<ma)   {   
  signal = "short";
} 
Die variable "signal" ist global (sprich außerhalb der Funktion deklariert). Das spielt nur in einem sehr speziellen Fall eine Rolle. Bei jedem Aufruf von start() gibt es 2 Fälle:

- Close[1] ist ungleich ma und somit wird signal auf long oder auf short gesetzt.

- In dem seltenen Fall das Close[1] == ma ist, würde signal keinen Wert erhalten. Da es aber global ist, bleibt der Wert vom letzten Aufruf erhalten.

  • Upvote 5
Link to comment
Share on other sites

Punkt 2: Einstiegsmarken, Kursziel und Stopp ermitteln

 

Hier macht der Entwickler etwas, das offensichtlich nur aufgrund der Fehlertoleranz von MQL4 funktioniert (ich wusste gar nicht das das geht). Er deklariert Variablen innerhalb eines if-blocks, und verwendet sie außerhalb weiter. Zusätzlich sind die Kurse in MT4 immer gleitkommazahlen, also vom Datentyp double, nicht int. Auf Märkten mit Pip

 

Korrekterweise müsste der Code so aussehen (die initialisierung auf 0 ist in MT4 nicht zwingend nötig, aber macht den Code mMn lesbarer):

 

double kauf= 0;
double kursziel= 0;
double stoppkurs= 0;   
if (signal == "long") {     
     kauf = Ask;
     kursziel = kauf + Kursziel_in_Punkten;
     stoppkurs = kauf - Stopp_in_Punkten;
}
   
if (signal == "short") {     
     kauf = Bid;
     kursziel = kauf - Kursziel_in_Punkten;
     stoppkurs = kauf + Stopp_in_Punkten;
}

Hier werden die entsprechenden Werte für das erstellen einer Order gesetzt. Je nachdem ob ein long oder short signal vorliegt wird der entsprechende Einstiegspunkt gewählt. Der EA steigt Market ein, somit ist der aktuelle Bid/Ask der Einstiegspunkt. Aufgrund dessen wird dann TP (kursziel) und SL (stoppkurs) berechnet. Hier ist auch zu beachten das Kursziel und Stopp in ganzen Punkten (nicht in Pip) angegeben wird. An der Forex ist sowas natürlich nicht sinnvoll weil eine Stopploss-entfernung von mind. 1.0 bei einem Kurs (zB EURUSD) von 1.09 eher sinnfrei ist ;)

 

Zu beachten ist auch das dieser EA immer ein Signal hat, nicht nur bei einer Kreuzung. Wie mit dem Signal umgegangen wird schauen wir uns im nächsten Block an.

  • Upvote 5
Link to comment
Share on other sites

Punkt 3: Prüfen ob Orders geöffnet:

 

Der Block 2 gibt die aktuelle Richtung vor. Je nachdem ob gerade eine Position offen ist, wird dann in diese Richtung eine neue eröffnet oder nicht. Damit ist immer nur eine Position gleichzeitig offen. Dafür muss man aber erstmal überprüfen ob eine Order offen ist. Und das tut dieser Block.

 

spannenderweise ist die temporäre Variable "zaehler" wiederum global definiert. Müsste sie aber nicht. Korrekterweise muss auch auf das Ergebnis von OrderSelect reagiert werden. Kann die Order nicht selektiert werden, sollte der nächste Index verwendet werden.

Dieser Code macht genau dasselbe:

 

int offeneorders=0;

for(int zaehler=0;zaehler < OrderTotal();zaehler++) {
  if(!OrderSelect(zaehler, SELECT_BY_POS, MODE_TRADES)) {
    continue;
  }
  if (OrderSymbol() == Symbol() && OrderMagicNumber()==MagicNumber) {
    offeneorders++;
  }       
}

Der Index (zaehler) läuft über alle offenen Orders. Zunächst wird mit OrderSelect versucht diese Order zu "selektieren". SELECT_BY_POS bedeutet das zaehler der Index in der Liste der Orders ist. MODE_TRADES das aus den offenen Orders selektiert werden soll.

Passiert hier ein Fehler, so retouniert OrderSelect false und per continue wird zur nächsten Order weitergesprungen.

Danach wird überprüft ob die Order auch wirklich zu diesem EA gehört. Dafür wird einerseits überprüft ob die Order im aktuellen Symbol erzeugt wurde, und ob die MagicNumber zur MagicNumber des EA passt. Falls das alles passt, wird die Variable offeneorders hochgezählt. Im weiteren Verlauf sagt uns diese Variable dann ob gerade eine oder mehrere Orders von diesem EA offen sind oder nicht.

  • Upvote 5
Link to comment
Share on other sites

Punkt 4: Orders aufgeben

 

In diesem Block wird nun eine konkrete Order eröffnet. Hierfür wird auf variablen aus früheren Blöcken zugegriffen:

signal, kauf, kursziel, stoppkurs und offeneorders.

Zur Erinnerung:

signal ist long oder short und gibt die aktuelle richtung vor,

kauf ist der Preis zu dem die neue Order erstellt werden soll,

kursziel der TP,

stoppkurs der SL und

offeneorders sagt uns wieviele Orders der EA gerade offen hat.

if(kauf > 0 && offeneorders == 0 ) {
  if(signal ==  "long" ) {
    ticket=OrderSend(Symbol(),OP_BUY,Lots,kauf,30,stoppkurs,kursziel,"Trend Longorder",MagicNumber,0,Black);
    if(ticket>0) {
      if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) 
        Print("Kauforder geöffnet : ",OrderOpenPrice()); 
    } else 
      Print("Error opening BUY order : ",GetLastError(), kauf); 
    return(0); 
  }
  
  if(signal == "short" ) {
    ticket=OrderSend(Symbol(),OP_SELL,Lots,kauf,30,stoppkurs,kursziel,"Trend Shortorder",MagicNumber,0,Red);
    if(ticket>0) {
      if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
        Print("SELL order opened : ",OrderOpenPrice());
    } else 
      Print("Error opening SELL order : ",GetLastError(), kauf); 
    return(0); 
  }
  return(0);
}   

 

An sich passiert hier nicht viel magisches. Eine neue Order darf nur eröffnet werden wenn der EA gerade keine andere offen hat (damit wird es nie mehr als 1 offene order gleichzeitig geben. Und wenn es einen kaufkurs gibt (Der spezielle Spezialfall in dem diese Bedingung nicht erfüllt ist, ist ne Art spezialaufgabe für die SilentReader ;)

Ist das erfüllt darf/soll also eine Order geöffnet werden. je nach Wert von Signal ist dies eine Kauf Order (OP_BUY) oder Verkauf (OP_SELL). Man beachte das es sich nicht um stop oder limit orders, sondern eine Market Order handelt. Sprich sie soll sofort ausgeführt werden.

 

Die Order soll im aktuellen Symbol (Symbol() ), mit Ordergröße Lots zum Preis "kauf" ausgeführt werden. Dabei ist eine Slippage von 30 erlaubt. Dieser Wert wird in Point angegeben, ist mMn aber sehr hoch.

Für die Order wird gleich der SL und TP mitgegeben. Zusätzlich erhält die Order einen Kommentar und die EA-spezifische MagicNumber.

Da es eine Market-Order ist, ist die Expiration natürlich 0 (nicht gesetzt). Die Farbe des pfeils für die Order im Chart wird noch auf Schwarz bzw. Rot gesetzt. Das ist nur für die Optik.

 

Was auffällt is das minimale Fehlerhandling: Es wird zwar der Rückgabewert von OrderSend entgegen genommen (Die Ticketnummer der Order), aber im Fall eines Fehlers wird dieser nur ausgegeben und nicht darauf reagiert.

Im Erfolgsfall wird eine entsprechende Nachricht mit dem Eröffnungspreis geloggt. Hier sieht man die 2. Variante wie man auf die Orders zugreifen kann: Mit SELECT_BY_TICKET und übergabe der Ticketnummer.

 

Welche Fehler können beim Senden einer Order auftreten, im speziellen: welche Fehler werden hier sehr wahrscheinlich auftreten?

  • Falsche Stoplevel
    In MT4 definiert jeder Broker einen gewissen Mindestabstand den Stops/Limits, SL und TP vom aktuellen Kurs/Eröffnungskurs haben müssen. ist jetzt der SL oder TP zu nahe beim Eröffnungskurs gibt OrderSend einen Error retour
  • Falsche Lotsize.
    Die Lotsize muss zwischen LOT_MIN und LOT_MAX sein und ein Vielfaches von LOT_STEP sein. Ist dies nicht erfüllt gibt OrderSend erneut einen Fehler.
  • Falscher Preis bei MarketOrder
    Im Fall einer MarketOrder muss der Preis dem aktuellen Bid/Ask vom Server entsprechen. Versucht man eine Order mit einem veralteten/falschen Preis zu eröffnen erhält man ERR_REQUOTE.

Zu guter letzt wird die start() Funktion hier vorzeitig beendet falls versucht wurde eine Order abzusetzen. Im Endeffekt würde das dritte return(0) reichen, die anderen zwei sind in dem Fall redundant.

  • Upvote 4
Link to comment
Share on other sites

Punkt 5: Offene Positionen bei Signalwechsel schliessen

 

Der EA öffnet nur Positionen wenn gerade keine andere offen ist. Eine Position wird natürlich automatisch geschlossen wenn der TP oder SL erreicht ist. Zusätzlich wird nun in diesem Block nach einer einfachen Regel die Order ggf. geschlossen wenn das signal dreht.

 

for(int zaehler=0;zaehler<OrdersTotal();zaehler++) {
      if(OrderSelect(zaehler,SELECT_BY_POS,MODE_TRADES)==false)        break;
      
      if(OrderType()==OP_BUY && OrderMagicNumber() == MagicNumber && OrderSymbol()== Symbol() ) {
         if(Close[1]<ma)
           OrderClose(OrderTicket(),OrderLots(),Bid,3,White);
         break;
      }
      if(OrderType()==OP_SELL) {
         if(Close[1]>ma) 
           OrderClose(OrderTicket(),OrderLots(),Ask,3,White);
         break;
     }
}

Diesmal wird sogar auf das Ergebnis von OrderSelect reagiert. Ansonsten ist der Code hier leider voll von Fehlern, deswegen schauen wir kurz was er vermutlich tun sollte:

Grundsätzlich läuft der Code wieder über alle aktiven Orders, gehört die Order dem EA (MagicNumber und Symbol stimmen) wird überprüft ob es eine Long oder Short Order ist (OrderTyp() == OP_BUY bzw. OP_SELL). Dann wird erneut die Signalbedingung von Block 1 überprüft. Ist das Signal gegenläufig zur Orderrichtung, dann wird die Order geschlossen.

 

Was läuft falsch:

  • Die Überprüfung ob die Order überhaupt dem EA gehört, geschieht nur bei OP_BUY. Ist es eine Sell Order ist dem EA egal ob sie ihm gehört oder nicht, er schließt sie ggf. einfach.
  • Nicht direkt ein Fehler aber sehr unschön: Anstatt den Wert von signal zu verwenden, wird die Bedingung erneut überprüft. Wird nun die Berechnung des Signals in Block 1 geändert, passt es nicht mehr mit dem Ausstieg zusammen.
  • Es wird nicht auf den Rückgabewert von OrderClose reagiert. Aber Errorhandling bei den Order-Methoden ist zugegebenermaßen ein komplexes Thema und darf in einem einfachen Tutorial durchaus ignoriert werden.
  • Ist eine Order gefunden, wird die Schleife beendet. Das funktioniert solange nur eine Order gleichzeitig offen ist. Aber der Kommentar suggeriert das "alle" geschlossen werden sollen. Wird also die Logik oben geändert sodass mehrere Positionen offen sein können, dann tut dieser Block nicht mehr was er soll. Da bei der Sell Order nicht auf die zugehörigkeit zum EA überprüft wird, funktioniert es schon nicht mehr, wenn parallel eine andere sell-order offen ist. Sowas ist richtig tötlich weil man es im Backtest nicht merkt, sondern erst wenn man (womöglich bereits auf live) mehrere EAs gleichzeitig laufen hat.

mMn sollte der Code so aussehen damit er zumindest im wesentlichen tut was er soll: (immer noch ohne Errorhandling)

for(int zaehler=OrdersTotal()-1;zaehler>=0;zaehler--)
     {
       if(OrderSelect(zaehler,SELECT_BY_POS,MODE_TRADES)==false)
         continue;
      if(OrderMagicNumber() != MagicNumber || OrderSymbol() != Symbol()) 
        continue;
         
      if(OrderType()==OP_BUY && signal == "short") 
           OrderClose(OrderTicket(),OrderLots(),Bid,3,White);
        
      if(OrderType()==OP_SELL && signal == "long") 
           OrderClose(OrderTicket(),OrderLots(),Ask,3,White);
      
     }

 

So, damit wär ich mit dem Code durch. Irgendwelche Fragen?

 

@claudia: kannst du mit den Infos schon vermuten wieso er sich so verhält wenn die Periode auf 1 gestellt wird?

  • Upvote 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...