English Русский 中文 Español 日本語 Português
TradeObjects: die Automatisierung des Handels aufgrund der graphischen Objekte in MetaTrader

TradeObjects: die Automatisierung des Handels aufgrund der graphischen Objekte in MetaTrader

MetaTrader 5Tester | 1 September 2017, 14:59
1 170 0
Stanislav Korotky
Stanislav Korotky
Die geometrischen Konstruktionen auf Charts der Notierungen — ist seit Jahrzehnten ein populärstes Instrument der Traders. Mit der Entwicklung der Technologien wird es immer einfacher die Linien Unterstützung oder Widerstands, die historischen Ebenen der Preise und ganze Figuren — zum Beispiel, die Kanäle und das Netz Fibonacci zu entwerfen. Die Software für ein algorithmisches Trading ermöglicht nicht nur klassischen Figuren zu analysieren, sondern auch auf ihrer Grundlage zu handeln. Für MetaTrader wurden auch die Programme entwickelt, die den Prozess mehr oder weniger automatisieren: es ist genug, das Objekt zum Chart mit einem gestarteten Experten oder Skript hinzuzufügen, und das Programm wird weiter selbst eine Position zum nötigen Moment öffnen, wird sie kontrollieren und schließt entsprechend den Einstellungen. Mit Hilfe von eine solchen Software kann man nicht nur online handeln, sondern auch seine Fähigkeiten im Tester im Visualisierungsmodus trainieren. Die ähnlichen Programme wurden auch in der Bibliothek der Quellcodes, und im Market der Gesellschaft der Trader angeboten.

Aber es ist nicht alles so perfekt. In der Regel, die Programme in der Bibliothek der Quellcodes haben eine vereinfachte Funktional und werden selten erneuert und deshalb sind oft alt (bis zum Verlust der Vereinbarkeit mit den letzten Versionen der Sprache MQL und des Terminales), und die kommerziellen Produkte können sich nicht alle leisten.

In diesem Artikel werden wir versuchen, das neue Instrument zu entwickeln, das die goldene Mitte anbietet. Er wird maximal einfach sein und dabei wird ziemlich ausreichenden Möglichkeiten anbieten. Er wird sowohl mit MetaTrader 4, als auch mit MetaTrader 5 vereinbar sein. Und dank einem offenen Quellcode, kann man ihn bei Bedarf leicht verbreiten und nach dem Wunsch modifizieren.

Die Unterstützung MetaTrader 4 ist nicht nur wegen dem Ziel wichtig, möglichst viele Menschen anzulocken, die immer noch diese Version benutzen, sondern auch wegen einiger Beschränkungen des Testers MetaTrader 5. Insbesondere ermöglicht momentan der visuelle Tester MetaTrader 5 mit den Objekten interaktiv zu arbeiten (hinzufügen, entfernen, Eigenschaften editieren), was für das gegebene Instrument nötig ist. Deshalb kann man seine Fähigkeiten nach der Verwaltung der Objekte auf der History nur im Tester MetaTrader 4 verbessern.

Die Leistung der Forderungen

Die ideologische Hauptforderung für unser System des automatischen Handels nach den graphischen Objekten — ist die Einfachheit. Wir werden ein Standard-Interface eines Benutzers MetaTrader verwenden, auch verwenden wir eine Eigenschaft der graphischen Objekte, ohne spezielle Felder und ohne komplizierte Logik der Einstellungen. Wie uns die Praxis vorführt, werden oft alle Vorteile der reichenden Systemoptionen von den Schwierigkeiten der Aneignung und der kleinen Nachfrage jedes konkreten Modus ihres Betriebes ausgeglichen. Wir werden versuchen, nur die allgemein bekannten Arbeitsverfahren mit den Objekten und die intuitiv klare Interpretation ihrer Eigenschaften zu verwenden.

Um die Entscheidungen beim Handel zu treffen, verwendet man unter einer Menge der Typen der graphischen Objekte meistens:

  • eine Trend-Linie;
  • eine horizontale Linie;
  • eine senkrechte Linie;
  • ein gleich entfernter Kanal;
  • die Fibonacci-Linien.

Eben für sie werden wir eine Unterstützung in erster Linie gewährleisten. Diese Liste könnte man mit den neuen Typen, die in MetaTrader 5 verfügbar sind, verbreiten, aber es wird die Vereinbarkeit mit MetaTrader 4 verletzen. Zugleich, aufgrund der grundlegenden Bearbeitungsprinzipien der Objekte, die im gegebenen Projekt realisiert wurden, können die Benutzer leicht andere Objekte nach ihren Wünschen hinzufügen.

Jedes der oben angeführten Objekte bildet im zweidimensionalen Raum des Charts eine gewisse logische Grenze, von der eine Kreuzung oder ein Sprung ein Signal bedeutet. Seine Interpretation entspricht normalerweise einer der folgenden Situationen:

  • Ein Durchbruch oder ein Sprung von der Linie Unterstützung/Widerstands;
  • Ein Durchbruch oder ein Sprung von der Preis-Ebene;
  • Die Erreichung der gegebenen Ebene von Stop-Loss oder Take-Profit;
  • die vordefinierte Zeit ist herum.

Je nach der gewählten Strategie kann der Trader infolge eines Ereignisses einen Kauf oder einen Verkauf durchführen, einen Pending-Order setzen oder eine vorhandene Position schließen. Das alles muss auch unser System machen können. So wird die Liste der Hauptfunktionen aussehen:

  • Die Versendung der Mitteilungen nach verschiedenen Weisen (Alert, push-Meldung, e-mail);
  • Die Eröffnung der Markt-Orders;
  • Die Setzung der Pendig-Orders (buy stop, sell stop, buy limit, sell limit);
  • Teilweise oder voll wird die offene Position geschlossen, bezüglich auch als Stop-Loss und Take-Profit.

Die Entwicklung des Benutzer-Interface

In vielen ähnlichen Produkten wird das Benutzer-Interface sehr viel Aufmerksamkeit zugeteilt. Felder, Dialoge, Schaltfläche, allgemeine drag'n'drop... Das alles wird in unserem Projekt nicht. Anstatt des speziellen graphischen Interfaces werden wir das benutzen, was MetaTrader standardmäßig gibt.

Jedes Objekt hat einen Standardsatz der Eigenschaften, den man auf eine aktuelle Aufgabe anpassen kann.

Erstens muss man die Objekte, die für einen Autohandel vorgesehen sind, von den übrigen Objekten unterscheiden können, die der Benutzer auf das Charts eintragen kann. Dazu geben wir unseren Objekten einen Namen mit einem vorherbestimmten Präfix. Wenn das Präfix nicht gegeben wird, wird der Experte alle Objekte mit den passenden Eigenschaften wie aktive Objekte annehmen. Aber ein solcher Modus wird nicht empfohlen, da das Terminal seine Objekte erstellen kann (zum Beispiel, die geschlossenen Orders), und sie können Nebeneffekte haben.

Zweitens für die Ausführung der verschiedenen Funktionen (deren Liste oben aufgeführt wurde) reservieren wir verschiedene Gestaltungsstile. Zum Beispiel, in den Einstellungen des Experten werden wir den Stil STYLE_DASH für die Setzung der Pending-Orders eingeben, und STYLE_SOLID — für einen unverzüglichen Eingang in den Markt bei der Kreuzung einer entsprechenden Linie vom Preis. Die Stile der verschiedenen Operationen müssen voneinander unterschiedlich sein.

Drittens muss man die Richtung des Handels bezeichnen. Zum Beispiel für die Käufe kann man die blaue Farbe verwenden, und für die Verkäufe — rot. Die Handlungen, die nicht mit dem Eingang in den Markt und mit Verlassen aus dem Markt zu tun haben, werden wir mit einer dritten Farbe bezeichnen, zum Beispiel - mir Grau. Das ist zum Beispiel, die Mitteilungen oder die Setzung der Pending Orders. Der letzte Fall wurde zu "einer neutralen" Kategorie zugeordnet, weil es oft direkt — ein paar — entgegengesetzte Pending Orders gesetzt werden.

Viertens ist es nötig, den Typ der Pending Orders zu bestimmen. Genau kann man es nach der gegenseitigen Zuneigungen der Order-Linie bezüglich des laufenden Marktpreises und der Farbe der Linie machen. Zum Beispiel, die blaue Linie über dem Preis vermutet buy stop, aber die blaue Linie unter dem Preis — ist schon buy limit.

Endlich fünftens, für die Mehrheit der Operationen ist es nötig, eine gewisse zusätzliche Information, Attribute zu haben. Insbesondere wenn Alert ausgelöst wurde (es können ein paar Alerts sein), so wird der Benutzer wahrscheinlich wollen, eine bedachte Mitteilung zu bekommen. Für dieses Ziel passt gut noch nicht eingesetztes Feld die Beschreibung. Für die Orders in diesem Feld werden wir die Größe des Lotes und die Ablaufzeit bezeichnen. Das alles ist optional, da für die Bequemlichkeit und die Minimierung der nötigen Einstellungen der Objekte im Experten die Eingangsparameter mit den standardmäßigen Werten vorgesehen sind. Außer den Einstellungen der Objekte werden diese standardmäßige Werte auch die Umfänge des Stop-Loss und Take-Profit enthalten.

Falls nach jeder Linie die spezifischen Umfänge des Stop-Loss und Take-Profit gesetzt werden, werden wir die Objekte benutzen, in den einige Linien vereinigt sind. Zum Beispiel, ein gleich entferntes Kanal hat zwei Linien. Die erste von ihnen, die auf zwei Punkten liegt, wird für die Bildung des Handelssignals verantwortlich sein, und die parallele — mit dem dritten Punkt — wird die Entfernung bis zu Stop-Loss oder Take-Profit eingeben. Mit welcher Ebene wir zu tun haben, kann man leicht nach der gegenseitigen Zuneigungen und der Farbe der Linien definieren. Zum Beispiel, für den roten Kanal wird die zusätzliche Linie, die höher der Hauptlinie ist, wird Stop-Loss bilden. Wenn sie niedriger wäre, so würde es wie Take-Profit angenommen.

Wenn man sowohl Stop-Loss als auch Take-Profit eingeben will, muss das Objekt mindestens aus drei Linien bestehen. Dazu passt zum Beispiel, das Netz der Fibonacci-Ebenen. Im Projekt werden standardmäßig die Standart Ebenen 38.2 % (Stop Loss), 61.8 % (der Punkt des Eingangs in den Markt) und 161.8 % (Take Profit) verwendet. Eine noch flexiblere Einstellung dieses und noch komplizierterer Typen der Objekte werden wir im vorliegenden Artikel nicht betrachten.

Bei der Aktivierung dieses oder jenes Objektes infolge der Kreuzung vom Preis muss man das Objekt wie bearbeitendes bezeichnen. Das kann man machen, zum Beispiel, wenn man ihm das Attribut "des Hintergrunds" OBJPROP_BACK setzt. Für die visuelle Rückmeldung mit dem Benutzer werden wir die Anfangsfarbe solcher Objekte einsperren. Zum Beispiel, die blaue Linie wird dunkel-blau nach ihrer Bearbeitung sein.

Jedoch kommen oft unter der Trader-Markierungen so "starken" Linien oder Ebenen vor, dass das mit ihnen verbundenen Ereignis — zum Beispiel, das Schlußsignal von der Linie der Unterstützung bei Korrektionen eines steigenden Trends — oftmals stattfinden kann.

Wir werden solche Situation mit Hilfe von der Dicke der Linie vorhersehen. Wie es bekannt ist, die Stile von MetaTrader ermöglichen die Dicke von 1 bis zu 5 einzugeben. Bei der Aktivierung der Linie werden wir auf ihre Dicke schauen, wenn sie mehr als 1 ist, so anstelle der Ausschaltung aus der weiteren Arbeit werden wir ihre Dicke um 1 verringern. So können wir auf dem Chart die erwarteten mehreren Ereignisse mit der Zahl der Wiederholungen bis zu 5 bezeichnen.

Diese Möglichkeit hat eine Nuance: die Preise in der Regel schwanken um einen Wert, und jede Linie kann oftmals im Laufe einer kleinen Zeit-Periode überquert sein. Der Trader, der manuell handelt, analysiert die Dynamik der Abweichungen des Preises nach Augenmaß und tatsächlich "filtriert" den ganzen Preislärm. Im Experten muss man den Mechanismus realisieren, der das gleiche automatisch macht.

Zu diesem Zweck führen wir die Eingangsparameter ein, die den Umfang "des heißen Bereichs" der Kreuzungen bestimmen, d.h. den minimalen Umfang der Preisbewegung und seine Dauer bestimmen, in deren Grenzen die Signale sich nicht bilden werden. Mit anderen Wörtern, das Ereignis "die Kreuzung der Linie" wird nicht direkt dann stattfinden, wenn der Preis die Linie überqueren wird, sondern nur wenn sie auf die gegebene Entfernung in den Punkten zurücktreten wird.

Auf die gleiche Weise werden wir den Parameter einführen, der das minimale Intervall zwischen zwei nacheinander gehenden Ereignissen mit einer und gleichen Linie eingibt (nur für die Linien, deren Dicke mehr als 1 ist). Hier entsteht die neue Aufgabe: man muss irgendwo die Zeit des vorhergehenden Ereignisses mit der Linie speichern. Wir verwenden dazu die Eigenschaft des Objektes OBJPROP_ZORDER. Diese Zahl ist des Typs long, und der Wert datetime wird dort sehr gut passen. Die Veränderung der Abbildungsreihe der Linien wirkt auf die äußerliche Darstellung des Charts fast gar nicht aus.

In der Benutzer-Interface für die Einstellungen der Linie ist es genug vorgesehen, um mit dem System zu arbeiten:

  • Das Dialogfeld der Eigenschaften des Objektes öffnen;
  • Das gewählte Präfix zum Namen hinzuzufügen;
  • Optional die Parameter in der Beschreibung zu bezeichnen:
    • Das Lot für die Linien der Markt- und Pending-Orders, der teilweise Schließung der Positionen,
    • Die Namen der Linien der Pending Orders für die Linie der Aktivierung der Pending Orders,
    • die Ablaufzeit der Linie des Pending-Orders;
  • Die Farbe als der Indikator der Richtung (standardmäßig blau — der Kauf, rot — der Verkauf, grau — neutral);
  • Der Stil als der Selektor der Operation (Alert, der Eingang in den Markt, die Setzung der Pending Orders, die Schließung der Position);
  • Die Breite als der Indikator der Wiederholung des Ereignisses.

Die Einstellung der Eigenschaften der horizontalen Linie für die Order buy limit (blau strich) mit dem Lot 0.02 und mit der Ablaufzeit 24 Bars (Stunden)

Die Einstellung der Eigenschaften der horizontalen Linie für die Order buy limit (blau strich) mit dem Lot 0.02 und mit der Ablaufzeit 24 Bars (Stunden)

Das Verzeichnis vom System kontrollierten Orders (die den beschriebenen Anforderungen entsprechen) wird im Kommentar auf dem Chart sein, zusammen mit der Detaillierung — der Typ des Objektes, die Beschreibung, der Status.


Die Entwicklung des Mechanismus der Ausführung

Entsprechend den Anforderungen und aus allgemeinen Gründen, die höher beschrieben wurden, werden wir die Realisierung des Experten mit den Eingangsparametern beginnen, in die das Präfix der Namen der Objekte, die bearbeiteten Farben und die Stile, der standardmäßige Wert, sowie die Umfänge der Bereiche, die die Ereignisse auf dem Chart generieren, übergeben.

input int Magic = 0;
input double Lot = 0.01 /*default lot*/;
input int Deviation = 10 /*tolerance to price changes during order execution*/;

input int DefaultTakeProfit = 0 /*points*/;
input int DefaultStopLoss = 0 /*points*/;
input int DefaultExpiration = 0 /*bars*/;

input string CommonPrefit = "exp" /*empty to handle all compatible objects*/;

input color BuyColor = clrBlue /*market and pending buy orders - open, close, sl, tp*/;
input color SellColor = clrRed /*market and pending sell orders - open, close, sl, tp*/;
input color ActivationColor = clrGray /*activation of pending orders placement, alert*/;

input ENUM_LINE_STYLE InstantType = STYLE_SOLID /*opens market trades*/;
input ENUM_LINE_STYLE PendingType = STYLE_DASH /*defines probable pending orders (requires activation)*/;
input ENUM_LINE_STYLE CloseStopLossTakeProfitType = STYLE_DOT /*applied to open positions*/;

input int EventHotSpot = 10 /*points*/;
input int EventTimeSpan = 10 /*seconds*/;
input int EventInterval = 10 /*bars*/;

Den Experten selbst werden wir in Form von der Klasse TradeObjects (die Datei TradeObjects.mq4, er.mq5) gestalten. Öffentlich darin werden nur der Konstrukteur, Destructor und die Methoden der Bearbeitung der Standardereignisse sein.

class TradeObjects
{
  private:
    Expert *e;

  public:
    void handleInit()
    {
      detectLines();
    }
    
    void handleTick()
    {
      #ifdef __MQL4__  
      if(MQLInfoInteger(MQL_TESTER))
      {
        static datetime lastTick = 0;
        if(TimeCurrent() != lastTick)
        {
          handleTimer();
          lastTick = TimeCurrent();
        }
      }
      #endif
    
      e.trailStops();
    }
    
    void handleTimer()
    {
      static int counter = 0;
      
      detectLines();
      
      counter++;
      if(counter == EventTimeSpan) // wait until we have history record of bid for EventTimeSpan
      {
        counter = 0;
        if(PreviousBid > 0) processLines();
        if(PreviousBid != Bid) PreviousBid = Bid;
      }
    }
    
    void handleChart(const int id, const long &lparam, const double &dparam, const string &sparam)
    {
      if(id == CHARTEVENT_OBJECT_CREATE || id == CHARTEVENT_OBJECT_CHANGE)
      {
        if(checkObjectCompliance(sparam))
        {
          if(attachObject(sparam))
          {
            display();
            describe(sparam);
          }
        }
        else
        {
          detectLines();
        }
      }
      else if(id == CHARTEVENT_OBJECT_DELETE)
      {
        if(removeObject(sparam))
        {
          display();
          Print("Line deleted: ", sparam);
        }
      }
    }
    
    TradeObjects()
    {
      e = new Expert(Magic, Lot, Deviation);
    }
    
    ~TradeObjects()
    {
      delete e;
    }
};

Das Exemplar der gegebenen Klasse werden wir statisch erstellen, und dann werden wir seine Ereignissebearbeiter zu den entsprechenden globalen Funktionen verknüpfen.

TradeObjects to;

void OnInit()
{
  ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
  EventSetTimer(1);
  to.handleInit();
}

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
  to.handleChart(id, lparam, dparam, sparam);
}
                 
void OnTimer()
{
  to.handleTimer();
}

void OnTick()
{
  to.handleTick();
}

Alle Handelsoperationen werden wir einem separaten Motor zuordnen, der in der äußerlichen Klasse Expert (die Datei Expert01.mqh) verborgen ist. Wir erstellen sein Exemplar (e) im Konstrukteur und wir entfernen die Klasse TradeObjects im Destructor. Den Motor selbst betrachten wir später noch gründlicher, und solange bemerken wir, dass TradeObjects ihm viele Operationen delegieren wird.

Alle Bearbeiter der Ereignisse handleInit, handleTick, handleTimer, handleChart rufen die Methode detectLines auf, den wir noch schreiben. Darin werden die vorhandenen Objekte analysiert und es werden nur diejenige ausgewählt, welche unseren Forderungen entsprechen, wobei der Benutzer selbst erstellen, entfernen, die Objekte im Laufe der Ausführung des Experten editieren kann. Die gefundenen Objekte werden im inneren Array gespeichert. Sein Vorhandensein ermöglicht die Veränderung des Zustandes des Charts zu prüfen und dem Benutzer über das Entdecken der neuen oder die Entfernung der alten Objekte zu berichten.

Periodisch nach dem Timer wird die andere Methode processLines aufgerufen, der im Loop nach dem Array den Eintritt der Ereignisse prüfen muss und die entsprechenden Handlungen durchführen.

Wie man sehen kann, wird bei den Objekten das Präfix, sowie ihre Stile, die Farben und der Status mit Hilfe von der Methode checkObjectCompliance geprüft (siehe. Weiter). Die passenden Objekte werden zum inneren Array von der Funktion attachObject hinzugefügt, die vom Chart entfernt wurden — werden auch aus dem Array von der Funktion removeObject entfernt. Die Liste der Objekte wird in Form von einem Kommentar auf dem Chart mit Hilfe von der Methode display dargestellt.

Das Array besteht aus den einfachen Strukturen, die den Namen des Objektes und seinen Zustand enthalten:

  private:
    struct LineObject
    {
      string name;
      int status;
      void operator=(const LineObject &o)
      {
        name = o.name;
        status = o.status;
      }
    };
    
    LineObject objects[];

Der Status wird vor allem für die Markierungen der existierenden Objekte verwendet — zum Beispiel, es wird direkt nach dem Hinzufügen des neuen Objektes zum Array von der Funktion attachObject durchgeführt:

  protected:
    bool attachObject(const string name)
    {
      bool found = false;
      int n = ArraySize(objects);
      for(int i = 0; i < n; i++)
      {
        if(objects[i].name == name)
        {
          objects[i].status = 1;
          found = true;
          break;
        }
      }
      
      if(!found)
      {
        ArrayResize(objects, n + 1);
        objects[n].name = name;
        objects[n].status = 1;
        return true;
      }
      
      return false;
    }

Die Prüfung der Existenz jedes Objektes findet in der Methode detectLines in den nachfolgenden Momenten statt:

    bool detectLines()
    {
      startRefresh();
      int n = ObjectsTotal(ChartID(), 0);
      int count = 0;
      for(int i = 0; i < n; i++)
      {
        string obj = ObjectName(ChartID(), i, 0);
        if(checkObjectCompliance(obj))
        {
          if(attachObject(obj))
          {
            describe(obj);
            count++;
          }
        }
      }
      if(count > 0) Print("New lines: ", count);
      bool changes = stopRefresh() || (count > 0);
      
      if(changes)
      {
        display();
      }
      
      return changes;
    }

Hier wird am Anfang die Hilfsfunktion startRefresh aufgerufen, die die Flaggen des Status um 0 bei allen Objekten des Arrays einstellt, dann bekommen die Arbeitsobjekte den Status 1 innerhalb des Loops mit der Hilfe von attachObject wieder, und am Ende findet der Aufruf stopRefresh statt, der die unnötigen Objekte im inneren Array nach dem Nullstatus findet, worüber er dem Benutzer signalisiert.

Die Prüfung jedes Objektes auf die Übereinstimmung mit den Anforderungen wird in der Methode checkObjectCompliance durchgeführt:

    bool checkObjectCompliance(const string obj)
    {
      if(CommonPrefit == "" || StringFind(obj, CommonPrefit) == 0)
      {
        if(_ln[ObjectGetInteger(0, obj, OBJPROP_TYPE)]
        && _st[ObjectGetInteger(0, obj, OBJPROP_STYLE)]
        && _cc[(color)ObjectGetInteger(0, obj, OBJPROP_COLOR)])
        {
          return true;
        }
      }
      return false;
    }

Darin, außer dem Präfix des Namens, werden die Sätze der Flaggen mit Typen, Stilen und Farben der Objekte geprüft. Dazu wird die Hilfsklasse Set verwendet:

#include <Set.mqh>

Set<ENUM_OBJECT> _ln(OBJ_HLINE, OBJ_VLINE, OBJ_TREND, OBJ_CHANNEL, OBJ_FIBO);
Set<ENUM_LINE_STYLE> _st(InstantType, PendingType, CloseStopLossTakeProfitType);
Set<color> _cc(BuyColor, SellColor, ActivationColor);

Jetzt werden wir über die Hauptmethode — processLines reden. Da er zentral ist, wirkt es auf seinen Umfang aus. Vollständig kann man den Code im Anhang finden, und hier werden wir die vorbildlichen Fragmente als Beispiel bringen.

    void processLines()
    {
      int n = ArraySize(objects);
      for(int i = 0; i < n; i++)
      {
        string name = objects[i].name;
        if(ObjectGetInteger(ChartID(), name, OBJPROP_BACK)) continue;
        
        int style = (int)ObjectGetInteger(0, name, OBJPROP_STYLE);
        color clr = (color)ObjectGetInteger(0, name, OBJPROP_COLOR);
        string text = ObjectGetString(0, name, OBJPROP_TEXT);
        datetime last = (datetime)ObjectGetInteger(0, name, OBJPROP_ZORDER);
    
        double aux = 0, auxf = 0;
        double price = getCurrentPrice(name, aux, auxf);
        ...

Im Loop bearbeiten wir alle Objekte durch, und dabei schließen die ausgelösten Objekte aus (bei ihnen, wie wir verabredet haben, wird die Flagge OBJPROP_BACK aufgestellt). Mit Hilfe von der Funktion getCurrentPrice, die unten gezeigt wird, erfahren wir die Werte des Preises des laufenden Objektes. Da einige Typen der Objekte aus einigen Linien bestehen, übergeben wir die zusätzlichen Werte der Preise durch 2 Parameter.

        if(clr == ActivationColor)
        {
          if(style == InstantType)
          {
            if(checkActivation(price))
            {
              disableLine(i);
              if(StringFind(text, "Alert:") == 0) Alert(StringSubstr(text, 6));
              else if(StringFind(text, "Push:") == 0) SendNotification(StringSubstr(text, 5));
              else if(StringFind(text, "Mail:") == 0) SendMail("TradeObjects", StringSubstr(text, 5));
              else Print(text);
            }
          }

Weiterhin prüfen wir den Stil des Objektes für die Klarstellung des Ereignistyps und wie sein Preis auf der 0-Bar mit dem Preis Bid zusammenpassen — falls ein Alert auftritt und die Setzung der Pending Orders durchgeführt werden soll, erledigt das die Funktion checkActivation. Wenn die Aktivierung stattfindet, führen wir die entsprechende Handlung (falls ein Alert auftritt, liefern die Mitteilung oder senden es dem Adressaten ab) aus und bezeichnen das Objekt wie das Objekt, das mit der Hilfe von disableLine ausgeschaltet wurde.

Für die Handelsoperationen wird der Aktivierungscode natürlich komplizierter sein. Zum Beispiel, die vereinfachte Variante für den Kauf nach dem Markt und die Schließung der offenen kurzen Positionen:

        else if(clr == BuyColor)
        {
          if(style == InstantType)
          {
            int dir = checkMarket(price, last);
            if((dir == 0) && checkTime(name))
            {
              if(clr == BuyColor) dir = +1;
              else if(clr == SellColor) dir = -1;
            }
            if(dir > 0)
            {
              double lot = StringToDouble(ObjectGetString(0, name, OBJPROP_TEXT)); // lot[%]
              if(lot == 0) lot = Lot;
    
              double sl = 0.0, tp = 0.0;
              if(aux != 0)
              {
                if(aux > Ask)
                {
                  tp = aux;
                  if(DefaultStopLoss != 0) sl = Bid - e.getPointsForLotAndRisk(DefaultStopLoss, lot) * _Point;
                }
                else
                {
                  sl = aux;
                  if(DefaultTakeProfit != 0) tp = Bid + e.getPointsForLotAndRisk(DefaultTakeProfit, lot) * _Point;
                }
              }
              else
              {
                if(DefaultStopLoss != 0) sl = Bid - e.getPointsForLotAndRisk(DefaultStopLoss, lot) * _Point;
                if(DefaultTakeProfit != 0) tp = Bid + e.getPointsForLotAndRisk(DefaultTakeProfit, lot) * _Point;
              }
              
              sl = NormalizeDouble(sl, _Digits);
              tp = NormalizeDouble(tp, _Digits);
            
              int ticket = e.placeMarketOrder(OP_BUY, lot, sl, tp);
              if(ticket != -1) // success
              {
                disableLine(i);
              }
              else
              {
                showMessage("Market buy failed with '" + name + "'");
              }
            }
          }
          else if(style == CloseStopLossTakeProfitType) // close sell position, stoploss for sell, takeprofit for sell
          {
            int dir = checkMarket(price) || checkTime(name);
            if(dir != 0)
            {
              double lot = StringToDouble(ObjectGetString(0, name, OBJPROP_TEXT)); // lot
              if(lot > 0)
              {
                if(e.placeMarketOrder(OP_BUY, lot) != -1) // will trigger OrderCloseBy();
                {
                  disableLine(i);
                }
                else
                {
                  showMessage("Partial sell close failed with '" + name + "'");
                }
              }
              else
              {
                if(e.closeMarketOrders(e.mask(OP_SELL)) > 0)
                {
                  disableLine(i);
                }
                else
                {
                  showMessage("Complete sell close failed with '" + name + "'");
                }
              }
            }
          }

Hier wird die Funktion checkMarket (die komplizierte Variante von checkActivation, beide werden weiter aufgeführt) verwendet, die die Prüfung des Eintritts des Ereignisses durchführt. Bei der Auslösung der Bedingung bekommen wir aus den Eigenschaften des Objektes die Ebene Stop-Los oder Take-Profit, des Lotes und dann öffnen wir die Order.

Der Umfang des Lotes wird in der Objektbeschreibung in den Verträgen oder als das Prozent von der freien Marge eingegeben — im letzten Fall wird die Größe wie negativ geschrieben. Der Sinn solcher Notierung ist leicht, zu merken, wenn man sich vorstellt , dass Sie tatsächlich bezeichnen, welchen Teil der Mittel Sie für die Versorgung der neuen Order planen.

Die Funktionen checkActivation und checkMarket sind ähnlich, sie verwenden die Eingangsparamter des Experten, die den Umfang des Bereichs der Ausnutzung der Ereignisse bestimmen:

    bool checkActivation(const double price)
    {
      if(Bid >= price - EventHotSpot * _Point && Bid <= price + EventHotSpot * _Point)
      {
        return true;
      }
      
      if((PreviousBid < price && Bid >= price)
      || (PreviousBid > price && Bid <= price))
      {
        return true;
      }
      return false;
    }
    
    int checkMarket(const double price, const datetime last = 0) // returns direction of price movement
    {
      if(last != 0 && (TimeCurrent() - last) / PeriodSeconds() < EventInterval)
      {
        return 0;
      }
    
      if(PreviousBid >= price - EventHotSpot * _Point && PreviousBid <= price + EventHotSpot * _Point)
      {
        if(Bid > price + EventHotSpot * _Point)
        {
          return +1; // up
        }
        else if(Bid < price - EventHotSpot * _Point)
        {
          return -1; // down
        }
      }
    
      if(PreviousBid < price && Bid >= price && MathAbs(Bid - PreviousBid) >= EventHotSpot * _Point)
      {
        return +1;
      }
      else if(PreviousBid > price && Bid <= price && MathAbs(Bid - PreviousBid) >= EventHotSpot * _Point)
      {
        return -1;
      }
      
      return 0;
    }

Wir erinnern, dass der Preis PreviousBid vom Experten im Bearbeiter handleTimer mit der Periodizität EventTimeSpan(Sekunden) gespeichert bleibt. Das Arbeitsergebnis der Funktionen — das Merkmal der Kreuzung vom Preis Bid den Preis des Objektes auf der nullwertigen Bar, wobei checkActivation die einfache logische Flagge zurückgibt, und checkMarket — die Richtung der Bewegung des Preises: +1 — nach oben,-1 — nach unten.

Besonders bemerken wir, dass die Kontrolle der Kreuzung von den Notierungen der Objekte nach dem Preis bid durchgeführt wird. Es wurde gemacht, weil das ganze Chart nach dem Preis bid aufgebaut ist, einschließlich der aufgetragenen Linien. Selbst wenn der Trader die Markierung für die Kauf-Orders gebildet hat, werden sie nach den richtigen Signalen ausgelöst: das Chart ask geht nicht auffällig über dem Chart bid um die Größe Spreads, und die potentiellen Linien, die nach dem Chart ask aufgebaut sein könnten, würden den Preis synchron mit der laufenden Markierung nach bid überqueren.

Die Linien des Stils PendingType und der neutralen ActivationColor haben eine besondere Funktionalität: im Moment ihrer Kreuzung wird es vom Preis die Pendig Orders gesetzt. Die Anordnung der Orders werden durch andere Linien eingegeben, deren Namen durch Slash (' / ') in der Beschreibung der Aktivierungslinie aufgezählt sind. Wenn die Beschreibung der Aktivierungslinie leer ist, das System findet alle Linien der Pending Orders nach dem Stil und wird sie setzten. Die Richtung der Pending Orders, genauso wie für die Markt-Orders, entspricht ihrer Farbe — BuyColor oder SellColor für Kauf oder Verkauf, und in der Beschreibung kann man das Lot und die Ablaufzeit (in Bars) bezeichnen.

Die Arten für die Varianten mit Stilen und Farben der Objekte und ihr entsprechender Wert wurden in der Tabelle aufgeführt.

Die Farbe und der StilBuyColorSellColorActivationColor
InstantType Der Kauf nach dem Markt Der Verkauf nach dem Markt Alert
PendingType Die potentielle Pending Order auf den Kauf Die potentielle Pending Order auf den Verkauf Die Initiierung der Setzung der Pending Orders
CloseStopLossTakeProfitType Schließung, Stop-Loss, Take-Profit
für eine Short-Position
Schließung, Stop-Loss, Take-Profit
für eine Long-Position
Alle schließen

Wir werden zur Methode getCurrentPrice zurückkehren — der wohl das wichtigste nach processLines ist.

    double getCurrentPrice(const string name, double &auxiliary, double &auxiliaryFibo)
    {
      int type = (int)ObjectGetInteger(0, name, OBJPROP_TYPE);
      if(type == OBJ_TREND)
      {
        datetime dt1 = (datetime)ObjectGetInteger(0, name, OBJPROP_TIME, 0);
        datetime dt2 = (datetime)ObjectGetInteger(0, name, OBJPROP_TIME, 1);
        int i1 = iBarShift(NULL, 0, dt1, true);
        int i2 = iBarShift(NULL, 0, dt2, true);
        if(i1 <= i2 || i1 == -1 || i2 == -1)
        {
          Print("Incorrect line: ", name);
          return 0;
        }
        double p1 = ObjectGetDouble(0, name, OBJPROP_PRICE, 0);
        double p2 = ObjectGetDouble(0, name, OBJPROP_PRICE, 1);
        
        double k = -(p1 - p2)/(i2 - i1);
        double b = -(i1 * p2 - i2 * p1)/(i2 - i1);
        
        return b;
      }
      else if(type == OBJ_HLINE)
      {
        return ObjectGetDouble(0, name, OBJPROP_PRICE, 0);
      }
      else if(type == OBJ_VLINE)
      {
        return EMPTY_VALUE; // should not be a null, not used otherwise
      }
      else if(type == OBJ_CHANNEL)
      {
        datetime dt1 = (datetime)ObjectGetInteger(0, name, OBJPROP_TIME, 0);
        datetime dt2 = (datetime)ObjectGetInteger(0, name, OBJPROP_TIME, 1);
        datetime dt3 = (datetime)ObjectGetInteger(0, name, OBJPROP_TIME, 2);
        int i1 = iBarShift(NULL, 0, dt1, true);
        int i2 = iBarShift(NULL, 0, dt2, true);
        int i3 = iBarShift(NULL, 0, dt3, true);
        if(i1 <= i2 || i1 == -1 || i2 == -1 || i3 == -1)
        {
          Print("Incorrect channel: ", name);
          return 0;
        }
        double p1 = ObjectGetDouble(0, name, OBJPROP_PRICE, 0);
        double p2 = ObjectGetDouble(0, name, OBJPROP_PRICE, 1);
        double p3 = ObjectGetDouble(0, name, OBJPROP_PRICE, 2);
        
        double k = -(p1 - p2)/(i2 - i1);
        double b = -(i1 * p2 - i2 * p1)/(i2 - i1);
        
        double dy = i3 * k + b - p3;
        
        auxiliary = p3 - i3 * k;
        
        return b;
      }
      else if(type == OBJ_FIBO)
      {
        // level 61.8 is enter point at retracement (buy/sell limit),
        // 38.2 and 161.8 as stoploss/takeprofit
        
        double p1 = ObjectGetDouble(0, name, OBJPROP_PRICE, 0);
        double p2 = ObjectGetDouble(0, name, OBJPROP_PRICE, 1);
        datetime dt1 = (datetime)ObjectGetInteger(0, name, OBJPROP_TIME, 0);
        datetime dt2 = (datetime)ObjectGetInteger(0, name, OBJPROP_TIME, 1);
        
        if(dt2 < dt1)
        {
          swap(p1, p2);
        }
        
        double price = (p2 - p1) * ObjectGetDouble(0, name, OBJPROP_LEVELVALUE, 4) + p1;
        auxiliary = (p2 - p1) * ObjectGetDouble(0, name, OBJPROP_LEVELVALUE, 2) + p1;
        auxiliaryFibo = (p2 - p1) * ObjectGetDouble(0, name, OBJPROP_LEVELVALUE, 6) + p1;
        return price;
      }
      return 0;
    }

Die Sache ist einfach — je nach dem Typ des Objektes muss man für ihn den Preis auf der nullwertigen Bar berechnen (für die Haupt- und zusätzliche Linien). Bei der Anordnung der Objekte auf dem Chart ist es wichtig, zu beachten, damit alle Punkte des Objektes der Vergangenheit gehören — dort wo die valide Nummer der Bar ist. Andernfalls wird das Objekt ungültig gelten, da es für ihn unmöglich ist, den Preis eindeutig zu rechnen.

Falls es um eine senkrechte Linie geht, geben wir EMPTY_VALUE zurück — das heißt, es ist nicht Null, aber auch kein konkreter Preis (weil eine solche Linie jedem beliebigen Preis entspricht). Deshalb ist es nötig, für die senkrechten Linien die zusätzliche Prüfung auf das Zusammenfallen mit der laufenden Zeit zu verwenden. Es macht die Funktion checkTime, deren Aufruf die aufmerksamen Leser schon im Fragment processLines bemerken konnten.

    bool checkTime(const string name)
    {
      return (ObjectGetInteger(0, name, OBJPROP_TYPE) == OBJ_VLINE
        && (datetime)ObjectGetInteger(0, name, OBJPROP_TIME, 0) == Time[0]);
    }

Endlich betrachten wir die Realisierung der Funktion disableLine, die schon mehrmals im Code vorgekommen ist.

    void disableLine(const string name)
    {
      int width = (int)ObjectGetInteger(0, name, OBJPROP_WIDTH);
      if(width > 1)
      {
        ObjectSetInteger(0, name, OBJPROP_WIDTH, width - 1);
        ObjectSetInteger(0, name, OBJPROP_ZORDER, TimeCurrent());
      }
      else
      {
        ObjectSetInteger(0, name, OBJPROP_BACK, true);
        ObjectSetInteger(0, name, OBJPROP_COLOR, darken((color)ObjectGetInteger(0, name, OBJPROP_COLOR)));
      }
      display();
    }

Wenn es die Dicke der Linie mehr als 1 ist, dann verringern wir sie um 1 und speichern die laufende Zeit des Ereignisses in der Eigenschaft OBJPROP_ZORDER. Falls es normale Linien gibt — versetzt wir sie auf den Hintergrund und wir sperren die Farbe ein. Die Objekte im Hintergrund gelten für die Ausgeschalteten.

Betreffs der Eigenschaft OBJPROP_ZORDER, so wird sie in der Methode processLines in die Variabel datetime last bearbeitet, wie es höher vorgeführt wurde, die dann als Argument in der Methode checkMarket (price, last) übergeben wird. Wir überprüfen drin, damit die Zeit ab dem vorhergehenden Aktivierungsmoment mehr als das Intervall (in Bars) wird, welches in der Eingangsvariabel eingegeben wurde:

      if(last != 0 && (TimeCurrent() - last) / PeriodSeconds() < EventInterval)
      {
        return 0;
      }

TradeObjects ermöglicht die teilweise Schließung zu machen, wenn in der Beschreibung des Objektes des Typs CloseStopLossTakeProfitType das Lot eingegeben ist. Das System öffnet die entgegenkommende Order des eingegebenen Volumens, und später ruft OrderCloseBy auf. Für die Aktivierung des Modus ist eine spezielle Flagge AllowOrderCloseBy in den Eingangsvariabelen vorgesehen. Wenn er aktiviert ist, werden die entgegenkommenden Positionen sich immer in eine zusammen bilden. Ich werde erinnern, dass diese Funktion nicht auf allen Konten zugelassen ist (der Experte prüft diese Einstellung und zeigt in das Log die entsprechende Mitteilung, wenn die vorliegende Möglichkeit blockiert ist). Falls es um MetaTrader 5 geht, dann muss das Konto mit Hadging sein. Die Interessierten können das System als alternative Realisierung der teilweise Schließung — ohne Nutzung OrderCloseBy verbessern, durch die Durchsicht der Liste der Positionen und die konkrete Auswahl, die mit Hilfe von irgendwelchen Attributen verringert sein kann.

Wir kehren zur Klasse Expert zurück, die für TradeObjects alle Handels-Operationen durchführt. Er stellt einen elementaren Satz der Methoden für die Eröffnung und Schließung der Orders, für die Begleitung Stop-Loss, die Berechnung der Lots, ausgehend vom gegebenen Risiko dar. Darin wird die Metapher der Orders MetaTrader 4 verwendet, die sich auf MetaTrader 5 mit Hilfe von der Bibliothek MT4Orders anpasst.

Die Klasse bietet kein Funktional nach der Veränderung der gesetzten Pending Orders. Die Versetzung ihres Preises, der Ebenen Stop-Loss und Take-Profit führt selbst das Terminal ein: wenn die Option "die Handelsebene zeigen", aktiviert ist, das ermöglicht er mit Hilfe von Drag'n'Drop zu machen.

Die Klasse Expert kann man um die Klasse ersetzen, die Sie benutzen.

Der hinzugefügte Quellcode wird sowohl in MetaTrader 4, als auch in MetaTrader 5 (mit den zusätzlichen Titeldateien) kompiliert.

Wir bemerken, dass es in der laufenden Realisierung TradeObjects eine Abweichung von den strengen Regeln von objektorientierter Programmierung gibt, um das einfacher zu machen. Zum Beispiel, man müsste eine abstrakte Handels-Interface haben, die Klasse des Experten Expert wie der Nachfahre dieser Interface realisieren und dann in die Klasse TradeObjects (zum Beispiel, durch das Parameter des Konstrukteurs) das zu übergeben. Es ist ein bekanntes Muster von objektorientierter Programmierung die Einführungen der Abhängigkeit (dependency injection). Im gegebenen Projekt ist der Handelsmotor in den Code "harter Weise" einprogrammiert worden: es entsteht und wird innerhalb des Objektes TradeObjects entfernt.

Außerdem verwenden wir verletzend der Prinzipien objektorientierter Programmierung die globalen Eingangsvariabel unmittelbar im Code der Klasse TradeObjects. Der beste Stil des Programmierens hätte gefordert, sie in die Klasse wie die Parameter des Konstrukteurs oder der speziellen Methoden zu übergeben. Es hat zum Beispiel ermöglicht, TradeObjects wie die Bibliothek innerhalb anderen Experten zu verwenden, dabei ihn mit den Funktionen des manuellen Handels nach der Markierung zu ergänzen.

Im Prinzip ist es umso wichtiger, die grundlegenden Prinzipien objektorientierter Programmierung zu halten, wenn das entwickelte Projekt größer ist. Da wir hier ziemlich einen einfachen und isolierten Motor des Autohandels nach den Objekten betrachten, so wird seine Verbesserung (welche keine Grenzen hat) für eine fakultative Forschung gelassen.

Das Programm im Betrieb

Unten wurde es schon gezeigt, wie das System während der Arbeit aussieht, bei den standardmäßigen Einstellungen der Stile und der Farben.

Wir nehmen an, wir haben auf dem Chart die Bildung der Figur "Kopf-Schulter" gesehen und wir setzen die horizontale rote Linie für Verkauf. Das System liefert das Verzeichnis der gedeckten und kontrollierten Objekte in den Kommentaren.


Der Stopp-Loss wird entsprechend mit dem Parameter des Experten DefaultStopLoss gesetzt, und anstelle Take-Profit werden wir die Verbleibszeit im Markt mit Hilfe von der senkrechten blauen punktierten Linie beschränken.


Nach dieser Linie wird die Position (unabhängig davon, ob es gewinnbringend ist) geschlossen. Die ausgelösten Linien werden wie inaktiv (ihre Farbe wird eingesperrt, und sie selber werden im Hintergrund versetzt) bezeichnet.


Nach einer Weile sieht es aus, dass die Notierungen sich noch einmal nach unten bewegen wollen, und wir stellen die Ebene Fibonacci, dabei haben die Hoffnung, dass ein Sprung von der Ebene 61.8 stattfindet (es ist alles, was die Ebene Fibonacci im gegebenen Projekt standardmäßig machen kann, aber Sie können auch andere Typen des Verhaltens realisieren). Bitte beachten Sie, dass die Farbe des Objektes Fibonacci eine Farbe der diagonalen Linie ist, und nicht der Ebenen: die Farbe der Ebenen wird durch eine andere Einstellung eingegeben.


Wenn der Preis bis zur Ebene geht, dann wird ein Trade geöffnet, und übrigens mit den eingegebenen Preisen Stop Loss (38.2) und Take Profit (161.8 ist auf dem Screenshot nicht sichtbar).


Eine Weile später sehen wir die Bildung der Linie des Widerstands oben und wir setzen den blauen Kanal mit der Idee, dass der Preis doch nach oben geht.


Wir bemerken, dass alle Linien bisher keine Beschreibung enthalten, und deshalb wurden die Orders mit dem Lot aus dem Parameter Lot (0.01, standardmäßig) geöffnet. In dem Fall steht die Beschreibung '-1 ', d.h. der Volumen des Lotes wird berechnet, wie der fordernde 1 % der freien Marge. Da die Hilfslinie unten der Hauptlinie ist, gibt der Kanal die Entfernung bis Stopp-Loss ein (unterschiedlicher vom standardmäßigen Wert).


Der Kanal wird wirklich durchgebrochen, und die neue Long-Position wir geöffnet. Wie wir sehen, wurde der Volumen wie 0.04 (beim Depositum 1000$) berechnet. Das blaue Segment auf dem Screenshot ist ein ausgelöster Kanal, der in den Hintergrund versetzt wurde (so MetaTrader 4 stellt die Kanäle auf dem Hintergrund dar).

Um beide Eröffnungen der Positionen auf Kauf zu schließen, werden wir die offenbare Linie Take-Profit — rot punktiert bezeichnen.


Der Preis geht bis zur gegebenen Ebene, und beide Orders werden geschlossen.


Wir vermuten, dass nach solcher Bewegung der Preis im "Korridor" gehen wird. Um diese Volatilität zu fangen, werden wir zwei horizontale Strich-Linien für die Limit-Orders oben und unten vom Preis setzen, sowie die graue senkrechte Strich-Linie für ihre Aktivierung. Im Prinzip müssen sie nicht horizontal oder senkrecht sein.


Beachten Sie bitte, dass zum Beispiel für die untere Pending Orders in der Beschreibung ein Personalisierunglot 0.02 und die Ablaufzeit 24 Bars (die Stunden) eingegeben ist. Nach der Linie der Aktivierung werden die Pending Orders gesetzt.


Nach einer Weile wird sell limit ausgelöst.


Buy limit läuft am Montag ab.


Wir setzen die senkrechte graue punktierte Linie, die die Schließung aller Positionen bedeutet.


Nach ihrer Erreichung wird die Short-Position geschlossen, obwohl sogar auch eine Long-Position geöffnet wäre, würde sie auch geschlossen.


Im Laufe der Arbeit führt der Experte die Hauptereignisse in den Log vor.

2017.07.06 02:00:00  TradeObjects EURUSD,H1: New line added: 'exp Channel 42597 break up' OBJ_CHANNEL buy -1
2017.07.06 02:00:00  TradeObjects EURUSD,H1: New lines: 1
2017.07.06 10:05:27  TradeObjects EURUSD,H1: Activated: exp Channel 42597 break up
2017.07.06 10:05:27  TradeObjects EURUSD,H1: open #3 buy 0.04 EURUSD at 1.13478 sl: 1.12908 ok
...
2017.07.06 19:02:18  TradeObjects EURUSD,H1: Activated: exp Horizontal Line 43116 takeprofit
2017.07.06 19:02:18  TradeObjects EURUSD,H1: close #3 buy 0.04 EURUSD at 1.13478 sl: 1.13514 at price 1.14093
2017.07.06 19:02:18  TradeObjects EURUSD,H1: close #2 buy 0.01 EURUSD at 1.13414 sl: 1.13514 tp: 1.16143 at price 1.14093
...
2017.07.07 05:00:09  TradeObjects EURUSD,H1: Activated: exp Vertical Line 42648
2017.07.07 05:00:09  TradeObjects EURUSD,H1: open #4 sell limit 0.01 EURUSD at 1.14361 sl: 1.15395 ok
2017.07.07 05:00:09  TradeObjects EURUSD,H1: #4 2017.07.07 05:00:09 sell limit 0.01 EURUSD 1.14361 1.15395 0.00000 0.00000 0.00 0.00 0.00  0 expiration 2017.07.08 05:00
2017.07.07 05:00:09  TradeObjects EURUSD,H1: open #5 buy limit 0.02 EURUSD at 1.13731 sl: 1.13214 ok
2017.07.07 05:00:09  TradeObjects EURUSD,H1: #5 2017.07.07 05:00:09 buy limit 0.02 EURUSD 1.13731 1.13214 0.00000 0.00000 0.00 0.00 0.00  0 expiration 2017.07.08 05:00

Die durcharbeitenden Objekte kann man klar entfernen, um das Chart zu reinigen. Im Beispiel wurden sie als Protokoll der durchgeführten Handlungen gelassen.

Zu dem Artikel wurden die Muster für MetaTrader 4 und MetaTrader 5 mit den Linien für den Demohandel im Tester auf dem Chart EURUSD H1, seit dem 1. Juli 2017 (die obenageführte Periode) hinzugefügt. Es werden die Standardeinstellungen des Experten mit Ausnahme des Parameters DefaultStopLoss verwendet, die in -1 eingestellt ist (dass dem Verlust 1 % der freien Marge entspricht). Für die anschauliche Illustration der Berechnung und der Begleitung Stop-Loss wird das Anfangsdepositum 1000$ und der Hebel 1:500 angeboten. Falls es im MetaTrader 5 ist, muss das Muster voraussichtlich in tester.tpl umbenannt werden (die Ladung und die Editierung der Muster kann direkt im Tester noch nicht durchgeführt werden). 

Fazit

Im Artikel wurde eine einfache, aber die funktionale Variante der Organisation des halbautomatischen Handels unter Nutzung der Standardobjekte vorgestellt, die auf dem Chart vom Trader gesetzt sind. Mit der Hilfe von den Trends-, Horizontalen, Senkrechten-Linien, den Kanälen und Fibonacci-Netzen kann das System die Marktorders ausführen, die Pending Orders setzen, den Trader über eine Bildung der charakteristischen Figuren auf dem Markt warnen. Der offene Quellcode ermöglicht den Satz der unterstützten Typen der Objekte zu verbreiten, und auch das Handelsfunktional zu verbessern.

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/3442

Beigefügte Dateien |
MT4.zip (11.97 KB)
MT5.zip (27.59 KB)
Walk-Forward-Optimierung in MetaTrader 5 - mit eigenen Händen Walk-Forward-Optimierung in MetaTrader 5 - mit eigenen Händen
Im Artikel werden verschiedene Herangehensweisen betrachtet, die es erlauben, eine Walk-Forward-Optimierung mithilfe des eingebauten Testers und Hilfsbibliotheken in MQL genau zu emulieren.
Verwendung eines Cloud-Speichers für den Datenaustausch zwischen Terminals Verwendung eines Cloud-Speichers für den Datenaustausch zwischen Terminals
Immer beliebter werden die wolkigen Technologien. Sowohl kostenpflichtige, als auch kostenfreie Speicher stehen uns zur Verfügung. Können wir sie im Traiding verwenden? In diesem Artikel wird die Technologie für den Datenaustausch zwischen Terminals durch die Verwendung wolkiger Speichers angeboten.
Der naive Bayes-Klassifikator für die Signale einer Reihe von Indikatoren Der naive Bayes-Klassifikator für die Signale einer Reihe von Indikatoren
Der Artikel analysiert die Verwendung der Bayes'schen Formel, um den Gewinn von Handelssystemen durch die Signale mehrerer unabhängiger Indikator zu erhöhen. Theoretische Berechnungen werden über einen einfachen, allgemeinen EA, der mit beliebigen Indikatoren arbeitet verifiziert.
Cross-Plattform Expert Advisor: Zeitfilter Cross-Plattform Expert Advisor: Zeitfilter
Dieser Artikel beschreibt die Implementierung verschiedener Methoden einer Zeitfilterung für einen Cross-Plattform Expert Advisor. Die Klassen der Zeitfilter sind verantwortlich für die Prüfung, ob ein bestimmter Zeitpunkt in eine besondere Zeitkonfiguration fällt oder nicht.