![Asesor Experto Grid-Hedge Modificado en MQL5 (Parte II): Creación de un EA de cuadrícula simple](https://c.mql5.com/2/64/Modified_Grid-Hedge_EA_in_MQL5_uPart_IIt_Making_a_Simple_Grid_EA_600x314.jpg)
Asesor Experto Grid-Hedge Modificado en MQL5 (Parte II): Creación de un EA de cuadrícula simple
Introducción
Bienvenido a la segunda entrega de nuestra serie de artículos, "Asesor Experto Grid-Hedge Modificado en MQL5". Vamos a empezar por recapitular lo que cubrimos en la primera parte. En la Parte I, exploramos la estrategia de cobertura clásica, la automatizamos utilizando un Asesor Experto (EA) y realizamos pruebas en el probador de estrategias, analizando algunos resultados iniciales. Esto marcó el primer paso en nuestro camino hacia la creación de un Asesor Experto de cuadrícula y cobertura (hedge) modificado, una mezcla de estrategias clásicas de cobertura y cuadrícula.
Anteriormente había mencionado que la Parte II se centraría en la optimización de la estrategia de cobertura clásica. Sin embargo, debido a retrasos inesperados, por ahora nos centraremos en la estrategia de cuadrícula clásica.
En este artículo, nos adentraremos en la estrategia de cuadrícula clásica, la automatizaremos con un EA en MQL5 y realizaremos pruebas en el probador de estrategias para analizar los resultados y extraer información útil sobre la estrategia.
Así pues, profundicemos en el artículo y exploremos los matices de la estrategia de cuadrícula clásica.
He aquí un breve resumen de lo que abordaremos en este artículo:
- Debatir la estrategia de la cuadrícula clásica
- Debatimos la automatización de nuestra estrategia de cuadrícula clásica
- Backtesting de la estrategia de cuadrícula clásica
- Conclusión
Debatir la estrategia de la cuadrícula clásica
En primer lugar, profundicemos en la propia estrategia antes de seguir adelante.
Iniciamos nuestro enfoque con una posición de compra, aunque es igualmente viable comenzar con una posición de venta. Por ahora, centrémonos en el escenario de compra. Comenzamos a un precio inicial específico, utilizando un tamaño de lote pequeño para simplificar - digamos 0,01, el tamaño de lote mínimo posible. A partir de este punto, hay dos resultados potenciales: el precio puede aumentar o disminuir. Si el precio sube, obtendremos un beneficio, cuyo alcance dependerá de la magnitud del aumento. Luego, obtenemos esta ganancia una vez que el precio alcanza nuestro nivel predeterminado de toma de ganancias. El reto surge cuando el precio empieza a caer: aquí es donde entra en juego nuestra estrategia de cuadrícula clásica, que ofrece una salvaguarda para garantizar los beneficios.
Si el precio cae una cierta cantidad, para facilitar la explicación digamos 15 pips, entonces ejecutamos otra orden de compra. Esta orden se coloca al precio inicial menos 15 pips, y aquí, aumentamos el tamaño del lote, en aras de la simplicidad, lo duplicamos, aplicando efectivamente un multiplicador de tamaño de lote de 2. Al colocar esta nueva orden de compra, nos enfrentamos de nuevo a dos escenarios: el precio puede subir o bajar. Un aumento del precio generaría beneficios con esta nueva orden debido al aumento del tamaño del lote. Además, esta subida no sólo reporta beneficios, sino que también mitiga las pérdidas de nuestra orden de compra inicial con un tamaño de lote de 0,01. El punto en el que nuestro beneficio neto es igual a cero es cuando el precio alcanza el nivel de precio medio ponderado de ambas ordenes. Esta media ponderada puede calcularse del siguiente modo:
En este cálculo, X i representa el precio al que se colocan las órdenes de compra, y W i denota las ponderaciones correspondientes, determinadas por el multiplicador del tamaño del lote. Hasta aquí, el nivel medio ponderado de precios, W, puede calcularse como:
W = 1 × ( Precio Inicial ) + 2 × ( Precio Inicial - 15 pips ) 3Aquí, X 1 es el Precio Inicial, X 2 es el Precio Inicial menos 15 pips, W 1 es igual a 1, y W 2 es igual a 2.
El beneficio neto llega a cero cuando el nivel de precios coincide con el nivel de precios medio ponderado calculado. La demostración de este concepto es la siguiente:
Simplifiquemos y consideremos que el precio inicial es X, donde se abre una orden de compra con un tamaño de lote de 0,01. Si el precio baja 15 pips, colocamos una nueva orden de compra a X - 15 y duplicamos el tamaño del lote a 0,02. El nivel medio ponderado de precios en este punto se calcula como: ( 1 × X + 2 × ( X - 15 ) ) / 3 , que es igual a X - 10 . Esto es 10 pips por debajo del nivel de precio inicial.
Cuando el precio alcanza X - 15 , la orden de compra inicial de 0,01 incurre en una pérdida de 1,5 $ (suponiendo el par EURUSD, donde 1 $ equivale a 10 pips). Si el precio entonces sube hasta el nivel medio ponderado de X - 10, recuperamos una pérdida de 0,5 dólares en la orden inicial. Además, ganamos con la nueva orden de compra de 0,02, ya que el precio ha subido 5 pips desde el nivel de X - 15 . Debido a la duplicación del tamaño del lote, nuestra ganancia aquí también se duplica, ascendiendo a 1 $. Por lo tanto, nuestro beneficio neto total es igual a 0 $ (que es -1,5 $ + 0,5 $ + 1 $).
Si el precio sigue subiendo desde el nivel medio ponderado de X - 10 , seguiremos obteniendo beneficios hasta que alcance el nivel de toma de beneficios.
Si el precio, en lugar de subir, sigue bajando desde el nivel del precio medio ponderado, aplicamos la misma estrategia. Si el precio cae otros 15 pips por debajo de X - 15, se coloca una nueva orden de compra a X - 30 , con el tamaño de lote duplicado respecto al anterior, ahora a 0,04 (2 veces 0,02). El nuevo nivel de precio medio ponderado se calcula como ( 1 × X + 2 × ( X - 15 ) + 4 × ( X - 30 ) ) / 7 , lo que se simplifica a X - 21,428 , situándose 21,428 pips por debajo del nivel de precio inicial.
En el nivel de precios de X - 30 , la orden de compra inicial de 0,01 se enfrenta a una pérdida de 3,0 $ (suponiendo el par EURUSD, donde 1 $ equivale a 10 pips). La segunda orden de compra de 0,02 incurre en una pérdida de 2 veces 1,5 $, lo que equivale a 3,0 $, lo que supone una pérdida total de 6,0 $. Sin embargo, si a continuación el precio asciende hasta el nivel medio ponderado de X - 21,428 , la pérdida de la orden de compra inicial de 0,01 se recupera parcialmente en 0,8572 $. Además, la pérdida en el segundo pedido de 0,02 se compensa con 2 veces 0,8572 $, lo que supone 1,7144 $. Además, nos beneficiamos de la nueva orden de compra de 0,04 ya que el precio ha subido 8,572 pips desde el nivel de X - 30 .< Debido a que el tamaño del lote se ha cuadruplicado (0,04), nuestra ganancia también se ha cuadruplicado, ascendiendo a 4 veces 0,8572 $, lo que equivale a 3,4288 $. Por tanto, el beneficio neto total será de aproximadamente 0 $ ( -6 $ + 0,8572 $ + 1,7144 $ + 3,4288 $ = 0,0004 $). Esta cifra no es exactamente cero debido al redondeo en el cálculo del nivel medio ponderado de precios.
Si el precio sigue subiendo desde el nivel medio ponderado de X - 21,428 , seguiremos acumulando beneficios positivos hasta alcanzar el nivel de toma de ganancias. Por el contrario, si el precio vuelve a bajar, repetimos el proceso, duplicando el tamaño del lote en cada iteración y ajustando en consecuencia el nivel del precio medio ponderado. Este planteamiento garantiza que obtengamos sistemáticamente un beneficio neto de aproximadamente 0 $ cada vez que el precio alcance el nivel del precio medio ponderado, lo que nos llevará gradualmente a obtener beneficios positivos.
Este mismo proceso es aplicable a las órdenes de venta, comenzando el ciclo con una orden de venta inicial. Vamos a desglosarlo:
Comenzamos con una posición de venta a un precio inicial determinado, utilizando un tamaño de lote pequeño para simplificar, digamos 0,01 (el tamaño mínimo posible). A partir de aquí, se pueden producir dos resultados: el precio puede subir o bajar. Si el precio cae, nos beneficiamos en función de la magnitud de la caída y realizamos este beneficio cuando el precio alcanza nuestro nivel de toma de beneficios. Sin embargo, la situación se complica cuando el precio empieza a subir, momento en el que se emplea nuestra clásica estrategia de parrilla para garantizar los beneficios.
Supongamos que el precio aumenta una cierta cantidad, para facilitar la explicación digamos 15 pips. En respuesta, colocamos otra orden de venta al precio inicial más 15 pips, y duplicamos el tamaño del lote para simplificar, haciendo que el multiplicador del tamaño del lote sea 2. Tras colocar esta nueva orden de venta, se plantean dos escenarios: el precio puede seguir subiendo o empezar a bajar. Si el precio cae, nos beneficiamos de esta nueva orden de venta debido al aumento del tamaño del lote. Además, esta disminución no sólo produce beneficios, sino que también reduce las pérdidas de nuestra orden de venta inicial de tamaño de lote 0,01. Alcanzamos un beneficio neto de cero cuando el precio alcanza el nivel de precio medio ponderado de ambas órdenes, un concepto que ya hemos explorado al hablar de las órdenes de compra.
La fórmula para calcular la media ponderada sigue siendo la misma, teniendo en cuenta los precios respectivos y el tamaño de los lotes de las órdenes. Este planteamiento estratégico garantiza que, incluso en mercados fluctuantes, nuestra posición se mantenga a salvo de pérdidas, logrando puntos de equilibrio o beneficios según se mueva el mercado.
Para simplificar, supongamos que el precio inicial es X, donde se coloca una orden de venta con un tamaño de lote de 0,01. Si el precio sube entonces 15 pips, colocamos una nueva orden de venta a X + 15 , duplicando el tamaño del lote a 0,02. El nivel de precio medio ponderado en esta fase se calcula como ( 1 × X + 2 × ( X + 15 ) ) / 3 , lo que se simplifica a X + 10 , o 10 pips por encima del nivel de precio inicial.
Cuando el precio alcanza x + 15 , la orden de venta inicial de 0,01 incurre en una pérdida de 1,5 $ (suponiendo el par EURUSD, donde 1 $ equivale a 10 pips). Si a continuación el precio cae hasta el nivel medio ponderado de x + 10 , compensamos una pérdida de 0,5 dólares en la orden de venta inicial. Además, también ganamos con la nueva orden de venta de 0,02, ya que el precio ha bajado 5 pips desde el nivel de x + 15 . Debido a la duplicación del tamaño del lote, nuestra ganancia también se duplica, lo que resulta en 1 $. Por lo tanto, nuestro beneficio neto total es igual a 0 $ (calculado como -1,5 $ + 0,5 $ + 1 $).
Si el precio sigue bajando desde el nivel medio ponderado de X + 10 , acumularemos beneficios positivos hasta alcanzar el nivel de toma de beneficios. Esta estrategia equilibra eficazmente las pérdidas y ganancias a través de diferentes movimientos de precios, garantizando un beneficio neto o un escenario de equilibrio en condiciones de mercado variables.
Si el precio, al contrario de disminuir, sigue subiendo desde el nivel del precio medio ponderado, aplicamos la misma estrategia que antes. Digamos que el precio supera el nivel X + 15 en otros 15 pips. En respuesta, colocamos una nueva orden de venta a X + 30 , duplicando de nuevo el tamaño de lote de la anterior, ahora a 0,04 (2 veces 0,02). El nivel de precio medio ponderado revisado se calcula entonces como ( 1 × X + 2 × ( X + 15 ) + 4 × ( X + 30 ) ) / 7 , que se simplifica a X + 21,428 , o 21,428 pips por encima del nivel de precio inicial.
En el nivel de precios de X + 30 , la orden de venta inicial de 0,01 se enfrenta a una pérdida de 3,0 $ (suponiendo el par EURUSD, donde 1 $ equivale a 10 pips). La segunda orden de venta de 0,02 incurre en una pérdida de 2 veces 1,5 $, lo que equivale a 3,0 $, lo que supone una pérdida total de 6,0 $. Sin embargo, si a continuación el precio cae hasta el nivel medio ponderado de X + 21,428, recuperamos parcialmente la pérdida de la orden de venta inicial de 0,01 en 0,8572 $. Además, recuperamos la pérdida en el segundo pedido de 0,02 por 2 veces 0,8572 $, lo que supone 1,7144 $. Además, nos beneficiamos de la nueva orden de venta de 0,04 ya que el precio ha bajado 8,572 pips desde el nivel de X + 30 . Debido a que el tamaño del lote se ha cuadruplicado (0,04), nuestra ganancia también se ha cuadruplicado, ascendiendo a 4 veces 0,8572 $, lo que equivale a 3,4288 $. Por tanto, el beneficio neto total será de aproximadamente 0 $ (calculado como -6 $ + 0,8572 $ + 1,7144 $ + 3,4288 $ = 0,0004 $). Esta cifra no es exactamente cero debido al redondeo en el cálculo del nivel medio ponderado de precios.
Si el precio sigue bajando desde el nivel medio ponderado de X + 21,428, acumularemos beneficios positivos hasta alcanzar el nivel de TakeProfit. A la inversa, si el precio sigue subiendo, repetimos el proceso, duplicando el tamaño del lote en cada iteración y ajustando en consecuencia el nivel del precio medio ponderado. Este planteamiento garantiza que obtengamos sistemáticamente un beneficio neto de aproximadamente 0 $ cada vez que el precio alcance el nivel del precio medio ponderado, lo que nos llevará gradualmente a obtener beneficios positivos.
Debatimos la automatización de nuestra estrategia de cuadrícula clásica
Ahora, vamos a profundizar en la automatización de esta estrategia de cuadrícula clásica utilizando un Asesor Experto (EA).
En primer lugar, declararemos algunas variables de entrada en el espacio global:
input bool initialPositionBuy = true; input double distance = 15; input double takeProfit = 5; input double initialLotSize = 0.01; input double lotSizeMultiplier = 2;
- initialPositionBuy: Variable booleana que determina el tipo de posición inicial (de compra o de venta). Si se establece en true, la posición inicial será de compra; en caso contrario, será de venta.
- distance: La distancia fija, medida en pips, entre cada orden consecutiva.
- takeProfit: La distancia, medida en pips, por encima del precio medio de todas las posiciones abiertas a la que se cerrarán todas las posiciones para obtener un beneficio neto total.
- initialLotSize: El tamaño del lote de la primera posición.
- lotSizeMultiplier: El multiplicador aplicado al tamaño del lote para cada posición consecutiva.
Estas son las variables de entrada que modificaremos para diversos fines, como la optimización en nuestra estrategia. Ahora definiremos algunas variables más en el espacio global:
bool gridCycleRunning = false; double lastPositionLotSize, lastPositionPrice, priceLevelsSumation, totalLotSizeSummation;
Estas variables se utilizarán para los siguientes fines:
- gridCycleRunning: Esta es una variable booleana será true si el ciclo se está ejecutando y false en caso contrario. Por defecto es false.
- lastPositionLotSize: Es una variable doble creada para almacenar el tamaño de lote de la última posición abierta en un momento dado del ciclo.
- lastPositionPrice: Es una variable doble creada para almacenar el nivel de precio abierto de la última posición en un momento dado del ciclo.
- priceLevelsSumation: Se trata de la suma de todos los niveles de precios abiertos de todas las posiciones, que se utilizará posteriormente para calcular el nivel medio de precios.
- totalLotSizeSummation: Se trata de la suma de todos los tamaños de lote de todas las posiciones que se utilizará posteriormente para calcular el nivel medio de precios.
//+------------------------------------------------------------------+ //| Hedge Cycle Intialization Function | //+------------------------------------------------------------------+ void StartGridCycle() { double initialPrice = initialPositionBuy ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); ENUM_ORDER_TYPE positionType = initialPositionBuy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; m_trade.PositionOpen(_Symbol, positionType, initialLotSize, initialPrice, 0, 0); lastPositionLotSize = initialLotSize; lastPositionPrice = initialPrice; ObjectCreate(0, "Next Position Price", OBJ_HLINE, 0, 0, lastPositionPrice - distance * _Point * 10); ObjectSetInteger(0, "Next Position Price", OBJPROP_COLOR, clrRed); priceLevelsSumation = initialLotSize * lastPositionPrice; totalLotSizeSummation = initialLotSize; if(m_trade.ResultRetcode() == 10009) gridCycleRunning = true; } //+------------------------------------------------------------------+En la función StartGridCycle(), primero creamos una variable doble, initialPrice , que almacenará el precio de compra o de venta, dependiendo de la variable initialPositionBuy. En concreto, si initialPositionBuy es true, almacenamos el precio de compra; si es false, almacenamos el precio de venta. Esta distinción es crucial porque una posición de compra sólo puede abrirse al precio de demanda, mientras que una posición de venta debe abrirse al precio de oferta.
ENUM_ORDER_TYPE positionType = initialPositionBuy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; CTrade m_trade; m_trade.PositionOpen(_Symbol, positionType, initialLotSize, initialPrice, 0, 0);
Ahora, abriremos una posición de compra o de venta en función del valor de initialPositionBuy. Para ello, crearemos una variable denominada positionType del tipo ENUM_ORDER_TYPE. ENUM_ORDER_TYPE es un tipo de variable personalizada predefinida en MQL5, capaz de tomar valores enteros de 0 a 8, cada uno representando un tipo de orden específico como se define en la siguiente tabla:
Valores enteros | Identificador |
---|---|
0 | ORDER_TYPE_BUY |
1 | ORDER_TYPE_SELL |
2 | ORDER_TYPE_BUY_LIMIT |
3 | ORDER_TYPE_SELL_LIMIT |
4 | ORDER_TYPE_BUY_STOP |
5 | ORDER_TYPE_SELL_STOP |
6 | ORDER_TYPE_BUY_STOP_LIMIT |
7 | ORDER_TYPE_SELL_STOP_LIMIT |
8 | ORDER_TYPE_CLOSE_BY |
En efecto, dentro del ENUM_ORDER_TYPE los valores 0 y 1 corresponden a ORDER_TYPE_BUY y ORDER_TYPE_SELL, respectivamente. Para nuestro propósito nos centraremos en estos dos. Utilizar los identificadores en lugar de sus valores enteros es ventajoso, ya que los identificadores son más intuitivos y fáciles de recordar.
Por lo tanto, establecemos positionType en ORDER_TYPE_BUY si initialPositionBuy es true; de lo contrario, lo establecemos en ORDER_TYPE_SELL.
Para proceder, primero importamos la biblioteca de comercio estándar Trade.mqh en el espacio global. Para ello se utiliza la siguiente sentencia:
#include <Trade/Trade.mqh>
CTrade m_trade;
Para continuar, definimos también una instancia de la clase CTrade, que llamaremos m_trade. Esta instancia se utilizará para gestionar las operaciones comerciales. A continuación, para abrir una posición, utilizamos la función PositionOpen() de m_trade que se encarga de la apertura real de posiciones de compra o venta en función de los parámetros que hayamos establecido, incluido el positionType y otros ajustes relevantes de la operación.
m_trade.PositionOpen(_Symbol, positionType, initialLotSize, initialPrice, 0, 0);
Al utilizar la función PositionOpen() de la instancia m_trade le proporcionamos varios parámetros esenciales para abrir una posición:
-
_Symbol: El primer parámetro es _Symbol , que se refiere al símbolo de negociación actual.
-
positionType: El segundo parámetro es positionType que definimos antes en función del valor de initialPositionBuy. Determina si la posición abierta es de compra o de venta.
-
initialLotSize: El tamaño del lote para la posición definido por nuestra variable de entrada initialLotSize.
-
initialPrice: Precio al que se abre la posición. Esto viene determinado por la variable initialPrice que contiene el precio de compra o de venta en función del tipo de posición que se vaya a abrir.
-
SL (Stop Loss) y TP (Take Profit): Los dos últimos parámetros sirven para fijar el Stop Loss (SL) y el Take Profit (TP). En esta estrategia específica, no establecemos estos parámetros inicialmente, ya que el cierre de las órdenes será determinado por la lógica de la estrategia, en particular cuando el precio alcance el precio medio más el valor takeProfit.
Ahora, pasemos a la siguiente parte del código:
lastPositionLotSize = initialLotSize; lastPositionPrice = initialPrice; ObjectCreate(0, "Next Position Price", OBJ_HLINE, 0, 0, lastPositionPrice - distance * _Point * 10); ObjectSetInteger(0, "Next Position Price", OBJPROP_COLOR, clrRed);
-
Configuración de las variables lastPositionLotSize y lastPositionPrice:
- Hemos inicializado la variable lastPositionLotSize, definida en el espacio global, para que sea igual a initialLotSize. Esta variable es crucial, ya que mantiene un registro del tamaño del lote de la última posición abierta, lo que permite calcular el tamaño del lote para la siguiente orden multiplicándolo por el multiplicador introducido.
- Del mismo modo, lastPositionPrice también se establece en initialPrice. Esta variable, también definida en el espacio global, es esencial para determinar el nivel de precios al que deben abrirse las órdenes posteriores.
-
Creación de una línea horizontal para la visualización:
- Para mejorar la representación visual de nuestra estrategia en el gráfico, utilizamos la función ObjectCreate. Esta función recibe los siguientes parámetros:
- 0 para el gráfico actual
- "Next Position Price" como nombre del objeto
- OBJ_HLINE como tipo de objeto, indicando una línea horizontal
- Dos ceros adicionales, uno para la subventana y el otro para la fecha y hora, ya que solo se necesita el nivel de precio para una línea horizontal
- El nivel de precio calculado para la siguiente orden, (lastPositionPrice - distance * _Point * 10) , como parámetro final.
- Para establecer el color de esta línea horizontal a rojo utilizamos la función ObjectSetInteger() con la propiedad OBJPROP_COLOR establecida a clrRed.
- Para mejorar la representación visual de nuestra estrategia en el gráfico, utilizamos la función ObjectCreate. Esta función recibe los siguientes parámetros:
-
Proceder a la gestión del precio medio en un ciclo de cuadrícula:
- Una vez completados estos pasos iniciales, pasamos a gestionar el precio medio dentro del ciclo de la cuadrícula. Se trata de calcular y ajustar dinámicamente el precio medio a medida que se abren nuevas posiciones y evoluciona el mercado, un componente clave de la estrategia de negociación en cuadrícula.
Sigamos adelante con la siguiente parte de la implementación de su código.
priceLevelsSumation = initialLotSize * lastPositionPrice; totalLotSizeSummation = initialLotSize;
-
Configuración priceLevelsSumation :
- Hemos definido priceLevelsSumation en el espacio global para calcular el precio medio ponderado de todas las posiciones abiertas. Inicialmente, como sólo hay una orden, establecemos priceLevelsSumation igual al precio de la última posición multiplicado por su peso correspondiente, que es el tamaño de lote de la orden. Esta configuración prepara la variable para acumular más niveles de precios, cada uno multiplicado por sus respectivos tamaños de lote, a medida que se abren nuevas posiciones.
-
Inicialización de totalLotSizeSummation :
- La variable totalLotSizeSummation se establece inicialmente igual a initialLotSize. Esto tiene sentido en el contexto de la fórmula de la media ponderada, en la que tenemos que dividir por los pesos totales. Al principio, con un solo pedido, el peso total es el tamaño de lote de ese único pedido. A medida que abra más posiciones, añadiremos sus pesos (tamaños de lote) a esta suma, actualizando así dinámicamente el peso total.
Ahora procedamos con la última parte de la función StartGridCycle():
if(m_trade.ResultRetcode() == 10009) gridCycleRunning = true;Configuración hedgeCycleRunning :
- La variable hedgeCycleRunning se establece en true sólo después de que se abra con éxito una posición. Esto se comprueba mediante la función ResultRetcode() de la instancia CTrade, denominada trade. El código de retorno "10009" indica que el pedido se ha realizado correctamente. (Nota: Se puede hacer referencia a los distintos códigos de devolución para distintos resultados de solicitudes de operaciones).
- El uso de hedgeCycleRunning es fundamental para la estrategia, ya que marca el inicio del ciclo de la cuadrícula. El significado de esta bandera se hará más evidente en las siguientes partes del código.
Una vez completada la función StartGridCycle(), que inicia la estrategia de cuadrícula, se pasa a la función OnTick(). Dividimos esta función en 5 segmentos, cada uno de los cuales se ocupa de un aspecto específico de la lógica de negociación:
- Inicio del ciclo de la cuadrícula
- Gestión de posiciones de compra
- Gestión de posiciones de venta
- Función de cierre del ciclo de la cuadrícula
- Gestión de cierre de posiciones
- Inicio del ciclo de la cuadrícula:
double price = initialPositionBuy ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); if(!gridCycleRunning) { StartGridCycle(); }
-
Variable para la declaración del precio:
- Se declara una nueva variable, denominada precio. Su valor viene determinado por la bandera initialPositionBuy:
- Si initialPositionBuy es true, el precio se establece en el precio ASK actual.
- Si initialPositionBuy es false, el precio se fija en el precio BID actual.
- Se declara una nueva variable, denominada precio. Su valor viene determinado por la bandera initialPositionBuy:
-
Ejecución condicional basada en gridCycleRunning:
- El siguiente paso consiste en una comprobación condicional de la variable gridCycleRunning:
- Si gridCycleRunning es false, esto indica que el ciclo de la cuadrícula aún no ha comenzado, o ha completado su ciclo anterior. En este caso ejecutamos la función StartGridCycle(), que ya se ha explicado con detalle anteriormente. Esta función inicializa el ciclo de la cuadrícula abriendo la primera posición y configurando los parámetros necesarios.
- Si gridCycleRunning es true, implica que el ciclo de la rejilla ya está activo. En este escenario, elegimos no hacer nada por el momento. Esta decisión permite que el ciclo de la cuadrícula existente siga funcionando según su lógica establecida sin iniciar un nuevo ciclo ni interferir con el actual.
- El siguiente paso consiste en una comprobación condicional de la variable gridCycleRunning:
Este enfoque gestiona eficazmente el inicio y la continuación del ciclo de la cuadrícula, garantizando que la estrategia de negociación se adhiere al flujo operativo diseñado. Sigamos con los siguientes pasos en la aplicación de la estrategia de la cuadrícula.
-
- Gestión de posiciones de compra:
if(initialPositionBuy && price <= lastPositionPrice - distance * _Point * 10 && gridCycleRunning) { double newPositionLotSize = NormalizeDouble(lastPositionLotSize * lotSizeMultiplier, 2); m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, newPositionLotSize, price, 0, 0); lastPositionLotSize *= lotSizeMultiplier; lastPositionPrice = price; ObjectCreate(0, "Next Position Price", OBJ_HLINE, 0, 0, lastPositionPrice - distance * _Point * 10); ObjectSetInteger(0, "Next Position Price", OBJPROP_COLOR, clrRed); priceLevelsSumation += newPositionLotSize * lastPositionPrice; totalLotSizeSummation += newPositionLotSize; ObjectCreate(0, "Average Price", OBJ_HLINE, 0, 0, priceLevelsSumation / totalLotSizeSummation); ObjectSetInteger(0, "Average Price", OBJPROP_COLOR, clrGreen); }
Aquí tenemos otra declaración if que tiene 3 condiciones:
-
Condición en inicialPositionBuy :
- El segmento de código se ejecuta sólo si la variable posicióninicialComprar es true. Esta condición garantiza que la lógica de gestión de las posiciones de compra esté separada de la de las posiciones de venta.
- El segmento de código se ejecuta sólo si la variable posicióninicialComprar es true. Esta condición garantiza que la lógica de gestión de las posiciones de compra esté separada de la de las posiciones de venta.
-
Condición en el precio:
- La segunda condición comprueba si la variable precio es menor o igual que lastPositionPrice - distance * _Point * 10 . Esta condición es crucial para determinar cuándo abrir una nueva posición de compra. Aquí se utiliza la operación de resta (-), alineada con la lógica direccional definida en su estrategia de cuadrícula para posiciones de compra.
- La segunda condición comprueba si la variable precio es menor o igual que lastPositionPrice - distance * _Point * 10 . Esta condición es crucial para determinar cuándo abrir una nueva posición de compra. Aquí se utiliza la operación de resta (-), alineada con la lógica direccional definida en su estrategia de cuadrícula para posiciones de compra.
-
Condición en gridCycleRunning :
- La tercera condición requiere que la variable gridCycleRunning sea true, indicando que el ciclo de la cuadrícula está actualmente activo. Esto es esencial para garantizar que las nuevas posiciones sólo se abran como parte de un ciclo de negociación en curso.
- La tercera condición requiere que la variable gridCycleRunning sea true, indicando que el ciclo de la cuadrícula está actualmente activo. Esto es esencial para garantizar que las nuevas posiciones sólo se abran como parte de un ciclo de negociación en curso.
Si se cumplen las tres condiciones, el EA procede a abrir una nueva posición de compra. Sin embargo, antes de hacerlo, calcula el tamaño del lote para la nueva posición:
- Se declara una nueva variable doble, newPositionLotSize, y se establece igual a lastPositionLotSize multiplicado por lotSizeMultiplier.
- El tamaño de lote resultante se normaliza a dos decimales para que el tamaño de lote sea válido, ya que el tamaño de lote tiene que ser múltiplo estricto de 0,01.
Este enfoque garantiza que las nuevas posiciones se abran con los tamaños adecuados, respetando las reglas de la estrategia de cuadrícula. Posteriormente, el EA utiliza la función PositionOpen() de la instancia de la clase CTrade llamada m_trade (declarada anteriormente en el espacio global) para abrir la posición de compra con el tamaño de lote calculado.
Siguiendo con la lógica, el siguiente paso consiste en actualizar la variable lastPositionLotSize. Esto es crucial para mantener la precisión del tamaño de los lotes en los pedidos posteriores:
- El lastPositionLotSize se establece igual a sí mismo multiplicado por lotSizeMultiplier. Lo más importante es que esta multiplicación no implica la normalización a dos decimales.
- La razón para evitar la normalización se ilustra considerando un escenario en el que el lotSizeMultiplier es 1,5 y el initialLotSize es 0,01. Multiplicando 0,01 por 1,5 se obtiene 0,015, que, normalizado a dos decimales, se redondea a 0,01. Esto crea un bucle en el que el tamaño del lote se mantiene constantemente en 0,01, a pesar de multiplicarse.
- Para evitar este problema y garantizar que los tamaños de lote aumentan según lo previsto, lastPositionLotSize se actualiza utilizando el producto no normalizado de sí mismo y el lotSizeMultiplier. Este paso es fundamental para que la estrategia de rejilla funcione correctamente, especialmente con multiplicadores fraccionarios.
Con esta actualización, el EA rastrea y ajusta con precisión los tamaños de lote para las nuevas posiciones, manteniendo la progresión prevista de la estrategia de cuadrícula.
Continuando con el proceso, el siguiente paso consiste en actualizar el lastPositionPrice y visualizar el siguiente nivel de posición en el gráfico:
- Actualización de lastPositionPrice :
- La variable lastPositionPrice se actualiza igual al precio, que viene determinado por la condición initialPositionBuy. Dado que la primera condición de la sentencia if garantiza la entrada sólo cuando posicióninicialComprar es verdadera, el precio corresponderá al precio ASK en este contexto.
- La variable lastPositionPrice se actualiza igual al precio, que viene determinado por la condición initialPositionBuy. Dado que la primera condición de la sentencia if garantiza la entrada sólo cuando posicióninicialComprar es verdadera, el precio corresponderá al precio ASK en este contexto.
- Visualizar el siguiente nivel de posición:
- En el gráfico se dibuja una línea horizontal denominada "Next Position Price". Esta línea representa el nivel de precios al que se abrirá la siguiente orden.
- Dado que initialPositionBuy es true, lo que indica que la próxima posición será una compra, el nivel de precio para esta línea se establece en lastPositionPrice (que se acaba de actualizar) menos la distancia (como se especifica en las entradas) multiplicado por _Point y luego multiplicado por 10.
- Esta línea horizontal se crea utilizando la función ObjectCreate(), y su color se establece en clrRed utilizando funciones adicionales de propiedades de objeto para facilitar su visualización. Esta ayuda visual permite identificar fácilmente el nivel de precios para la siguiente orden de compra potencial.
Al actualizar lastPositionPrice y marcar visualmente el siguiente nivel de orden, el EA se prepara eficazmente para los pasos posteriores en el ciclo de la cuadrícula, asegurando que cada nueva posición se alinee con los criterios de la estrategia y sea visualmente rastreable en el gráfico.
Ahora vamos a refinar el cálculo del nivel medio de precios, centrándonos concretamente en la media ponderada:
-
Actualización de priceLevelsSummation y totalLotSizeSummation :
- Para actualizar el precio medio ponderado, añadimos el producto de lastPositionPrice y newPositionLotSize a priceLevelsSummation.
- Para totalLotSizeSummation, simplemente añadimos el valor de newPositionLotSize.
- Estas actualizaciones son cruciales para realizar un seguimiento de los niveles de precios acumulados y del tamaño total de los lotes de todas las posiciones.
-
Cálculo del nivel medio ponderado de precios:
- El nivel medio de precios, que en este contexto es una media ponderada, se calcula dividiendo priceLevelsSummation entre totalLotSizeSummation.
- Este cálculo refleja con exactitud el precio medio de todas las posiciones abiertas, teniendo en cuenta sus respectivos tamaños de lote.
-
Visualización del nivel de precios medios ponderados:
- Se crea otra línea horizontal en el gráfico en el nivel del precio medio calculado utilizando la función ObjectCreate().
- El color de esta línea se establece en clrGreen, diferenciándola de la otra línea horizontal que indica el precio de la siguiente posición.
- Es importante tener en cuenta que para este cálculo se utiliza el valor normalizado de lastPositionLotSize multiplicado por lotSizeMultiplier. Esto garantiza que se tenga en cuenta el tamaño real del lote de la posición recién abierta, proporcionando una media ponderada exacta.
Al incorporar estos pasos, el EA no sólo realiza un seguimiento del nivel medio de precios de todas las posiciones abiertas, sino que también lo representa visualmente en el gráfico. Esto facilita la supervisión y la toma de decisiones en función del estado actual del ciclo de la cuadrícula y de las condiciones del mercado.
-
- Gestión de posiciones de venta:
if(!initialPositionBuy && price >= lastPositionPrice + distance * _Point * 10 && gridCycleRunning) { double newPositionLotSize = NormalizeDouble(lastPositionLotSize * lotSizeMultiplier, 2); m_trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, newPositionLotSize, price, 0, 0); lastPositionLotSize *= lotSizeMultiplier; lastPositionPrice = price; ObjectCreate(0, "Next Position Price", OBJ_HLINE, 0, 0, lastPositionPrice + distance * _Point * 10); ObjectSetInteger(0, "Next Position Price", OBJPROP_COLOR, clrRed); priceLevelsSumation += newPositionLotSize * lastPositionPrice; totalLotSizeSummation += newPositionLotSize; ObjectCreate(0, "Average Price", OBJ_HLINE, 0, 0, priceLevelsSumation / totalLotSizeSummation); ObjectSetInteger(0, "Average Price", OBJPROP_COLOR, clrGreen); }
Aquí tenemos otra declaración if que nuevamente tiene 3 condiciones:
-
Condición en inicialPositionBuy :
- Este segmento del código se ejecuta sólo si initialPositionBuy es false. Esta condición asegura que la lógica maneja específicamente posiciones de venta, distintas de las posiciones de compra.
- Este segmento del código se ejecuta sólo si initialPositionBuy es false. Esta condición asegura que la lógica maneja específicamente posiciones de venta, distintas de las posiciones de compra.
-
Condición en el precio:
- La segunda condición comprueba si el precio es mayor o igual que lastPositionPrice + distance * _Point * 10 . Esto es esencial para determinar el momento adecuado para abrir una nueva posición de venta. En este caso se utiliza la operación de suma (+), alineándose con la lógica direccional de su estrategia para posiciones de venta.
- La segunda condición comprueba si el precio es mayor o igual que lastPositionPrice + distance * _Point * 10 . Esto es esencial para determinar el momento adecuado para abrir una nueva posición de venta. En este caso se utiliza la operación de suma (+), alineándose con la lógica direccional de su estrategia para posiciones de venta.
-
Condición en gridCycleRunning :
- La tercera condición requiere que gridCycleRunning sea true, lo que indica que el ciclo de la cuadrícula se está ejecutando activamente. Esto garantiza que las nuevas posiciones sólo se abran como parte del ciclo de negociación en curso.
- La tercera condición requiere que gridCycleRunning sea true, lo que indica que el ciclo de la cuadrícula se está ejecutando activamente. Esto garantiza que las nuevas posiciones sólo se abran como parte del ciclo de negociación en curso.
Si se cumplen las tres condiciones, el EA procede a abrir una nueva posición de venta:
- Se declara una variable double newPositionLotSize y se establece igual a lastPositionLotSize multiplicado por lotSizeMultiplier.
- A continuación, este nuevo tamaño de lote se normaliza con dos decimales para que el tamaño de lote sea válido, ya que el tamaño de lote tiene que ser múltiplo estricto de 0,01.
- Por último, el EA utiliza la función PositionOpen() de la instancia de clase CTrade m_trade (declarada anteriormente en el espacio global) para abrir la posición de venta con el tamaño de lote calculado.
Este enfoque garantiza que las nuevas posiciones de venta se abran a intervalos y tamaños adecuados, respetando las reglas de la estrategia de cuadrícula y manteniendo la progresión de la estrategia.
En el siguiente paso de gestión de posiciones de venta, nos centramos en actualizar correctamente la variable lastPositionLotSize:
- La variable lastPositionLotSize se actualiza para ser igual a sí misma multiplicada por lotSizeMultiplier. Este paso es crucial para mantener la progresión de los tamaños de lote en el ciclo de la cuadrícula.
- Es importante destacar que esta multiplicación no implica la normalización a dos decimales. Esta decisión es fundamental para evitar un posible problema con los multiplicadores fraccionarios.
- A modo de ejemplo: con un lotSizeMultiplier de 1,5 y un initialLotSize de 0,01, la multiplicación daría como resultado 0,015. Normalizándolo a dos decimales, se redondearía a 0,01. Si se repitiera este proceso, el tamaño del lote sería siempre de 0,01, lo que crearía un bucle y desvirtuaría la intención de la estrategia.
- Para evitar este problema, lastPositionLotSize se establece en el producto no normalizado de sí mismo y el lotSizeMultiplier. Este enfoque garantiza que los tamaños de los lotes aumenten adecuadamente, especialmente cuando se trata de multiplicadores que dan lugar a tamaños de lote fraccionarios.
Al actualizar lastPositionLotSize sin normalización, el EA rastrea y ajusta eficazmente los tamaños de lote para las nuevas posiciones de venta, garantizando que la estrategia de cuadrícula funcione según lo previsto.
-
Actualización de lastPositionPrice :
- La variable lastPositionPrice se actualiza para igualar el precio, que será el precio ASK o BID dependiendo del valor de initialPositionBuy.
- En este caso, ya que entramos en este segmento del código sólo si initialPositionBuy es false (según la primera condición), lastPositionPrice se establece en el precio BID.
-
Dibujar una línea horizontal para la siguiente posición:
- En el gráfico se dibuja una línea horizontal denominada "Next Position Price". Esta línea indica el nivel de precios en el que se abrirá la siguiente orden (una orden de venta, en este caso).
- El nivel de precio para esta línea horizontal se establece en lastPositionPrice (que se ha actualizado) más la distancia especificada en las entradas, multiplicada por _Point y luego multiplicada por 10. Este cálculo determina el nivel adecuado para la siguiente orden de venta.
- La línea se crea utilizando la función ObjectCreate(), una función predefinida en MQL5 para dibujar objetos en los gráficos.
- El color de esta línea se fija en clrRed, lo que mejora su visibilidad y facilita su distinción en el gráfico.
Al establecer lastPositionPrice adecuadamente y representar visualmente el nivel de la siguiente orden, el EA se prepara eficazmente para las órdenes de venta posteriores, asegurándose de que se alinean con las reglas de la estrategia de cuadrícula y son fácilmente identificables en el gráfico.
En la gestión del cálculo del nivel medio de precios, centrándose específicamente en la media ponderada para las posiciones de venta, el proceso implica:
-
Actualización de priceLevelsSummation y totalLotSizeSummation :
- El valor de lastPositionPrice multiplicado por newPositionLotSize se añade a priceLevelsSummation. Este paso acumula los niveles de precios de todas las posiciones abiertas, cada una ponderada por su respectivo tamaño de lote.
- El valor de newPositionLotSize se añade a totalLotSizeSummation. Esta variable lleva la cuenta de los tamaños de lote acumulados de todas las posiciones.
-
Cálculo del nivel medio ponderado de precios:
- El nivel medio de precios se obtiene dividiendo priceLevelsSummation entre totalLotSizeSummation. Este cálculo da como resultado el precio medio ponderado de todas las posiciones abiertas.
- El nivel medio de precios se obtiene dividiendo priceLevelsSummation entre totalLotSizeSummation. Este cálculo da como resultado el precio medio ponderado de todas las posiciones abiertas.
-
Visualización del nivel de precios medios ponderados:
- Se crea una línea horizontal en el nivel del precio medio ponderado utilizando la función ObjectCreate(). Esta representación visual ayuda a controlar el precio medio de todas las posiciones.
- El color de esta línea se establece en clrVerde, lo que permite distinguirla fácilmente de otras líneas del gráfico.
- Es importante tener en cuenta que en estos cálculos se utiliza el valor normalizado de lastPositionLotSize multiplicado por lotSizeMultiplier. Esto garantiza que se tengan en cuenta los tamaños de lote reales de las posiciones abiertas, lo que proporciona un cálculo medio ponderado preciso.
Este método de cálculo y visualización del nivel medio ponderado de precios es crucial para la gestión eficaz de las posiciones vendedoras en el ciclo de la cuadrícula, ya que permite tomar decisiones informadas basadas en el estado actual del mercado y de las posiciones.
-
- Función de cierre de ciclo de la cuadrícula:
//+------------------------------------------------------------------+ //| Stop Function for a particular Grid Cycle | //+------------------------------------------------------------------+ void StopGridCycle() { gridCycleRunning = false; ObjectDelete(0, "Next Position Price"); ObjectDelete(0, "Average Price"); for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { m_trade.PositionClose(ticket); } } } //+------------------------------------------------------------------+
-
Configuración gridCycleRunning a false:
- La primera acción de esta función es establecer la variable booleana gridCycleRunning en false. Este cambio significa que el ciclo de la cuadrícula ya no está activo y está en proceso de cierre.
- La primera acción de esta función es establecer la variable booleana gridCycleRunning en false. Este cambio significa que el ciclo de la cuadrícula ya no está activo y está en proceso de cierre.
-
Eliminación de objetos del gráfico:
- A continuación, se utiliza la función predefinida ObjectDelete() para eliminar dos objetos específicos del gráfico: "Next Position Price" y "Average Price". Este paso limpia el gráfico de estos marcadores, indicando que el ciclo está concluyendo y que estos niveles de precios ya no son relevantes.
- A continuación, se utiliza la función predefinida ObjectDelete() para eliminar dos objetos específicos del gráfico: "Next Position Price" y "Average Price". Este paso limpia el gráfico de estos marcadores, indicando que el ciclo está concluyendo y que estos niveles de precios ya no son relevantes.
-
Cierre de todas las posiciones:
- A continuación, la función recorre todas las posiciones abiertas.
- Cada posición se selecciona individualmente por su número de ticket.
- Una vez seleccionada una posición, se cierra utilizando la función PositionClose() de la instancia m_trade. El número de ticket de la posición se pasa como parámetro a esta función.
- Este enfoque sistemático garantiza que todas las posiciones abiertas como parte del ciclo de la cuadrícula se cierren, dando por concluida de hecho la actividad comercial para ese ciclo concreto.
Siguiendo estos pasos, la función de cierre de ciclo de la cuadrícula cierra de forma metódica y eficaz todas las posiciones abiertas, reinicia el entorno de negociación y prepara el EA para un nuevo ciclo de cuadrícula.
-
- Gestión de posiciones de cierre:
if(gridCycleRunning) { if(initialPositionBuy && price >= (priceLevelsSumation / totalLotSizeSummation) + takeProfit * _Point * 10) StopGridCycle(); if(!initialPositionBuy && price <= (priceLevelsSumation / totalLotSizeSummation) - takeProfit * _Point * 10) StopGridCycle(); }
En esta sección, "Gestión de posiciones de cierre", el proceso de cierre de órdenes se controla mediante una declaración if, supeditada a determinadas condiciones:
- La condición principal para que se produzca cualquier acción es que gridCycleRunning sea true, lo que indica que hay un ciclo de la cuadrícula activo.
- Dentro de esto, hay otras dos comprobaciones condicionales basadas en el valor de initialPositionBuy:
- Si initialPositionBuy es true y el precio actual es takeProfit pips (definido en las variables de entrada) por encima del nivel de precio medio ponderado, entonces se ejecuta la función StopGridCycle().
- Por el contrario, si initialPositionBuy es false y el precio actual es takeProfit pips por debajo del nivel de precio medio ponderado, se ejecuta la función StopGridCycle().
Estas condiciones garantizan que el ciclo de la cuadrícula se detiene y que las posiciones se cierran en función de los criterios de toma de beneficios especificados en relación con el nivel de precios medios ponderados. Esto marca la conclusión del proceso de automatización de la estrategia de parrilla clásica.
Backtesting de la estrategia de cuadrícula clásica
Una vez completada la automatización de nuestra estrategia de cuadrícula clásica, es hora de evaluar su rendimiento en un escenario real.
Para el backtest, se utilizarán los siguientes parámetros de entrada:
- initialPositionBuy : true
- distance : 15 pips
- takeProfit : 5 pips
- initialLotSize : 0.01
- lotSizeMultiplier : 2.0
Las pruebas se llevarán a cabo en el par EURUSD, desde el 1 de noviembre de 2023 hasta el 22 de diciembre de 2023. El apalancamiento elegido es de 1:500, con un depósito inicial de 10.000 $. En cuanto al marco temporal, cabe señalar que es irrelevante para nuestra estrategia, por lo que cualquier selección será suficiente sin afectar a los resultados. Esta prueba, aunque abarca un periodo relativamente corto de algo menos de dos meses, pretende servir de muestra representativa de los posibles resultados a más largo plazo.
Ahora, profundicemos en los resultados de este backtest:
Estos resultados parecen bastante buenos. Al revisar los resultados del backtest, observamos tendencias intrigantes representadas por las líneas azul y verde del gráfico. Veamos qué significa cada línea y cómo sus movimientos reflejan el rendimiento de la estrategia:
-
Entender las líneas azul y verde:
- La línea azul representa el saldo de la cuenta, mientras que la línea verde indica los fondos propios.
- Se observa un patrón notable en el que el saldo aumenta, los fondos propios disminuyen y, finalmente, convergen en el mismo punto.
-
Explicación de las fluctuaciones de equilibrio:
- La estrategia dicta cerrar todos los pedidos de un ciclo simultáneamente, lo que idealmente debería traducirse en un aumento directo del saldo. Sin embargo, el gráfico muestra un patrón de subida y bajada del saldo que requiere una explicación más detallada.
- Esta fluctuación se atribuye al ligero retraso (fracciones de segundo) en el cierre de las órdenes. Aunque las órdenes se cierran casi simultáneamente, el gráfico captura las actualizaciones incrementales en el saldo.
- Inicialmente, el saldo aumenta a medida que las posiciones rentables se cierran primero. Las posiciones se cierran en un bucle, empezando por la última posición (la más rentable), como indica la función PositionsTotal(). Por lo tanto, el movimiento ascendente y el breve movimiento descendente de la línea de equilibrio pueden ignorarse, centrándose en cambio en la tendencia ascendente neta.
-
Movimiento de la línea de equidad:
- En correspondencia con el equilibrio, el patrimonio neto baja inicialmente y luego sube. Esto se debe a que primero se cierran las posiciones rentables, lo que reduce temporalmente el capital antes de que se recupere.
- El movimiento de la línea verde de equidad sigue una lógica similar a la de la línea azul de equilibrio, lo que lleva a la misma conclusión de una tendencia general positiva.
En resumen, a pesar de las pequeñas fluctuaciones recogidas en el gráfico debidas a la secuencia de cierre de órdenes y a ligeros retrasos, la tendencia general indica un resultado satisfactorio de la estrategia, como demuestra la convergencia final y el movimiento al alza de las líneas de saldo y de fondos propios.
Los resultados del backtest demuestran la rentabilidad de la estrategia de cuadrícula clásica. Sin embargo, es importante reconocer una importante limitación inherente a esta estrategia: el requisito de una gran capacidad de retención.
Esta estrategia suele requerir un capital considerable para soportar las caídas que se producen antes de alcanzar la rentabilidad. La capacidad de mantener posiciones durante movimientos adversos del mercado sin tener que hacer frente a ajustes de márgenes o verse obligado a cerrar posiciones con pérdidas es crucial.
Esta limitación será uno de los puntos clave de las siguientes partes de nuestra serie, en las que exploraremos técnicas de optimización para estas estrategias. El objetivo será aumentar su eficacia y reducir la capacidad de tenencia necesaria, haciendo la estrategia más accesible y menos arriesgada para operadores con capital de diverso tamaño.
Conclusión
En esta entrega, nos adentramos en los entresijos de la estrategia de cuadrícula clásica, automatizándola con éxito mediante un Asesor Experto (EA) en MQL5. También examinamos algunos resultados iniciales de esta estrategia, destacando su potencial y los aspectos susceptibles de mejora.
Sin embargo, nuestro camino hacia la optimización de tales estrategias dista mucho de haber concluido. Las próximas partes de esta serie se centrarán en la puesta a punto de la estrategia, en particular el perfeccionamiento de los valores óptimos para los parámetros de entrada como la distancia, takeProfit, initialLotSize, y lotSizeMultiplier para maximizar los rendimientos y minimizar las detracciones. Un aspecto intrigante de nuestra próxima exploración será determinar la eficacia de comenzar con una posición de compra o de venta, que puede variar en función de las distintas divisas y condiciones del mercado.
Hay mucho que esperar de nuestros próximos artículos, en los que descubriremos más ideas y técnicas valiosas. Aprecio el tiempo que dedicas a leer mis artículos y espero que proporcionen tanto conocimiento como ayuda práctica en tus actividades de trading y programación. Si hay temas o ideas específicas que te gustaría ver discutidas en la próxima parte de esta serie, tus sugerencias son siempre bienvenidas.
¡Feliz codificación! ¡Feliz comercio!
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/13906
![Redes neuronales: así de sencillo (Parte 72): Predicción de trayectorias en entornos ruidosos](https://c.mql5.com/2/64/Neural_networks_made_easy_6Part_72m__Predicting_trajectories_in_the_presence_of_noise___LOGO-FNYbN4B.png)
![Algoritmos de optimización de la población: Evolución de grupos sociales (Evolution of Social Groups, ESG)](https://c.mql5.com/2/68/Population_optimization_algorithms_Evolution_of_Social_Groups_rESGw___LOGO.png)
![Desarrollo de un sistema de repetición (Parte 51): Esto complica las cosas (III)](https://c.mql5.com/2/79/Desenvolvendo_um_sistema_de_Replay_Parte_51____LOGO.png)
![Características del Wizard MQL5 que debe conocer (Parte 11): Muros numéricos](https://c.mql5.com/2/66/MQL5_Wizard_Techniques_you_should_know_3Part_11s_Number_Walls_____LOGO.png)
![MQL5 - Lenguaje de estrategias comerciales para el terminal de cliente MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso