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

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

enum SellStopLossOptions
{
    UpperBand,
    MiddleBandSell
};

extern double LotSize = 1;
extern double Slippage = 3;
extern double StopLossMultiplier = 1; // Multiplier for initial stop loss
extern double TakeProfitMultiplier = 2; // Multiplier for take profit
extern double TrailingStop = 50; // Distance in points for trailing stop
extern int Period_BB = 30;
extern double Deviations = 0.8;
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

// Declare the global variables
bool isBuySignal = false;
bool isSellSignal = false;
bool isTradeOpen = false; // Flag to check if a trade is open
int openOrderType = -1; // Track the type of open order (-1 for none, 0 for buy, 1 for sell)

//+------------------------------------------------------------------+
//| Expert initialization function                                     |
//+------------------------------------------------------------------+
int OnInit()
{
    // Initialize the EA
    return (INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // Cleanup code can go here.
}

//+------------------------------------------------------------------+
//| Expert tick function                                              |
//+------------------------------------------------------------------+
void OnTick()
{
    // Update the buy/sell signals based on the Bollinger Bands indicator
    UpdateSignals();
    
    // Check if there are open trades
    isTradeOpen = CheckOpenTrades();

    // Execute buy orders if the buy signal is set, no trade is open, and the current order type is not a buy
    if (isBuySignal && !isTradeOpen && openOrderType != 0)
    {
        double sl = CalculateBuyStopLoss(); // Calculate Stop Loss for Buy
        sl = AdjustStopLoss(sl, Ask, true); // Adjust Stop Loss if it's too close to the current price
        double tp = Ask + TakeProfitMultiplier * (Ask - sl); // Calculate Take Profit based on the Stop Loss

        int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, Slippage, sl, tp, "BB_Cross Buy", 0, 0, clrGreen);
        if (ticket > 0)
            openOrderType = 0; // Set the open order type to Buy
        else
            Print("Buy Order Error: ", GetLastError());
    }
    
    // Execute sell orders if the sell signal is set, no trade is open, and the current order type is not a sell
    if (isSellSignal && !isTradeOpen && openOrderType != 1)
    {
        double sl = CalculateSellStopLoss(); // Calculate Stop Loss for Sell
        sl = AdjustStopLoss(sl, Bid, false); // Adjust Stop Loss if it's too close to the current price
        double tp = Bid - TakeProfitMultiplier * (sl - Bid); // Calculate Take Profit based on the Stop Loss

        int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, Slippage, sl, tp, "BB_Cross Sell", 0, 0, clrRed);
        if (ticket > 0)
            openOrderType = 1; // Set the open order type to Sell
        else
            Print("Sell Order Error: ", GetLastError());
    }

    // Manage existing orders
    ManageOpenOrders();
}

//+------------------------------------------------------------------+
//| 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; // A trade is open 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 from points to actual value
    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()))
        {
            // For Buy orders
            if (OrderType() == OP_BUY)
            {
                double stopLossPrice = CalculateBuyStopLoss();
                stopLossPrice = AdjustStopLoss(stopLossPrice, Bid, true); // Adjust Stop Loss if it's too close to the current price
                
                // Update stop loss if the new calculated stop loss is higher
                if (stopLossPrice > OrderStopLoss())
                {
                    if (OrderModify(OrderTicket(), OrderOpenPrice(), stopLossPrice, OrderTakeProfit(), 0, clrGreen) == false)
                        Print("Error in modifying Buy order: ", GetLastError());
                }
            }

            // For Sell orders
            if (OrderType() == OP_SELL)
            {
                double stopLossPrice = CalculateSellStopLoss();
                stopLossPrice = AdjustStopLoss(stopLossPrice, Ask, false); // Adjust Stop Loss if it's too close to the current price
                
                // Update stop loss if the new calculated stop loss is lower
                if (stopLossPrice < OrderStopLoss())
                {
                    if (OrderModify(OrderTicket(), OrderOpenPrice(), stopLossPrice, OrderTakeProfit(), 0, clrRed) == false)
                        Print("Error in 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); // shift set to 1 for last closed candle
    double lowerBand = iBands(Symbol(), 0, Period_BB, Deviations, 0, PRICE_CLOSE, MODE_LOWER, 1); // shift set to 1 for last closed candle

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

    // 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;
}
//+------------------------------------------------------------------+

make option for martingale if loss