//+------------------------------------------------------------------+ //| 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); } |