//+------------------------------------------------------------------+
//|                          Advanced Breakout EA (MT5)              |
//|         Full Version with SL/TP Modes, Trailing, Risk, etc.     |
//+------------------------------------------------------------------+
#property strict
#include <Trade/Trade.mqh>
CTrade trade;

//--- INPUTS
input int    Breakout_Lookback     = 20;
input ENUM_TIMEFRAMES Timeframe    = PERIOD_M15;
input int    EMA_Period            = 50;
input bool   UseRSI                = true;
input int    RSI_Period            = 14;
input double RSI_Buy_Level         = 55.0;
input double RSI_Sell_Level        = 45.0;

//--- Risk and SL
input double Risk_Percent          = 1.0;
input int    SL_Mode               = 1; // 1=Fixed, 2=ATR, 3=Breakout Candle, 4=Swing High/Low
input int    Fixed_SL              = 50;
input double ATR_Multiplier        = 1.5;
input int    ATR_Period            = 14;

//--- TP
input int    TP_Mode               = 1; // 1=RR TP, 2=Trailing
input double RR_Multiplier         = 2.0;

//--- Trailing Stop
input int    TrailingMode          = 1; // 1=Standard, 2=ATR
input int    Trailing_Stop         = 50;
input int    Trail_Start           = 30;
input double ATR_Trail_Multiplier  = 1.5;
input int    ATR_Trail_Period      = 14;

//--- Control
input int    Max_Open_Positions    = 1;
input uint   MagicNumber           = 123456;
input double Max_Daily_Drawdown_Percent = 5.0;

//--- Globals
double DayStartEquity;
bool   TradingPaused = false;
int    lastCheckDay;

int OnInit()
{
    DayStartEquity = AccountInfoDouble(ACCOUNT_EQUITY);
    MqlDateTime t;
    TimeToStruct(TimeLocal(), t);
    lastCheckDay = t.day;
    return(INIT_SUCCEEDED);
}

void OnTick()
{
    MqlDateTime t;
    TimeToStruct(TimeLocal(), t);
    if (t.day != lastCheckDay)
    {
        DayStartEquity = AccountInfoDouble(ACCOUNT_EQUITY);
        TradingPaused = false;
        lastCheckDay = t.day;
    }

    double equity = AccountInfoDouble(ACCOUNT_EQUITY);
    double maxDrawdownEquity = DayStartEquity * (1.0 - Max_Daily_Drawdown_Percent / 100.0);

    if (equity < maxDrawdownEquity && !TradingPaused)
    {
        CloseAllPositions();
        TradingPaused = true;
        Print("Daily drawdown limit reached. All positions closed.");
        return;
    }

    if (TradingPaused) return;

    if (PositionsTotalByMagic() >= Max_Open_Positions) return;

    string symbol = _Symbol;
    double ema = iMA(symbol, Timeframe, EMA_Period, 0, MODE_EMA, PRICE_CLOSE, 0);
    double close = iClose(symbol, Timeframe, 1);

    if (close > ema && NewBreakoutSignal(true))
        OpenTrade(true);
    else if (close < ema && NewBreakoutSignal(false))
        OpenTrade(false);
}

bool NewBreakoutSignal(bool isBuy)
{
    string symbol = _Symbol;
    double price = iClose(symbol, Timeframe, 1);
    double high = iHigh(symbol, Timeframe, iHighest(symbol, Timeframe, MODE_HIGH, Breakout_Lookback, 1));
    double low  = iLow(symbol, Timeframe, iLowest(symbol, Timeframe, MODE_LOW, Breakout_Lookback, 1));

    return (isBuy && price > high) || (!isBuy && price < low);
}

void OpenTrade(bool isBuy)
{
    string symbol = _Symbol;
    double entry = SymbolInfoDouble(symbol, SYMBOL_ASK);
    if (!isBuy) entry = SymbolInfoDouble(symbol, SYMBOL_BID);

    if (!PassRSIFilter(symbol, isBuy)) return;

    double slPrice = GetStopLossPrice(isBuy, entry, symbol);
    double tpPrice = (TP_Mode == 1) ? GetTakeProfitPrice(entry, slPrice, isBuy) : 0;
    double lotSize = CalculateLotSize(symbol, MathAbs(entry - slPrice) / _Point);

    trade.SetExpertMagicNumber(MagicNumber);
    if (TP_Mode == 1) trade.SetTakeProfit(tpPrice);

    if (isBuy)
        trade.Buy(lotSize, symbol, entry, slPrice, tpPrice);
    else
        trade.Sell(lotSize, symbol, entry, slPrice, tpPrice);
}

int PositionsTotalByMagic()
{
    int count = 0;
    for (int i = 0; i < PositionsTotal(); i++)
    {
        if (PositionGetTicket(i))
        {
            if ((ulong)PositionGetInteger(POSITION_MAGIC) == MagicNumber)
                count++;
        }
    }
    return count;
}

void CloseAllPositions()
{
    for (int i = PositionsTotal() - 1; i >= 0; i--)
    {
        if (PositionGetTicket(i))
        {
            if ((ulong)PositionGetInteger(POSITION_MAGIC) == MagicNumber)
            {
                string symbol = PositionGetString(POSITION_SYMBOL);
                trade.PositionClose(symbol);
            }
        }
    }
}

//--- Helpers

double GetATR(string symbol, ENUM_TIMEFRAMES tf, int period) {
    return iATR(symbol, tf, period, 0);
}

double GetStopLossPrice(bool isBuy, double entryPrice, string symbol) {
    double sl = 0;
    switch(SL_Mode) {
        case 1:
            sl = isBuy ? entryPrice - Fixed_SL * _Point : entryPrice + Fixed_SL * _Point;
            break;
        case 2: {
            double atr = GetATR(symbol, Timeframe, ATR_Period);
            sl = isBuy ? entryPrice - atr * ATR_Multiplier : entryPrice + atr * ATR_Multiplier;
            break;
        }
        case 3: {
            int bar = Breakout_Lookback;
            sl = isBuy ? iLow(symbol, Timeframe, bar) : iHigh(symbol, Timeframe, bar);
            break;
        }
        case 4: {
            int back = 5;
            sl = isBuy ? iLow(symbol, Timeframe, iLowest(symbol, Timeframe, MODE_LOW, back, 1))
                       : iHigh(symbol, Timeframe, iHighest(symbol, Timeframe, MODE_HIGH, back, 1));
            break;
        }
    }
    return NormalizeDouble(sl, _Digits);
}

double GetTakeProfitPrice(double entryPrice, double slPrice, bool isBuy) {
    double sl_range = MathAbs(entryPrice - slPrice);
    double tp = isBuy ? entryPrice + sl_range * RR_Multiplier : entryPrice - sl_range * RR_Multiplier;
    return NormalizeDouble(tp, _Digits);
}

double CalculateLotSize(string symbol, double stopLossPoints) {
    double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * Risk_Percent / 100.0;
    double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
    double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
    double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);

    double valuePerPoint = tickValue / tickSize;
    double lots = riskAmount / (stopLossPoints * valuePerPoint);
    lots = MathFloor(lots / lotStep) * lotStep;

    double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
    double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
    return MathMax(minLot, MathMin(lots, maxLot));
}

bool PassRSIFilter(string symbol, bool isBuy) {
    if (!UseRSI) return true;
    double rsi = iRSI(symbol, Timeframe, RSI_Period, PRICE_CLOSE, 0);
    return (isBuy && rsi > RSI_Buy_Level) || (!isBuy && rsi < RSI_Sell_Level);
}