Documentación

Aplicaciones

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

Indicador ForceIndex

Vamos a ir a través de la adición de nuevos indicadores personalizados en StrategyQuant X. A diferencia de SQ3, SQX permite ampliar el programa mediante la creación de sus propios indicadores personalizados y bloques de construcción - similar a cómo se puede añadir nuevos indicadores a las plataformas de negociación normales como MetaTrader 4/5, Tradestation y así sucesivamente.

Revisaremos este proceso paso a paso para explicarle todo lo necesario.

Al final tendremos un nuevo indicador personalizado añadido a StrategyQuant y podrá añadirlo a la lista de bloques de construcción para la generación de estrategias.

Utilizaremos Índice de fuerza un ejemplo. Este indicador ya está incorporado en Metatrader, puede encontrar su código fuente aquí: https://www.mql5.com/en/code/8013

Este es el aspecto del indicador en el gráfico:

 

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

  1. Añadir un nuevo bloque de construcción de indicadores
  2. (Opcional, recomendado) Probar el nuevo indicador en SQ X frente a los datos de MT
  3. (Opcional, recomendado) Añadir nuevo(s) bloque(s) de señales basado(s) en el indicador
  4. Añadir la traducción del bloque Indicador al idioma de la plataforma de destino

 

Paso 1 - Creación de un nuevo indicador personalizado en el Editor de código

El primer paso es crear nuestro indicador en Code Editor. StrategyQuant utiliza internamente el lenguaje de programación Java, y los indicadores personalizados deben ser programados en Java.

Usted no puede tomar su código MQL y simplemente copiar y pegar a StrategyQuant, no funcionaría. Debe reescribir el indicador en lenguaje Java.

Primero tenemos que abrir el Editor de Código:

En el Editor de Código puedes crear, editar y modificar fragmentos, así que crearemos un nuevo fragmento para nuestro nuevo indicador.

Una vez en el Editor de Código hacemos clic en el botón Crear nuevo de la barra de herramientas superior.

Esto abrirá un cuadro de diálogo, donde podemos nombrar nuestro nuevo fragmento y elegir su tipo. Lo llamaremos "ForceIndex"y seleccione Indicador como tipo de fragmento.

Tras hacer clic en Aceptar, se creará una nueva carpeta ForceIndex en Fragmentos -> SQ -> Bloques -> Indicadores y un nuevo archivo de fragmentos ForceIndex.java en esta carpeta.

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 crea un nuevo fichero para nuestro indicador ForceIndex y lo abre en el editor. Puedes 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 se llama a nuestro nuevo indicador en el método OnBlockEvaluate().

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

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

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 ForceIndex NO se muestra en el gráfico de precios, por lo que su tipo de retorno es Número, no Precio. Lo cambiaremos en el siguiente paso.

@Parameter public DataSeries Entrada;
 
@Parameter(defaultValue = "10", isPeriod = true, minValue=1, maxValue=10000, step=1) public int Periodo;
 
@Output public DataSeries Valor;

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() {...}

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

 

Paso 2 - Modificación de la plantilla por defecto generada e implementación del indicagtor

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

 

Actualiza su anotación @BuildingBlocks

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

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

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.

También cambiamos returnType a Number, porque este indicador calcula números mostrados en un gráfico separado, no muestra un valor de precio.

 

Definir parámetros ForceIndex

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

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 echas un vistazo al código fuente de ForceIndex 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 Gráfico;


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.


Nota rápida - elegir el tipo adecuado de variable de datos de entrada :
Si el indicador se calcula a partir de un precio, utilice DataSeries.
Si se calcula a partir de varios precios - por ejemplo, Máximo, Mínimo, Cierre, etc. - utilice ChartData.

Luego hay un parámetro Periodo, también podemos dejarlo sin cambios:

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

El tercer parámetro es el método de la media móvil:

@Parameter(name="Método", defaultValue="0") @Editor(type=Editors.Selection, values="Simple=0,Exponencial=1,Suavizado=2,Lineal ponderado=3") public int MAMétodo;

Esto 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í, al editar en el Asistente, el usuario podrá elegir entre los valores predefinidos.

El último parámetro es el precio aplicado - precio que debe utilizarse en el cálculo de la media móvil:

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

