
Como criar um Consultor Especializado Multi-Moedas simples usando MQL5 (Parte 7): ZigZag com Sinais dos Indicadores Awesome Oscillator
Introdução
O Consultor Especializado Multi-Moedas é uma negociação automatizada que pode abrir, fechar e gerenciar ordens para mais de um par de símbolos a partir de um único gráfico de símbolo.
Este artigo foca na negociação do Consultor Especializado para 30 pares e no uso do indicador ZigZag, que é filtrado com o Awesome Oscillator ou filtram os sinais um do outro.
Como demonstrado em artigos anteriores, a negociação multi-moedas é possível usando o poder, capacidades e facilidades do MQL5 tanto no terminal de negociação quanto no testador de estratégias.
Para atender às necessidades dos traders que buscam uma negociação automatizada eficiente e eficaz, contamos com o poder, capacidades e facilidades fornecidas pelo confiável MQL5. Nosso objetivo é criar um consultor especializado multi-moedas simples usando várias ideias e estratégias. Este artigo se concentrará no uso do indicador ZigZag, que será filtrado com o Awesome Oscillator ou filtrando os sinais um do outro.
Planos e Recursos
1. Negociação de Pares de Moedas.
Este Consultor Especializado Multi-Moedas está planejado para negociar em um Símbolo ou Par como segue:
Para Forex:
EURUSD,GBPUSD,AUDUSD,NZDUSD,USDCAD,USDCHF,USDJPY,EURGBP,EURAUD, EURNZD, EURCAD, EURCHF, EURJPY, GBPAUD, GBPNZD,
GBPCAD,GBPCHF,GBPJPY,AUDNZD,AUDCAD,AUDCHF,AUDJPY,NZDCAD,NZDCHF,NZDJPY, CADCHF, CADJPY, CHFJPY = 28 pairs
Além de 2 pares de Metais: XAUUSD (Ouro) e XAGUSD (Prata)
Totalizando 30 pares.
Para garantir o funcionamento suave do Consultor Especializado discutido neste artigo, implementei uma função que lida automaticamente com nomes de símbolos com prefixos e/ou sufixos.
No entanto, é importante notar que esta função só funciona para nomes de pares de símbolos Forex e Metais no MT5, e não para símbolos especiais e índices.
1.1. Recursos adicionais:
1.1.1. Consultor Especializado de Moeda Única
Alguns usuários perguntaram sobre o uso deste EA Multi-Moedas como um EA de moeda única ou independente.
Para resolver isso, foi adicionada uma funcionalidade para permitir o uso deste EA Multi-Moedas como um EA de Moeda Única.
Nas opções de Modo de Seleção de Pares de Negociação (Multi ou Único), os traders podem escolher entre duas condições de par de negociação: moeda única ou multi-moedas.
1. Par Único (moeda única)
2. Pares Múltiplos (multi-moedas)
Defina os Parâmetros de Entrada do Expert conforme mostrado na figura abaixo
Se 'Par Único' for selecionado:
A opção 'SP' ou par único limita o consultor especializado a negociar apenas no par onde ele está colocado.
Por exemplo, se um consultor especializado for colocado no par EURUSD, ele negociará apenas no par EURUSD.
Se 'Pares Múltiplos' for selecionado:
O grupo de opções 'Pares Selecionados para Negociar' inclui 10 pares de opções que serão negociados.
Um desses pares é chamado 'Pares Desejados pelo Trader', que exige que o trader insira manualmente os pares a serem negociados na propriedade 'Entrada do Expert'.
No entanto, é importante lembrar que o nome do par inserido deve já estar na lista dos 30 pares.
A Opção de Pares Desejados pelo Trader pode ser usada para garantir que os consultores especializados negociem apenas moedas únicas ou trabalhem como um EA independente.
O consultor especializado negociará ou trabalhará apenas no nome do par desejado fornecido. Isso garante uma abordagem focada na negociação ou trabalho em um único par.
Se o trader inserir apenas o nome do par XAUUSD, o consultor especializado negociará apenas nesse par.
O consultor especializado negociará apenas no par XAUUSD, independentemente de sua colocação entre os 30 pares disponíveis.
As configurações para o parâmetro de Entrada do Expert devem ser configuradas conforme mostrado na figura abaixo.
Portanto, neste artigo, existem duas maneiras de negociar com um único par de moedas ou trabalhar como um consultor especializado independente usando os consultores especializados.
1. Opte pela opção multi-par ou 'MP' e selecione a opção 'Pares Desejados pelo Trader'. No entanto, insira apenas um nome de par, como XAUUSD.
Esta opção restringe o consultor especializado a negociar apenas no par especificado em Pares Desejados pelo Trader. Ele não negociará em outros pares.2. No Modo de Seleção de Pares de Negociação, escolha 'SP' ou de único par.
Se um consultor especializado for aplicado ao par EURUSD, ele negociará exclusivamente no par EURUSD.
1.1.2. Negociar em Horários Específicos
No grupo Negociar em Horários Específicos, opções são fornecidas para traders que desejam negociar de acordo com o fuso horário.
Talvez muitos traders queiram negociar de acordo com o fuso horário, então os pares que serão negociados podem corresponder ao horário da sessão de negociação. Portanto, neste consultor especializado, ainda utilizamos a opção para sessão de negociação (fuso horário).
2. Indicadores de sinal.
2.1. Indicador ZigZag.
O indicador ZigZag é um método de medir os movimentos de preços sem ruídos desnecessários. Ele opera determinando a distância entre os movimentos de preço (altos e baixos). Subsequentemente, esse indicador calcula o retrocesso. Se o retrocesso exceder uma certa quantidade antecipada, o movimento de preço é considerado completo.
Como é sabido, o ZigZag é um dos indicadores técnicos mais antigos que migraram para a negociação de moedas a partir do mercado de ações. Ele permite que os traders visualizem a estrutura do mercado.
Ao tentar avaliar as mudanças de preço, o indicador ZigZag ajuda os traders a filtrar automaticamente os pequenos movimentos de preço.
Utilizar o indicador ZigZag pode ajudar a obter uma compreensão mais clara da estrutura do mercado.
Quando as condições de movimento de preço flutuam com o impacto de flutuações aleatórias de preço, o indicador ZigZag pode ser usado para ajudar a identificar tendências de preço e mudanças nas tendências de preço.
Analistas técnicos dizem que:
- O indicador ZigZag reduz o impacto de flutuações aleatórias de preço e é usado para identificar tendências de preço e mudanças nas tendências de preço.
- O indicador reduz os níveis de ruído, enfatizando tendências subjacentes mais altas e mais baixas.
- O indicador ZigZag funciona melhor em mercados com forte tendência.
Limitações do Indicador ZigZag.
Semelhante a outros indicadores seguidores de tendência, sinais de compra e venda são determinados observando movimentos de preço passados, que podem não prever com precisão os movimentos de preço futuros. Por exemplo, grande parte de uma tendência pode já ter ocorrido quando uma linha ZigZag é gerada.
Os traders devem estar cientes de que a linha ZigZag mais recente pode não ser permanente. Quando o preço muda de direção, o indicador começa a desenhar uma nova linha.
Se essa linha não atingir a configuração percentual do indicador e o preço do ativo reverter a direção, a linha é removida e substituída por uma linha ZigZag estendida na direção original da tendência.
Parâmetros de Configuração do ZigZag:
Existem 3 parâmetros de entrada no indicador ZigZag:
1. Depth - com valor padrão 12.
Depth refere-se a quantos candles para trás na série de barras ele irá olhar.
Para obter os altos e baixos definidos, você precisa garantir que tenha profundidade suficiente.
É o número mínimo de barras sem uma segunda máxima ou mínima. Por exemplo: se temos uma máxima no candle x e a profundidade é 12, não será possível desenhar a máxima seguinte até pelo menos x+12 candles.
2. Deviation - com valor padrão 5.
Deviation refere-se a qual porcentagem na mudança de preço é necessária para alterar a linha de tendência de positiva para negativamente.
3. Backstep - com valor padrão 3.
Backstep é o número mínimo de barras entre os altos e baixos das oscilações.
Fórmula do Indicador ZigZag:
ZigZag (HL, %change=X, retrace=FALSE, LastExtreme=TRUE)
Se %change>=X, plotar ZigZag.
onde:
HL = Série de preços High-Low ou série de preços de fechamento.
%change = Movimento mínimo de preço, em porcentagem.
Retrace = A mudança é um retrocesso do movimento anterior ou uma mudança absoluta do pico ao vale?
Last Extreme = Se o preço extremo for o mesmo em múltiplos períodos, o preço extremo é a primeira ou última observação?
Em minhas observações, para o indicador ZigZag, existem pelo menos 4 algoritmos de sinal que podem ser utilizados.
E neste consultor especializado, criei uma opção para que os traders possam escolher e experimentar os quatro sinais de algoritmo do indicador ZigZag.
2.2. Awesome Oscillator (AO.
O Awesome Oscillator (AO) é um indicador de momentum usado por traders para identificar tendências de mercado e momentum. Foi desenvolvido por Bill Williams, um analista técnico conhecido, e se tornou uma ferramenta popular entre os traders devido à sua simplicidade e confiabilidade.
O Awesome Oscillator é um indicador de momentum de mercado que compara movimentos recentes do mercado com movimentos históricos.
Ele usa uma linha zero no centro, em cada lado da qual os movimentos de preços são plotados de acordo com a comparação de duas médias móveis diferentes.
O Awesome Oscillator é calculado subtraindo uma média móvel simples (SMA) de 34 períodos de uma SMA de 5 períodos do preço do ponto médio (H+L)/2 de um instrumento financeiros.
O preço do ponto médio é considerado uma representação mais precisa do verdadeiro preço de mercado do que os preços de abertura ou fechamento, pois leva em consideração os preços altos e baixos de um determinado período.
O AO oscila entre valores positivos e negativos, com valores positivos indicando uma tendência de alta e valores negativos indicando uma tendência de baixa.
Os valores da média móvel simples (SMA) de 34 períodos e da SMA de 5 períodos são definidos permanentemente no código do indicador e não podem ser alterados nas propriedades de entrada do indicador.
Awesome Oscillator = SMA de 5 períodos (preço mediano, 5 períodos) – SMA de 34 períodos (preço mediano, 34 períodos)
Onde o preço mediano é: (Preço alto de um período de sessão + preço baixo de um período de sessão) / 2.
Para o indicador AO, existem pelo menos 3 algoritmos de sinal que podem ser utilizados.
Portanto, neste consultor especializado, criei uma opção para que os traders possam escolher e experimentar os três sinais de algoritmo deste indicador AO.
Ilustração dos sinais do indicador ZigZag filtrados com o Awesome Oscillator
A ilustração dos sinais abaixo é a opção número 2 do sinal ZigZag e a opção número 2 do sinal AO
3. Gerenciamento de Negociações e Ordens
Existem várias maneiras de gerenciar negociações com este consultor especializado multi-moeda:
3.1. Ordens de Stop Loss
Opções: Usar Ordem Stop Loss (Sim) ou (Não)
- Se a opção Usar Ordem Stop Loss (Não) for selecionada, todas as ordens serão abertas sem um stop loss.
Abrir uma ordem sem stop loss será seguro desde que Fechar Negociação por Sinal Oposto esteja definido como Sim. Mas se Fechar Negociação por Sinal Oposto estiver definido como Não, haverá um risco muito alto para o patrimônio. Portanto, adicionei uma função para verificar a porcentagem entre patrimônio e saldo. Nesse caso, se a porcentagem de patrimônio do saldo for menor que (100% - Percentual de Risco de Patrimônio por Negociação), o consultor executará a função CheckLoss (uma função para executar um stop loss virtual) e fechará ordens que tenham uma perda maior do que o valor definido de stop loss.
//-- if(use_sl==No && CheckVSLTP==Yes) { if(!mc.CheckEquityBalance()) if(mc.CloseAllLoss()) mc.Do_Alerts(symbol,"Close order due stop in loss to secure equity."); } //--
bool MCEA::CheckEquityBalance(void) { //--- bool isgood=false; if((mc_account.Equity()/mc_account.Balance()*100) > (100.00-Risk)) isgood=true; //-- return(isgood); //--- } //-end CheckEquityBalance() //---------//
bool MCEA::CheckLoss(const string symbol,ENUM_POSITION_TYPE intype,double slc=0.0) { //--- Pips(symbol); bool inloss=false; double lossval=slc==0.0 ? (SLval*0.5) : slc; double posloss = mc_symbol.NormalizePrice(slc*pip); int ttlorder=PositionsTotal(); // number of open positions //-- for(int x=0; x<arrsymbx; x++) { string symbol=DIRI[x]; //-- for(int i=ttlorder-1; i>=0; i--) { string position_Symbol = PositionGetSymbol(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double posloss = mc_symbol.NormalizePrice(lossval*pip); double pricegab = mc_symbol.NormalizePrice(fabs(price-pos_open)); //--- if(type==intype && pricegab>posloss) inloss=true; } } } //-- return(inloss); //---- } //-end CheckLoss() //---------//
bool MCEA::CloseAllLoss(void) { //---- ResetLastError(); //-- bool orclose=false; string isloss="due stop in loss."; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int ttlorder=PositionsTotal(); // number of open positions //-- for(int x=0; x<arrsymbx; x++) { string symbol=DIRI[x]; Pips(symbol); double posloss=mc_symbol.NormalizePrice(SLval*pip); orclose=false; //-- for(int i=ttlorder-1; i>=0; i--) { string position_Symbol = PositionGetSymbol(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double posloss = mc_symbol.NormalizePrice(SLval*pip); double pricegab = mc_symbol.NormalizePrice(fabs(price-pos_open)); ulong position_ticket = PositionGetTicket(i); //--- if(type==POSITION_TYPE_BUY && pricegab>posloss) { RefreshTick(position_Symbol); orclose = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close Buy %s %s %s",symbol,EnumToString(POSITION_TYPE_BUY),isloss); } if(type==POSITION_TYPE_SELL && pricegab>posloss) { RefreshTick(position_Symbol); orclose = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close Sell %s %s %s",symbol,EnumToString(POSITION_TYPE_BUY),isloss); } } } } //-- return(orclose); //---- } //-end CloseAllLoss() //---------//
- Se a opção Usar Stop Loss de Ordem for (Sim): Será dada novamente a opção: Usar Cálculo Automático de Stop Loss (Sim) ou (Não)
- Se a opção Cálculo Automático de Stop Loss for (Sim), então o cálculo do Stop Loss será realizado automaticamente pelo Expert.
- Se a opção Cálculo Automático de Stop Loss for (Não), então o trader deve inserir o valor do Stop Loss em Pips.
- Se a opção Usar Stop Loss de Ordem for (Não): Então o Expert verificará para cada ordem aberta, se a condição do sinal ainda é boa e a ordem pode ser mantida em lucro ou se a condição do sinal enfraqueceu e a ordem precisa ser fechada para salvar o lucro ou se a condição do sinal inverteu a direção e a ordem deve ser fechada em condição de perda.
Nota: Especialmente para Fechar Trade e Salvar lucro devido a sinal fraco, é dada uma opção, se deve ativá-la ou não.
Na parte da função ExpertActionTrade():
//-- if(SaveOnRev==Yes) //-- Close Trade and Save profit due to weak signal (Yes) { mc.CheckOpenPMx(symbol); if(mc.profitb[x]>mc.minprofit && mc.xob[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) { mc.CloseBuyPositions(symbol); mc.Do_Alerts(symbol,"Close BUY order "+symbol+" to save profit due to weak signal."); } if(mc.profits[x]>mc.minprofit && mc.xos[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) { mc.CloseSellPositions(symbol); mc.Do_Alerts(symbol,"Close SELL order "+symbol+" to save profit due to weak signal."); } } //--
O código para fechar a trade e salvar o lucro devido a um sinal fraco é o seguinte:
int MCEA::GetCloseInWeakSignal(const string symbol,int exis) // Signal Indicator Position Close in profit { //--- int ret=0; int rise=1, down=-1; //-- int AOdir=AOColorSignal(symbol); int ZZDir=ZigZagSignal(symbol); //-- if(exis==down && (AOdir==rise||ZZDir==rise)) ret=rise; if(exis==rise && (AOdir==down||ZZDir==down)) ret=down; //-- return(ret); //--- } //-end GetCloseInWeakSignal() //---------//
- Se não estiver ativado (Não), mesmo que o sinal tenha enfraquecido, a ordem ainda será mantida ou não será fechada para salvar o lucro.
- Se ativado (Sim), as condições para o indicador ZigZag e o indicador AO são:
Para fechar as ordens de Compra:
Quando o indicador AO mudar de cor de verde para vermelho (cor padrão) ou quando o indicador ZigZag atingir uma posição extrema alta e o preço mudar de direção, a ordem de Compra será fechada.Para fechar as ordens de Venda:
Quando o indicador AO mudar de cor de vermelho para verde (cor padrão) ou quando o indicador ZigZag atingir uma posição extrema baixa e o preço mudar de direção, a ordem de Venda será fechada.O código para definir uma ordem de stop loss é o seguinte:
double MCEA::OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice) { //--- slv=0.0; int x=PairsIdxArray(xsymb); Pips(xsymb); RefreshTick(xsymb); //-- switch(type) { case (ORDER_TYPE_BUY): { if(use_sl==Yes && autosl==Yes) slv=mc_symbol.NormalizePrice(atprice-38*pip); else if(use_sl==Yes && autosl==No) slv=mc_symbol.NormalizePrice(atprice-SLval*pip); else slv=0.0; //-- break; } case (ORDER_TYPE_SELL): { if(use_sl==Yes && autosl==Yes) slv=mc_symbol.NormalizePrice(atprice+38*pip); else if(use_sl==Yes && autosl==No) slv=mc_symbol.NormalizePrice(atprice+SLval*pip); else slv=0.0; } } //--- return(slv); //--- } //-end OrderSLSet() //---------//
3.2. Ordens de Take Profit.
Opções: Usar Ordem de Take Profit (Sim) ou (Não)
- Se a opção Usar Ordem de Take Profit for selecionada como (Não), então todas as ordens serão abertas sem take profit.
- Se a opção Usar Ordem de Take Profit for (Sim): Será dada novamente a opção: Usar Cálculo Automático de Ordem de Take Profit (Sim) ou (Não)
- Se a opção Cálculo Automático de Ordem de Take Profit for (Sim), então o cálculo da Ordem de Take Profit será realizado automaticamente pelo Expert.
- Se a opção Cálculo Automático de Ordem de Take Profit for (Não), então o trader deve inserir o valor da Ordem de Take Profit em Pips.
O código para definir uma ordem de Take Profit é o seguinte:
double MCEA::OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice) { //--- tpv=0.0; int x=PairsIdxArray(xsymb); Pips(xsymb); RefreshTick(xsymb); //-- switch(type) { case (ORDER_TYPE_BUY): { if(use_tp==Yes && autotp==Yes) tpv=mc_symbol.NormalizePrice(atprice+50*pip); else if(use_tp==Yes && autotp==No) tpv=mc_symbol.NormalizePrice(atprice+TPval*pip); else tpv=0.0; //-- break; } case (ORDER_TYPE_SELL): { if(use_tp==Yes && autotp==Yes) tpv=mc_symbol.NormalizePrice(atprice-50*pip); else if(use_tp==Yes && autotp==No) tpv=mc_symbol.NormalizePrice(atprice-TPval*pip); else tpv=0.0; } } //--- return(tpv); //--- } //-end OrderTPSet() //---------//
3.3. Trailing Stop
Opções: Usar Stop Loss Móvel (Sim) ou (Não)
- Se a opção Usar Stop SL Móvel for (Não), então o Expert não fará stop loss móvel e nem take profit móvel.
- Se a opção Usar Stop SL Móvel for (Sim): Os traders podem escolher entre 3 opções:
1. Trailing pelo Preço
O stop móvel será executado pelo Expert usando movimentos de preço e o valor na propriedade de entrada.
2. Trailing por Indicador
O stop móvel será executado pelo Expert usando o indicador VIDYA.
De acordo com minhas pesquisas e experimentos, o indicador VIDYA é ligeiramente melhor e ideal para stops móveis comparado ao Parabolic SAR ou várias variantes dos indicadores de Média Móvel.
Comparado ao indicador Parabolic SAR, o indicador VIDYA está mais próximo dos movimentos de preço, e comparado aos indicadores AMA, DEMA e MA, o indicador VIDYA está ainda mais distante dos movimentos de preço.
Então, neste artigo, decidi usar o indicador VIDYA para a função de stop móvel com base no indicador.
3. Trailing Stop no ALTO ou BAIXO da barra anterior
Para ordens de Compra, a posição do stop móvel será colocada no preço BAIXO da barra anterior (BAIXO[1]).
Para ordens de Venda, a posição do stop móvel será colocada no preço ALTO da barra anterior (ALTO[1]).
Função do Preço de Stop Móvel:
double MCEA::TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type) { //--- int br=2; double pval=0.0; int x=PairsIdxArray(xsymb); Pips(xsymb); //-- switch(TS_type) { case byprice: { RefreshTick(xsymb); if(ptype==POSITION_TYPE_BUY) pval=mc_symbol.NormalizePrice(mc_symbol.Bid()-TSval*pip); if(ptype==POSITION_TYPE_SELL) pval=mc_symbol.NormalizePrice(mc_symbol.Ask()+TSval*pip); break; } case byindi: { double VIDyAv[]; ArrayResize(VIDyAv,br,br); ArraySetAsSeries(VIDyAv,true); CopyBuffer(hVIDyAv[x],0,0,br,VIDyAv); RefreshPrice(xsymb,TFt,br); //-- if(ptype==POSITION_TYPE_BUY && (VIDyAv[0]<mc_symbol.NormalizePrice(mc_symbol.Bid()-TSval*pip))) pval=VIDyAv[0]; if(ptype==POSITION_TYPE_SELL && (VIDyAv[0]>mc_symbol.NormalizePrice(mc_symbol.Ask()+TSval*pip))) pval=VIDyAv[0]; break; } case byHiLo: { UpdatePrice(xsymb,TFt,2); //-- if(ptype==POSITION_TYPE_BUY && (HIGH[0]>HIGH[1])) pval=LOW[1]; if(ptype==POSITION_TYPE_SELL && (LOW[0]<LOW[1])) pval=HIGH[1]; break; } } //-- return(pval); //--- } //-end TSPrice() //---------//
bool MCEA::ModifyOrdersSL(const string symbx,int TS_type) { //--- ResetLastError(); MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int TRSP=TS_type; bool modist=false; int x=PairsIdxArray(symbx); Pips(symbx); //-- int total=PositionsTotal(); //-- for(int i=total-1; i>=0; i--) { string symbol=PositionGetSymbol(i); if(symbol==symbx && mc_position.Magic()==magicEA) { ENUM_POSITION_TYPE opstype = mc_position.PositionType(); if(opstype==POSITION_TYPE_BUY) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double vtrsb = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP)); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_tp = mc_position.TakeProfit(); double pos_profit = mc_position.Profit(); double pos_swap = mc_position.Swap(); double pos_comm = mc_position.Commission(); double netp=pos_profit+pos_swap+pos_comm; double modstart=mc_symbol.NormalizePrice(pos_open+TSmin*pip); double modminsl=mc_symbol.NormalizePrice(vtrsb+((TSmin-1.0)*pip)); double modbuysl=vtrsb; bool modbuy = (price>modminsl && modbuysl>modstart && (pos_stop==0.0||modbuysl>pos_stop)); //-- if(modbuy && netp>minprofit) { modist=mc_trade.PositionModify(symbol,modbuysl,pos_tp); } } if(opstype==POSITION_TYPE_SELL) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double vtrss = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP)); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_tp = mc_position.TakeProfit(); double pos_profit = mc_position.Profit(); double pos_swap = mc_position.Swap(); double pos_comm = mc_position.Commission(); double netp=pos_profit+pos_swap+pos_comm; double modstart=mc_symbol.NormalizePrice(pos_open-TSmin*pip); double modminsl=mc_symbol.NormalizePrice(vtrss-((TSmin+1.0)*pip)); double modselsl=vtrss; bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==0.0||modselsl<pos_stop)); //-- if(modsel && netp>minprofit) { modist=mc_trade.PositionModify(symbol,modselsl,pos_tp); } } } } //-- return(modist); //--- } //-end ModifyOrdersSL() //---------//
3.4. Obtenção de lucro final
Opções: Usar Trailing Take Profit (Sim) ou (Não)
- Se a opção Usar Trailing TP for (Não), então o Expert não fará trailing take profit.
- Se a opção Usar Trailing TP for (Sim), então insira o valor do Trailing Profit em Pips (valor padrão de 25 pips) e o expert advisor realizará trailing profit com base no valor da variável TPmin (valor mínimo de trailing profit).
bool MCEA::ModifyOrdersTP(const string symbx) { //--- ResetLastError(); MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- bool modist=false; int x=PairsIdxArray(symbx); Pips(symbx); //-- int total=PositionsTotal(); //-- for(int i=total-1; i>=0; i--) { string symbol=PositionGetSymbol(i); if(symbol==symbx && mc_position.Magic()==magicEA) { ENUM_POSITION_TYPE opstype = mc_position.PositionType(); if(opstype==POSITION_TYPE_BUY) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_tp = mc_position.TakeProfit(); double modbuytp = pos_tp==0.0 ? mc_symbol.NormalizePrice(pos_open+TPmin*pip) : pos_tp; double modpostp = mc_symbol.NormalizePrice(price+TPmin*pip); bool modtpb = (price>pos_open && modbuytp-price<TPmin*pip && pos_tp<modpostp); //-- if(modtpb) { modist=mc_trade.PositionModify(symbol,pos_stop,modpostp); } } if(opstype==POSITION_TYPE_SELL) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_tp = mc_position.TakeProfit(); double modseltp = pos_tp==0.0 ? mc_symbol.NormalizePrice(pos_open-TPmin*pip) : pos_tp; double modpostp = mc_symbol.NormalizePrice(price-TPmin*pip); bool modtps = (price<pos_open && price-modseltp<TPmin*pip && pos_tp>modpostp); //-- if(modtps) { modist=mc_trade.PositionModify(symbol,pos_stop,modpostp); } } } } //-- return(modist); //--- } //-end ModifyOrdersTP() //---------//
3.5. Fechar negociação por sinal oposto
Opções: Fechar Trade por Sinal Oposto (Sim) ou (Não)
- Se Fechar Trade por Sinal Oposto (Sim):
Então, se uma ordem de Venda tiver sido aberta anteriormente e o sinal do indicador se inverter, a ordem de Venda será fechada e, em seguida, o expert advisor abrirá uma ordem de Compra. Da mesma forma, vice-versa.
Na parte da função ExpertActionTrade():
if(Close_by_Opps==Yes && mc.xos[x]>0) mc.CloseSellPositions(symbol);bool MCEA::CloseSellPositions(const string symbol) { //--- ResetLastError(); bool sellclose=false; int total=PositionsTotal(); // number of open positions ENUM_POSITION_TYPE closetype = POSITION_TYPE_SELL; ENUM_ORDER_TYPE type_req = ORDER_TYPE_BUY; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int x=PairsIdxArray(symbol); //--- iterate over all open positions for(int i=total-1; i>=0; i--) { if(mc_position.SelectByIndex(i)) { //--- Parameters of the order string position_Symbol = PositionGetSymbol(i); ulong position_ticket = PositionGetTicket(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); //--- if the MagicNumber matches if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { //-- if(type==closetype) { RefreshTick(position_Symbol); sellclose=mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close Sell #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); } } } } //--- return(sellclose); //---- } //-end CloseSellPositions() //---------//
Na parte da função ExpertActionTrade():
if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol);
bool MCEA::CloseBuyPositions(const string symbol) { //--- //-- ResetLastError(); bool buyclose=false; int total=PositionsTotal(); // number of open positions ENUM_POSITION_TYPE closetype = POSITION_TYPE_BUY; ENUM_ORDER_TYPE type_req = ORDER_TYPE_SELL; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int x=PairsIdxArray(symbol); //--- iterate over all open positions for(int i=total-1; i>=0; i--) { if(mc_position.SelectByIndex(i)) { //--- Parameters of the order string position_Symbol = PositionGetSymbol(i); ulong position_ticket = PositionGetTicket(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); //--- if the MagicNumber matches if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { //-- if(type==closetype) { RefreshTick(position_Symbol); buyclose=mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close Buy #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); } } } } //--- return(buyclose); //---- } //-end CloseBuyPositions() //---------//
Problemas surgirão se Fechar Trade por Sinal Oposto for (Não):
1. A ordem será 2 vezes o total de cada par negociado.
2. Em um par, haverá ordens que estão em condição de perda e ordens que estão em condição de lucro.
3. O capital será erodido devido a condições desequilibradas de perda e lucro.
Para resolver esse problema, criei várias funções para detectar condições de ordens de perda e lucro.
Na parte da função ExpertActionTrade():
//-- mc.CheckOpenPMx(symbol); if(Close_by_Opps==No && (mc.xob[x]+mc.xos[x]>1)) { if(mc.CheckProfitLoss(symbol)) mc.Do_Alerts(symbol,"Close order due stop in loss."); } //--
bool MCEA::CheckProfitLoss(const string symbol) { //---- ResetLastError(); //-- bool closeinloss=false; string isloss="due stop in loss."; //-- int xx=PairsIdxArray(symbol); //-- bool BuyProfitSellLoss=(xob[xx]>0 && CheckProfit(symbol,POSITION_TYPE_BUY)) && (xos[xx]>0 && CheckLoss(symbol,POSITION_TYPE_SELL,0.0)); bool SellProfitBuyLoss=(xos[xx]>0 && CheckProfit(symbol,POSITION_TYPE_SELL)) && (xob[xx]>0 && CheckLoss(symbol,POSITION_TYPE_BUY,0.0)); //-- if(BuyProfitSellLoss && !SellProfitBuyLoss) { if(CloseSellPositions(symbol)) { PrintFormat("Close Sell %s %s %s",symbol,EnumToString(POSITION_TYPE_BUY),isloss); closeinloss=true; } } if(SellProfitBuyLoss && !BuyProfitSellLoss) { if(CloseBuyPositions(symbol)) { PrintFormat("Close Buy %s %s %s",symbol,EnumToString(POSITION_TYPE_SELL),isloss); closeinloss=true; } } //-- return(closeinloss); //---- } //-end CheckProfitLoss() //---------//
A função CheckProfitLoss() chamará 2 outras funções, que irão comparar a ordem em um par com as condições:
Lucro em Compra e Perda em Venda, ou Perda em Compra e Lucro em Venda.
- Se Lucro em Compra e Perda em Venda, então a ordem de Venda será fechada.
- Se Perda em Compra e Lucro em Venda, então a ordem de Compra será fechada.
bool MCEA::CheckProfit(const string symbol,ENUM_POSITION_TYPE intype) { //--- Pips(symbol); double posprofit=mc_symbol.NormalizePrice((TPval*0.5)*pip); bool inprofit=false; //-- int ttlorder=PositionsTotal(); // number of open positions //-- for(int x=0; x<arrsymbx; x++) { string symbol=DIRI[x]; //-- for(int i=ttlorder-1; i>=0; i--) { string position_Symbol = PositionGetSymbol(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double posprofit = mc_symbol.NormalizePrice((TPval*0.5)*pip); double pricegab = mc_symbol.NormalizePrice(fabs(price-pos_open)); //--- if(type==intype && posprofit<pricegab) inprofit=true; } } } //-- return(inprofit); //---- } //-end CheckProfit() //---------//
bool MCEA::CheckLoss(const string symbol,ENUM_POSITION_TYPE intype,double slc=0.0) { //--- Pips(symbol); bool inloss=false; double lossval=slc==0.0 ? (SLval*0.5) : slc; double posloss = mc_symbol.NormalizePrice(slc*pip); int ttlorder=PositionsTotal(); // number of open positions //-- for(int x=0; x<arrsymbx; x++) { string symbol=DIRI[x]; //-- for(int i=ttlorder-1; i>=0; i--) { string position_Symbol = PositionGetSymbol(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double posloss = mc_symbol.NormalizePrice(lossval*pip); double pricegab = mc_symbol.NormalizePrice(fabs(price-pos_open)); //--- if(type==intype && pricegab>posloss) inloss=true; } } } //-- return(inloss); //---- } //-end CheckLoss() //---------//
4. Gerenciamento Manual de Ordens.
Neste expert advisor multi-moeda, foram adicionados vários cliques em botões manuais para proporcionar eficiência e eficácia aos traders na monitoração do trabalho do expert advisor.
4.1. Definir SL / TP em Todas as Ordens:
Este botão é útil se o trader tiver inserido os conjuntos de parâmetros Usar Stop Loss de Ordem (Não) e/ou Usar Take Profit de Ordem (Não), mas depois deseja usar Stop Loss ou Take Profit em todas as ordens. Com um único clique no botão "Definir SL/TP em Todas as Ordens", todas as ordens serão modificadas e um Stop Loss e/ou Take Profit será aplicado.4.2. Fechar Todas as Ordens:
Se um trader deseja fechar todas as ordens, um único clique no botão "Fechar Todas as Ordens" fechará todas as ordens abertas.
4.3. Fechar Todas as Ordens em Lucro:
Se um trader deseja fechar todas as ordens que já estão lucrativas, um único clique no botão "Fechar Todas as Ordens em Lucro" fechará todas as ordens abertas que já estão lucrativas.
5. Gerenciamento de Ordens e Símbolos do Gráfico.
Para expert advisors multi-moeda que irão negociar 30 pares a partir de um único símbolo de gráfico, seria muito útil e fácil se fosse fornecido um painel de botões para todos os símbolos, para que os traders possam alterar o intervalo de tempo ou os símbolos dos gráficos com apenas um clique para ver a precisão do sinal do indicador quando o expert abre ou fecha uma ordem.
Implementação do planejamento no programa MQL5
1. Cabeçalho do programa e propriedades de entrada.
Incluir Arquivo de Cabeçalho MQL5
//+------------------------------------------------------------------+ //| Include | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> #include <Trade\PositionInfo.mqh> #include <Trade\SymbolInfo.mqh> #include <Trade\AccountInfo.mqh> //-- CTrade mc_trade; CSymbolInfo mc_symbol; CPositionInfo mc_position; CAccountInfo mc_account; //---
Enumeração para usar fuso horário
//-- enum tm_zone { Cus_Session, // Trading on Custom Session New_Zealand, // Trading on New Zealand Session Australia, // Trading on Autralia Sydney Session Asia_Tokyo, // Trading on Asia Tokyo Session Europe_London, // Trading on Europe London Session US_New_York // Trading on US New York Session }; //--
Enumeração para selecionar hora
//-- enum swhour { hr_00=0, // 00:00 hr_01=1, // 01:00 hr_02=2, // 02:00 hr_03=3, // 03:00 hr_04=4, // 04:00 hr_05=5, // 05:00 hr_06=6, // 06:00 hr_07=7, // 07:00 hr_08=8, // 08:00 hr_09=9, // 09:00 hr_10=10, // 10:00 hr_11=11, // 11:00 hr_12=12, // 12:00 hr_13=13, // 13:00 hr_14=14, // 14:00 hr_15=15, // 15:00 hr_16=16, // 16:00 hr_17=17, // 17:00 hr_18=18, // 18:00 hr_19=19, // 19:00 hr_20=20, // 20:00 hr_21=21, // 21:00 hr_22=22, // 22:00 hr_23=23 // 23:00 }; //--
Enumeração para selecionar minutos de tempo
//-- enum inmnt { mn_00=0, // Minute 0 mn_05=5, // Minute 5 mn_10=10, // Minute 10 mn_15=15, // Minute 15 mn_20=20, // Minute 20 mn_25=25, // Minute 25 mn_30=30, // Minute 30 mn_35=35, // Minute 35 mn_40=40, // Minute 40 mn_45=45, // Minute 45 mn_50=50, // Minute 50 mn_55=55 // Minute 55 }; //--
Enumeração para selecionar 10 pares de opções para negociar
//-- enum PairsTrade { All30, // All Forex 30 Pairs TrdWi, // Trader Wishes Pairs Usds, // Forex USD Pairs Eurs, // Forex EUR Pairs Gbps, // Forex GBP Pairs Auds, // Forex AUD Pairs Nzds, // Forex NZD Pairs Cads, // Forex CDD Pairs Chfs, // Forex CHF Pairs Jpys // Forex JPY Pairs }; //--
A enumeração YN é usada para as opções (Sim) ou (Não) na propriedade Expert Input.
//-- enum YN { No, Yes }; //--
Enumeração para usar o tamanho do lote de gerenciamento de dinheiro
//-- enum mmt { FixedLot, // Fixed Lot Size DynamLot // Dynamic Lot Size }; //--
Enumeração para selecionar o período de tempo a ser usado no cálculo dos indicadores de sinal
//-- enum TFUSE { TFM5, // 00_PERIOD_M5 TFM15, // 01_PERIOD_M15 TFM30, // 02_PERIOD_M30 TFH1, // 03_PERIOD_H1 TFH2, // 04_PERIOD_H2 TFH3, // 05_PERIOD_H3 TFH4, // 06_PERIOD_H4 TFH6, // 07_PERIOD_H6 TFH8, // 08_PERIOD_H8 TFH12, // 09_PERIOD_H12 TFD1 // 10_PERIOD_D1 }; //--
Na enumeração TFUSE, limito o uso dos cálculos de intervalo de tempo para os experts apenas de TF-M5 a TF-D1.
Enumeração para selecionar o tipo a ser utilizado no cálculo do Trailing Stop
//-- enum TrType { byprice, // Trailing Stop by Price byindi, // Trailing Stop by Indicator byHiLo // Trailing Stop in HIGH or LOW bar }; //--
Enumeração para selecionar o tipo de negociação que o expert realizará: moeda única ou multi-moeda.
//-- enum MS { SP, // Single Pair MP // Multi Pairs }; //--
Enumeração para selecionar o algoritmo de sinal do indicador ZigZag
//-- enum SignalZZ { SZZ1, // ZigZagSignal 1 SZZ2, // ZigZagSignal 2 SZZ3, // ZigZagSignal 3 SZZ4 // ZigZagSignal 4 }; //--
Enumeração para selecionar o algoritmo de sinal do indicador AO
//-- enum SignalAO { SAO1, // AOSignal 1 SAO2, // AOSignal 2 SAO3 // AOSignal 3 }; //--
Propriedades de entrada especializadas
//--- input group "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter input TFUSE tfinuse = TFH4; // Select Expert TimeFrame, default PERIOD_H4 //--- input group "=== ZigZag Indicator Input Properties ==="; // ZigZag Indicator Input Properties input int zzDepth = 12; // Input ZigZag Depth, default 12 input int zzDevia = 5; // Input ZigZag Deviation, default 5 input int zzBackS = 3; // Input ZigZag Back Step, default 3 input SignalZZ sigzz = SZZ2; // Select ZigZag Signal to Use input SignalAO sigao = SAO2; // Select AO Signal to Use //--- input group "=== Selected Pairs to Trade ==="; // Selected Pairs to trading input MS trademode = MP; // Select Trading Pairs Mode (Multi or Single) input PairsTrade usepairs = All30; // Select Pairs to Use input string traderwishes = "eg. eurusd,usdchf"; // If Use Trader Wishes Pairs, input pair name here, separate by comma //-- input group "=== Money Management Lot Size Parameter ==="; // Money Management Lot Size Parameter input mmt mmlot = DynamLot; // Money Management Type input double Risk = 10.0; // Percent Equity Risk per Trade (Min=1.0% / Max=10.0%) input double Lots = 0.01; // Input Manual Lot Size FixedLot //--Trade on Specific Time input group "=== Trade on Specific Time ==="; // Trade on Specific Time input YN trd_time_zone = Yes; // Select If You Like to Trade on Specific Time Zone input tm_zone session = Cus_Session; // Select Trading Time Zone input swhour stsescuh = hr_00; // Time Hour to Start Trading Custom Session (0-23) input inmnt stsescum = mn_15; // Time Minute to Start Trading Custom Session (0-55) input swhour clsescuh = hr_23; // Time Hour to Stop Trading Custom Session (0-23) input inmnt clsescum = mn_55; // Time Minute to Stop Trading Custom Session (0-55) //--Day Trading On/Off input group "=== Day Trading On/Off ==="; // Day Trading On/Off input YN ttd0 = No; // Select Trading on Sunday (Yes) or (No) input YN ttd1 = Yes; // Select Trading on Monday (Yes) or (No) input YN ttd2 = Yes; // Select Trading on Tuesday (Yes) or (No) input YN ttd3 = Yes; // Select Trading on Wednesday (Yes) or (No) input YN ttd4 = Yes; // Select Trading on Thursday (Yes) or (No) input YN ttd5 = Yes; // Select Trading on Friday (Yes) or (No) input YN ttd6 = No; // Select Trading on Saturday (Yes) or (No) //--Trade & Order management Parameter input group "=== Trade & Order management Parameter ==="; // Trade & Order management Parameter input YN use_sl = No; // Use Order Stop Loss (Yes) or (No) input YN autosl = Yes; // Use Automatic Calculation Stop Loss (Yes) or (No) input double SLval = 30.0; // If Not Use Automatic SL - Input SL value in Pips input YN use_tp = Yes; // Use Order Take Profit (Yes) or (No) input YN autotp = Yes; // Use Automatic Calculation Take Profit (Yes) or (No) input double TPval = 60.0; // If Not Use Automatic TP - Input TP value in Pips input YN TrailingSL = Yes; // Use Trailing Stop Loss (Yes) or (No) input TrType trlby = byHiLo; // Select Trailing Stop Type input double TSval = 10.0; // If Use Trailing Stop by Price Input value in Pips input double TSmin = 5.0; // Minimum Pips to start Trailing Stop input YN TrailingTP = Yes; // Use Trailing Take Profit (Yes) or (No) input double TPmin = 25.0; // Input Trailing Profit Value in Pips input YN Close_by_Opps = Yes; // Close Trade By Opposite Signal (Yes) or (No) input YN SaveOnRev = Yes; // Close Trade and Save profit due to weak signal (Yes) or (No) input YN CheckVSLTP = Yes; // Check Virtual SL/TP & Close Loss Trade (Yes) or (No) //--Others Expert Advisor Parameter input group "=== Others Expert Advisor Parameter ==="; // Others EA Parameter input YN alerts = Yes; // Display Alerts / Messages (Yes) or (No) input YN UseEmailAlert = No; // Email Alert (Yes) or (No) input YN UseSendnotify = No; // Send Notification (Yes) or (No) input YN trade_info_display = Yes; // Select Display Trading Info on Chart (Yes) or (No) input ulong magicEA = 20240218; // Expert ID (Magic Number) //---
Nota: Se a propriedade de entrada do ID do Expert (Número Mágico) for deixada em branco, o Expert Advisor será capaz de gerenciar ordens abertas manualmente.
No grupo de propriedades de entrada do expert Global Strategy EA Parameters, os traders devem selecionar o Intervalo de Tempo do Expert para cálculos de sinal do indicador, com o padrão sendo PERIOD_H4.
No grupo de propriedades "Selecionar Pares para Negociar" do Expert Advisor, os traders precisam selecionar o par a ser negociado entre as 10 opções fornecidas; por padrão, Todos os Pares Forex 30 está selecionado.
Para configurar o par a ser negociado, chamaremos a função HandlingSymbolArrays(). Com a função HandlingSymbolArrays(), gerenciaremos todos os pares que serão negociados.
void MCEA::HandlingSymbolArrays(void) { //--- string All30[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY","EURGBP", "EURAUD","EURNZD","EURCAD","EURCHF","EURJPY","GBPAUD","GBPNZD","GBPCAD", "GBPCHF","GBPJPY","AUDNZD","AUDCAD","AUDCHF","AUDJPY","NZDCAD","NZDCHF", "NZDJPY","CADCHF","CADJPY","CHFJPY","XAUUSD","XAGUSD"}; // 30 pairs string USDs[]={"USDCAD","USDCHF","USDJPY","AUDUSD","EURUSD","GBPUSD","NZDUSD","XAUUSD","XAGUSD"}; // USD pairs string EURs[]={"EURAUD","EURCAD","EURCHF","EURGBP","EURJPY","EURNZD","EURUSD"}; // EUR pairs string GBPs[]={"GBPAUD","GBPCAD","GBPCHF","EURGBP","GBPJPY","GBPNZD","GBPUSD"}; // GBP pairs string AUDs[]={"AUDCAD","AUDCHF","EURAUD","GBPAUD","AUDJPY","AUDNZD","AUDUSD"}; // AUD pairs string NZDs[]={"AUDNZD","NZDCAD","NZDCHF","EURNZD","GBPNZD","NZDJPY","NZDUSD"}; // NZD pairs string CADs[]={"AUDCAD","CADCHF","EURCAD","GBPCAD","CADJPY","NZDCAD","USDCAD"}; // CAD pairs string CHFs[]={"AUDCHF","CADCHF","EURCHF","GBPCHF","NZDCHF","CHFJPY","USDCHF"}; // CHF pairs string JPYs[]={"AUDJPY","CADJPY","CHFJPY","EURJPY","GBPJPY","NZDJPY","USDJPY"}; // JPY pairs //-- sall=ArraySize(All30); arusd=ArraySize(USDs); areur=ArraySize(EURs); aretc=ArraySize(JPYs); ArrayResize(VSym,sall,sall); ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY); //-- if(usepairs==TrdWi && StringFind(traderwishes,"eg.",0)<0) { string to_split=traderwishes; // A string to split into substrings pairs name string sep=","; // A separator as a character ushort u_sep; // The code of the separator character //--- Get the separator code u_sep=StringGetCharacter(sep,0); //--- Split the string to substrings int p=StringSplit(to_split,u_sep,SPC); if(p>0) { for(int i=0; i<p; i++) StringToUpper(SPC[i]); //-- for(int i=0; i<p; i++) { if(ValidatePairs(SPC[i])<0) ArrayRemove(SPC,i,1); } } arspc=ArraySize(SPC); } //-- SetSymbolNamePS(); // With this function we will detect whether the Symbol Name has a prefix and/or suffix //-- if(inpre>0 || insuf>0) { if(usepairs==TrdWi && arspc>0) { for(int t=0; t<arspc; t++) { SPC[t]=pre+SPC[t]+suf; } } //-- for(int t=0; t<sall; t++) { All30[t]=pre+All30[t]+suf; } for(int t=0; t<arusd; t++) { USDs[t]=pre+USDs[t]+suf; } for(int t=0; t<areur; t++) { EURs[t]=pre+EURs[t]+suf; } for(int t=0; t<aretc; t++) { GBPs[t]=pre+GBPs[t]+suf; } for(int t=0; t<aretc; t++) { AUDs[t]=pre+AUDs[t]+suf; } for(int t=0; t<aretc; t++) { NZDs[t]=pre+NZDs[t]+suf; } for(int t=0; t<aretc; t++) { CADs[t]=pre+CADs[t]+suf; } for(int t=0; t<aretc; t++) { CHFs[t]=pre+CHFs[t]+suf; } for(int t=0; t<aretc; t++) { JPYs[t]=pre+JPYs[t]+suf; } } //-- ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY); ArrayResize(AS30,sall,sall); ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY); for(int x=0; x<sall; x++) {SymbolSelect(AS30[x],true);} if(ValidatePairs(Symbol())>=0) symbfix=true; if(!symbfix) { Alert("Expert Advisors will not trade on pairs "+Symbol()); Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart."); ExpertRemove(); } //-- switch(usepairs) { case 0: // All Forex & Metal 30 Pairs { ArrayResize(DIRI,sall,sall); arrsymbx=sall; ArraySymbolResize(); ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY); pairs="Multi Currency "+string(sall)+" Pairs"; //-- break; } case 1: // Trader wishes pairs { ArrayResize(DIRI,arspc,arspc); arrsymbx=arspc; ArraySymbolResize(); ArrayCopy(DIRI,SPC,0,0,WHOLE_ARRAY); pairs="("+string(arspc)+") Trader Wishes Pairs"; //-- break; } case 2: // USD pairs { ArrayResize(DIRI,arusd,arusd); arrsymbx=arusd; ArraySymbolResize(); ArrayCopy(DIRI,USDs,0,0,WHOLE_ARRAY); pairs="("+string(arusd)+") Multi Currency USD Pairs"; //-- break; } case 3: // EUR pairs { ArrayResize(DIRI,areur,areur); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,EURs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex EUR Pairs"; //-- break; } case 4: // GBP pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,GBPs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex GBP Pairs"; //-- break; } case 5: // AUD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,AUDs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex AUD Pairs"; //-- break; } case 6: // NZD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,NZDs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex NZD Pairs"; //-- break; } case 7: // CAD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,CADs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex CAD Pairs"; //-- break; } case 8: // CHF pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,CHFs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex CHF Pairs"; //-- break; } case 9: // JPY pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,JPYs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex JPY Pairs"; //-- break; } } //-- return; //--- } //-end HandlingSymbolArrays() //---------//
Dentro da função HandlingSymbolArrays() chamaremos a função SetSymbolNamePS(). Com a SetSymbolNamePS(), poderemos gerenciar nomes de símbolos com prefixos e/ou sufixos.
void MCEA::SetSymbolNamePS(void) { //--- int sym_Lenpre=0; int sym_Lensuf=0; string sym_pre=""; string sym_suf=""; SymbolSelect(Symbol(),true); string insymbol=Symbol(); int inlen=StringLen(insymbol); int toseek=-1; string dep=""; string bel=""; string sym_use =""; int pairx=-1; string xcur[]={"EUR","GBP","AUD","NZD","USD","CAD","CHF"}; // 7 major currency int xcar=ArraySize(xcur); //-- for(int x=0; x<xcar; x++) { toseek=StringFind(insymbol,xcur[x],0); if(toseek>=0) { pairx=x; break; } } if(pairx>=0) { int awl=toseek-3 <0 ? 0 : toseek-3; int sd=StringFind(insymbol,"SD",0); if(toseek==0 && sd<4) { dep=StringSubstr(insymbol,toseek,3); bel=StringSubstr(insymbol,toseek+3,3); sym_use=dep+bel; } else if(toseek>0) { dep=StringSubstr(insymbol,toseek,3); bel=StringSubstr(insymbol,toseek+3,3); sym_use=dep+bel; } else { dep=StringSubstr(insymbol,awl,3); bel=StringSubstr(insymbol,awl+3,3); sym_use=dep+bel; } } //-- string sym_nmx=sym_use; int lensx=StringLen(sym_nmx); //-- if(inlen>lensx && lensx==6) { sym_Lenpre=StringFind(insymbol,sym_nmx,0); sym_Lensuf=inlen-lensx-sym_Lenpre; //-- if(sym_Lenpre>0) { sym_pre=StringSubstr(insymbol,0,sym_Lenpre); for(int i=0; i<xcar; i++) if(StringFind(sym_pre,xcur[i],0)>=0) sym_pre=""; } if(sym_Lensuf>0) { sym_suf=StringSubstr(insymbol,sym_Lenpre+lensx,sym_Lensuf); for(int i=0; i<xcar; i++) if(StringFind(sym_suf,xcur[i],0)>=0) sym_suf=""; } } //-- pre=sym_pre; suf=sym_suf; inpre=StringLen(pre); insuf=StringLen(suf); posCur1=inpre; posCur2=posCur1+3; //-- return; //--- } //-end SetSymbolNamePS() //---------//
Nota: O expert valida os pares. Se o trader cometer um erro ao inserir o nome do par (erros de digitação) ou se a validação do par falhar, o expert receberá um aviso e o expert advisor será removido do gráfico.
No grupo de propriedades de entrada do expert, Comércio em Horário Específico, aqui o trader escolherá se Deseja Negociar em Horário Específico (Sim) ou (Não).
Se a opção Comércio em Horário Específico for especificada como Não, então o expert negociará das 00:15 às 23:59 no MT5.
Se Sim, então selecione as opções da enumeração:
- Negociação em Sessão Personalizada
- Negociação na Sessão da Nova Zelândia
- Negociação na Sessão de Sydney, Austrália
- Negociação na Sessão de Tóquio, Ásia
- Negociação na Sessão de Londres, Europa
- Negociação na Sessão de Nova York, América
Por padrão, Negociação em Horários Específicos está definida como Sim e configurada para Negociação em Sessões Personalizadas.
Negociação em Sessão Personalizada Nesta sessão, os traders devem definir o horário ou as horas e minutos para começar a negociar e as horas e minutos para parar de negociar. Isso significa que o EA realizará atividades apenas durante o período de tempo especificado, do início ao fim.
Enquanto isso, na Sessão de Negociação da Nova Zelândia até a Sessão de Negociação dos EUA em Nova York, o tempo desde o início da negociação até o fechamento da negociação é calculado pelo EA.
2. Classe para trabalhar com o Expert Advisor
Para construir e configurar o fluxo de trabalho do Expert Advisor, criamos uma classe que declara todas as variáveis, objetos e funções necessárias para um Expert Advisor multi-moeda.
//+------------------------------------------------------------------+ //| Class for working Expert Advisor | //+------------------------------------------------------------------+ class MCEA { //--- private: //---- int x_year; // Year int x_mon; // Month int x_day; // Day of the month int x_hour; // Hour in a day int x_min; // Minutes int x_sec; // Seconds //-- int oBm, oSm, ldig; //--- Variables used in prefix and suffix symbols int posCur1, posCur2; int inpre, insuf; bool symbfix; string pre,suf; string prefix,suffix; //--- Variables are used in Trading Time Zone int ishour, onhour; int tftrlst, tfcinws; datetime rem, znop, zncl, zntm; datetime SesCuOp, SesCuCl, Ses01Op, Ses01Cl, Ses02Op, Ses02Cl, Ses03Op, Ses03Cl, Ses04Op, Ses04Cl, Ses05Op, Ses05Cl, SesNoOp, SesNoCl; //-- string tz_ses, tz_opn, tz_cls; //-- string tmopcu, tmclcu, tmop01, tmcl01, tmop02, tmcl02, tmop03, tmcl03, tmop04, tmcl04, tmop05, tmcl05, tmopno, tmclno; //---------------------- //-- double LotPS; double point; double slv, tpv, pip, xpip; double SARstep, SARmaxi; double floatprofit, fixclprofit; //-- string pairs, hariini, daytrade, trade_mode; //-- double OPEN[], HIGH[], LOW[], CLOSE[]; datetime TIME[]; datetime closetime; //-- //------------ //------------ void SetSymbolNamePS(void); void HandlingSymbolArrays(void); void Set_Time_Zone(void); void Time_Zone(void); bool Trade_session(void); string PosTimeZone(void); int ThisTime(const int reqmode); int ReqTime(datetime reqtime,const int reqmode); //-- int DirectionMove(const string symbol,const ENUM_TIMEFRAMES stf); int GetIndiSignals(const string symbol); int ZigZagSignal(const string symbol); int AOSignal(const string symbol); int AOColorSignal(const string symbol); int PARSAR05(const string symbol); int PARSAR15(const string symbol); int LotDig(const string symbol); //-- double MLots(const string symbx); double NonZeroDiv(double val1,double val2); double OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice); double OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice); double SetOrderSL(const string xsymb,ENUM_POSITION_TYPE type,double atprice); double SetOrderTP(const string xsymb,ENUM_POSITION_TYPE type,double atprice); double TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type); //-- string ReqDate(int d,int h,int m); string TF2Str(ENUM_TIMEFRAMES period); string timehr(int hr,int mn); string TradingDay(void); string AccountMode(); string GetCommentForOrder(void) { return(expname); } //------------ public: //--- //-- ZigZag_AO_MCEA Config -- string DIRI[], AS30[], VSym[]; string SPC[]; string USD[]; string EUR[]; string GBP[]; string AUD[]; string NZD[]; string CAD[]; string CHF[]; string JPY[]; //-- string expname; string indiname1; //-- //--- Indicators Handle int hZigZag[], hAO[]; int hVIDyAv[]; int hPar05[], hPar15[]; //--- int ALO, dgts, arrsar, arrsymbx; int sall, arusd, areur, aretc, arspc, arper; ulong slip; //-- double profitb[], profits[]; double minprofit; //-- int Buy, Sell; int ccur, psec, xtto, checktml; int OpOr[],xob[],xos[]; //-- int year, // Year mon, // Month day, // Day hour, // Hour min, // Minutes sec, // Seconds dow, // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) doy; // Day number of the year (January 1st is assigned the number value of zero) //-- ENUM_TIMEFRAMES TFt, TFT05, TFT15; //-- bool PanelExtra; //------------ MCEA(void); ~MCEA(void); //------------ //-- virtual void ZigZag_AO_MCEA_Config(void); virtual void ExpertActionTrade(void); //-- void ArraySymbolResize(void); void CurrentSymbolSet(const string symbol); void Pips(const string symbol); void TradeInfo(void); void Do_Alerts(const string symbx,string msgText); void CheckOpenPMx(const string symbx); void SetSLTPOrders(void); void CloseAllOrders(void); void CheckClose(const string symbx); void TodayOrders(void); void UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf); void UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf,int bars); void RefreshPrice(const string symbx,ENUM_TIMEFRAMES xtf,int bars); //-- bool CheckEquityBalance(void); bool RefreshTick(const string symbx); bool TradingToday(void); bool OpenBuy(const string symbol); bool OpenSell(const string symbol); bool ModifyOrderSLTP(double mStop,double ordtp); bool ModifyOrdersSL(const string symbx,int TS_type); bool ModifyOrdersTP(const string symbx); bool CloseAllProfit(void); bool CloseAllLoss(void); bool ManualCloseAllProfit(void); bool CheckProfitLoss(const string symbol); bool CloseBuyPositions(const string symbol); bool CloseSellPositions(const string symbol); bool CheckProfit(const string symbol,ENUM_POSITION_TYPE intype); bool CheckLoss(const string symbol,ENUM_POSITION_TYPE intype,double slc=0.0); //-- int PairsIdxArray(const string symbol); int ValidatePairs(const string symbol); int GetOpenPosition(const string symbol); int GetCloseInWeakSignal(const string symbol,int exis); //-- string getUninitReasonText(int reasonCode); //-- //------------ //--- }; //-end class MCEA //---------// MCEA mc; //---------//
A primeira e mais importante função no processo de fluxo de trabalho do Expert Advisor Multi-Moeda é chamada a partir do OnInit() e é a ZigZag_AO_MCEA_Config().
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(void) { //--- mc.ZigZag_AO_MCEA_Config(); //-- return(INIT_SUCCEEDED); //--- } //-end OnInit() //---------//
A função ZigZag_AO_MCEA_Config() configura todos os símbolos a serem usados, todos os intervalos de tempo, todos os manipuladores de indicadores e algumas funções importantes do arquivo de cabeçalho incluído para o fluxo de trabalho do Expert Advisor.
A função ZigZag_AO_MCEA_Config() descreve e implementa como lidar com intervalos de tempo e criar manipuladores de indicadores para todos os indicadores usados no fluxo de trabalho do Expert Advisor.
//+------------------------------------------------------------------+ //| Expert Configuration | //+------------------------------------------------------------------+ void MCEA::ZigZag_AO_MCEA_Config(void) { //--- //-- HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded //-- TFT05=PERIOD_M5; TFT15=PERIOD_M15; ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1}; int arTFs=ArraySize(TFs); //-- for(int x=0; x<arTFs; x++) if(tfinuse==x) TFt=TFs[x]; // TF for calculation signal //-- //-- Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { hZigZag[x] = iCustom(DIRI[x],TFt,indiname1,zzDepth,zzDevia,zzBackS); //-- Handle for the ZigZag indicator hAO[x] = iAO(DIRI[x],TFt); //-- Handle for the Awesome_Oscillator indicator hVIDyAv[x] = iVIDyA(DIRI[x],TFt,9,12,0,PRICE_WEIGHTED); //-- Handle for the VIDYA indicator for Trailing Stop hPar05[x] = iSAR(DIRI[x],TFT05,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M5 Timeframe hPar15[x] = iSAR(DIRI[x],TFT15,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M15 Timeframe //-- } //-- TesterHideIndicators(true); minprofit=NormalizeDouble(TSmin/100.0,2); //-- ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders(); if(Close_by_Opps==No) { if((int)mc_account.LimitOrders()>=(sall*2)) ALO=sall*2; else ALO=(int)(mc_account.LimitOrders()/2); } //-- LotPS=(double)ALO; //-- mc_trade.SetExpertMagicNumber(magicEA); mc_trade.SetDeviationInPoints(slip); mc_trade.SetMarginMode(); Set_Time_Zone(); //-- return; //--- } //-end ZigZag_AO_MCEA_Config() //---------//
3. Função e fluxo de trabalho do Expert Tick
Dentro da função Expert Tick (função OnTick()), chamaremos uma das funções mais importantes em um Expert Advisor multi-moeda, a saber, a função ExpertActionTrade().
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(void) { //--- mc.ExpertActionTrade(); //-- return; //--- } //-end OnTick() //---------//
Todo o processo de funcionamento do EA para negociação está incluído nesta função.
Isso significa que a função ExpertActionTrade() realizará todas as atividades e gerenciará a negociação automática, começando pela abertura de ordens, fechamento de ordens, stops móveis ou lucros móveis e outras atividades adicionais.
void MCEA::ExpertActionTrade(void) { //--- //--Check Trading Terminal ResetLastError(); //-- if(!MQLInfoInteger(MQL_TRADE_ALLOWED) && mc.checktml==0) //-- Check whether MT5 Algorithmic trading is Allow or Prohibit { mc.Do_Alerts(Symbol(),"Trading Expert at "+Symbol()+" are NOT Allowed by Setting."); mc.checktml=1; //-- Variable checktml is given a value of 1, so that the alert is only done once. return; } //-- if(!DisplayManualButton("M","C","R")) DisplayManualButton(); //-- Show the expert manual button panel //-- if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart //--- //-- int mcsec=mc.ThisTime(mc.sec); //-- if(fmod((double)mcsec,5.0)==0) mc.ccur=mcsec; //-- if(mc.ccur!=mc.psec) { string symbol; //-- Here we start with the rotation of the name of all symbol or pairs to be traded for(int x=0; x<mc.arrsymbx && !IsStopped(); x++) { //-- switch(trademode) { case SP: { if(mc.DIRI[x]!=Symbol()) continue; symbol=Symbol(); mc.pairs=mc.pairs+" ("+symbol+")"; break; } case MP: { if(mc.DIRI[x]==Symbol()) symbol=Symbol(); else symbol=mc.DIRI[x]; break; } } //-- mc.CurrentSymbolSet(symbol); //-- if(mc.TradingToday() && mc.Trade_session()) { //-- mc.OpOr[x]=mc.GetOpenPosition(symbol); //-- Get trading signals to open positions //-- //-- and store in the variable OpOr[x] if(mc.OpOr[x]==mc.Buy) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Buy" (value=1) { //-- mc.CheckOpenPMx(symbol); //-- if(Close_by_Opps==Yes && mc.xos[x]>0) mc.CloseSellPositions(symbol); //-- if(mc.xob[x]==0 && mc.xtto<mc.ALO) mc.OpenBuy(symbol); else if(mc.xtto>=mc.ALO) { //-- mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+ "\n the limit = "+string(mc.ALO)+" Orders "); //-- mc.CheckOpenPMx(symbol); //-- if(mc.xos[x]>0 && mc.profits[x]<-1.02 && mc.xob[x]==0) {mc.CloseSellPositions(symbol); mc.OpenBuy(symbol);} else mc.CloseAllProfit(); //-- if(mc.xos[x]>0 && use_sl==No && CheckVSLTP==Yes) { if(mc.CheckLoss(symbol,POSITION_TYPE_SELL,SLval)) if(mc.CloseSellPositions(symbol)) mc.Do_Alerts(symbol,"Check Profit Trade and Close order due stop in loss."); } } } if(mc.OpOr[x]==mc.Sell) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Sell" (value=-1) { //-- mc.CheckOpenPMx(symbol); //-- if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol); //-- if(mc.xos[x]==0 && mc.xtto<mc.ALO) mc.OpenSell(symbol); else if(mc.xtto>=mc.ALO) { //-- mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+ "\n the limit = "+string(mc.ALO)+" Orders "); //-- mc.CheckOpenPMx(symbol); //-- if(mc.xob[x]>0 && mc.profitb[x]<-1.02 && mc.xos[x]==0) {mc.CloseBuyPositions(symbol); mc.OpenSell(symbol);} else mc.CloseAllProfit(); //-- if(mc.xob[x]>0 && use_sl==No && CheckVSLTP==Yes) { if(mc.CheckLoss(symbol,POSITION_TYPE_BUY,SLval)) if(mc.CloseBuyPositions(symbol)) mc.Do_Alerts(symbol,"Check Profit Trade and Close order due stop in loss."); } } } } //-- mc.CheckOpenPMx(symbol); //-- if(mc.xtto>0) { //-- if(SaveOnRev==Yes) //-- Close Trade and Save profit due to weak signal (Yes) { mc.CheckOpenPMx(symbol); if(mc.profitb[x]>mc.minprofit && mc.xob[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) { mc.CloseBuyPositions(symbol); mc.Do_Alerts(symbol,"Close BUY order "+symbol+" to save profit due to weak signal."); } if(mc.profits[x]>mc.minprofit && mc.xos[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) { mc.CloseSellPositions(symbol); mc.Do_Alerts(symbol,"Close SELL order "+symbol+" to save profit due to weak signal."); } } //-- if(TrailingSL==Yes) mc.ModifyOrdersSL(symbol,trlby); //-- Use Trailing Stop Loss (Yes) if(TrailingTP==Yes) mc.ModifyOrdersTP(symbol); //-- Use Trailing Take Profit (Yes) } //-- mc.CheckOpenPMx(symbol); if(Close_by_Opps==No && (mc.xob[x]+mc.xos[x]>1)) { if(mc.CheckProfitLoss(symbol)) mc.Do_Alerts(symbol,"Close order due stop in loss."); } //-- if(use_sl==No && CheckVSLTP==Yes) { if(!mc.CheckEquityBalance()) if(mc.CloseAllLoss()) mc.Do_Alerts(symbol,"Close order due stop in loss to secure equity."); } //-- mc.CheckClose(symbol); } //-- mc.psec=mc.ccur; } //-- return; //--- } //-end ExpertActionTrade() //---------//
Enquanto isso, o grupo de propriedades Dia de Negociação Ativar/Desativar permite que os traders negociem em determinados dias, de domingo a sábado. Isso permite que os traders habilitem ou desabilitem o expert para negociar em um dia específico usando as opções (Sim) ou (Não).
//--Day Trading On/Off input group "=== Day Trading On/Off ==="; // Day Trading On/Off input YN ttd0 = No; // Select Trading on Sunday (Yes) or (No) input YN ttd1 = Yes; // Select Trading on Monday (Yes) or (No) input YN ttd2 = Yes; // Select Trading on Tuesday (Yes) or (No) input YN ttd3 = Yes; // Select Trading on Wednesday (Yes) or (No) input YN ttd4 = Yes; // Select Trading on Thursday (Yes) or (No) input YN ttd5 = Yes; // Select Trading on Friday (Yes) or (No) input YN ttd6 = No; // Select Trading on Saturday (Yes) or (No)
A execução para o Dia de Negociação Ativar/Desativar é a seguinte:
bool MCEA::TradingToday(void) { //--- bool tradetoday=false; int trdday=ThisTime(dow); hariini="No"; //-- int ttd[]; ArrayResize(ttd,7); ttd[0]=ttd0; ttd[1]=ttd1; ttd[2]=ttd2; ttd[3]=ttd3; ttd[4]=ttd4; ttd[5]=ttd5; ttd[6]=ttd6; //-- if(ttd[trdday]==Yes) {tradetoday=true; hariini="Yes";} //-- return(tradetoday); //--- } //-end TradingToday() //---------//
Notas: As condições de Dia de Negociação Ativar/Desativar serão exibidas nas Informações de Negociação no Gráfico.
O que é executado pela função TradingDay()
string MCEA::TradingDay(void) { //--- int trdday=ThisTime(dow); switch(trdday) { case 0: daytrade="Sunday"; break; case 1: daytrade="Monday"; break; case 2: daytrade="Tuesday"; break; case 3: daytrade="Wednesday"; break; case 4: daytrade="Thursday"; break; case 5: daytrade="Friday"; break; case 6: daytrade="Saturday"; break; } return(daytrade); //--- } //-end TradingDay() //---------//
Os traders têm a opção de negociar por fuso horário no grupo de propriedades "Negociar em Horário Específico" do Expert Advisor.
Notas: Como explicado acima, no caso de negociação na Sessão da Nova Zelândia até a negociação na Sessão de Nova York, o tempo desde o início da negociação até o fechamento da negociação é calculado pelo EA.
Portanto, nas propriedades de entrada do Expert, os traders só precisam definir o horário e minuto em que a negociação começa e o horário e minuto em que a negociação termina para a Sessão Personalizada.
A função ExpertActionTrade() foi estendida com uma chamada para a função booleana Trade_session() especificamente para negociação por fuso horário.
Se Trade_session() for verdadeiro, então o processo de trabalho do EA continuará até ser concluído, mas se for falso, o EA apenas executará as tarefas "Fechar Negociação e Salvar Lucro devido a Sinal Fraco, se for (Sim)" e "Trailing Stop, se for (Sim)".
bool MCEA::Trade_session(void) { //--- bool trd_ses=false; ishour=ThisTime(hour); if(ishour!=onhour) Set_Time_Zone(); datetime tcurr=TimeCurrent(); // Server Time //-- switch(session) { case Cus_Session: { if(tcurr>=SesCuOp && tcurr<=SesCuCl) trd_ses=true; break; } case New_Zealand: { if(tcurr>=Ses01Op && tcurr<=Ses01Cl) trd_ses=true; break; } case Australia: { if(tcurr>=Ses02Op && tcurr<=Ses02Cl) trd_ses=true; break; } case Asia_Tokyo: { if(tcurr>=Ses03Op && tcurr<=Ses03Cl) trd_ses=true; break; } case Europe_London: { if(tcurr>=Ses04Op && tcurr<=Ses04Cl) trd_ses=true; break; } case US_New_York: { if(tcurr>=Ses05Op && tcurr<=Ses05Cl) trd_ses=true; break; } } //-- if(trd_time_zone==No) { if(tcurr>=SesNoOp && tcurr<=SesNoCl) trd_ses=true; } //-- onhour=ishour; //-- return(trd_ses); //--- } //-end Trade_session() //---------//
O fluxo de trabalho em Negociar em Horário Específico é o seguinte: primeiro, a função ExpertActionTrade() chama a função Trade_session(), então a função Trade_session() chama a função Set_Time_Zone(), e finalmente a função Set_Time_Zone() chama a função Time_Zone().
void MCEA::Set_Time_Zone(void) { //--- //-- Server Time==TimeCurrent() datetime TTS=TimeTradeServer(); datetime GMT=TimeGMT(); //-- MqlDateTime svrtm,gmttm; TimeToStruct(TTS,svrtm); TimeToStruct(GMT,gmttm); int svrhr=svrtm.hour; // Server time hour int gmthr=gmttm.hour; // GMT time hour int difhr=svrhr-gmthr; // Time difference Server time to GMT time //-- int NZSGMT=12; // New Zealand Session GMT/UTC+12 int AUSGMT=10; // Australia Sydney Session GMT/UTC+10 int TOKGMT=9; // Asia Tokyo Session GMT/UTC+9 int EURGMT=0; // Europe London Session GMT/UTC 0 int USNGMT=-5; // US New York Session GMT/UTC-5 //-- int NZSStm=8; // New Zealand Session time start: 08:00 Local Time int NZSCtm=17; // New Zealand Session time close: 17:00 Local Time int AUSStm=7; // Australia Sydney Session time start: 07:00 Local Time int AUSCtm=17; // Australia Sydney Session time close: 17:00 Local Time int TOKStm=9; // Asia Tokyo Session time start: 09:00 Local Time int TOKCtm=18; // Asia Tokyo Session time close: 18:00 Local Time int EURStm=9; // Europe London Session time start: 09:00 Local Time int EURCtm=19; // Europe London Session time close: 19:00 Local Time int USNStm=8; // US New York Session time start: 08:00 Local Time int USNCtm=17; // US New York Session time close: 17:00 Local Time //-- int nzo = (NZSStm+difhr-NZSGMT)<0 ? 24+(NZSStm+difhr-NZSGMT) : (NZSStm+difhr-NZSGMT); int nzc = (NZSCtm+difhr-NZSGMT)<0 ? 24+(NZSCtm+difhr-NZSGMT) : (NZSCtm+difhr-NZSGMT); //-- int auo = (AUSStm+difhr-AUSGMT)<0 ? 24+(AUSStm+difhr-AUSGMT) : (AUSStm+difhr-AUSGMT); int auc = (AUSCtm+difhr-AUSGMT)<0 ? 24+(AUSCtm+difhr-AUSGMT) : (AUSCtm+difhr-AUSGMT); //-- int tko = (TOKStm+difhr-TOKGMT)<0 ? 24+(TOKStm+difhr-TOKGMT) : (TOKStm+difhr-TOKGMT); int tkc = (TOKCtm+difhr-TOKGMT)<0 ? 24+(TOKCtm+difhr-TOKGMT) : (TOKCtm+difhr-TOKGMT); //-- int euo = (EURStm+difhr-EURGMT)<0 ? 24+(EURStm+difhr-EURGMT) : (EURStm+difhr-EURGMT); int euc = (EURCtm+difhr-EURGMT)<0 ? 24+(EURCtm+difhr-EURGMT) : (EURCtm+difhr-EURGMT); //-- int uso = (USNStm+difhr-USNGMT)<0 ? 24+(USNStm+difhr-USNGMT) : (USNStm+difhr-USNGMT); int usc = (USNCtm+difhr-USNGMT)<0 ? 24+(USNCtm+difhr-USNGMT) : (USNCtm+difhr-USNGMT); if(usc==0||usc==24) usc=23; //-- //---Trading on Custom Session int _days00=ThisTime(day); int _days10=ThisTime(day); if(stsescuh>clsescuh) _days10=ThisTime(day)+1; tmopcu=ReqDate(_days00,stsescuh,stsescum); tmclcu=ReqDate(_days10,clsescuh,clsescum); //-- //--Trading on New Zealand Session GMT/UTC+12 int _days01=ThisTime(hour)<nzc ? ThisTime(day)-1 : ThisTime(day); int _days11=ThisTime(hour)<nzc ? ThisTime(day) : ThisTime(day)+1; tmop01=ReqDate(_days01,nzo,0); // start: 08:00 Local Time == 20:00 GMT/UTC tmcl01=ReqDate(_days11,nzc-1,59); // close: 17:00 Local Time == 05:00 GMT/UTC //-- //--Trading on Australia Sydney Session GMT/UTC+10 int _days02=ThisTime(hour)<auc ? ThisTime(day)-1 : ThisTime(day); int _days12=ThisTime(hour)<auc ? ThisTime(day) : ThisTime(day)+1; tmop02=ReqDate(_days02,auo,0); // start: 07:00 Local Time == 21:00 GMT/UTC tmcl02=ReqDate(_days12,auc-1,59); // close: 17:00 Local Time == 07:00 GMT/UTC //-- //--Trading on Asia Tokyo Session GMT/UTC+9 int _days03=ThisTime(hour)<tkc ? ThisTime(day) : ThisTime(day)+1; int _days13=ThisTime(hour)<tkc ? ThisTime(day) : ThisTime(day)+1; tmop03=ReqDate(_days03,tko,0); // start: 09:00 Local Time == 00:00 GMT/UTC tmcl03=ReqDate(_days13,tkc-1,59); // close: 18:00 Local Time == 09:00 GMT/UTC //-- //--Trading on Europe London Session GMT/UTC 00:00 int _days04=ThisTime(hour)<euc ? ThisTime(day) : ThisTime(day)+1; int _days14=ThisTime(hour)<euc ? ThisTime(day) : ThisTime(day)+1; tmop04=ReqDate(_days04,euo,0); // start: 09:00 Local Time == 09:00 GMT/UTC tmcl04=ReqDate(_days14,euc-1,59); // close: 19:00 Local Time == 19:00 GMT/UTC //-- //--Trading on US New York Session GMT/UTC-5 int _days05=ThisTime(hour)<usc ? ThisTime(day) : ThisTime(day)+1; int _days15=ThisTime(hour)<=usc ? ThisTime(day) : ThisTime(day)+1; tmop05=ReqDate(_days05,uso,0); // start: 08:00 Local Time == 13:00 GMT/UTC tmcl05=ReqDate(_days15,usc,59); // close: 17:00 Local Time == 22:00 GMT/UTC //-- //--Not Use Trading Time Zone if(trd_time_zone==No) { tmopno=ReqDate(ThisTime(day),0,15); tmclno=ReqDate(ThisTime(day),23,59); } //-- Time_Zone(); //-- return; //--- } //-end Set_Time_Zone() //---------//
void MCEA::Time_Zone(void) { //--- //-- tz_ses=""; //-- switch(session) { case Cus_Session: { SesCuOp=StringToTime(tmopcu); SesCuCl=StringToTime(tmclcu); zntm=SesCuOp; znop=SesCuOp; zncl=SesCuCl; tz_ses="Custom_Session"; tz_opn=timehr(stsescuh,stsescum); tz_cls=timehr(clsescuh,clsescum); break; } case New_Zealand: { Ses01Op=StringToTime(tmop01); Ses01Cl=StringToTime(tmcl01); zntm=Ses01Op; znop=Ses01Op; zncl=Ses01Cl; tz_ses="New_Zealand/Oceania"; tz_opn=timehr(ReqTime(Ses01Op,hour),ReqTime(Ses01Op,min)); tz_cls=timehr(ReqTime(Ses01Cl,hour),ReqTime(Ses01Cl,min)); break; } case Australia: { Ses02Op=StringToTime(tmop02); Ses02Cl=StringToTime(tmcl02); zntm=Ses02Op; znop=Ses02Op; zncl=Ses02Cl; tz_ses="Australia Sydney"; tz_opn=timehr(ReqTime(Ses02Op,hour),ReqTime(Ses02Op,min)); tz_cls=timehr(ReqTime(Ses02Cl,hour),ReqTime(Ses02Cl,min)); break; } case Asia_Tokyo: { Ses03Op=StringToTime(tmop03); Ses03Cl=StringToTime(tmcl03); zntm=Ses03Op; znop=Ses03Op; zncl=Ses03Cl; tz_ses="Asia/Tokyo"; tz_opn=timehr(ReqTime(Ses03Op,hour),ReqTime(Ses03Op,min)); tz_cls=timehr(ReqTime(Ses03Cl,hour),ReqTime(Ses03Cl,min)); break; } case Europe_London: { Ses04Op=StringToTime(tmop04); Ses04Cl=StringToTime(tmcl04); zntm=Ses04Op; znop=Ses04Op; zncl=Ses04Cl; tz_ses="Europe/London"; tz_opn=timehr(ReqTime(Ses04Op,hour),ReqTime(Ses04Op,min)); tz_cls=timehr(ReqTime(Ses04Cl,hour),ReqTime(Ses04Cl,min)); break; } case US_New_York: { Ses05Op=StringToTime(tmop05); Ses05Cl=StringToTime(tmcl05); zntm=Ses05Op; znop=Ses05Op; zncl=Ses05Cl; tz_ses="US/New_York"; tz_opn=timehr(ReqTime(Ses05Op,hour),ReqTime(Ses05Op,min)); tz_cls=timehr(ReqTime(Ses05Cl,hour),ReqTime(Ses05Cl,min)); break; } } //-- if(trd_time_zone==No) { SesNoOp=StringToTime(tmopno); SesNoCl=StringToTime(tmclno); zntm=SesNoOp; znop=SesNoOp; zncl=SesNoCl; tz_ses="Not Use Time Zone"; tz_opn=timehr(ReqTime(SesNoOp,hour),ReqTime(SesNoOp,min)); tz_cls=timehr(ReqTime(SesNoCl,hour),ReqTime(SesNoCl,min)); } //-- return; //--- } //-end Time_Zone() //---------//
4. Como obter sinais de negociação para posições abertas?
Para obter um sinal para abrir uma posição, a função ExpertActionTrade() chama a função GetOpenPosition().
int MCEA::GetOpenPosition(const string symbol) // Signal Open Position { //--- int ret=0; int rise=1, down=-1; //-- int ZZAOSignal=GetIndiSignals(symbol); int dirmove=DirectionMove(symbol,TFt); int psar15=PARSAR15(symbol); //-- if(ZZAOSignal==rise && dirmove==rise && psar15==rise) ret=rise; if(ZZAOSignal==down && dirmove==down && psar15==down) ret=down; //-- return(ret); //--- } //-end GetOpenPosition() //---------//
E a função GetOpenPosition() chamará 3 funções:
- GetIndiSignals(symbol)
- DirectionMove(symbol,TFt)
- PARSAR15(symbol)
4.1. A função GetIndiSignals(symbol) chamará 2 funções:
- ZigZagSignal(symbol)
- AOSignal(symbol)
4.1.1. Sinal ZigZag
Dentro da função ZigZagSignal(), utilizamos e chamamos 1 função, que é a função PairsIdxArray().
int xx=PairsIdxArray(symbol)
int MCEA::PairsIdxArray(const string symbol) { //--- int pidx=-1; //-- for(int x=0; x<arrsymbx; x++) { if(DIRI[x]==symbol) { pidx=x; break; } } //-- return(pidx); //--- } //-end PairsIdxArray() //---------//
A função PairsIdxArray() é utilizada para obter o nome do símbolo solicitado e os manipuladores dos seus indicadores.
Então, o manipulador do indicador correspondente é chamado para obter o valor do buffer do indicador ZigZag daquele intervalo de tempo.
//-- Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { hZigZag[x] = iCustom(DIRI[x],TFt,indiname1,zzDepth,zzDevia,zzBackS); //-- Handle for the ZigZag indicator hAO[x] = iAO(DIRI[x],TFt); //-- Handle for the Awesome_Oscillator indicator hVIDyAv[x] = iVIDyA(DIRI[x],TFt,9,12,0,PRICE_WEIGHTED); //-- Handle for the VIDYA indicator for Trailing Stop hPar05[x] = iSAR(DIRI[x],TFT05,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M5 Timeframe hPar15[x] = iSAR(DIRI[x],TFT15,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M15 Timeframe //-- } //--
Para obter o valor do buffer do indicador ZigZag, copiaremos cada buffer do manipulador dos indicadores ZigZag.
Para copiar o buffer ZigZag (buffer 0) do manipulador do indicador ZigZag para o array de destino:
CopyBuffer(hZigZag[x],0,0,barcalc,ZZBuffer);
Além disso, a função UpdatePrice() também será chamada para obter o valor do preço Alto e o valor do preço Baixo, que serão utilizados para obter as posições dos buffers ZigZag Alto e ZigZag Baixo.
void MCEA::UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf) { //--- //-- ArrayFree(OPEN); ArrayFree(HIGH); ArrayFree(LOW); ArrayFree(CLOSE); ArrayFree(TIME); //-- ArrayResize(OPEN,arper,arper); ArrayResize(HIGH,arper,arper); ArrayResize(LOW,arper,arper); ArrayResize(CLOSE,arper,arper); ArrayResize(TIME,arper,arper); //-- ArraySetAsSeries(OPEN,true); ArraySetAsSeries(HIGH,true); ArraySetAsSeries(LOW,true); ArraySetAsSeries(CLOSE,true); ArraySetAsSeries(TIME,true); //-- ArrayInitialize(OPEN,0.0); ArrayInitialize(HIGH,0.0); ArrayInitialize(LOW,0.0); ArrayInitialize(CLOSE,0.0); ArrayInitialize(TIME,0); //-- RefreshPrice(symbol,xtf,arper); //-- int co=CopyOpen(symbol,xtf,0,arper,OPEN); int ch=CopyHigh(symbol,xtf,0,arper,HIGH); int cl=CopyLow(symbol,xtf,0,arper,LOW); int cc=CopyClose(symbol,xtf,0,arper,CLOSE); int ct=CopyTime(symbol,xtf,0,arper,TIME); //-- return; //--- } //-end UpdatePrice() //---------//
E para obter as posições das barras de ZigZag Alto e ZigZag Baixo, fazemos iterações e comparamos com o Preço Alto e o Preço Baixo.
//-- for(int i=barcalc-1; i>=0; i--) { if(ZZBuffer[i]==HIGH[i]) ZH=i; if(ZZBuffer[i]==LOW[i]) ZL=i; } //--
Após obter as posições das barras de ZigZag Alto (ZH) e ZigZag Baixo (ZL), então depende apenas da opção de sinal do indicador ZigZag selecionada na entrada de propriedades.
A função completa ZigZagSignal() é a seguinte:
int MCEA::ZigZagSignal(const string symbol) // ZigZag Signal for Open Position { //--- int ret=0; int rise=1, down=-1; int ZH=-1, ZL=-1; int barcalc=100; bool ZZrise=false; bool ZZdown=false; //-- double ZZBuffer[]; ArrayResize(ZZBuffer,barcalc,barcalc); ArraySetAsSeries(ZZBuffer,true); //-- int x=PairsIdxArray(symbol); UpdatePrice(symbol,TFt); //-- CopyBuffer(hZigZag[x],0,0,barcalc,ZZBuffer); //-- for(int i=barcalc-1; i>=0; i--) { if(ZZBuffer[i]==HIGH[i]) ZH=i; if(ZZBuffer[i]==LOW[i]) ZL=i; } //-- switch(sigzz) { case SZZ1: { ZZrise=((ZH==0 && HIGH[0]>HIGH[1])||(ZL<ZH && ZL>1)); ZZdown=((ZL==0 && LOW[0]<LOW[1])||(ZH<ZL && ZH>1)); //-- break; } case SZZ2: { ZZrise=(ZL<ZH && ZL>1); ZZdown=(ZH<ZL && ZH>1); //-- break; } case SZZ3: { ZZrise=((ZH==0 && HIGH[0]>HIGH[1])||(ZL<ZH && ZL>0)); ZZdown=((ZL==0 && LOW[0]<LOW[1])||(ZH<ZL && ZH>0)); //-- break; } case SZZ4: { ZZrise=(ZL<ZH && ZL>0); ZZdown=(ZH<ZL && ZH>0); //-- break; } }; //-- if(ZZrise) ret=rise; if(ZZdown) ret=down; //-- return(ret); //--- } //-end ZigZagSignal() //---------//
4.1.2. Sinal AO
Assim como na função ZigZagSignal(), na função AOSignal() também precisamos usar a função PairsIdxArray() para obter o valor do buffer do indicador AO.
Então, para obter o valor do buffer do indicador AO, copiaremos cada buffer do manipulador dos indicadores AO.
Para copiar o buffer AO (buffer 0) do manipulador do indicador AO para o array de destino:
CopyBuffer(hAO[x],0,0,barcalc,AOValue);
E então, depende apenas da opção de sinal do indicador AO selecionada na entrada de propriedades.
Além disso, para completar o sinal do indicador AO, também utilizamos a cor do indicador AO para verificar o sinal a partir do valor do buffer.
Para esse propósito, criamos uma função para obter o valor da cor do indicador AO com o nome da função AOColorSignal()
Nesta função, copiaremos o buffer 1 (índice de cor do indicador) do indicador AO.
CopyBuffer(hAO[x],1,0,barcalc,AOColor);
int MCEA::AOColorSignal(const string symbol) { //--- int ret=0; int rise=1, down=-1; int barcalc=9; //-- double AOColor[]; ArrayResize(AOColor,barcalc,barcalc); ArraySetAsSeries(AOColor,true); //-- int x=PairsIdxArray(symbol); UpdatePrice(symbol,TFt,barcalc); //-- CopyBuffer(hAO[x],1,0,barcalc,AOColor); //-- bool AORise=((AOColor[1]==1.0 && AOColor[0]==0.0)||(AOColor[1]==0.0 && AOColor[0]==0.0)); bool AODown=((AOColor[1]==0.0 && AOColor[0]==1.0)||(AOColor[1]==1.0 && AOColor[0]==1.0)); //-- if(AORise) ret=rise; if(AODown) ret=down; //-- return(ret); //--- } //-end AOColorSignal() //---------//
A função completa AOSignal() é a seguinte:
int MCEA::AOSignal(const string symbol) { //--- int ret=0; int rise=1, down=-1; int barcalc=9; bool AORValue=false; bool AODValue=false; //-- double AOValue[]; ArrayResize(AOValue,barcalc,barcalc); ArraySetAsSeries(AOValue,true); //-- int x=PairsIdxArray(symbol); UpdatePrice(symbol,TFt,barcalc); //-- CopyBuffer(hAO[x],0,0,barcalc,AOValue); //-- switch(sigao) { case SAO1: { AORValue=(AOValue[2]<=0.0 && AOValue[1]>0.0 && AOValue[0]>AOValue[1])||(AOValue[1]>AOValue[2] && AOValue[0]>AOValue[1]); AODValue=(AOValue[2]>=0.0 && AOValue[1]<0.0 && AOValue[0]<AOValue[1])||(AOValue[1]<AOValue[2] && AOValue[0]<AOValue[1]); //-- break; } case SAO2: { AORValue=(AOValue[1]<=0.0 && AOValue[0]>0.0)||(AOValue[0]>0.0 && AOValue[0]>AOValue[1]); AODValue=(AOValue[1]>=0.0 && AOValue[0]<0.0)||(AOValue[0]<0.0 && AOValue[0]<AOValue[1]); //-- break; } case SAO3: { AORValue=(AOValue[1]<=0.0 && AOValue[0]>0.0)||(AOValue[0]>AOValue[1]); AODValue=(AOValue[1]>=0.0 && AOValue[0]<0.0)||(AOValue[0]<AOValue[1]); //-- break; } }; //-- bool AORise=(AOColorSignal(symbol)==rise); bool AODown=(AOColorSignal(symbol)==down); //-- if(AORValue && AORise) ret=rise; if(AODValue && AODown) ret=down; //-- return(ret); //--- } //-end AOSignal() //---------//
A função GetIndiSignals() somará os valores de retorno das funções ZigZagSignal() e AOSignal().
int MCEA::GetIndiSignals(const string symbol) // Get Signal for Open Position { //--- int ret=0; int rise=1, down=-1; int sigrise=2; int sigdown=-2; //-- int ZZSignal=ZigZagSignal(symbol); int AwSignal=AOSignal(symbol); //Print(symbol+" = ZZ="+string(ZZSignal)+" AO="+string(AwSignal)+" Signal="+string(ZZSignal+AwSignal)); //-- if(ZZSignal+AwSignal==sigrise) ret=rise; if(ZZSignal+AwSignal==sigdown) ret=down; //-- return(ret); //--- } //-end GetIndiSignals() //---------//
A função GetIndiSignals() somará os valores de retorno das funções ZigZagSignal() e AOSignal().
- Se o resultado for 2, é um sinal para Comprar.
- Se o resultado for -2, é um sinal para Vender.
4.2. Função DirectionMove
A função DirectionMove() é útil para obter a posição do preço de fechamento na barra atual, se está acima do preço de abertura (alta) ou abaixo do preço de abertura (baixa).
int MCEA::DirectionMove(const string symbol,const ENUM_TIMEFRAMES stf) // Bar Price Direction { //--- int ret=0; int rise=1, down=-1; //-- Pips(symbol); double difud=mc_symbol.NormalizePrice(1.5*pip); UpdatePrice(symbol,stf,2); //-- if(CLOSE[0]>OPEN[0]+difud) ret=rise; if(CLOSE[0]<OPEN[0]-difud) ret=down; //-- return(ret); //--- } //-end DirectionMove() //---------//
4.3. Função PARSAR15()
A função PARSAR15() é útil para alinhar o movimento do indicador ZigZag e do indicador AO com o indicador Parabolic Stop and Reverse (PSAR/iSAR) no intervalo de tempo M15.
int MCEA::PARSAR15(const string symbol) // formula Parabolic SAR M15 { //--- int ret=0; int rise=1, down=-1; int br=2; //-- double PSAR[]; ArrayResize(PSAR,br,br); ArraySetAsSeries(PSAR,true); int xx=PairsIdxArray(symbol); CopyBuffer(hPar15[xx],0,0,br,PSAR); //-- UpdatePrice(symbol,TFT15,br); //-- if(PSAR[0]<LOW[0]) ret=rise; if(PSAR[0]>HIGH[0]) ret=down; //-- return(ret); //--- } //-end PARSAR15() //---------//
Após executar as 3 funções principais de sinal e várias funções de suporte, a função GetOpenPosition() fornecerá os valores:
- Valor = 0, sinal desconhecido.
- Valor = 1, é um sinal para abrir uma ordem de Compra.
- Valor = -1, é um sinal para abrir uma ordem de Venda.
Quando a função GetOpenPosition() retorna um valor de 1, o Expert Advisor chama a função OpenBuy() para abrir uma ordem de Compra.
bool MCEA::OpenBuy(const string symbol) { //--- ResetLastError(); //-- bool buyopen = false; string ldComm = GetCommentForOrder()+"_Buy"; double ldLot = MLots(symbol); ENUM_ORDER_TYPE type_req = ORDER_TYPE_BUY; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- structure is set to zero ZeroMemory(req); ZeroMemory(res); ZeroMemory(check); //-- CurrentSymbolSet(symbol); double SL=OrderSLSet(symbol,type_req,mc_symbol.Bid()); double TP=OrderTPSet(symbol,type_req,mc_symbol.Ask()); //-- if(RefreshTick(symbol)) buyopen=mc_trade.Buy(ldLot,symbol,mc_symbol.Ask(),SL,TP,ldComm); //-- int error=GetLastError(); if(buyopen||error==0) { string bsopen="Open BUY Order for "+symbol+" ~ Ticket= ["+(string)mc_trade.ResultOrder()+"] successfully..!"; Do_Alerts(symbol,bsopen); } else { mc_trade.CheckResult(check); Do_Alerts(Symbol(),"Open BUY order for "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); return(false); } //-- return(buyopen); //-- //--- } //-end OpenBuy //---------//
Se a função GetOpenPosition() retornar um valor de -1, o Expert Advisor chamará a função OpenSell() para abrir uma ordem de Venda.
bool MCEA::OpenSell(const string symbol) { //--- ResetLastError(); //-- bool selopen = false; string sdComm = GetCommentForOrder()+"_Sell"; double sdLot = MLots(symbol); ENUM_ORDER_TYPE type_req = ORDER_TYPE_SELL; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- structure is set to zero ZeroMemory(req); ZeroMemory(res); ZeroMemory(check); //-- CurrentSymbolSet(symbol); double SL=OrderSLSet(symbol,type_req,mc_symbol.Ask()); double TP=OrderTPSet(symbol,type_req,mc_symbol.Bid()); //-- if(RefreshTick(symbol)) selopen=mc_trade.Sell(sdLot,symbol,mc_symbol.Bid(),SL,TP,sdComm); //-- int error=GetLastError(); if(selopen||error==0) { string bsopen="Open SELL Order for "+symbol+" ~ Ticket= ["+(string)mc_trade.ResultOrder()+"] successfully..!"; Do_Alerts(symbol,bsopen); } else { mc_trade.CheckResult(check); Do_Alerts(Symbol(),"Open SELL order for "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); return(false); } //-- return(selopen); //-- //--- } //-end OpenSell //---------//
5. Função ChartEvent
Para apoiar a eficácia e a eficiência no uso dos Expert Advisors Multi-Currency, é considerado necessário criar um ou mais botões manuais para gerenciar ordens e mudar o intervalo de tempo ou símbolos dos gráficos.
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- //--- handling CHARTEVENT_CLICK event ("Clicking the chart") ResetLastError(); //-- ENUM_TIMEFRAMES CCS=mc.TFt; //-- if(id==CHARTEVENT_OBJECT_CLICK) { int lensymbol=StringLen(Symbol()); int lensparam=StringLen(sparam); //-- //--- if "Set SL All Orders" button is click if(sparam=="Set SL/TP All Orders") { mc.SetSLTPOrders(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Set SL/TP All Orders"); //--- unpress the button ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_STATE,false); ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "Close All Order" button is click if(sparam=="Close All Order") { mc.CloseAllOrders(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Orders"); //--- unpress the button ObjectSetInteger(0,"Close All Order",OBJPROP_STATE,false); ObjectSetInteger(0,"Close All Order",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "Close All Profit" button is click if(sparam=="Close All Profit") { mc.ManualCloseAllProfit(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Profit"); //--- unpress the button ObjectSetInteger(0,"Close All Profit",OBJPROP_STATE,false); ObjectSetInteger(0,"Close All Profit",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "X" button is click if(sparam=="X") { ObjectsDeleteAll(0,0,OBJ_BUTTON); ObjectsDeleteAll(0,0,OBJ_LABEL); ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL); //--- unpress the button ObjectSetInteger(0,"X",OBJPROP_STATE,false); ObjectSetInteger(0,"X",OBJPROP_ZORDER,0); //-- DeleteButtonX(); mc.PanelExtra=false; DisplayManualButton(); } //--- if "M" button is click if(sparam=="M") { //--- unpress the button ObjectSetInteger(0,"M",OBJPROP_STATE,false); ObjectSetInteger(0,"M",OBJPROP_ZORDER,0); mc.PanelExtra=true; CreateManualPanel(); } //--- if "C" button is click if(sparam=="C") { //--- unpress the button ObjectSetInteger(0,"C",OBJPROP_STATE,false); ObjectSetInteger(0,"C",OBJPROP_ZORDER,0); mc.PanelExtra=true; CreateSymbolPanel(); } //--- if "R" button is click if(sparam=="R") { Alert("-- "+mc.expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart."); ExpertRemove(); //--- unpress the button ObjectSetInteger(0,"R",OBJPROP_STATE,false); ObjectSetInteger(0,"R",OBJPROP_ZORDER,0); if(!ChartSetSymbolPeriod(0,Symbol(),Period())) ChartSetSymbolPeriod(0,Symbol(),Period()); DeletePanelButton(); ChartRedraw(0); } //--- if Symbol button is click if(lensparam==lensymbol) { int sx=mc.ValidatePairs(sparam); ChangeChartSymbol(mc.AS30[sx],CCS); mc.PanelExtra=false; } //-- } //-- return; //--- } //-end OnChartEvent() //---------//
No grupo de propriedades de entrada Outros Parâmetros do Expert Advisor, o trader tem a opção de selecionar se deseja exibir informações de negociação no gráfico (Sim) ou (Não).
Se essa opção for selecionada como (Sim), as informações de negociação serão exibidas no gráfico ao qual o Expert Advisor está anexado, chamando a função TradeInfo().
Também foi adicionada uma função para descrever o tempo de acordo com as condições de fuso horário de negociação como parte da função TradeInfo().
string MCEA::PosTimeZone(void) { //--- string tzpos=""; //-- if(ReqTime(zntm,day)>ThisTime(day)) { tzpos=tz_opn+ " Next day to " +tz_cls + " Next day"; } else if(TimeCurrent()<znop) { if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)==ReqTime(zncl,day)) tzpos=tz_opn+" to " +tz_cls+ " Today"; //else if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day)) tzpos=tz_opn+ " Today to " +tz_cls+ " Next day"; } else if(TimeCurrent()>=znop && TimeCurrent()<zncl) { if(ThisTime(day)<ReqTime(zncl,day)) tzpos=tz_opn+ " Today to " +tz_cls+ " Next day"; else if(ThisTime(day)==ReqTime(zncl,day)) tzpos=tz_opn+" to " +tz_cls+ " Today"; } else if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day)) { tzpos=tz_opn+" Today to " +tz_cls+ " Next day"; } //-- return(tzpos); //---- } //-end PosTimeZone() //---------//
void MCEA::TradeInfo(void) // function: write comments on the chart { //---- Pips(Symbol()); double spread=SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/xpip; rem=zntm-TimeCurrent(); string postime=PosTimeZone(); string eawait=" - Waiting for active time..!"; //-- string comm=""; TodayOrders(); //-- comm="\n :: Server Date Time : "+string(ThisTime(year))+"."+string(ThisTime(mon))+"."+string(ThisTime(day))+ " "+TimeToString(TimeCurrent(),TIME_SECONDS)+ "\n ------------------------------------------------------------"+ "\n :: Broker : "+ TerminalInfoString(TERMINAL_COMPANY)+ "\n :: Expert Name : "+ expname+ "\n :: Acc. Name : "+ mc_account.Name()+ "\n :: Acc. Number : "+ (string)mc_account.Login()+ "\n :: Acc. TradeMode : "+ AccountMode()+ "\n :: Acc. Leverage : 1 : "+ (string)mc_account.Leverage()+ "\n :: Acc. Equity : "+ DoubleToString(mc_account.Equity(),2)+ "\n :: Margin Mode : "+ (string)mc_account.MarginModeDescription()+ "\n :: Magic Number : "+ string(magicEA)+ "\n :: Trade on TF : "+ EnumToString(TFt)+ "\n :: Today Trading : "+ TradingDay()+" : "+hariini+ "\n :: Trading Session : "+ tz_ses+ "\n :: Trading Time : "+ postime; if(TimeCurrent()<zntm) { comm=comm+ "\n :: Time Remaining : "+(string)ReqTime(rem,hour)+":"+(string)ReqTime(rem,min)+":"+(string)ReqTime(rem,sec) + eawait; } comm=comm+ "\n ------------------------------------------------------------"+ "\n :: Trading Pairs : "+pairs+ "\n :: BUY Market : "+string(oBm)+ "\n :: SELL Market : "+string(oSm)+ "\n :: Total Order : "+string(oBm+oSm)+ "\n :: Order Profit : "+DoubleToString(floatprofit,2)+ "\n :: Fixed Profit : "+DoubleToString(fixclprofit,2)+ "\n :: Float Money : "+DoubleToString(floatprofit,2)+ "\n :: Nett Profit : "+DoubleToString(floatprofit+fixclprofit,2); //-- Comment(comm); ChartRedraw(0); return; //---- } //-end TradeInfo() //---------//
Interface do Multi-Currency Expert Advisor ZigZag_AO_MCEA A interface do Expert Advisor ZigZag_AO_MCEA é semelhante à figura a seguir.
Como você pode ver, há botões "M", "C" e "R" abaixo do nome do Expert Advisor ZigZag_AO_MCEA.
Quando o botão "M" é clicado, um painel de botões manuais de clique é exibido, conforme mostrado abaixo.
O trader pode gerenciar ordens manualmente quando o painel de botões manuais de clique é exibido:
5.1. Set SL/TP All Orders
Como explicado acima, se o trader entrar com os parâmetros "Use Order Stop Loss" (Não) e/ou "Use Order Take Profit" (Não), mas depois desejar usar Stop Loss ou Take Profit em todas as ordens, então, com um único clique no botão "Set SL/TP All Orders", todas as ordens serão modificadas e será aplicado Stop Loss e/ou Take Profit.
void MCEA::SetSLTPOrders(void) { //--- ResetLastError(); MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- double modbuysl=0; double modselsl=0; double modbuytp=0; double modseltp=0; string position_symbol; int totalorder=PositionsTotal(); //-- for(int i=totalorder-1; i>=0; i--) { string symbol=PositionGetSymbol(i); position_symbol=symbol; if(mc_position.Magic()==magicEA) { ENUM_POSITION_TYPE opstype = mc_position.PositionType(); if(opstype==POSITION_TYPE_BUY) { Pips(symbol); RefreshTick(symbol); double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_take = mc_position.TakeProfit(); modbuysl=SetOrderSL(symbol,opstype,pos_open); if(price<modbuysl) modbuysl=mc_symbol.NormalizePrice(price-slip*pip); modbuytp=SetOrderTP(symbol,opstype,pos_open); if(price>modbuytp) modbuytp=mc_symbol.NormalizePrice(price+slip*pip); //-- if(pos_stop==0.0 || pos_take==0.0) { if(!mc_trade.PositionModify(position_symbol,modbuysl,modbuytp)) { mc_trade.CheckResult(check); Do_Alerts(symbol,"Set SL and TP for "+EnumToString(opstype)+" on "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); } } } if(opstype==POSITION_TYPE_SELL) { Pips(symbol); RefreshTick(symbol); double price = mc_position.PriceCurrent(); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_take = mc_position.TakeProfit(); modselsl=SetOrderSL(symbol,opstype,pos_open); if(price>modselsl) modselsl=mc_symbol.NormalizePrice(price+slip*pip); modseltp=SetOrderTP(symbol,opstype,pos_open); if(price<modseltp) modseltp=mc_symbol.NormalizePrice(price-slip*pip); //-- if(pos_stop==0.0 || pos_take==0.0) { if(!mc_trade.PositionModify(position_symbol,modselsl,modseltp)) { mc_trade.CheckResult(check); Do_Alerts(symbol,"Set SL and TP for "+EnumToString(opstype)+" on "+symbol+" FAILED!!. Return code= "+ (string)mc_trade.ResultRetcode()+". Code description: ["+mc_trade.ResultRetcodeDescription()+"]"); } } } } } //-- return; //--- } //-end SetSLTPOrders //---------//
5.2. Fechar Todas as Ordens
Se um trader deseja fechar todas as ordens, um único clique no botão "Fechar Todas as Ordens" fechará todas as ordens abertas.
void MCEA::CloseAllOrders(void) //-- function: close all order { //---- ResetLastError(); //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int total=PositionsTotal(); // number of open positions //--- iterate over all open positions for(int i=total-1; i>=0; i--) { //--- if the MagicNumber matches if(mc_position.Magic()==magicEA) { //-- string position_Symbol = PositionGetSymbol(i); // symbol of the position ulong position_ticket = PositionGetTicket(i); // ticket of the the opposite position ENUM_POSITION_TYPE type = mc_position.PositionType(); RefreshTick(position_Symbol); bool closepos = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); //--- } } //--- return; //---- } //-end CloseAllOrders() //---------//
5.3. Fechar Todos os Lucros
Se um trader desejar fechar todas as ordens que já estão lucrativas, um único clique no botão "Fechar Todos os Lucros" fechará todas as ordens em aberto que já estão lucrativas.
bool MCEA::ManualCloseAllProfit(void) { //---- ResetLastError(); //-- bool orclose=false; //-- MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int ttlorder=PositionsTotal(); // number of open positions //-- for(int x=0; x<arrsymbx; x++) { string symbol=DIRI[x]; orclose=false; //-- for(int i=ttlorder-1; i>=0; i--) { string position_Symbol = PositionGetSymbol(i); ENUM_POSITION_TYPE type = mc_position.PositionType(); if((position_Symbol==symbol) && (mc_position.Magic()==magicEA)) { double pos_profit = mc_position.Profit(); double pos_swap = mc_position.Swap(); double pos_comm = mc_position.Commission(); double cur_profit = NormalizeDouble(pos_profit+pos_swap+pos_comm,2); ulong position_ticket = PositionGetTicket(i); //--- if(type==POSITION_TYPE_BUY && cur_profit>0.02) { RefreshTick(position_Symbol); orclose = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); } if(type==POSITION_TYPE_SELL && cur_profit>0.02) { RefreshTick(position_Symbol); orclose = mc_trade.PositionClose(position_Symbol,slip); //--- output information about the closure PrintFormat("Close #%I64d %s %s",position_ticket,position_Symbol,EnumToString(type)); } } } } //-- return(orclose); //---- } //-end ManualCloseAllProfit() //---------//
Além disso, quando o botão C for clicado, um painel com 30 nomes de símbolos ou pares será exibido, e os traders poderão clicar em um dos nomes dos pares ou nomes dos símbolos.
Clicar em um dos nomes dos pares ou nomes dos símbolos substituirá imediatamente o símbolo do gráfico pelo símbolo cujo nome foi clicado.
void CreateSymbolPanel() { //--- //-- ResetLastError(); DeletePanelButton(); int sydis=83; int tsatu=int(mc.sall/2); //-- CreateButtonTemplate(0,"Template",180,367,STYLE_SOLID,5,BORDER_RAISED,clrYellow,clrBurlyWood,clrWhite,CORNER_RIGHT_UPPER,187,45,true); CreateButtonTemplate(0,"TempCCS",167,25,STYLE_SOLID,5,BORDER_RAISED,clrYellow,clrBlue,clrWhite,CORNER_RIGHT_UPPER,181,50,true); CreateButtonClick(0,"X",14,14,"Arial Black",10,BORDER_FLAT,"X",clrWhite,clrWhite,clrRed,ANCHOR_CENTER,CORNER_RIGHT_UPPER,22,48,true,"Close Symbol Panel"); //-- string chsym="Change SYMBOL"; int cspos=int(181/2)+int(StringLen(chsym)/2); CreateButtontLable(0,"CCS","Bodoni MT Black",chsym,11,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,cspos,62,true,"Change Chart Symbol"); //-- for(int i=0; i<tsatu; i++) CreateButtonClick(0,mc.AS30[i],80,17,"Bodoni MT Black",8,BORDER_RAISED,mc.AS30[i],clrYellow,clrBlue,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,180,sydis+(i*22),true,"Change to "+mc.AS30[i]); //-- for(int i=tsatu; i<mc.sall; i++) CreateButtonClick(0,mc.AS30[i],80,17,"Bodoni MT Black",8,BORDER_RAISED,mc.AS30[i],clrYellow,clrBlue,clrWhite,ANCHOR_CENTER,CORNER_RIGHT_UPPER,94,sydis+((i-tsatu)*22),true,"Change to "+mc.AS30[i]); //-- ChartRedraw(0); //-- return; //--- } //-end CreateSymbolPanel() //---------//
Nesse caso, a função OnChartEvent() chamará a função ChangeChartSymbol() quando um dos nomes dos símbolos for clicado.
if(id==CHARTEVENT_OBJECT_CLICK) { int lensymbol=StringLen(Symbol()); int lensparam=StringLen(sparam); //--- if Symbol button is click if(lensparam==lensymbol) { int sx=mc.ValidatePairs(sparam); ChangeChartSymbol(mc.AS30[sx],CCS); mc.PanelExtra=false; } //-- }
void ChangeChartSymbol(string c_symbol,ENUM_TIMEFRAMES cstf) { //--- //--- unpress the button ObjectSetInteger(0,c_symbol,OBJPROP_STATE,false); ObjectSetInteger(0,c_symbol,OBJPROP_ZORDER,0); ObjectsDeleteAll(0,0,OBJ_BUTTON); ObjectsDeleteAll(0,0,OBJ_LABEL); ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL); //-- ChartSetSymbolPeriod(0,c_symbol,cstf); //-- ChartRedraw(0); //-- return; //--- } //-end ChangeChartSymbol() //---------//
E, finalmente, clicar no botão R removerá o Consultor Especialista Multimoeda ZigZag_AO_MCEA do gráfico, para que os traders não precisem remover os especialistas manualmente.
if(id==CHARTEVENT_OBJECT_CLICK) { //-- //--- if "R" button is click if(sparam=="R") { Alert("-- "+mc.expname+" -- ",Symbol()," -- Expert Advisor will be Remove from the chart."); ExpertRemove(); //--- unpress the button ObjectSetInteger(0,"R",OBJPROP_STATE,false); ObjectSetInteger(0,"R",OBJPROP_ZORDER,0); if(!ChartSetSymbolPeriod(0,Symbol(),Period())) ChartSetSymbolPeriod(0,Symbol(),Period()); DeletePanelButton(); ChartRedraw(0); } //--- }
Strategy Tester
A vantagem do Strategy Tester do MetaTrader 5 é que ele suporta e permite testar estratégias que irão negociar em múltiplos símbolos ou testar negociação automática para todos os símbolos disponíveis e em todos os períodos de tempo disponíveis. Portanto, na plataforma do Strategy Tester do MetaTrader 5, testaremos o Consultor Especialista Multimoeda ZigZag_AO_MCEA.
No teste, colocamos o ZigZag_AO_MCEA no par XAUUSD e no período de tempo H4, com um período de tempo personalizado de 2023.10.01 a 2024.02.17.
E os resultados são como nas figuras a seguir.
Conclusão
A conclusão ao criar um Consultor Especialista Multimoeda com sinais do indicador ZigZag, que são filtrados com o Awesome Oscillator ou que filtram os sinais entre si para negociação forex usando MQL5, é a seguinte:
- Acontece que criar um Consultor Especialista multimoeda no MQL5 é muito simples e não muito diferente de criar um Consultor Especialista de uma única moeda, onde o Consultor Especialista multimoeda também pode ser usado como um Consultor Especialista de uma única moeda.
- Criar um Consultor Especialista Multimoeda aumentará a eficiência e a eficácia dos traders, eliminando a necessidade de abrir muitos símbolos de gráfico para negociação.
- Aplicar a estratégia de negociação certa aumentará a probabilidade de lucro em comparação com o uso de um Consultor Especialista de uma única moeda. Isso ocorre porque as perdas em um par serão cobertas pelos lucros em outros pares.
- Este Consultor Especialista Multimoeda ZigZag_AO_MCEA é apenas um exemplo para aprendizado e geração de ideias. Os resultados dos testes no Strategy Tester ainda não são bons. Portanto, ao experimentar e testar em diferentes períodos de tempo ou diferentes cálculos de período de indicador, e diferentes sinais selecionados, é possível obter uma estratégia melhor e resultados mais lucrativos.
- Na minha opinião, essa estratégia ZigZag com indicadores AO deve ser mais pesquisada com diversos experimentos diferentes, começando pelo período de tempo, valor de diferenciação da entrada de parâmetros do indicador ZigZag, e talvez você possa adicionar outros sinais de algoritmo para o indicador ZigZag e indicador AO.
- Com base nos resultados dos meus experimentos no Strategy Tester, em períodos de tempo abaixo de H1, os resultados não são bons; apenas em períodos de tempo H1 e acima, os resultados são bons com poucas negociações abertas, em comparação com períodos de tempo pequenos com muitas negociações abertas, mas em perda.
Obrigado por ler.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/14329





- 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
Prezado Roberto Jacobs
Olá para você e para todos
Muito obrigado por seu excelente artigo.
Executei os códigos no testador de estratégias e em várias corretoras e, infelizmente, todas as vezes recebo o erro "limite da ordem atingido". Ficarei muito grato se puderem me ajudar a resolver esse problema.
Com todo o respeito e meus melhores votos
Prezado Roberto Jacobs
Olá para você e para todos
Muito obrigado por seu excelente artigo.
Executei os códigos no testador de estratégias e em várias corretoras e, infelizmente, todas as vezes recebo o erro "limite da ordem atingido". Ficarei muito grato se puderem me ajudar a resolver esse problema.
Com todo o respeito e meus melhores votos
Pergunte ao seu corretor sobre o AccountInfoInteger(ACCOUNT_LIMIT_ORDERS) de sua conta ou se sua conta está limitada no momento.