Loops que ralentizan el probador de estrategias

 

Buenas. Tengo un expert en el que realizo un monton de loops por separado, y creo que son las culpables de que el strategy tester vaya extremadamente lento. Y con esto me refiero a tardar mas de una hora en avanzar dos semanas en graficas de M15... una eternidad desde mi punto de vista.

Añado codigo con comentarios al respecto.

Agradeceria alguna idea para optimizarlo, y si a alguno le sirve algo de mi codigo, que aproveche :)

//Esto va OnTick()... Tengo unos cuantos loops asi, para distintas cosas como crear arrays, que tienen que tener el counterz y al final un break porque sino se le iba la olla y no sabia por qué...
   double zoneu=0;
   double zoned=0;
   int counterz=0;

   for(int l = 1 ; l < 20; l++)
     {
      zoneu=zV4[l]+150*Point;
      zoned=zV4[l]-150*Point;
      if(Ask<zoneu && Ask>zoned)
        {
         inzone[l]=true;
        }
      else
        {
         inzone[l]=false;
        }
      counterz++;
      if(counterz==20)
        {
         break;
        }

     }
//---

//Esto va fuera, para obtener ciertos valores del historial de ordenes. Hay alguna manera de sacar varios valores dentro de un mismo loop?
//Orders Counter SELL
int CountOrdersSell()
  {
   int NumberSell=0;
   for(int h=OrdersTotal()-1; h>=0; h--)
     {
      if(OrderSelect(h,SELECT_BY_POS,MODE_TRADES))
         if(OrderSymbol()==Symbol())
            if(OrderType()==OP_SELL)
              {
               NumberSell=NumberSell+1;
              }
     }
   return NumberSell;
  }

//Last Price SELL
double LastPriceSell()
  {
   double PriceSell=0;
   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
         PriceSell=OrderOpenPrice();
      if(OrderSymbol()==Symbol() && OrderType()==OP_SELL && OrderComment()==CountOrdersSell())
         return PriceSell;
     }
   return 0;
  }

//LastOrderSell
int LastOrderSell()
  {
   double LastSell=0;
   for(int ii=OrdersTotal()-1; ii>=0; ii--)
     {
      if(OrderSelect(ii,SELECT_BY_POS,MODE_TRADES))
         LastSell=OrderTicket();
      if(OrderSymbol()==Symbol() && OrderType()==OP_SELL && OrderComment()==CountOrdersSell())
         return LastSell;
     }
   return 0;
  }
//---
 
NikoSeneca:

Buenas. Tengo un expert en el que realizo un monton de loops por separado, y creo que son las culpables de que el strategy tester vaya extremadamente lento. Y con esto me refiero a tardar mas de una hora en avanzar dos semanas en graficas de M15... una eternidad desde mi punto de vista.

Añado codigo con comentarios al respecto.

Agradeceria alguna idea para optimizarlo, y si a alguno le sirve algo de mi codigo, que aproveche :)

Hola, sí puede mejorar el código. Pero no está especialmente mal. 

En función de lo que muestras no debería ser tan lento como describes. Quizá hay algo que no está aquí que realmente está ralentizando. 

Puedes usar para ello el botón (en Metaeditor), iniciar perfilado con datos reales, y ejecutarlo unos minutos, o lo que consideres para que te indique donde hay mayor carga de recursos


Edito, después de releer tu mensaje, ¿Estás imprimiendo estos valores en forma de Comment o Print? Eso sí suele ralentizar bastante los backtest.

Y una posible forma de juntar las 3 funciones, entiendo que quieres sacar el número de operaciones de venta, el precio de la última operación, y el ticket:

void GetLastSellOrderInfo(int magicNumber, int& sellCount, double& lastPrice, int& lastOrder)
  {
   sellCount = 0;
   lastPrice = 0;
   lastOrder = 0;

   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         Print("Error selecting order at position ", i);
         return;
        }

      if(OrderSymbol() == Symbol() && OrderType() == OP_SELL && OrderMagicNumber() == magicNumber)
        {
         sellCount++;
         if(OrderClosePrice() > 0)
           {
            lastPrice = OrderClosePrice();
            lastOrder = OrderTicket();
            break;
           }
        }
     }
  }

NO termino de entender el principio del código, 
counterz++;

¿sirve para algo?

 
Enrique Enguix #:
...

Puedes usar para ello el botón (en Metaeditor), iniciar perfilado con datos reales, y ejecutarlo unos minutos, o lo que consideres para que te indique donde hay mayor carga de recursos


