Criação de um Expert Advisor simples em várias moedas usando MQL5 (Parte 4): Média móvel triangular — Sinais do indicador
Introdução
Neste artigo, por EA multimoeda, entendemos um robô investidor, ou um robô de negociação, que pode negociar (abrir/fechar ordens, gerenciar ordens, por exemplo, do tipo trailing stop-loss e trailing profit) mais de um par de moedas em um gráfico. Neste artigo, o robô investidor negociará 30 pares.
Desta vez, usaremos apenas um indicador, em particular a média móvel triangular em um ou mais timeframes, ou escalas de tempo.A média móvel triangular é um indicador personalizado para MetaTrader 5, criado por Mladen Rakic. Recebi permissão do autor para usar esse indicador como sinal dentro de meu robô investidor multimoeda TriangularMA_MTF_MCEA.
Agradeço a Mladen Rakic pela oportunidade de usar seu trabalho.
Bem, afinal o objetivo é atender às necessidades básicas dos traders que precisam de robôs de negociação eficazes e práticos. E é graças aos pontos fortes e as capacidades do MQL5 que podemos criar um robô investidor multimoeda simples que, neste artigo, irá utilizar sinais da média móvel triangular.
Nota: O robô investidor multimoeda TriangularMA_MTF_MCEA foi criado a pedido dos traders.
Características
1. Pares de negociação.
O robô investidor negociará com os seguintes pares:
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 pares
Mais 2 pares de metais: XAUUSD (ouro) e XAGUSD (prata).
Total de 30 pares.
No artigo anterior usamos uma função automática para detectar nomes de pares com prefixos e/ou sufixos.
Neste artigo, simplificamos a tarefa adicionando propriedades de entrada especiais para o prefixo e o sufixo do nome do par.
Então, por meio de uma função simples, processamos os nomes dos pares com prefixos e/ou sufixos em combinação com os 30 nomes de pares registrados, de modo que, se um robô investidor com tais nomes especiais para seus símbolos for usado no MetaTrader 5, tudo funcionará sem problemas.
A desvantagem da função de detecção de nomes de símbolos que têm prefixos e sufixos é que ela funciona apenas com pares ou nomes de símbolos para forex e metais no MetaTrader 5, mas não funciona com símbolos especiais e índices.
Além disso, outra desvantagem desse método é a necessidade de evitar erros de digitação (é necessário inserir levando em consideração o caso) no nome do prefixo e/ou sufixo do par.
Como no artigo anterior, também adicionamos 10 opções para os pares negociados neste robô investidor.
Um dos 10 pares de opções que serão negociados é o Trader Wishes Pairs, em cujo caso os pares negociados devem ser inseridos manualmente pelo operador nas propriedades do EA. Lembre-se de que o nome do par inserido já deve estar na lista de 30 pares.
Como no artigo anterior, nesta versão do robô investidor também adicionamos a opção de sessão de negociação (fuso horário), portanto os pares negociados correspondem ao horário da sessão de negociação.
2. Indicador de sinais.
Na descrição da média móvel triangular, o autor escreve:
"Uso:
Pode-se utilizar a mudança de cor como sinal".
As cores padrão do indicador de média móvel triangular são:
- 0-DarkGray = sinal desconhecido
- 1-DeepPink = sinal de venda
- 2-MediumSeaGreen = sinal de compra.
Nesta versão do robô investidor, criamos duas opções de uso de timeframes ao calcular o sinal da média móvel triangular.
1. Cálculo de sinais baseado em multi-timeframe.
No sistema de cálculo com vários timeframes, os traders devem escolher na lista a série de timeframes desejados.
A série de timeframes escolhida é fornecida na faixa de M5 a D1 (11 timeframes).
Os traders podem escolher a série de timeframes: início (por exemplo, M15) e fim (por exemplo, H4).
Assim, o robô investidor calculará o sinal da média móvel triangular começando no timeframe M15 e terminando no H4.
Cálculos da média móvel triangular em vários timeframes:
- Sinal de compra, se em todos os timeframes selecionados o indicador estiver na cor MediumSeaGreen, e
- Sinal de venda, se em todos os timeframes selecionados o indicador estiver na cor DeepPink.
2. Cálculo de sinais baseado em um único timeframe.
No sistema de cálculo de sinais em um único timeframe, os traders devem escolher um dos 11 timeframes, começando em M5 e terminando em D1.
Assim, o robô investidor calculará o sinal do indicador de média móvel triangular no timeframe selecionado.
Enquanto isso, o cálculo do sinal da média móvel triangular em um único timeframe será assim:
- Sinal de compra, se as 2 barras anteriores forem DeepPink, a barra anterior for MediumSeaGreen e a barra atual for MediumSeaGreen.
- Sinal de venda, se as 2 barras anteriores forem MediumSeaGreen, a barra anterior for DeepPink e a barra atual for DeepPink.
A média móvel triangular para sinais de compra e venda pode ser vista nas figuras 1 e 2.
3. Gerenciamento de trading e ordens.
A gestão de operações neste EA multimoeda tem várias opções:
1. Ordens stop-loss
- Opções: Use Order Stop Loss (Yes) ou (No) - usar ordem de stop-loss: sim ou não
Ao escolher Use Order Stop Loss (No), todas as ordens serão abertas sem stop-loss.
Ao escolher Use Order Stop Loss (Yes):
Novamente é dada uma opção: Use Automatic Calculation Stop Loss (Yes) ou (No) - usar cálculo automático de stop-loss: sim ou não
Ao escolher Automatic Calculation Stop Loss (Yes), o stop-loss é calculado pelo EA.
Ao escolher Automatic Calculation Stop Loss (No), o trader precisa inserir o valor do stop-loss em pips.
Quando Use Order Stop Loss (No):
Então, o EA verificará o estado do sinal para cada ordem aberta e avaliará
o potencial de lucro. Se o sinal enfraquecer, significa que a ordem deve ser fechada para preservar
o lucro. Ou se o sinal indicar uma mudança de direção, a ordem deve ser fechada com prejuízo.
Nota:
Antes de fechar uma operação devido a um sinal fraco, é solicitada a confirmação do usuário.
2. Ordens de take-profit
- Opções: Use Order Take Profit (Yes) ou (No) - usar take-profit da ordem: sim ou não
Ao escolher Use Order Take Profit (Não), todas as ordens serão abertas sem take-profit.
Quando Use Order Take Profit (Yes):
Novamente é dada uma opção: Use Automatic Calculation Order Take Profit (Yes) ou (No) - usar take-profit calculado automaticamente: sim ou não
Ao escolher Automatic Calculation Order Take Profit (Yes), o take-profit é calculado pelo EA.
Ao escolher Automatic Calculation Order Take Profit (No), o trader precisa inserir o valor do take-profit em pips.
3. Trailing stop e trailing take-profit
- Opções: Use Trailing SL/TP (Yes) ou (No) - usar stop-loss/take-profit de trailing: sim ou não
Com a opção Use Trailing SL/TP (No), o EA não usará stop-loss e take-profit de trailing.
Quando Use Trailing SL/TP (Yes):
Novamente é dada uma opção: Use Automatic Trailing (Yes) ou (No) - usar trailing automático: sim ou não
Com Use Automatic Trailing (Yes), o trailing stop é executado pelo EA usando
um buffer zero da média móvel triangular (dados do indicador) no timeframe automaticamente selecionado pelo EA, e simultaneamente
capturando lucros móveis com base no valor da variável TPmin (valor mínimo de lucro móvel).
Com Use Automatic Trailing (No), o trailing-stop é executado pelo EA usando o valor do parâmetro de entrada.
Nota: O EA executa o trailing do take-profit simultaneamente com o trailing-stop.
Função Trailing Stop Price:
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 0: { 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 1: { double TriMAID[]; //-- ArrayResize(TriMAID,br,br); ArraySetAsSeries(TriMAID,true); CopyBuffer(hTriMAt[x],0,0,br,TriMAID); // Copy buffer 0 from the hTriMAt indicator handle //-- RefreshTick(xsymb); if(ptype==POSITION_TYPE_BUY && (mc_symbol.Bid()>mc_symbol.NormalizePrice(TriMAID[0]+TSval*pip))) pval=TriMAID[0]; if(ptype==POSITION_TYPE_SELL && (mc_symbol.Ask()<mc_symbol.NormalizePrice(TriMAID[0]-TSval*pip))) pval=TriMAID[0]; break; } } //-- return(pval); //--- } //-end TSPrice() //---------//
Alteração da função SL/TP:
bool MCEA::ModifySLTP(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_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*pip); double modbuysl=vtrsb; double modbuytp=mc_symbol.NormalizePrice(price+TPmin*pip); bool modbuy = (price>modminsl && modbuysl>modstart && (pos_stop==0.0||modbuysl>pos_stop)); //-- if(modbuy && netp>0.05) { modist=mc_trade.PositionModify(symbol,modbuysl,modbuytp); } } 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_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*pip); double modselsl=vtrss; double modseltp=mc_symbol.NormalizePrice(price-TPmin*pip); bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==0.0||modselsl<pos_stop)); //-- if(modsel && netp>0.05) { modist=mc_trade.PositionModify(symbol,modselsl,modseltp); } } } } //-- return(modist); //--- } //-end ModifySLTP() //---------//
4. Gestão manual de ordens.
Para aumentar a eficiência, serão adicionados vários botões.
1. Set SL / TP All Orders (definir stop-loss/take-profit para todas as ordens)
Se o trader configurar Use Order Stop Loss (No) e/ou Use Order Take Profit (No),
mas depois quiser usar stop-loss ou take-profit para todas as ordens, ele só precisa pressionar o botão
Set SL / TP All Orders para alterar todas as ordens e aplicar o stop-loss e/ou take-profit.
2. Close All Orders
Fechar todas as ordens.3. Close All Orders Profit
Se o trader desejar fechar todas as ordens que já são lucrativas, basta um clique no botão
Close All Orders Profit para fechar todas as ordens abertas lucrativas.
5. Management Orders and Chart Symbols.
Uma função muito útil para EAs multimoeda, que operam 30 pares de um único gráfico, será ter um painel unificado de botões para que os traders possam mudar gráficos ou símbolos com um clique do mouse.
Implementação em um programa MQL5
1. Cabeçalho do programa e parâmetros de entrada
Inclusão do arquivo de cabeçalho em 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 uso do 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 seleção de horas
//-- 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 seleção de atas
//-- 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 escolha de pares de opções para negociação
//-- 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 }; //--
Enumeração YN usada para opções (Yes) ou (No) no parâmetro do robô investidor
//-- enum YN { No, Yes }; //--
A enumeração para usar o tamanho do lote na gestão de capital
//-- enum mmt { FixedLot, // Fixed Lot Size DynamLot // Dynamic Lot Size }; //--
Enumeração para escolha de timeframe, que será usado em um ou vários timeframes
//-- enum TFMTF { TFM5, // PERIOD_M5 TFM15, // PERIOD_M15 TFM30, // PERIOD_M30 TFH1, // PERIOD_H1 TFH2, // PERIOD_H2 TFH3, // PERIOD_H3 TFH4, // PERIOD_H4 TFH6, // PERIOD_H6 TFH8, // PERIOD_H8 TFH12, // PERIOD_H12 TFD1 // PERIOD_D1 }; //--
Enumeração para uso de um ou vários timeframes
//-- enum SMTF { MTF, // Use Multi-Timeframe STF // Use Single-Timeframe }; //--
Parâmetros de entrada do EA
//--- input group "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter input SMTF tfinuse = MTF; // Select Calculation in Multi or Single Timeframe input TFMTF singletf = TFH1; // Select Single Calculation TimeFrame, default PERIOD_H1 input TFMTF tfstart = TFM15; // Select Multi Timeframe calculation start input TFMTF tfclose = TFH4; // Select Multi Timeframe calculation end input int Trmaperiod = 14; // Input Triangular MA Indicator period, default 14 input ENUM_APPLIED_PRICE Trprice = PRICE_CLOSE; // Select Triangular MA Applied Price, default Price Close //--- input group "=== Select Pairs to Trade ==="; // Selected Pairs to trading 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 string sym_prefix = ""; // Input the symbol prefix in case sensitive (if any) input string sym_suffix = ""; // Input the symbol suffix in case sensitive (if any) //-- 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; // 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 = 10; // If Not Use Automatic TP - Input TP value in Pips input YN TrailingSLTP = Yes; // Use Trailing SL/TP (Yes) or (No) input YN autotrl = Yes; // Use Automatic Trailing (Yes) or (No) input double TSval = 5; // If Not Use Automatic Trailing Input Trailing value in Pips input double TSmin = 5; // Minimum Pips to start Trailing Stop input double TPmin = 25; // 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) //--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 = 2023111; // Expert ID (Magic Number) //---
No grupo de propriedades de entrada Global Strategy EA Parameter do robô investidor, os traders devem escolher se usam o cálculo de sinais em um único timeframe ou em vários.
Ao escolher um único timeframe (STF), ele deve ser especificado.
No parâmetro de entrada do robô investidor, selecione Select Single Calculation timeframe (escolher um timeframe para cálculo), o valor padrão é PERIOD_H1.
Ao escolher vários timeframes (MTF), eles devem ser especificados.
No parâmetro de entrada do robô investidor, selecione Select Multi Timeframe calculation start (início do cálculo em vários timeframes) e Select Multi Timeframe calculation end (fim do cálculo em vários timeframes).
Nas linhas 478-518, a função TriangularMA_MTF_MCEA_Config() explica como trabalhar com um e vários timeframes.
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(singletf==x) TFt=TFs[x]; // TF for single-timeframe if(tfstart==x) arstr=x; // multi-timeframe start calculation timeframe if(tfclose==x) arend=x; // multi-timeframe end calculation timeframe } //-- if(arstr>=arend) { Alert("Error selecting Start and End Timeframe, Start Timeframe must be smaller than End Timeframe"); Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart."); ExpertRemove(); } //-- switch(tfinuse) { case MTF: { TFArrays=arend-arstr+1; ArrayResize(TFTri,TFArrays,TFArrays); ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY); tfcinws=arstr+1; tftrlst=(int)TFArrays/2; TFts=TFs[tftrlst+arstr-1]; // TF for Trailing Stop TFCWS=TFs[tfcinws]; // TF for Close Order in weak signal break; } case STF: { TFArrays=arTFs; ArrayResize(TFTri,TFArrays,TFArrays); ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY); tfcinws=TFIndexArray(TFt)-2 <=0 ? 1 : TFIndexArray(TFt)-2; TFts=TFt; // TF for Trailing Stop TFCWS=TFs[tfcinws]; // TF for Close Order in weak signal break; } }
A variável ENUM_TIMEFRAMES TFs[] deve ser atribuída à opção enum TFMTF
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}; //-- enum TFMTF { TFM5, // PERIOD_M5 TFM15, // PERIOD_M15 TFM30, // PERIOD_M30 TFH1, // PERIOD_H1 TFH2, // PERIOD_H2 TFH3, // PERIOD_H3 TFH4, // PERIOD_H4 TFH6, // PERIOD_H6 TFH8, // PERIOD_H8 TFH12, // PERIOD_H12 TFD1 // PERIOD_D1 }; //--
Então, o trader deve definir o período do indicador Triangular MA. O período padrão é 14.
Além disso, é necessário especificar o preço de cálculo do Triangular MA. O preço padrão é PRICE_CLOSE.
No grupo de propriedades de entrada Select Pairs to Trade, é necessário escolher um par para negociar entre as 10 opções fornecidas. O valor padrão é All Forex 30 Pairs (todos os 30 pares Forex).
Para configurar o par negociado, vamos chamar a função HandlingSymbolArrays().
Usando a função HandlingSymbolArrays(), trataremos todos os pares 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); aretc=ArraySize(EURs); 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<aretc; 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 30 Pairs { ArrayResize(DIRI,sall,sall); arrsymbx=sall; ArraySymbolResize(); ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY); pairs="Multi Currency 30 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,aretc,aretc); 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(), chamamos a função SetSymbolNamePS().
Com isso, poderemos processar os nomes dos símbolos que têm prefixos e/ou sufixos.
void MCEA::SetSymbolNamePS(void) { //--- symbfix=false; int ptriml; int ptrimr; string insymbol=Symbol(); int sym_Lenpre=StringLen(prefix); int sym_Lensuf=StringLen(suffix); if(sym_Lenpre>0) { ptriml=StringTrimLeft(suffix); ptriml=StringTrimRight(suffix); } if(sym_Lensuf>0) { ptrimr=StringTrimLeft(suffix); ptrimr=StringTrimRight(suffix); } string sym_pre=prefix; string sym_suf=suffix; //-- pre=sym_pre; suf=sym_suf; inpre=StringLen(pre); insuf=StringLen(suf); posCur1=inpre; posCur2=posCur1+3; //-- return; //--- } //-end SetSymbolNamePS() //---------//
Nota:
O robô investidor verificará os pares.
Se o trader cometer um erro ao inserir o nome do par ou o nome do prefixo/sufixo
ou se a verificação do par falhar, o robô investidor emitirá um alerta e será removido do gráfico.
No grupo de propriedades de entrada Trade on Specific Time, o trader precisa escolher Trade on Specific Time Zone (Yes) ou (No)
- negociar em um fuso horário específico: sim ou não Quando Yes, é necessário escolher os parâmetros de enumeração:
- Negociação em sessão personalizada
- Negociação na sessão da Nova Zelândia
- Negociação na sessão de Sydney da Austrália
- Negociação na sessão asiática de Tóquio
- Negociação na sessão da Europa em Londres (sessão de Londres)
- Negociação na sessão de Nova York da América (sessão de Nova York)
Assim, o Expert Advisor só executará ações durante o tempo especificado.
Em outros casos, os horários de início e término da negociação são escolhidos pelo Expert Advisor.
Para declarar todas as variáveis, objetos e funções necessários neste EA multimoeda, criaremos uma classe para especificar a estrutura e as configurações operacionais do EA.
Em particular, as variáveis usadas na função para processar nomes de símbolos com prefixo e/ou sufixo, bem como cálculos de fusos horários, foram feitas na classe MCEA.
//+------------------------------------------------------------------+ //| 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 slv, tpv, pip, xpip; 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 TriaMASMTF(const string symbol,ENUM_TIMEFRAMES mtf); int GetTriaMASignalMTF(string symbol); int TriaMASignalSTF(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: //--- //-- TriangularMA_MTF_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 indiname; //-- int hTriMAt[]; int hTriMAs[]; int hTriMAm[]; int hTriMAb[][11]; int ALO, dgts, arrsar, arrsymbx; int sall, arusd, aretc, arspc, arper; ulong slip; //-- double profitb[], profits[]; //-- int Buy, Sell; int ccur, psec, xtto, TFArrays, 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, TFts, TFT05, TFCWS; ENUM_TIMEFRAMES TFTri[]; //-- bool PanelExtra; //------------ MCEA(void); ~MCEA(void); //------------ //-- virtual void TriangularMA_MTF_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 CloseBuyPositions(const string symbol); void CloseSellPositions(const string symbol); void CloseAllOrders(void); void CheckClose(const string symbx); void TodayOrders(void); void UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf); void RefreshPrice(const string symbx,ENUM_TIMEFRAMES xtf,int bars); //-- 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 ModifySLTP(const string symbx,int TS_type); bool CloseAllProfit(void); bool ManualCloseAllProfit(void); //-- int PairsIdxArray(const string symbol); int ValidatePairs(const string symbol); int TFIndexArray(ENUM_TIMEFRAMES TF); int GetOpenPosition(const string symbol); int GetSignalMidTF(const string symbol); int GetCloseInWeakSignal(const string symbol,int exis); //-- string getUninitReasonText(int reasonCode); //-- //------------ //--- }; //-end class MCEA //---------//
A função inicial e principal no funcionamento do robô investidor multimoeda, chamada de OnInit(), é a TriangularMA_MTF_MCEA_Config().
Na função TriangularMA_MTF_MCEA_Config(), todos os símbolos usados, todos os indicadores de handle aplicados e algumas funções importantes do arquivo de cabeçalho include são configurados.
void MCEA::TriangularMA_MTF_MCEA_Config(void) { //--- //-- HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded //-- int arstr=0, arend=0; TFT05=PERIOD_M5; 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(singletf==x) TFt=TFs[x]; // TF for single-timeframe if(tfstart==x) arstr=x; // multi-timeframe start calculation timeframe if(tfclose==x) arend=x; // multi-timeframe end calculation timeframe } //-- if(arstr>=arend) { Alert("Error selecting Start and End Timeframe, Start Timeframe must be smaller than End Timeframe"); Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart."); ExpertRemove(); } //-- switch(tfinuse) { case MTF: { TFArrays=arend-arstr+1; ArrayResize(TFTri,TFArrays,TFArrays); ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY); tfcinws=arstr+1; tftrlst=(int)TFArrays/2; TFts=TFs[tftrlst+arstr-1]; // TF for Trailing Stop TFCWS=TFs[tfcinws]; // TF for Close Order in weak signal break; } case STF: { TFArrays=arTFs; ArrayResize(TFTri,TFArrays,TFArrays); ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY); tfcinws=TFIndexArray(TFt)-2 <=0 ? 1 : TFIndexArray(TFt)-2; TFts=TFt; // TF for Trailing Stop TFCWS=TFs[tfcinws]; // TF for Close Order in weak signal break; } } //-- //-- Triangular MA Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { hTriMAs[x]=iCustom(DIRI[x],TFT05,indiname,Trmaperiod,Trprice); hTriMAm[x]=iCustom(DIRI[x],TFCWS,indiname,Trmaperiod,Trprice); hTriMAt[x]=iCustom(DIRI[x],TFts,indiname,Trmaperiod,Trprice); //-- for(int i=0; i<TFArrays; i++) { if(tfinuse==MTF) // MTF indicator handle { hTriMAb[x][i]=iCustom(DIRI[x],TFTri[i],indiname,Trmaperiod,Trprice); } if(tfinuse==STF) { if(TFs[i]==TFt) // Single-TF indicator handle { hTriMAb[x][i]=iCustom(DIRI[x],TFs[i],indiname,Trmaperiod,Trprice); break; } } } } //-- ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders(); //-- LotPS=(double)ALO; //-- mc_trade.SetExpertMagicNumber(magicEA); mc_trade.SetDeviationInPoints(slip); mc_trade.SetMarginMode(); Set_Time_Zone(); //-- return; //--- } //-end TriangularMA_MTF_MCEA_Config() //---------//
2. Função Expert tick
Na função Expert tick (OnTick()), chamaremos uma das funções principais do EA multimoeda, a saber, a função ExpertActionTrade().
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(void) { //--- mc.ExpertActionTrade(); //-- return; //--- } //-end OnTick() //---------//
A sequência do EA dentro dessa função.
A função ExpertActionTrade() executará todas as ações e gerenciará a negociação automática, incluindo a abertura/fechamento de ordens, trailing-stop, trailing take-profit, e outras ações 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++) { //-- if(mc.DIRI[x]==Symbol()) symbol=Symbol(); else symbol=mc.DIRI[x]; //-- 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 if(SaveOnRev==Yes) mc.CloseAllProfit(); } } 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 if(SaveOnRev==Yes) mc.CloseAllProfit(); } } } //-- 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]>0.02 && 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]>0.02 && 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(TrailingSLTP==Yes) //-- Use Trailing SL/TP (Yes) { if(autotrl==Yes) mc.ModifySLTP(symbol,1); //-- If Use Automatic Trailing (Yes) if(autotrl==No) mc.ModifySLTP(symbol,0); //-- Use Automatic Trailing (No) } } //-- mc.CheckClose(symbol); } //-- mc.psec=mc.ccur; } //-- return; //--- } //-end ExpertActionTrade() //---------//
Especificamente para os fusos horários de negociação, a função ExpertActionTrade() adicionou a chamada da função lógica Trade_session().
Quando Trade_session() for true, o EA funcionará até o encerramento e, quando for false, o EA só executará as tarefas Close Trade e Save Profit devido a sinal fraco (Yes) e Trailing stop (Yes).
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() //---------//
3. Obtenção de sinais de negociação para abrir posições
Para obter o sinal, 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 trimOp=GetTriaMASignalMTF(symbol); int getmid=GetSignalMidTF(symbol); if(trimOp==rise && getmid==rise) ret=rise; if(trimOp==down && getmid==down) ret=down; //-- return(ret); //--- } //-end GetOpenPosition() //---------//
A função GetOpenPosition() chamará duas funções que executam o cálculo dos sinais:
1. GetSignalMidTF(const string symbol); //-- Obtenção de sinais por posições de timeframe médio e movimento de preço
int MCEA::GetSignalMidTF(const string symbol) // Signal Indicator Position Close in profit { //--- int ret=0; int rise=1, down=-1; //-- int br=2; //-- double TriMACI[]; //-- ArrayResize(TriMACI,br,br); ArraySetAsSeries(TriMACI,true); int xx=PairsIdxArray(symbol); CopyBuffer(hTriMAm[xx],1,0,br,TriMACI); //#property indicator_color1 clrDarkGray,clrDeepPink,clrMediumSeaGreen // 0 1 2 //-- int dirmove=DirectionMove(symbol,TFCWS); //-- if(TriMACI[0]==2.0 && dirmove==rise) ret=rise; if(TriMACI[0]==1.0 && dirmove==down) ret=down; //-- return(ret); //--- } //-end GetSignalMidTF() //---------//
2. GetTriaMASignalMTF(const string symbol); //-- Cálculo da fórmula da média móvel triangular.
A função GetTriaMASignalMTF() chama a função TriaMASMTF(), que calcula o sinal da média móvel triangular de acordo com o timeframe solicitado.
int MCEA::GetTriaMASignalMTF(string symbol) { //--- int mv=0; int rise=1, down=-1; int tfloop=tfinuse==MTF ? TFArrays : 1; //-- int trimup=0, trimdw=0; //-- for(int x=0; x<tfloop; x++) { if(TriaMASMTF(symbol,TFTri[x])>0) trimup++; if(TriaMASMTF(symbol,TFTri[x])<0) trimdw++; } //-- if(trimup==tfloop) mv=rise; if(trimdw==tfloop) mv=down; //-- return(mv); //--- } //- end GetTriaMASignalMTF() //---------//
int MCEA::TriaMASMTF(const string symbol,const ENUM_TIMEFRAMES mtf) // formula Triangular MA on the requested Timeframe { //--- int ret=0; int rise=1, down=-1; int br=3; ENUM_TIMEFRAMES TFUse=tfinuse==MTF ? mtf : TFt; //-- double TriMACI[]; ArrayResize(TriMACI,br,br); ArraySetAsSeries(TriMACI,true); int xx=PairsIdxArray(symbol); int tx=TFIndexArray(TFUse); CopyBuffer(hTriMAb[xx][tx],1,0,br,TriMACI); //#property indicator_color1 clrDarkGray,clrDeepPink,clrMediumSeaGreen // 0 1 2 //Print("Symbol = "+symbol+" TF = "+EnumToString(mtf)+" TriMACI[0] = "+string(TriMACI[0])); //-- switch(tfinuse) { case MTF: { if(TriMACI[0]==2.0) ret=rise; if(TriMACI[0]==1.0) ret=down; //-- break; } case STF: { if(TriMACI[2]==1.0 && TriMACI[1]==2.0 && TriMACI[0]==2.0) ret=rise; if(TriMACI[2]==2.0 && TriMACI[1]==1.0 && TriMACI[0]==1.0) ret=down; //-- break; } } //-- return(ret); //--- } //-end TriaMASMTF() //---------//
Como você pode ver, usamos e chamamos duas funções dentro da função TriaMASMTF():
- 1. int xx= PairsIdxArray(symbol)
- 2. int tx=TFIndexArray(mtf).
A função PairsIdxArray() é usada para obter o nome do símbolo solicitado, e a função TFIndexArray() para obter a sequência do array do timeframe solicitado.
Então, é chamado o handle do indicador apropriado para obter o valor do buffer da média móvel triangular desse timeframe.
Como diz o autor do indicador:
"Uso:
Pode-se utilizar a mudança de cor como sinal".
Então, como aceitamos o sinal da média móvel triangular?
Na propriedade da média móvel triangular:
#property indicator_color1 clrDarkGray,clrDeepPink,clrMediumSeaGreen // 0 1 2
SetIndexBuffer(1,valc,INDICATOR_COLOR_INDEX);
valc[i] = (i>0) ?(val[i]>val[i-1]) ? 2 :(val[i]<val[i-1]) ? 1 : valc[i-1]: 0;
Sabemos que:
- 0-DarkGray = sinal desconhecido
- 1-DeepPink = sinal de venda
- 2-MediumSeaGreen = sinal de compra.
Assim, podemos pegar o valor do buffer 1 da média móvel triangular como um sinal usando a função CopyBuffer, como na função TriaMASMTF().
double TriMACI[]; ArrayResize(TriMACI,br,br); ArraySetAsSeries(TriMACI,true); int xx=PairsIdxArray(symbol); int tx=TFIndexArray(TFUse); CopyBuffer(hTriMAb[xx][tx],1,0,br,TriMACI); //#property indicator_color1 clrDarkGray,clrDeepPink,clrMediumSeaGreen // 0 1 2
4. Função ChartEvent
Para maior eficácia dos robôs investidores multimoeda, criaremos vários botões para gerenciar ordens, bem como
mudar gráficos e símbolos.
//+------------------------------------------------------------------+ //| 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() //---------//
Para alterar os símbolos do gráfico com um clique do mouse, ao pressionar em um dos nomes dos símbolos, o evento OnChartEvent() será chamado pela função ChangeChartSymbol().
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() //---------//
Como estamos adicionando uma sessão de negociação ou um fuso horário de negociação e parâmetros de pares negociados em um ou mais timeframes, precisamos adicionar novos dados na informação de negociação exibida no gráfico. Para isso, fizemos alterações na função TradeInfo().
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 tradetf=tfinuse==MTF ? EnumToString(Period()) : EnumToString(TFts); string eamode=tfinuse==MTF ? "Multi-Timeframe" : "Single-Timeframe"; 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 : "+ tradetf+ "\n :: Trade Mode : "+ eamode+ "\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() //---------//
Também adicionamos uma função para descrever o tempo de acordo com as condições do 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() //---------//
A interface do robô investidor multimoeda TriangularMA_MTF_MCEA é a seguinte.
Como você pode ver, sob o nome do EA TriangularMA_MTF_MCEA há os botões M, C e R
Ao pressionar M, o painel de controle manual será exibido
O operador pode então gerenciar as ordens conforme descrito na seção "Gerenciamento manual de ordens".
- 1. Set SL/TP All Orders (definir stop-loss/take-profit para todas as ordens)
- 2. Close All Orders (fechar todas as ordens)
- 3. Close All Profits (fechar todas as ordens lucrativas)
Ao pressionar C, um botão do painel com 30 nomes de símbolos ou pares é exibido, e os traders podem clicar em um dos nomes dos pares ou símbolos.
Ao pressionar qualquer um deles, o símbolo do gráfico será imediatamente substituído pelo indicado no botão pressionado.
Quando R é pressionado, o Expert Advisor TriangularMA_MTF_MCEA multimoeda é removido do gráfico, de modo que os traders não precisam desativar os EAs manualmente.
Testador de estratégias
Como é conhecido, o testador de estratégias do terminal MetaTrader 5 suporta e permite testar estratégias multissímbolos ou negociação automática para todos os símbolos disponíveis e em todos os timeframes disponíveis.
Vamos testar o EA multimoeda e multi-timeframe FXSAR_MTF_MCEA por meio do testador de estratégias do MetaTrader 5.
1. Teste do triangularMA_MTF_MCEA em vários timeframes.
2. Teste triangularMA_MTF_MCEA em um timeframe.
Considerações finais
Os resultados da criação de um robô multimoeda e multi-timeframe para trabalhar com um e várias escalas de tempo usando MQL5 podem ser concluídos da seguinte forma:
- Criar um EA multimoeda no MQL5 é pouco diferente de desenvolver um de uma só moeda. Porém, para Expert Advisors multimoedas com múltiplos timeframes, o processo é um pouco mais complexo do que para os Expert Advisors com um único timeframe.
- Criar um EA multimoeda aumenta a eficiência e eficácia dos traders, já que eles não precisarão abrir muitos gráficos.
- A estratégia de negociação correta aumenta a probabilidade de lucro em comparação com o uso de um Expert Advisor de moeda única. As perdas em um par serão compensadas pelos lucros em outros pares.
- O EA multimoeda FXSAR_MTF_MCEA é apenas um exemplo para estudo e desenvolvimento de ideias próprias.
- Os resultados do teste no testador de estratégias ainda são insatisfatórios. Com a implementação de uma estratégia melhor, com cálculos de sinal mais precisos e melhores timeframes, os resultados, na minha opinião, deveriam ser melhores do que os atuais.
- Os resultados do teste da TriangularMA_MTF_MCEA no testador de estratégias demonstram que os resultados em um timeframe são melhores do que em vários timeframes.
Nota:
Se você tiver uma ideia para criar um simples EA multimoeda baseado nos sinais padrão do indicador MQL5, compartilhe-a nos comentários.
Espero que o artigo e o EA multimoeda sejam úteis para os traders no estudo e desenvolvimento de ideias. Obrigado pela atenção!
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/13770
- 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