ICTLibraryEasy/Examples/Benchmark/OtherCode/Code6.mq5

626 lines
42 KiB
MQL5
Raw Permalink Normal View History

2026-01-14 07:41:55 -05:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| FVG_Detector_EA.mq5 |
//| Fair Value Gap Detection Tool |
//| Professional Smart Money Concepts Expert |
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
#property copyright "FVG Detector"
#property version "1.00"
2026-01-14 07:41:55 -05:00
#property strict
2026-05-25 11:41:23 -05:00
#property description "High-performance FVG detector. Visualization only. No trading."
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "..\\Utils\\MetricSaver.mqh"
2026-05-25 11:41:23 -05:00
/* Codigo hecho por ia Claude Opus 4.7 (best ai today 25/05/2026)
Desarrollo de EA MT5 (MQL5) para detecci<EFBFBD>n y dibujo de FVG
Objetivo
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
Necesito un Expert Advisor (EA) para MetaTrader 5, desarrollado en MQL5, cuya <EFBFBD>nica funci<EFBFBD>n sea detectar, dibujar y gestionar autom<EFBFBD>ticamente los Fair Value Gaps (FVG) en el gr<EFBFBD>fico.
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
No debe abrir operaciones ni ejecutar l<EFBFBD>gica de trading. Debe comportarse como un sistema visual de detecci<EFBFBD>n, similar a un indicador, pero implementado como EA.
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
Requerimientos funcionales
1. Detecci<EFBFBD>n de FVG
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
El EA debe detectar autom<EFBFBD>ticamente todos los Fair Value Gaps (FVG) que se vayan formando en el gr<EFBFBD>fico.
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
2. Dibujado visual
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
Cada FVG detectado debe representarse visualmente mediante:
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
Un rect<EFBFBD>ngulo que cubra toda la zona del FVG.
Una l<EFBFBD>nea horizontal central ubicada exactamente en el midpoint del gap (size / 2).
3. Mitigaci<EFBFBD>n
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
El EA debe detectar cu<EFBFBD>ndo un FVG ha sido mitigado (precio toca o invalida la zona, segun esta logica simple:
para alcitas: top > low (rectangulo)
para bajistas: high > bottom (rectangulo))
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
Cuando esto ocurra:
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
El FVG debe marcarse como mitigado.
Debe eliminarse autom<EFBFBD>ticamente del gr<EFBFBD>fico.
Tambi<EFBFBD>n deben eliminarse sus objetos asociados (l<EFBFBD>nea central, rect<EFBFBD>ngulo, etc.).
4. Multi-timeframe
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
Debe permitirme seleccionar el timeframe sobre el cual calcular los FVG, independientemente del timeframe del gr<EFBFBD>fico actual.
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
Ejemplo:
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
Calcular FVG en H1 mientras estoy viendo M5.
Par<EFBFBD>metros configurables
El EA debe exponer inputs configurables para:
Timeframe
Timeframe de c<EFBFBD>lculo de FVG.
Apariencia visual
Color del rect<EFBFBD>ngulo FVG bullish.
Color del rect<EFBFBD>ngulo FVG bearish.
Color de la l<EFBFBD>nea central.
Estilo de l<EFBFBD>nea (ENUM_LINE_STYLE).
Grosor de l<EFBFBD>nea.
Transparencia del rect<EFBFBD>ngulo (si aplica).
Si mostrar u ocultar la l<EFBFBD>nea central.
Comportamiento
Activar/desactivar eliminaci<EFBFBD>n autom<EFBFBD>tica al mitigarse.
M<EFBFBD>ximo n<EFBFBD>mero de FVG activos a mantener en memoria/gr<EFBFBD>fico.
Requisitos de rendimiento (MUY IMPORTANTE)
La prioridad principal es m<EFBFBD>xima velocidad y optimizaci<EFBFBD>n.
Necesito que el EA est<EFBFBD> dise<EFBFBD>ado con enfoque de alto rendimiento.
Reglas de optimizaci<EFBFBD>n:
Debe ejecutarse solo en nueva vela (new bar detection).
No necesito procesamiento tick-by-tick.
Nada debe recalcularse en cada tick innecesariamente.
Debe minimizar:
uso de memoria,
llamadas innecesarias a funciones,
creaci<EFBFBD>n/destrucci<EFBFBD>n excesiva de objetos,
b<EFBFBD>squedas repetitivas en arrays o estructuras.
Reutilizar datos/cache siempre que sea posible.
Evitar loops completos sobre hist<EFBFBD>rico innecesario.
Debe estar preparado para manejar muchos FVG sin degradar rendimiento.
Dise<EFBFBD>o enfocado en bajo overhead gr<EFBFBD>fico.
Arquitectura y c<EFBFBD>digo
Puedes elegir la arquitectura que consideres m<EFBFBD>s eficiente:
Programaci<EFBFBD>n procedural
OOP / clases
structs
arrays raw
buffers
cualquier enfoque h<EFBFBD>brido
La prioridad no es elegancia, sino MAXIMA velocidad posible y estabilidad.
Restricciones importantes
1. NO trading
El EA:
NO debe abrir <EFBFBD>rdenes.
NO debe cerrar <EFBFBD>rdenes.
NO debe modificar posiciones.
NO debe usar l<EFBFBD>gica de ejecuci<EFBFBD>n de mercado.
Solo visualizaci<EFBFBD>n y gesti<EFBFBD>n de FVG.
2. Logging / Debug
No quiero Print() innecesarios.
Opciones aceptables:
Sin logs.
O logs opcionales mediante #ifdef DEBUG.
La build final debe quedar limpia y SUPER RAPIDA.
3. Archivo <EFBFBD>nico
Necesito recibir todo en un solo archivo .mq5 de tipo Expert Advisor.
No usar:
.mqh externos
includes personalizados
archivos auxiliares
librer<EFBFBD>as separadas
Todo debe estar autocontenido en un <EFBFBD>nico EA.
Buenas pr<EFBFBD>cticas esperadas
Quiero que uses buenas pr<EFBFBD>cticas de MQL5 orientadas a performance:
manejo correcto de OnInit()
limpieza en OnDeinit()
ejecuci<EFBFBD>n optimizada en OnTick()
detecci<EFBFBD>n eficiente de nueva vela
naming consistente de objetos
eliminaci<EFBFBD>n segura de objetos
evitar memory leaks
control de duplicados de FVG
no redibujar objetos existentes
gesti<EFBFBD>n robusta de arrays/estructuras
Entregable
Genera el c<EFBFBD>digo completo de un EA en MQL5 (.mq5) que cumpla todo lo anterior.
Debe ser:
estable,
altamente optimizado,
f<EFBFBD>cil de mantener,
r<EFBFBD>pido incluso con muchos FVG,
y centrado exclusivamente en dibujo/gesti<EFBFBD>n de FVG.
Empieza directamente generando el c<EFBFBD>digo completo del EA.
*/
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Inputs |
//+------------------------------------------------------------------+
input group "=== Timeframe ==="
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; // Timeframe de c<EFBFBD>lculo
input group "=== Apariencia Visual ==="
input color InpBullColor = clrDodgerBlue; // Color FVG alcista
input color InpBearColor = clrOrangeRed; // Color FVG bajista
input color InpMidLineColor = clrGold; // Color l<EFBFBD>nea central
input ENUM_LINE_STYLE InpLineStyle = STYLE_DOT; // Estilo de l<EFBFBD>nea
input int InpLineWidth = 1; // Grosor de l<EFBFBD>nea
input bool InpFillRectangle = true; // Rellenar rect<EFBFBD>ngulo
input bool InpRectBack = true; // Rect<EFBFBD>ngulo en fondo
input bool InpShowMidLine = true; // Mostrar l<EFBFBD>nea central
input group "=== Comportamiento ==="
input bool InpRemoveOnMitig = true; // Eliminar al mitigarse
input int InpMaxActiveFVG = 200; // M<EFBFBD>x. FVG activos
input int InpScanInitialBars = 500; // Barras a escanear al inicio
input group "=== Identificaci<00>n ==="
input string InpObjPrefix = "FVG_"; // Prefijo objetos
input long InpMagic = 20260101; // Identificador <EFBFBD>nico
//+------------------------------------------------------------------+
//| Estructura compacta para FVG activo |
//+------------------------------------------------------------------+
struct FVG
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
double top; // Borde superior del gap
double bottom; // Borde inferior del gap
double mid; // Punto medio precalculado
datetime time_start; // Tiempo barra inicio del rect<EFBFBD>ngulo
datetime time_end; // Tiempo barra fin (se extiende)
long id; // ID <EFBFBD>nico
bool bullish; // true=alcista, false=bajista
};
//+------------------------------------------------------------------+
//| Variables globales |
//+------------------------------------------------------------------+
FVG g_fvgs[]; // Array din<EFBFBD>mico de FVG activos
int g_fvg_count = 0; // Conteo l<EFBFBD>gico (puede ser <= ArraySize)
long g_next_id = 0; // Generador de IDs
datetime g_last_bar_time = 0; // Para detecci<EFBFBD>n de nueva vela
string g_prefix; // Prefijo cacheado
int g_prefix_len = 0; // Longitud cacheada
ENUM_TIMEFRAMES g_tf; // Timeframe efectivo
long g_chart_id = 0; // Chart ID cacheado
// CORRECION por mi parte (LEO) no se puede hacer esto asi que hare el array dinamico no hay de otra...
// Los arrays estaticos no pueden ser set "set as series"
// Buffers reutilizables para evitar reallocs en cada nueva barra
MqlRates g_rates[]; // Solo necesitamos 3 barras para detectar FVG
//+------------------------------------------------------------------+
//| Helpers de naming (inline) |
//+------------------------------------------------------------------+
string MakeRectName(const long id)
{
return g_prefix + "R_" + IntegerToString(id);
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
string MakeLineName(const long id)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
return g_prefix + "L_" + IntegerToString(id);
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Crear objetos gr<EFBFBD>ficos para un FVG |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void DrawFVG(const FVG &f)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
const string rname = MakeRectName(f.id);
const color col = f.bullish ? InpBullColor : InpBearColor;
if(ObjectCreate(g_chart_id, rname, OBJ_RECTANGLE, 0, f.time_start, f.top, f.time_end, f.bottom))
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
ObjectSetInteger(g_chart_id, rname, OBJPROP_COLOR, col);
ObjectSetInteger(g_chart_id, rname, OBJPROP_FILL, InpFillRectangle);
ObjectSetInteger(g_chart_id, rname, OBJPROP_BACK, InpRectBack);
ObjectSetInteger(g_chart_id, rname, OBJPROP_SELECTABLE,false);
ObjectSetInteger(g_chart_id, rname, OBJPROP_SELECTED, false);
ObjectSetInteger(g_chart_id, rname, OBJPROP_HIDDEN, true);
ObjectSetInteger(g_chart_id, rname, OBJPROP_WIDTH, 1);
ObjectSetInteger(g_chart_id, rname, OBJPROP_STYLE, STYLE_SOLID);
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
if(InpShowMidLine)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
const string lname = MakeLineName(f.id);
if(ObjectCreate(g_chart_id, lname, OBJ_TREND, 0, f.time_start, f.mid, f.time_end, f.mid))
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
ObjectSetInteger(g_chart_id, lname, OBJPROP_COLOR, InpMidLineColor);
ObjectSetInteger(g_chart_id, lname, OBJPROP_STYLE, InpLineStyle);
ObjectSetInteger(g_chart_id, lname, OBJPROP_WIDTH, InpLineWidth);
ObjectSetInteger(g_chart_id, lname, OBJPROP_RAY_RIGHT, false);
ObjectSetInteger(g_chart_id, lname, OBJPROP_RAY_LEFT, false);
ObjectSetInteger(g_chart_id, lname, OBJPROP_SELECTABLE, false);
ObjectSetInteger(g_chart_id, lname, OBJPROP_SELECTED, false);
ObjectSetInteger(g_chart_id, lname, OBJPROP_HIDDEN, true);
ObjectSetInteger(g_chart_id, lname, OBJPROP_BACK, false);
2026-01-14 07:41:55 -05:00
}
}
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Extender el tiempo final del rect<EFBFBD>ngulo y la l<EFBFBD>nea |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void ExtendFVG(const FVG &f, const datetime new_end)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
const string rname = MakeRectName(f.id);
ObjectSetInteger(g_chart_id, rname, OBJPROP_TIME, 1, new_end);
if(InpShowMidLine)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
const string lname = MakeLineName(f.id);
ObjectSetInteger(g_chart_id, lname, OBJPROP_TIME, 1, new_end);
2026-01-14 07:41:55 -05:00
}
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Eliminar objetos gr<EFBFBD>ficos asociados a un FVG |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void DeleteFVGObjects(const long id)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
ObjectDelete(g_chart_id, MakeRectName(id));
if(InpShowMidLine)
ObjectDelete(g_chart_id, MakeLineName(id));
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Remover FVG del array por <EFBFBD>ndice (swap con <EFBFBD>ltimo, O(1)) |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void RemoveFVGAt(const int idx)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
const int last = g_fvg_count - 1;
if(idx != last)
g_fvgs[idx] = g_fvgs[last];
g_fvg_count--;
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Eliminar todos los FVG y limpiar gr<EFBFBD>fico |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void ClearAllFVG()
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
for(int i = 0; i < g_fvg_count; i++)
DeleteFVGObjects(g_fvgs[i].id);
g_fvg_count = 0;
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Eliminar TODOS los objetos del EA del gr<EFBFBD>fico (limpieza total) |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void CleanupChartObjects()
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
ObjectsDeleteAll(g_chart_id, g_prefix);
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Agregar un nuevo FVG al array (gestionando capacidad y m<EFBFBD>ximo) |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void AddFVG(const double top, const double bottom, const datetime ts,
const datetime te, const bool bullish)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
// Si se alcanza el m<EFBFBD>ximo, eliminar el m<EFBFBD>s antiguo (<EFBFBD>ndice 0)
if(g_fvg_count >= InpMaxActiveFVG)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
DeleteFVGObjects(g_fvgs[0].id);
// Desplazar (shift)  solo cuando llegamos al l<EFBFBD>mite, no es hot path
for(int i = 1; i < g_fvg_count; i++)
g_fvgs[i - 1] = g_fvgs[i];
g_fvg_count--;
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
// Asegurar capacidad sin reallocar en cada inserci<EFBFBD>n
if(ArraySize(g_fvgs) <= g_fvg_count)
{
int new_size = ArraySize(g_fvgs) * 2;
if(new_size < 64) new_size = 64;
if(new_size > InpMaxActiveFVG) new_size = InpMaxActiveFVG;
ArrayResize(g_fvgs, new_size);
}
FVG f;
f.top = top;
f.bottom = bottom;
f.mid = (top + bottom) * 0.5;
f.time_start = ts;
f.time_end = te;
f.id = g_next_id++;
f.bullish = bullish;
g_fvgs[g_fvg_count++] = f;
DrawFVG(f);
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Comprobar mitigaci<EFBFBD>n de TODOS los FVG con la barra reci<EFBFBD>n cerrada|
//| L<EFBFBD>gica solicitada: |
//| alcista: bar.low <= fvg.top (precio entr<EFBFBD> desde arriba) |
//| bajista: bar.high >= fvg.bottom (precio entr<EFBFBD> desde abajo) |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void CheckMitigation(const double bar_high, const double bar_low)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
if(!InpRemoveOnMitig)
return;
// Recorrido inverso para borrar in-place con swap
for(int i = g_fvg_count - 1; i >= 0; i--)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
const FVG f = g_fvgs[i];
bool mitigated = false;
if(f.bullish)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
// FVG alcista: mitigado si el low de la barra entra en el gap
if(bar_low <= f.top)
mitigated = true;
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
else
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
// FVG bajista: mitigado si el high de la barra entra en el gap
if(bar_high >= f.bottom)
mitigated = true;
}
if(mitigated)
{
DeleteFVGObjects(f.id);
RemoveFVGAt(i);
2026-01-14 07:41:55 -05:00
}
}
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Extender el time_end de todos los FVG activos a la barra actual |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void ExtendAllFVG(const datetime new_end)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
for(int i = 0; i < g_fvg_count; i++)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
if(g_fvgs[i].time_end != new_end)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
g_fvgs[i].time_end = new_end;
ExtendFVG(g_fvgs[i], new_end);
2026-01-14 07:41:55 -05:00
}
}
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Escaneo inicial de N barras hist<EFBFBD>ricas para sembrar FVG activos |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void InitialScan()
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
if(InpScanInitialBars < 3)
return;
int bars_avail = Bars(_Symbol, g_tf);
if(bars_avail < 3)
return;
int to_scan = InpScanInitialBars;
if(to_scan > bars_avail - 1)
to_scan = bars_avail - 1;
MqlRates rates[];
ArraySetAsSeries(rates, true);
int copied = CopyRates(_Symbol, g_tf, 1, to_scan, rates); // descartamos barra en formaci<EFBFBD>n
if(copied < 3)
return;
// rates[0] = barra cerrada m<EFBFBD>s reciente
// Recorremos desde la m<EFBFBD>s antigua a la m<EFBFBD>s reciente para mantener orden cronol<EFBFBD>gico de IDs
// Triple cronol<EFBFBD>gico: oldest=rates[k+2], middle=rates[k+1], newest=rates[k]
const datetime extend_to = rates[0].time;
for(int k = copied - 3; k >= 0; k--)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
const MqlRates b0 = rates[k]; // newest del triple
const MqlRates b1 = rates[k + 1]; // middle
const MqlRates b2 = rates[k + 2]; // oldest
bool bullish = false, bearish = false;
double top = 0, bottom = 0;
if(b0.low > b2.high)
{
bullish = true;
top = b0.low;
bottom = b2.high;
}
else if(b0.high < b2.low)
{
bearish = true;
top = b2.low;
bottom = b0.high;
}
if(!bullish && !bearish)
2026-01-14 07:41:55 -05:00
continue;
2026-05-25 11:41:23 -05:00
// Verificar si ya est<EFBFBD> mitigado por alguna barra posterior (entre b0 y la barra actual)
// Si est<EFBFBD> mitigado, no lo a<EFBFBD>adimos.
bool already_mitigated = false;
for(int m = k - 1; m >= 0; m--)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
if(bullish)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
if(rates[m].low <= top)
{
already_mitigated = true;
break;
}
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
else
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
if(rates[m].high >= bottom)
{
already_mitigated = true;
break;
}
2026-01-14 07:41:55 -05:00
}
}
2026-05-25 11:41:23 -05:00
if(already_mitigated)
continue;
AddFVG(top, bottom, b1.time, extend_to, bullish);
2026-01-14 07:41:55 -05:00
}
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Procesamiento de nueva barra cerrada |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void ProcessNewBar()
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
// Necesitamos las 3 <EFBFBD>ltimas barras CERRADAS: <EFBFBD>ndices 1, 2, 3 (0 = en formaci<EFBFBD>n)
// Pero como solo procesamos en nueva vela, tambi<EFBFBD>n validamos mitigaci<EFBFBD>n con la
// reci<EFBFBD>n cerrada (<EFBFBD>ndice 1).
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
ArraySetAsSeries(g_rates, true);
int copied = CopyRates(_Symbol, g_tf, 1, 3, g_rates);
if(copied < 3)
return;
// g_rates[0] = barra reci<EFBFBD>n cerrada (la m<EFBFBD>s reciente cerrada)
// g_rates[1] = anterior
// g_rates[2] = pen<EFBFBD>ltima anterior
const MqlRates b0 = g_rates[0]; // newest closed
const MqlRates b1 = g_rates[1];
const MqlRates b2 = g_rates[2];
// 1) Comprobar mitigaci<EFBFBD>n con la barra reci<EFBFBD>n cerrada
CheckMitigation(b0.high, b0.low);
// 2) Extender visualmente todos los FVG activos hasta el tiempo de la barra reci<EFBFBD>n cerrada
ExtendAllFVG(b0.time);
// 3) Detectar nuevo FVG con el triple (b2, b1, b0) cronol<EFBFBD>gico
bool bullish = false, bearish = false;
double top = 0, bottom = 0;
if(b0.low > b2.high)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
bullish = true;
top = b0.low;
bottom = b2.high;
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
else if(b0.high < b2.low)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
bearish = true;
top = b2.low;
bottom = b0.high;
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
if(bullish || bearish)
AddFVG(top, bottom, b1.time, b0.time, bullish);
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| Detecci<EFBFBD>n eficiente de nueva vela (en el TF de c<EFBFBD>lculo) |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
bool IsNewBar()
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
datetime t[1];
if(CopyTime(_Symbol, g_tf, 0, 1, t) != 1)
return false;
if(t[0] != g_last_bar_time)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
g_last_bar_time = t[0];
return true;
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
return false;
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
//+------------------------------------------------------------------+
//| OnInit |
//+------------------------------------------------------------------+
int OnInit()
{
CMetricsSave::Start(FILE_CODE6);
2026-01-14 07:41:55 -05:00
2026-05-25 11:41:23 -05:00
g_chart_id = ChartID();
g_tf = (InpTimeframe == PERIOD_CURRENT) ? (ENUM_TIMEFRAMES)Period() : InpTimeframe;
g_prefix = InpObjPrefix + IntegerToString(InpMagic) + "_";
g_prefix_len= StringLen(g_prefix);
// Reservar capacidad inicial razonable para evitar reallocaciones tempranas
int initial_cap = 64;
if(initial_cap > InpMaxActiveFVG) initial_cap = InpMaxActiveFVG;
ArrayResize(g_fvgs, initial_cap);
g_fvg_count = 0;
g_next_id = 0;
// Limpieza de objetos antiguos por seguridad
CleanupChartObjects();
// Inicializar <EFBFBD>ltima barra para evitar disparar en el primer tick
datetime t[1];
if(CopyTime(_Symbol, g_tf, 0, 1, t) == 1)
g_last_bar_time = t[0];
// Escaneo hist<EFBFBD>rico inicial (siembra)
InitialScan();
ChartRedraw(g_chart_id);
return INIT_SUCCEEDED;
}
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
//| OnDeinit |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void OnDeinit(const int reason)
2026-01-14 07:41:55 -05:00
{
2026-05-25 11:41:23 -05:00
// Liberar gr<EFBFBD>ficamente todos los objetos creados
CleanupChartObjects();
// Liberar memoria del array
ArrayFree(g_fvgs);
g_fvg_count = 0;
ChartRedraw(g_chart_id);
CMetricsSave::Destroy();
2026-01-14 07:41:55 -05:00
}
2026-05-25 11:41:23 -05:00
//+------------------------------------------------------------------+
//| OnTick  solo trabaja en nueva barra |
2026-01-14 07:41:55 -05:00
//+------------------------------------------------------------------+
2026-05-25 11:41:23 -05:00
void OnTick()
{
if(!IsNewBar())
return;
ProcessNewBar();
ChartRedraw(g_chart_id);
}