Buenas, gracias por tu respuesta.

El perfilado, herramienta que no habia utilizado nunca por desconocimiento, pone que hay una gran carga en los iCustoms que uso con el indicador zig zag (60%) y , respondiendo a tu otra pregunta, imprimo unos valores como Comment, que gasta el otro 40%.


Los zig zags, supongo que sera por la cantidad de velas que analizo porque el que mas velas uso (20.000 debido al largo periodo que necesito) gasta mucho mas que el otro que solo usa 200 velas.


Respecto al counterz, lo uso para el break.

Cuando empecé el codigo hace tiempo, no recuerdo que error me salia si usaba solo el loop normal, y tenia que frenarlo de alguna manera :)


En cuanto a optimizar el codigo, hace tiempo habia realizado una pregunta sobre loops en el foro en ingles, y el compañero William Roeder despues de solventar mi problema, me dio una idea para hacer el codigo mas rapido ya que decia que tenia un OrderSelect dentro de un OrderSelect. Y su solución fue esta, aunque para mi problema actual no ha servido de nada.

int nBuy=CountOrdersBuy();
for(int g=OrdersTotal()-1; g>=0; g--) if(
   OrderSelect(g,SELECT_BY_POS)
&& OrderType()   == OP_BUY 
&& OrderComment()== nBuy
&& OrderSymbol() == _Symbol
){
   return OrderOpenPrice();
}


Y aun tengo que implementar la idea que me has dado tu, aunque los datos que necesito son ademas son 

bool CheckOrder()
  {
   for(int j=OrdersTotal()-1; j>=0; j--)
     {
      if(
         OrderSelect(j,SELECT_BY_POS,MODE_TRADES)
         && OrderSymbol()==Symbol()
         && OrderMagicNumber()==MagNum)
         return(false);
     }
   return(true);
  }


// Y tengo otro loop para conseguir esto...
         Proftick+=OrderProfit()+OrderCommission()+OrderSwap();

Asi que le daré una vuelta de rosca en unos dias (que ando liado) y a ver como avanza el asunto.


--- Edito ---

He conseguido que vaya mucho mas rapido reduciendo las velas a analizar en este loop.

   double zV4[20];
   datetime zT4[20];
   int counter4 = 0;

   double value4 = 0;
   datetime datezz4 = 0;
   for(int jj = 0; jj < 400; jj++)
     {
      value4 = iCustom(Symbol(), Period(), "ZigZag",86,45,24, 0, jj);
      datezz4 = Time[jj];
      if(value4 != 0)
        {
         zV4[counter4] = value4;
         zT4[counter4] = datezz4;
         counter4++;
         if(counter4 == 20)
           {
            break;
           }
        }
     }
No se si hay alguna manera de optimizarlo :)
 

Hola de nuevo, vaya por delante que no soy un crack de la programación, pero son problemas con los que yo también me he topado en el pasado.

Para los Comments yo lo que haría es usarlos solo si no es backtest, o si es backtest, solo si es modo visual

if ( !IsTesting() || IsTesting && IsVisualMode()){Comment.....}

Los iCustom inevitablemente te van a ralentizar, quizá te interesa en función de la situación, solo revisarlo con cada nueva vela

Función: 

bool IsNewBar(int i, ENUM_TIMEFRAMES timeFrame)
  {
   if((i < 0) || (i > 3))
      return false;

   static datetime lastBarOpenTime[4] = { 0, 0, 0, 0 };

   datetime barOpenTime = iTime(NULL, timeFrame, 0);

   if(0 == barOpenTime)
     {
      return false;
     }

   bool isNewBar = (barOpenTime > lastBarOpenTime[i]);

   lastBarOpenTime[i] = barOpenTime;

   return isNewBar;
  }

Y solo lo ejecutas una vez por vela. Eso ya depende del código

if(isNewBar(1 o i o lo que quieras, PERIOD_H1) {
(.....lo que sea)

 double zV4[20];
   datetime zT4[20];
   int counter4 = 0;

   double value4 = 0;
   datetime datezz4 = 0;
   for(int jj = 0; jj < 400; jj++)
     {
      value4 = iCustom(Symbol(), Period(), "ZigZag",86,45,24, 0, jj);
      datezz4 = Time[jj];
      if(value4 != 0)
        {
         zV4[counter4] = value4;
         zT4[counter4] = datezz4;
         counter4++;
         if(counter4 == 20)
           {
            break;
           }
        }
     }
}
Razón de la queja: