Documentação

Aplicações

Última atualização em 18. 5. 2020 por Mark Fric

Indicador de envelopes

neste exemplo, vamos acrescentar Envelopes indicador para StrategyQuant X.

O código MQL para este indicador pode ser encontrado aqui: https://www.mql5.com/en/code/7975

Este indicador também já está incorporado no MetaTrader, você pode chamá-lo de código MQL usando o método iEnvelopes. Esta é a aparência do indicador no gráfico:

Há poucos passos a seguir para adicionar um novo indicador ao SQ X:

  1. Adicionando novo bloco de construção de indicadores 
    criaremos um novo indicador e atualizaremos seu código para computar o indicador Envelopes.
  2. (Opcional, recomendado) Teste de novo indicador no SQ X vs dados da MT
    durante ou após a implementação, devemos comparar os valores dos indicadores computados pelo SQ com aqueles computados pela MQL - para garantir que o indicador seja implementado corretamente
  3. Acréscimo da tradução do bloco Indicador no idioma da plataforma de destino
    O indicador funciona agora no SQ, mas as estratégias que utilizam este indicador não funcionam. Temos que adicionar modelos para gerar o código fonte para este indicador para cada plataforma comercial que queremos apoiar

 

Acréscimo de novo indicador

para fazer isso, vamos abrir Editor de código.

Aí clicamos em Criar novos botão na barra de ferramentas

e no diálogo popup, entramos 'Envelopescomo novo nome indicador e sair Indicador como o tipo Snippet.

Clique OKe um novo indicador será criado.

 

Você pode vê-lo na árvore de Navegação, em Snippets -> SQ -> Blocos -> Indicadores. Ele tem sua própria pasta chamada 'Envelopes', e o código de snippet indicador está em arquivo Envelopes.java

A convenção em StrategyQuant é que cada indicador está em sua própria pasta - é porque mais tarde poderemos querer criar sinais para este indicador, e todos os trechos relacionados estarão na mesma pasta.

Esta ação criou um novo arquivo para nosso indicador Envelopes e o abriu em editor. Você pode ver que o indicador é uma classe e já tem alguma estrutura.

 

Cada indicador é estendido da classe IndicatorBlock e ele deve implementar um método:

  • EmBarUpdate() - onde o valor do indicador é computado e armazenado em um dos amortecedores de saída. É chamado para cada barra no gráfico.

 

Quando você verificar o código fonte, você deve notar poucas coisas.

Primeiro, trechos em StrategyQuant usam muito anotações - @Parameter, @Output, @BuildingBlock - estas anotações são usadas para declarar uma propriedade especial de uma determinada variável ou classe - que a variável é um parâmetro público ou valor de saída, ou que a classe é um bloco indicador.

Em segundo lugar, uma vez que você cria e compila um indicador, você pode chamá-lo de outros métodos ou indicadores usando Indicadores.SeuIndicador(YourIndicatorParameters). É assim que um indicador pode ser chamado de outro - vamos usá-lo também em Envelopes para chamar indicadores de Média Móvel, chegaremos a ele mais tarde.

 

Vamos percorrer passo a passo o código fonte da classe indicadora padrão criada a partir do modelo:

package SQ.Blocks.Indicators.Envelopes;

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

import SQ.Internal.IndicatorBlock;

esta é a declaração padrão Java de um pacote e importação de classes requeridas - as que usamos em nossa própria classe.


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

Definição anotada de nossa classe indicadora, dizendo ao sistema que se trata de um bloco de construção com nome dado.

  • nome campo é o que é exibido na IU ao escolher os blocos de construção.
  • exibir campo é o que é exibido em Wizard com parâmetros. Você pode controlar quais parâmetros são mostrados e em qual lugar
  • returnType é um tipo de indicador, ele diz que tipo de valor este indicador calcula. Ele é usado para que StrategyQuant saiba quais tipos devem ser comparados com o quê. Por exemplo, ele não compararia CCI (que retorna Número) com Bandas de Bolinger (que retorna Preço).

 

Existem basicamente três tipos de retorno que um indicador pode ter:

  • Preço - O indicador calcula o preço e é exibido na tabela de preços - como Bandas de Bollinger, Média Móvel, etc.
  • Número - O indicador calcula o número que é exibido em seu próprio gráfico - como CCI, RSI, MACD, etc.
  • Intervalo de preços - indicador calcula a faixa de preços (diferença de dois preços) - como ATR

Outros tipos de retorno são utilizados em outros tipos de blocos de construção.

 

Em nosso caso, os envelopes são calculados a partir da média móvel de um preço, de modo que são exibidos na tabela de preços. Isto significa que seu tipo de retorno é Preço.

 

@Parameter
public DataSeries Input;

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

@Output
public DataSeries Value;

o que se segue são parâmetros indicadores. Cada indicador pode ter vários parâmetros de entrada, o modelo cria apenas dois deles como exemplo. Cada parâmetro é anotado com @Parameter anotação, que poderia ter vários atributos.

O primeiro parâmetro é EntradaÉ o conjunto de séries de dados a partir do qual o indicador é calculado - pode ser, por exemplo, Preço Aberto, Alto, Baixo ou Fechado.

O segundo parâmetro é PeríodoOs indicadores geralmente têm algum período no qual são computados.

A terceira variável é Valor, observe que tem anotação diferente @Output. Isto significa que esta variável não é um parâmetro indicador, mas seu buffer de saída. Os indicadores geralmente têm apenas um buffer de saída, mas podem ter mais - por exemplo, a banda Bollinger tem buffer superior e inferior.

Há mais um parâmetro oculto Turno - é por padrão em todos os indicadores e diz ao motor de negociação qual o valor de volta que ele deve procurar. Geralmente não é preciso se preocupar com este parâmetro, ele é usado automaticamente.

 

Depois há um método:

vazio protegido No BarUpdate() lança TradingException {...}

 

Este é o método onde os valores indicadores são computados. Ele é chamado internamente pelo SQ para cada barra e deve calcular o valor do indicador para esta barra e salvá-lo no buffer de saída.

Este é o código fonte do modelo de indicador padrão. Na próxima etapa mostraremos as mudanças que devem ser feitas para implementar nosso indicador de Envelopes.

 

Modificando o modelo padrão gerado e implementando o indicador

O indicador criado no passo 1 é um modelo de indicador padrão, ele ainda não computa Envelopes. Para implementá-lo, devemos fazer algumas coisas:

Atualizar sua anotação @BuildingBlocks

Atualizaremos a anotação deste indicador da seguinte forma:

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

Esta é a parte mais simples. Vamos apenas atualizar nome do indicador e adicionar os novos parâmetros reais (ver abaixo) ao exibir atributo.

 

Definir seus parâmetros reais

A primeira coisa a fazer é pouco complicada - devemos mudar o tipo de padrão Entrada parâmetro. No modelo padrão ele é definido da seguinte forma:

@Parameter
public DataSeries Input;

é um parâmetro chamado Entradacom tipo Série DataSeries. Isto é válido para uma grande parte dos indicadores que são computados a partir de apenas um preço. Por exemplo, os indicadores CCI, RSI, etc. são geralmente computados a partir de Close price. Você pode configurá-los para serem computados a partir de preços diferentes, por exemplo, a partir de preço Aberto, mas ainda assim é apenas uma matriz de preços.

 

O tipo DataSeries é um conjunto de valores tipo que contém valores para preços Fechados, ou para preços Abertos, ou para preços Típicos, etc.
Entretanto, se você olhar o código fonte do Envelopes MQL, verá que ele calcula seus valores a partir de um dos valores de preço e a partir do Volume.

 

Para poder acessar várias matrizes de preços de uma só vez, usaremos tipos diferentes para a produção:

@Parameter
public ChartData Input;


ChartData
 tipo é um objeto que representa todo o gráfico - você terá acesso aos preços Aberto, Alto, Baixo, Fechado, Volume no gráfico dado. Precisamos disto para que possamos cmputar o indicador de acordo com o parâmetro Preço Aplicado.

 

