Documentation

Applications

Dernière mise à jour le 18. 5. 2020 par Mark Fric

Indicateur d'enveloppes

Dans cet exemple, nous ajouterons Enveloppes à StrategyQuant X.

Le code MQL de cet indicateur est disponible ici : https://www.mql5.com/en/code/7975

Cet indicateur est également déjà intégré dans MetaTrader, vous pouvez l'appeler à partir du code MQL en utilisant la méthode iEnvelopes. Voici comment l'indicateur se présente sur le graphique :

Il y a quelques étapes à suivre pour ajouter un nouvel indicateur à SQ X :

  1. Ajout d'un nouvel indicateur 
    nous allons créer un nouvel extrait d'indicateur et mettre à jour son code pour calculer l'indicateur Enveloppes.
  2. (Facultatif, recommandé) Test du nouvel indicateur dans SQ X par rapport aux données de MT
    pendant ou après la mise en œuvre, nous devrions comparer les valeurs de l'indicateur calculées par SQ avec celles calculées par MQL - pour nous assurer que l'indicateur est mis en œuvre correctement
  3. Ajout de la traduction du bloc d'indicateurs dans la langue de la plateforme cible
    fonctionne maintenant dans SQ, mais les stratégies utilisant cet indicateur ne le font pas. Nous devons ajouter des modèles pour générer le code source de cet indicateur pour chaque plateforme de trading que nous voulons supporter.

 

Ajout d'un nouveau snippet d'indicateur

Pour ce faire, nous ouvrirons Éditeur de code.

Là, nous cliquons sur Créer un nouveau dans la barre d'outils

et dans la boîte de dialogue contextuelle, nous saisissons 'Enveloppes' comme nouveau nom d'indicateur et laisser Indicateur comme type d'extrait.

Cliquez sur OKet un nouvel indicateur sera créé.

 

Vous pouvez le voir dans l'arbre de navigation, dans Snippets -> SQ -> Blocks -> Indicators. Il a son propre dossier nommé 'Envelopes', et le code de l'indicateur se trouve dans le fichier Enveloppes.java

La convention dans StrategyQuant est que chaque indicateur est dans son propre dossier - c'est parce que plus tard nous pourrions vouloir créer des signaux pour cet indicateur, et tous les snippets liés seront dans le même dossier.

Cette action a créé un nouveau fichier pour notre indicateur Envelopes et l'a ouvert dans l'éditeur. Vous pouvez voir que l'indicateur est une classe et qu'il a déjà une certaine structure.

 

Chaque indicateur est étendu à partir de la classe IndicatorBlock et doit implémenter une méthode :

  • OnBarUpdate() - où la valeur de l'indicateur est calculée et stockée dans l'un des tampons de sortie. Elle est appelée pour chaque barre du graphique.

 

Lorsque vous vérifierez le code source, vous devriez remarquer certaines choses.

Tout d'abord, les snippets dans StrategyQuant utilisent beaucoup d'annotations - @Parameter, @Output, @BuildingBlock - ces annotations sont utilisées pour déclarer une propriété spéciale d'une variable ou d'une classe donnée - que la variable est un paramètre public ou une valeur de sortie, ou que la classe est un bloc d'indicateur.

Deuxièmement, une fois que vous avez créé et compilé un indicateur, vous pouvez l'appeler à partir d'autres méthodes ou indicateurs en utilisant la fonction Indicators.YourIndicator(YourIndicatorParameters). C'est ainsi qu'un indicateur peut être appelé à partir d'un autre - nous l'utiliserons également dans les enveloppes pour appeler les indicateurs de moyenne mobile, nous y reviendrons plus tard.

 

Nous allons parcourir pas à pas le code source de la classe d'indicateur par défaut créée à partir d'un modèle :

package SQ.Blocks.Indicators.Envelopes;

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

import SQ.Internal.IndicatorBlock;

il s'agit de la déclaration Java standard d'un paquet et de l'importation des classes nécessaires - celles que nous utilisons dans notre propre classe.


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

Définition annotée de notre classe d'indicateurs, indiquant au système qu'il s'agit d'un bloc de construction avec un nom donné.

  • nom est ce qui est affiché dans l'interface utilisateur lors de la sélection des blocs de construction.
  • affichage est ce qui est affiché dans l'assistant avec les paramètres. Vous pouvez contrôler quels paramètres sont affichés et à quel endroit.
  • type de retour est un type d'indicateur, il indique quel type de valeur cet indicateur calcule. Il est utilisé pour que StrategyQuant sache quels types doivent être comparés avec quoi. Par exemple, il ne comparera pas l'indicateur CCI (qui renvoie un nombre) avec les bandes de Bolinger (qui renvoient un prix).

 

Un indicateur peut avoir trois types de retour :

  • Prix - L'indicateur calcule le prix et est affiché sur le graphique des prix - comme les bandes de Bollinger, les moyennes mobiles, etc.
  • Nombre - L'indicateur calcule un nombre qui est affiché sur son propre graphique - comme CCI, RSI, MACD, etc.
  • Fourchette de prix - l'indicateur calcule la fourchette de prix (différence entre deux prix) - comme l'ATR

D'autres types de retour sont utilisés dans d'autres types de blocs de construction.

 

Dans notre cas, Enveloppes est calculé à partir de la moyenne mobile d'un prix, il est donc affiché sur le graphique des prix. Cela signifie que son type de retour est Price.

 

@Parameter
public DataSeries Input;

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

@Output
public DataSeries Value;

ce qui suit sont les paramètres de l'indicateur. Chaque indicateur peut avoir plusieurs paramètres d'entrée, le modèle n'en crée que deux à titre d'exemple. Chaque paramètre est annoté avec @Paramètre qui peut avoir plusieurs attributs.

Le tout premier paramètre est EntréeIl s'agit du tableau de la série de données à partir duquel l'indicateur est calculé - il peut s'agir par exemple du cours d'ouverture, du cours le plus élevé, du cours le plus bas ou du cours de clôture.

Le deuxième paramètre est PériodeLes indicateurs ont généralement une période sur laquelle ils sont calculés.

La troisième variable est ValeurIl est à noter qu'il a une annotation différente @Sortie. Cela signifie que cette variable n'est pas un paramètre de l'indicateur mais son tampon de sortie. Les indicateurs n'ont généralement qu'un seul tampon de sortie, mais ils peuvent en avoir plusieurs - par exemple, la bande de Bollinger a un tampon supérieur et un tampon inférieur.

Il existe un autre paramètre caché Déplacement - Il est présent par défaut dans tous les indicateurs et indique au moteur de trading quelle valeur il doit rechercher. Vous n'avez généralement pas besoin de vous préoccuper de ce paramètre, il est utilisé automatiquement.

 

Ensuite, il y a une méthode :

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

 

C'est la méthode par laquelle les valeurs des indicateurs sont calculées. Elle est appelée en interne par SQ pour chaque barre et doit calculer la valeur de l'indicateur pour cette barre et l'enregistrer dans le tampon de sortie.

Il s'agit du code source du modèle d'indicateur standard. Dans l'étape suivante, nous montrerons les modifications à apporter pour mettre en œuvre notre indicateur Envelopes.

 

Modification du modèle par défaut généré et mise en œuvre de l'indicateur

L'indicateur créé à l'étape 1 est un modèle d'indicateur standard, il ne calcule pas encore d'enveloppes. Pour l'implémenter, nous devons faire quelques choses :

Mettre à jour son annotation @BuildingBlocks

Nous mettrons à jour l'annotation de cet indicateur comme suit :

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

C'est la partie la plus simple. Nous allons simplement mettre à jour nom de l'indicateur et ajouter les nouveaux paramètres actuels (voir ci-dessous) à l'indicateur affichage attribut.

 

Définir ses paramètres réels

La première chose à faire est un peu délicate - nous devons changer le type de l'élément par défaut Entrée paramètre. Dans le modèle standard, il est défini comme suit :

