//+------------------------------------------------------------------+
//| The EA displays MessageBox window with a request for further work|
//| upon reaching specified number of series of unprofitable trades |
//| Wait for the specified number of bars and display MessageBox |
//| with a request to continue work. |
//| To check, we need to manually open and close several positions |
//| with a loss, since the EA does not control |
//| its own "positions" by magic number for simplicity. |
//+------------------------------------------------------------------+
//--- input parameters
input uint InpMaxLossDeals = 3; // Max Loss deals
input uint InpInactivityNumBars = 5; // Number of bars of advisor inactivity
//--- global variables
bool ExtFirstStart=true; // First launch flag
bool ExtFlag=true; // Flag for allowing the EA to work
uint ExtNumLoss; // Number of consecutive unprofitable trades
datetime ExtTimeLastLoss; // Time of the last trade to close a losing position
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- get the number of losing trades in a row and the time of the last trade to close the position
ExtNumLoss=GetNumLosingTradesInRow(ExtTimeLastLoss);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- determine how many bars have passed since the last closed losing position in the series
int bars_remaining=iBarShift(Symbol(),PERIOD_CURRENT,ExtTimeLastLoss);
//--- if this is the first launch
if(ExtFirstStart)
{
//--- If a specified number of bars have already passed after a series of unprofitable positions, set the EA operation flag
if(bars_remaining>(int)InpInactivityNumBars)
ExtFlag=true;
ExtFirstStart=false;
}
//--- if the EA operation flag is disabled
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)));
//--- if a specified number of bars have passed after a series of unprofitable positions
if(bars_remaining>(int)InpInactivityNumBars)
{
//--- display MessageBox window with the specified text and window title
//--- the request window has two Yes/No buttons and an icon with a question mark.
//--- the Yes button is selected by default.
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);
//--- if the return code from MessageBox is the Yes button pressed, set the EA operation flag
if(mb_id==IDYES)
{
ExtFlag=true;
return;
}
}
//--- the EA operation flag is disabled, exit OnTick()
return;
}
//--- the EA operation flag is set - the EA works as provided by the code below
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)
{
//--- if the transaction type is adding a transaction to history
if(trans.type==TRADE_TRANSACTION_DEAL_ADD)
{
//--- get a deal ticket and select a deal from the list by ticket
ulong deal_ticket=trans.deal;
if(HistoryDealSelect(deal_ticket))
{
//--- if this is a market exit trade, get the number of losing trades in a row and the time of the last trade
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);
}
}
//--- if the number of losing trades in a row is greater than the specified value and the EA operation flag is enabled
if(ExtNumLoss>=InpMaxLossDeals && ExtFlag)
{
//--- display MessageBox window with the specified text and window title
//--- the request window has two Yes/No buttons and an icon with an exclamation mark.
//--- the No button is selected by default.
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);
//--- if the return code from MessageBox is the No button pressed, disable the EA operation flag
if(mb_id==IDNO)
ExtFlag=false;
}
}
//+------------------------------------------------------------------+
//| Return the number of consecutive unprofitable trades |
//| and the time of the last trade to close a losing position |
//+------------------------------------------------------------------+
uint GetNumLosingTradesInRow(datetime &time_last_deal)
{
//--- select the entire history
if(!HistorySelect(0,TimeCurrent()))
return(0);
//--- get the next trade ticket by the list of historical deals in a loop
uint res=0;
uint total=HistoryDealsTotal();
for(int i=(int)total-1; i>=0; i--)
{
ulong deal_ticket=HistoryDealGetTicket(i);
if(deal_ticket>0)
{
//--- if the deal is not for exiting the position, move on to the next one
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;
//--- if the result of closing a position has a profit, interrupt the loop
if(!IsClosePositionWithLoss(deal_ticket))
break;
//--- increase the counter of consecutive loss-making trades
res++;
//--- write the maximum trade time into a variable (looking for the last one)
datetime deal_time=(datetime)HistoryDealGetInteger(deal_ticket,DEAL_TIME);
if(deal_time>time_last_deal)
time_last_deal=deal_time;
}
}
//--- return the number of consecutive losses
return(res);
}
//+------------------------------------------------------------------+
//| Return the flag of closing a position with a loss |
//+------------------------------------------------------------------+
bool IsClosePositionWithLoss(const ulong deal_ticket)
{
//--- get the values of the properties affecting profit from the 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);
//--- return the flag indicating that the total value of the received properties is negative
return(profit+comission+swap+fee<0);
}
|