Discusión sobre el artículo "Descifrando las estrategias de trading intradía de ruptura del rango de apertura"

 

Artículo publicado Descifrando las estrategias de trading intradía de ruptura del rango de apertura:

Las estrategias de ruptura del rango de apertura (Opening Range Breakout, ORB) se basan en la idea de que el rango de negociación inicial establecido poco después de la apertura del mercado refleja niveles de precios significativos en los que compradores y vendedores acuerdan el valor. Al identificar rupturas por encima o por debajo de un determinado rango, los operadores pueden aprovechar el impulso que suele producirse cuando la dirección del mercado se vuelve más clara. En este artículo, exploraremos tres estrategias ORB adaptadas del Grupo Concretum.

Las estrategias de ruptura del rango de apertura (Opening Range Breakout, ORB) se basan en la idea de que el rango de negociación inicial establecido poco después de la apertura del mercado refleja niveles de precios significativos en los que compradores y vendedores acuerdan el valor. Al identificar rupturas por encima o por debajo de un determinado rango, los operadores pueden aprovechar el impulso que suele producirse cuando la dirección del mercado se vuelve más clara. 

En este artículo, exploraremos tres estrategias ORB adaptadas de los artículos del Grupo Concretum. En primer lugar, abordaremos los antecedentes de la investigación, incluidos los conceptos clave y la metodología utilizada. A continuación, para cada estrategia, explicaremos cómo funcionan, enumeraremos sus reglas de señal y analizaremos su rendimiento estadísticamente. Por último, los examinaremos desde una perspectiva de cartera, centrándonos en el tema de la diversificación.  

Este artículo no profundizará en la programación, sino que se centrará en el proceso de investigación, incluyendo la recreación, el análisis y la prueba de las estrategias de estos tres artículos. Esto será adecuado para lectores que busquen posibles ventajas comerciales o que sientan curiosidad por saber cómo se estudiaron y replicaron estas estrategias. No obstante, se revelará todo el código MQL5 de los Asesores Expertos. Los lectores pueden ampliar este marco según sus propias necesidades.


Autor: Zhuo Kai Chen

 
Gran artículo

Vale la pena para cualquier comerciante que persigue

Hablando desde mi propia experiencia
 
Timmy T #:
Gran artículo

Vale la pena para cualquier comerciante

Hablando desde mi propia experiencia

Gracias Timmy.

 

Efectivamente gran artículo, agradezco el tiempo y esfuerzo que has invertido en escribir el código y compartirlo con la comunidad.

Tengo una simple pregunta sobre"En los estudios que estamos adaptando, se centran en estrategias que operan entre la apertura y el cierre del mercado (9:30 AM a 4:00 PM hora del Este).Dado que nuestro corredor utiliza UTC + 2/3, esto se traduce en 18:30-24:00 hora del servidor, asegúrese de ajustar para su propia zona horaria del corredor cuando la prueba"

¿Podría explicarme su proceso de conversión de la hora?

El uso de un convertidor de tiempo genérico - mi conversión de 09:30 hora del Este termina siendo 16:30 para cuando mt5 está en GMT + 2 y 17:30 para cuando mt5 está en GMT + 3. 18:30 se siente como si fuera 1-2 horas después de la apertura del mercado.

Apreciar la ayuda y gracias de nuevo ..

Archivos adjuntos:
NY_GMT.png  12 kb
 
Sunjoo hora del servidor-asegúrese de ajustar para la zona horaria de su propio broker cuando realice las pruebas "

¿Puede guiarme a través de su proceso de pensamiento en la conversión de tiempo?

Usando un convertidor de tiempo genérico - mi conversión de 09:30 hora del este termina siendo 16:30 para cuando mt5 está en GMT + 2 y 17:30 para cuando mt5 está en GMT + 3. 18:30 se siente como si fuera 1-2 horas después de la apertura del mercado.

Apreciar la ayuda y gracias de nuevo ..

Tienes razón, me equivoqué al convertir la hora del servidor en el artículo para la hora de apertura de la bolsa de Nueva York. Debería ser 17:30 en lugar de 18:30. Dicho esto, puede asumir que todas las reglas de mi estrategia en el artículo deberían estar operando 1 hora después de la apertura del mercado. Gracias por señalarlo y perdón por la confusión.

 

Gracias por la publicación, ¡muy interesante!

Una pregunta sobre el código:

En tu función MarketOpened utilizas:

"if (currentHour >= startHour && currentMinute>=startMinute)return true;" <- Esto parece que sólo operará parte de la hora si el mercado está abierto, ya que devolverá false si estás al principio de cada hora, aunque el mercado esté abierto. Sólo funciona si el minuto está en 0, que no es el inicio de la sesión de mercado.

 
Digitus #:

Gracias por publicarlo, ¡muy interesante!

Una pregunta sobre el código:

En tu función MarketOpened utilizas:

"if (currentHour >= startHour && currentMinute>=startMinute)return true;" <- Esto parece que operará sólo parte de la hora si el mercado está abierto, ya que devolverá false si estás al principio de cada hora, aunque el mercado esté abierto. Sólo funciona si el minuto está en 0, que no es el inicio de la sesión de mercado.

OMG, no puedo creer que me perdí esto. Debería:

    if ((currentHour >= startHour &&currentMinute>=startMinute)||currentHour>startHour)return true;

Lo siento sinceramente por el error descuidado. Gracias por leer tan atentamente y señalarlo.

 

Ps. Para ORB3, yo codifiqué la hora de apertura del mercado a las 9:30. Usted puede cambiarlo a estas funciones para que pueda coincidir con la hora del servidor de la apertura del mercado de Nueva York. Usted puede cambiarlo a estas funciones para que pueda coincidir con el tiempo de servidor de Nueva York el tiempo de apertura del mercado.

//+------------------------------------------------------------------+
//| Obtener el valor de la banda superior de Concretum|
//+------------------------------------------------------------------+
double getUpperBand(int target_hour = 17, int target_min = 30) {
    // Obtener la hora de la barra actual
    datetime current_time = iTime(_Symbol, PERIOD_CURRENT, 0);
    MqlDateTime current_dt;
    TimeToStruct(current_time, current_dt);
    int current_hour = current_dt.hour;
    int current_min = current_dt.min;
    
    // Buscar el precio de apertura de hoy a la hora objetivo (por ejemplo, 17:30 hora del servidor)
    datetime today_start = iTime(_Symbol, PERIOD_D1, 0);
    int bar_at_target_today = getBarShiftForTime(today_start, target_hour, target_min);
    if (bar_at_target_today < 0) return 0; // Devuelve 0 si no existe barra de destino
    double open_target_today = iOpen(_Symbol, PERIOD_M1, bar_at_target_today);
    if (open_target_today == 0) return 0; // Ningún precio válido
    
    // Calcular sigma basado en los últimos 14 días
    double sum_moves = 0;
    int valid_days = 0;
    for (int i = 1; i <= 14; i++) {
        datetime day_start = iTime(_Symbol, PERIOD_D1, i);
        int bar_at_target = getBarShiftForTime(day_start, target_hour, target_min);
        int bar_at_HHMM = getBarShiftForTime(day_start, current_hour, current_min);
        if (bar_at_target < 0 || bar_at_HHMM < 0) continue; // Saltar si no existen barras
        double open_target = iOpen(_Symbol, PERIOD_M1, bar_at_target);
        double close_HHMM = iClose(_Symbol, PERIOD_M1, bar_at_HHMM);
        if (open_target == 0) continue; // Saltar si no hay precio de apertura válido
        double move = MathAbs(close_HHMM / open_target - 1);
        sum_moves += move;
        valid_days++;
    }
    if (valid_days == 0) return 0; // Devuelve 0 si no hay datos válidos
    double sigma = sum_moves / valid_days;
    
    // Calcular la banda superior
    double upper_band = open_target_today * (1 + sigma);
    
    // Traza un punto azul en el nivel superior de la banda
    string obj_name = "UpperBand_" + TimeToString(current_time, TIME_DATE|TIME_MINUTES|TIME_SECONDS);
    ObjectCreate(0, obj_name, OBJ_ARROW, 0, current_time, upper_band);
    ObjectSetInteger(0, obj_name, OBJPROP_ARROWCODE, 159); // Símbolo de punto
    ObjectSetInteger(0, obj_name, OBJPROP_COLOR, clrBlue);
    ObjectSetInteger(0, obj_name, OBJPROP_WIDTH, 2);
    
    return upper_band;
}

//+------------------------------------------------------------------+
//| Obtener el valor de la banda inferior de Concretum|
//+------------------------------------------------------------------+
double getLowerBand(int target_hour = 17, int target_min = 30) {
    // Obtener la hora de la barra actual
    datetime current_time = iTime(_Symbol, PERIOD_CURRENT, 0);
    MqlDateTime current_dt;
    TimeToStruct(current_time, current_dt);
    int current_hour = current_dt.hour;
    int current_min = current_dt.min;
    
    // Buscar el precio de apertura de hoy a la hora objetivo (por ejemplo, 17:30 hora del servidor)
    datetime today_start = iTime(_Symbol, PERIOD_D1, 0);
    int bar_at_target_today = getBarShiftForTime(today_start, target_hour, target_min);
    if (bar_at_target_today < 0) return 0; // Devuelve 0 si no existe barra de destino
    double open_target_today = iOpen(_Symbol, PERIOD_M1, bar_at_target_today);
    if (open_target_today == 0) return 0; // Ningún precio válido
    
    // Calcular sigma basado en los últimos 14 días
    double sum_moves = 0;
    int valid_days = 0;
    for (int i = 1; i <= 14; i++) {
        datetime day_start = iTime(_Symbol, PERIOD_D1, i);
        int bar_at_target = getBarShiftForTime(day_start, target_hour, target_min);
        int bar_at_HHMM = getBarShiftForTime(day_start, current_hour, current_min);
        if (bar_at_target < 0 || bar_at_HHMM < 0) continue; // Saltar si no existen barras
        double open_target = iOpen(_Symbol, PERIOD_M1, bar_at_target);
        double close_HHMM = iClose(_Symbol, PERIOD_M1, bar_at_HHMM);
        if (open_target == 0) continue; // Saltar si no hay precio de apertura válido
        double move = MathAbs(close_HHMM / open_target - 1);
        sum_moves += move;
        valid_days++;
    }
    if (valid_days == 0) return 0; // Devuelve 0 si no hay datos válidos
    double sigma = sum_moves / valid_days;
    
    // Calcular la banda inferior
    double lower_band = open_target_today * (1 - sigma);
    
    // Traza un punto rojo en el nivel inferior de la banda
    string obj_name = "LowerBand_" + TimeToString(current_time, TIME_DATE|TIME_MINUTES|TIME_SECONDS);
    ObjectCreate(0, obj_name, OBJ_ARROW, 0, current_time, lower_band);
    ObjectSetInteger(0, obj_name, OBJPROP_ARROWCODE, 159); // Símbolo de punto
    ObjectSetInteger(0, obj_name, OBJPROP_COLOR, clrRed);
    ObjectSetInteger(0, obj_name, OBJPROP_WIDTH, 2);
    
    return lower_band;
}

Cambiar la hora del cálculo podría ser una manera de optimizar la estrategia más. :)

 
Zhuo Kai Chen #:

OMG, no puedo creer que me perdí esto. Debería ser:

Lo siento sinceramente por el error descuidado. Gracias por leer tan atentamente y señalarlo.

No te preocupes, ya he fusionado el mercado abierto y cerrado en una sola función.

bool MarketState()
{
   MqlDateTime structTime;
   TimeCurrent(structTime);
   structTime.sec = 0;
   structTime.hour = startHour;
   structTime.min = startMinute; 
   datetime timeStart = StructToTime(structTime);
   structTime.hour = endHour;
   structTime.min = endMinute;   
   datetime timeEnd = StructToTime(structTime);
   if(TimeCurrent() >= timeStart && TimeCurrent() < timeEnd)return true;
   else return false;
}


Una cosa más: Utilizas los datos OHLC del broker para el backtesting, sin retraso. Esos backtests parecen un poco optimistas comparados con los backtests hechos con datos reales con retardo aleatorio por deslizamiento y recotizaciones.

Gracias de nuevo por sus esfuerzos.

 
Digitus #:

No te preocupes, ya he fusionado el mercado abierto y cerrado en una sola función.


Una cosa más: Utilizas los datos OHLC del broker para el backtesting, sin retraso. Esos backtests parecen un poco optimistas en comparación con los backtests realizados con datos reales de tick con retardo aleatorio para deslizamiento y recotizaciones.

Gracias de nuevo por sus esfuerzos.

¡Bien hecho en su modificación! He actualizado todo el código en mi Github.

Para su preocupación, la lógica de negociación se produce cada nueva barra y no implica movimiento de garrapatas. Además, el tiempo medio de retención es como unas pocas horas, que creo que no hará deslizamiento problema significativo. Yo diría que muy pocos corredores proporcionan datos reales de garrapatas durante más de 5 años, y 1 min OHLC es suficiente.

 
Gran artículo