Creador de cuadrículas 1.1 - página 4

 
Lo siento Cori, sólo tengo una orden para cualquier posición de la cuadrícula y he probado casi todas las variaciones - durante varias semanas.

De vez en cuando borro todas las órdenes abiertas para que nuestros amigos de MT4 no se molesten.

usted obtendrá este problema en las pruebas de espalda, pero esto no es un problema de la secuencia de comandos ... pero un problema de backtesting MT4.

Si continúa, por favor, hágamelo saber o envíeme algunos informes que muestran el problema ...

gracias y reagrds,

hugues
 
Lo he encontrado. Y no me hace ninguna gracia.

El asesor está creando la rejilla con mi comentario dado "GridEURUSD". Este comentario se mantiene en el campo de comentarios mientras la orden está en espera. Si la orden se activa, el comentario cambia a "activate/auto". Después de todo, está claro que este comportamiento conduce al problema descrito.

Estoy operando con Alpari. Ellos están apoyando MT4 en las cuentas de demostración

Comprobaré si puedo evitar este comportamiento, es decir, utilizar la magia de la orden como identificador para la rejilla, y les comunicaré los resultados.

Mientras probaba esto, también he realizado modificaciones en el script de limpieza de la rejilla. He añadido la funcionalidad de cerrar las órdenes abiertas también. Lamentablemente, si intento cerrar una orden abierta, obtengo el error 129, que significa Orden bloqueada. Pero borra todas las órdenes pendientes para la rejilla dada.

//+------------------------------------------------------------------+ //| RemoveGrid.mq4 | //| Copyright © 2005, hdb | //| http://www.dubois1.net/hdb |+------------------------------------------------------------------+ #property copyright "Copyright © 2005, hdb" #property link "http://www.dubois1.net/hdb" extern string GridName = "Grid"; extern bool closeOpen = false; //+------------------------------------------------------------------+ //| función de inicio del programa de script |+------------------------------------------------------------------+ int start() { #property show_inputs // muestra los parámetros - gracias Slawa... 

//---- int total = OrdersTotal(); int i ; for(i=total-1; i>=0;i--) { OrderSelect(i, SELECT_BY_POS); int type = OrderType(); if ( OrderSymbol()==Symbol() && OrderComment() == GridName ) { bool result = false; switch(type) { case OP_BUY : if ( closeOpen ) { result = OrderClose( OrderTicket(), OrderLots(), Ask, 0, Blue ); } break; case OP_SELL : if ( closeOpen ) { result = OrderClose( OrderTicket(), OrderLots(), Bid, 0, Blue ); } break; /Cerrar órdenes pendientes case OP_BUYLIMIT : result = OrderDelete( OrderTicket() ); break; case OP_BUYSTOP : result = OrderDelete( OrderTicket() ); break; case OP_SELLLIMIT : result = OrderDelete( OrderTicket() ); break; case OP_SELLSTOP : result = OrderDelete( OrderTicket() ); break; } if(result == false) { Print("Order " , OrderTicket() , " failed to close. Error:" , GetLastError() ); // Sleep(3000); }  
        } } //---- return(0); } //+------------------------------------------------------------------+




cori

 
ok cori, gracias..

¡¡avisame si funciona y usare la magia.. ya que no sabia que el broker hace cosas raras como esa!!

gracias y saludos,

hugues
 
Ahora, eso es todo.

He cambiado el gridMaker para usar el OrderMagicNumber en lugar del comentario. También he hecho alguna pequeña modificación sobre la construcción del comentario.

Aquí está el resultado.

