//+------------------------------------------------------------------+
//| O EA mostra uma MessageBox com uma solicitação de trabalho extra |
//| quando alcançado o limite de negociações perdedoras consecutivas |
//| Aguarda um número especificado de barras e exibe uma MessageBox |
//| mostrando uma solicitação para continuar a trabalhar. |
//| Para verificar, abra e feche manualmente algumas posições |
//| com prejuízo, pois, para simplificar, o EA não |
//| controla "suas" posições com base no magic number. |
//+------------------------------------------------------------------+
//--- input parameters
input uint InpMaxLossDeals = 3; // Max Loss deals
input uint InpInactivityNumBars = 5; // Number of bars of advisor inactivity
//--- global variables
bool ExtFirstStart=true; // Flag de primeira inicialização
bool ExtFlag=true; // Flag de permissão de operação do EA
uint ExtNumLoss; // Número de negociações perdedoras consecutivas
datetime ExtTimeLastLoss; // Tempo da última operação de fechamento de posição perdedora
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- obtemos o número de negociações perdedoras consecutivas e o tempo da última operação de fechamento de posição
ExtNumLoss=GetNumLosingTradesInRow(ExtTimeLastLoss);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- determinamos quantas a barras se passaram desde a última posição perdedora fechada em sequência
int bars_remaining=iBarShift(Symbol(),PERIOD_CURRENT,ExtTimeLastLoss);
//--- se for a primeira inicialização
if(ExtFirstStart)
{
//--- se já passou o número especificado de a barras após a série de posições perdedoras, definimos a flag de operação do EA
if(bars_remaining>(int)InpInactivityNumBars)
ExtFlag=true;
ExtFirstStart=false;
}
//--- se a flag de operação do EA for removida
if(!ExtFlag)
{
Comment(StringFormat("The advisor is stopped for %d bars. Num Loss positions: %u, Time last loss: %s",
(InpInactivityNumBars-bars_remaining),ExtNumLoss,TimeToString(ExtTimeLastLoss,TIME_DATE|TIME_MINUTES|TIME_SECONDS)));
//--- se passou o número especificado de a barras após a série de posições perdedoras
if(bars_remaining>(int)InpInactivityNumBars)
{
//--- exibimos uma caixa de diálogo MessageBox com o texto especificado e o título da janela
//--- a janela de solicitação tem dois botões Yes/No e um ícone com um sinal de interrogação.
//--- o botão Yes é selecionado por padrão.
string mb_text="The specified number of bars of EA inactivity have passed.\n Continue its work?";
string mb_caption="Please note";
int mb_id=MessageBox(mb_text,mb_caption,MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON1);
//--- se o código de retorno do MessageBox for o botão Yes pressionado, definimos a flag de operação do EA
if(mb_id==IDYES)
{
ExtFlag=true;
return;
}
}
//--- se a flag de operação do EA for removida, saímos do OnTick()
return;
}
//--- a flag de operação do EA está definida, o EA funciona conforme o código abaixo prevê
Comment(StringFormat("The advisor is working. Num Loss positions: %u, Time last loss: %s, Elapsed Bars: %d",
ExtNumLoss,TimeToString(ExtTimeLastLoss,TIME_DATE|TIME_MINUTES|TIME_SECONDS),bars_remaining));
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//--- se o tipo de transação for a adição de uma negociação ao histórico
if(trans.type==TRADE_TRANSACTION_DEAL_ADD)
{
//--- Obtemos o ticket da negociação e selecionamos a negociação da lista pelo ticket
ulong deal_ticket=trans.deal;
if(HistoryDealSelect(deal_ticket))
{
//--- se for uma negociação para sair do mercado, obtemos o número de negociações perdedoras consecutivas e o tempo da última negociação
ENUM_DEAL_ENTRY entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket,DEAL_ENTRY);
if(entry==DEAL_ENTRY_OUT || entry==DEAL_ENTRY_INOUT || entry==DEAL_ENTRY_OUT_BY)
ExtNumLoss=GetNumLosingTradesInRow(ExtTimeLastLoss);
}
}
//--- se o número de negociações perdedoras consecutivas for maior que o valor especificado e a flag de operação do EA estiver definida
if(ExtNumLoss>=InpMaxLossDeals && ExtFlag)
{
//--- exibimos uma caixa de diálogo MessageBox com o texto especificado e o título da janela
//--- a janela de solicitação tem dois botões Yes/No e um ícone com um sinal de exclamação
//--- o botão No é selecionado por padrão
string mb_text="The number of losing trades has reached the specified maximum. The advisor is stopped.\n Continue its work?";
string mb_caption="Attention!";
int mb_id=MessageBox(mb_text,mb_caption,MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2);
//--- se o código de retorno do MessageBox for o botão No pressionado, removemos a flag de operação do EA
if(mb_id==IDNO)
ExtFlag=false;
}
}
//+------------------------------------------------------------------+
//| Retorna o número de negociações perdedoras consecutivas |
//| e o tempo da última operação de fechamento de posição perdedora |
//+------------------------------------------------------------------+
uint GetNumLosingTradesInRow(datetime &time_last_deal)
{
//--- selecionamos todo o histórico
if(!HistorySelect(0,TimeCurrent()))
return(0);
//--- no ciclo pela lista de negociações históricas, obtemos o ticket da próxima negociação
uint res=0;
uint total=HistoryDealsTotal();
for(int i=(int)total-1; i>=0; i--)
{
ulong deal_ticket=HistoryDealGetTicket(i);
if(deal_ticket>0)
{
//--- se a negociação não for de saída de posição, passamos para a próxima
ENUM_DEAL_ENTRY entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket,DEAL_ENTRY);
if(entry!=DEAL_ENTRY_OUT && entry!=DEAL_ENTRY_OUT_BY && entry!=DEAL_ENTRY_INOUT)
continue;
//--- se o resultado do fechamento da posição tiver lucro positivo, interrompemos o ciclo
if(!IsClosePositionWithLoss(deal_ticket))
break;
//--- incrementamos o contador de negociações consecutivas com prejuízo
res++;
//--- registramos na variável o tempo máximo da negociação (procuramos a última)
datetime deal_time=(datetime)HistoryDealGetInteger(deal_ticket,DEAL_TIME);
if(deal_time>time_last_deal)
time_last_deal=deal_time;
}
}
//--- Retornamos o número de perdas consecutivas
return(res);
}
//+------------------------------------------------------------------+
//| Retorna a flag de fechamento da posição com perda |
//+------------------------------------------------------------------+
bool IsClosePositionWithLoss(const ulong deal_ticket)
{
//--- obtemos a partir da negociação os valores das propriedades que afetam o lucro
double profit=HistoryDealGetDouble(deal_ticket,DEAL_PROFIT);
double comission=HistoryDealGetDouble(deal_ticket,DEAL_COMMISSION);
double swap=HistoryDealGetDouble(deal_ticket,DEAL_SWAP);
double fee=HistoryDealGetDouble(deal_ticket,DEAL_FEE);
//--- retornamos a flag de que o valor total das propriedades obtidas é negativo
return(profit+comission+swap+fee<0);
}
|