Documentación

Aplicaciones

Última actualización el 18. 5. 2020 by Mark Fric

Indicador de sobres

en este ejemplo añadiremos Sobres a StrategyQuant X.

El código MQL para este indicador se puede encontrar aquí: https://www.mql5.com/en/code/7975

Este indicador también ya está incorporado en MetaTrader, puede llamarlo desde el código MQL utilizando el método iEnvelopes. Así es como el indicador se ve en el gráfico:

Hay algunos pasos a seguir para añadir un nuevo indicador a SQ X:

  1. Añadir un nuevo bloque de construcción de indicadores 
    crearemos un nuevo fragmento de indicador y actualizaremos su código para calcular el indicador Envelopes.
  2. (Opcional, recomendado) Probar el nuevo indicador en SQ X frente a los datos de MT
    durante o después de la aplicación, debemos comparar los valores del indicador calculados por SQ con los calculados por MQL, para asegurarnos de que el indicador se aplica correctamente.
  3. Añadir la traducción del bloque Indicador al idioma de la plataforma de destino
    funciona en SQ ahora, pero las estrategias que utilizan este indicador no. Tenemos que añadir plantillas o generar código fuente para este indicador para cada plataforma de negociación que queremos apoyar

 

Añadir un nuevo fragmento de indicador

Para ello, abriremos Editor de código.

Allí hacemos clic en Crear nuevo en la barra de herramientas

y en el cuadro de diálogo emergente introducimos 'Sobrescomo nuevo nombre del indicador y dejar Indicador como tipo de fragmento.

Haga clic en OKy se creará un nuevo indicador.

 

Puede verlo en el árbol de navegación, en Snippets -> SQ -> Bloques -> Indicadores. Tiene su propia carpeta llamada 'Envelopes', y el código del fragmento del indicador está en el archivo Sobres.java

La convención en StrategyQuant es que cada indicador está en su propia carpeta - es porque más tarde podríamos querer crear señales para este indicador, y todos los fragmentos relacionados estarán en la misma carpeta.

Esta acción creó un nuevo archivo para nuestro indicador Envelopes y lo abrió en el editor. Usted puede ver que el indicador es una clase y ya tiene alguna estructura.

 

Cada indicador se extiende a partir de la clase IndicatorBlock y debe implementar un método:

  • OnBarUpdate() - donde se calcula el valor del indicador y se almacena en uno de los búferes de salida. Se ejecuta para cada barra del gráfico.

 

Cuando compruebes el código fuente te darás cuenta de algunas cosas.

En primer lugar, los snippets en StrategyQuant utilizan mucho las anotaciones - @Parameter, @Output, @BuildingBlock - estas anotaciones se utilizan para declarar una propiedad especial de una determinada variable o clase - que la variable es un parámetro público o un valor de salida, o que la clase es un bloque indicador.

En segundo lugar, una vez creado y compilado un indicador, puede llamarlo desde otros métodos o indicadores utilizando Indicators.YourIndicator(YourIndicatorParameters). Así es como un indicador puede ser llamado desde otro - lo usaremos también en Envolventes para llamar indicadores de Media Móvil, llegaremos a ello más adelante.

 

Revisaremos paso a paso el código fuente de la clase de indicador por defecto creada a partir de la plantilla:

package SQ.Blocks.Indicators.Envelopes;

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

import SQ.Internal.IndicatorBlock;

esta es la declaración estándar de Java de un paquete y las importaciones de las clases necesarias - las que utilizamos en nuestra propia clase.


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

Definición anotada de nuestra clase indicadora, que indica al sistema que se trata de un bloque de construcción con un nombre determinado.

  • nombre es lo que se muestra en la interfaz de usuario al elegir los bloques de construcción.
  • mostrar es lo que se muestra en el Asistente con los parámetros. Puede controlar qué parámetros se muestran y en qué lugar
  • returnType es un tipo de indicador, dice qué tipo de valor calcula este indicador. Se utiliza para que StrategyQuant sepa qué tipos deben ser comparados con qué. Por ejemplo, no compararía CCI (que devuelve Número) con Bolinger Bands (que devuelve Precio).

 

Existen básicamente tres tipos de retorno que puede tener un indicador:

  • Precio - El indicador calcula el precio y se muestra en el gráfico de precios, como las bandas de Bollinger, la media móvil, etc.
  • Número - El indicador calcula el número que se muestra en su propio gráfico, como CCI, RSI, MACD, etc.
  • Rango de precios - El indicador calcula el rango de precios (diferencia entre dos precios), como el ATR.

Otros tipos de retorno se utilizan en otros tipos de bloques de construcción.

 

En nuestro caso Envelopes se calcula a partir de la media móvil de un precio, por lo que se muestra en el gráfico de precios. Esto significa que su tipo de retorno es Precio.

 

@Parameter
public DataSeries Input;

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

@Output
public DataSeries Value;

lo que sigue son parámetros del indicador. Cada indicador puede tener múltiples parámetros de entrada, la plantilla crea sólo dos de ellos como ejemplo. Cada parámetro se anota con @Parámetro que puede tener varios atributos.

El primer parámetro es Entradaes la serie de datos a partir de la cual se calcula el indicador; puede ser, por ejemplo, el precio de apertura, el precio máximo, el precio mínimo o el precio de cierre.

El segundo parámetro es PeriodoPor lo general, los indicadores tienen un periodo sobre el que se calculan.

La tercera variable es Valorobserve que tiene una anotación diferente @Salida. Esto significa que esta variable no es un parámetro del indicador, sino su búfer de salida. Los indicadores suelen tener sólo un búfer de salida, pero pueden tener más - por ejemplo la banda de Bollinger tiene búfer Superior e Inferior.

Hay un parámetro oculto más Turno - está por defecto en todos los indicadores y le dice al motor de negociación qué valor debe buscar. Generalmente no necesita preocuparse por este parámetro, se utiliza automáticamente.

 

Entonces hay un método:

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

 

Este es el método donde se calculan los valores de los indicadores. Es llamado internamente por SQ para cada barra y debe calcular el valor del indicador para esta barra y guardarlo en el buffer de salida.

Este es el código fuente de la plantilla estándar del indicador. En el siguiente paso mostraremos los cambios que hay que hacer para implementar nuestro indicador Envelopes.

 

Modificación de la plantilla por defecto generada e implementación del indicador

El indicador creado en el paso 1 es una plantilla de indicador estándar, todavía no calcula Envolventes. Para implementarlo debemos hacer algunas cosas:

Actualiza su anotación @BuildingBlocks

Actualizaremos la anotación de este indicador de la siguiente manera:

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

Esta es la parte más sencilla. Nos limitaremos a actualizar nombre del indicador y añada los nuevos parámetros reales (véase más abajo) al indicador mostrar atributo.

 

Definir sus parámetros reales

Lo primero que hay que hacer es un poco complicado: debemos cambiar el tipo del archivo por defecto Entrada parámetro. En la plantilla estándar se define de la siguiente manera:

@Parameter
public DataSeries Input;

es parámetro denominado Entradacon tipo Series de datos. Esto es válido para una gran parte de los indicadores que se calculan a partir de un solo precio. Por ejemplo los indicadores CCI, RSI, etc. son usualmente calculados desde el precio de Cierre. Usted puede configurarlos para que sean calculados a partir de un precio diferente, por ejemplo a partir del precio de Apertura, pero aún así es sólo una matriz de precios.

 

El tipo DataSeries es un tipo de matriz de valores que contiene valores para precios de Cierre, o para precios de Apertura, o para precios Típicos, etc.
Sin embargo, si miras el código fuente de Envelopes MQL, verás que calcula sus valores a partir de uno de los valores del precio y del Volumen.

 

Para poder acceder a varias matrices de precios a la vez, utilizaremos un tipo diferente para la salida:

@Parameter
public ChartData Input;