@Parameter
public DataSeries Input;

il s'agit d'un paramètre nommé Entréeavec le type Série de données. Ceci est valable pour une grande partie des indicateurs qui sont calculés à partir d'un seul prix. Par exemple, les indicateurs CCI, RSI, etc. sont généralement calculés à partir du cours de clôture. Vous pouvez les configurer pour qu'ils soient calculés à partir d'un prix différent, par exemple à partir du prix de l'ouverture, mais il s'agit toujours d'un seul tableau de prix.

 

Le type DataSeries est un tableau de valeurs qui contient des valeurs pour les cours de clôture, les cours d'ouverture, les cours typiques, etc.
Cependant, si vous regardez le code source MQL d'Envelopes, vous verrez qu'il calcule ses valeurs à partir de l'une des valeurs de prix et du volume.

 

Pour pouvoir accéder à plusieurs tableaux de prix à la fois, nous utiliserons différents types de sortie :

@Parameter
public ChartData Input;


Données graphiques
 est un objet qui représente l'ensemble du graphique - vous aurez accès aux prix Open, High, Low, Close, Volume dans le graphique donné. Nous en avons besoin pour calculer l'indicateur en fonction du paramètre Applied price.

 

Remarque rapide : il n'est pas difficile de choisir le bon type de variable pour les données d'entrée :
Si l'indicateur est calculé à partir d'un prix et qu'il n'y a pas d'option pour choisir le prix appliqué, continuez à utiliser DataSeries.
S'il est calculé à partir de plusieurs prix ou s'il y a un choix - par exemple High, Low, Close, etc. - utilisez ChartData.

 

Ensuite, il y a l'indicateur autres paramètres :

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

MA_Period est un paramètre de période "standard" pour cet indicateur.


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

MA_Moved est le décalage de cet indicateur. Dans le code MQL, ce paramètre s'appelle MA_Shift, mais Shift est un mot réservé dans SQ, nous devons donc le renommer.

 

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

Ce paramètre correspond à la méthode de la moyenne mobile. C'est un peu plus complexe, car nous définissons une liste de sélection (boîte combo) comme contrôle d'édition de ce paramètre. Ainsi, lors de l'édition dans l'assistant, l'utilisateur pourra choisir parmi les valeurs prédéfinies.

 

@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;

Il en va de même pour Applied_Price - il s'agit d'un choix d'entrées qui peuvent être utilisées pour calculer les enveloppes.

 

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

L'écart est le dernier paramètre d'entrée de l'indicateur Enveloppes.

 

Veuillez noter que nous avons également spécifié des valeurs pour le min, le max et le pas pour ces paramètres.

valeur min/valeur max sont les fourchettes minimales/maximales que vous pourrez définir.

Valeur minimale/valeur maximale du constructeur sont des fourchettes optionnelles que le constructeur de SQ utilisera lors de la génération de stratégies - elles peuvent être plus petites que les fourchettes maximales définies dans minValue/maxValue

valeur par défaut définit la valeur par défaut de cet indicateur.

step/builderStep définit le pas de la valeur du paramètre

 

Définir les sorties

L'indicateur Enveloppes a deux sorties - Supérieure et Inférieure - vous pouvez voir deux lignes différentes dans le graphique MT4.

Nous devons donc également définir deux sorties :

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

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

L'annotation @Sortie signifie qu'il s'agit d'un tampon de sortie pour cet indicateur. Notez qu'il est de type DataSeries, ce qui signifie qu'il s'agit d'un tableau de valeurs doubles.

 

Mise en œuvre de la méthode OnBarUpdate()

Si vous regardez le code MQL d'Envelopes, vous verrez qu'il est assez simple, son code MQL est le suivant :

  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);
  }

Si vous l'analysez un peu, vous verrez que les valeurs supérieure et inférieure sont calculées à l'aide d'une formule simple :

Bande supérieure = [1+DEVIATION/100] * MA(PRIX, PÉRIODE)
Bande inférieure = [1-DEVIATION/100] * MA(PRIX, PÉRIODE)