Tenga en cuenta que hemos utilizado algunos atributos en el @Parámetro anotación:

  • defaultValue establece el valor por defecto de este parámetro
  • isPeriod=true le dice a SQ que este parámetro es un periodo - se manejan de una manera especial, en la configuración del Constructor se puede configurar el valor mínimo y máximo para los periodos, por lo que SQ necesita saber qué parámetros son periodos.
  • valor mínimo, valor máximo, paso son los valores mínimo y máximo que se generarán para este parámetro durante el proceso de generación aleatoria.

Definir salidas ForceIndex

El indicador ForceIndex sólo tiene una salida, por lo que podemos dejarlo también sin cambios:

@Output public DataSeries Valor;

La anotación @Salida significa que se trata de un búfer de salida para este indicador. Tenga en cuenta que es de 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 ForceIndex verás que es bastante sencillo, su código MQL es:

int inicio() {
  int nLímite;
  int nBarrasContadas=IndicadorContado();

  //---- datos insuficientes
  if(BarsPeriodoFuerzaExterior) nContadasBaras--;
  nLimit=Barras-nBarrasContadas;

  //---- Índice de fuerza contado
  for(int i=0; i<nLimit; i++)
    ExtForceBuffer[i] = Volumen[i] * (iMA(NULL,0,ExtForcePeriod,0,ExtForceMAMethod,ExtForceAppliedPrice,i) - iMA(NULL,0,ExtForcePeriod,0,ExtForceMAMethod,ExtForceAppliedPrice,i+1));

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

Analizando el algoritmo, podemos ver que el valor del Índice de Fuerza en una vela dada se calcula como:

ForceIndex[i] = Volumen[i] *(MovAvg(Period, MAMethod, AppliedPrice)[i] - MovAvg(Period, MAMethod, AppliedPrice)
[i+1]

 

Podemos implementarlo en Java de la siguiente manera:

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

En este caso, el indicador es bastante simple y su cálculo requiere prácticamente sólo una línea en StrategyQuant.

Primero obtenemos el precio para calcular el indicador a partir de - llamando a Chart.getSeries(PrecioAplicado).
A continuación, calculamos el nuevo valor del indicador como una diferencia de la media del valor del precio actual y el anterior multiplicado por el volumen actual.

 

Esto es todo, ahora cuando golpeamos Compile y luego reinicie SQ veremos nuestro nuevo indicador ForceIndex en la sección Señales de Indicadores Aleatorios.

Código fuente completo de nuestro nuevo indicador:

paquete SQ.Blocks.Indicators.ForceIndex;

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

import SQ.Internal.IndicatorBlock;

/**
 * Nombre del indicador como se mostrará en la interfaz de usuario, y su tipo de retorno.
 * Posibles tipos de retorno:
 * ReturnTypes.Price - el indicador se dibuja en el gráfico de precios, como SMA, Bollinger Bands, etc.
 * ReturnTypes.Price - el indicador se dibuja en un gráfico separado, como CCI, RSI, MACD
 * ReturnTypes.PriceRange - el indicador es un rango de precios, como ATR.
 */
@BuildingBlock(name="(FI) ForceIndex ", display="ForceIndex (#Period#)[#Shift#]", returnType = ReturnTypes.Number)
@Help("Texto de ayuda de ForceIndex")
public class ForceIndex extends IndicadorBloque {

  @Parámetro
  public ChartData Gráfico;

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

  @Parameter(name="Método", defaultValue="0")
  @Editor(type=Editors.Selection, values="Simple=0,Exponencial=1,Suavizado=2,Lineal ponderado=3")
  public int MAMétodo;

  @Parámetro(defaultValor="0")
  @Editor(type=Editors.Selection, values="Cierre=0,Apertura=1,Máximo=2,Mínimo=3,Mediana=4,Típico=5,Ponderado=6")
  public int PrecioAplicado;

  @Salida
  public DataSeries Valor;

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

  /**
   * Este método es llamado en cada actualización de barra y aquí se calcula el valor del indicador.
   *
   * A diferencia de MT4, no se calculan los valores del indicador para múltiples barras en un bucle,
   * Usted necesita calcular el valor sólo para la última barra (actual).
   * El motor de negociación se encargará de llamar a este método para cada barra en el gráfico.
   *
   * La barra actual para la que se calcula el valor del indicador se almacena en la variable CurrentBar.
   * Si es 0, significa que es la primera barra del gráfico.
   */
  @Override
  protected void OnBarUpdate() throws TradingException {
    	doble 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);
  }

}

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

Suscríbase a
Notificar a
5 Comentarios
Más antiguo
Más reciente Más votados
Feedbacks de Inline
Ver todos los comentarios
Pieter Kotzee
Pieter Kotzee
21. 6. 2020 8:56 am

Hola. He copiado el código exactamente como se indica más arriba, pero al intentar compilarlo aparecen dos errores. Ambos están en la línea 55 y ambos tienen la misma descripción. Uno es la columna 54 y el otro es la 114:
no puede encontrar el símbolo símbolo: método MA(com.strategyquant.datalib.Dataseries,int,int) ubicación: variable Indicadores de tipo SQ>Internal.Indicators
 

Última edición hace 3 años por Pieter Kotzee
tomas262
tomas262
Responder a  Pieter Kotzee
29. 6. 2020 10:06 pm

El método MA no forma parte del paquete. Puede encontrarlo aquí https://strategyquant.com/codebase/forceindex/

Emmanuel2
21. 9. 2021 7:37 pm

Muchas gracias, este ejemplo me está ayudando mucho

Matthew Nowlis
Matthew Nowlis
26. 2. 2022 7:09 pm

Pude agregar con éxito el código java para el indicador Force Index y los bloques de señal. Se compila correctamente sin errores. Sin embargo, cuando genero estrategias en StrategyQuant con el indicador obtengo un error porque faltan las plantillas de código (MT4, MT5, pseudocódigo, etc). Dice en el código de la estrategia:

¡Error! Uno o más bloques que utiliza la estrategia no está implementado en (MT4, MT5, pseudocódigo, etc)

Error de inclusión de plantilla (para valor del parámetro "bloques/ForceIndex.tpl"):
Plantilla no encontrada para nombre "PseudoCode/blocks/ForceIndex.tpl".
El nombre fue interpretado por este Cargador de plantillas: MultiTemplateLoader(loader1 = FileTemplateLoader(baseDir="C:\StrategyQuantX\internal\extend\Code"), loader2 = FileTemplateLoader(baseDir="C:\StrategyQuantX\user\extend\Code")).

—-
Rastreo de pila FTL (“~” significa relacionado con los nidos):
    - Falló en: 1TP5Incluir "bloques/" + blockKey + ".tpl"  [en plantilla "PseudoCode/pseudoBlocks.inc" en macro "printBlock" en la línea 122, columna 20]
    - Alcanzado a través de: Bloque @printBlock?children[0], shift [en plantilla "PseudoCode/pseudoBlocks.inc" en macro "printBlock" en la línea 107, columna 9]
    - Alcanzado a través de: @printBlock c, shift [en plantilla "PseudoCode/pseudoBlocks.inc" en macro "printBlockChild" en la línea 148, columna 14]
    - Alcanzado a través de: Bloque @printBlockChild, "#Izquierda#"  [en plantilla "PseudoCode/blocks/IsGreater.tpl" en la línea 1, columna 2]
    - Alcanzado a través de: #incluir "bloques/" + blockKey + ".tpl"  [en plantilla "PseudoCode/pseudoBlocks.inc" en macro "printBlock" en la línea 122, columna 20]
    - Alcanzado a través de: Bloque @printBlock?children[0], shift [en plantilla "PseudoCode/pseudoBlocks.inc" en macro "printBlock" en la línea 107, columna 9]
    - Alcanzado a través de: Bloque @printBlock [en plantilla "PseudoCódigo/bloques/AND.tpl" en la línea 5, columna 38]
    - Alcanzado a través de: #incluir "bloques/" + blockKey + ".tpl"  [en plantilla "PseudoCode/pseudoBlocks.inc" en macro "printBlock" en la línea 122, columna 20]
    - Alcanzado a través de: Bloque @printBlock?children[0], shift [en plantilla "PseudoCode/pseudoBlocks.inc" en macro "printBlock" en la línea 107, columna 9]
    ... (Had 18 más, oculto para tersenos) (Oculto 4 “~” líneas para tersura)

¿Cómo añado las plantillas de código para los respectivos lenguajes de código de estrategia?

tomas262
Admin
Responder a  Matthew Nowlis
28. 2. 2022 13:53

En su lugar, puede intentar importar el paquete desde esta página https://strategyquant.com/codebase/forceindex/

El pseudocódigo y MT4 se implementan y trabajan para mí cuando se prueba