ChartData
 es un objeto que representa el gráfico completo - tendrá acceso a los precios de Apertura, Máximo, Mínimo, Cierre y Volumen en el gráfico dado. Necesitamos esto para que podamos cmpute el indicador de acuerdo con el parámetro de precio Aplicado.

 

Nota rápida: elegir el tipo adecuado de variable de datos de entrada no es difícil:
Si el indicador se calcula a partir de un precio y no hay opción de elegir el precio aplicado, siga utilizando DataSeries.
Si se computa a partir de múltiples precios o hay una opción - por ejemplo High, Low, Close, etc. - utilice ChartData.

 

Además, existen otros parámetros indicadores:

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

MA_Period es un parámetro de periodo "estándar" para este indicador.


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

MA_Moved es el desplazamiento de este indicador. En el código MQL este parámetro se llama MA_Shift, pero Shift es una palabra reservada en SQ, así que tenemos que cambiarle el nombre.

 

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

Este parámetro es el método de la media móvil. Es un poco más complejo, porque definimos una lista de selección (combo box control) como control de edición de este parámetro. Así que cuando se edita en el Asistente, el usuario será capaz de elegir entre los valores predefinidos.

 

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

Lo mismo se aplica a Applied_Price: se trata de una selección de entradas que pueden utilizarse para calcular las envolventes.

 

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

La desviación es el último parámetro de entrada del indicador Envolventes.

 

Tenga en cuenta que también especificamos algunos valores para min, max y step para estos parámetros.

valor mínimo/valor máximo son los rangos mínimo/máximo que podrás establecer.

constructorValorMín/ constructorValorMáx son rangos opcionales que el constructor en SQ utilizará al generar estrategias - pueden ser menores que los rangos máximos definidos en minValue/maxValue

defaultValue define el valor por defecto de este indicador.

paso/constructorPaso define el paso del valor del parámetro

 

Definir salidas

El indicador Envelopes tiene dos salidas - Superior e Inferior - puede ver dos líneas diferentes en el gráfico MT4.

Así que también tenemos que definir dos salidas:

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

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

La anotación @Salida significa que se trata de un búfer de salida para este indicador. Tenga en cuenta que tiene tipo DataSeries, lo que significa que es una matriz de valores dobles.

 

Implementar el método OnBarUpdate()

Si echas un vistazo al código MQL de Envelopes verás que es bastante sencillo, su código MQL es:

  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 lo analizas un poco, verás que los valores Superior e Inferior se calculan mediante una fórmula sencilla:

Banda superior = [1+DEVIACIÓN/100] * MA(PRECIO, PERÍODO)
Banda inferior = [1-DEVIACIÓN/100] * MA(PRECIO, PERÍODO)

donde los parámetros DEVIACIÓN, MA ,PRECIO y PERÍODO son configurables.

 

Podemos implementarlo en Java de la siguiente manera:

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

 

Método OnBarUpdate() se ejecuta en cada barra del gráfico. Su responsabilidad es calcular el valor(es) del indicador en esta barra y almacenarlo en los buffers de salida.

En nuestro caso, calcularemos los valores superior e inferior de la barra y los almacenaremos en sus buffers llamando a Superior.set(), Lower.set().

 

Tenga en cuenta que utilizamos un método de ayuda especial calcularMA() para calcular la media móvil según los parámetros MA_Method y Applied_Price.

El código de este método de ayuda es:

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 un poco más largo, pero comprensible. Primero elegiremos los datos de precios correctos según Precio_aplicado parámetro.

En el segundo paso llamaremos al indicador de media móvil apropiado en esta entrada según Método MA parámetro.

 

