//+------------------------------------------------------------------+
//| L'EA affiche la MessageBox avec une demande supplémentaire |
//| après avoir atteint le nombre de transactions non rentables |
//| Attendre le nombre de barres spécifié et afficher MessageBox |
//| avec une demande pour continuer à travailler. |
//| Pour vérifier, nous devons ouvrir et fermer manuellement |
//| plusieurs positions avec une perte, puisque l'EA ne contrôle pas |
//| ses propres "positions" par le magic number. |
//+------------------------------------------------------------------+
//--- paramètres d'entrée
input uint InpMaxLossDeals = 3; // Nombre maximum de transactions perdantes
input uint InpInactivityNumBars = 5; // Nombre de barres d'inactivité de l'Expert Advisor
//--- variables globales
bool ExtFirstStart=true; // Flag du 1er lancement
bool ExtFlag=true; // Flag pour permettre à l'EA de fonctionner
uint ExtNumLoss; // Nombre de transactions consécutives non rentables
datetime ExtTimeLastLoss; // Heure de la dernière transaction pour clôturer une position perdante
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- obtient le nombre de transactions perdantes consécutives et l'heure de la dernière transaction pour clôturer la position
ExtNumLoss=GetNumLosingTradesInRow(ExtTimeLastLoss);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- détermine combien de barres se sont écoulées depuis la dernière position perdante fermée de la série
int bars_remaining=iBarShift(Symbol(),PERIOD_CURRENT,ExtTimeLastLoss);
//--- si c'est le premier lancement
if(ExtFirstStart)
{
//--- Si un nombre spécifié de barres est déjà passé après une série de positions non rentables, active l'indicateur d'opération de l'EA
if(bars_remaining>(int)InpInactivityNumBars)
ExtFlag=true;
ExtFirstStart=false;
}
//--- si le flag d'opération de l'EA est désactivé
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)));
//--- si un nombre spécifié de barres est passé après une série de positions non rentables
if(bars_remaining>(int)InpInactivityNumBars)
{
//--- affiche la fenêtre MessageBox avec le texte et le titre de la fenêtre spécifiés
//--- la fenêtre de requête comporte deux boutons Oui/Non et une icône avec un point d'interrogation.
//--- le bouton Oui est sélectionné par défaut.
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);
//--- si le code de retour de MessageBox est le bouton Oui enfoncé, définit l'indicateur d'opération de l'EA
if(mb_id==IDYES)
{
ExtFlag=true;
return;
}
}
//--- le flag d'opération de l'EA est désactivé, quitte OnTick()
return;
}
//--- le flag d'opération de l'EA est défini - l'EA fonctionne comme prévu par le code ci-dessous
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)
{
//--- si le type de transaction ajoute une transaction à l'historique
if(trans.type==TRADE_TRANSACTION_DEAL_ADD)
{
//--- obtient un ticket d'offre et sélectionne une offre dans la liste par ticket
ulong deal_ticket=trans.deal;
if(HistoryDealSelect(deal_ticket))
{
//--- s'il s'agit d'une transaction de sortie de marché, obtient le nombre de transactions perdantes consécutives et l'heure de la dernière transaction.
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);
}
}
//--- si le nombre de transactions perdantes d'affilée est supérieur à la valeur spécifiée et que l'indicateur d'opération de l'EA est activé
if(ExtNumLoss>=InpMaxLossDeals && ExtFlag)
{
//--- affiche la fenêtre MessageBox avec le texte et le titre de la fenêtre spécifiés
//--- la fenêtre de requête comporte deux boutons Oui/Non et une icône avec un point d'exclamation.
//--- le bouton Non est sélectionné par défaut.
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);
//--- si le code de retour de MessageBox est le bouton Non enfoncé, désactive l'indicateur d'opération de l'EA
if(mb_id==IDNO)
ExtFlag=false;
}
}
//+------------------------------------------------------------------+
//| Retourne le nombre de transactions consécutives non rentables |
//| et l'heure de la dernière transaction pour clôturer la position |
//+------------------------------------------------------------------+
uint GetNumLosingTradesInRow(datetime &time_last_deal)
{
//--- sélection de l'historique entier
if(!HistorySelect(0,TimeCurrent()))
return(0);
//--- obtient le ticket suivant grâce à la liste des transactions historiques en boucle
uint res=0;
uint total=HistoryDealsTotal();
for(int i=(int)total-1; i>=0; i--)
{
ulong deal_ticket=HistoryDealGetTicket(i);
if(deal_ticket>0)
{
//--- si la transaction ne vise pas à quitter la position, passe à la suivante
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;
//--- si le résultat de la clôture d'une position génère un profit, on interrompt la boucle
if(!IsClosePositionWithLoss(deal_ticket))
break;
//--- augmente le compteur de transactions perdantes consécutives
res++;
//--- écrit la durée maximale de transaction dans une variable (en recherchant la dernière)
datetime deal_time=(datetime)HistoryDealGetInteger(deal_ticket,DEAL_TIME);
if(deal_time>time_last_deal)
time_last_deal=deal_time;
}
}
//--- renvoie le nombre de pertes consécutives
return(res);
}
//+------------------------------------------------------------------+
//| Retourne le flag de clôture d'une position avec une perte |
//+------------------------------------------------------------------+
bool IsClosePositionWithLoss(const ulong deal_ticket)
{
//--- obtient les valeurs des propriétés affectant le profit du trade
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);
//--- retourne le flag indiquant que la valeur totale des propriétés demandées est négative
return(profit+comission+swap+fee<0);
}
|