//+------------------------------------------------------------------+
//| El asesor muestra MessageBox solicitando el trabajo subsiguiente |
//| al alcanzar el número indicado de transacciones con pérdidas |
//| Esperamos el número de barras indicado y mostramos MessageBox |
//| solicitando el trabajo subsiguiente. |
//| Para comprobar, basta abrir y cerrar manualmente con pérdidas |
//| varias posiciones, ya que para simplificar, el asesor no controla|
//| "sus" posiciones según el número mágico. |
//+------------------------------------------------------------------+
//--- input parameters
input uint InpMaxLossDeals = 3; // Max Loss deals
input uint InpInactivityNumBars = 5; // Number of bars of advisor inactivity
//--- global variables
bool ExtFirstStart=true; // Bandera de primer inicio
bool ExtFlag=true; // Bandera de permiso de funcionamiento del asesor
uint ExtNumLoss; // Número de transacciones perdedoras consecutivas
datetime ExtTimeLastLoss; // Hora de la última operación de cierre de una posición perdedora
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- obtenemos el número de transacciones perdedoras consecutivas y la hora de la última operación de cierre de posición
ExtNumLoss=GetNumLosingTradesInRow(ExtTimeLastLoss);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- determinamos cuántas barras han pasado desde la última posición perdedora cerrada en la serie
int bars_remaining=iBarShift(Symbol(),PERIOD_CURRENT,ExtTimeLastLoss);
//--- si es el primer inicio
if(ExtFirstStart)
{
//--- si el número especificado de barras ya ha pasado después de una serie de posiciones no rentables, establecemos la bandera de funcionamiento del asesor
if(bars_remaining>(int)InpInactivityNumBars)
ExtFlag=true;
ExtFirstStart=false;
}
//--- si la bandera de funcionamiento del asesor se ha desactivado
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 ha transcurrido el número de barras especificado tras una serie de posiciones perdedoras
if(bars_remaining>(int)InpInactivityNumBars)
{
//--- mostramos la ventana MessageBox con el texto y el encabezado de ventana indicados
//--- la ventana de solicitud tiene dos botones Yes/No y un icono con un signo de interrogación.
//--- el botón Yes está seleccionado por defecto.
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 el código de retorno de MessageBox es un botón Yes pulsado, establecemos la bandera de funcionamiento del asesor
if(mb_id==IDYES)
{
ExtFlag=true;
return;
}
}
//--- la bandera del asesor está desactivada, salimos de OnTick()
return;
}
//--- la bandera de funcionamiento del asesor está activada, el asesor funciona como se indica en el código siguiente
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 el tipo de transacción es la adición de una operación a la historia
if(trans.type==TRADE_TRANSACTION_DEAL_ADD)
{
//--- obtenemos el ticket de la transacción y seleccionamos una transacción de la lista según el ticket
ulong deal_ticket=trans.deal;
if(HistoryDealSelect(deal_ticket))
{
//--- si se trata de una transacción de salida del mercado, obtenemos el número de transacciones perdedoras consecutivas y la hora de la última transacción
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 el número de transacciones perdedoras consecutivas es superior al valor especificado y se ha establecido la bandera de funcionamiento del asesor
if(ExtNumLoss>=InpMaxLossDeals && ExtFlag)
{
//--- mostramos la ventana MessageBox con el texto y el encabezado de ventana indicados
//--- la ventana de solicitud tiene dos botones Yes/No y un icono con un signo de exclamación.
//--- el botón No está seleccionado por defecto.
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 el código de retorno de MessageBox es un botón No pulsado, quitamos la bandera de funcionamiento del asesor
if(mb_id==IDNO)
ExtFlag=false;
}
}
//+------------------------------------------------------------------+
//| Retorna el número de transacciones perdedoras consecutivas |
//| y la hora de la última operación de cierre |
//| de una posición perdedora |
//+------------------------------------------------------------------+
uint GetNumLosingTradesInRow(datetime &time_last_deal)
{
//--- Seleccionamos la historia completa
if(!HistorySelect(0,TimeCurrent()))
return(0);
//--- en un ciclo a través de la lista de transacciones históricas obtenemos el ticket de la siguiente transacción
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 transacción no es de salida de la posición, pasamos a la siguiente
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 el resultado del cierre de posición tiene un beneficio positivo, interrumpimos el ciclo
if(!IsClosePositionWithLoss(deal_ticket))
break;
//--- aumentamos el contador de transacciones consecutivas con beneficio negativo
res++;
//--- escribimos en la variable la hora máxima de la transacción (buscando la última)
datetime deal_time=(datetime)HistoryDealGetInteger(deal_ticket,DEAL_TIME);
if(deal_time>time_last_deal)
time_last_deal=deal_time;
}
}
//--- retorna el número de pérdidas consecutivas
return(res);
}
//+------------------------------------------------------------------+
//| Retorna la bandera de cierre de una posición con pérdidas |
//+------------------------------------------------------------------+
bool IsClosePositionWithLoss(const ulong deal_ticket)
{
//--- obtenemos de la transacción los valores de las propiedades que afectan a los beneficios
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);
//--- retorna la bandera que indica que el valor total de las propiedades obtenidas es negativo
return(profit+comission+swap+fee<0);
}
|