Dokumentation

Anwendungen

Zuletzt aktualisiert am 18. 5. 2020 von Mark Fric

Indikator für Umschläge

In diesem Beispiel fügen wir Folgendes hinzu Briefumschläge Indikator zu StrategyQuant X.

Den MQL-Code für diesen Indikator finden Sie hier: https://www.mql5.com/en/code/7975

Dieser Indikator ist auch schon in MetaTrader eingebaut, Sie können ihn aus dem MQL Code mit der iEnvelopes Methode aufrufen. So sieht der Indikator im Chart aus:

Es sind nur wenige Schritte erforderlich, um einen neuen Indikator zu SQ X hinzuzufügen:

  1. Hinzufügen eines neuen Indikator-Bausteins 
    erstellen wir ein neues Indikator-Snippet und aktualisieren seinen Code, um den Hüllkurven-Indikator zu berechnen.
  2. (Optional, empfohlen) Testen des neuen Indikators in SQ X im Vergleich zu den Daten aus MT
    während oder nach der Implementierung sollten wir die von SQ berechneten Indikatorwerte mit den von MQL berechneten vergleichen, um sicherzustellen, dass der Indikator korrekt implementiert ist
  3. Hinzufügen der Übersetzung des Indikatorblocks in die Sprache der Zielplattform
    Indikator funktioniert jetzt in SQ, aber Strategien, die diesen Indikator verwenden, nicht. Wir müssen für jede Handelsplattform, die wir unterstützen wollen, Vorlagen hinzufügen oder Quellcode für diesen Indikator generieren

 

Hinzufügen eines neuen Indikatorensnippets

Um dies zu tun, öffnen wir Code-Editor.

Dort klicken wir auf Neu erstellen Schaltfläche in der Symbolleiste

und im Popup-Dialog geben wir 'Briefumschläge' als neuen Indikatornamen und lassen Sie Indikator als Snippet-Typ.

Klicken Sie auf OKund es wird ein neuer Indikator erstellt.

 

Sie können es im Navigationsbaum unter Snippets -> SQ -> Blöcke -> Indikatoren sehen. Er hat einen eigenen Ordner mit dem Namen "Envelopes", und der Code des Indikator-Snippets befindet sich in der Datei Briefumschläge.java

Die Konvention in StrategyQuant ist, dass jeder Indikator in einem eigenen Ordner liegt - das liegt daran, dass wir später vielleicht Signale für diesen Indikator erstellen wollen, und alle zugehörigen Snippets werden im selben Ordner liegen.

Mit dieser Aktion wird eine neue Datei für unseren Hüllkurven-Indikator erstellt und im Editor geöffnet. Sie können sehen, dass der Indikator eine Klasse ist und bereits eine gewisse Struktur hat.

 

Jeder Indikator wird von der Klasse IndicatorBlock erweitert und muss eine Methode implementieren:

  • OnBarUpdate() - Methode, bei der der Indikatorwert berechnet und in einem der Ausgabepuffer gespeichert wird. Sie wird für jeden Balken im Diagramm aufgerufen.

 

Wenn Sie sich den Quellcode ansehen, sollten Sie einige Dinge bemerken.

Erstens verwenden Snippets in StrategyQuant häufig Annotationen - @Parameter, @Output, @BuildingBlock - diese Annotationen werden verwendet, um eine spezielle Eigenschaft einer bestimmten Variablen oder Klasse zu deklarieren - dass die Variable ein öffentlicher Parameter oder Ausgabewert ist, oder dass die Klasse ein Indikatorblock ist.

Zweitens: Sobald Sie einen Indikator erstellt und kompiliert haben, können Sie ihn von anderen Methoden oder Indikatoren aus aufrufen, indem Sie Indicators.YourIndicator(YourIndicatorParameters). Auf diese Weise kann ein Indikator von einem anderen aufgerufen werden - wir werden dies auch in den Hüllkurven verwenden, um Indikatoren für gleitende Durchschnitte aufzurufen, wir werden später dazu kommen.

 

Wir werden den Quellcode der Standardindikatorenklasse, die aus der Vorlage erstellt wurde, Schritt für Schritt durchgehen:

package SQ.Blocks.Indicators.Envelopes;

import com.strategyquant.lib.*;
import com.strategyquant.datalib.*;
import com.strategyquant.tradinglib.*;

import SQ.Internal.IndicatorBlock;

Dies ist die Standard-Java-Deklaration eines Pakets und des Imports der erforderlichen Klassen - derjenigen, die wir in unserer eigenen Klasse verwenden.


@BuildingBlock(name="(XXX) Envelopes", display="Envelopes(#Period#)[#Shift#]", returnType = ReturnTypes.Price)
@Help("Envelopes help text")
public class Envelopes extends IndicatorBlock {

Kommentierte Definition unserer Indikatorklasse, die dem System mitteilt, dass es sich um einen Baustein mit einem bestimmten Namen handelt.

  • Name ist das Feld, das bei der Auswahl von Bausteinen in der Benutzeroberfläche angezeigt wird.
  • Anzeige ist das Feld, das im Assistenten mit Parametern angezeigt wird. Sie können steuern, welche Parameter angezeigt werden und an welcher Stelle
  • returnType ist ein Indikatortyp, der angibt, welche Art von Wert dieser Indikator errechnet. Er wird verwendet, damit StrategyQuant weiß, welche Typen mit welchen verglichen werden sollten. Zum Beispiel würde StrategyQuant den CCI (der eine Zahl liefert) nicht mit den Bolinger-Bändern (die den Preis liefern) vergleichen.

 

Es gibt grundsätzlich drei Arten von Rückgaben, die ein Indikator haben kann:

  • Preis - Der Indikator berechnet den Preis und wird auf dem Preisdiagramm angezeigt - wie Bollinger Bänder, gleitender Durchschnitt, usw.
  • Nummer - Der Indikator berechnet eine Zahl, die auf seinem eigenen Diagramm angezeigt wird - wie CCI, RSI, MACD, usw.
  • Preisspanne - Indikator berechnet die Preisspanne (Differenz zwischen zwei Preisen) - wie ATR

Andere Rückgabearten werden in anderen Arten von Bausteinen verwendet.

 

In unserem Fall werden die Hüllkurven aus dem gleitenden Durchschnitt eines Preises berechnet, so dass er im Preisdiagramm angezeigt wird. Das bedeutet, dass sein Rückgabetyp Preis ist.

 

@Parameter
public DataSeries Input;

@Parameter(defaultValue="10", isPeriod=true, minValue=2, maxValue=1000, step=1)
public int Period;

@Output
public DataSeries Value;

was folgt, sind Indikatorparameter. Jeder Indikator kann mehrere Eingabeparameter haben, die Vorlage erstellt nur zwei davon als Beispiel. Jeder Parameter ist kommentiert mit @Parameter Anmerkung, die mehrere Attribute haben kann.

Der allererste Parameter ist Eingabeist das Datenreihen-Array, aus dem der Indikator berechnet wird - es kann zum Beispiel der Eröffnungs-, Höchst-, Tiefst- oder Schlusskurs sein.

Der zweite Parameter ist ZeitraumIndikatoren haben in der Regel einen bestimmten Zeitraum, für den sie berechnet werden.

Die dritte Variable ist Wertbeachten Sie, dass es eine andere Anmerkung hat @Output. Das bedeutet, dass es sich bei dieser Variablen nicht um einen Indikatorparameter, sondern um seinen Ausgabepuffer handelt. Indikatoren haben in der Regel nur einen Ausgabepuffer, aber sie können auch mehrere haben - zum Beispiel hat das Bollinger Band einen oberen und einen unteren Puffer.

Es gibt einen weiteren versteckten Parameter Schicht - ist standardmäßig in jedem Indikator enthalten und teilt der Trading Engine mit, nach welchem Wert sie suchen soll. Sie müssen sich im Allgemeinen nicht um diesen Parameter kümmern, er wird automatisch verwendet.

 

Dann gibt es eine Methode:

protected void OnBarUpdate() throws TradingException {...}

 

Dies ist die Methode, mit der die Indikatorwerte berechnet werden. Sie wird intern von SQ für jeden Balken aufgerufen und sollte den Indikatorwert für diesen Balken berechnen und in den Ausgabepuffer speichern.

Dies ist der Quellcode der Standard-Indikatorvorlage. Im nächsten Schritt zeigen wir die Änderungen, die vorgenommen werden müssen, um unseren Hüllkurven-Indikator zu implementieren.

 

Modifizierung der generierten Standardvorlage und Implementierung des Indikators

Der in Schritt 1 erstellte Indikator ist eine Standard-Indikatorvorlage, er berechnet noch keine Hüllkurven. Um ihn zu implementieren, müssen wir ein paar Dinge tun:

seine @BuildingBlocks-Anmerkung aktualisieren

Wir werden die Anmerkung dieses Indikators wie folgt aktualisieren:

@BuildingBlock(name="(EP) Envelopes", display="Envelopes(#MA_Period#, #Deviation#)[#Shift#]", returnType = ReturnTypes.Price)
@Help("Envelopes indicator")
public class Envelopes extends IndicatorBlock {

Dies ist der einfachste Teil. Wir aktualisieren einfach Name des Indikators und fügen Sie die aktuellen neuen Parameter (siehe unten) in die Anzeige Attribut.

 

Definieren Sie seine realen Parameter

Das erste, was zu tun ist, ist etwas knifflig - wir müssen den Typ der Standard Eingabe Parameter. In der Standardvorlage ist er wie folgt definiert:

@Parameter
public DataSeries Input;

es ist ein Parameter namens Eingabe, mit Typ DataSeries. Dies gilt für einen großen Teil der Indikatoren, die aus nur einem Preis berechnet werden. Zum Beispiel CCI, RSI, etc. Indikatoren sind in der Regel von Close Preis berechnet. Sie können sie so konfigurieren, dass sie von einem anderen Preis berechnet werden, z. B. vom Eröffnungskurs, aber es handelt sich immer noch um ein einziges Preisfeld.

 

Der Typ DataSeries ist ein Array von Werten, das Werte für Close-Preise, Open-Preise, typische Preise usw. enthält.
Wenn Sie sich jedoch den Quellcode von Envelopes MQL ansehen, werden Sie sehen, dass es seine Werte aus einem der Preiswerte und aus Volume berechnet.

 

Um auf mehrere Preis-Arrays gleichzeitig zugreifen zu können, werden wir verschiedene Typen für die Ausgabe verwenden:

@Parameter
public ChartData Input;


ChartData
 Typ ist ein Objekt, das den gesamten Chart repräsentiert - Sie haben Zugriff auf die Preise Open, High, Low, Close, Volume im gegebenen Chart. Wir benötigen dies, um den Indikator entsprechend dem Parameter Angewandter Preis berechnen zu können.

 

Kurzer Hinweis: Die Wahl des richtigen Typs für die Eingangsdatenvariable ist nicht schwer:
Wenn der Indikator aus einem Preis berechnet wird und es keine Möglichkeit gibt, den angewandten Preis zu wählen, verwenden Sie weiterhin DataSeries.
Wenn er aus mehreren Kursen berechnet wird oder eine Auswahlmöglichkeit besteht - z. B. Hoch, Tief, Schluss, etc. - verwenden Sie ChartData.

 

Dann gibt es noch Indikatorparameter:

@Parameter(defaultValue="14", isPeriod=true, minValue=2, maxValue=1000, step=1)
public int MA_Period;

MA_Period ist ein "Standard"-Periodenparameter für diesen Indikator.


@Parameter(defaultValue="0", minValue=0, maxValue=10, step=1)
public int MA_Moved;

MA_Moved ist die Verschiebung dieses Indikators. Im MQL-Code heißt dieser Parameter MA_Shift, aber Shift ist ein reserviertes Wort in SQ, also müssen wir ihn umbenennen.

 

@Parameter(name="Method", defaultValue="0")
@Editor(type=Editors.Selection, values="Simple=0,Exponential=1,Smoothed=2,Linear weighted=3")
public int MA_Method;

Dieser Parameter ist die Methode des gleitenden Durchschnitts. Er ist etwas komplizierter, da wir eine Auswahlliste (Combobox) als Bearbeitungselement für diesen Parameter definieren. Bei der Bearbeitung im Assistenten kann der Benutzer also aus den vordefinierten Werten auswählen.

 

@Parameter(defaultValue="0")
@Editor(type=Editors.Selection, values="Close=0,Open=1,High=2,Low=3,Median=4,Typical=5,Weighted=6")
public int Applied_Price;

Dasselbe gilt für Applied_Price - dies ist eine Auswahl von Eingaben, die zur Berechnung von Hüllkurven verwendet werden können.

 

@Parameter(defaultValue="0.1", minValue=0.01, maxValue=10, step=0.01, builderMinValue=0.05, builderMaxValue=1, builderStep=0.05)
public double Deviation;

Die Abweichung ist der letzte Eingabeparameter des Hüllkurvenindikators.

 

Bitte beachten Sie, dass wir auch einige Werte für min, max und step für diese Parameter angegeben haben.

minWert/maxWert sind die Mindest-/Maximalbereiche, die Sie einstellen können.

builderMinValue/builderMaxValue sind optionale Bereiche, die Builder in SQ bei der Erstellung von Strategien verwenden - sie können kleiner sein als die in minValue/maxValue definierten Maximalbereiche

defaultValue definiert den Standardwert für diesen Indikator.

step/builderStep definiert die Stufe des Parameterwertes

 

Definieren Sie Ausgaben

Der Hüllkurvenindikator hat zwei Ausgänge - Upper und Lower - Sie können zwei verschiedene Linien im MT4-Chart sehen.

Wir müssen also auch zwei Ausgänge definieren:

@Output(name="Upper", color=Colors.Green)
public DataSeries Upper;

@Output(name="Lower", color=Colors.Red)
public DataSeries Lower;

Der Vermerk @Output bedeutet, dass dies ein Ausgabepuffer für diesen Indikator ist. Beachten Sie, dass er vom Typ DataSeries ist, was bedeutet, dass es sich um ein Array von Doppelwerten handelt.

 

Implementierung der Methode OnBarUpdate()

Wenn Sie sich den MQL-Code von Envelopes anschauen, werden Sie sehen, dass er ziemlich einfach ist:

  int start()
  {
   int limit;
   if(Bars<=MA_Period) return(0);
   ExtCountedBars=IndicatorCounted();
//---- check for possible errors
   if (ExtCountedBars<0) return(-1);
//---- last counted bar will be recounted
   if (ExtCountedBars>0) ExtCountedBars--;
   limit=Bars-ExtCountedBars;
//---- EnvelopesM counted in the buffers
   for(int i=0; i<limit; i++)
     { 
      ExtMapBuffer1[i] = (1+Deviation/100)*iMA(NULL,0,MA_Period,0,MA_Method,Applied_Price,i);
      ExtMapBuffer2[i] = (1-Deviation/100)*iMA(NULL,0,MA_Period,0,MA_Method,Applied_Price,i);
     }
//---- done
   return(0);
  }

Wenn Sie es ein wenig analysieren, werden Sie sehen, dass die oberen und unteren Werte mit einer einfachen Formel berechnet werden:

Oberes Band = [1+DEVIATION/100] * MA(PRICE, PERIOD)
Unteres Band = [1-DEVIATION/100] * MA(PRICE, PERIOD)

wobei die Parameter DEVIATION, MA, PRICE und PERIOD konfigurierbar sind.

 

Wir können es in Java wie folgt implementieren:

    @Override
    protected void OnBarUpdate() throws TradingException {
        double ma = computeMA();
        Upper.set( (1+Deviation/100d) * ma );
        Lower.set( (1-Deviation/100d) * ma );
    }

 

Methode OnBarUpdate() wird für jeden Balken im Diagramm aufgerufen. Seine Aufgabe ist es, den/die Wert(e) des Indikators für diesen Balken zu berechnen und in den Ausgabepuffern zu speichern.

In unserem Fall berechnen wir also sowohl den oberen als auch den unteren Wert für den aktuellen Balken und speichern sie in ihren Puffern, indem wir Upper.set(), Lower.set().

 

Beachten Sie, dass wir eine spezielle Hilfsmethode verwenden computeMA() um den gleitenden Durchschnitt gemäß den Parametern MA_Methode und Angewandter_Preis zu berechnen.

Der Code für diese Hilfsmethode lautet:

private double computeMA() throws TradingException {
  DataSeries MAInput;

  switch(Applied_Price){
    case 0: MAInput = Input.Close; break;
    case 1: MAInput = Input.Open; break;
    case 2: MAInput = Input.High; break;
    case 3: MAInput = Input.Low; break;
    case 4: MAInput = Input.Median; break;
    case 5: MAInput = Input.Typical; break;
    default: throw new TradingException(String.format("Undefined Applied price: %d !", Applied_Price));
  }

  switch(MA_Method){
    case 0: return Indicators.SMA(MAInput, MA_Period).Value.get(MA_Moved);
    case 1: return Indicators.EMA(MAInput, MA_Period).Value.get(MA_Moved);
    case 2: return Indicators.SMMA(MAInput, MA_Period).Value.get(MA_Moved);
    case 3: return Indicators.LWMA(MAInput, MA_Period).Value.get(MA_Moved);
    default: throw new TradingException(String.format("Undefined MA Method: %d !", MA_Method));
  }
}

Es ist ein bisschen länger, aber verständlich. Zuerst wählen wir die richtigen Preisdaten nach Angewandter_Preis Parameter.

Im zweiten Schritt rufen wir den entsprechenden gleitenden Durchschnittsindikator für diese Eingabe auf, und zwar gemäß MA_Methode Parameter.

 

Nehmen wir zum Beispiel einen der Aufrufe auseinander: Indicators.SMA(MAInput, MA_Period).Value.get(MA_Moved):