//+------------------------------------------------------------------+ //| MakeGrid.mq4 | //| Copyright © 2005, hdb | //| http://www.dubois1.net/hdb |+------------------------------------------------------------------+ #propiedad copyright "Copyright © 2005, hdb" #propiedad link "http://www.dubois1.net/hdb" //#propiedad versión "1.4beta" // modificada por cori. Usando OrderMagicNumber para identificar las operaciones de la parrilla extern int uniqueGridMagic = 11111; // Número mágico de las operaciones. debe ser único para identificar // las operaciones de una parrilla extern double Lots = 0.1; // extern double GridSize = 6; // pips entre ordenes - tamaño de la rejilla o de la malla extern double GridSteps = 12; // número total de ordenes a colocar extern double TakeProfit = 6 ; // número de ticks para tomar beneficios. normalmente es = tamaño de la rejilla pero se puede anular extern double StopLoss = 0; // si se quiere añadir un stop loss. las cuadrículas normales no usan stop loss extern double UpdateInterval = 1; // actualiza las órdenes cada x minutos extern bool wantLongs = true; // queremos posiciones largas extern bool wantShorts = true; // queremos posiciones cortas extern bool wantBreakout = true;       // queremos posiciones largas por encima del precio, posiciones cortas por debajo del precio extern bool wantCounter = true; // queremos posiciones largas por debajo del precio, posiciones cortas por encima del precio extern bool limitEMA34 = false; // queremos posiciones largas sólo por encima de la ema, posiciones cortas sólo por debajo de la ema // modificado sólo por cori. sólo variables internas double LastUpdate = 0; // contador utilizado para anotar la hora de la última actualización double GridMaxOpen = 0; // número máximo de posiciones abiertas string GridName = "Grid"; // identifica la parrilla. permite varias parrillas coexistentes //+------------------------------------------------------------------+ //| función de inicialización experta | //+------------------------------------------------------------------+ int init() { //---- #property show_inputs // muestra los parámetros - gracias Slawa...    
 if ( TakeProfit <= 0 ) // { TakeProfit = GridSize; } //---- GridName = StringConcatenate( "Grid", Symbol() ); return(0);
  } //+------------------------------------------------------------------------+ //| comprueba si hay una posición u orden abierta en la región de atRate | //| comprobará los largos si checkLongs es verdadero, de lo contrario comprobará | //| los cortos | //+------------------------------------------------------------------------+ bool IsPosition(double atRate, double inRange, bool checkLongs ) { int totalorders = OrdersTotal(); for(int j=0;j<totalorders;j++) // escanea todas las órdenes y posiciones... { OrderSelect(j, SELECT_BY_POS); // modificado por cori. Usar OrderMagicNumber para identificar las operaciones de la rejilla if ( OrderSymbol()==Symbol() && OrderMagicNumber() == uniqueGridMagic )  // sólo busca si mi rejilla y símbolo... { int type = OrderType(); if (MathAbs( OrderOpenPrice() - atRate ) < inRange) // no busca el precio exacto sino la proximidad del precio (menos que el tamaño de la rejilla) { if ( checkLongs && ( type == OP_BUY || type == OP_BUYLIMIT || type == OP_BUYSTOP ) )  || (!checkLongs && ( type == OP_SELL || type == OP_SELLLIMIT | type == OP_SELLSTOP ) ) ) { return(true); } } } 

   return(false); } //+------------------------------------------------------------------+ //| función de inicio del programa de script | //+------------------------------------------------------------------+ int start() { //---- int i, j,k, ticket, entermode, totalorders; bool doit; double point, startrate, traderate; //---- if (MathAbs(CurTime()-LastUpdate)> UpdateInterval*60) // actualizamos la primera vez que se llama y cada UpdateInterval minutos { LastUpdate = CurTime();
   Print("Updating"); point = MarketInfo(Symbol(),MODE_POINT); startrate = ( Ask + point*GridSize/2 ) / point / GridSize; // redondea a un número de ticks divisible por GridSize k = startrate ; k = k * GridSize ; startrate = k * point - GridSize*GridSteps/2*point ;          ¡// calcular el punto de entrada más bajo double EMA34=iMA(NULL,0,34,0,MODE_EMA,PRICE_CLOSE,0); for( i=0;i<GridSteps;i++) { traderate = startrate + i*point*GridSize; if ( wantLongs && (!limitEMA34 || traderate > EMA34)) { if ( IsPosition(traderate,point*GridSize,true) == false )           // prueba si no tengo órdenes abiertas cerca de mi precio: si es así, pon una { double myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate-point*StopLoss ; } if ( traderate > Ask ) { entermode = OP_BUYSTOP; } 
              else { entermode = OP_BUYLIMIT ; } 
              
              if ( ((traderate > Ask ) && (wantBreakout)) || ((traderate <= Ask ) && (wantCounter)) ) 

              { // modificado por cori. Usando OrderMagicNumber para identificar las operaciones de la parrilla ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate+point*TakeProfit,GridName,uniqueGridMagic,0,Green); } } if ( wantShorts && (!limitEMA34 | traderate < EMA34)) { if (IsPosition(traderate,point*GridSize,false)== false )           // comprueba si no tengo órdenes abiertas cerca de mi precio: si es así, pon una { myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate+punto*StopLoss ; } if ( traderate > Bid ) { entermode = OP_SELLLIMIT; } 
              si no { entermode = OP_SELLSTOP ; } 
              
              if ( ((traderate < Bid ) && (wantBreakout)) || ((traderate >= Bid ) && (wantCounter)) ) 
               { // modificado por cori. Usando OrderMagicNumber para identificar las operaciones de la parrilla ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate-point*TakeProfit,GridName,uniqueGridMagic,0,Red); } } } } return(0); }+------------------------------------------------------------------+



con saludos, cori

 
gracias cori...

como ya había hecho algunos cambios yo mismo, integré tus cambios en la nueva versión.

Hice una pequeña variación: para mantener mis cuadrículas actuales activas, puse un test en magic OR gridname...

¿puedes comprobar si lo hice correctamente?



//+------------------------------------------------------------------+ //| MakeGrid.mq4 | //| Copyright © 2005, hdb | //| http://www.dubois1.net/hdb |+------------------------------------------------------------------+ #property copyright "Copyright © 2005, hdb" #property link "http://www.dubois1.net/hdb" //#property version "1.6beta" // modificado por cori. Usando OrderMagicNumber para identificar las operaciones de la parrilla extern int uniqueGridMagic = 11111; // Número mágico de las operaciones. debe ser único para identificar // las operaciones de una parrilla extern double Lots = 0.1; // extern double GridSize = 6; // pips entre ordenes - tamaño de la rejilla o de la malla extern double GridSteps = 12; // número total de ordenes a colocar extern double TakeProfit = 12 ; // número de ticks para tomar beneficios. normalmente es = tamaño de la rejilla pero se puede anular extern double StopLoss = 0; // si se quiere añadir un stop loss. las cuadrículas normales no usan stop loss extern double UpdateInterval = 1; // actualiza las órdenes cada x minutos extern bool wantLongs = true; // queremos posiciones largas extern bool wantShorts = false; // queremos posiciones cortas extern bool wantBreakout = true;     // queremos posiciones largas por encima del precio, posiciones cortas por debajo del precio extern bool wantCounter = true; // queremos posiciones largas por debajo del precio, posiciones cortas por encima del precio extern bool limitEMA34 = true; // queremos posiciones largas sólo por encima de la ema, posiciones cortas sólo por debajo de la ema extern double GridMaxOpen = 0; // número máximo de posiciones abiertas : aún no se ha implementado.. extern bool UseMACD = true; // si es true, usará macd >0 sólo para largos, macd >0 sólo para cortos // en el cruce, cancelará todas las órdenes pendientes. Esto anulará cualquier configuración // wantLongs y wantShort - al menos por ahora. extern bool CloseOpenPositions = false;// si UseMACD, ¿también cerramos las posiciones abiertas con pérdidas? // modificado por cori. variables internas solamente string GridName = "Grid"; // identifica la cuadrícula. permite la coexistencia de varias rejillas double LastUpdate = 0; // contador utilizado para anotar la hora de la última actualización //+------------------------------------------------------------------+ //| función de inicialización experta | //+------------------------------------------------------------------+ int init() { //---- #property show_inputs // muestra los parámetros - gracias Slawa...    
 if ( TakeProfit <= 0 ) // { TakeProfit = GridSize; } //---- // ¡¡¡Añadido por mi corri y eliminado por hdb!! lol.. solo para seguir siendo compatible con las rejillas abiertas...
// GridName = StringConcatenate( "Grid", Symbol() ); return(0); } //+------------------------------------------------------------------------+ //| comprueba si hay una posición u orden abierta en la región de atRate | //| comprobará los largos si checkLongs es verdadero, de lo contrario comprobará | //| los cortos | //+------------------------------------------------------------------------+ bool IsPosition(double atRate, double inRange, bool checkLongs ) { int totalorders = OrdersTotal();
     for(int j=0;j<totalorders;j++) // escanea todas las órdenes y posiciones... { OrderSelect(j, SELECT_BY_POS); // modificado por cori. Usando OrderMagicNumber para identificar las operaciones de la rejilla // hdb añadido o gridname para la compatibilidad if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) | (OrderComment() == GridName)) )  // sólo busca si mi rejilla y símbolo... { int type = OrderType(); if (MathAbs( OrderOpenPrice() - atRate ) < inRange) // no busca el precio exacto sino la proximidad del precio (menos que el tamaño de la rejilla) { if ( checkLongs && ( type == OP_BUY || type == OP_BUYLIMIT || type == OP_BUYSTOP ) )  || (!checkLongs && ( type == OP_SELL || type == OP_SELLLIMIT | type == OP_SELLSTOP ) ) ) { return(true); } } } 
   return(false); } //+------------------------------------------------------------------------+ //| cancela todas las órdenes pendientes | //+------------------------------------------------------------------------+ void CloseAllPendingOrders( ) { int totalorders = OrdersTotal(); for(int j=totalorders-1;j>=0;j--) // escanea todas las órdenes y posiciones... { OrderSelect(j, SELECT_BY_POS); // modificado según cori. Usando OrderMagicNumber para identificar las operaciones de la rejilla // hdb añadido o gridname para la compatibilidad if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) | (OrderComment() == GridName)) )  // sólo mira si mygrid y symbol...
         { int type = OrderType(); bool result = false; switch(type) { case OP_BUY : result = true ; case OP_SELL : result = true ; /Cerrar órdenes pendientes case OP_BUYLIMIT : result = OrderDelete( OrderTicket() ); case OP_BUYSTOP : result = OrderDelete( OrderTicket() ); case OP_SELLLIMIT : result = OrderDelete( OrderTicket() ); case OP_SELLSTOP : result = OrderDelete( OrderTicket() ); } } 
   return; } //+------------------------------------------------------------------------+ //| cancela todas las órdenes pendientes y cierra las posiciones abiertas | //+------------------------------------------------------------------------+ void CloseOpenOrders() { int total = OrdersTotal(); for(int i=total-1;i>=0;i--) { OrderSelect(i, SELECT_BY_POS); int type = OrderType(); bool result = false; // modificado por cori. Usando OrderMagicNumber para identificar las operaciones de la rejilla // hdb añadido o gridname por compatibilidad if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) | (OrderComment() == GridName)) )  // sólo mira si migrid y símbolo...
     { // Print("Closing 2 ",type); switch(type) { /Cerrar posiciones largas abiertas case OP_BUY : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red ); break; /Cerrar posiciones cortas abiertas case OP_SELL : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red ); break; /Cierre de órdenes pendientes case OP_BUYLIMIT : case OP_BUYSTOP :
           case OP_SELLLIMIT : case OP_SELLSTOP : result = OrderDelete( OrderTicket() ); } } if(result == false) { // Alert("Order " , OrderTicket() , " failed to close. Error:" , GetLastError() ); // Sleep(3000); }  
  } return; } //+------------------------------------------------------------------+ //| función de inicio del programa de script | //+------------------------------------------------------------------+ int start() { //---- int i, j,k, ticket, entermode, totalorders; bool doit; double point, startrate, traderate; //---- if (MathAbs(CurTime()-LastUpdate)> UpdateInterval*60) // actualizamos la primera vez que se llama y cada UpdateInterval minutos { LastUpdate = CurTime();
   point = MarketInfo(Symbol(),MODE_POINT); startrate = ( Ask + point*GridSize/2 ) / point / GridSize; // redondeamos a un número de ticks divisible por GridSize k = startrate ; k = k * GridSize ;
   startrate = k * punto - GridSize*GridSteps/2*punto ; // calcula el punto de entrada más bajo double EMA34=iMA(NULL,0,34,0,MODE_EMA,PRICE_CLOSE,0); if ( UseMACD ) { double Macd0=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0)
      double Macd1=iMACD(NULL,0,12,26,9,PRECIO_CIERRE,MODO_MAIN,1); double Macd2=iMACD(NULL,0,12,26,9,PRECIO_CIERRE,MODO_MAIN,2); if( Macd0>0 && Macd1>0 && Macd2<0) // cross up { CloseAllPendingOrders();
         if ( CloseOpenPositions == true ) { CloseOpenOrders(); } } if( Macd0<0 && Macd1<0 && Macd2>0) // cross down { CloseAllPendingOrders(); if ( CloseOpenPositions == true ) { CloseOpenOrders(); } } wantLongs = false; wantShorts = false; if( Macd0>0 && Macd1>0 && Macd2>0) // está muy por encima de cero { wantLongs = true; } if( Macd0<0 &¡& Macd1<0 && Macd2<0) // está muy por debajo de cero { wantShorts = true; } } for( i=0;i<GridSteps;i++) { traderate = startrate + i*point*GridSize; if ( wantLongs && (!limitEMA34 || traderate > EMA34)) { if ( IsPosition(traderate,point*GridSize,true) == false )           // prueba si no tengo órdenes abiertas cerca de mi precio: si es así, pon una { double myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate-point*StopLoss ; } if ( traderate > Ask ) { entermode = OP_BUYSTOP; } 
              else { entermode = OP_BUYLIMIT ; } 
              if ( ((traderate > Ask ) && (wantBreakout)) || ((traderate <= Ask ) && (wantCounter)) ) 
              { // modificado por cori. Usando OrderMagicNumber para identificar las operaciones de la parrilla ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate+point*TakeProfit,GridName,uniqueGridMagic,0,Green); } } if ( wantShorts && (!limitEMA34 | traderate < EMA34)) { if (IsPosition(traderate,point*GridSize,false)== false )           // comprueba si no tengo órdenes abiertas cerca de mi precio: si es así, pon una { myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate+punto*StopLoss ; } if ( traderate > Bid ) { entermode = OP_SELLLIMIT; } 
              si no { entermode = OP_SELLSTOP ; } 
              
              if ( ((traderate < Bid ) && (wantBreakout)) || ((traderate >= Bid ) && (wantCounter)) ) 
                { // modificado por cori. Usando OrderMagicNumber para identificar las operaciones de la parrilla ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate-point*TakeProfit,GridName,uniqueGridMagic,0,Red); } } } } return(0); }+------------------------------------------------------------------+
 
Hola hdb,

parece estar bien. Pero deberías definir el GridName como externo, lo cual cambié, porque no lo necesitaba como parámetro.

saludos, cori
 
ATENCIÓN a todos los usuarios de GridMaker - hay un error en la función IsPosition - el resultado es que no se llenan todas las ranuras de la cuadrícula.

Puede cambiar la línea:

if (MathAbs( OrderOpenPrice() - atRate ) < inRange) // no busca el precio exacto sino la proximidad del precio (menos que el tamaño de la cuadrícula)

to

if (MathAbs( OrderOpenPrice() - atRate ) < (inRange*0.9)) // no busque el precio exacto sino la proximidad del precio (menos que el tamaño de la cuadrícula) - agregó 0.9 debido a los errores de pont flotante


y esto corrige el problema.

Disculpen las molestias...

hugues
 
Hola hugues,

¿Este problema ya existe?

Encontré algo similar en el viejo MQL2.

La forma realmente seguro para ir alrededor de este problema es hacer algo como:

intOOP = MathRound( OrdeOpenPrice() / Point );

para todas sus variables dobles. Entonces tienes todas las variables int directas que son comparables sin fallos.

Es un poco más de escribir para mantenerlo claro y comprensible, pero es menos defectuoso.

Con saludos,

cori
 
Tienes razón Cori, es mucho más elegante. Sólo me da pereza.

saludos,
hugues
 
Aquí hay una actualización del GridMaker EA. En esta versión he:

1) cambiado la lógica para UseMACD, wantLongs, wantShorts. Anteriormente, si useMACD estaba establecido, el EA tomaba largos y cortos, independientemente de las banderas wantLongs y wantShorts. Ahora, useMACD no anulará estas banderas, por lo que puede ser largo sólo con useMACD o corto sólo.

2) He añadido una comprobación adicional para asegurarme de que no hay órdenes abiertas en el lado equivocado de la EMA si la limitEMA34 está activada. Lo que solía pasar es que las órdenes estaban bien colocadas por encima o por debajo de la EMA pero después de unas horas la EMA se movía.. así que había órdenes a ambos lados de la EMA.

