اگر ربات زیر را در بخش optimization کنیم، در ستون custom جدول نتایج، چه چیزی را نمایش می دهد؟
//+------------------------------------------------------------------+
//| Check for position closing based on LTF RSI                     |
//+------------------------------------------------------------------+
void CheckPositionClosing()
{
    // Only check if we have open positions
    if(PositionsTotal() == 0)
        return;
        
    // Sync martingale orders on new LTF bar
    datetime currentLTFBar = iTime(_Symbol, LowerTimeFrame, 0);
    if(currentLTFBar != lastLTFBarTime)
    {
        lastLTFBarTime = currentLTFBar;
        // 1) اگر سفارش اصلی داریم، بررسی و باز کردن مارتینگل‌های ناقص
        SyncMartingaleOpenMissing();
        // 2) اگر مارتینگل باز داریم، بستن موارد بدون سفارش اصلی
        SyncMartingaleCloseOrphans();
    }
    
    // Get current LTF RSI values for last 3 bars
    double lowerRSI[];
    ArraySetAsSeries(lowerRSI, true);
    
    // Get 3 bars to have better visibility of the movement
    if(CopyBuffer(lowerRSI_handle, 0, 0, 3, lowerRSI) != 3)
    {
        Print("Failed to get Lower TimeFrame RSI data for position closing");
        return;
    }
    
    // Debug print to see exact RSI values
    Print("=== RSI Values ===");
    Print("Current (0): ", NormalizeDouble(lowerRSI[0], 2));
    Print("Previous (1): ", NormalizeDouble(lowerRSI[1], 2));
    Print("2 bars ago (2): ", NormalizeDouble(lowerRSI[2], 2));
    Print("Neutral Level: ", LowerRSI_Neutral);
    
    // Regular check for current value
    CheckAndClosePositions(lowerRSI[1], lowerRSI[2]); // Using completed bars
    
    // Store current RSI value for next comparison
    previousLowerRSI = lowerRSI[1]; // Store the last completed bar
}

