Criando um Expert Advisor simples multimoeda usando MQL5 (Parte 1): Sinais baseados no ADX em combinação com o Parabolic SAR
Introdução
Neste artigo, por EA multimoeda, entendemos um Expert Advisor ou robô de negociação capaz de negociar (abrir/fechar ordens, gerenciar ordens, etc.) mais de um par de símbolos a partir de um único gráfico.
Atualmente, há uma grande necessidade e interesse por sistemas de automação de negociação e robôs de negociação multimoeda, mas observamos que a implementação de programas de sistema multimoeda em robôs de negociação MQL5 ainda não se tornou amplamente difundida ou pode ainda ser mantida em segredo por muitos programadores.
Assim, o objetivo é atender às necessidades fundamentais dos traders que precisam de robôs de negociação eficazes e práticos. Com base nos pontos fortes e capacidades do MQL5, podemos criar um simples EA multimoeda que, neste artigo, utiliza o Movimento Direcional Médio em combinação com o indicador Parabolic SAR.
Características
1. Pares de negociação.
O EA negociará nos 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).
Totalizando 30 pares.
Todos esses pares são comumente usados por corretoras. Portanto, este EA multimoeda não funcionará com corretoras cujos nomes de símbolos ou pares tenham prefixos ou sufixos.
2. Sinais.
O EA multimoeda usará 2 sinais de indicador: 1. O indicador de Movimento Direcional Médio (ADX) com período de 7 como sinal principal e 2. o indicador Parabolic SAR como confirmação de sinal.
Os dois principais indicadores utilizarão o mesmo timeframe, especificado na propriedade do EA. Além de determinar a força ou fraqueza da tendência, o indicador Parabolic SAR também é usado com timeframes M15 e M5.
Fórmula da estratégia de estado dos sinais: iADX
UP = (+DI[2] <= -DI[2]) && (+DI[1] > -DI[1]+difference) && (+DI[0] > +DI[1]) && ((+DI[0]/-DI[0]) > (+DI[1]/-DI[1]))
DOWN = (+DI[2] >= -DI[2]) && (+DI[1] < -DI[1]-difference) && (+DI[0] < +DI[1]) && ((+DI[0]/-DI[0]) < (+DI[1]/-DI[1]))
onde diferença = 0.34:
(+DI[1] > -DI[1]+0.34) = sinal de compra verdadeiro;
(+DI[1] < -DI[1]-0.34) = sinal de venda verdadeiro;
Porcentagem da barra atual PLUSDI_LINE, dividida pela barra atual MINUSDI_LINE.
em comparação com
Porcentagem da barra anterior PLUSDI_LINE, dividida pela barra anterior MINUSDI_LINE.
(+DI[0]/-DI[0]) = V0 = (barra atual PLUSDI_LINE / barra atual MINUSDI_LINE x 100) - 100;
(+DI[1]/-DI[1]) = V1 = (barra anterior PLUSDI_LINE / barra anterior MINUSDI_LINE x 100) - 100;
Então:
SE V0 > V1 = valor percentual da condição ADX = Aumento
SE V0 < V1 = valor percentual da condição ADX = Queda
Estratégia de estado dos sinais Parabolic SAR: Parabolic Stop And Reverse System (iSAR) - sistema parabólico de parada e reversão
iSAR UP = PRICE_LOW[0] > iSAR[0]
iSAR DOWN = PRICE_HIGH[0] < iSAR[0]
Na Figura 1 é mostrado o sinal iADX em combinação com o iSAR.
3. Gestão de trades e ordens
A gestão de negociação neste EA multimoeda tem várias opções:
1. Ordens stop-loss
- Opções: Use Order Stop Loss (Yes) ou (No) - usar ordem 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), surge novamente a 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.
Ao escolher Use Order Stop Loss (No), o EA verificará a execução das condições do sinal. Se elas forem cumpridas,
a ordem é mantida. Se o sinal enfraquecer, a ordem deve ser fechada para preservar lucros
ou se o sinal indicar uma mudança de direção, e a ordem deve ser fechada com perda.
2. Ordens 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.
Ao escolher Use Order Take Profit (Yes), surge novamente a 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 trailing stop-loss/take-profit: sim ou não
Na opção Use Trailing SL/TP (No), o EA não usará trailing stop e trailing take-profit.
Ao escolher Use Trailing SL/TP (Yes), surge novamente a opção: Use Automatic Trailing (Yes) ou (No) - usar trailing automático: sim ou não
Ao escolher Use Automatic Trailing (Yes), o trailing stop é executado pelo EA usando o valor do Parabolic SAR.
Ao escolher Use Automatic Trailing (No), o trailing stop é executado pelo EA usando o valor do parâmetro de entrada.
Nota: O EA realiza o trailing do take-profit simultaneamente com o trailing stop.
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 definir 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 precisará apenas pressionar o botão "Set SL / TP All Orders" para
modificar 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 (fechar todas as ordens lucrativas)
5. Gestão de ordens e gráficos de símbolos.
Uma função muito útil para EAs multimoedas, que negociam 30 pares a partir de um único gráfico, será ter um painel unificado de botões, permitindo que os traders mudem gráficos ou símbolos com um único clique do mouse.
Realizando o planejamento 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 YN usada para opções (Yes) ou (No) no parâmetro do EA.
enum YN { No, Yes }; //--
Enumeração para uso do tamanho do lote na gestão de capital
enum mmt { FixedLot, // Fixed Lot Size DynamLot // Dynamic Lot Size }; //--
Enumeração de timeframes para cálculo do sinal do EA
enum TFX { TFH1, // PERIOD_H1 TFH2, // PERIOD_H2 TFH3, // PERIOD_H3 TFH4, // PERIOD_H4 TFH6, // PERIOD_H6 TFH8, // PERIOD_H8 TFH12, // PERIOD_H12 TFD1 // PERIOD_D1 }; //--
Parâmetros de entrada do EA
//--- input group "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter input TFX TimeFrames = TFH4; // Select Expert TimeFrame, default PERIOD_H4 input int ADXPeriod = 7; // Input ADX Period 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 //--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 = No; // Use Order Take Profit (Yes) or (No) input YN autotp = Yes; // Use Automatic Calculation Take Profit (Yes) or (No) input double TPval = 50; // If Not Use Automatic TP - Input TP value in Pips input YN TrailingSLTP = Yes; // Use Trailing SL/TP (Yes) or (No) input YN autotrl = No; // 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 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 = 202307; // Expert ID (Magic Number) //---
Para declarar todas as variáveis, objetos e funções necessárias neste EA multimoeda, criaremos uma classe para especificar a construção e as configurações de trabalho do EA.
//+------------------------------------------------------------------+ //| 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; int posCur1, posCur2; //-- double LotPS, difDi; double slv, tpv, pip, xpip; double floatprofit, fixclprofit; double ADXDIp[]; double ADXDIm[]; //-- string pairs, hariini, daytrade, trade_mode; //-- double OPEN[], HIGH[], LOW[], CLOSE[]; datetime TIME[]; datetime closetime; //-- //------------ //------------ int iADXCross(const string symbol); int iADXpct(const string symbol,const int index); int PARSAR05(const string symbol); int PARSAR15(const string symbol); int PARSAROp(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: //--- //-- ADXPSAR_MCEA Config -- string DIRI[], AS30[]; string expname; int handADX[]; int hParOp[], hPar15[], hPar05[]; int ALO, dgts, arrsymbx; int sall, arper; ulong slip; ENUM_TIMEFRAMES TFt, TFT15, TFT05; //-- double SARstep, SARmaxi; double profitb[], profits[]; //-- 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) //------------ MCEA(void); ~MCEA(void); //------------ //-- virtual void ADXPSAR_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 GetOpenPosition(const string symbol); int DirectionMove(const string symbol); int GetCloseInWeakSignal(const string symbol,int exis); int CheckToCloseInWeakSignal(const string symbol,int exis); int ThisTime(const int reqmode); //-- string getUninitReasonText(int reasonCode); //-- //------------ //--- }; //-end class MCEA //---------//
A primeira e principal função no funcionamento do EA multimoeda, chamada a partir de OnInit(), é ADXPSAR_MCEA_Config().
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(void) { //--- mc.ADXPSAR_MCEA_Config(); //-- return(INIT_SUCCEEDED); //--- } //-end OnInit() //---------//
Na função ADXPSAR_MCEA_Config(), são configurados todos os símbolos utilizados, todos os handles dos indicadores utilizados e algumas funções importantes do arquivo de cabeçalho include.
//+------------------------------------------------------------------+ //| Expert Configuration | //+------------------------------------------------------------------+ void MCEA::ADXPSAR_MCEA_Config(void) { //--- //-- Here we will register all the symbols or pairs that will be used on the Multi-Currency Expert Advisor //-- 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 //-- sall=ArraySize(All30); ArrayResize(AS30,sall,sall); //-- These AS30[] arrays will be used in the symbol list panel and for the buttons to change symbols and charts ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY); //-- arrsymbx=sall; ArraySymbolResize(); ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY); //-- The "DIRI[]" array containing the symbol or pair name will be used //-- in all trading activities of the multi-currency expert //-- //-- This function is for Select all symbol in the Market Watch window for(int x=0; x<arrsymbx; x++) { SymbolSelect(DIRI[x],true); } pairs="Multi Currency 30 Pairs"; //--- //-- Here we will provide a Period Timeframe value which will be used for signal calculations according //-- to the Timeframe option on the expert input property. ENUM_TIMEFRAMES TFs[]= {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(x==TimeFrames) { TFt=TFs[x]; break; } } //-- //-- Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { handADX[x]=iADX(DIRI[x],TFt,ADXPeriod); //-- Handle for the iADX indicator according to the selected Timeframe hParOp[x]=iSAR(DIRI[x],TFt,SARstep,SARmaxi); //-- Handle for the iSAR indicator according to the selected Timeframe hPar15[x]=iSAR(DIRI[x],TFT15,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M15 Timeframe hPar05[x]=iSAR(DIRI[x],TFT05,SARstep,SARmaxi); //-- Handle for the iSAR indicator for M5 Timeframe } //-- //-- Since this expert advisor is a multi-currency expert, we must check the maximum number //-- of account limit orders allowed by the broker. //-- This needs to be checked, so that when the expert opens an order there will be //-- no return codes of the trade server error 10040 = TRADE_RETCODE_LIMIT_POSITIONS ALO=(int)mc_account.LimitOrders()>arrsymbx ? arrsymbx : (int)mc_account.LimitOrders(); //-- //-- The LotPS variable will later be used for the proportional distribution of Lot sizes for each symbol LotPS=(double)ALO; //-- mc_trade.SetExpertMagicNumber(magicEA); //-- Set Magic Number as expert ID mc_trade.SetDeviationInPoints(slip); //-- Set expert deviation with slip variable value mc_trade.SetMarginMode(); //-- Set the Margin Mode expert to the value of Account Margin Mode //-- return; //--- } //-end ADXPSAR_MCEA_Config() //---------//
2. Função Expert tick
Na função Expert tick (OnTick()), chamaremos uma das principais funções do EA multimoeda, a saber, a função ExpertActionTrade().
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(void) { //--- mc.ExpertActionTrade(); //-- return; //--- } //-end OnTick() //---------//
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.
A sequência de trabalho é indicada abaixo.
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 //-- //-- The functions below will be displayed on the expert chart according to //-- the Select Display Trading Info on Chart (Yes) or (No) option on expert property. //-- if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart //-- //-- if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart //--- //-- Because the current prices of a specified symbol (SymbolInfoTick) will occur differently //-- for each symbol, we reduce the tick update frequency to only every 5 seconds. //-- So, looping to check the signal for all trading activity of all symbols will only be done every 5 seconds. //-- int mcsec=mc.ThisTime(mc.sec); //-- With the function ThisTime(mc.sec), we will retrieve the current seconds value to mcsec variable. //-- //-- MathMod is a formula that gives the (modulus) real remainder after the division of two numbers. //-- By dividing the value of seconds with the value of 5.0, if the result is 0, it means that 5 seconds //-- have been reached from the previous psec variable seconds value. //-- if(fmod((double)mcsec,5.0)==0) mc.ccur=mcsec; //-- if(mc.ccur!=mc.psec) //-- So, if the seconds value in the ccur variable is not the same as the psec variable value { //-- (then the psec variable value already 5 seconds before) string symbol; //-- Here we start with the rotation of the name of all symbol or pairs to be traded //-- This is the basic framework for the automated trading workflow of this Multi-Currency Expert Advisor //-- Here we start with the rotation of the name of all symbol or pairs to be traded //-- This is the basic framework for the automated trading workflow of this Multi-Currency Expert Advisor for(int x=0; x<mc.arrsymbx && !IsStopped(); x++) { //-- if(mc.DIRI[x]==Symbol()) symbol=Symbol(); else symbol=mc.DIRI[x]; //-- After the symbol or pair name is set, we declare or notify the symbol to MarketWatch //-- and the trade server by calling the CurrentSymbolSet(symbol) function. mc.CurrentSymbolSet(symbol); //-- if(mc.TradingToday()) //-- The TradingToday() function checks whether today is allowed for trading { //-- If today is not allowed for trading, then the Expert will only perform management //-- orders such as trailing stops or trailing profits and closing orders. //-- according to the expert input property Day Trading On/Off group //-- If TradingToday() == Yes, then the next process is to call the function ThisTime(mc.sec) //-- 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 it turns out that the "Sell Order" has been opened, //-- and Close Trade By Opposite Signal according to the input property is (Yes), //-- then call the function CloseSellPositions(symbol) to close the sell order on that 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); //-- Open BUY order for this symbol else //-- OR //-- If Close Trade and Save profit due to weak signal according to the input property is (Yes) //-- then call the CloseAllProfit() function to close all orders //-- who are already in profit. //-- if(mc.xtto>=mc.ALO) { //-- If the total number of orders is greater than or equal //-- to the account limit orders allowed by the broker, then turn on alerts //-- 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); //-- Call the CheckOpenPMx(symbol) function //-- //-- If it turns out that the "Sell Order" has been opened, //-- and the condition of the Sell order has lost more than 1.02 USD, //-- and the "Buy Order" has not been opened, then call CloseSellPositions(symbol) //-- to close "Sell order" and open "Buy order". if(mc.xos[x]>0 && mc.profits[x]<-1.02 && mc.xob[x]==0) { mc.CloseSellPositions(symbol); mc.OpenBuy(symbol); } else //-- OR //-- If Close Trade and Save profit due to weak signal according to the input property is (Yes) //-- then call the CloseAllProfit() function to close all orders //-- who are already in profit. //-- if(SaveOnRev==Yes) mc.CloseAllProfit(); } } if(mc.OpOr[x]==mc.Sell) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Sell" (value=-1) { //-- //-- Call the CheckOpenPMx(symbol) function to check whether there are //-- already open "Buy" or "Sell" orders or no open orders. //-- mc.CheckOpenPMx(symbol); //-- //-- If it turns out that the "Buy Order" has been opened, //-- and Close Trade By Opposite Signal according to the input property is (Yes), //-- then call the function CloseBuyPositions(symbol) to close the buy order on that symbol. //-- if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol); //-- //-- The algorithm below means that the expert will only open 1 order per symbol, //-- provided that the total number of orders is still less than //-- the account limit orders allowed by the broker. //-- if(mc.xos[x]==0 && mc.xtto<mc.ALO) mc.OpenSell(symbol); //-- Open SELL order for this symbol else if(mc.xtto>=mc.ALO) { //-- If the total number of orders is greater than or equal //-- to the account limit orders allowed by the broker, then turn on alerts //-- 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); //-- Call the CheckOpenPMx(symbol) function //-- //-- If it turns out that the "Buy Order" has been opened, //-- and the condition of the Buy order has lost more than 1.02 USD, //-- and the "Sell Order" has not been opened, then call CloseBuyPositions(symbol) //-- to close "Buy order" and open "Sell order". if(mc.xob[x]>0 && mc.profitb[x]<-1.02 && mc.xos[x]==0) { mc.CloseBuyPositions(symbol); mc.OpenSell(symbol); } else //-- OR //-- If Close Trade and Save profit due to weak signal according to the input property is (Yes) //-- then call the CloseAllProfit() function to close all orders //-- who are already in profit. //-- if(SaveOnRev==Yes) mc.CloseAllProfit(); } } //-- mc.CheckOpenPMx(symbol); //-- The algorithm block below will check whether there is a weakening of the signal on Buy or Sell positions. //-- If it is true that there is a weakening signal and the iSAR indicator has reversed direction, //-- then close the losing order and immediately opened an order in the opposite direction. //-- if(mc.xob[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) {mc.CloseBuyPositions(symbol); mc.OpenSell(symbol);} if(mc.xos[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) {mc.CloseSellPositions(symbol); mc.OpenBuy(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(mc.xob[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) mc.CloseBuyPositions(symbol); if(mc.xos[x]>0 && mc.CheckToCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) mc.CloseSellPositions(symbol); } //-- 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) } } //-- //-- Check if there are orders that were closed in the last 6 seconds. //-- If there are give alerts. mc.CheckClose(symbol); } //-- replace the value of the psec variable with the value of the ccur variable. mc.psec=mc.ccur; } //-- return; //--- } //-end ExpertActionTrade() //---------//
3. Obtenção de sinais de negociação para abertura/fechamento de posições
Para obter o sinal do indicador, chamamos a função GetOpenPosition(symbol) para obter o sinal de abertura.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int MCEA::GetOpenPosition(const string symbol) // Signal Open Position { //--- int ret=0; int rise=1, down=-1; //-- int dirmov=DirectionMove(symbol); int pars15=PARSAR15(symbol); int parsOp=PARSAROp(symbol); int sigADX=iADXCross(symbol); //-- if(sigADX==rise && parsOp==rise && dirmov==rise && pars15==rise) ret=rise; if(sigADX==down && parsOp==down && dirmov==down && pars15==down) ret=down; //-- return(ret); //--- } //-end GetOpenPosition() //---------//
A função GetOpenPosition() chamará quatro funções de sinal e as salvará na variável OpOr[].
1. DirectionMove(symbol); //-- Função para verificar a presença de preço na barra de vela no timeframe do EA
2. PARSAR15(symbol); //-- Função para verificar o aumento ou queda do indicador iSAR no timeframe M15
3. PARSAROp(symbol); //-- Função para verificar o aumento ou queda do indicador iSAR no timeframe do EA
4. iADXCross(symbol); //-- Função para verificar o aumento ou queda do indicador iADX no timeframe do EA
Em seguida, na função iADXCross(symbol), a função iADXpct() será chamada para verificar o movimento percentual entre +DI e -DI, conforme descrito na seção "Sinais".
Para obter o estado do indicador, precisamos obter o número ordinal de cada handle do indicador necessário nas quatro funções PARSAR15(symbol), PARSAROP(symbol), iADXCross(symbol) e iADXpct().
Para obter o número ordinal do handle do indicador, chamamos a função PairsIdxArray(symbol) com
int x=PairsIdxArray(symbol);
O valor x representa os arrays do número ordinal do handle do indicador do símbolo em questão.
No exemplo da função PARSAR15(), podemos ver como chamar o handle do indicador iSAR para o símbolo em questão.
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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); //-- RefreshPrice(symbol,TFT15,br); double HIG0=iHigh(symbol,TFT15,0); double LOW0=iLow(symbol,TFT15,0); //-- if(PSAR[0]<LOW0) ret=rise; if(PSAR[0]>HIG0) ret=down; //-- return(ret); //--- } //-end PARSAR15() //---------//
4. Função ChartEvent
Para maior eficiência dos EAs multimoedas, criaremos vários botões para gerenciar ordens e mudar gráficos ou 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/TP 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); //-- Button state (depressed button) ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events 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); //-- Button state (depressed button) ObjectSetInteger(0,"Close All Order",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events 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); //-- Button state (depressed button) ObjectSetInteger(0,"Close All Profit",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events 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); //-- Button state (depressed button) ObjectSetInteger(0,"X",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events //-- DeleteButtonX(); mc.PanelExtra=false; DisplayManualButton(); } //--- if "M" button is click if(sparam=="M") { //--- unpress the button ObjectSetInteger(0,"M",OBJPROP_STATE,false); //-- Button state (depressed button) ObjectSetInteger(0,"M",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events mc.PanelExtra=true; CreateManualPanel(); } //--- if "C" button is click if(sparam=="C") { //--- unpress the button ObjectSetInteger(0,"C",OBJPROP_STATE,false); //-- Button state (depressed button) ObjectSetInteger(0,"C",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events 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); //-- Button state (depressed button) ObjectSetInteger(0,"R",OBJPROP_ZORDER,0); //-- Priority of a graphical object for receiving events if(!ChartSetSymbolPeriod(0,Symbol(),Period())) ChartSetSymbolPeriod(0,Symbol(),Period()); DeletePanelButton(); ChartRedraw(0); } //--- if Symbol name button is click if(lensparam==lensymbol) { int sx=mc.PairsIdxArray(sparam); ChangeChartSymbol(mc.AS30[sx],CCS); } //-- } //-- return; //--- } //-end OnChartEvent() //---------//
A interface do EA multimoeda é a seguinte.
Botões
Ao pressionar M, o painel de controle manual será exibido
Então, o trader pode gerenciar as 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 painel de botões com 30 pares será exibido
Ao clicar em qualquer um deles, o símbolo do gráfico será imediatamente substituído pelo indicado no botão pressionado.
Ao pressionar R, o EA multimoeda ADXPSAR_MCEA será removido do gráfico.
Testador de estratégias
Como sabemos, o testador permite realizar verificações históricas de estratégias que operam com vários instrumentos, além de testar a negociação automática em todos os símbolos disponíveis.
Testando estratégias de negociação Teste Multimoeda
Vamos testar o EA multimoeda ADXPSAR_MCEA no testador de estratégias do MetaTrader 5.
Considerações finais
- Criar um EA multimoeda em MQL5 não é muito diferente de desenvolver um de moeda única.
- A criação de um EA multimoeda aumentará a eficiência e a eficácia dos traders, já que eles não precisam abrir vários gráficos.
- Uma estratégia de negociação correta e sinais de indicadores de qualidade aumentam a probabilidade de obter lucro em comparação com o uso de um EA de moeda única. As perdas em um par podem ser compensadas por lucros em outros pares.
- O EA multimoeda ADXPSAR_MCEA é apenas um exemplo para estudo e desenvolvimento de ideias próprias. Os resultados dos testes ainda não são impressionantes. Com a implementação de uma estratégia melhor e cálculo mais preciso de sinais, o resultado, a meu ver, deve ser melhor do que o atual.
Espero que este 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/13008
- 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