3) Parece que hay un error en la sentencia switch en OrderType().. no estoy seguro de lo que es pero realmente se comporta de forma extraña. Simplemente he eliminado las sentencias switch y las he sustituido por "if"... no me gusta pero funciona.

4) Hice el período de EMA variable ... agradable para backtesting..

También tengo algunos scripts complementarios si alguien quiere:

1) para eliminar las órdenes abiertas no cumplidas para un par
2) para eliminar todas las órdenes abiertas para todos los pares de una sola vez
3) para cerrar todas las posiciones y eliminar las órdenes abiertas.
4) para obtener algunas estadísticas simples sobre el comportamiento de la red a partir de las posiciones abiertas y el historial.

Aquí está el código de la V1.08:


//+------------------------------------------------------------------+ //| MakeGrid.mq4 | //| Copyright © 2005, hdb | //|
http://www.dubois1.net/hdb | //+------------------------------------------------------------------+ #property copyright "Copyright © 2005, hdb" #property link "http://www.dubois1.net/hdb" //#property version "1.8" // DISCLAIMER ***** NOTA IMPORTANTE ***** LEER ANTES DE USAR ***** // Este asesor experto puede abrir y cerrar posiciones reales y por lo tanto hacer operaciones reales y perder dinero real.
// Este no es un "sistema de trading" sino un simple robot que coloca operaciones de acuerdo a reglas fijas. // El autor no tiene pretensiones en cuanto a la rentabilidad de este sistema y no sugiere el uso de este EA más que para propósitos de prueba en cuentas demo. // El uso de este sistema es gratuito - pero no puede revenderlo - y es sin ninguna garantía en cuanto a su // idoneidad para cualquier propósito.
// Al usar este programa usted reconoce implícitamente que entiende lo que hace y acepta que // el autor no tiene ninguna responsabilidad por cualquier pérdida. // Antes de usarlo, por favor, compruebe también con su broker que sus sistemas están adaptados para las operaciones más frecuentes // asociadas a este experto. // Los cambios de la versión 1.8 // convierten wantLongs y wantShorts en variables locales. Anteriormente, si establecías UseMACD en true, // hacía longs y shorts y simplemente ignoraba las banderas wantLongs y wantShorts. 
// Ahora, estas banderas no se ignoran. // Se ha añadido un bucle para comprobar si hay órdenes abiertas "ilícitas" por encima o por debajo de la EMA cuando se utiliza la bandera limitEMA34 //. Estas se acumulan con el tiempo y nunca se eliminan y se debe a que la EMA se mueve. // se eliminó la instrucción switch ya que no parece funcionar - se reemplazó con declaraciones if // se hizo la variable del periodo de la EMA // // modificada por cori. Usando OrderMagicNumber para identificar las operaciones de la parrilla extern int uniqueGridMagic = 11111; // Número mágico de las operaciones. debe ser único para identificar // las operaciones de una parrilla extern double Lots = 0.1; // extern double GridSize = 6; // pips entre ordenes - tamaño de la rejilla o de la malla extern double GridSteps = 12; // número total de ordenes a colocar extern double TakeProfit = 12 ; // número de ticks para tomar beneficios. normalmente es = tamaño de la rejilla pero se puede anular extern double StopLoss = 0; // si se quiere añadir un stop loss. las cuadrículas normales no usan stop loss extern double UpdateInterval = 1; // actualiza las órdenes cada x minutos extern bool wantLongs = true; // queremos posiciones largas extern bool wantShorts = true; // queremos posiciones cortas extern bool wantBreakout = true;     // queremos posiciones largas por encima del precio, posiciones cortas por debajo del precio extern bool wantCounter = true; // queremos posiciones largas por debajo del precio, posiciones cortas por encima del precio extern bool limitEMA = true; // queremos posiciones largas sólo por encima de la ema, posiciones cortas sólo por debajo de la ema extern int EMAperiod = 34; // la longitud de la EMA.. anteriormente estaba fijada en 34 extern double GridMaxOpen = 0; // número máximo de posiciones abiertas : aún no se ha implementado.. extern bool UseMACD = true; // si es true, usará macd >0 sólo para largos, macd >0 sólo para cortos // en el cruce, cancelará todas las órdenes pendientes. Esto anulará cualquier configuración // wantLongs y wantShort - al menos por ahora. extern bool CloseOpenPositions = false;// si UseMACD, ¿también cerramos las posiciones abiertas con pérdidas? extern bool doHouseKeeping = true; // sólo una prueba // modificada por cori. sólo variables internas string GridName = "Grid"; // identifica la cuadrícula. permite la coexistencia de varias rejillas double LastUpdate = 0; // contador utilizado para anotar la hora de la última actualización //+------------------------------------------------------------------+ //| función de inicialización experta |+------------------------------------------------------------------+ int init() { //---- #property show_inputs // muestra los parámetros - gracias Slawa...    
//---- // ¡¡¡Añadido por mi corri y quitado por hdb!! lol.. solo para seguir siendo compatible con las rejillas abiertas...
// GridName = StringConcatenate( "Grid", Symbol() ); return(0); } //+------------------------------------------------------------------------+ //| comprueba si hay una posición u orden abierta en la región de atRate | //| comprobará los largos si checkLongs es verdadero, de lo contrario comprobará | //| los cortos | //+------------------------------------------------------------------------+ bool IsPosition(double atRate, double inRange, bool checkLongs ) { int totalorders = OrdersTotal();
     for(int j=0;j<totalorders;j++) // escanea todas las órdenes y posiciones... { OrderSelect(j, SELECT_BY_POS); // modificado por cori. Usando OrderMagicNumber para identificar las operaciones de la rejilla // hdb añadido o gridname para la compatibilidad if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) | (OrderComment() == GridName)) )  // sólo busca si mygrid y símbolo... { int type = OrderType(); if (MathAbs( OrderOpenPrice() - atRate ) < (inRange*0.9)) // no se busca el precio exacto sino la proximidad del precio (menos que el tamaño de la rejilla) - se añade 0,9 debido a los errores de punto flotante { si ( checkLongs && ( type == OP_BUY || type == OP_BUYLIMIT || type == OP_BUYSTOP ) )  || (!checkLongs && ( type == OP_SELL || type == OP_SELLLIMIT | type == OP_SELLSTOP ) ) ) { return(true); } } } 
   return(false); } //+------------------------------------------------------------------------+ //| cancela todas las órdenes pendientes | //+------------------------------------------------------------------------+ void CloseAllPendingOrders( ) { int totalorders = OrdersTotal(); for(int j=totalorders-1;j>=0;j--) // escanea todas las órdenes y posiciones... { OrderSelect(j, SELECT_BY_POS); // modificado según cori. Usando OrderMagicNumber para identificar las operaciones de la rejilla // hdb añadido o gridname para la compatibilidad if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) | (OrderComment() == GridName)) )  // sólo mira si mygrid y symbol... { int type = OrderType(); if ( type > 1 ) bool result = OrderDelete( OrderTicket() ); } } 
   return; } //+------------------------------------------------------------------------+ //| cancela todas las órdenes pendientes y cierra las posiciones abiertas | //+------------------------------------------------------------------------+ void CloseOpenOrders() { int total = OrdersTotal(); for(int i=total-1;i>=0;i--) { OrderSelect(i, SELECT_BY_POS); int type = OrderType(); bool result = false; // modificado por cori. Usando OrderMagicNumber para identificar las operaciones de la rejilla // hdb añadido o gridname por compatibilidad if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) | (OrderComment() == GridName)) )  // sólo mira si mi rejilla y el símbolo...
     { /Cerrar posiciones largas abiertas si ( type == OP_BUY ) result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red );
           /Cerrar las posiciones cortas abiertas si ( type == OP_SELL ) result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red ); /Cerrar las órdenes pendientes si ( type > 1 ) result = OrderDelete( OrderTicket() ); } } return;
} //+------------------------------------------------------------------------+ //| cancela todas las órdenes abiertas que caen en el lado equivocado de la EMA | //+------------------------------------------------------------------------+ void CloseOrdersfromEMA( double theEMAValue ) { int totalorders = OrdersTotal(); for(int j=totalorders-1;j>=0;j--) // analiza todas las órdenes y posiciones... { OrderSelect(j, SELECT_BY_POS); if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) )  // sólo mira si mygrid y symbol...
         { int type = OrderType(); bool result = false; //si (type > 1) Print(type," ",theEMAValue," ",OrderOpenPrice()); if ( type == OP_BUYLIMIT && OrderOpenPrice() <= theEMAValue ) result = OrderDelete( OrderTicket() ); if ( type = OP_BUYSTOP && OrderOpenPrice() <= theEMAValue ) result = OrderDelete( OrderTicket() ); si ( type == OP_SELLLIMIT && OrderOpenPrice() >= theEMAValue ) result = OrderDelete( OrderTicket() ); si ( type = OP_SELLSTOP && OrderOpenPrice() >= theEMAValue ) result = OrderDelete( OrderTicket() ); } } 
   return; } //+------------------------------------------------------------------+ //| función de inicio del programa de scripts |+------------------------------------------------------------------+ int start() { //---- int i, j,k, ticket, entermode, totalorders; bool doit; double point, startrate, traderate; //---- setup parameters if ( TakeProfit <= 0 ) // { TakeProfit = GridSize; } bool myWantLongs = wantLongs;
 bool myWantShorts = wantShorts; //---- if (MathAbs(CurTime()-LastUpdate)> UpdateInterval*60) // actualizamos la primera vez que se llama y cada UpdateInterval minutos { LastUpdate = CurTime();
   point = MarketInfo(Symbol(),MODE_POINT); startrate = ( Ask + point*GridSize/2 ) / point / GridSize; // redondeamos a un número de ticks divisible por GridSize k = startrate ; k = k * GridSize ; startrate = k * point - GridSize*GridSteps/2*point ;          // calcula el punto de entrada más bajo double myEMA=iMA(NULL,0,EMAperiod,0,MODE_EMA,PRICE_CLOSE,0); if (limitEMA) { if (doHouseKeeping) CloseOrdersfromEMA(myEMA); } if ( UseMACD ) { double Macd0=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0)
      double Macd1=iMACD(NULL,0,12,26,9,PRECIO_CIERRE,MODO_MAIN,1); double Macd2=iMACD(NULL,0,12,26,9,PRECIO_CIERRE,MODO_MAIN,2); if( Macd0>0 && Macd1>0 && Macd2<0) // cruza hacia arriba { CloseAllPendingOrders(); if ( CloseOpenPositions == true ) { CloseOpenOrders(); } } if( Macd0<0 && Macd1<0 && Macd2>0) // cruza hacia abajo { CloseAllPendingOrders();
         if ( CloseOpenPositions == true ) { CloseOpenOrders(); } } myWantLongs = false; myWantShorts = false; if( Macd0>0 && Macd1>0 && Macd2>0 && wantLongs )     // está muy por encima de cero { myWantLongs = true; } if( Macd0<0 && Macd1<0 && Macd2<0 && wantShorts )     // está muy por debajo de cero { myWantShorts = true; } } for( i=0;i<GridSteps;i++) { traderate = startrate + i*point*GridSize; if ( myWantLongs && (!limitEMA | traderate > myEMA)) { if ( IsPosition(traderate,point*GridSize,true) == false )           // prueba si no tengo órdenes abiertas cerca de mi precio: si es así, pon una { double myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate-point*StopLoss ; } if ( traderate > Ask ) { entermode = OP_BUYSTOP; } 
              else { entermode = OP_BUYLIMIT ; } 
              if ( ((traderate > Ask ) && (wantBreakout)) || ((traderate <= Ask ) && (wantCounter)) ) 
              { // modificado por cori. Usando OrderMagicNumber para identificar las operaciones de la parrilla ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate+point*TakeProfit,GridName,uniqueGridMagic,0,Green); } } if ( myWantShorts && (!limitEMA | traderate < myEMA)) { if (IsPosition(traderate,point*GridSize,false)== false )           // comprueba si no tengo órdenes abiertas cerca de mi precio: si es así, pon una { myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate+punto*StopLoss ; } if ( traderate > Bid ) { entermode = OP_SELLLIMIT; } 
              si no { entermode = OP_SELLSTOP ; } 
              
              if ( ((traderate < Bid ) && (wantBreakout)) || ((traderate >= Bid ) && (wantCounter)) ) 
                { // modificado por cori. Usando OrderMagicNumber para identificar las operaciones de la parrilla ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate-point*TakeProfit,GridName,uniqueGridMagic,0,Red); } } } } return(0); }+------------------------------------------------------------------+