où les paramètres DEVIATION, MA ,PRICE et PERIOD sont configurables.

 

Nous pouvons l'implémenter en Java de la manière suivante :

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

 

Méthode OnBarUpdate() est appelé pour chaque barre du graphique. Sa responsabilité est de calculer la (les) valeur(s) de l'indicateur sur cette barre et de la (les) stocker dans les tampons de sortie.

Dans notre cas, nous calculons les valeurs supérieure et inférieure de la barre actuelle et les stockons dans leurs tampons en appelant la fonction Supérieur.set(), Bas.set().

 

Notez que nous utilisons une méthode d'aide spéciale calculerMA() pour calculer la moyenne mobile en fonction des paramètres MA_Method et Applied_Price.

Le code de cette méthode d'aide est le suivant :

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));
  }
}

C'est un peu plus long, mais compréhensible. Tout d'abord, nous allons choisir les données de prix correctes en fonction de Prix appliqué paramètre.

Dans la deuxième étape, nous appellerons l'indicateur de moyenne mobile approprié sur cette entrée selon la procédure suivante MA_Méthode paramètre.

 

Décortiquons l'un des appels, par exemple : Indicateurs.SMA(MAInput, MA_Period).Value.get(MA_Moved) :

  • Indicateurs.SMA(MAInput, MA_Period) appellera l'indicateur SMA sur l'entrée MAInput avec MA_Period. L'indicateur SMA n'a qu'un seul tampon de sortie appelé Value, les valeurs calculées de l'indicateur seront donc stockées dans ce tampon.
  • nous obtiendrons le tampon en appelant simplement Valeur
  • Value est un tampon (de type DataSeries), identique à nos tampons Upper et Lower, ce qui signifie qu'il s'agit d'un tableau de valeurs doubles, où chaque valeur correspond à une barre du graphique. Pour obtenir la valeur de la barre à la Nième position, nous devons appeler Valeur.get(N).
    Dans notre cas, nous appellerons .Value.get(MA_Moved)car nous voulons que la valeur décale optionnellement certaines barres vers l'arrière, selon le paramètre MA_Moved.

 

Ainsi, l'appel Indicators.SMA(MAInput, MA_Period).Value.get(MA_Moved) calculera la SMA avec la période. MA_Période sur le MAInput et renvoie sa valeur MA_Moved il y a quelques années.

 

Notez que les valeurs de la mémoire tampon de sortie sont indexées à partir de zéro, zéro étant la valeur de la barre la plus récente.

Ainsi :

  • Value.get(0) - renvoie la valeur de la barre actuelle
  • Value.get(1) - renvoie la valeur de la barre précédente
  • Value.get(2) - renvoie la valeur de la barre avant la barre précédente et ainsi de suite

 

C'est tout, maintenant quand on touche Compiler et redémarrer SQ nous verrons notre nouvel indicateur Envelopes dans la section Random Indicators Signals.

 

Code source complet de notre nouvel indicateur - vous pouvez le télécharger également dans la pièce jointe à cet article :

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));
    }
  }
}

 

 

Test d'un nouvel indicateur dans SQ X par rapport aux données de MT

Nous venons de créer (ou nous sommes en train de développer) notre nouvel indicateur. Comment savoir si nous l'avons mis en œuvre correctement ?

Lorsque vous avez créé votre nouvel indicateur dans StrategyQuant et qu'il a été compilé avec succès, il faut également vérifier s'il fonctionne réellement de la même manière que dans MetaTrader - en d'autres termes, si les valeurs calculées par l'indicateur sont les mêmes que ses valeurs dans MT4.

 

Pour cela, nous disposons d'un outil de test d'indicateurs dans l'éditeur de code. Il fonctionne simplement en comparant les valeurs calculées dans SQ avec les valeurs calculées dans MT4.

 

En général, il fonctionne en quelques étapes simples :

  1. Utiliser un script d'aide pour calculer et exporter les données de l'indicateur dans MetaTrader
  2. Copier les fichiers de données calculées à l'endroit approprié pour que le SQ puisse les trouver.
  3. Configurer et exécuter un test d'indicateur dans SQ

