Dokumentation

Anwendungen

Zuletzt aktualisiert am 18. 5. 2020 von Mark Fric

ForceIndex-Indikator

Im Gegensatz zu SQ3 erlaubt es SQX, das Programm durch die Erstellung eigener Indikatoren und Bausteine zu erweitern - ähnlich wie Sie neue Indikatoren zu normalen Handelsplattformen wie MetaTrader 4/5, Tradestation und so weiter hinzufügen können.

Wir werden diesen Prozess Schritt für Schritt durchgehen und alles Notwendige erklären.

Am Ende haben wir einen neuen benutzerdefinierten Indikator zu StrategyQuant hinzugefügt und Sie können ihn in die Liste der Bausteine für die Erstellung von Strategien aufnehmen.

Wir verwenden Kraftindex Indikator ein Beispiel. Dieser Indikator ist bereits in Metatrader eingebaut, seinen Quellcode finden Sie hier: https://www.mql5.com/en/code/8013

So sieht der Indikator im Diagramm aus:

 

Um einen neuen Indikator zu SQ X hinzuzufügen, sind vier Schritte zu beachten:

  1. Hinzufügen eines neuen Indikator-Bausteins
  2. (Optional, empfohlen) Testen des neuen Indikators in SQ X im Vergleich zu den Daten aus MT
  3. (Optional, empfohlen) Hinzufügen neuer Signalblöcke auf der Grundlage des Indikators
  4. Hinzufügen der Übersetzung des Indikatorblocks in die Sprache der Zielplattform

 

Schritt 1 - Erstellen eines neuen benutzerdefinierten Indikators im Code-Editor

Der erste Schritt besteht darin, unseren Indikator im Code-Editor zu erstellen. StrategyQuant verwendet intern die Programmiersprache Java, und benutzerdefinierte Indikatoren müssen in Java programmiert werden.

Sie können Ihren MQL-Code nicht einfach kopieren und in StrategyQuant einfügen, das würde nicht funktionieren. Sie müssen den Indikator in Java-Sprache umschreiben.

Zuerst müssen wir den Code-Editor öffnen:

Im Code-Editor können Sie Snippets erstellen, bearbeiten und ändern. Wir werden also ein neues Snippet für unseren neuen Indikator erstellen.

Im Code-Editor klicken wir auf die Schaltfläche Neu erstellen in der oberen Symbolleiste.

Daraufhin wird ein Dialog geöffnet, in dem wir unser neues Snippet benennen und seinen Typ auswählen können. Wir nennen es "ForceIndex" und wählen Sie Indikator als Snippet-Typ.

Nachdem wir auf OK geklickt haben, wird ein neuer Ordner ForceIndex unter Schnipsel -> SQ -> Blöcke -> Indikatoren und eine neue Schnipseldatei ForceIndex.java in diesem Ordner.

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 ForceIndex-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). So wird unser neuer Indikator in der Methode OnBlockEvaluate() aufgerufen.

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

Paket SQ.Blocks.Indicators.ForceIndex;
 
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) ForceIndex ", display="ForceIndex (#Period#)[#Shift#]", returnType = ReturnTypes.Price)
@Help("ForceIndex Hilfetext")

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 wird ForceIndex NICHT im Preisdiagramm angezeigt, daher ist sein Rückgabetyp Zahl und nicht Preis. Wir werden dies im nächsten Schritt ändern.

@Parameter public DataSeries Input;
 
@Parameter(defaultValue = "10", isPeriod = true, minValue=1, maxValue=10000, step=1) public int Period;
 
@Output public Datenreihe 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() {...}

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 zur Implementierung unseres ForceIndex-Indikators vorgenommen werden müssen.

 

Schritt 2 - Modifizierung der generierten Standardvorlage und Implementierung des Indikators

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

 

seine @BuildingBlocks-Anmerkung aktualisieren

Wir werden die Anmerkung dieses Indikators wie folgt aktualisieren:

@BuildingBlock(name="(FI) ForceIndex ", display="ForceIndex (#Nbr_Periods#, #Multiplier)[#Shift#]", returnType = ReturnTypes.Number)

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.

Wir haben auch returnType auf Number geändert, weil dieser Indikator Zahlen berechnet, die in einem separaten Diagramm angezeigt werden, und nicht einen Preiswert ausgibt.

 

Definieren Sie ForceIndex-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 ForceIndex MQL-Quellcode ansehen, werden Sie sehen, dass er 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 Chart;


ChartData
ist ein Objekt, das das gesamte Diagramm darstellt - Sie haben Zugang zu den Preisen Open, High, Low, Close, Volume im gegebenen Diagramm.


Kurzer Hinweis - Auswahl des richtigen Typs für die Eingangsdatenvariable :
Wenn der Indikator aus einem Preis berechnet wird, verwenden Sie DataSeries.
Wenn er aus mehreren Preisen berechnet wird - z. B. Hoch, Tief, Schluss, usw. - verwenden Sie ChartData.

Dann gibt es einen Parameter Period, den wir ebenfalls unverändert lassen können:

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

Der dritte Parameter ist die Methode des gleitenden Durchschnitts:

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

Dies ist etwas komplizierter, da wir eine Auswahlliste (Combobox-Steuerelement) als Bearbeitungssteuerung für diesen Parameter definieren. Bei der Bearbeitung im Assistenten kann der Benutzer also aus den vordefinierten Werten wählen.

Der letzte Parameter ist der angewandte Preis - der Preis, der für die Berechnung des gleitenden Durchschnitts verwendet werden soll:

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

Beachten Sie, dass wir einige Attribute in der @Parameter Bemerkung:

  • defaultValue legt den Standardwert für diesen Parameter fest
  • isPeriod=true teilt SQ mit, dass es sich bei diesem Parameter um eine Periode handelt - diese werden auf besondere Weise gehandhabt. In der Builder-Konfiguration können Sie den Mindest- und Höchstwert für Perioden konfigurieren, daher muss SQ wissen, welche Parameter Perioden sind.
  • minWert, maxWert, Schritt sind Minimal- und Maximalwerte, die für diesen Parameter während des Zufallsgenerierungsprozesses erzeugt werden.

Definieren Sie ForceIndex-Ausgaben

Der ForceIndex-Indikator hat nur einen Ausgang, daher können wir ihn auch unverändert lassen:

@Output public DataSeries Value;

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 ForceIndex MQL-Code anschauen, werden Sie sehen, dass er ziemlich einfach ist:

int start() {
  int nLimit;
  int nCountedBars=IndicatorCounted();

  //---- unzureichende Daten
  if(BarsExtForcePeriod) nCountedBars--;
  nLimit=Balken-nGezählteBalken;

  //---- Kraftindex gezählt
  for(int i=0; i<nLimit; i++)
    ExtForceBuffer[i] = Volume[i] * (iMA(NULL,0,ExtForcePeriod,0,ExtForceMAMethod,ExtForceAppliedPrice,i) - iMA(NULL,0,ExtForcePeriod,0,ExtForceMAMethod,ExtForceAppliedPrice,i+1));

  //---- erledigt
  return(0);
}

Die Analyse des Algorithmus zeigt, dass der Kraftindexwert bei einer bestimmten Kerze wie folgt berechnet wird:

ForceIndex[i] = Volumen[i] *(MovAvg(Zeitraum, MAMethode, AngewandterPreis)[i] - MovAvg(Zeitraum, MAMethode, AngewandterPreis)
[i+1]

 

Wir können es in Java wie folgt implementieren:

protected void OnBarUpdate() throws TradingException {
    DataSeries computedFrom = Chart.getSeries(AppliedPrice);
 
    double indiValue = Chart.Volume.get(0) * (Indicators.MA(computedFrom, Period, MAMethod).Value.get(0) - Indicators.MA(computedFrom, Period, MAMethod).Value.get(1));
 
    Value.set(0, indiValue);
} 

In diesem Fall ist der Indikator recht einfach und seine Berechnung erfordert praktisch nur eine Zeile in StrategyQuant.

Zuerst erhalten wir den Preis, aus dem wir den Indikator berechnen - durch den Aufruf Chart.getSeries(AngewandterPreis).
Dann berechnen wir den neuen Indikatorwert als Differenz des Durchschnitts aus aktuellem und vorherigem Kurswert multipliziert mit dem aktuellen Volumen.

 

Das ist alles, wenn wir jetzt auf Kompilieren und starten Sie dann SQ neu. Sie sehen dann unseren neuen ForceIndex-Indikator im Abschnitt Random Indicators Signals.

Vollständiger Quellcode unseres neuen Indikators:

Paket SQ.Blocks.Indicators.ForceIndex;

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

import SQ.Internal.IndicatorBlock;

/**
 * Name des Indikators, wie er in der Benutzeroberfläche angezeigt wird, und sein Rückgabetyp.
 * Mögliche Rückgabetypen:
 * ReturnTypes.Price - Indikator wird auf dem Preisdiagramm gezeichnet, wie SMA, Bollinger Bands usw.
 * ReturnTypes.Price - Indikator wird auf einem separaten Chart gezeichnet, z.B. CCI, RSI, MACD
 * ReturnTypes.PriceRange - Indikator ist eine Preisspanne, wie ATR.
 */
@BuildingBlock(name="(FI) ForceIndex ", display="ForceIndex (#Period#)[#Shift#]", returnType = ReturnTypes.Number)
@Help("ForceIndex Hilfetext")
public class ForceIndex extends IndicatorBlock {

  @Parameter
  public ChartData Chart;

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

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

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

  @Output
  public DataSeries Value;

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

  /**
   * Diese Methode wird bei jeder Balkenaktualisierung aufgerufen, und hier wird der Indikatorwert errechnet.
   *
   * Anders als in MT4 werden die Indikatorwerte nicht für mehrere Balken in einer Schleife berechnet,
   * müssen Sie den Wert nur für den letzten (aktuellen) Balken berechnen.
   * Die Trading Engine kümmert sich darum, diese Methode für jeden Balken im Diagramm aufzurufen.
   *
   * Der tatsächliche Balken, für den der Indikatorwert berechnet wird, wird in der Variablen CurrentBar gespeichert.
   * Wenn der Wert 0 ist, bedeutet dies, dass es sich um den allerersten Balken des Charts handelt.
   */
  @Override
  protected void OnBarUpdate() throws TradingException {
    	double indiValue;

    	indiValue = Chart.Volume.get(0) * (Indicators.MA(Chart.Close, Period, MAMethod).Value.get(0) - Indicators.MA(Chart.Close, Period, MAMethod).Value.get(1));

      	Value.set(0, indiValue);
  }

}

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

Abonnieren
Benachrichtigen Sie mich bei
5 Kommentare
Älteste
Neuestes Meistgewählt
Inline-Rückmeldungen
Alle Kommentare anzeigen
Pieter Kotzee
Pieter Kotzee
21. 6. 2020 8:56 am

Hallo. Ich habe den Code genau wie oben angegeben kopiert, erhalte aber 2 Fehler, wenn ich versuche zu kompilieren. Beide sind in Zeile 55 und beide haben die gleiche Beschreibung. Die eine ist Spalte 54 und die andere ist 114:
Symbol kann nicht gefunden werden Symbol: Methode MA(com.strategyquant.datalib.Dataseries,int,int) Ort: Variable Indicators vom Typ SQ>Internal.Indicators
 

Zuletzt geändert 3 Jahre zuvor von Pieter Kotzee
tomas262
tomas262
Antwort an  Pieter Kotzee
29. 6. 2020 10:06 Uhr

Die MA-Methode ist nicht Teil des Pakets. Bitte finden Sie sie hier https://strategyquant.com/codebase/forceindex/

Emanuel2
21. 9. 2021 7:37 Uhr

Vielen Dank, dieses Beispiel ist sehr hilfreich

Matthäus Nowlis
Matthäus Nowlis
26. 2. 2022 7:09 Uhr

Ich konnte erfolgreich den Java-Code für den Force Index Indikator und die Signalblöcke hinzufügen. Es kompiliert erfolgreich ohne Fehler. Wenn ich jedoch Strategien in StrategyQuant mit dem Indikator generiere, erhalte ich eine Fehlermeldung, weil die (MT4, MT5, Pseudocode, etc.) Codevorlagen fehlen. Es heißt im Strategiecode:

Fehler! Einer oder mehrere Blöcke, die die Strategie verwendet, sind nicht implementiert (MT4, MT5, Pseudocode, etc)

Vorlageneinbindung fehlgeschlagen (für Parameterwert "blocks/ForceIndex.tpl"):
Vorlage nicht gefunden für Name "PseudoCode/Blöcke/ForceIndex.tpl".
Der Name wurde interpretiert von diese TemplateLoader: MultiTemplateLoader(loader1 = FileTemplateLoader(baseDir="C:\StrategyQuantX\internal\extend\Code"), loader2 = FileTemplateLoader(baseDir="C:\StrategyQuantX\user\extend\Code")).

—-
FTL-Stapelverfolgung (“~” bedeutet nistplatzbezogen):
    - Gescheitert bei: 1TP5Einschließen "Blöcke/" + blockKey + ".tpl"  [in Vorlage "PseudoCode/pseudoBlocks.inc" in Makro "printBlock" auf der Linie 122Spalte 20]
    - Erreicht durch: @printBlock block?children[0], Verschiebung [in Vorlage "PseudoCode/pseudoBlocks.inc" in Makro "printBlock" auf der Linie 107Spalte 9]
    - Erreicht durch: @printBlock c, shift [in Vorlage "PseudoCode/pseudoBlocks.inc" in Makro "printBlockChild" auf der Linie 148Spalte 14]
    - Erreicht durch: @printBlockChild-Block, "#Links#"  [in Vorlage "PseudoCode/Blöcke/IsGreater.tpl" auf der Linie 1Spalte 2]
    - Erreichbar über: #include "Blöcke/" + blockKey + ".tpl"  [in Vorlage "PseudoCode/pseudoBlocks.inc" in Makro "printBlock" auf der Linie 122Spalte 20]
    - Erreicht durch: @printBlock block?children[0], Verschiebung [in Vorlage "PseudoCode/pseudoBlocks.inc" in Makro "printBlock" auf der Linie 107Spalte 9]
    - Erreicht durch: @printBlock block [in Vorlage "PseudoCode/Blöcke/AND.tpl" auf der Linie 5Spalte 38]
    - Erreichbar über: #include "Blöcke/" + blockKey + ".tpl"  [in Vorlage "PseudoCode/pseudoBlocks.inc" in Makro "printBlock" auf der Linie 122Spalte 20]
    - Erreicht durch: @printBlock block?children[0], Verschiebung [in Vorlage "PseudoCode/pseudoBlocks.inc" in Makro "printBlock" auf der Linie 107Spalte 9]
    ... (Hatte 18 mehr, versteckt für tersen) (Versteckt 4 “~” Zeilen für Knappheit)

Wie füge ich die Code-Vorlagen für die jeweiligen Strategie-Code-Sprachen hinzu?

tomas262
Verwaltung
Antwort an  Matthäus Nowlis
28. 2. 2022 1:53 Uhr

Sie können stattdessen versuchen, das Paket von dieser Seite zu importieren https://strategyquant.com/codebase/forceindex/

Der Pseudo-Code und MT4 sind implementiert und arbeiten für mich, wenn getestet