  • Indicators.SMA(MAInput, MA_Period) ruft den SMA-Indikator über den MAInput-Eingang mit MA_Period auf. Der SMA-Indikator hat nur einen Ausgangspuffer mit dem Namen Value, so dass die berechneten Indikatorwerte dort gespeichert werden.
  • erhalten wir den Puffer durch einfachen Aufruf von .Wert
  • Value ist ein Puffer (Typ DataSeries), wie unsere oberen und unteren Puffer, d.h. es handelt sich um ein Array von Doppelwerten, wobei jeder Wert zu einem Balken im Diagramm gehört. Um den Wert des Balkens an der N-ten Position zu erhalten, sollten wir Wert.get(N).
    In unserem Fall rufen wir .Value.get(MA_Moved)denn wir wollen den Wert optional um einige Balken nach hinten verschieben, entsprechend dem Parameter MA_Moved.

 

Der gesamte Aufruf Indicators.SMA(MAInput, MA_Period).Value.get(MA_Moved) berechnet also den SMA mit Periode MA_Zeitraum über die MAInput Daten, und gibt ihren Wert zurück MA_bewegt Bars vor.

 

Beachten Sie, dass die Werte im Ausgabepuffer von Null an indiziert sind, wobei Null der Wert des aktuellsten Balkens ist.

Also:

  • Value.get(0) - gibt den Wert des aktuellen Balkens zurück
  • Value.get(1) - gibt den Wert des vorherigen Balkens zurück
  • Value.get(2) - gibt den Wert des Barrens vor dem vorherigen Barren zurück und so weiter

 

Das ist alles, wenn wir jetzt auf Kompilieren und starten Sie dann SQ neu. Sie sehen dann unseren neuen Hüllkurven-Indikator im Bereich Zufallsindikatoren-Signale.

 

Vollständiger Quellcode unseres neuen Indikators - Sie können ihn auch im Anhang zu diesem Artikel herunterladen:

package SQ.Blocks.Indicators.Envelopes;

import com.strategyquant.lib.*;
import com.strategyquant.datalib.*;
import com.strategyquant.tradinglib.*;

import SQ.Internal.IndicatorBlock;

/**
 * Indicator name as it will be displayed in UI, and its return type.
 * Possible return types:
 * ReturnTypes.Price - indicator is drawn on the price chart, like SMA, Bollinger Bands etc.
 * ReturnTypes.Price - indicator is drawn on separate chart, like CCI, RSI, MACD
 * ReturnTypes.PriceRange - indicator is price range, like ATR.
 */
@BuildingBlock(name="(EP) Envelopes", display="Envelopes(#MA_Period#, #Deviation#)[#Shift#]", returnType = ReturnTypes.Price)
@Help("Envelopes indicator")
public class Envelopes extends IndicatorBlock {

  @Parameter
  public ChartData Input;

  @Parameter(defaultValue="14", isPeriod=true, minValue=2, maxValue=1000, step=1)
  public int MA_Period;

  @Parameter(defaultValue="0", minValue=0, maxValue=10, step=1)
  public int MA_Moved;

  @Parameter(name="Method", defaultValue="0")
  @Editor(type=Editors.Selection, values="Simple=0,Exponential=1,Smoothed=2,Linear weighted=3")
  public int MA_Method;

  @Parameter(defaultValue="0")
  @Editor(type=Editors.Selection, values="Close=0,Open=1,High=2,Low=3,Median=4,Typical=5,Weighted=6")
  public int Applied_Price;
  
  @Parameter(defaultValue="0.1", minValue=0.01, maxValue=10, step=0.01, builderMinValue=0.05, builderMaxValue=1, builderStep=0.05)
  public double Deviation;

  @Output(name="Upper", color=Colors.Green)
  public DataSeries Upper;

  @Output(name="Lower", color=Colors.Red)
  public DataSeries Lower;

  
  //------------------------------------------------------------------------
  //------------------------------------------------------------------------
  //------------------------------------------------------------------------

  @Override
  protected void OnBarUpdate() throws TradingException {
    double ma = computeMA();

    Upper.set( (1+Deviation/100d) * ma );
    Lower.set( (1-Deviation/100d) * ma );
  }

  //------------------------------------------------------------------------

  private double computeMA() throws TradingException {
    DataSeries MAInput;

    switch(Applied_Price){
      case 0: MAInput = Input.Close; break;
      case 1: MAInput = Input.Open; break;
      case 2: MAInput = Input.High; break;
      case 3: MAInput = Input.Low; break;
      case 4: MAInput = Input.Median; break;
      case 5: MAInput = Input.Typical; break;
      default: throw new TradingException(String.format("Undefined Applied price: %d !", Applied_Price));
    }

    switch(MA_Method){
      case 0: return Indicators.SMA(MAInput, MA_Period).Value.get(MA_Moved);
      case 1:	return Indicators.EMA(MAInput, MA_Period).Value.get(MA_Moved);
      case 2: return Indicators.SMMA(MAInput, MA_Period).Value.get(MA_Moved);
      case 3: return Indicators.LWMA(MAInput, MA_Period).Value.get(MA_Moved);
      default: throw new TradingException(String.format("Undefined MA Method: %d !", MA_Method));
    }
  }
}

 

 

Testen eines neuen Indikators in SQ X im Vergleich zu Daten aus MT

wir haben gerade unseren neuen Indikator erstellt (oder sind dabei, ihn zu entwickeln). Woher wissen wir, dass wir ihn richtig implementiert haben?

Wenn Sie Ihren neuen Indikator in StrategyQuant erstellt haben und er erfolgreich kompiliert wurde, sollte auch überprüft werden, ob er wirklich so funktioniert wie im MetaTrader - mit anderen Worten, ob die von ihm berechneten Werte die gleichen sind wie die Werte im MT4.

 

Zu diesem Zweck haben wir im Code-Editor ein Indikator-Tester-Tool. Es vergleicht einfach die in SQ berechneten Werte mit den in MT4 berechneten Werten.

 

Im Allgemeinen funktioniert es in wenigen einfachen Schritten:

  1. Hilfsskript zum Berechnen und Exportieren von Indikatordaten in MetaTrader verwenden
  2. Kopieren Sie die berechneten Datendateien an den richtigen Ort, damit SQ sie finden kann
  3. Konfigurieren und Ausführen von Indikatortests in SQ

Hilfsskript zum Berechnen und Exportieren von Indikatordaten in MetaTrader verwenden

Als ersten Schritt müssen wir MT4-Testdaten vorbereiten - wir müssen den Indikator auf einer Reihe von Bars berechnen und die berechneten Werte in einer Datei speichern.

Hierfür stellen wir einen einfachen EA zur Verfügung, den Sie verwenden können - er befindet sich in {SQ}/benutzerdefinierte_Indikatoren/MetaTrader4/Experts/SqIndicatorValuesExportEA.mq4

 

Fügen Sie diesen EA zu Ihrem MetaTrader hinzu, modifizieren Sie ihn so, dass er den Wert Ihres Indikators berechnet und ausgibt, und lassen Sie ihn im MT4 StrategyTester auf beliebigen Daten laufen - für einen optimalen Test sollte er auf mindestens 1000 Bars laufen.

 

Da Envelopes zwei Ausgabepuffer hat, müssen wir es zweimal ausführen - einmal für den oberen und einmal für den unteren Puffer.

Hier ist ein geänderter Code dieses Hilfsexportskripts, das den Hüllkurvenindikator berechnet:

//+------------------------------------------------------------------+
//|                                   SQ_IndicatorValuesExportEA.mq4 |
//|                                                                  |
//|                    EA to export indicator values from MetaTrader |
//|                Output to: /{Data folder}/tester/files/******.csv |
//+------------------------------------------------------------------+

#property copyright "Copyright © 2019 StrategyQuant"
#property link      "https://strategyquant.com"

string currentTime = "";
string lastTime = "";

//+------------------------------------------------------------------+

int start() {
   currentTime = TimeToStr(Time[1], TIME_DATE|TIME_MINUTES|TIME_SECONDS);
   if(currentTime == lastTime) {
      return(0);
   }
   
   double value;

   // change the file name below
   string fileName = "Envelopes_14_0_0_0_0.1_upper.csv";

   int handle = FileOpen(fileName, FILE_READ | FILE_WRITE, ";");
   if(handle>0) {
      FileSeek(handle,0,SEEK_END);

      // here is the indicator value 
      value = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0.1 , 1 , 1); // upper value
      //value = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0.1 , 2 , 1); // lower value
      
      FileWrite(handle, TimeToStr(Time[1], TIME_DATE|TIME_MINUTES|TIME_SECONDS), Open[1], High[1], Low[1], Close[1], Volume[1], value);
      FileClose(handle);
   }

   lastTime = currentTime;
   return(0);
}

er berechnet den Envelopes-Inikator auf MT4, indem er seine interne Methode iEnvelopes() mit den richtigen Parametern aufruft.

Bitte beachten Sie, dass die Parameter konfiguriert werden können - Sie müssen nicht die Standardparameter verwenden. Es ist eine gute Praxis, die Parameterwerte auch in den Namen der Ausgabedatei aufzunehmen - wie in unserem Fall "Envelopes_14_0_0_0_0.1_upper.csv", so dass wir wissen, dass sie mit diesen Parametern erzeugt wurde.

Jetzt können wir dieses Skript zwei Mal in MT Tester ausführen:

Wenn es fertig ist, sollte es eine Datendatei mit den berechneten Indikatorwerten sowie den Eröffnungs-, Hoch-, Tief- und Schlusskursen für jeden Balken erstellen. Die Datei wird in MetaTrader4 gespeichert -> {Datenordner}/Tester/Dateien/Ihre_DATEI_NAME.csv


Dort sollten zwei Dateien zu sehen sein:
Envelopes_14_0_0_0_0.1_upper.csv
Envelopes_14_0_0_0_0.1_lower.csv

 

Kopieren Sie die berechneten Datendateien an den richtigen Ort, damit SQ sie finden kann


Kopieren Sie diese Dateien in einen Ordner
{SQ-Installation}/Tests/Indikatoren/MetaTrader4

Erstellen Sie diesen Ordner, wenn er noch nicht existiert. SQ Indicaotrs Tester sucht in diesem Ordner nach Dateien.

Nachdem wir nun die Datendatei vorbereitet haben, können wir einen Test in StrategyQuant starten.

 

Konfigurieren und Ausführen von Indikatortests in SQ

Wechseln Sie zum Code-Editor und klicken Sie in der Symbolleiste auf Testindikatoren.

Es öffnet sich der Dialog Indicator Tester, klicken Sie auf Neuen Test hinzufügen. Fügen Sie dem Test Hüllkurven-Indikatoren sowohl für den oberen als auch für den unteren Ausgang hinzu.

Sie sehen das in der Tabelle wie folgt. Als Letztes müssen wir noch die Name der Testdateis entsprechend den Namen der im vorherigen Schritt erstellten Testdatendateien, und optional auch Test-Parameterwenn Sie andere als die Standardeinstellungen verwendet haben:

Danach klicken Sie auf Start um die Tests durchzuführen.

Im Idealfall sind die Tests erfolgreich und die in SQ berechneten Werte stimmen mit den in MT4 berechneten Werten überein:

Wenn etwas nicht funktioniert, gibt es Unterschiede zwischen den Werten von SQ und MT4. Sie können auf die Unterschiede klicken, um sie in der Liste zu sehen:

Wenn der Test fehlschlägt, überprüfen Sie zunächst, ob die in MT4 generierten Testdaten dieselben Indikatorparameter verwenden, da es sich um einen Fehler handeln kann.

Wenn die Testdaten korrekt sind, dann stimmt etwas mit der SQ-Implementierung Ihres Indikators nicht - er funktioniert anders als sein MT4-Gegenstück und muss korrigiert werden.

 

Hinzufügen der Übersetzung des Indikatorblocks in die Sprache der Zielplattform

Jetzt funktioniert der Indikator korrekt in StrategyQuant. Sie können ihn verwenden, um einige darauf basierende Strategien zu generieren, oder ihn im AlgoWizard einsetzen. Aber wir sind noch nicht fertig.

Wenn Sie sich den Quellcode Ihrer Strategie ansehen, werden Sie eine Fehlermeldung wie diese sehen:

Das bedeutet, dass StrategyQuant bei der Generierung von Pseudo Code / MT4 / MT5 oder Tradestation Code keine Vorlage finden konnte, die den Block vom internen SQ XML Format in die Sprache der Zielplattform übersetzt.


Bisher haben wir einen Code für Envelopes erstellt, der innerhalb von StrategyQuant berechnet werden kann. Aber StrategyQuant weiß nicht, wie man diesen Indikator in einen Code in Ihrer Handelsplattform übersetzt - es hängt von der Plattform selbst ab.

In StrategyQuant werden die generierten Strategien intern im XML-Format gespeichert. Wenn Sie zu Strategy XML wechseln und nach dem Indikator Envelopes suchen, werden Sie sehen, dass er wie folgt gespeichert ist:

<Item key="IsGreater" name="(&gt;) Is greater" display="#Left# &gt; #Right#" mI="Comparisons" returnType="boolean" categoryType="operators">
  <Block key="#Left#">
    <Item key="Envelopes" name="(EP) Envelopes" display="Envelopes(#Period#)[#Shift#]" help="Envelopes help text" mI="Envelopes" returnType="price" categoryType="indicator">
      <Param key="#Chart#" name="Chart" type="data" controlType="dataVar" defaultValue="0">0</Param>
      <Param key="#MA_Period#" name="MA _ Period" type="int" defaultValue="14" genMinValue="-1000003" genMaxValue="-1000004" paramType="period" controlType="jspinnerVar" minValue="2" maxValue="1000" step="1" builderStep="1">14</Param>
      <Param key="#MA_Moved#" name="MA _ Moved" type="int" defaultValue="0" controlType="jspinnerVar" minValue="0" maxValue="10" step="1" builderStep="1">0</Param>
      <Param key="#MA_Method#" name="Method" type="int" defaultValue="0" controlType="combo" values="Simple=0,Exponential=1,Smoothed=2,Linear weighted=3" builderStep="1">0</Param>
      <Param key="#Applied_Price#" name="Applied _ Price" type="int" defaultValue="0" controlType="combo" values="Close=0,Open=1,High=2,Low=3,Median=4,Typical=5,Weighted=6" builderStep="1">0</Param>
      <Param key="#Deviation#" name="Deviation" type="double" defaultValue="0.1" controlType="jspinnerVar" minValue="0.01" maxValue="10" step="0.01" builderMinValue="0.05" builderMaxValue="1" builderStep="0.05">0.1</Param>
      <Param key="#Shift#" name="Shift" type="int" defaultValue="1" controlType="jspinnerVar" minValue="0" maxValue="1000" genMinValue="-1000001" genMaxValue="-1000002" paramType="shift" step="1" builderStep="1">1</Param>
      <Param key="#Line#" name="Line" type="int" controlType="combo" values="Upper=0,Lower=1" defaultValue="0">0</Param>
    </Item>
  </Block>
  <Block key="#Right#">
    <Item key="Number" name="(NUM) Number" display="#Number#" help="Number constant" mI="Other" returnType="number" categoryType="other" notFirstValue="true">
      <Param key="#Number#" name="Number" type="double" defaultValue="0" controlType="jspinner" minValue="-999999999" maxValue="999999999" step="1" builderStep="1">0</Param>
    </Item>
  </Block>
</Item>

Dies ist nur ein Teil der Strategie-XML, die den Vergleich der Umschläge mit der Nummer enthält. Beachten Sie, dass es Blöcke () verwendet IstGrößer, Briefumschläge, Nummer.

SQ sucht nach Vorlagen, um jeden der XML-Blöcke in die Sprache der Zielplattform zu übersetzen. Schablonen für IstGrößer und Nummer sind standardmäßig im System vorhanden, aber es fehlt eine Vorlage für Briefumschläge.

 

Vorlagen werden gespeichert in Code Teilbaum. Dort gibt es für jede unterstützte Plattform einen eigenen Ordner und innerhalb dieses Ordners einen Unterordner /Blöcke die Vorlagen für jeden Baustein enthält.

 

Vorlagendateien haben .tpl Erweiterung und sie sind sehr einfach. Sie verwenden die Freemarker Template Engine (https://freemarker.apache.org), um XML des Indikators in den Code der Zielplattform zu übersetzen.

Beachten Sie, dass Vorlagen NICHT enthalten Code zur Berechnung des Indikators auf der Zielplattform, sie enthalten Code zur ANRUFEN den Indikator.

Wenn Sie es überprüfen, werden Sie sehen, dass es keine Vorlage Envelopes.tpl gibt, daher zeigt der Quellcode eine Meldung, dass die Vorlage dafür fehlt.

Hinzufügen einer Pseudocode-Vorlage für einen neuen Block

Wenn Sie sich Ihr Envelopessnippet im Navigator-Fenster ansehen, sehen Sie ein Fehlersymbol, und wenn Sie mit der Maus darüberfahren, sehen Sie die Fehlermeldung - es fehlt der Vorlagencode für jede Zielplattform.

 

Am einfachsten ist es, mit der rechten Maustaste auf die Datei Envelopes.java zu klicken, um das Pull-Down-Menü zu öffnen und dort
Aktion wählen
Fügen Sie alle fehlenden.

Dadurch werden Standardvorlagen für alle Zielplattformen hinzugefügt.
Wenn Sie zu Code -> Pseudocode -> Blöcke gehen, werden Sie sehen, dass die Vorlage hinzugefügt wurde Umschläge.tpl mit einigen Standardinhalten.

Wie Sie sehen können, ist die Vorlage recht einfach und besteht in der Regel aus nur einer Zeile.

 

Da die Vorlage nun vorhanden ist, können Sie den Quellcode Ihrer Strategie erneut überprüfen.


Sie können sehen, dass der Quellcode erstellt wurde, aber er ist nicht wirklich korrekt. 

Sie zeigt Briefumschläge(Hauptkarte, , , 1) anstelle der echten Envelopes-Parameter. Das liegt daran, dass die Datei Envelopes.tpl mit einer Standardvorlage erstellt wurde und nicht die echten Parameter der Indikatoren verwendet.

Wenn Sie den Code PseudoCode/blocks/Envelopes.tpl überprüfen, werden Sie sehen, dass er wie folgt lautet:

Umschläge( , , )

Die Methoden printInput und printShift sind Standardmethoden, um Dateneingabe- und Verschiebungswerte zu drucken, und sie funktionieren standardmäßig korrekt, da jeder Indikator eine Diagramm-/Dateneingabe und eine Verschiebung hat.

Aber wir haben keine Parameter namens Param1 und Param2 in unserem Indikator. 

Stattdessen haben wir dort fünf andere Parameter: MA_Period, MA_Moved, MA_Method, Applied_Price, Deviation.

 

Wir ändern die Vorlage also wie folgt:

Envelopes( , , , , )

 

Wenn Sie sich nun den Pseudocode ansehen, werden Sie sehen, dass er mit den richtigen Parameterwerten angezeigt wird:

Wie Sie sehen können, ist das Drucken eines Parameters in einer Vorlage sehr einfach - Sie müssen nur die Methode verwenden:

<@printParam block “#PARAMETER_NAME#” />

wobei PARAMETER_NAME ist der Name der Parametervariablen aus dem Java-Code.


Es gibt noch eine Sache, die verbessert werden kann - die Parameter MA_Methode und Angewandter_Preis werden als Zahlen angezeigt - wir würden sie gerne als Text anzeigen, damit wir wissen, welche Werte ausgewählt wurden.

Zu diesem Zweck können wir die Methode verwenden:

<@printParamOptions block “# PARAMETER_NAME #” “0=Option1,1=Option2,3=Option3” />


Mit dieser Methode wird der Zahlenwert in die Option auf der Grundlage ihrer Nummer übersetzt.

Um nicht mit unwichtigen Informationen überschüttet zu werden, brauchen wir den Wert des Parameters MA_Moved im Pseudocode überhaupt nicht anzuzeigen. Wir können ihn einfach aus der Vorlage löschen.

Unser endgültiger PseudoCode-Vorlagencode für Envelopes in PseudoCode wird also wie folgt aussehen:

Envelopes( , , , )

und es wird eine Ausgabe wie diese erzeugt:

 

Hinzufügen der MetaTrader 4-Vorlage für den neuen Block

Im vorherigen Schritt haben wir eine Pseudo-Code-Vorlage für unseren Envelopes-Indikator hinzugefügt, so dass wir die Strategieregeln im Pseudo-Code sehen können.

Wir müssen diesen Schritt für jede Zielplattform wiederholen, auf der wir unsere Strategie anwenden wollen. 

Lassen Sie uns also die Vorlage für MetaTrader MQL festlegen. In MetaTrader gibt es zwei Möglichkeiten:

  • Entweder ist der Indikator in MetaTrader integriert und wir können ihn dann über seinen MQL-Funktionsaufruf aufrufen,
  • oder es handelt sich um einen benutzerdefinierten Indikator und wir müssen ihn mit dem iCustom MQL-Aufruf aufrufen.

Wir zeigen beide Möglichkeiten, sie unterscheiden sich nur geringfügig im Code der Vorlage.

 

Erste Möglichkeit - Indikator ist in MetaTrader eingebaut

In diesem Fall finden Sie den Indikator in der Liste der verfügbaren Indikatoren im MT4-Navigator, und Sie
finden Sie auch die Methode zum Aufrufen in der MQL-Referenzanleitung:

Aus der MQL-Dokumentation wissen wir, dass wir beim Aufruf dieses Indikators die Funktion iUmschläge() mit den richtigen Parametern.

Wir öffnen also die Datei Code / MetaTrader4 / blocks / Envelopes.tpl und ändern sie wie folgt:

iEnvelopes(, , , , , , +1, )

Wir haben die Methode umbenannt und die richtigen Parameter hinzugefügt. Methoden printInput und printShift erzeugen standardmäßig eine korrekte Ausgabe.

Beachten Sie einen weiteren Parameter - Leitung. Da Umschläge zwei Zeilen haben (obere und untere), können Sie auch beim Aufruf von iEnvelopes angeben, welchen Wert Sie abrufen möchten - es ist der 8. Modusder Zeilenindex ist.

Dieser Parameter in MQL ist 1 für Upper, oder 2 für Lower.

Leitung Parameter wird ebenfalls standardmäßig von SQ erstellt - überprüfen Sie einfach das XML dieses Blocks. Er ist jedoch nullbasiert, und der Zeilenindex hängt von der Reihenfolge der in der Java-Klasse definierten @Output-Variablen ab. In SQ ist also 0 = Upper, 1=Lower. Um die gleichen Werte wie in MT4 zu erhalten, müssen wir 1 zum Zeilenwert hinzufügen.

 

Wenn wir den MT4-Quellcode aufrufen, sehen wir, dass er diese Ausgabe erzeugt:

Welches ist der richtige Weg, um den Hüllkurven-Indikator in MQL aufzurufen? .

 

Zweite Möglichkeit - es ist ein benutzerdefinierter (externer) Indikator für MetaTrader

Was aber, wenn der Indikator nicht in Metatrader integriert ist? Die Situation ist nur geringfügig komplizierter.
Nehmen wir als Beispiel an, dass der Envelopes-Indikator in MT4 nicht existiert und wir ihn als benutzerdefinierten Indikator verwenden müssen.


Laden Sie zunächst den Indikator für Umschläge von diesem Link herunter: https://www.mql5.com/en/code/7975
 und speichern Sie sie in einer Datei unter {MT4} -> Datenordner/MQL/Indikatoren/Umschläge.mq4

Auf diese Weise wird er im MetaTrader verfügbar und kann verwendet und aufgerufen werden. 

 

Benutzerdefinierte Indikatoren werden mit der MQL-Funktion iCustom aufgerufen:

Der korrekte Aufruf des benutzerdefinierten Envelopes-Indikators in MQL würde also lauten:

iCustom(Symbol, Zeitrahmen, "Hüllkurven", MA_Periode, MA_Bewegt, MA_Methode, Angewandter_Preis, Abweichung, 1, Verschiebung)

um die obere Zeile zu erhalten, und

iCustom(Symbol, Zeitrahmen, "Hüllkurven", MA_Periode, MA_Bewegt, MA_Methode, Angewandter_Preis, Abweichung, 2, Verschiebung)

um die untere Zeile zu erhalten.

Wir definieren unsere Vorlage wie folgt:

iCustom(, "Hüllkurven", , , , , , +1, )

 

was wiederum korrekten MQL-Code erzeugt, der einen benutzerdefinierten Indikatoraufruf verwendet:

 

Der einzige Unterschied zur vorherigen Option besteht darin, dass wir nicht die vordefinierte MQL-Methode iEnvelopes verwenden, sondern eine allgemeine Methode iCustom, mit der wir jeden externen benutzerdefinierten Indikator aufrufen können.

 

 

War dieser Artikel hilfreich? Der Artikel war nützlich Der Artikel war nicht nützlich

Abonnieren
Benachrichtigen Sie mich bei
2 Kommentare
Älteste
Neuestes Meistgewählt
Inline-Rückmeldungen
Alle Kommentare anzeigen
dorsler
dorsler
26. 10. 2020 4:20 pm

Danke Marc
Ich schaue mir gerade den Umschlagindikator an und versuche, diesen aus dem Artikel, den Sie geschrieben haben, in SQ zu ziehen
https://strategyquant.com/doc/programming-sq/adding-envelopes-indicator-step-by-step
Die unten generierte CSV-Datei liefert nur eine einzige Datei in der MT4-Tester-Datei, wenn der Indikator den Test durchgeführt hat.
// Ändern Sie den Dateinamen wie folgt  
string fileName = “Envelopes_14_0_0_0_0.1_upper.csv”;
Kann SQ trotzdem die oberen und unteren Werte lesen oder ist eine weitere Codezeile erforderlich?
Dieser Indikator gefällt mir sehr gut und ist eine gute Ergänzung für die Testbibliothek.
Danke
Dave

tomas262
tomas262
Antwort an  dorsler
30. 10. 2020 7:39 Uhr

Sie müssen 2 separate CSV-Dateien exportieren. Eine mit den Werten für den oberen Umschlag unter Verwendung des Codes value = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0 , 0.1 , 1 , 1); und dann exportieren Sie eine weitere CSV-Datei mit den Werten für den unteren Umschlag unter Verwendung des Codes value = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0.1 , 2 , 1); Beachten Sie die geänderten Werte für die Nummer 2, die an der vorletzten Position in der zweiten Codezeile verwendet werden. Sie haben jetzt also 2 CSV-Dateien: Envelopes_14_0_0_0_0.1_upper.csv und Envelopes_14_0_0_0_0.1_lower.csv... Weiterlesen "

Zuletzt geändert 3 Jahre zuvor von tomas262