Utiliser un script d'aide pour calculer et exporter les données de l'indicateur dans MetaTrader

La première étape consiste à préparer les données de test de MT4 - nous devons calculer l'indicateur sur un certain nombre de barres et enregistrer les valeurs calculées dans un fichier.

Pour ce faire, nous fournissons un EA simple que vous pouvez utiliser - il se trouve à l'adresse suivante {SQ}/custom_indicators/MetaTrader4/Experts/SqIndicatorValuesExportEA.mq4

 

Ajoutez cet EA à votre MetaTrader, modifiez-le pour calculer la valeur de sortie de votre indicateur et exécutez-le dans MT4 StrategyTester sur n'importe quelles données - pour faire un test optimal, il devrait être exécuté sur au moins 1000 barres.

 

Comme Envelopes possède deux tampons de sortie, nous devons l'exécuter deux fois - une fois pour le tampon supérieur et une fois pour le tampon inférieur.

Voici un code modifié de ce script d'aide à l'exportation qui calcule l'indicateur Enveloppes :

//+------------------------------------------------------------------+
//|                                   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);
}

il calculera l'indicateur Envelopes sur MT4 en appelant sa méthode interne iEnvelopes() avec les paramètres appropriés.

Veuillez noter que les paramètres peuvent être configurés - vous n'avez pas besoin d'utiliser les paramètres par défaut. Il est conseillé d'inclure les valeurs des paramètres dans le nom du fichier de données de sortie - comme dans notre cas "Enveloppes_14_0_0_0_0.1_upper.csv", afin que nous sachions qu'il a été généré avec ces paramètres.

Nous pouvons maintenant exécuter ce script deux fois dans MT Tester :

Une fois terminé, il devrait créer un fichier de données avec les valeurs calculées de l'indicateur ainsi que les prix de l'ouverture, de la hausse, de la baisse et de la clôture pour chaque barre. Le fichier sera sauvegardé dans MetaTrader4 -> {Dossier de données}/tester/fichiers/votre_nom_de_fichier.csv


Nous devrions y trouver deux fichiers :
Envelopes_14_0_0_0_0.1_upper.csv
Envelopes_14_0_0_0_0.1_lower.csv

 

Copier les fichiers de données calculées à l'endroit approprié pour que le SQ puisse les trouver.


Copiez ces fichiers dans un dossier
{Installation SQ}/tests/Indicateurs/MetaTrader4

Créez ce dossier s'il n'existe pas, SQ Indicaotrs Tester recherche des fichiers dans ce dossier.

Maintenant que nous avons préparé le fichier de données, lançons un test dans StrategyQuant.

 

Configurer et exécuter un test d'indicateur dans SQ

Allez dans l'éditeur de code et cliquez sur Test indicators (indicateurs de test) dans la barre d'outils.

La boîte de dialogue du testeur d'indicateurs s'ouvre, cliquez sur Ajouter un nouveau test. Ajouter des indicateurs d'enveloppes au test, pour les sorties supérieure et inférieure.

Vous le verrez dans le tableau suivant. La dernière chose que nous devons faire est de modifier l'élément Nom du fichier de testen fonction des noms des fichiers de données d'essai créés à l'étape précédente et, éventuellement, en fonction des noms des fichiers de données d'essai créés à l'étape précédente. Paramètres d'essaisi vous avez utilisé d'autres options que celles par défaut :

Lorsque c'est fait, cliquez sur Démarrage pour exécuter les tests.

Dans le cas idéal, les tests seront réussis et les valeurs calculées dans SQ correspondront aux valeurs calculées dans MT4 :

Si quelque chose ne fonctionne pas, il y aura des différences entre les valeurs de SQ et de MT4. Vous pouvez cliquer sur les différences pour les voir dans la liste :

Si le test échoue, vérifiez d'abord si les données de test générées dans MT4 utilisaient les mêmes paramètres d'indicateur, car il peut y avoir une erreur.