Vamos a diseccionar una de las llamadas, por ejemplo: Indicadores.SMA(MAInput, MA_Period).Value.get(MA_Moved):

  • Indicadores.SMA(MAInput, MA_Period) llamará al indicador SMA en la entrada MAInput con MA_Period. El indicador SMA sólo tiene un búfer de salida llamado Valor, por lo que los valores calculados del indicador se almacenarán allí.
  • obtendremos el búfer simplemente llamando a Valor
  • Value es un buffer (tipo DataSeries), igual que nuestros buffers Upper y lower, lo que significa que es un array de valores dobles, donde cada valor pertenece a una barra del gráfico. Para obtener el valor de la barra en la posición N, debemos llamar a Valor.get(N).
    En nuestro caso llamaremos a .value.get(MA_Movido), porque queremos que el valor desplace opcionalmente algunas barras hacia atrás, según el parámetro MA_Moved.

 

Así que toda la llamada Indicators.SMA(MAInput, MA_Period).Value.get(MA_Moved) calculará SMA con periodo MA_Period en el MAInput y devuelve su valor MA_Movido bares atrás.

 

Tenga en cuenta que los valores en el búfer de salida están indexados desde cero, donde cero es el valor de la barra más actual.

Así que..:

  • Value.get(0) - devuelve el valor de la barra actual
  • Value.get(1) - devuelve el valor de la barra anterior
  • Value.get(2) - devuelve el valor de la barra anterior a la anterior y así sucesivamente

 

Esto es todo, ahora cuando golpeamos Compile y luego reinicie SQ veremos nuestro nuevo indicador Envelopes en la sección Random Indicators Signals.

 

Código fuente completo de nuestro nuevo indicador - puede descargarlo también en el archivo adjunto a este artículo:

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

 

 

Prueba de un nuevo indicador en SQ X frente a los datos de MT

Acabamos de crear (o estamos desarrollando) nuestro nuevo indicador. ¿Cómo sabemos si lo hemos implementado correctamente?

Cuando usted creó su nuevo indicador en StrategyQuant y fue compilado con éxito, también se debe verificar si realmente funciona de la misma manera que en MetaTrader - en otras palabras, si los valores calculados por él son los mismos que sus valores en MT4.

 

Para esto, tenemos una herramienta de Probador de Indicadores en el Editor de Código. Funciona simplemente comparando los valores calculados en SQ con los valores calculados en MT4.

 

En general, funciona en unos sencillos pasos:

  1. Utilizar script de ayuda para calcular y exportar datos de indicadores en MetaTrader
  2. Copie los archivos de datos calculados en la ubicación adecuada para que SQ pueda encontrarlos
  3. Configurar y ejecutar la prueba de indicadores en SQ

Utilizar script de ayuda para calcular y exportar datos de indicadores en MetaTrader

Como primer paso debemos preparar los datos de prueba de MT4 - debemos calcular el indicador en un número de barras y guardar sus valores calculados en un archivo.

Para ello le proporcionamos un EA sencillo que puede utilizar - se encuentra en {SQ}/custom_indicators/MetaTrader4/Experts/SqIndicatorValuesExportEA.mq4

 

Añada este EA a su MetaTrader, modifíquelo para calcular y el valor de salida de su indicador y ejecútelo en MT4 StrategyTester en cualquier dato - para hacer una prueba óptima se debe ejecutar en al menos 1000 barras.

 

Como Envelopes tiene dos búferes de salida, tenemos que ejecutarlo dos veces: una para el búfer superior y otra para el inferior.

He aquí un código modificado de este script de ayuda a la exportación que calcula el indicador Envelopes:

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

calculará el inicador Envelopes en MT4 llamando a su método interno iEnvelopes() con los parámetros adecuados.

Tenga en cuenta que los parámetros pueden configurarse, no es necesario utilizar los predeterminados. Es una buena práctica incluir los valores de los parámetros también en el nombre del archivo de datos de salida - como en nuestro caso "Envelopes_14_0_0_0.1_upper.csv", para que sepamos que fue generado con estos parámetros.

Ahora podemos ejecutar este script dos veces en MT Tester:

Cuando termine debería crear un archivo de datos con los valores calculados del indicador así como los precios de Apertura, Máximo, Mínimo y Cierre para cada barra. El archivo se guardará en MetaTrader4 -> {Carpeta de datos}/tester/files/Your_FILE_NAME.csv


Deberíamos ver dos archivos allí:
Envelopes_14_0_0_0_0.1_upper.csv
Envelopes_14_0_0_0_0.1_lower.csv

 

Copie los archivos de datos calculados en la ubicación adecuada para que SQ pueda encontrarlos


Copie estos archivos en una carpeta
{Instalación de SQ}/pruebas/Indicadores/MetaTrader4

Cree esta carpeta si no existe, SQ Indicaotrs Tester busca archivos en esta carpeta.

Ahora que tenemos el archivo de datos preparado, vamos a iniciar una prueba en StrategyQuant.

 

Configurar y ejecutar la prueba de indicadores en SQ

Co al Editor de código y haga clic en Indicadores de prueba en la barra de herramientas.

Se abrirá el cuadro de diálogo Comprobador de indicadores, haga clic en Añadir nueva prueba. Añada indicadores Envelopes a la prueba, tanto para la salida superior como para la inferior.

Lo verás en la siguiente tabla. Lo último que tenemos que hacer es modificar la directiva Nombre del archivo de pruebas según los nombres de los archivos de datos de prueba reales creados en el paso anterior, y opcionalmente también Parámetros de pruebasi ha utilizado otros que no sean los predeterminados:

Cuando haya terminado, haga clic en Inicio para ejecutar las pruebas.

En el caso ideal las pruebas serán exitosas y los valores calculados en SQ coincidirán con los valores calculados en MT4:

Si algo falla habrá diferencias entre los valores de SQ y MT4. Puede hacer clic en el mensaje de diferencias para verlas en la lista:

Si la prueba falla, compruebe primero si los datos de prueba generados en MT4 estaban utilizando los mismos parámetros del indicador, puede haber un error en eso.

Si los datos de prueba son correctos, entonces hay algo mal con la implementación SQ de su indicador - funciona de manera diferente a su contraparte MT4 y debe ser corregido.

 

Añadir la traducción del bloque Indicador al idioma de la plataforma de destino

Ahora el indicador funciona correctamente en StrategyQuant. Puede utilizarlo para generar algunas estrategias basadas en él, o utilizarlo en AlgoWizard. Pero no hemos terminado todavía.

Si vas al código fuente de tu estrategia, verás un mensaje de error como este:

Significa que al generar el código Pseudo Code / MT4 / MT5 o Tradestation, StrategyQuant no pudo encontrar una plantilla que traducirá el bloque del formato interno SQ XML al lenguaje de la plataforma de destino.


Hasta ahora hemos creado un código para sobres para ser computado dentro StrategyQuant. Pero StrategyQuant no sabe cómo traducir este indicador en un código en su plataforma de negociación - que depende de la propia plataforma.

En StrategyQuant, las estrategias generadas se guardan internamente en formato XML. Cuando cambie a Strategy XML y busque el indicador Envelopes, verá que está guardado así:

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

Esto es sólo una parte del XML de la estrategia que contiene la comparación de Sobres con número. Nótese que utiliza bloques () EsMayor, Sobres, Número.

SQ buscará plantillas para traducir cada uno de los bloques XML al idioma de la plataforma de destino. Plantillas para EsMayor y Número están por defecto en el sistema, pero nos falta una plantilla para Sobres.

 

Las plantillas se almacenan en Código subárbol. Allí, cada plataforma compatible tiene su propia carpeta, y dentro de ella hay una subcarpeta /bloquea que contiene plantillas para cada bloque de construcción.

 

Los archivos de plantilla tienen .tpl y son muy sencillas. Utilizan el motor de plantillas Freemarker (https://freemarker.apache.org) para traducir el XML del indicador al código de la plataforma de destino.

Tenga en cuenta que las plantillas NO contienen código para calcular el indicador en la plataforma de destino, contienen código para LLAMAR A el indicador.

Si lo compruebas verás que no hay plantilla Envelopes.tpl, de ahí que el código fuente muestre un mensaje de que falta la plantilla para ello.

Añadir plantilla de pseudocódigo para un nuevo bloque

Cuando usted mira a su Envelopessnippet en la ventana del Navegador verás que hay un icono de error y cuando el ratón sobre él, usted 'll ver el mensaje de error - que falta código de plantilla para cada plataforma de destino.

 

La forma más fácil de añadirlo es hacer clic en el archivo Envelopes.java con el botón derecho del ratón para abrir el menú desplegable y allí
elegir la acción
Añadir todos los que faltan.

Esto añadirá plantillas por defecto para todas las plataformas de destino.
Cuando vayas a Código -> Pseudocódigo -> bloques verás que se ha añadido la plantilla Sobres.tpl con un contenido predeterminado.

Puede ver que la plantilla es bastante simple, por lo general es sólo una línea.

 

Ahora que la plantilla está ahí, puede comprobar de nuevo el código fuente de su estrategia.


Se puede ver que el código fuente se produjo, pero no es realmente correcto. 

Muestra Sobres(Gráfico principal, , , 1) en lugar de los parámetros reales de Envelopes. Esto se debe a que el Envelopes.tpl fue creado utilizando la plantilla por defecto, no utiliza los parámetros reales de los indicadores.

Si revisas el código de PseudoCode/blocks/Envelopes.tpl verás que es como sigue:

Envelopes( , , )

Los métodos printInput y printShift son métodos predeterminados para imprimir los valores de entrada de datos y desplazamiento y funcionan correctamente por defecto porque cada indicador tiene alguna entrada de datos/gráfico y desplazamiento.

Pero no tenemos parámetros llamados Param1 y Param2 en nuestro indicador. 

En su lugar tenemos otros cinco parámetros MA_Period, MA_Moved, MA_Method, Applied_Price, Deviation.

 

Así que vamos a modificar la plantilla de esta manera:

Envelopes( , , , , )

 

Ahora si miras el Pseudo Código verás que se muestra con los valores correctos de los parámetros:

Como puedes ver, imprimir un parámetro en una plantilla es muy sencillo - sólo tienes que utilizar el método:

<@printParam block “#PARAMETER_NAME#” />

donde NOMBRE_PARÁMETRO es el nombre de la variable de parámetro del código Java.


Todavía hay algo que se puede mejorar: los parámetros. Método MA y Precio_aplicado se muestran como números - nos gustaría mostrarlos como textos, para saber qué valores se seleccionaron.

Para ello, podemos utilizar el método

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


Este método traducirá el valor numérico a la opción basada en su número.

Además, para no estar abrumados con información sin importancia, no necesitamos mostrar el valor del parámetro MA_Moved en el código Pseud. Podemos simplemente eliminarlo de la plantilla.

Así que nuestro código final de plantilla de PseudoCódigo para Sobres en PseudoCódigo será el siguiente:

Envelopes( , , , )

y producirá una salida como esta:

 

Añadir plantilla MetaTrader 4 para el nuevo bloque

En el paso anterior añadimos la plantilla Pseudo Code para nuestro indicador Envelopes, de forma que podamos ver las reglas de la estrategia en Pseudo Code.

Debemos repetir este paso para cada plataforma objetivo en la que queramos utilizar nuestra estrategia. 

Así que vamos a arreglar la plantilla para MetaTrader MQL. Hay dos posibilidades en MetaTrader:

  • o bien el indicador está incorporado en MetaTrader y entonces podemos llamarlo utilizando su llamada a función MQL,
  • o es un indicador personalizado y debemos llamarlo utilizando la llamada iCustom MQL.

Mostraremos ambas formas, sólo difieren ligeramente en el código de la plantilla.

 

Primera posibilidad - el indicador está incorporado en MetaTrader

En este caso, puede encontrar el indicador en la lista de indicadores disponibles en el navegador MT4, y usted
también puede encontrar el método para llamarlo en MQL Guía de referencia:

De la documentación de MQL sabemos que al llamar a este indicador tenemos que llamar a la función iSobres() con los parámetros adecuados.

Así que vamos a abrir el archivo Code / MetaTrader4 / bloques / Envelopes.tpl y cambiarlo de la siguiente manera:

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

Lo que hemos hecho es cambiar el nombre del método y añadir los parámetros correctos. Métodos printInput y printShift producen una salida correcta por defecto.

Tenga en cuenta un parámetro más - Línea. Dado que los sobres tienen dos líneas (superior e inferior), la llamada a iEnvelopes también le permite especificar el valor de la línea que desea recuperar (es el octavo parámetro). modoque es el índice de línea.

Este parámetro en MQL es 1 para Superior, o 2 para Inferior.

Línea también es creado por defecto por SQ - basta con comprobar el XML de este bloque. Pero está basado en cero, y el índice de línea depende del orden de las variables @Output definidas en la clase Java. Así que en SQ 0 = Superior, 1=Inferior. Para obtener los mismos valores que en MT4, tenemos que añadir 1 al valor de la línea.

 

Cuando vamos al código fuente de MT4 vemos que produce esta salida:

¿Cuál es la forma correcta de llamar al indicador Envelopes en MQL? .

 

Segunda posibilidad - es un indicador personalizado (externo) para MetaTrader

¿Y si el indicador no está integrado en Metatrader? La situación es un poco más complicada.
Como ejemplo digamos que el indicador Envelopes no existe en MT4, y tenemos que usarlo como indicador personalizado.


En primer lugar, descargue el indicador Sobres desde este enlace: https://www.mql5.com/en/code/7975
 y guardarlo en un archivo a {MT4} -> Carpeta de datos/MQL/Indicadores/Envelopes.mq4

De esta manera estará disponible en MetaTrader y podrá ser utilizado y llamado. 

 

Los indicadores personalizados se llaman utilizando la función MQL iCustom:

Así que la llamada correcta de Sobres indicador personalizado en MQL sería:

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

para obtener la línea superior, y

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

para obtener la línea inferior.

Definimos nuestra plantilla del siguiente modo:

iCustom(, "Sobres", , , , , , +1, )

 

que de nuevo produce un código MQL correcto, utilizando la llamada al indicador personalizado:

 

La única diferencia con la opción anterior es que no utilizamos el método MQL predefinido iEnvelopes, sino un método general iCustom que nos permite llamar a cualquier indicador personalizado externo.

 

 

¿Le ha resultado útil este artículo? El artículo era útil El artículo no era útil

Suscríbase a
Notificar a
2 Comentarios
Más antiguo
Más reciente Más votados
Feedbacks de Inline
Ver todos los comentarios
dorsler
dorsler
26. 10. 2020 16:20

Gracias Marc
Sólo mirando el indicador de sobres tratando de tirar de esto en SQ del artículo que escribió
https://strategyquant.com/doc/programming-sq/adding-envelopes-indicator-step-by-step
El archivo CSV generado a continuación sólo devuelve un único archivo en MT4 archivo probador cuando el indicador ha ejecutado la prueba.
// cambie el nombre del archivo  
cadena fileName = “Envelopes_14_0_0_0_0.1_upper.csv”;
¿Seguirá SQ siendo capaz de leer los valores superior e inferior o es necesaria otra línea de código?
Realmente me gusta este indicador por lo que será una buena adición a la biblioteca de prueba.
Gracias
Dave

tomas262
tomas262
Responder a  dorsler
30. 10. 2020 19:39

Necesita exportar 2 archivos CSV separados. Uno que contenga los valores para el sobre superior utilizando este valor de código = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0.1 , 1 , 1); y luego exportar otro archivo CSV con los valores para el sobre inferior utilizando el valor de código = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0.1 , 2 , 1); Tenga en cuenta los valores cambiados al número 2 utilizado en la penúltima posición en la segunda línea de código. Así que ahora tienes 2 archivos CSV ambos Envelopes_14_0_0_0.1_upper.csv y Envelopes_14_0_0_0.1_lower.csv... Leer más "

Última edición hace 3 años por tomas262