112 lines
4.5 KiB
Text
112 lines
4.5 KiB
Text
//+------------------------------------------------------------------+
| |||
//| 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; i<FVGLookback; i++){
| |||
double prevHigh = c[i].high, prevLow = c[i].low;
| |||
double midHigh = c[i-1].high, midLow = c[i-1].low;
| |||
double nextHigh = c[i-2].high, nextLow = c[i-2].low;
| |||
| |||
if(direction<0){ // short: hueco bajista (prevHigh < nextLow)
| |||
if(prevHigh < nextLow){
| |||
fvgTop = nextLow; fvgBottom = prevHigh; return true;
| |||
}
| |||
} else if(direction>0){ // 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 <Trade/Trade.mqh>
| |||
CTrade trade;
| |||
| |||
int OnInit(){ return(INIT_SUCCEEDED); }
| |||
void OnTick(){ TryEntry(); }
|