Nota rápida - escolher o tipo certo para a variável de dados de entrada não é difícil:
Se o indicador for calculado a partir de um preço e não houver opção de escolher o preço aplicado, continue usando a série DataSeries.
Se for calculado a partir de vários preços ou se houver uma escolha - por exemplo, Alto, Baixo, Fechado, etc. - use ChartData.

 

Depois há outros parâmetros indicadores:

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

MA_Period é um parâmetro de período "padrão" para este indicador.


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

MA_Moved é a mudança deste indicador. No código MQL este parâmetro se chama MA_Shift, mas Shift é uma palavra reservada no SQ, portanto temos que renomeá-lo.

 

@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 é o método da média móvel. É um pouco mais complexo, porque definimos uma lista de seleção (controle de caixa combinada) como controle de edição deste parâmetro. Portanto, ao editar no Wizard, o usuário poderá escolher entre os valores pré-definidos.

 

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

O mesmo se aplica a Applied_Price - esta é uma escolha de entradas que pode ser usada para calcular Envelopes.

 

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

Desvio é o último parâmetro de entrada do indicador Envelopes.

 

Observe que também especificamos alguns valores para min, max, e passo para estes parâmetros.

minValor/maxValor são as faixas mínimas/máximas que você será capaz de definir.

construtorMinValue/builderMaxValue são faixas opcionais que o construtor em SQ utilizará ao gerar estratégias - elas podem ser menores que as faixas máximas definidas em minValue/maxValue

defaultValue define o valor padrão deste indicador.

passo/construtorStep define o passo do valor do parâmetro

 

Definir saídas

O indicador Envelopes tem duas saídas - superior e inferior - você pode ver duas linhas diferentes no gráfico MT4.

Portanto, temos que definir também duas saídas:

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

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

A anotação @Output significa que este é um buffer de saída para este indicador. Note que ele tem o tipo DataSeries, o que significa que é uma matriz de valores duplos.

 

Implementar o método OnBarUpdate()

Se você olhar o código MQL da Envelopes, verá que é bastante simples, seu código MQL é:

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

Se você analisar um pouco, verá que os valores Superior e Inferior são computados usando uma fórmula simples:

Faixa superior = [1+DEVIO/100] * MA(PREÇO, PERÍODO)
Banda inferior = [1-DEVIATION/100] * MA(PREÇO, PERÍODO)

onde os parâmetros DEVIATION, MA ,PRICE e PERIOD são configuráveis.

 

Podemos implementá-lo em Java desta forma:

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

 

Método EmBarUpdate() é chamado para cada barra na tabela. Sua responsabilidade é computar o(s) valor(es) do indicador nesta barra e armazená-lo nos buffers de saída.

Assim, em nosso caso, calcularemos os valores superiores e inferiores da barra real e os armazenaremos em seus amortecedores, chamando Upper.set(), Lower.set().

 

Note que utilizamos um método especial de ajuda computeMA() para calcular a média móvel de acordo com os parâmetros MA_Method e Applied_Price.

O código para este método de ajuda é:

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

É um pouco mais longo, mas compreensível. Primeiro vamos escolher os dados de preço corretos de acordo com Preço_aplicado parâmetro.

Na segunda etapa, chamaremos o indicador de média móvel apropriado nesta entrada, de acordo com MA_Método parâmetro.

 

Vamos dissecar uma das chamadas, por exemplo: Indicators.SMA(MAInput, MA_Period).Value.get(MA_Moved):

  • Indicadores.SMA(MAInput, MA_Period) chamará o indicador SMA na entrada MAInput com MA_Period. O indicador SMA tem apenas um valor chamado de buffer de saída, portanto, os valores do indicador computados serão armazenados lá.
  • obteremos o buffer simplesmente chamando Valor
  • O valor é um buffer (tipo DataSeries), o mesmo que nossos buffers superior e inferior, o que significa que é uma matriz de valores duplos, onde cada valor pertence a uma barra no gráfico. Para obter o valor da barra na nona posição, devemos chamar Valor.get(N).
    Em nosso caso, vamos chamar Value.get(MA_Moved)porque queremos valorizar opcionalmente algumas barras para trás, de acordo com o parâmetro MA_Moved.

 

Assim, toda a chamada Indicadores.SMA(MAInput, MA_Period).Value.get(MA_Moved) irá computar SMA com período Período MA_P sobre o MAInput dados, e retorna seu valor MA_Moved bares atrás.

 

Observe que os valores no buffer de saída são indexados a partir de zero, onde zero é o valor da barra mais atual.

Portanto:

  • Value.get(0) - retorna o valor da barra atual
  • Value.get(1) - retorna o valor da barra anterior
  • Value.get(2) - devolve valor da barra antes da barra anterior e assim por diante

 

Isso é tudo, agora que atingimos Compilação e depois reiniciar o SQ, veremos nosso novo indicador de Envelopes na seção Sinais de Indicadores Aleatórios.

 

Código fonte completo de nosso novo indicador - você pode baixá-lo também no anexo a este artigo:

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

 

 

Teste de novo indicador no SQ X vs dados da MT

acabamos de criar (ou estamos em processo de desenvolvimento) nosso novo indicador. Como sabemos que o implementamos corretamente?

Quando você criou seu novo indicador em StrategyQuant e ele foi compilado com sucesso, também deve ser verificado se ele realmente funciona da mesma forma que no MetaTrader - em outras palavras, se os valores computados por ele são os mesmos que seus valores em MT4.

 

Para isso, temos uma ferramenta de Teste de Indicadores no Editor de Código. Ela funciona simplesmente comparando os valores computados em SQ com os valores computados em MT4.

 

Em geral, ele funciona em algumas etapas simples:

  1. Use o helper script para computar e exportar dados indicadores no MetaTrader
  2. Copiar os arquivos de dados computados para o local apropriado para que o SQ possa encontrá-los
  3. Configurar e executar o teste indicador no SQ

Use o helper script para computar e exportar dados indicadores no MetaTrader

Como primeiro passo devemos preparar os dados de teste MT4 - devemos calcular o indicador em um número de barras e salvar seus valores computados em um arquivo.

Para isso fornecemos uma simples EA que você pode usar - ela está localizada em {SQ}/custom_indicators/MetaTrader4/Experts/SqIndicatorValuesExportEA.mq4

 

Adicione este EA ao seu MetaTrader, modifique-o para computar e calcular o valor de saída de seu indicador e execute-o no MT4 StrategyTester em qualquer dado - para fazer um teste ideal ele deve ser executado em pelo menos 1000 barras.

 

Como o Envelopes tem dois amortecedores de saída, temos que rodá-lo duas vezes - uma para o amortecedor superior, outra para o inferior.

Aqui está um código modificado deste roteiro de exportação de ajuda que computa o 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);
}

ele irá calcular o inicador de Envelopes no MT4 chamando seu método interno de iEnvelopes() com parâmetros apropriados.

Observe que os parâmetros podem ser configurados - você não precisa usar parâmetros padrão. É uma boa prática incutir valores de parâmetros também no nome do arquivo de dados de saída - como no nosso caso "Envelopes_14_0_0_0_0_0.1_upper.csv", para que saibamos que ele foi gerado com estes parâmetros.

Agora podemos executar este roteiro duas vezes no MT Tester:

Quando terminar deve criar um arquivo de dados com valores indicadores computados, bem como preços Abertos, Altos, Baixos, Fechados para cada barra. O arquivo será salvo em MetaTrader4 -> {Pasta de dados}/tester/files/Your_FILE_NAME.csv


Deveríamos ver dois arquivos ali:
Envelopes_14_0_0_0_0.1_upper.csv
Envelopes_14_0_0_0_0.1_lower.csv

 

Copiar os arquivos de dados computados para o local apropriado para que o SQ possa encontrá-los


