Não resisti, precisava compartilhar esta imagem – é engraçada, mas há uma pitada de verdade na brincadeira. Tenham consciência de que o sucesso depende de paciência, esforço e perseverança. Acreditem, não é frase de autoajuda não, é uma constatação!
O tempo, neste caso, será sempre seu maior aliado.
A paciência é o segredo para o sucesso! 😉 O enriquecimento não acontecerá da noite para o dia…
Finalmente, trataremos a codificação do Expert Advisor (robô ou assistente especializado). As etapas tratadas anteriormente foram fundamentais para melhor compreensão e aprendizado da linguagem MQL5. Neste artigo, veremos como codificar um EA e integrá-lo com o indicador implementado anteriormente.
“Vale lembrar que o segredo deste EA está no indicador, não no EA. Logo, é preciso melhorar a eficiência do indicador APF-Color-Base!”
Para agilizar o processo de codificação e reduzir a margem de erros, incluímos as bibliotecas internas CPositionInfo (controle de posição), CTrade (operações de trade) e CSymbolInfo (informações de mercado, referentes ao ativo analisado).
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
CPositionInfo m_position; // trade position object
CTrade m_trade; // trading object
CSymbolInfo m_symbol; // symbol info object
Como o robô se orienta pelo indicador APF-Color-Base, precisamos obter a cor da barra através de uma chamada iCustom, no bloco OnInit:
Percebam que a chamada não difere muito dos exemplos que utilizamos no indicador com chamadas iMA e iSAR.
A leitura do sinal (obtenção da cor da barra) foi codificada na função GetSignal.
Mas, para ampliar a segurança das operações, a primeira verificação é referente a tentativa de encerrar operações em aberto (m_trade.PositionClose).
int signal=GetSignal();
if (signal==0 || close_trade) {
if (count_buy>0 || count_sell>0) {
int close_pos=0;
for(int i=PositionsTotal()-1;i>=0;i--)
if(m_position.SelectByIndex(i))
if(m_position.Symbol()==Symbol() && m_position.Magic()==m_magic) {
close_pos=0;
if (signal==0 || close_trade) {
m_trade.PositionClose(m_position.Ticket());
close_pos=1;
}
}
}
return;
}
“A função GetSignal retornará a cor da barra: sendo 0 (branco), 1 (verde/long) e 2 (vermelho/short) – vide indicador!“
Quando count_buy ou count_sell for maior que 0, certamente existirá uma operação em aberto (Long ou Short). Neste caso, a posição será fechada caso GetSignal retorne 0 (a barra mudou de cor – para branco) ou close_trade seja diferente de zero (para forçar o fechamento).
Confiram o código da função GetSignal:
int GetSignal()
{
//--- load buf_color_line
if (CopyBuffer(hAPF,4,0,2,buf_APF) < 0){
Print("CopyBuffer APF error =",GetLastError());
return(0);
}
int vSignal=0;
if ((buf_APF[0]==1 && buf_APF[1]==0) || (count_buy>0 && buf_APF[0]==1 && buf_APF[1]==1)) vSignal=1;
if ((buf_APF[0]==2 && buf_APF[1]==0) || (count_sell>0 && buf_APF[0]==2 && buf_APF[1]==2)) vSignal=2;
return (vSignal);
}
A cor dos dois últimos candles é obtida através da função do MQL5 CopyBuffer: o primeiro parâmetro identifica o handle do indicador (hAPF), o segundo parâmetro a posição do buffer do indicador (4 é o índice que representa buf_color_line – consulte os mapeamentos feitos com SetIndexBuffer), o terceiro a posição inicial (0 – última barra) e o último corresponde ao número de elementos para copiar (2 – duas barras).
“A leitura dos dois últimos candles se faz necessário para comparar uma possível mudança de cor“
Já a abertura de posição foi codificada na função OpenBuy (posição comprada) e OpenSell (posição vendida). Conforme exposto anteriormente, utilizamos a biblioteca CTrade para controlar a abertura de posição (m_trade.PositionOpen):
void OpenBuy(double sl,double tp)
{
sl=m_symbol.NormalizePrice(sl);
tp=m_symbol.NormalizePrice(tp);
int aux_Lots=InpLots;
//--- check volume before OrderSend to avoid "not enough money" error (CTrade)
double check_volume_lot=m_trade.CheckVolume(m_symbol.Name(),aux_Lots,m_symbol.Ask(),ORDER_TYPE_BUY);
if (count_buy>0) return;
if(check_volume_lot!=0.0) {
if(m_trade.PositionOpen(m_symbol.Name(),ORDER_TYPE_BUY,aux_Lots,m_symbol.Ask(),sl,tp,"LONG"))
{
if (trade_maxgain==0) {
count_buy++;
max_trades++;
}
Print("PositionOpen() BUY method executed SUCCESSFULLY. Return code=",m_trade.ResultRetcode(),
" (",m_trade.ResultRetcodeDescription(),")");
PrintResultTrade(m_trade,m_symbol);
// preço confirmado pela corretora
trade_open=m_trade.ResultPrice();
}
...
}
...
//---
}
“Cada ordem será enviada à mercado (ORDER_TYPE_BUY). Sendo assim, logo que o indicador sinalizar a mudança de cor, o robô fará a negociação pelo preço negociado naquele instante!“
Caso tenha ficado alguma dúvida referente a lógica básica de construção de um EA, também recomendo acessar o seguinte vídeo:
“No vídeo anterior, algumas estrategias foram escritas de maneira um pouco diferente (até porque abordou uma codificação em MQL4). Mas a lógica padrão é a mesma.“
Para finalizar a série de artigos sobre a codificação de indicadores no MT5, resolvi compartilhar mais um vídeo explicando as razões que nos levaram modificar o código para abertura de posição simulado pelo indicador.
Quanto maior o número de comparações dos preços do candlestick, menos preciso o algoritmo se mostrava em relação ao “histórico” (quando prev_calculated é igual a 0) e o “testador de estratégia” (a cada negócio) – por incrível que pareça, em um segundo, a estimativa de volume ou a diferença do preço máximo pelo fechamento pode mudar algum critério de decisão.
A única forma de coincidir as comparações históricas com o processamento online (no testador de estratégia ou durante o trade real), é validando os critérios para abertura de posição assim que a nova barra for desenhada e comparar os valores da barra anterior.
“Outro indicador que foi adicionado ao código foi o StdDev (desvio padrão). O objetivo é capturar a volatilidade do mercado – o valor do indicador aumenta na medida em que os preços se distanciam da média apurada (período).”
A variável “i” é o índice que representa cada barra processada. Para que possamos “identificar a barra atual (i)” e “comparar a anterior (i-1)“, podemos incluir outro índice (“k“) que será igual a “i-1” apenas quando a operação não estiver aberta – quando trade_open for igual a 0.
for (int i=start; i < rates_total; i++) {
HighBuf[i]=high[i];
CloseBuf[i]=close[i];
OpenBuf[i]=open[i];
LowBuf[i]=low[i];
...
int k=i;
if (!trade_open) k=i-1;
...
// Identificação da barra
bool CANDLE_0 = (open[k]-close[k] == 0);
bool CANDLE_UP = (close[k]>open[k] && close[k]-open[k]>=1);
bool CANDLE_DOWN = (close[k]=1);
...
O ajuste anterior resolve a questão da comparação da barra anterior, mas precisamos alterar o momento em que as comparações serão liberadas. Este controle é feito pela função isNewBar.
bool isNewBar(const datetime lastbar_time, const int op_type, const int prev_calc)
{
//--- memorize the time of opening of the last bar in the static variable
static datetime last_time=0;
static datetime init_time=0;
datetime init_auxtime=TimeCurrent();
int limit_time=0;
long time_match=0;
limit_time=300;
time_match=(limit_time-(init_auxtime-init_time));
if (time_match<0) time_match=0;
string label_name1="Seconds", label_text="Seconds... "+(string) (long)time_match;
ObjectDelete(0, label_name1);
ObjectCreate(0, label_name1, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0,label_name1,OBJPROP_XDISTANCE,ChartGetInteger(0,CHART_WIDTH_IN_PIXELS,0)-100);
ObjectSetInteger(0,label_name1,OBJPROP_YDISTANCE,30);
ObjectSetInteger(0,label_name1,OBJPROP_COLOR,YellowGreen);
ObjectSetString(0,label_name1,OBJPROP_TEXT,label_text);
if (last_time==0 || init_time==0 || last_time!=lastbar_time) {
last_time=lastbar_time;
init_time=init_auxtime;
if (last_time==0) return(false);
if (prev_calc==0 || op_type==1) return(true);
return(false);
}
if (op_type==2 && time_match<=2) return(true);
return(false);
}