212 lines
11 KiB
Markdown
212 lines
11 KiB
Markdown
# MessageBox
|
||
|
||
It creates and shows a message box and manages it. A message box contains a message and header, any combination of predefined signs and command buttons.
|
||
|
||
```
|
||
int MessageBox(
|
||
string text, // message text
|
||
string caption=NULL, // box header
|
||
int flags=0 // defines set of buttons in the box
|
||
);
|
||
|
||
```
|
||
|
||
Parameters
|
||
|
||
text
|
||
|
||
[in] Text, containing message to output.
|
||
|
||
caption=[NULL](/en/docs/basis/types/void)
|
||
|
||
[in] Optional text to be displayed in the box header. If the parameter is empty, Expert Advisor name is shown in the box header.
|
||
|
||
flags=0
|
||
|
||
[in] Optional [flags](/en/docs/constants/io_constants/messbconstants#messageboxflags) defining appearance and behavior of a message box. Flags can be a combination of a special group of flags.
|
||
|
||
Return Value
|
||
|
||
If the function is successfully performed, the returned value is one of values of [MessageBox()](/en/docs/constants/io_constants/messbconstants) return codes.
|
||
|
||
Note
|
||
|
||
The function cannot be used in custom indicators since calling MessageBox() suspends the [thread of execution](/en/docs/runtime/running) for the whole time while waiting for the user's response. Since all indicators for each symbol are executed in a single thread, such suspension makes the operation of all charts on all timeframes for this symbol impossible.
|
||
|
||
MessageBox() function does not work in the [Strategy Tester](/en/docs/runtime/testing#alert_etc).
|
||
|
||
Example:
|
||
|
||
```
|
||
//+------------------------------------------------------------------+
|
||
//| 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);
|
||
}
|
||
|
||
```
|