Copie estes arquivos para uma pasta
{SQ instalação}/teste/indicadores/MetaTrader4

Crie esta pasta se ela não existir, o SQ Indicaotrs Tester procura por arquivos nesta pasta.

Agora temos o arquivo de dados preparado, vamos iniciar um teste em StrategyQuant.

 

Configurar e executar o teste indicador no SQ

Co to Code Editor e clique em Test indicators on the toolbar.

Abrirá o diálogo Indicator Tester, clique em Adicionar novo teste. Adicionar indicadores de Envelopes ao teste, tanto para a saída superior quanto para a inferior.

Você o verá na tabela como segue. O último pensamento que precisamos fazer é modificar o Nome do arquivo de testes de acordo com os nomes reais dos arquivos de dados de teste criados na etapa anterior, e opcionalmente também Parâmetros de testese você usou outros que não os padrões:

Quando estiver pronto clique em Início para executar os testes.

No caso ideal, os testes serão bem sucedidos e os valores computados no SQ corresponderão aos valores computados no MT4:

Se algo falhar, haverá diferenças entre os valores de SQ e MT4. Você pode clicar na mesagem das diferenças para vê-las na lista:

Se o teste falhar, primeiro verifique se os dados de teste gerados no MT4 estavam usando os mesmos parâmetros indicadores, pode haver um erro nisso.

Se os dados de teste estiverem corretos, então há algo errado com sua implementação do SQ de seu indicador - ele funciona de forma diferente de sua contraparte MT4 e deve ser corrigido.

 

Acréscimo da tradução do bloco Indicador no idioma da plataforma de destino

Agora o indicador está funcionando corretamente em StrategyQuant. Você pode usá-lo para gerar algumas estratégias com base nele, ou usá-lo no AlgoWizard. Mas ainda não terminamos.

Se você for para o código fonte de sua estratégia, você verá uma mensagem de erro como esta:

Isso significa que ao gerar o Pseudo Code / MT4 / MT5 ou código de estação, StrategyQuant não conseguiu encontrar um modelo que traduzisse o bloco do formato SQ XML interno para o idioma da plataforma de destino.


Até agora, criamos um código para os envelopes a serem computados dentro da StrategyQuant. Mas StrategyQuant não sabe como traduzir este indicador em um código em sua plataforma de negociação - ele depende da própria plataforma.

Em StrategyQuant, as estratégias geradas são salvas internamente no formato XML. Quando você mudar para Strategy XML e procurar pelo indicador Envelopes, você verá que ele é salvo assim:

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

Esta é apenas uma parte da estratégia XML que contém a comparação de Envelopes com número. Note que ele usa blocos () IsGreater, Envelopes, Número.

A SQ procurará por modelos para traduzir cada um dos blocos XML para a linguagem da plataforma de destino. Templates para IsGreater e Número estão por padrão no sistema, mas nos falta um modelo para Envelopes.

 

Os gabaritos são armazenados em Código sub-árvore. Lá, cada plataforma suportada tem sua própria pasta, e dentro dela há uma subpasta /blocos que contém modelos para cada bloco de construção.

 

Os arquivos de modelo têm .tpl extensão e são muito simples. Eles usam o motor de modelo Freemarker (https://freemarker.apache.org) para traduzir o XML do indicador para o código da plataforma alvo.

Note que os modelos NÃO contém código para calcular o indicador na plataforma alvo, eles contêm código para CHAMADO o indicador.

Se você verificar, verá que não há Envelopes.tpl modelo, portanto o código fonte mostra uma mensagem de que o modelo para ele está faltando.

Adicionando o modelo de código Pseudo para um novo bloco

Quando você olhar para seu Envelopessnippet na janela Navigator você verá que há um ícone de erro e quando passar o mouse sobre ele, você 'verá a mensagem de erro - falta o código do modelo para cada plataforma alvo.

 

A maneira mais fácil de adicioná-lo é clicar no arquivo Envelopes.java com o botão direito do mouse para abrir o menu de puxar para baixo e lá
escolha a ação
Adicionar tudo o que falta.

Isto adicionará modelos padrão para todas as plataformas alvo.
Quando você vai para Code -> Pseudo code -> blocks você verá que ele adicionou o modelo Envelopes.tpl com algum conteúdo padrão.

Você pode ver que o modelo é bastante simples, geralmente é apenas uma linha.

 

Agora que o modelo está lá, você pode verificar novamente o código fonte de sua estratégia.


Você pode ver que o código fonte foi produzido, mas ele não é realmente correto. 

Ele mostra Envelopes(Tabela principal, , , 1) ao invés de parâmetros reais de Envelopes. É porque o Envelopes.tpl foi criado utilizando o modelo padrão, ele não utilizou os parâmetros reais dos indicadores.

Se você verificar o código PseudoCode/blocos/Envelopes.tpl você verá que é o seguinte:

Envelopes( , , )

Os métodos printInput e imprimirShift são métodos padrão para imprimir valores de entrada de dados e de deslocamento e funcionam corretamente por padrão porque cada indicador tem alguma entrada de gráficos/dados e deslocamento.

Mas não temos parâmetros chamados Param1 e Param2 em nosso indicador. 

Em vez disso, temos aí outros cinco parâmetros: MA_Period, MA_Moved, MA_Method, Applied_Price, Deviation.

 

Portanto, modificaremos o modelo desta forma:

Envelopes( , , , , )

 

Agora, se você olhar para o Código Pseudo, verá que ele é exibido com os valores corretos dos parâmetros:

Como você pode ver, imprimir um parâmetro em um modelo é muito simples - você só tem que usar o método:

<@printParam block “#PARAMETER_NAME#” />

onde NOME_DO_PARÂMETRO é o nome da variável de parâmetro do código Java.


Ainda há uma coisa que pode ser melhorada - os parâmetros MA_Método e Preço_aplicado são exibidos como números - gostaríamos de exibi-los como textos, para que possamos saber quais valores foram selecionados.

Para fazer isso, podemos usar o método:

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


Este método traduzirá o valor numérico para a opção com base em seu número.

Além disso, para não ficarmos sobrecarregados com informações sem importância, não precisamos exibir o valor do parâmetro MA_Moved em código Pseud. Podemos simplesmente apagá-lo do modelo.

Portanto, nosso código final de modelo de PseudoCódigo para envelopes em PseudoCódigo será o seguinte:

Envelopes( , , , )

e produzirá uma produção como esta:

 

Adicionando o modelo MetaTrader 4 para o novo bloco

Na etapa anterior, adicionamos o modelo de Código Pseudo para nosso indicador Envelopes, para que possamos ver as regras de estratégia no Código Pseudo.

Devemos repetir este passo para cada plataforma alvo sobre a qual queremos utilizar nossa estratégia. 

Portanto, vamos corrigir o modelo para o MetaTrader MQL. Há duas possibilidades no MetaTrader:

  • ou o indicador está incorporado no MetaTrader e então podemos chamá-lo usando sua chamada de função MQL,
  • ou é um indicador personalizado e devemos chamá-lo usando a chamada iCustom MQL.

Mostraremos os dois caminhos, eles diferem apenas ligeiramente no código do modelo.

 

Primeira possibilidade - o indicador está embutido no MetaTrader

Neste caso, você pode encontrar o indicador na lista de indicadores disponíveis no navegador MT4, e você
também pode encontrar o método para chamá-lo no guia de referência MQL:

A partir da documentação da MQL sabemos que quando chamamos este indicador temos que chamar a função iEnvelopes() com os parâmetros corretos.

Portanto, abriremos o arquivo Code / MetaTrader4 / blocks / Envelopes.tpl e o modificaremos da seguinte forma:

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

O que fizemos foi renomear o método e acrescentar os parâmetros corretos. Métodos printInput e imprimirShift produzir uma saída correta por padrão.

Observe mais um parâmetro - Linha. Como Envelopes tem duas linhas (Alta, Baixa), também a chamada para iEnvelopes permite especificar o valor para qual linha você quer recuperar - é o 8º parâmetro modoque é o índice da linha.

Este parâmetro em MQL é 1 para Superior, ou 2 para Inferior.

Linha parâmetro também é criado por padrão pelo SQ - basta verificar o XML deste bloco. Mas é baseado em zero, e o índice de linha depende da ordem das variáveis @Output definidas na classe Java. Assim, em SQ 0 = Superior, 1 = Inferior. Para obter os mesmos valores que em MT4, temos que adicionar 1 ao valor da linha.

 

Quando vamos ao código fonte MT4, vemos que ele produziu esta saída:

Que é uma maneira correta de chamar o indicador Envelopes em MQL .

 

Segunda possibilidade - é um indicador personalizado (externo) para MetaTrader

Agora, e se o indicador não estiver incorporado no Metatrader? A situação é apenas um pouco mais complicada.
Como exemplo, digamos que o indicador Envelopes não existe no MT4, e temos que usá-lo como indicador personalizado.


Primeiro, baixe o indicador Envelopes a partir deste link: https://www.mql5.com/en/code/7975
 e salvá-lo em um arquivo para {MT4} -> Pasta de dados/MQL/Indicadores/Envelopes.mq4

Desta forma, ele ficará disponível no MetaTrader e poderá ser usado e chamado. 

 

Os indicadores personalizados são chamados usando a função iCustom do MQL:

Portanto, a chamada correta do indicador personalizado de Envelopes em MQL seria:

iCustom(Símbolo, Prazo, "Envelopes", MA_Period, MA_Moved, MA_Method, Applied_Price, Desvio, 1, Shift)

para obter a linha superior, e

iCustom(Símbolo, Prazo, "Envelopes", MA_Period, MA_Moved, MA_Method, Applied_Price, Desvio, 2, Shift)

para conseguir a linha inferior.

Definimos nosso modelo da seguinte forma:

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

 

que novamente produz o código MQL correto, usando a chamada de indicador personalizada:

 

A única diferença da opção anterior é que não usamos o método iEnvelopes MQL predefinido, mas um método geral iCustom que nos permite chamar qualquer indicador personalizado externo.

 

 

Este artigo foi útil? O artigo foi útil O artigo não foi útil

Assine
Notificação de
2 Comentários
Mais antigo
Novidades Mais Votados
Feedbacks em linha
Ver todos os comentários
dorsler
dorsler
26. 10. 2020 4:20 pm

Obrigado Marc
Basta olhar para o indicador de envelopes tentando puxar isto para o SQ do artigo que você escreveu
https://strategyquant.com/doc/programming-sq/adding-envelopes-indicator-step-by-step
O arquivo CSV gerado abaixo só retorna um único arquivo no arquivo de teste MT4 quando o indicador tiver executado o teste.
// alterar o nome do arquivo abaixo  
string fileName = “Envelopes_14_0_0_0_0.1_upper.csv”;
A SQ ainda será capaz de ler os valores superior e inferior ou é necessária outra linha de código?
Muito parecido com este indicador, portanto será uma boa adição à biblioteca de testes.
Obrigado
Dave

tomas262
tomas262
Responder a  dorsler
30. 10. 2020 7:39 pm

Você precisa exportar 2 arquivos CSV separados. Um contendo valores para o envelope superior usando este valor de código = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0 , 0.1 , 1 , 1); e depois exportar outro arquivo CSV com valores para o envelope inferior usando o valor de código = iEnvelopes(NULL, 0 , 14 , 0 , 0 , 0 , 0 , 0.1 , 2 , 1); Note os valores alterados para o número 2 usados na última mas uma posição na segunda linha de código. Portanto, agora você tem 2 arquivos CSV tanto Envelopes_14_0_0_0_0_0.1_upper.csv como Envelopes_14_0_0_0_0_0.1_lower.csv… Leia mais "

Última edição 3 anos atrás por tomas262