Si les données de test sont correctes, il y a quelque chose qui ne va pas dans l'implémentation SQ de votre indicateur - il fonctionne différemment de son homologue MT4 et doit être corrigé.

 

Ajout de la traduction du bloc d'indicateurs dans la langue de la plateforme cible

L'indicateur fonctionne maintenant correctement dans StrategyQuant. Vous pouvez l'utiliser pour générer des stratégies basées sur lui, ou l'utiliser dans AlgoWizard. Mais nous n'avons pas encore terminé.

Si vous allez dans le code source de votre stratégie, vous verrez un message d'erreur comme celui-ci :

Cela signifie que lors de la génération du code Pseudo / MT4 / MT5 ou Tradestation, StrategyQuant n'a pas pu trouver un modèle qui traduira le bloc du format XML interne de SQ vers le langage de la plateforme cible.


Jusqu'à présent, nous avons créé un code pour que les enveloppes soient calculées dans StrategyQuant. Mais StrategyQuant ne sait pas comment traduire cet indicateur en un code dans votre plateforme de trading - cela dépend de la plateforme elle-même.

Dans StrategyQuant, les stratégies générées sont sauvegardées en interne au format XML. Lorsque vous passez à Strategy XML et que vous cherchez l'indicateur Envelopes, vous verrez qu'il est sauvegardé comme ceci :

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

Il ne s'agit que d'une partie de la stratégie XML qui contient la comparaison des enveloppes avec leur numéro. Notez qu'il utilise des blocs () Est plus grand, Enveloppes, Nombre.

La SQ cherchera des modèles pour traduire chacun des blocs XML dans la langue de la plate-forme cible. Modèles pour Est plus grand et Nombre sont par défaut dans le système, mais il manque un modèle pour les Enveloppes.

 

Les modèles sont stockés dans Code sous-arbre. Chaque plate-forme prise en charge y a son propre dossier, à l'intérieur duquel se trouve un sous-dossier /blocs qui contient des modèles pour chaque élément de construction.

 

