//+------------------------------------------------------------------+
//|                                       BB_Cross_EA.mq4           |
//|                        Created by OpenAI - Assistant            |
//|                                                                  |
//+------------------------------------------------------------------+
#property strict

// Define an enumeration for stop loss options
enum BuyStopLossOptions
{
    LowerBand,
    MiddleBandBuy
};

enum SellStopLossOptions
{
    UpperBand,
    MiddleBandSell
};

// External parameters
extern double LotSize = 1;                      // Base lot size for trades
extern double Slippage = 3;                      // Slippage in points
extern double StopLossMultiplier = 1;            // Multiplier for stop loss
extern double TakeProfitMultiplier = 2;           // Multiplier for take profit
extern double TrailingStop = 50;                 // Trailing stop in points
extern int Period_BB = 30;                        // Bollinger Bands period
extern double Deviations = 0.8;                   // Standard deviations for BB
extern double MinDistance = 10;                   // Minimum distance for stop loss in points

// User choice for buy stop loss band
extern BuyStopLossOptions BuyStopLossBand = LowerBand; // Default to LowerBand for Buy

// User choice for sell stop loss band
extern SellStopLossOptions SellStopLossBand = UpperBand; // Default to UpperBand for Sell

// Martingale parameters
extern bool UseMartingale = false;                 // Enable/disable Martingale strategy
extern double MartingaleMultiplier = 2.0;         // Multiplier for Martingale
extern double InitialLotSize = 1;                  // Starting lot size for the first trade

// Global variables
bool isBuySignal = false;
bool isSellSignal = false;
bool isTradeOpen = false;                           // Flag to check if a trade is open
int openOrderType = -1;                            // Track open order type (-1 for none, 0 for buy, 1 for sell)
int lossCount = 0;                                 // Counter for consecutive losses
double currentLotSize;                             // Current lot size based on Martingale

