Os dejo por aquí el último indicdor que he preparado y con el que actualmente estoy testeando la estrategia del DAX.
Es algo muy sencillo y limpio, simplemente marca el rango mínimo y maximo de la apertura del mercado desde al noche hasta las 8:00 am hora española (GMT +2) que en MT5 son las 6:00 am UTC, y tambien marcará, si es que son diferentes, el máximo y el mínimo entre las 8:00 am y 9:00 am hora española, que en MT5 son entre las 6:00 am y 7:am UTC.
Todos llevan su etiqueta. Obviamente, hasta las 9 se mueven, como si fueran soportes y resistencias dinámicos, pero a partir de las 9 se quedan fijos (porque a mi solo me interesa ese rango horario).
Tambien calcula el VWAP: como no hay un volumen real de contratos, lo hace en base a los ticks, pero la correlación es bastante buena, simplemente como soporte visual.
Y por último, lleva también una linea que marca el 50% del rango. ¿Por que?
Es muy normal en este indice, que el precio justo en apertura busque una zona de liquidez, barriendo e inmediatamente girandose, para despues revertir y continuar con el movimiento iniciado en la madrugada. Esa linea del 50% se puede usar como gatillo de entrada a favor del movimiento.

No puedo decir que lo haga a diario, pero la probalidad en este índice es alta. En este día (21 de agosto) el 50% del rango funciona como soporte toda la madrugada, es roto con violencia en la apertura, el precio se va a buscar el mínimo relativo de la sesión anterior y retoma su direción inicial. Podeis llamarlo manipulación, liquidity pool, barrido de SL, toma de Sell Stops pendientes… me da igual, no es el objeto de esta entrada.
Puedes buscar en el DAX varios ejemplos de estos a la semana.
La entrada ya la buscais cada uno con su estategia 😀
//+------------------------------------------------------------------+
//| Apertura DAX.mq5 |
//| Copyright 2026, AI Assistant, Raulito 073 |
//+------------------------------------------------------------------+
#property copyright "Raulito073 Copyright 2026"
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots 6
// --- Configuración Visual de Líneas ---
#property indicator_label1 "VWAP Diario"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDarkOrange
#property indicator_style1 STYLE_DASH
#property indicator_label2 "Max Asia (00:00-06:00)"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrLightCoral
#property indicator_style2 STYLE_DOT
#property indicator_label3 "Min Asia (00:00-06:00)"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrOrange
#property indicator_style3 STYLE_DOT
#property indicator_label4 "Asia 50% (00:00-06:00)"
#property indicator_type4 DRAW_LINE
#property indicator_color4 clrFuchsia
#property indicator_style4 STYLE_DOT
#property indicator_width4 1
#property indicator_label5 "Max Pre-Euro (00:00-07:00)"
#property indicator_type5 DRAW_LINE
#property indicator_color5 clrGreen
#property indicator_style5 STYLE_DOT
#property indicator_label6 "Min Pre-Euro (00:00-07:00)"
#property indicator_type6 DRAW_LINE
#property indicator_color6 clrRed
#property indicator_style6 STYLE_DOT
// Buffers del indicador
double vwapDiarioBuffer[];
double max6Buffer[];
double min6Buffer[];
double mid6Buffer[];
double max7Buffer[];
double min7Buffer[];
// Estructura para ordenar y posicionar etiquetas sin pisarse
struct TEtiqueta {
string name;
string texto;
double precio;
color col;
};
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, vwapDiarioBuffer, INDICATOR_DATA);
SetIndexBuffer(1, max6Buffer, INDICATOR_DATA);
SetIndexBuffer(2, min6Buffer, INDICATOR_DATA);
SetIndexBuffer(3, mid6Buffer, INDICATOR_DATA);
SetIndexBuffer(4, max7Buffer, INDICATOR_DATA);
SetIndexBuffer(5, min7Buffer, INDICATOR_DATA);
IndicatorSetString(INDICATOR_SHORTNAME, "apertura DAX");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObjectsDeleteAll(0, "Asia_Text_");
ObjectsDeleteAll(0, "Asia_VLine");
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(rates_total < 10) return(0);
int start = 0;
datetime limitTime = time[rates_total - 1] - (30 * 86400);
double diarioSumPV = 0.0; long diarioSumV = 0; int lastDay = -1;
for(int i = start; i < rates_total; i++)
{
datetime barTime = time[i];
if(barTime < limitTime)
{
vwapDiarioBuffer[i] = close[i];
max6Buffer[i] = EMPTY_VALUE; min6Buffer[i] = EMPTY_VALUE; mid6Buffer[i] = EMPTY_VALUE;
max7Buffer[i] = EMPTY_VALUE; min7Buffer[i] = EMPTY_VALUE;
continue;
}
MqlDateTime dt;
TimeToStruct(barTime, dt);
if(dt.day != lastDay)
{
diarioSumPV = 0.0; diarioSumV = 0;
lastDay = dt.day;
}
// =================================================================
// 1. CÁLCULO DE NIVELES FIJOS (0-6 y 0-7)
// =================================================================
int dayStartIndex = i;
while(dayStartIndex >= 0)
{
MqlDateTime tDt; TimeToStruct(time[dayStartIndex], tDt);
if(tDt.day != dt.day) { dayStartIndex++; break; }
if(dayStartIndex == 0) break;
dayStartIndex--;
}
double tempMax6 = 0, tempMin6 = 999999;
double tempMax7 = 0, tempMin7 = 999999;
bool count6 = false, count7 = false;
for(int k = dayStartIndex; k < rates_total; k++)
{
MqlDateTime kDt; TimeToStruct(time[k], kDt);
if(kDt.day != dt.day) break;
// RANGO 00:00 A 05:59
if(kDt.hour >= 0 && kDt.hour < 6)
{
if(high[k] > tempMax6) tempMax6 = high[k];
if(low[k] < tempMin6) tempMin6 = low[k];
count6 = true;
}
// RANGO 00:00 A 06:59 (Tu modificación corregida)
if(kDt.hour >= 0 && kDt.hour < 7)
{
if(high[k] > tempMax7) tempMax7 = high[k];
if(low[k] < tempMin7) tempMin7 = low[k];
count7 = true;
}
}
if(count6)
{
max6Buffer[i] = tempMax6;
min6Buffer[i] = tempMin6;
mid6Buffer[i] = tempMin6 + ((tempMax6 - tempMin6) / 2.0);
}
else { max6Buffer[i] = EMPTY_VALUE; min6Buffer[i] = EMPTY_VALUE; mid6Buffer[i] = EMPTY_VALUE; }
if(count7) { max7Buffer[i] = tempMax7; min7Buffer[i] = tempMin7; }
else { max7Buffer[i] = EMPTY_VALUE; min7Buffer[i] = EMPTY_VALUE; }
// =================================================================
// 2. CÁLCULO DE VWAP DIARIO
// =================================================================
double typicalPriceDiario = (high[i] + low[i] + close[i]) / 3.0;
diarioSumPV += typicalPriceDiario * tick_volume[i];
diarioSumV += tick_volume[i];
vwapDiarioBuffer[i] = (diarioSumV > 0) ? (diarioSumPV / (double)diarioSumV) : close[i];
}
// =================================================================
// 3. MATRIZ DE ETIQUETAS COLECTIVA Y ALGORITMO ANTISOLAPAMIENTO
// =================================================================
int lastIndex = rates_total - 1;
datetime lastBarTime = time[lastIndex];
TEtiqueta lista[6];
lista[0].name = "Asia_Text_Max6"; lista[0].texto = " Max Asia: " + DoubleToString(max6Buffer[lastIndex], _Digits); lista[0].precio = max6Buffer[lastIndex]; lista[0].col = clrLightCoral;
lista[1].name = "Asia_Text_Min6"; lista[1].texto = " Min Asia: " + DoubleToString(min6Buffer[lastIndex], _Digits); lista[1].precio = min6Buffer[lastIndex]; lista[1].col = clrOrange;
lista[2].name = "Asia_Text_Mid6"; lista[2].texto = " Asia 50%: " + DoubleToString(mid6Buffer[lastIndex], _Digits); lista[2].precio = mid6Buffer[lastIndex]; lista[2].col = clrFuchsia;
lista[3].name = "Asia_Text_Max7"; lista[3].texto = " Max Pre-Euro: " + DoubleToString(max7Buffer[lastIndex], _Digits); lista[3].precio = max7Buffer[lastIndex]; lista[3].col = clrGreen;
lista[4].name = "Asia_Text_Min7"; lista[4].texto = " Min Pre-Euro: " + DoubleToString(min7Buffer[lastIndex], _Digits); lista[4].precio = min7Buffer[lastIndex]; lista[4].col = clrRed;
lista[5].name = "Asia_Text_VwapD"; lista[5].texto = " VWAP Diario: " + DoubleToString(vwapDiarioBuffer[lastIndex], _Digits); lista[5].precio = vwapDiarioBuffer[lastIndex]; lista[5].col = clrDarkOrange;
// Método Bubble Sort: Ordenamos las etiquetas de mayor precio a menor precio
for(int m = 0; m < 5; m++) {
for(int n = m + 1; n < 6; n++) {
if(lista[m].precio < lista[n].precio) {
TEtiqueta temp = lista[m];
lista[m] = lista[n];
lista[n] = temp;
}
}
}
// Filtro de proximidad (Evita colisiones solapando verticalmente en base a píxeles simulados)
// Calculamos el umbral mínimo de separación en puntos del precio (aprox 12 píxeles de altura de fuente)
double chartMax = ChartGetDouble(0, CHART_PRICE_MAX);
double chartMin = ChartGetDouble(0, CHART_PRICE_MIN);
double umbralSeparacion = (chartMax - chartMin) * 0.025; // 2.5% de la altura visible del gráfico
for(int m = 1; m < 6; m++) {
if(lista[m].precio == EMPTY_VALUE || lista[m-1].precio == EMPTY_VALUE) continue;
// Si la etiqueta actual está demasiado pegada a la de arriba, la empujamos hacia abajo
if((lista[m-1].precio - lista[m].precio) < umbralSeparacion) {
lista[m].precio = lista[m-1].precio - umbralSeparacion;
}
}
// Dibujamos las etiquetas finales reubicadas matemáticamente
for(int m = 0; m < 6; m++) {
if(lista[m].precio <= 0 || lista[m].precio == EMPTY_VALUE) continue;
if(ObjectFind(0, lista[m].name) < 0) {
ObjectCreate(0, lista[m].name, OBJ_TEXT, 0, lastBarTime, lista[m].precio);
}
ObjectMove(0, lista[m].name, 0, lastBarTime, lista[m].precio);
ObjectSetString(0, lista[m].name, OBJPROP_TEXT, lista[m].texto);
ObjectSetInteger(0, lista[m].name, OBJPROP_COLOR, lista[m].col);
ObjectSetInteger(0, lista[m].name, OBJPROP_FONTSIZE, 9);
ObjectSetString(0, lista[m].name, OBJPROP_FONT, "Arial Bold");
ObjectSetInteger(0, lista[m].name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
}
// =================================================================
// 4. LÍNEAS VERTICALES DIARIAS A LAS 06:00 Y 07:00
// =================================================================
int vlineCount = 0;
string prevDay = "";
for(int i = rates_total - 1; i >= 0; i--)
{
MqlDateTime bDt;
TimeToStruct(time[i], bDt);
string key = IntegerToString(bDt.year) + "_" + IntegerToString(bDt.mon) + "_" + IntegerToString(bDt.day);
if(key != prevDay)
{
prevDay = key;
// Línea vertical a las 06:00
bDt.hour = 6; bDt.min = 0; bDt.sec = 0;
datetime t6 = StructToTime(bDt);
string n6 = "Asia_VLine6_" + key;
if(ObjectFind(0, n6) < 0)
ObjectCreate(0, n6, OBJ_VLINE, 0, t6, 0);
ObjectSetInteger(0, n6, OBJPROP_TIME, t6);
ObjectSetInteger(0, n6, OBJPROP_COLOR, clrLightCoral);
ObjectSetInteger(0, n6, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, n6, OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, n6, OBJPROP_BACK, false);
// Línea vertical a las 07:00
bDt.hour = 7;
datetime t7 = StructToTime(bDt);
string n7 = "Asia_VLine7_" + key;
if(ObjectFind(0, n7) < 0)
ObjectCreate(0, n7, OBJ_VLINE, 0, t7, 0);
ObjectSetInteger(0, n7, OBJPROP_TIME, t7);
ObjectSetInteger(0, n7, OBJPROP_COLOR, clrGreen);
ObjectSetInteger(0, n7, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, n7, OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, n7, OBJPROP_BACK, false);
vlineCount++;
if(vlineCount >= 30) break; // máximo 30 días hacia atrás
}
}
return(rates_total);
}
Queda así:

Saludos. Si te gusta, compartelo. El código es libre y puedes copiarlo y modificarlo a tu gusto.
Deja una respuesta