Gerador de sinal de negócios baseado em um indicador personalizado
Introdução
Nesse artigo, direi a você como criar um gerador de sinal de negócios baseado em um indicador personalizado. Você verá como pode escrever seu próprio modelo de negócios para um indicador personalizado. Também explicarei o objetivo do modelo 0 e porque estruturas do tipo IS_PATTERN_USAGE(0) são utilizadas no módulo de sinais de negócios.
O artigo utilizará dois tipos de código: o código que estamos preste a modificar e o código já modificado. O código modificado será destacado como a seguir:
//+------------------------------------------------------------------+
//| MySignal.mqh |
//| Copyright © 2012, Vladimir Karputov |
//| http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
O código modificado é o código a ser copiado e colado no gerador de sinal de negócios. Espero que você entenda melhor o código através do destaque.
1. Indicador personalizado
Tenho certeza que deve haver um indicador não incluído na entrega padrão que você a muito deseja utilizar. E esse é o indicador baseado no qual você deseja elaborar um módulo de sinal de negócios. Usarei o indicador MACD da entrega padrão como um indicador. O localização do indicador é a conforme a seguir: ...MQL5\Indicators\Examples\MACD.mq5.
Cada indicador pode descrever um ou mais modelos de mercado. Um modelo de mercado é uma certa combinação do valor do indicador e do valor do preço. Os modelos disponíveis para o indicador MACD são opostos, o cruzamento entre os principais e a linha do sinal, o cruzamento do nível zero, a divergência e a dupla divergência.
1.1 O modelo novo do indicador.
Vamos presumir que não estamos felizes com os modelos de mercado dados fornecidos disponíveis para o indicador e queremos introduzir nosso próprio modelo de indicador. A descrição do novo modelo de indicado: se o indicador MACD estiver abaixa da linha zero e seus valores estão aumentando, podemos esperar um crescimento futuro e abrirmos uma posição longa:
Figura 1: Modelo de crescimento potencial do indicador
Se o indicador MACD estiver acima da linha zero e seus valores estiverem diminuindo, podemos esperar um decréscimo futuro e abrirmos uma posição curta:
Figura 2: Modelo de queda potencial do indicador
Então, tomamos uma decisão sobre o indicador personalizado e surgimos com o novo modelo de negócios para o indicador e sua descrição. Vamos prosseguir para a escrita do código.
2. Escrevendo o gerador do sinal de negócios baseado em nosso indicador personalizado
Nosso gerador é o descendente da classe base CExpertSignal. A classe base CExpertSignal é uma classe para a criação de geradores de sinais de negócios. A classe CExpertSignal contém um conjunto de métodos públicos(sendo assim acessíveis externamente) que permitem a um Expert Advisor ver o indicador de um gerador de sinal de negócios com relação a direção da entrada no mercado.
Já que estamos trabalhando com nosso próprio gerador de sinal de negócios, ele deve ser herdado da classe CExpertSignal, com os relevantes métodos virtuais redefinidos (preenchidos com o código correspondente).
3. Criando a classe do gerador de sinal de negócios
O gerador do sinal de negociação deve estar por padrão localizado na pasta ...MQL5\Include\Expert\Signal. Para não sobrecarregar a pasta ...\Signal da biblioteca padrão com muita informação, vamos criar uma nova pasta sob a pasta ...\Expert e chamá-la de \MySignals:
Figura 3. Criando a nova pasta MySignals
Em seguida, criaremos um include file utilizando o assistente do MQL5. No MetaEditor, selecione "Novo" sob o menu do arquivo e depois selecione "Incluir Arquivo (*.mqh)".
Figura 4. Assistente do MQL5. Criando uma inclusão do arquivo mqh
O nome da classe do gerador de sinal será MySignal. Ela ficará localizada sob Include\Expert\MySignals\MySignal. Vamos especificá-lo:
Figura 5. Assistente do MQL5. Configuração do local do arquivo incluso.
Após clicar em "Concluir", o assistente do MQL5 gerará um modelo vazio. Desse momento em diante, faremos tudo manualmente e copiaremos/colaremos dados. Gostaria de chamar sua atenção para o fato de que, internamente, todos os sinais da biblioteca padrão são quase idênticos. Eles apenas diferem nos algoritmos utilizados para determinar modelos de negócios.
Portanto, você pode tomar qualquer arquivo da pasta \Include\Expert\Signal, copiar seu conteúdo e colá-lo dentro de seu modelo. Depois você pode começar a editar o arquivo resultante do gerador do sinal de negócios.
4. Descrição da classe do gerador do sinal de negócios
Como um modelo, eu peguei o arquivo \Include\Expert\Signal\SignalEnvelopes.mqh, do qual eu copiei tudo, menos o cabeçalho://+------------------------------------------------------------------+ //| SignalEnvelopes.mqh | //| Copyright 2009-2013, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+
e colei ele todo dentro de nosso modelo MySignal.mqh quase vazio. Cheguei a esse resultado:
//+------------------------------------------------------------------+ //| MySignal.mqh | //| Copyright © 2012, Vladimir Karputov | //| http://wmua.ru/slesar/ | //+------------------------------------------------------------------+ #include <Expert\ExpertSignal.mqh> // wizard description start //+------------------------------------------------------------------+ //| Description of the class | //| Title=Signals of indicator 'Envelopes' | //| Type=SignalAdvanced | //| Name=Envelopes | //| ShortName=Envelopes | //| Class=CSignalEnvelopes | //| Page=signal_envelopes | //| Parameter=PeriodMA,int,45,Period of averaging | //| Parameter=Shift,int,0,Time shift | //| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging | //| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | //| Parameter=Deviation,double,0.15,Deviation | //+------------------------------------------------------------------+ // wizard description end //+------------------------------------------------------------------+ //| Class CSignalEnvelopes. | //| Purpose: Class of generator of trade signals based on | //| the 'Envelopes' indicator. | //| It is derived from the CExpertSignal class. | //+------------------------------------------------------------------+ class CSignalEnvelopes : public CExpertSignal { protected: CiEnvelopes m_env; // object-indicator //--- adjusted parameters int m_ma_period; // the "period of averaging" parameter of the indicator int m_ma_shift; // the "time shift" parameter of the indicator ENUM_MA_METHOD m_ma_method; // the "method of averaging" parameter of the indicator ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter of the indicator double m_deviation; // the "deviation" parameter of the indicator double m_limit_in; // threshold sensitivity of the 'rollback zone' double m_limit_out; // threshold sensitivity of the 'break through zone' //--- "weights" of market models (0-100) int m_pattern_0; // model 0 "price is near the necessary border of the envelope" int m_pattern_1; // model 1 "price crossed a border of the envelope" public: CSignalEnvelopes(void); ~CSignalEnvelopes(void); //--- methods of setting adjustable parameters void PeriodMA(int value) { m_ma_period=value; } void Shift(int value) { m_ma_shift=value; } void Method(ENUM_MA_METHOD value) { m_ma_method=value; } void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; } void Deviation(double value) { m_deviation=value; } void LimitIn(double value) { m_limit_in=value; } void LimitOut(double value) { m_limit_out=value; } //--- methods of adjusting "weights" of market models void Pattern_0(int value) { m_pattern_0=value; } void Pattern_1(int value) { m_pattern_1=value; } //--- method of verification of settings virtual bool ValidationSettings(void); //--- method of creating the indicator and time series virtual bool InitIndicators(CIndicators *indicators); //--- methods of checking if the market models are formed virtual int LongCondition(void); virtual int ShortCondition(void); protected: //--- method of initialization of the indicator bool InitMA(CIndicators *indicators); //--- methods of getting data double Upper(int ind) { return(m_env.Upper(ind)); } double Lower(int ind) { return(m_env.Lower(ind)); } }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CSignalEnvelopes::CSignalEnvelopes(void) : m_ma_period(45), m_ma_shift(0), m_ma_method(MODE_SMA), m_ma_applied(PRICE_CLOSE), m_deviation(0.15), m_limit_in(0.2), m_limit_out(0.2), m_pattern_0(90), m_pattern_1(70) { //--- initialization of protected data m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CSignalEnvelopes::~CSignalEnvelopes(void) { } //+------------------------------------------------------------------+ //| Validation settings protected data. | //+------------------------------------------------------------------+ bool CSignalEnvelopes::ValidationSettings(void) { //--- validation settings of additional filters if(!CExpertSignal::ValidationSettings()) return(false); //--- initial data checks if(m_ma_period<=0) { printf(__FUNCTION__+": period MA must be greater than 0"); return(false); } //--- ok return(true); } //+------------------------------------------------------------------+ //| Create indicators. | //+------------------------------------------------------------------+ bool CSignalEnvelopes::InitIndicators(CIndicators *indicators) { //--- check pointer if(indicators==NULL) return(false); //--- initialization of indicators and time series of additional filters if(!CExpertSignal::InitIndicators(indicators)) return(false); //--- create and initialize MA indicator if(!InitMA(indicators)) return(false); //--- ok return(true); } //+------------------------------------------------------------------+ //| Initialize MA indicators. | //+------------------------------------------------------------------+ bool CSignalEnvelopes::InitMA(CIndicators *indicators) { //--- check pointer if(indicators==NULL) return(false); //--- add object to collection if(!indicators.Add(GetPointer(m_env))) { printf(__FUNCTION__+": error adding object"); return(false); } //--- initialize object if(!m_env.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied,m_deviation)) { printf(__FUNCTION__+": error initializing object"); return(false); } //--- ok return(true); } //+------------------------------------------------------------------+ //| "Voting" that the price will grow. | //+------------------------------------------------------------------+ int CSignalEnvelopes::LongCondition(void) { int result=0; int idx =StartIndex(); double close=Close(idx); double upper=Upper(idx); double lower=Lower(idx); double width=upper-lower; //--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying if(IS_PATTERN_USAGE(0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width) result=m_pattern_0; //--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width) result=m_pattern_1; //--- return the result return(result); } //+------------------------------------------------------------------+ //| "Voting" that the price will fall. | //+------------------------------------------------------------------+ int CSignalEnvelopes::ShortCondition(void) { int result =0; int idx =StartIndex(); double close=Close(idx); double upper=Upper(idx); double lower=Lower(idx); double width=upper-lower; //--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width) result=m_pattern_0; //--- if the model 1 is used and price is above the rollback zone, then there is a condition for selling if(IS_PATTERN_USAGE(1) && close<lower-m_limit_out*width) result=m_pattern_1; //--- return the result return(result); } //+------------------------------------------------------------------+
‘Nota’ linha 6:
#include <Expert\ExpertSignal.mqh>
Aqui damos ao pré-processador um pedido para incluir a classe base CExpertSignal para a criação dos geradores de sinais do sinal de negócios em nosso modelo.
Continuamos a editar o modelo. Para garantir que nosso modelo esteja visível posteriormente no assistente do MQL5, precisamos alterar a descrição de nossa classe:
//+------------------------------------------------------------------+ //| Description of the class | //| Title=Signals of indicator 'Envelopes' | //| Type=SignalAdvanced | //| Name=Envelopes | //| ShortName=Envelopes | //| Class=CSignalEnvelopes | //| Page=signal_envelopes | //| Parameter=PeriodMA,int,45,Period of averaging | //| Parameter=Shift,int,0,Time shift | //| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging | //| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | //| Parameter=Deviation,double,0.15,Deviation | //+------------------------------------------------------------------+
Então, vamos ver. A linha
//| Title=Signals of indicator 'Envelopes' |
mostra o nome de nossa classe do sinal sob a qual ele será exibido no assistente do MQL5. Alteraremos esse nome para algo como isso:
//| Title=Signal of the 'Custom Indicator' indicator |
A próxima linha:
//| Name=Envelopes |
indica o nome para variáveis descritivas de nossa classe do sinal de negócios. Essa descrição será utilizada pelo assistente do MQL5. Vamos modificar essa linha como a seguir:
//| Name=MyCustomIndicator |
A próxima linha:
//| ShortName=Envelopes |
Daremos o mesmo nome a esse parâmetro:
//| ShortName=MyCustomIndicator |
A linha seguinte define o nome da classe:
//| Class=CSignalEnvelopes |
Vamos renomear esse parâmetro:
//| Class=CSignalMyCustInd |
Deixe o próximo parâmetro como está.
//| Page=signal_envelopes |
O grupo de parâmetro seguinte é responsável pela descrição dos parâmetros do indicador subjacentes ao gerador do sinal de negócios. Conforme mencionei anteriormente, utilizarei o ...MQL5\Indicators\Examples\MACD.mq5 como o indicador personalizado. Ele tem os seguintes parâmetros:
//--- input parameters input int InpFastEMA=12; // Fast EMA period input int InpSlowEMA=26; // Slow EMA period input int InpSignalSMA=9; // Signal SMA period input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_CLOSE; // Applied price
4.1 Bloco da descrição dos parâmetros
Por favor, note que os parâmetros dados acima aplicam-se somente ao MACD.mq5. Seu indicador personalizado pode ter parâmetros completamente diferentes. O principal aqui é coincidir os parâmetros do indicador com suas descrições na classe do sinal de negócios. O bloco de descrição do parâmetro na classe do sinal de negócios para o indicador personalizado em questão, MACD.mq5 , será como o seguinte:
//| Parameter=PeriodFast,int,12,Period of fast EMA |
//| Parameter=PeriodSlow,int,24,Period of slow EMA |
//| Parameter=PeriodSignal,int,9,Period of averaging of difference |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series |
Dê uma olhada em como os parâmetros no indicador coincidem agora com as descrições no bloco de descrição da classe. Seguindo todas as modificações, o bloco de descrição de nossa classe será como o seguinte:
//+------------------------------------------------------------------+ //| Description of the class | //| Title=Signal of the 'Custom Indicator' indicator | //| Type=SignalAdvanced | //| Name=MyCustomIndicator | //| ShortName=MyCustomIndicator | //| Class=CSignalMyCustInd | //| Page=signal_envelopes | //| Parameter=PeriodFast,int,12,Period of fast EMA | //| Parameter=PeriodSlow,int,24,Period of slow EMA | //| Parameter=PeriodSignal,int,9,Period of averaging of difference | //| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | //+------------------------------------------------------------------+
Em programação, é considerada uma boa prática fornecer comentários ao código de alguém, tornando assim o mesmo mais fácil de ser compreendido, ao retomá-lo após algum tempo ter se passado. Então, modificaremos o seguinte bloco:
//+------------------------------------------------------------------+ //| Class CSignalEnvelopes. | //| Purpose: Class of generator of trade signals based on | //| the 'Envelopes' indicator. | //| It is derived from the CExpertSignal class. | //+------------------------------------------------------------------+
para coincidir com a descrição de nossa classe:
//+------------------------------------------------------------------+
//| Class CSignalMyCustInd. |
//| Purpose: Class of the trading signal generator based on |
//| the custom indicator. |
//| It is derived from the CExpertSignal class. |
//+------------------------------------------------------------------+
Para evitar confusão, precisamos substituir todos os valores "CSignalEnvelopes" por "CSignalMyCustInd".
Figura 6. Substituindo CSignalEnvelopes por CSignalMyCustInd
Agora vamos dar uma olhada em alguns aspectos teóricos.
5. A classe CiCustom
Precisaremos da classe CiCustom para continuar a trabalhar no código da classe dos indicadores de negócios do indicador personalizado. A classe CiCustom foi criada especificamente para trabalhar com indicadores personalizados. A classe CiCustom fornece criação, configuração e acesso aos dados do indicador personalizado.
6. A classe CIndicators
CIndicators é a classe de coleção de instâncias de série temporal e de classes indicadoras técnicas. A classe CIndicators fornece criação, armazenamento e gerenciamento (sincronização de dados, identificação e gerenciamento de memória) de instância de classes de indicadores técnicos.
Estamos particularmente interessados na classe CIndicators por causa do método Create. Esse método cria um indicador de um tipo específico com parâmetros especificados.
7. Continue escrevendo nossa classe do sinal de negócios
O próximo bloco de código que modificaremos (linhas 28-42) é como a seguir:class CSignalMyCustInd : public CExpertSignal { protected: CiEnvelopes m_env; // object-indicator //--- adjusted parameters int m_ma_period; // the "period of averaging" parameter of the indicator int m_ma_shift; // the "time shift" parameter of the indicator ENUM_MA_METHOD m_ma_method; // the "method of averaging" parameter of the indicator ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter of the indicator double m_deviation; // the "deviation" parameter of the indicator double m_limit_in; // threshold sensitivity of the 'rollback zone' double m_limit_out; // threshold sensitivity of the 'break through zone' //--- "weights" of market models (0-100) int m_pattern_0; // model 0 "price is near the necessary border of the envelope" int m_pattern_1; // model 1 "price crossed a border of the envelope"
8. Criação do indicador personalizado no gerador do sinal de negócios
Dê uma olhada no bloco do código fornecido acima. A linha
CiEnvelopes m_env; // object-indicator
declara um objeto - o indicador de classe CiEnvelopes. CiEnvelopes é a classe para trabalhar com o indicador técnico da biblioteca padrão. A classe CiEnvelopes foi criada baseada no indicador técnico da biblioteca padrão. No entanto, estamos escrevendo o código do gerador baseado em nosso indicador personalizado. Portanto não há classe previamente pronta para nosso ou seu indicador personalizado na biblioteca padrão. O que podemos fazer é utilizar a classe CiCustom.
Vamos declarar nosso indicador como a classe CiCustom:
CiCustom m_mci; // indicator object "MyCustomIndicator"
8.1 Quatro Variáveis
Você se lembra do bloco de descrição de parâmetro na classe? Existiam três parâmetros naquela descrição. Na área protegida de nosso gerador de classe, declararemos agora quatro variáveis para passarmos os valores para nossos quatro parâmetros:
//--- adjustable parameters
int m_period_fast; // "fast EMA period"
int m_period_slow; // "slow EMA period"
int m_period_signal; // "difference averaging period"
ENUM_APPLIED_PRICE m_applied; // "price type"
O bloco de código seguinte:
//--- "weights" of market models (0-100) int m_pattern_0; // model 0 "price is near the necessary border of the envelope" int m_pattern_1; // model 1 "price crossed a border of the envelope"
Esse código declara variáveis que dão "peso" aos modelos de negócios de nosso gerador do sinal de negócios. Vamos substituir o bloco de "pesos" com o seguinte código:
//--- "weights" of the market models (0-100)
int m_pattern_0; // model 0 "the oscillator has required direction"
int m_pattern_1; // model 1 "the indicator is gaining momentum - buy; the indicator is falling - sell"
9. Modelo 0
Como você se lembra, no início desse artigo foi decidido descrever somente um novo modelo que será gerado por nosso gerador do sinal de negócios. No entanto, no código acima especifiquei dois modelos de mercado (modelo 0 e modelo 1). Aqui, o modelo 0 é um importante modelo auxiliar. Ele é necessário ao fazer negócios com pedidos pendentes. Quando aplicado, o modelo 0 assegura que pedidos pendentes sejam deslocados junto ao preço. Vamos dar uma olhada em nosso gerador do sinal de negócios e as seguintes condições:
- O indicador personalizado MACD está abaixo da linha zero,
- e seus valores estão decrescendo,
- estamos fazendo negócios com pedidos pendentes posicionados a 50 pontos do preço de abertura da barra (valor de preço de quatro dígitos).
Essas condições descrevem perfeitamente nosso modelo de negócios. Eis aqui como as coisas se desenrolarão: Nossas condições do modelo de negócios serão verificadas no aparecimento da barra nº 1. Aqui temos: O MACD está abaixo da linha zero, ainda que seja um momento vantajoso. Isso corresponde ao sinal de compra. Portanto, colocamos um pedido de interrupção de compra pendente:
Figura 7. Colocando um pedido de interrupção de compra pendente
Diante do aparecimento da próxima barra nº 2, o verificador de condição descobre que o MACD está abaixo de zero e está caindo. De acordo com nosso modelo de negócios, não existem condições atuais para compra ou venda. No entanto, perceba: quanto a lógica da classe CExpertSignal, já que não existem condições tanto para compra quanto para venda, todos os pedidos pendentes devem ser EXCLUíDOS. Nesse caso, se o preço subir de subitamente e dramaticamente, perderemos a oportunidade de entrar no mercado com nossa vantagem já que não haverá pedido pendente.
Aqui é onde o modelo 0 auxiliar parece ser bastante útil. O modelo auxiliar zero será aplicado, uma vez que:
- O indicador personalizado MACD está abaixo da linha zero.
Então podemos colocar um pedido de interrupção de compra pendente: Já que colocamos um pedido a 50 pontos do preço de abertura da barra, nós, de fato, simplesmente deslocamos a pedido de interrupção de compra pendente de acordo com o movimento do preço:
Figura 8. Deslocando o pedido de interrupção de compra para baixo
Assim, ao utilizar o modelo 0 auxiliar obtemos a oportunidade de deslocar um pedido pendente quanto ao movimento do preço.
10. Modificações futuras do código modelo
O próximo bloco de código a ser modificado é o a seguir:public: CSignalMyCustInd(void); ~CSignalMyCustInd(void); //--- methods of setting adjustable parameters void PeriodMA(int value) { m_ma_period=value; } void Shift(int value) { m_ma_shift=value; } void Method(ENUM_MA_METHOD value) { m_ma_method=value; } void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; } void Deviation(double value) { m_deviation=value; } void LimitIn(double value) { m_limit_in=value; } void LimitOut(double value) { m_limit_out=value; } //--- methods of adjusting "weights" of market models void Pattern_0(int value) { m_pattern_0=value; } void Pattern_1(int value) { m_pattern_1=value; } //--- method of verification of settings virtual bool ValidationSettings(void); //--- method of creating the indicator and time series virtual bool InitIndicators(CIndicators *indicators); //--- methods of checking if the market models are formed virtual int LongCondition(void); virtual int ShortCondition(void);
Nesse bloco, declaramos métodos de ajuste de parâmetros ajustáveis, métodos de ajuste de pesos de modelos de negócios, método de verificação de configurações, método de inicialização de indicador e métodos de verificação se os modelos do mercado estão gerados.
Levando em consideração que declaramos quatro variáveis nos parâmetros ajustáveis, o bloco de métodos para ajuste dos parâmetros será como a seguir:
//--- methods of setting adjustable parameters
void PeriodFast(int value) { m_period_fast=value; }
void PeriodSlow(int value) { m_period_slow=value; }
void PeriodSignal(int value) { m_period_signal=value; }
void Applied(ENUM_APPLIED_PRICE value) { m_applied=value; }
O próximo fragmento de código permanecerá inalterado:
//--- methods of adjusting "weights" of market models void Pattern_0(int value) { m_pattern_0=value; } void Pattern_1(int value) { m_pattern_1=value; } //--- method of verification of settings virtual bool ValidationSettings(void); //--- method of creating the indicator and time series virtual bool InitIndicators(CIndicators *indicators); //--- methods of checking if the market models are generated virtual int LongCondition(void); virtual int ShortCondition(void);
O próximo bloco de código a ser modificado é o a seguir:
protected: //--- method of initialization of the indicator bool InitMA(CIndicators *indicators); //--- methods of getting data double Upper(int ind) { return(m_env.Upper(ind)); } double Lower(int ind) { return(m_env.Lower(ind)); } };
Esse bloco será o mais modificado. Por favor, note que estou utilizando o método GetData da classe CIndicator. Nomes do métodos acionados serão fornecidos diretamente no código:
protected:
//--- indicator initialization method
bool InitMyCustomIndicator(CIndicators *indicators);
//--- methods for getting data
//- getting the indicator value
double Main(int ind) { return(m_mci.GetData(0,ind)); }
//- getting the signal line value
double Signal(int ind) { return(m_mci.GetData(1,ind)); }
//- difference between two successive indicator values
double DiffMain(int ind) { return(Main(ind)-Main(ind+1)); }
int StateMain(int ind);
double State(int ind) { return(Main(ind)-Signal(ind)); }
//- preparing data for the search
bool ExtState(int ind);
//- searching the market model with the specified parameters
bool CompareMaps(int map,int count,bool minimax=false,int start=0);
};
O próximo bloco de código é o construtor:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CSignalMyCustInd::CSignalMyCustInd(void) : m_ma_period(45), m_ma_shift(0), m_ma_method(MODE_SMA), m_ma_applied(PRICE_CLOSE), m_deviation(0.15), m_limit_in(0.2), m_limit_out(0.2), m_pattern_0(90), m_pattern_1(70) { //--- initialization of protected data m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE; }
No construtor, alteraremos os nomes das variáveis. Mais adiante, utilizaremos apenas duas séries: USE_SERIES_HIGH+USE_SERIES_LOW
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CSignalMyCustInd::CSignalMyCustInd(void) : m_period_fast(12),
m_period_slow(24),
m_period_signal(9),
m_applied(PRICE_CLOSE),
m_pattern_0(10),
m_pattern_1(50)
{
//--- initialization of protected data
m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
}
Vamos modificar o método ValidationSettings de nossa classe.
//+------------------------------------------------------------------+ //| Validation settings protected data. | //+------------------------------------------------------------------+ bool CSignalMyCustInd::ValidationSettings(void) { //--- validation settings of additional filters if(!CExpertSignal::ValidationSettings()) return(false); //--- initial data checks if(m_ma_period<=0) { printf(__FUNCTION__+": period MA must be greater than 0"); return(false); } //--- ok return(true); }
No bloco de verificação, verificamos a condição principal para o indicador personalizado dado: m_period_fast>=m_period_slow
//+------------------------------------------------------------------+
//| Checking parameters of protected data |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::ValidationSettings(void)
{
//--- validation settings of additional filters
if(!CExpertSignal::ValidationSettings())
return(false);
//--- initial data checks
if(m_period_fast>=m_period_slow)
{
printf(__FUNCTION__+": slow period must be greater than fast period");
return(false);
}
//--- ok
return(true);
}
O próximo bloco lida com a criação de indicadores:
//+------------------------------------------------------------------+ //| Create indicators. | //+------------------------------------------------------------------+ bool CSignalMyCustInd::InitIndicators(CIndicators *indicators) { //--- check pointer if(indicators==NULL) return(false); //--- initialization of indicators and time series of additional filters if(!CExpertSignal::InitIndicators(indicators)) return(false); //--- create and initialize MA indicator if(!InitMA(indicators)) return(false); //--- ok return(true); }
Conforme aplicado ao nosso indicador personalizado:
//+------------------------------------------------------------------+
//| Creation of indicators. |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::InitIndicators(CIndicators *indicators)
{
//--- check of pointer is performed in the method of the parent class
//---
//--- initialization of indicators and time series of additional filters
if(!CExpertSignal::InitIndicators(indicators))
return(false);
//--- creation and initialization of the custom indicator
if(!InitMyCustomIndicator(indicators))
return(false);
//--- ok
return(true);
}
O bloco seguinte é um bloco de inicialização do indicador:
//+------------------------------------------------------------------+ //| Initialize MA indicators. | //+------------------------------------------------------------------+ bool CSignalMyCustInd::InitMA(CIndicators *indicators) { //--- check pointer if(indicators==NULL) return(false); //--- add object to collection if(!indicators.Add(GetPointer(m_env))) { printf(__FUNCTION__+": error adding object"); return(false); } //--- initialize object if(!m_env.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied,m_deviation)) { printf(__FUNCTION__+": error initializing object"); return(false); } //--- ok return(true); }
Primeiro, adicionamos um objeto à coleção. Depois ajustamos os parâmetros de nosso indicador e criamos o indicador personalizado utilizando o método Create da classe CIndicators:
//+------------------------------------------------------------------+
//| Initialization of indicators. |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::InitMyCustomIndicator(CIndicators *indicators)
{
//--- add an object to the collection
if(!indicators.Add(GetPointer(m_mci)))
{
printf(__FUNCTION__+": error adding object");
return(false);
}
//--- set parameters of the indicator
MqlParam parameters[4];
//---
parameters[0].type=TYPE_STRING;
parameters[0].string_value="Examples\\MACD.ex5";
parameters[1].type=TYPE_INT;
parameters[1].integer_value=m_period_fast;
parameters[2].type=TYPE_INT;
parameters[2].integer_value=m_period_slow;
parameters[3].type=TYPE_INT;
parameters[3].integer_value=m_period_signal;
//--- object initialization
if(!m_mci.Create(m_symbol.Name(),0,IND_CUSTOM,4,parameters))
{
printf(__FUNCTION__+": error initializing object");
return(false);
}
//--- number of buffers
if(!m_mci.NumBuffers(4)) return(false);
//--- ok
return(true);
}
O próximo bloco verifica as condições de compra:
//+------------------------------------------------------------------+ //| "Voting" that the price will grow. | //+------------------------------------------------------------------+ int CSignalMyCustInd::LongCondition(void) { int result=0; int idx =StartIndex(); double close=Close(idx); double upper=Upper(idx); double lower=Lower(idx); double width=upper-lower; //--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying if(IS_PATTERN_USAGE(0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width) result=m_pattern_0; //--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width) result=m_pattern_1; //--- return the result return(result); }
De acordo com nossa implementação do modelo 0, dois modelos são verificados:
//+------------------------------------------------------------------+
//| "Voting" that the price will grow. |
//+------------------------------------------------------------------+
int CSignalMyCustInd::LongCondition(void)
{
int result=0;
int idx =StartIndex();
//--- check direction of the main line
if(DiffMain(idx)>0.0)
{
//--- the main line goes upwards, which confirms the possibility of the price growth
if(IS_PATTERN_USAGE(0))
result=m_pattern_0; // "confirming" signal number 0
//--- if the model 1 is used, look for a reverse of the main line
if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)<0.0)
result=m_pattern_1; // signal number 1
}
//--- return the result
return(result);
}
O seguinte bloco verifica as condições de venda:
//+------------------------------------------------------------------+ //| "Voting" that the price will fall. | //+------------------------------------------------------------------+ int CSignalMyCustInd::ShortCondition(void) { int result =0; int idx =StartIndex(); double close=Close(idx); double upper=Upper(idx); double lower=Lower(idx); double width=upper-lower; //--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width) result=m_pattern_0; //--- if the model 1 is used and price is above the rollback zone, then there is a condition for selling if(IS_PATTERN_USAGE(1) && close<lower-m_limit_out*width) result=m_pattern_1; //--- return the result return(result); }
De acordo com nossa implementação do modelo 0, dois modelos são verificados:
//+------------------------------------------------------------------+
//| "Voting" that the price will fall. |
//+------------------------------------------------------------------+
int CSignalMyCustInd::ShortCondition(void)
{
int result=0;
int idx =StartIndex();
//--- check direction of the main line
if(DiffMain(idx)<0.0)
{
//--- the main line gown downwards, which confirms the possibility of the price fall
if(IS_PATTERN_USAGE(0))
result=m_pattern_0; // "confirming" signal number 0
//--- if the model 1 is used, look for a reverse of the main line
if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)>0.0)
result=m_pattern_1; // signal number 1
}
//--- return the result
return(result);
}
Conclusão
Espero que esse artigo tenha ajudado a você compreender com você pode criar um gerador do sinal de negócios baseado em seu indicador personalizado.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/691
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso