#property copyright "Algobot"
#property link      "https://www.algobot.live"
#property version   "1.00"
#property strict

#include <Trade\Trade.mqh>
CTrade trade;

//--- inputs (mirrors SweepRejectionReversal.DescribeParameters) ---
input int    Lookback     = 12;     // How many prior bars define the swing high/low (support/resistance)
input double WickRatio    = 0.55;   // Rejection wick must be at least this fraction of the trigger range
input double BodyMaxRatio = 0.40;   // Body must be at most this fraction of the range (keeps it a pin)
input double StopBuffer   = 0.10;   // Stop placed this fraction of the trigger range beyond the swept wick
input double RewardRatio  = 2.0;    // Take-profit distance as a multiple of the stop distance (R:R)
input double Lots         = 0.10;   // Trade size
input long   Magic        = 1001;   // Magic number

//--- state ---
datetime g_lastSignalTime = 0;      // mirrors _lastSignalTime (avoids repaint / re-eval per bar)

int OnInit()
{
    trade.SetExpertMagicNumber(Magic);
    g_lastSignalTime = 0;
    return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
    // No indicator handles to release (strategy is pure OHLC geometry).
}

void OnTick()
{
    // Need the signal bar plus a full lookback window behind it.
    if(Bars(_Symbol, _Period) < Lookback + 3) return;

    // Evaluate the most recently COMPLETED bar (shift 1) once per bar to avoid repaint.
    datetime sigTime = iTime(_Symbol, _Period, 1);
    if(sigTime == g_lastSignalTime) return;
    g_lastSignalTime = sigTime;

    // One position at a time for this strategy's magic.
    if(HasPosition(Magic)) return;

    // --- trigger bar (shift 1) geometry ---
    double sigOpen  = iOpen(_Symbol,  _Period, 1);
    double sigHigh  = iHigh(_Symbol,  _Period, 1);
    double sigLow   = iLow(_Symbol,   _Period, 1);
    double sigClose = iClose(_Symbol, _Period, 1);

    double range = sigHigh - sigLow;
    if(range <= 0) return;

    double body      = MathAbs(sigClose - sigOpen);
    double lowerWick = MathMin(sigOpen, sigClose) - sigLow;
    double upperWick = sigHigh - MathMax(sigOpen, sigClose);
    bool   smallBody = body <= BodyMaxRatio * range;

    // Recent swing extremes over bars shift 2 .. lookback+1 (the level being swept).
    double priorHigh = -DBL_MAX, priorLow = DBL_MAX;
    for(int s = 2; s <= Lookback + 1; s++)
    {
        double h = iHigh(_Symbol, _Period, s);
        double l = iLow(_Symbol,  _Period, s);
        if(h > priorHigh) priorHigh = h;
        if(l < priorLow)  priorLow  = l;
    }

    // ---- LONG: swept BELOW support, then reclaimed it with a bullish rejection pin ----
    bool sweptLow  = sigLow   < priorLow;    // ran the stops under support
    bool reclaimUp = sigClose > priorLow;    // closed back above the level
    bool bullPin   = lowerWick >= WickRatio * range && smallBody && sigClose >= sigOpen;
    if(sweptLow && reclaimUp && bullPin)
    {
        double entry = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
        double sl    = sigLow - StopBuffer * range;
        double risk  = entry - sl;
        if(risk > 0)
        {
            double tp = entry + RewardRatio * risk;
            trade.Buy(Lots, _Symbol, 0.0, sl, tp, "SweepRejectionReversal long");
        }
        return;
    }

    // ---- SHORT: swept ABOVE resistance, then reclaimed it with a bearish rejection pin ----
    bool sweptHigh = sigHigh  > priorHigh;   // ran the stops above resistance
    bool reclaimDn = sigClose < priorHigh;   // closed back below the level
    bool bearPin   = upperWick >= WickRatio * range && smallBody && sigClose <= sigOpen;
    if(sweptHigh && reclaimDn && bearPin)
    {
        double entry = SymbolInfoDouble(_Symbol, SYMBOL_BID);
        double sl    = sigHigh + StopBuffer * range;
        double risk  = sl - entry;
        if(risk > 0)
        {
            double tp = entry - RewardRatio * risk;
            trade.Sell(Lots, _Symbol, 0.0, sl, tp, "SweepRejectionReversal short");
        }
    }
}

//+------------------------------------------------------------------+
//| True only on the first tick of a freshly opened bar              |
//+------------------------------------------------------------------+
bool IsNewBar()
{
    static datetime last = 0;
    datetime cur = iTime(_Symbol, _Period, 0);
    if(cur != last){ last = cur; return true; }
    return false;
}

//+------------------------------------------------------------------+
//| Any open position for this symbol + magic?                       |
//+------------------------------------------------------------------+
bool HasPosition(long magic)
{
    for(int i = PositionsTotal()-1; i >= 0; i--)
    {
        ulong t = PositionGetTicket(i);
        if(PositionSelectByTicket(t) &&
           PositionGetString(POSITION_SYMBOL) == _Symbol &&
           PositionGetInteger(POSITION_MAGIC) == magic) return true;
    }
    return false;
}
