//+------------------------------------------------------------------+ //| SMC_FVG_Liquidity_EA.mq5 | //+------------------------------------------------------------------+ #property strict input double RiskPct = 0.5; // % riesgo por trade input ENUM_TIMEFRAMES HTF = PERIOD_H1; // Marco para bias input ENUM_TIMEFRAMES LTF = PERIOD_M5; // Marco para FVG/entrada input int FVGLookback = 100; // Velas a escanear LTF input int StopBufferPoints = 30; // Colchón extra para SL input bool AllowLong = true; input bool AllowShort = true; // --- utilidades double GetAccountRiskValue(){ return(AccountInfoDouble(ACCOUNT_BALANCE) * RiskPct/100.0); } double PipToPoints(double pips){ return(pips * (_Point==0.00001 || _Point==0.001 ? 10 : 1)); } // --- bias HTF simple (puedes mejorar con BOS/CHoCH) int BiasHTF() { // 1 = alcista, -1 = bajista, 0 = neutro MqlRates r[]; if(!CopyRates(_Symbol, HTF, 0, 200, r)) return 0; if(r[1].close > r[1].open && r[2].close > r[2].open) return 1; if(r[1].close < r[1].open && r[2].close < r[2].open) return -1; return 0; } // --- detección básica de FVG (tres velas): gap entre vela1.high y vela3.low (ventas) o vela1.low y vela3.high (compras) bool FindFVG(int direction, double &fvgTop, double &fvgBottom){ MqlRates c[]; if(!CopyRates(_Symbol, LTF, 0, FVGLookback, c)) return false; ArraySetAsSeries(c,true); for(int i=2; i0){ // long: hueco alcista (prevLow > nextHigh) if(prevLow > nextHigh){ fvgTop = prevLow; fvgBottom = nextHigh; return true; } } } return false; } // --- barrida simple: rompe el máximo/mínimo previo reciente y regresa bool LiquiditySweep(int direction){ MqlRates c[]; if(!CopyRates(_Symbol, LTF, 0, 50, c)) return false; ArraySetAsSeries(c,true); double recentHigh = c[10].high, recentLow = c[10].low; for(int i=1;i<=10;i++){ recentHigh = MathMax(recentHigh, c[i].high); recentLow = MathMin(recentLow, c[i].low); } if(direction<0){ // short: barrió arriba y vuelve debajo return (iHigh(_Symbol,LTF,1) > recentHigh && Close[0] < recentHigh); } else if(direction>0){ // long: barrió abajo y vuelve encima return (iLow(_Symbol,LTF,1) < recentLow && Close[0] > recentLow); } return false; } // --- tamaño de lote por SL en puntos double CalcLotBySL(double slPrice){ double risk = GetAccountRiskValue(); double slPoints = MathAbs((slPrice - SymbolInfoDouble(_Symbol,SYMBOL_BID))/_Point); double tickValue = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE); double tickSize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE); if(slPoints<=0 || tickValue<=0 || tickSize<=0) return 0.0; double valuePerPointPerLot = tickValue / (tickSize/_Point); double lot = risk / (slPoints * valuePerPointPerLot); double minLot = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); double step = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); // normaliza lot = MathMax(minLot, MathFloor(lot/step)*step); return lot; } // --- ejecución void TryEntry(){ int bias = BiasHTF(); if(bias==0) return; double fvgTop, fvgBottom; if(!FindFVG(bias, fvgTop, fvgBottom)) return; if(!LiquiditySweep(bias)) return; // definimos precio de entrada en el borde del FVG double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID); if(bias<0 && AllowShort){ double entry = fvgBottom; // vender en rebote al borde inferior del FVG bajista double sl = fvgTop + StopBufferPoints*_Point; double lot = CalcLotBySL(sl); if(lot>0 && bid>=entry){ // condición simple, podrías usar órdenes pendientes trade.Sell(lot,_Symbol,bid,sl,0,"SMC short"); } } if(bias>0 && AllowLong){ double entry = fvgTop; // comprar en rebote al borde superior del FVG alcista double sl = fvgBottom - StopBufferPoints*_Point; double lot = CalcLotBySL(sl); if(lot>0 && ask<=entry){ trade.Buy(lot,_Symbol,ask,sl,0,"SMC long"); } } } #include CTrade trade; int OnInit(){ return(INIT_SUCCEEDED); } void OnTick(){ TryEntry(); }