//+------------------------------------------------------------------+
//| Expert initialization function                                     |
//+------------------------------------------------------------------+
int OnInit()
{
    currentLotSize = InitialLotSize; // Set initial lot size
    return (INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Function to adjust current lot size based on Martingale          |
//+------------------------------------------------------------------+
void AdjustLotSize()
{
    if (lossCount == 0) 
    {
        currentLotSize = InitialLotSize; // Reset to initial lot size
    }
    else 
    {
        // Calculate the current lot size based on the loss count
        currentLotSize = InitialLotSize * MathPow(MartingaleMultiplier, lossCount);
    }
}

//+------------------------------------------------------------------+
//| Expert tick function                                              |
//+------------------------------------------------------------------+
void OnTick()
{
    UpdateSignals();              // Update buy/sell signals
    isTradeOpen = CheckOpenTrades(); // Check if there are open trades
    AdjustLotSize();              // Adjust lot size based on losses

    // Buy Logic
    if (isBuySignal && !isTradeOpen && openOrderType != 0)
    {
        double sl = CalculateBuyStopLoss(); // Calculate Stop Loss for Buy
        sl = AdjustStopLoss(sl, Ask, true); // Adjust Stop Loss
        double tp = Ask + TakeProfitMultiplier * (Ask - sl); // Calculate Take Profit

        int ticket = OrderSend(Symbol(), OP_BUY, currentLotSize, Ask, Slippage, sl, tp, "BB_Cross Buy", 0, 0, clrGreen);
        if (ticket > 0)
        {
            openOrderType = 0; // Set open order type to Buy
            lossCount = 0;     // Reset loss count after a successful order
        }
        else
        {
            Print("Buy Order Error: ", GetLastError());
            if (UseMartingale) lossCount++; // Increment loss count on failure
        }
    }
    
    // Sell Logic
    if (isSellSignal && !isTradeOpen && openOrderType != 1)
    {
        double sl = CalculateSellStopLoss(); // Calculate Stop Loss for Sell
        sl = AdjustStopLoss(sl, Bid, false); // Adjust Stop Loss
        double tp = Bid - TakeProfitMultiplier * (sl - Bid); // Calculate Take Profit

        int ticket = OrderSend(Symbol(), OP_SELL, currentLotSize, Bid, Slippage, sl, tp, "BB_Cross Sell", 0, 0, clrRed);
        if (ticket > 0)
        {
            openOrderType = 1; // Set open order type to Sell
            lossCount = 0;     // Reset loss count after a successful order
        }
        else
        {
            Print("Sell Order Error: ", GetLastError());
            if (UseMartingale) lossCount++; // Increment loss count on failure
        }
    }

    ManageOpenOrders(); // Manage existing orders
}

//+------------------------------------------------------------------+
//| Function to check if there are open trades                       |
//+------------------------------------------------------------------+
bool CheckOpenTrades()
{
    for (int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if (OrderSymbol() == Symbol())
            {
                return true; // Open trade exists for this symbol
            }
        }
    }
    return false; // No trades open for this symbol
}

//+------------------------------------------------------------------+
//| Function to calculate buy stop loss based on user selection      |
//+------------------------------------------------------------------+
double CalculateBuyStopLoss()
{
    double lowerBand = iBands(Symbol(), 0, Period_BB, Deviations, 0, PRICE_CLOSE, MODE_LOWER, 0);
    double middleBand = iMA(Symbol(), 0, Period_BB, 0, MODE_SMA, PRICE_CLOSE, 0); // Calculate Middle Band (SMA)

    switch (BuyStopLossBand)
    {
        case LowerBand:
            return lowerBand - StopLossMultiplier * Point; // Set SL below lower band
        case MiddleBandBuy:
        default:
            return middleBand; // Set SL at the middle band
    }
}

//+------------------------------------------------------------------+
//| Function to calculate sell stop loss based on user selection     |
//+------------------------------------------------------------------+
double CalculateSellStopLoss()
{
    double upperBand = iBands(Symbol(), 0, Period_BB, Deviations, 0, PRICE_CLOSE, MODE_UPPER, 0);
    double middleBand = iMA(Symbol(), 0, Period_BB, 0, MODE_SMA, PRICE_CLOSE, 0); // Calculate Middle Band (SMA)

    switch (SellStopLossBand)
    {
        case UpperBand:
            return upperBand + StopLossMultiplier * Point; // Set SL above upper band
        case MiddleBandSell:
        default:
            return middleBand; // Set SL at the middle band
    }
}

//+------------------------------------------------------------------+
//| Function to adjust stop loss if it's too close to current price  |
//+------------------------------------------------------------------+
double AdjustStopLoss(double stopLoss, double marketPrice, bool isBuy)
{
    double minDistanceInPips = MinDistance * Point; // Convert minimum distance to points
    if (isBuy)
    {
        // For buy orders, SL must be below the market price
        if (stopLoss >= marketPrice - minDistanceInPips)
        {
            stopLoss = marketPrice - minDistanceInPips; // Set SL to minimum distance below market price
        }
    }
    else
    {
        // For sell orders, SL must be above the market price
        if (stopLoss <= marketPrice + minDistanceInPips)
        {
            stopLoss = marketPrice + minDistanceInPips; // Set SL to minimum distance above market price
        }
    }
    return stopLoss; // Return the adjusted (or original) stop loss
}

//+------------------------------------------------------------------+
//| Function to manage open orders with trailing stop                 |
//+------------------------------------------------------------------+
void ManageOpenOrders()
{
    // Loop through all open orders
    for (int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && (OrderSymbol() == Symbol()))
        {
            // Manage Buy orders
            if (OrderType() == OP_BUY)
            {
                double stopLossPrice = CalculateBuyStopLoss();
                stopLossPrice = AdjustStopLoss(stopLossPrice, Bid, true); // Adjust Stop Loss if it's too close
                
                // Update stop loss if the new calculated stop loss is higher
                if (stopLossPrice > OrderStopLoss())
                {
                    if (!OrderModify(OrderTicket(), OrderOpenPrice(), stopLossPrice, OrderTakeProfit(), 0, clrGreen))
                        Print("Error modifying Buy order: ", GetLastError());
                }
            }

            // Manage Sell orders
            if (OrderType() == OP_SELL)
            {
                double stopLossPrice = CalculateSellStopLoss();
                stopLossPrice = AdjustStopLoss(stopLossPrice, Ask, false); // Adjust Stop Loss if it's too close
                
                // Update stop loss if the new calculated stop loss is lower
                if (stopLossPrice < OrderStopLoss())
                {
                    if (!OrderModify(OrderTicket(), OrderOpenPrice(), stopLossPrice, OrderTakeProfit(), 0, clrRed))
                        Print("Error modifying Sell order: ", GetLastError());
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Function to update buy/sell signals                               |
//+------------------------------------------------------------------+
void UpdateSignals()
{
    double upperBand = iBands(Symbol(), 0, Period_BB, Deviations, 0, PRICE_CLOSE, MODE_UPPER, 1); // Last closed candle
    double lowerBand = iBands(Symbol(), 0, Period_BB, Deviations, 0, PRICE_CLOSE, MODE_LOWER, 1); // Last closed candle

    double closePrice = Close[1]; // Last close price (previous candle)
    double closePricePrev = Close[2]; // Close price before previous candle

    // Check for Buy signal
    if (closePrice > upperBand && closePricePrev <= upperBand)
    {
        isBuySignal = true;
        isSellSignal = false; // Reset sell signal
    }
    else
        isBuySignal = false;

    // Check for Sell signal
    if (closePrice < lowerBand && closePricePrev >= lowerBand)
    {
        isSellSignal = true;
        isBuySignal = false; // Reset buy signal
    }
    else
        isSellSignal = false;
}

//+------------------------------------------------------------------+

exception draw arrow make draw verticle line (red for sell, blue for buy) too