Les fichiers modèles ont .tpl et elles sont très simples. Elles utilisent le moteur de template Freemarker (https://freemarker.apache.org) pour traduire le XML de l'indicateur dans le code de la plate-forme cible.

Notez que les modèles NE PAS contiennent du code pour calculer l'indicateur dans la plateforme cible, ils contiennent du code pour calculer l'indicateur dans la plateforme cible, ils contiennent du code pour calculer l'indicateur dans la plateforme cible. APPEL l'indicateur.

Si vous le vérifiez, vous verrez qu'il n'y a pas de modèle Envelopes.tpl, et que le code source affiche un message indiquant que le modèle correspondant est manquant.

Ajout d'un modèle de pseudo-code pour un nouveau bloc

Lorsque vous regardez votre Envelopessnippet dans la fenêtre du Navigateur, vous voyez qu'il y a une icône d'erreur et lorsque vous passez la souris dessus, vous voyez le message d'erreur - il manque le code du modèle pour chaque plateforme cible.

 

La façon la plus simple de l'ajouter est de cliquer sur le fichier Envelopes.java avec le bouton droit de la souris pour ouvrir le menu déroulant.
choisir l'action
Ajouter tous les manquants.

Cela ajoutera des modèles par défaut pour toutes les plateformes cibles.
Lorsque vous irez dans Code -> Pseudo-code -> blocs, vous verrez qu'il a ajouté le modèle Enveloppes.tpl avec un contenu par défaut.

Vous pouvez voir que le modèle est assez simple, il ne comporte généralement qu'une seule ligne.

 

Maintenant que le modèle est en place, vous pouvez à nouveau vérifier le code source de votre stratégie.


Vous pouvez voir que le code source a été produit, mais il n'est pas vraiment correct. 

Il montre Enveloppes(Tableau principal, , , 1) au lieu des paramètres réels des enveloppes. C'est parce que le fichier Envelopes.tpl a été créé en utilisant le modèle par défaut, il n'a pas utilisé les paramètres réels des indicateurs.

Si vous vérifiez le code PseudoCode/blocks/Envelopes.tpl, vous verrez qu'il est le suivant :

Enveloppes( , , )

Les méthodes printInput et printShift sont des méthodes par défaut pour imprimer les valeurs d'entrée et de décalage des données et elles fonctionnent correctement par défaut parce que chaque indicateur a une entrée et un décalage des données/graphiques.

Mais nous n'avons pas de paramètres nommés Param1 et Param2 dans notre indicateur. 

Au lieu de cela, nous avons cinq autres paramètres : MA_Period, MA_Moved, MA_Method, Applied_Price, Deviation.

 

Nous allons donc modifier le modèle comme suit :

Enveloppes( , , , , )

 

Maintenant, si vous regardez le pseudo-code, vous verrez qu'il est affiché avec des valeurs de paramètres correctes :

Comme vous pouvez le constater, l'impression d'un paramètre dans un modèle est très simple - il suffit d'utiliser la méthode :

<@printParam block “#PARAMETER_NAME#” />

PARAMETER_NAME est le nom de la variable paramètre du code Java.


Il y a encore une chose qui peut être améliorée - les paramètres MA_Méthode et Prix appliqué sont affichés sous forme de nombres - nous aimerions les afficher sous forme de textes, afin de savoir quelles valeurs ont été sélectionnées.

Pour ce faire, nous pouvons utiliser la méthode :

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


Cette méthode traduit la valeur numérique de l'option en fonction de son numéro.

En outre, pour ne pas être submergé par des informations sans importance, nous n'avons pas besoin d'afficher la valeur du paramètre MA_Moved dans le code Pseud. Nous pouvons simplement le supprimer du modèle.

Notre code modèle final pour les enveloppes dans PseudoCode sera donc le suivant :

Enveloppes( , , , )

et il produira un résultat comme celui-ci :

 

Ajout d'un modèle MetaTrader 4 pour le nouveau bloc

Dans l'étape précédente, nous avons ajouté un modèle de Pseudo Code pour notre indicateur Envelopes, de sorte que nous puissions voir les règles de la stratégie dans le Pseudo Code.

Nous devons répéter cette étape pour chaque plateforme cible sur laquelle nous voulons utiliser notre stratégie. 

Fixons donc le modèle pour MetaTrader MQL. Il y a deux possibilités dans MetaTrader :

  • soit l'indicateur est intégré à MetaTrader et nous pouvons alors l'appeler en utilisant son appel de fonction MQL,
  • ou il s'agit d'un indicateur personnalisé et nous devons l'appeler en utilisant l'appel MQL iCustom.

Nous montrerons les deux méthodes, qui ne diffèrent que légèrement dans le code du modèle.

 

Première possibilité - l'indicateur est intégré dans MetaTrader

Dans ce cas, vous pouvez trouver l'indicateur dans la liste des indicateurs disponibles dans le navigateur MT4, et vous pouvez
Vous trouverez également la méthode pour l'appeler dans le guide de référence MQL :

La documentation MQL nous apprend que lors de l'appel de cet indicateur, nous devons appeler la fonction iEnveloppes() avec les bons paramètres.

Nous allons donc ouvrir le fichier Code / MetaTrader4 / blocks / Envelopes.tpl et le modifier comme suit :

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

Nous avons renommé la méthode et ajouté les bons paramètres. Les méthodes printInput et printShift produisent des résultats corrects par défaut.

Notez un paramètre supplémentaire - Ligne. Comme les enveloppes comportent deux lignes (supérieure et inférieure), l'appel à iEnvelopes vous permet également de spécifier la valeur de la ligne que vous souhaitez récupérer - il s'agit du 8e paramètre. modequi est l'indice de ligne.

Dans MQL, ce paramètre est égal à 1 pour le niveau supérieur ou à 2 pour le niveau inférieur.

Ligne est également créé par défaut par SQ - il suffit de vérifier le XML de ce bloc. Mais il est basé sur zéro, et l'indice de ligne dépend de l'ordre des variables @Output définies dans la classe Java. Ainsi, dans SQ, 0 = supérieur, 1 = inférieur. Pour obtenir les mêmes valeurs que dans MT4, nous devons ajouter 1 à la valeur de la ligne.

 

Lorsque nous allons dans le code source de MT4, nous voyons qu'il produit cette sortie :

Quelle est la bonne façon d'appeler l'indicateur Enveloppes dans MQL ? .

 

Deuxième possibilité : il s'agit d'un indicateur personnalisé (externe) pour MetaTrader.

Que se passe-t-il si l'indicateur n'est pas intégré dans Metatrader ? La situation est à peine plus compliquée.
Supposons par exemple que l'indicateur Enveloppes n'existe pas dans MT4 et que nous devions l'utiliser comme indicateur personnalisé.


Tout d'abord, téléchargez l'indicateur Enveloppes à partir de ce lien : https://www.mql5.com/en/code/7975
 et l'enregistrer dans un fichier à l'adresse {MT4} -> Dossier de données/MQL/Indicateurs/Enveloppes.mq4

De cette façon, il sera disponible dans MetaTrader et pourra être utilisé et appelé. 

 

Les indicateurs personnalisés sont appelés à l'aide de la fonction MQL iCustom :

Ainsi, l'appel correct de l'indicateur personnalisé Envelopes dans MQL serait :

iCustom(Symbol, Timeframe, "Envelopes", MA_Period, MA_Moved, MA_Method, Applied_Price, Deviation, 1, Shift)

pour obtenir la ligne supérieure, et

iCustom(Symbol, Timeframe, "Envelopes", MA_Period, MA_Moved, MA_Method, Applied_Price, Deviation, 2, Shift)

pour obtenir la ligne inférieure.

Nous définissons notre modèle comme suit :

iCustom(, "Envelopes", , , , , , +1, )

 

qui produit à nouveau un code MQL correct, en utilisant un appel d'indicateur personnalisé :

 

La seule différence avec l'option précédente est que nous n'utilisons pas la méthode MQL prédéfinie iEnvelopes, mais une méthode générale iCustom qui nous permet d'appeler n'importe quel indicateur personnalisé externe.

 

 

Cet article a-t-il été utile ? L'article était utile L'article n'était pas utile

S'abonner
Notification pour
2 Commentaires
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
dorsler
dorsler
26. 10. 2020 4:20 pm

Merci Marc
Il suffit de regarder l'indicateur d'enveloppes en essayant de tirer cela de l'article que vous avez écrit.
https://strategyquant.com/doc/programming-sq/adding-envelopes-indicator-step-by-step
Le fichier CSV généré ci-dessous ne renvoie qu'un seul fichier dans le fichier MT4 tester lorsque l'indicateur a exécuté le test.
// modifier le nom du fichier ci-dessous  
string fileName = “Envelopes_14_0_0_0_0.1_upper.csv”;
La SQ pourra-t-elle toujours lire les valeurs supérieures et inférieures ou faudra-t-il une autre ligne de code ?
J'aime beaucoup cet indicateur, il sera donc un bon ajout à la bibliothèque de tests.
Remerciements
Dave

tomas262
tomas262
Répondre à  dorsler
30. 10. 2020 7:39 pm

Vous devez exporter deux fichiers CSV distincts. L'un contenant les valeurs de l'enveloppe supérieure à l'aide du code suivant : iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0.1 , 1 , 1) ; puis exporter un autre fichier CSV contenant les valeurs de l'enveloppe inférieure à l'aide du code suivant : iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0.1 , 2 , 1) ; notez les valeurs modifiées au numéro 2 utilisées à l'avant-dernière position de la deuxième ligne de code. Vous avez maintenant deux fichiers CSV : Envelopes_14_0_0_0_0.1_upper.csv et Envelopes_14_0_0_0_0.1_lower.csv.... Lire la suite "

Dernière modification le 3 années il y a par tomas262