//+------------------------------------------------------------------+
//| Check and close positions when Lower RSI crosses neutral level  |
//+------------------------------------------------------------------+
void CheckAndClosePositions(double currentLowerRSI, double prevLowerRSI)
{
    // Get current RSI value only
    double lowerRSI[];
    ArraySetAsSeries(lowerRSI, true);
    
    if(CopyBuffer(lowerRSI_handle, 0, 0, 1, lowerRSI) != 1)
    {
        Print("Failed to get current Lower TimeFrame RSI data");
        return;
    }
    
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        ulong ticket = PositionGetTicket(i);
        if(PositionSelectByTicket(ticket))
        {
            if(PositionGetString(POSITION_SYMBOL) == _Symbol && 
               PositionGetInteger(POSITION_MAGIC) == MagicNumber)
            {
                ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
                bool shouldClose = false;
                string closeReason = "";

                // Debug print for every position check
                Print("=== Position Check ===");
                Print("Position Type: ", EnumToString(posType));
                Print("Current RSI: ", NormalizeDouble(currentLowerRSI, 2));
                Print("Previous RSI: ", NormalizeDouble(prevLowerRSI, 2));
                Print("Neutral Level: ", LowerRSI_Neutral);

                if(posType == POSITION_TYPE_BUY)
                {
                    // Close if RSI crosses up through neutral level
                    if(prevLowerRSI <= LowerRSI_Neutral && currentLowerRSI > LowerRSI_Neutral)
                    {
                        shouldClose = true;
                        closeReason = "Buy Position: RSI crossed up through neutral level";
                    }
                }
                else if(posType == POSITION_TYPE_SELL)
                {
                    // Close if RSI crosses down through neutral level
                    if(prevLowerRSI >= LowerRSI_Neutral && currentLowerRSI < LowerRSI_Neutral)
                    {
                        shouldClose = true;
                        closeReason = "Sell Position: RSI crossed down through neutral level";
                    }
                }

                if(shouldClose)
                {
                    Print("=== CLOSING POSITION ===");
                    Print(closeReason);
                    Print("Ticket: ", ticket);
                    Print("Previous RSI: ", NormalizeDouble(prevLowerRSI, 2));
                    Print("Current RSI: ", NormalizeDouble(currentLowerRSI, 2));
                    Print("Neutral Level: ", LowerRSI_Neutral);
                    
                    ClosePosition(ticket);
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Close individual position                                        |
//+------------------------------------------------------------------+
void ClosePosition(ulong ticket)
{
    if(!PositionSelectByTicket(ticket))
    {
        Print("Failed to select position: ", ticket);
        return;
    }
    
    // First close/cancel martingale orders if this is a main position
    for(int i = ArraySize(martingaleGroups) - 1; i >= 0; i--)
    {
        if(martingaleGroups[i].mainTicket == ticket)
        {
            // Close/Cancel all martingale orders in this group
            for(int j = 0; j < ArraySize(martingaleGroups[i].martingaleTickets); j++)
            {
                if(martingaleGroups[i].martingaleTickets[j] > 0)
                {
                    // Check if it's an active position or pending order
                    if(PositionSelectByTicket(martingaleGroups[i].martingaleTickets[j]))
                    {
                        // It's an active position - close it
                        CloseSpecificPosition(martingaleGroups[i].martingaleTickets[j]);
                        Print("Closed martingale position: ", martingaleGroups[i].martingaleTickets[j]);
                    }
                    else if(OrderSelect(martingaleGroups[i].martingaleTickets[j]))
                    {
                        // It's a pending order - cancel it
                        CancelPendingOrder(martingaleGroups[i].martingaleTickets[j]);
                        Print("Cancelled martingale pending order: ", martingaleGroups[i].martingaleTickets[j]);
                    }
                }
            }
            // Remove this group
            ArrayRemove(martingaleGroups, i, 1);
            break;
        }
    }
    
    // Then close the main position
    CloseSpecificPosition(ticket);
    
    // Remove from activeTickets array
    for(int i = 0; i < ArraySize(activeTickets); i++)
    {
        if(activeTickets[i] == ticket)
        {
            ArrayRemove(activeTickets, i, 1);
            break;
        }
    }
}

//+------------------------------------------------------------------+
//| Cancel a pending order                                           |
//+------------------------------------------------------------------+
void CancelPendingOrder(ulong ticket)
{
    MqlTradeRequest request = {};
    MqlTradeResult result = {};
    
    request.action = TRADE_ACTION_REMOVE;
    request.order = ticket;
    
    if(OrderSend(request, result))
    {
        Print("Pending order cancelled successfully. Ticket: ", ticket);
    }
    else
    {
        Print("Failed to cancel pending order: ", ticket, " Error: ", GetLastError());
    }
}

//+------------------------------------------------------------------+
//| Close a specific position                                        |
//+------------------------------------------------------------------+
void CloseSpecificPosition(ulong ticket)
{
    if(!PositionSelectByTicket(ticket)) return;
    
    string symbol = PositionGetString(POSITION_SYMBOL);
    double volume = PositionGetDouble(POSITION_VOLUME);
    ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
    
    MqlTradeRequest request = {};
    MqlTradeResult result = {};
    
    request.action = TRADE_ACTION_DEAL;
    request.symbol = symbol;
    request.volume = volume;
    request.deviation = 10;
    request.magic = MagicNumber;
    request.position = ticket;
    request.type_filling = GetFillingMode();
    
    if(posType == POSITION_TYPE_BUY)
    {
        request.type = ORDER_TYPE_SELL;
        request.price = SymbolInfoDouble(symbol, SYMBOL_BID);
        request.comment = CommentPrefix + "_Close_Buy";
    }
    else if(posType == POSITION_TYPE_SELL)
    {
        request.type = ORDER_TYPE_BUY;
        request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
        request.comment = CommentPrefix + "_Close_Sell";
    }
    
    if(OrderSend(request, result))
    {
        Print("Position closed successfully. Ticket: ", ticket);
    }
    else
    {
        Print("Failed to close position: ", ticket, " Error: ", GetLastError());
    }
}

//+------------------------------------------------------------------+
//|                                            RSI Dual TimeFrame EA |
//|                                       Copyright 2025, Your Name |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Your Name"
#property link      ""
#property version   "1.00"
#property strict

//--- Input parameters
input group "Lower TimeFrame RSI Settings"
input ENUM_TIMEFRAMES LowerTimeFrame = PERIOD_M15;        // Lower TimeFrame for RSI
input int LowerRSI_Period = 14;                           // Lower TF RSI Period
input ENUM_APPLIED_PRICE LowerRSI_Price = PRICE_CLOSE;    // Lower TF RSI Applied Price
input double LowerRSI_OverBought = 70.0;                  // Lower TF RSI OverBought Level
input double LowerRSI_Neutral   = 50.0;                   // Lower TF RSI Neutral Level
input double LowerRSI_OverSold  = 30.0;                   // Lower TF RSI OverSold Level

input group "Higher TimeFrame RSI Settings"
input ENUM_TIMEFRAMES HigherTimeFrame = PERIOD_H1;        // Higher TimeFrame for RSI
input int HigherRSI_Period = 14;                          // Higher TF RSI Period
input ENUM_APPLIED_PRICE HigherRSI_Price = PRICE_CLOSE;   // Higher TF RSI Applied Price
input double HigherRSI_Neutral = 50.0;                    // Higher TF RSI Neutral Level

input group "Trade Settings"
input double TradeLotSize = 0.01;                         // Trade Lot Size
input ENUM_TIMEFRAMES CandleTimeFrame = PERIOD_CURRENT;   // Candle Analysis TimeFrame
input int MagicNumber = 12345;                            // Magic Number
input string CommentPrefix = "RSI_EA";                    // Comment Prefix

input group "Martingale Settings"
input int MartingaleCount = 3;        // Number of Martingale Orders
input double MartingaleMultiplier = 1.2;  // Volume multiplier for each martingale level
input int MartingaleDistance = 100;   // Distance between Orders (Points)

// Structure to hold martingale orders info
struct MartingaleGroup
{
    ulong mainTicket;           // Main position ticket
    ulong martingaleTickets[]; // Array of martingale position tickets
};

//--- Global variables
ulong activeTickets[];  // آرایه‌ای برای نگهداری تیکت پوزیشن‌های فعال
int lowerRSI_handle;
int higherRSI_handle;
datetime lastBarTime = 0;
datetime lastLTFBarTime = 0;  // For tracking LTF bar changes
double previousLowerRSI = 0;
bool firstRun = true;
datetime lastPositionCheck = 0;  // برای کنترل زمان بررسی بستن پوزیشن‌ها
string globalVarName = "RSI_EA_" + IntegerToString(MagicNumber) + "_PrevRSI";
MartingaleGroup martingaleGroups[];  // Array to store martingale groups
double peakEquity = 0.0;        // برای ذخیره بالاترین مقدار سرمایه
double maxDrawdownPercent = 0.0; // برای ذخیره حداکثر درصد افت سرمایه نسبی

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    // Create RSI indicators
    lowerRSI_handle = iRSI(_Symbol, LowerTimeFrame, LowerRSI_Period, LowerRSI_Price);
    higherRSI_handle = iRSI(_Symbol, HigherTimeFrame, HigherRSI_Period, HigherRSI_Price);

    if(lowerRSI_handle == INVALID_HANDLE || higherRSI_handle == INVALID_HANDLE)
    {
        Print("Error creating RSI indicators");
        return(INIT_FAILED);
    }

    // Restore previous RSI value if exists
    if(GlobalVariableCheck(globalVarName))
        previousLowerRSI = GlobalVariableGet(globalVarName);

    // Load saved martingale groups
    LoadMartingaleGroups();
    
    // Verify and cleanup invalid groups
    ValidateMartingaleGroups();

    // Check open positions immediately after initialization
    if(PositionsTotal() > 0)
        CheckPositionClosing();

    // Check symbol properties for trading
    Print("Symbol filling mode: ", (int)SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE));
    Print("Minimum lot size: ", SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
    Print("Maximum lot size: ", SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX));
    Print("Lot step: ", SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP));

    // مقداردهی اولیه متغیرهای Drawdown
    peakEquity = AccountInfoDouble(ACCOUNT_EQUITY);
    maxDrawdownPercent = 0.0;
    
    Print("RSI Dual TimeFrame EA initialized successfully");
    Print("Initialized by: middleeastwallstreet at ", TimeToString(TimeGMT(), TIME_DATE|TIME_SECONDS));
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // Release indicator handles
    if(lowerRSI_handle != INVALID_HANDLE)
        IndicatorRelease(lowerRSI_handle);
    if(higherRSI_handle != INVALID_HANDLE)
        IndicatorRelease(higherRSI_handle);
        
    // Store previousLowerRSI before shutdown
    GlobalVariableSet(globalVarName, previousLowerRSI);
    
    // Save martingale groups before shutdown
    SaveMartingaleGroups();
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    // Check if new bar formed on candle analysis timeframe (for signal detection)
    datetime currentBarTime = iTime(_Symbol, CandleTimeFrame, 0);
    bool newCandleTFBar = (lastBarTime != currentBarTime);
    
    if(newCandleTFBar)
    {
        lastBarTime = currentBarTime;
        // Analyze the completed bar for new signals
        AnalyzeCompletedBar();
    }
    
    // Check for position closing every second when there are open positions
    if(PositionsTotal() > 0)
    {
        datetime currentTime = TimeTradeServer();
        if(currentTime - lastPositionCheck >= 1) // Check if 1 second has passed
        {
            lastPositionCheck = currentTime;
            CheckPositionClosing();
        }
    }
    
    // Periodically validate martingale groups
    static datetime lastValidationTime = 0;
    datetime currentTime = TimeTradeServer();
    
    if(currentTime - lastValidationTime >= 60) // Check every minute
    {
        lastValidationTime = currentTime;
        ValidateMartingaleGroups();
    }
    
    // به‌روزرسانی Drawdown
    UpdateDrawdown();
}

//+------------------------------------------------------------------+
//| Analyze completed bar for B and S candles                       |
//+------------------------------------------------------------------+
void AnalyzeCompletedBar()
{
    // Get RSI values
    double lowerRSI[], higherRSI[];
    ArraySetAsSeries(lowerRSI, true);
    ArraySetAsSeries(higherRSI, true);
    
    if(CopyBuffer(lowerRSI_handle, 0, 1, 1, lowerRSI) != 1)
    {
        Print("Failed to get Lower TimeFrame RSI data");
        return;
    }
    
    if(CopyBuffer(higherRSI_handle, 0, 1, 1, higherRSI) != 1)
    {
        Print("Failed to get Higher TimeFrame RSI data");
        return;
    }
    
    double lowerRSI_value = lowerRSI[0];
    double higherRSI_value = higherRSI[0];
    
    Print("Lower RSI: ", lowerRSI_value, " Higher RSI: ", higherRSI_value);
    
    // Check for B candle (Buy signal)
    if(lowerRSI_value < LowerRSI_OverSold && higherRSI_value < HigherRSI_Neutral)
    {
        Print("B Candle detected! Lower RSI: ", lowerRSI_value, " < ", LowerRSI_OverSold,
              " AND Higher RSI: ", higherRSI_value, " < ", HigherRSI_Neutral);
        
        if(!HasActiveBuyOrder())
        {
            ProcessBCandle();
        }
        else
        {
            Print("Buy order already active, skipping new buy order");
        }
    }
    
    // Check for S candle (Sell signal)
    if(lowerRSI_value > LowerRSI_OverBought && higherRSI_value > HigherRSI_Neutral)
    {
        Print("S Candle detected! Lower RSI: ", lowerRSI_value, " > ", LowerRSI_OverBought,
              " AND Higher RSI: ", higherRSI_value, " > ", HigherRSI_Neutral);
        
        if(!HasActiveSellOrder())
        {
            ProcessSCandle();
        }
        else
        {
            Print("Sell order already active, skipping new sell order");
        }
    }
    
    // NOTE: Position closing is now handled separately in OnTick() based on LTF bar changes
}

//+------------------------------------------------------------------+
//| Process B candle - Buy signal                                   |
//+------------------------------------------------------------------+
void ProcessBCandle()
{
    // Draw blue arrow below the candle
    string arrowName = "B_" + TimeToString(iTime(_Symbol, CandleTimeFrame, 1), TIME_DATE|TIME_MINUTES);
    double arrowPrice = iLow(_Symbol, CandleTimeFrame, 1) - 50 * _Point;
    
    DrawArrow(arrowName, 0, iTime(_Symbol, CandleTimeFrame, 1), arrowPrice, clrBlue, 233);
    Print("Blue arrow drawn for B candle at: ", TimeToString(iTime(_Symbol, CandleTimeFrame, 1)));
    
    // Open buy order
    OpenBuyOrder();
}

//+------------------------------------------------------------------+
//| Process S candle - Sell signal                                  |
//+------------------------------------------------------------------+
void ProcessSCandle()
{
    // Draw orange arrow above the candle
    string arrowName = "S_" + TimeToString(iTime(_Symbol, CandleTimeFrame, 1), TIME_DATE|TIME_MINUTES);
    double arrowPrice = iHigh(_Symbol, CandleTimeFrame, 1) + 50 * _Point;
    
    DrawArrow(arrowName, 0, iTime(_Symbol, CandleTimeFrame, 1), arrowPrice, clrOrange, 234);
    Print("Orange arrow drawn for S candle at: ", TimeToString(iTime(_Symbol, CandleTimeFrame, 1)));
    
    // Open sell order
    OpenSellOrder();
}

//+------------------------------------------------------------------+
//| Open Buy Order                                                  |
//+------------------------------------------------------------------+
void OpenBuyOrder()
{
    MqlTradeRequest request = {};
    MqlTradeResult result = {};
    
    // Set request parameters
    request.action = TRADE_ACTION_DEAL;
    request.symbol = _Symbol;
    request.volume = NormalizeDouble(TradeLotSize, 2);
    request.type = ORDER_TYPE_BUY;
    request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    request.deviation = 10;
    request.magic = MagicNumber;
    request.comment = CommentPrefix + "_B";
    
    // Set filling mode based on symbol properties
    ENUM_ORDER_TYPE_FILLING filling = GetFillingMode();
    request.type_filling = filling;
    
    Print("Attempting to open buy order with filling mode: ", (int)filling);
    
    if(OrderSend(request, result))
    {
        Print("Buy order opened successfully. Ticket: ", result.order, " Volume: ", request.volume);
    
        // اضافه کردن تیکت به آرایه فعال‌ها
        int size = ArraySize(activeTickets);
        ArrayResize(activeTickets, size+1);
        activeTickets[size] = result.order;
        
        // Open martingale orders
        OpenMartingaleOrders(result.order);
        
        // Save updated martingale groups
        SaveMartingaleGroups();
    }
    else
    {
        Print("Failed to open buy order. Error: ", GetLastError(), " Return code: ", result.retcode);
        PrintFormat("Request details - Price: %G, Volume: %G, Deviation: %d", 
                   request.price, request.volume, request.deviation);
    }
}

//+------------------------------------------------------------------+
//| Open Sell Order                                                 |
//+------------------------------------------------------------------+
void OpenSellOrder()
{
    MqlTradeRequest request = {};
    MqlTradeResult result = {};
    
    // Set request parameters
    request.action = TRADE_ACTION_DEAL;
    request.symbol = _Symbol;
    request.volume = NormalizeDouble(TradeLotSize, 2);
    request.type = ORDER_TYPE_SELL;
    request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    request.deviation = 10;
    request.magic = MagicNumber;
    request.comment = CommentPrefix + "_S";
    
    // Set filling mode based on symbol properties
    ENUM_ORDER_TYPE_FILLING filling = GetFillingMode();
    request.type_filling = filling;
    
    Print("Attempting to open sell order with filling mode: ", (int)filling);
    
    if(OrderSend(request, result))
    {
        Print("Sell order opened successfully. Ticket: ", result.order, " Volume: ", request.volume);
    
        // اضافه کردن تیکت به آرایه فعال‌ها
        int size = ArraySize(activeTickets);
        ArrayResize(activeTickets, size+1);
        activeTickets[size] = result.order;
        
        // Open martingale orders
        OpenMartingaleOrders(result.order);
        
        // Save updated martingale groups
        SaveMartingaleGroups();
    }
    else
    {
        Print("Failed to open sell order. Error: ", GetLastError(), " Return code: ", result.retcode);
        PrintFormat("Request details - Price: %G, Volume: %G, Deviation: %d", 
                   request.price, request.volume, request.deviation);
    }
}

//+------------------------------------------------------------------+
//| Get appropriate filling mode for the symbol                     |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING GetFillingMode()
{
    uint filling_mode = (uint)SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
    
    if((filling_mode & SYMBOL_FILLING_FOK) == SYMBOL_FILLING_FOK)
        return ORDER_FILLING_FOK;
    else if((filling_mode & SYMBOL_FILLING_IOC) == SYMBOL_FILLING_IOC)
        return ORDER_FILLING_IOC;
    else
        return ORDER_FILLING_RETURN;
}

//+------------------------------------------------------------------+
//| Check if there's an active buy order                            |
//+------------------------------------------------------------------+
bool HasActiveBuyOrder()
{
    for(int i = 0; i < PositionsTotal(); i++)
    {
        ulong ticket = PositionGetTicket(i);
        if(PositionSelectByTicket(ticket))
        {
            if(PositionGetString(POSITION_SYMBOL) == _Symbol && 
               PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
               PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
            {
                return true;
            }
        }
    }
    return false;
}

//+------------------------------------------------------------------+
//| Check if there's an active sell order                           |
//+------------------------------------------------------------------+
bool HasActiveSellOrder()
{
    for(int i = 0; i < PositionsTotal(); i++)
    {
        ulong ticket = PositionGetTicket(i);
        if(PositionSelectByTicket(ticket))
        {
            if(PositionGetString(POSITION_SYMBOL) == _Symbol && 
               PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
               PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
            {
                return true;
            }
        }
    }
    return false;
}

//+------------------------------------------------------------------+
//| Draw arrow on chart                                             |
//+------------------------------------------------------------------+
void DrawArrow(string name, int window, datetime time, double price, color clr, int code)
{
    // Delete existing arrow if exists
    if(ObjectFind(0, name) >= 0)
        ObjectDelete(0, name);
    
    // Create new arrow
    if(ObjectCreate(0, name, OBJ_ARROW, window, time, price))
    {
        ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
        ObjectSetInteger(0, name, OBJPROP_ARROWCODE, code);
        ObjectSetInteger(0, name, OBJPROP_WIDTH, 5);
        ObjectSetInteger(0, name, OBJPROP_BACK, false);
        ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
        ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
        
        // Refresh chart to show the arrow
        ChartRedraw();
        
        Print("Arrow created successfully: ", name);
    }
    else
    {
        Print("Failed to create arrow: ", name, " Error: ", GetLastError());
    }
}

//+------------------------------------------------------------------+
//| Open Martingale Orders                                           |
//+------------------------------------------------------------------+
void OpenMartingaleOrders(ulong mainTicket)
{
    if(!PositionSelectByTicket(mainTicket)) return;
    
    ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
    double mainPrice = PositionGetDouble(POSITION_PRICE_OPEN);
    
    // Create new martingale group
    int groupIndex = ArraySize(martingaleGroups);
    ArrayResize(martingaleGroups, groupIndex + 1);
    martingaleGroups[groupIndex].mainTicket = mainTicket;
    ArrayResize(martingaleGroups[groupIndex].martingaleTickets, MartingaleCount);
    
    MqlTradeRequest request = {};
    MqlTradeResult result = {};
    
    // Basic trade parameters
    request.action = TRADE_ACTION_PENDING;
    request.symbol = _Symbol;
    request.deviation = 10;
    request.magic = MagicNumber;
    request.type_filling = GetFillingMode();
    
    // Calculate base volume
    double baseVolume = TradeLotSize;
    double currentVolume = baseVolume;
    
    // Open martingale orders
    for(int i = 0; i < MartingaleCount; i++)
    {
        // Calculate volume for this level (multiply by MartingaleMultiplier for each level)
        currentVolume = baseVolume * MathPow(MartingaleMultiplier, i + 1);
        
        // Normalize volume according to symbol requirements
        double minVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
        double maxVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
        double volumeStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
        
        // Round volume to valid step
        currentVolume = MathRound(currentVolume / volumeStep) * volumeStep;
        
        // Check volume limits
        if(currentVolume < minVolume) currentVolume = minVolume;
        if(currentVolume > maxVolume) currentVolume = maxVolume;
        
        request.volume = NormalizeDouble(currentVolume, 2);
        
        double distance = (i + 1) * MartingaleDistance * _Point;
        
        if(posType == POSITION_TYPE_BUY)
        {
            request.type = ORDER_TYPE_BUY_LIMIT;
            request.price = mainPrice - distance;
            request.comment = CommentPrefix + "_M" + IntegerToString(i+1) + "_B";
        }
        else
        {
            request.type = ORDER_TYPE_SELL_LIMIT;
            request.price = mainPrice + distance;
            request.comment = CommentPrefix + "_M" + IntegerToString(i+1) + "_S";
        }
        
        // Add expiration time (optional - set to 0 for no expiration)
        request.expiration = 0;  // No expiration
        request.type_time = ORDER_TIME_GTC;  // Good Till Cancelled
        
        if(OrderSend(request, result))
        {
            martingaleGroups[groupIndex].martingaleTickets[i] = result.order;
            Print("Martingale pending order ", i+1, " placed successfully. Ticket: ", result.order,
                  " at price: ", request.price, " with volume: ", request.volume);
        }
        else
        {
            Print("Failed to place martingale pending order ", i+1, ". Error: ", GetLastError(),
                  " at price: ", request.price, " with volume: ", request.volume);
        }
    }
}

//+------------------------------------------------------------------+
//| Save martingale groups to JSON file                              |
//+------------------------------------------------------------------+
void SaveMartingaleGroups()
{
    string filename = "RSI_EA_" + IntegerToString(MagicNumber) + "_martingale.json";
    int handle = FileOpen(filename, FILE_WRITE|FILE_TXT);
    if(handle != INVALID_HANDLE)
    {
        string json = "{\"groups\":[";
        
        for(int i = 0; i < ArraySize(martingaleGroups); i++)
        {
            if(i > 0) json += ",";
            json += "{\"main\":" + IntegerToString(martingaleGroups[i].mainTicket) + ",\"martingales\":[";
            
            for(int j = 0; j < ArraySize(martingaleGroups[i].martingaleTickets); j++)
            {
                if(j > 0) json += ",";
                json += IntegerToString(martingaleGroups[i].martingaleTickets[j]);
            }
            json += "]}";
        }
        json += "]}";
        
        FileWriteString(handle, json);
        FileClose(handle);
    }
}

//+------------------------------------------------------------------+
//| Load martingale groups from JSON file                            |
//+------------------------------------------------------------------+
void LoadMartingaleGroups()
{
    string filename = "RSI_EA_" + IntegerToString(MagicNumber) + "_martingale.json";
    if(!FileIsExist(filename)) return;
    
    int handle = FileOpen(filename, FILE_READ|FILE_TXT);
    if(handle != INVALID_HANDLE)
    {
        string json = FileReadString(handle);
        FileClose(handle);
        
        // Parse JSON and validate tickets
        ArrayFree(martingaleGroups);
        
        // Simple JSON parsing (you might want to use a proper JSON parser)
        string groups[];
        StringSplit(StringSubstr(json, StringFind(json, "[") + 1), ',', groups);
        
        for(int i = 0; i < ArraySize(groups); i++)
        {
            string main = StringSubstr(groups[i], StringFind(groups[i], "\"main\":") + 7);
            main = StringSubstr(main, 0, StringFind(main, ","));
            
            ulong mainTicket = StringToInteger(main);
            
            // Verify if position still exists
            if(PositionSelectByTicket(mainTicket))
            {
                int groupIndex = ArraySize(martingaleGroups);
                ArrayResize(martingaleGroups, groupIndex + 1);
                martingaleGroups[groupIndex].mainTicket = mainTicket;
                
                // Parse martingale tickets
                string marts = StringSubstr(groups[i], StringFind(groups[i], "[") + 1);
                marts = StringSubstr(marts, 0, StringFind(marts, "]"));
                string martTickets[];
                StringSplit(marts, ',', martTickets);
                
                ArrayResize(martingaleGroups[groupIndex].martingaleTickets, ArraySize(martTickets));
                for(int j = 0; j < ArraySize(martTickets); j++)
                {
                    ulong ticket = StringToInteger(martTickets[j]);
                    if(PositionSelectByTicket(ticket))
                    {
                        martingaleGroups[groupIndex].martingaleTickets[j] = ticket;
                    }
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Validate and cleanup martingale groups                           |
//+------------------------------------------------------------------+
void ValidateMartingaleGroups()
{
    for(int i = ArraySize(martingaleGroups) - 1; i >= 0; i--)
    {
        bool isValid = false;
        
        // Check if main position exists
        if(PositionSelectByTicket(martingaleGroups[i].mainTicket))
        {
            if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
                PositionGetInteger(POSITION_MAGIC) == MagicNumber)
            {
                isValid = true;
            }
        }
        
        if(!isValid)
        {
            // Close/Cancel any remaining martingale positions/orders
            for(int j = 0; j < ArraySize(martingaleGroups[i].martingaleTickets); j++)
            {
                if(martingaleGroups[i].martingaleTickets[j] > 0)
                {
                    // Check if it's an active position
                    if(PositionSelectByTicket(martingaleGroups[i].martingaleTickets[j]))
                    {
                        CloseSpecificPosition(martingaleGroups[i].martingaleTickets[j]);
                    }
                    // Check if it's a pending order
                    else if(OrderSelect(martingaleGroups[i].martingaleTickets[j]))
                    {
                        CancelPendingOrder(martingaleGroups[i].martingaleTickets[j]);
                    }
                }
            }
            
            // Remove invalid group
            ArrayRemove(martingaleGroups, i, 1);
        }
    }
}

//+------------------------------------------------------------------+
//| Place a single martingale pending order for a given main ticket  |
//+------------------------------------------------------------------+
ulong PlaceSingleMartingale(ulong mainTicket, int level)
{
    // مطمئن شو اصلی هنوز وجود دارد
    if(!PositionSelectByTicket(mainTicket))
        return(0);
    
    // پارامترهای اصلی
    ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
    double mainPrice       = PositionGetDouble(POSITION_PRICE_OPEN);
    double baseVolume      = TradeLotSize;
    double currentVolume   = baseVolume * MathPow(MartingaleMultiplier, level+1);
    
    // رُند کردن حجم به step مجاز
    double minVol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
    double maxVol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
    double step   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
    currentVolume = MathRound(currentVolume/step)*step;
    currentVolume = MathMax(minVol, MathMin(maxVol, currentVolume));

    // آماده‌سازی درخواست
    MqlTradeRequest request={};
    MqlTradeResult  result={};
    request.action       = TRADE_ACTION_PENDING;
    request.symbol       = _Symbol;
    request.volume       = NormalizeDouble(currentVolume,2);
    request.deviation    = 10;
    request.magic        = MagicNumber;
    request.type_filling = GetFillingMode();
    request.expiration   = 0;               // GTC
    request.type_time    = ORDER_TIME_GTC;

    double distance = (double)(level+1) * MartingaleDistance * _Point;
    if(posType == POSITION_TYPE_BUY)
    {
        request.type  = ORDER_TYPE_BUY_LIMIT;
        request.price = mainPrice - distance;
        request.comment = CommentPrefix + "_M" + IntegerToString(level+1) + "_B";
    }
    else
    {
        request.type  = ORDER_TYPE_SELL_LIMIT;
        request.price = mainPrice + distance;
        request.comment = CommentPrefix + "_M" + IntegerToString(level+1) + "_S";
    }

    // ارسال سفارش
    if(OrderSend(request, result))
        return(result.order);
    else
    {
        Print("Failed to place martingale #", level+1,
              " for main ", mainTicket,
              " Error: ", result.retcode);
        return(0);
    }
}

//+------------------------------------------------------------------+
//| Sync martingale: open missing orders for each main position     |
//+------------------------------------------------------------------+
void SyncMartingaleOpenMissing()
{
    // برای هر سفارش اصلی ثبت‌شده در activeTickets
    for(int i=0; i<ArraySize(activeTickets); i++)
    {
        ulong mainTicket = activeTickets[i];
        if(!PositionSelectByTicket(mainTicket)) continue;
        // بررسی تعداد تیکت‌های مارتینگل فعلی برای این گروه
        int groupIndex = -1;
        for(int g=0; g<ArraySize(martingaleGroups); g++)
            if(martingaleGroups[g].mainTicket == mainTicket)
                groupIndex = g;
        // اگر گروهی تعریف نشده، یک گروه جدید بساز
        if(groupIndex < 0)
        {
            groupIndex = ArraySize(martingaleGroups);
            ArrayResize(martingaleGroups, groupIndex+1);
            martingaleGroups[groupIndex].mainTicket = mainTicket;
            ArrayResize(martingaleGroups[groupIndex].martingaleTickets, MartingaleCount);
        }
        // برای هر سطح مارتینگل، اگر تیکتی نداریم یا بسته شده، مجدداً بازش کن
        for(int m=0; m<MartingaleCount; m++)
        {
            ulong mTicket = martingaleGroups[groupIndex].martingaleTickets[m];
            bool exists = (mTicket>0 && (PositionSelectByTicket(mTicket) || OrderSelect(mTicket)));
            if(!exists)
            {
                // بازکردن مجدد pending order
                martingaleGroups[groupIndex].martingaleTickets[m] = PlaceSingleMartingale(mainTicket, m);
                Print("Re‑placed missing martingale #", m+1, " for main ", mainTicket);
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Sync martingale: close orphans (بدون سفارش اصلی)                 |
//+------------------------------------------------------------------+
void SyncMartingaleCloseOrphans()
{
    // برای هر گروه مارتینگل
    for(int g=ArraySize(martingaleGroups)-1; g>=0; g--)
    {
        ulong mainTicket = martingaleGroups[g].mainTicket;
        // اگر سفارش اصلی وجود نداشت، همه مارتینگل‌ها را ببند و گروه را حذف کن
        if(!PositionSelectByTicket(mainTicket))
        {
            for(int m=0; m<ArraySize(martingaleGroups[g].martingaleTickets); m++)
            {
                ulong mTicket = martingaleGroups[g].martingaleTickets[m];
                if(mTicket>0)
                {
                    if(PositionSelectByTicket(mTicket))
                        CloseSpecificPosition(mTicket);
                    else if(OrderSelect(mTicket))
                        CancelPendingOrder(mTicket);
                    Print("Closed orphan martingale ", mTicket);
                }
            }
            ArrayRemove(martingaleGroups, g, 1);
        }
    }
}

//+------------------------------------------------------------------+
//| به‌روزرسانی محاسبه افت سرمایه نسبی                                |
//+------------------------------------------------------------------+
void UpdateDrawdown()
{
    double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
    
    // مقداردهی اولیه peakEquity
    if(peakEquity == 0.0)
        peakEquity = currentEquity;
        
    // به‌روزرسانی اوج سرمایه
    if(currentEquity > peakEquity)
    {
        peakEquity = currentEquity;
        Print("New Peak Equity: ", DoubleToString(peakEquity, 2));
    }
        
    // محاسبه Drawdown فعلی
    double dd = (peakEquity - currentEquity) / peakEquity * 100.0;
    
    // به‌روزرسانی حداکثر Drawdown
    if(dd > maxDrawdownPercent)
    {
        maxDrawdownPercent = dd;
        Print("New Max Drawdown at ", TimeToString(TimeGMT(), TIME_DATE|TIME_SECONDS),
              ": ", DoubleToString(maxDrawdownPercent, 2), "%",
              " (Current Equity: ", DoubleToString(currentEquity, 2),
              ", Peak Equity: ", DoubleToString(peakEquity, 2), ")");
    }
}

//+------------------------------------------------------------------+
//| تابع تستر برای نمایش drawdown                                    |
//+------------------------------------------------------------------+
double OnTester()
{
    return maxDrawdownPercent; // بازگشت مقدار مثبت درصد drawdown
}