2nd order not opening when loss level hit

 
The EA will not open the second order when the first loss level is reached. I have attached the full code and highlighted the relevant section in white. Any hint or pointing in the right direction will be much appreciated. Thank You.
//+------------------------------------------------------------------+
//| Martingale EA with 3 EMA Crossover Entry, Second Trade in Profit, and Trailing Stop Loss |
//+------------------------------------------------------------------+
#property copyright "PB"
#property link      ""
#property version   "" // Fixed Martingale by ensuring unidirectional baskets
#property strict

// Input parameters
input double InitialLotSize = 0.01;
input double MartingaleMultiplier = 2.0;
input int MaxMartingaleSteps = 8;
input double BasketTakeProfit = 12.5;
input double ProfitIncrement = 6.0;
input double ProfitCutoff = 5.0;
input double BasketStopLoss = -50.0;
input double LossLevel1 = -5.0;
input double LossLevel2 = -15.0;
input double LossLevel3 = -30.0;
input double ProfitLevelForSecondTrade = 5.0;
input int StartHour = 2;
input int EndHour = 23;
input int FastEMAPeriod = 10;
input int MediumEMAPeriod = 20;
input int SlowEMAPeriod = 50;
input ENUM_TIMEFRAMES EMATimeframe = PERIOD_M30;
input int MagicNumber = 12345;

// Global variables
double currentLotSize = InitialLotSize;
int martingaleStep = 0;
bool inTrade = false;
double lastTradePrice = 0;
datetime lastBarTime = 0;
int basketDirection = -1; // 0 = Buy, 1 = Sell, -1 = None
double lossLevels[3];
bool hasTriggered[3];
double currentProfitTarget = 0.0;
double trailingStopLoss = 0.0;
bool profitTargetReached = false;
int lastEMACrossoverDirection = -1;
bool hasAddedSecondTradeInProfit = false;

//+------------------------------------------------------------------+
//| Expert initialization function                                     |
//+------------------------------------------------------------------+
int OnInit()
{
   lastBarTime = 0;
   currentLotSize = InitialLotSize;
   martingaleStep = 0;
   basketDirection = -1;
   lastEMACrossoverDirection = -1;
   hasAddedSecondTradeInProfit = false;
   currentProfitTarget = BasketTakeProfit;
   trailingStopLoss = BasketTakeProfit - ProfitCutoff;
   profitTargetReached = false;

   lossLevels[0] = LossLevel1;
   lossLevels[1] = LossLevel2;
   lossLevels[2] = LossLevel3;

   for(int i = 0; i < 3; i++) hasTriggered[i] = false;

   Print("DEBUG: Initialized - LossLevel1=", LossLevel1, ", LossLevel2=", LossLevel2, ", LossLevel3=", LossLevel3);
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                               |
//+------------------------------------------------------------------+
void OnTick()
{
   if(!IsTradeAllowed()) return;

   int hour = GetServerHour();
   if(hour < StartHour || hour >= EndHour) return;

   double basketProfit = CalculateBasketProfit();
   Print("DEBUG: basketProfit=", basketProfit, ", martingaleStep=", martingaleStep, ", basketDirection=", basketDirection, ", OrdersTotal()=", OrdersTotal());

   ManageTrades();

   // Open new trades on new bars only
   if(Time[0] != lastBarTime)
   {
      lastBarTime = Time[0];
      if(OrdersTotal() < MaxMartingaleSteps + 1)
      {
         int crossoverDirection = GetEMACrossoverDirection();

         // If no basket is active, start a new one
         if(martingaleStep == 0)
         {
            if(crossoverDirection == 0 && lastEMACrossoverDirection != 0)
            {
               OpenBuyTrade(false);
            }
            else if(crossoverDirection == 1 && lastEMACrossoverDirection != 1)
            {
               OpenSellTrade(false);
            }
            lastEMACrossoverDirection = crossoverDirection;
         }
         // Second trade in profit
         else if(martingaleStep == 1 && !hasAddedSecondTradeInProfit)
         {
            if(basketProfit >= ProfitLevelForSecondTrade)
            {
               if(basketDirection == 0 && crossoverDirection == 0)
               {
                  OpenBuyTrade(false);
                  hasAddedSecondTradeInProfit = true;
                  Print("Second buy trade added in profit. Lot Size: ", currentLotSize);
               }
               else if(basketDirection == 1 && crossoverDirection == 1)
               {
                  OpenSellTrade(false);
                  hasAddedSecondTradeInProfit = true;
                  Print("Second sell trade added in profit. Lot Size: ", currentLotSize);
               }
            }
         }
         // If the trend reverses, close the basket and start a new one
         else if((basketDirection == 0 && crossoverDirection == 1) || (basketDirection == 1 && crossoverDirection == 0))
         {
            CloseAllTrades(basketProfit);
            if(crossoverDirection == 0)
            {
               OpenBuyTrade(false);
            }
            else if(crossoverDirection == 1)
            {
               OpenSellTrade(false);
            }
            lastEMACrossoverDirection = crossoverDirection;
         }
      }
   }

   // Martingale trades (check on every tick)
   if(OrdersTotal() < MaxMartingaleSteps + 1 && martingaleStep > 0)
   {
      basketProfit = CalculateBasketProfit();
      int levelIndex = martingaleStep - (hasAddedSecondTradeInProfit ? 2 : 1); // Adjust for second trade in profit
      if(levelIndex >= 0 && levelIndex < 3)
      {
         Print("DEBUG: Martingale Check - levelIndex=", levelIndex, ", basketProfit=", basketProfit, ", lossLevels[", levelIndex, "]=", lossLevels[levelIndex], ", hasTriggered[", levelIndex, "]=", hasTriggered[levelIndex], ", basketDirection=", basketDirection);
         if(basketProfit <= lossLevels[levelIndex] && !hasTriggered[levelIndex])
         {
            Print("DEBUG: Triggering Martingale trade at level ", levelIndex + 1);
            if(basketDirection == 0)
            {
               OpenBuyTrade(true);
               hasTriggered[levelIndex] = true;
            }
            else if(basketDirection == 1)
            {
               OpenSellTrade(true);
               hasTriggered[levelIndex] = true;
            }
         }
         else
         {
            Print("DEBUG: Martingale not triggered - basketProfit <= lossLevels[", levelIndex, "]=", basketProfit <= lossLevels[levelIndex], ", !hasTriggered[", levelIndex, "]=", !hasTriggered[levelIndex]);
         }
      }
   }

   // Recalculate basket profit for closure checks
   basketProfit = CalculateBasketProfit();

   if(basketProfit <= BasketStopLoss)
   {
      CloseAllTrades(basketProfit);
      return;
   }

   if(basketProfit >= BasketTakeProfit)
   {
      if(!profitTargetReached)
      {
         profitTargetReached = true;
         currentProfitTarget = BasketTakeProfit;
         trailingStopLoss = BasketTakeProfit - ProfitCutoff;
      }

      if(basketProfit >= currentProfitTarget)
      {
         bool trendContinues = CheckTrendContinuation();
         if(trendContinues)
         {
            trailingStopLoss = currentProfitTarget;
            currentProfitTarget += ProfitIncrement;
            Print("Trend continues. New profit target: ", currentProfitTarget, ", New stop loss: ", trailingStopLoss);
         }
         else
         {
            CloseAllTrades(basketProfit);
            return;
         }
      }

      if(basketProfit <= trailingStopLoss)
      {
         CloseAllTrades(basketProfit);
         return;
      }
   }
}

//+------------------------------------------------------------------+
//| Supporting functions                                               |
//+------------------------------------------------------------------+
int GetEMACrossoverDirection()
{
   double fastEMA = iMA(NULL, EMATimeframe, FastEMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
   double mediumEMA = iMA(NULL, EMATimeframe, MediumEMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
   double slowEMA = iMA(NULL, EMATimeframe, SlowEMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);

   if(fastEMA > mediumEMA && mediumEMA > slowEMA) return 0;
   else if(fastEMA < mediumEMA && mediumEMA < slowEMA) return 1;
   return -1;
}

bool CheckTrendContinuation()
{
   int crossoverDirection = GetEMACrossoverDirection();
   return (basketDirection == 0 && crossoverDirection == 0) || (basketDirection == 1 && crossoverDirection == 1);
}

double CalculateBasketProfit()
{
   double totalProfit = 0.0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderCloseTime() == 0)
         {
            totalProfit += OrderProfit() + OrderSwap() + OrderCommission();
         }
      }
   }
   return NormalizeDouble(totalProfit, 2);
}

void CloseAllTrades(double basketProfit)
{
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderCloseTime() == 0)
         {
            bool success = OrderType() == OP_BUY ? OrderClose(OrderTicket(), OrderLots(), Bid, 3, clrRed) : OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrRed);
            if(!success) Print("Failed to close order #", OrderTicket(), ". Error: ", GetLastError());
         }
      }
   }
   martingaleStep = 0;
   currentLotSize = InitialLotSize;
   lastTradePrice = 0;
   basketDirection = -1;
   inTrade = false;
   currentProfitTarget = BasketTakeProfit;
   trailingStopLoss = BasketTakeProfit - ProfitCutoff;
   profitTargetReached = false;
   lastEMACrossoverDirection = -1;
   hasAddedSecondTradeInProfit = false;
   for(int i = 0; i < 3; i++) hasTriggered[i] = false;
   Print("Basket closed. Profit: ", basketProfit);
}

void ManageTrades()
{
   inTrade = false;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderCloseTime() == 0)
         {
            inTrade = true;
         }
      }
   }
}

void OpenBuyTrade(bool isMartingale)
{
   double lotSize = NormalizeDouble(currentLotSize, 2);
   int ticket = OrderSend(Symbol(), OP_BUY, lotSize, Ask, 3, 0, 0, 
                         "EMA Buy Step " + IntegerToString(martingaleStep) + (isMartingale ? " (Martingale)" : ""), 
                         MagicNumber, 0, clrGreen);
   if(ticket > 0)
   {
      inTrade = true;
      lastTradePrice = Ask;
      basketDirection = 0;
      currentLotSize = NormalizeDouble(currentLotSize * MartingaleMultiplier, 2);
      martingaleStep++;
      Print("Buy order opened. Ticket: ", ticket, " Lot Size: ", lotSize, " Next Lot Size: ", currentLotSize);
   }
   else
   {
      Print("Error opening buy trade: ", GetLastError());
   }
}

void OpenSellTrade(bool isMartingale)
{
   double lotSize = NormalizeDouble(currentLotSize, 2);
   int ticket = OrderSend(Symbol(), OP_SELL, lotSize, Bid, 3, 0, 0, 
                         "EMA Sell Step " + IntegerToString(martingaleStep) + (isMartingale ? " (Martingale)" : ""), 
                         MagicNumber, 0, clrRed);
   if(ticket > 0)
   {
      inTrade = true;
      lastTradePrice = Bid;
      basketDirection = 1;
      currentLotSize = NormalizeDouble(currentLotSize * MartingaleMultiplier, 2);
      martingaleStep++;
      Print("Sell order opened. Ticket: ", ticket, " Lot Size: ", lotSize, " Next Lot Size: ", currentLotSize);
   }
   else
   {
      Print("Error opening sell trade: ", GetLastError());
   }
}

int GetServerHour()
{
   return(TimeHour(TimeCurrent()));
}

 
Patrick Burns: The EA will not open the second order when the first loss level is reached.

Use the debugger or print out your variables, including _LastError and prices and find out why. Do you really expect us to debug your code for you?
          Code debugging - Developing programs - MetaEditor Help
          Error Handling and Logging in MQL5 - MQL5 Articles (2015)
          Tracing, Debugging and Structural Analysis of Source Code - MQL5 Articles (2011)
          Introduction to MQL5: How to write simple Expert Advisor and Custom Indicator - MQL5 Articles (2010)

 
William Roeder #:

Use the debugger or print out your variables, including _LastError and prices and find out why. Do you really expect us to debug your code for you?
          Code debugging - Developing programs - MetaEditor Help
          Error Handling and Logging in MQL5 - MQL5 Articles (2015)
          Tracing, Debugging and Structural Analysis of Source Code - MQL5 Articles (2011)
          Introduction to MQL5: How to write simple Expert Advisor and Custom Indicator - MQL5 Articles (2010)

I apologise. My oversight, I don't expect such a thing.

Files:
 
I think i have sorted it. It is the Martingale logic not being checked on every tick. Thank you Mr Roeder. I wouldn't want to burden your avuncular attitude any further.
//+------------------------------------------------------------------+
//| Martingale EA with 3 EMA Crossover Entry, Second Trade in Profit, and Trailing Stop Loss |
//+------------------------------------------------------------------+
#property copyright "PB"
#property link      ""
#property version   "" // Martingale logic to check on every tick
#property strict

// Input parameters
input double InitialLotSize = 0.01;      // Initial lot size
input double MartingaleMultiplier = 2.0; // Lot size multiplier for Martingale
input int MaxMartingaleSteps = 8;        // Max Martingale steps
input double BasketTakeProfit = 12.5;    // Initial Basket Take Profit in base currency
input double ProfitIncrement = 6.0;      // Profit increment for rechecking
input double ProfitCutoff = 5.0;         // Profit cutoff below BasketTakeProfit for immediate reversal
input double BasketStopLoss = -50.0;     // Basket Stop Loss in base currency (negative)
input double LossLevel1 = -5.0;          // Loss level for 1st Martingale trade (must be negative)
input double LossLevel2 = -15.0;         // Loss level for 2nd Martingale trade (must be more negative than LossLevel1)
input double LossLevel3 = -30.0;         // Loss level for 3rd Martingale trade (must be more negative than LossLevel2)
input double ProfitLevelForSecondTrade = 5.0; // Profit level to open second trade in the same direction
input int StartHour = 2;                 // Trading start hour (0-23)
input int EndHour = 23;                  // Trading end hour (0-23)
input int FastEMAPeriod = 10;            // Fast EMA period for trend confirmation
input int MediumEMAPeriod = 20;          // Medium EMA period for trend confirmation
input int SlowEMAPeriod = 50;            // Slow EMA period for trend confirmation
input ENUM_TIMEFRAMES EMATimeframe = PERIOD_M30; // Timeframe for EMA calculation (M5, M30, H1, etc.)
input int MagicNumber = 12345;           // Magic Number for trades

// Global variables
double currentLotSize = InitialLotSize;
int totalTradesInBasket = 0;             // Total trades in the current basket
int martingaleTradesOpened = 0;          // Number of Martingale trades opened
bool inTrade = false;
double lastTradePrice = 0;
datetime lastBarTime = 0;
int lastTradeDirection = -1;             // Track direction of last trade (0 = Buy, 1 = Sell)
double lossLevels[3];                    // Array to store loss levels
bool hasTriggered[3];                    // Track if a loss level has been triggered
double currentProfitTarget = 0.0;        // Current profit target for rechecking
double trailingStopLoss = 0.0;           // Trailing stop loss level (previous increment)
bool profitTargetReached = false;        // Flag to indicate if BasketTakeProfit has been reached
int lastEMACrossoverDirection = -1;      // Track the previous EMA crossover direction (0 = Buy, 1 = Sell, -1 = None)
bool hasAddedSecondTrade = false;        // Flag to track if the second trade has been added

//+------------------------------------------------------------------+
//| Expert initialization function                                     |
//+------------------------------------------------------------------+
int OnInit()
{
   lastBarTime = 0;
   currentLotSize = InitialLotSize;
   totalTradesInBasket = 0;
   martingaleTradesOpened = 0;
   lastTradeDirection = -1;
   lastEMACrossoverDirection = -1;
   hasAddedSecondTrade = false;
   currentProfitTarget = BasketTakeProfit;
   trailingStopLoss = BasketTakeProfit - ProfitCutoff;
   profitTargetReached = false;

   // Initialize loss levels array
   lossLevels[0] = LossLevel1;
   lossLevels[1] = LossLevel2;
   lossLevels[2] = LossLevel3;

   // Initialize trigger flags
   for(int i = 0; i < 3; i++) hasTriggered[i] = false;

   // Debug prints to verify parameter values
   Print("DEBUG: LossLevel1 = ", LossLevel1, ", LossLevel2 = ", LossLevel2, ", LossLevel3 = ", LossLevel3);
   Print("DEBUG: LossLevel1 > LossLevel2: ", LossLevel1 > LossLevel2, ", LossLevel2 > LossLevel3: ", LossLevel2 > LossLevel3);

   // Validate loss levels
   if(LossLevel1 >= 0 || LossLevel2 >= 0 || LossLevel3 >= 0)
   {
      Print("Error: Loss levels must be negative (e.g., -5, -15, -30).");
      return(INIT_PARAMETERS_INCORRECT);
   }

   if(!(LossLevel1 > LossLevel2 && LossLevel2 > LossLevel3))
   {
      Print("Error: Loss levels must be in increasing order of negativity (e.g., -5, -15, -30).");
      return(INIT_PARAMETERS_INCORRECT);
   }

   // Validate ProfitLevelForSecondTrade
   if(ProfitLevelForSecondTrade <= 0)
   {
      Print("Error: ProfitLevelForSecondTrade must be positive.");
      return(INIT_PARAMETERS_INCORRECT);
   }

   // Validate StartHour and EndHour
   if(StartHour < 0 || StartHour > 23 || EndHour < 0 || EndHour > 23 || StartHour >= EndHour)
   {
      Print("Error: StartHour and EndHour must be between 0 and 23, and StartHour must be less than EndHour.");
      return(INIT_PARAMETERS_INCORRECT);
   }

   // Validate ProfitIncrement and ProfitCutoff
   if(ProfitIncrement <= 0)
   {
      Print("Error: ProfitIncrement must be positive.");
      return(INIT_PARAMETERS_INCORRECT);
   }
   if(ProfitCutoff < 0)
   {
      Print("Error: ProfitCutoff must be non-negative.");
      return(INIT_PARAMETERS_INCORRECT);
   }

   // Validate EMA periods
   if(FastEMAPeriod <= 0 || MediumEMAPeriod <= 0 || SlowEMAPeriod <= 0)
   {
      Print("Error: EMA periods must be positive.");
      return(INIT_PARAMETERS_INCORRECT);
   }
   if(FastEMAPeriod >= MediumEMAPeriod || MediumEMAPeriod >= SlowEMAPeriod)
   {
      Print("Error: EMA periods must be in increasing order (Fast < Medium < Slow).");
      return(INIT_PARAMETERS_INCORRECT);
   }

   Print("Initialization successful.");
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // No cleanup needed
}

//+------------------------------------------------------------------+
//| Expert tick function                                               |
//+------------------------------------------------------------------+
void OnTick()
{
   if(!IsTradeAllowed()) return;

   int hour = GetServerHour();
   if(hour < StartHour || hour >= EndHour) return;

   double basketProfit = CalculateBasketProfit();

   // Check if basket should be closed due to stop loss
   if(basketProfit <= BasketStopLoss)
   {
      CloseAllTrades(basketProfit);
      return;
   }

   // Check profit against BasketTakeProfit and incremental levels
   if(basketProfit >= BasketTakeProfit)
   {
      if(!profitTargetReached)
      {
         profitTargetReached = true;
         currentProfitTarget = BasketTakeProfit;
         trailingStopLoss = BasketTakeProfit - ProfitCutoff;
      }

      if(basketProfit >= currentProfitTarget)
      {
         bool trendContinues = CheckTrendContinuation();
         if(trendContinues)
         {
            trailingStopLoss = currentProfitTarget;
            currentProfitTarget += ProfitIncrement;
            Print("Trend continues. New profit target: ", currentProfitTarget, ", New stop loss: ", trailingStopLoss);
         }
         else
         {
            CloseAllTrades(basketProfit);
            return;
         }
      }

      if(basketProfit <= trailingStopLoss)
      {
         CloseAllTrades(basketProfit);
         return;
      }
   }

   // Martingale trades (check on every tick)
   if(OrdersTotal() < MaxMartingaleSteps + 1 && OrdersTotal() > 0 && martingaleTradesOpened < 3)
   {
      int levelIndex = martingaleTradesOpened;
      if(levelIndex < 3 && basketProfit <= lossLevels[levelIndex] && !hasTriggered[levelIndex])
      {
         if(lastTradeDirection == 0)
         {
            OpenBuyTrade(true);
            hasTriggered[levelIndex] = true;
            martingaleTradesOpened++;
         }
         else if(lastTradeDirection == 1)
         {
            OpenSellTrade(true);
            hasTriggered[levelIndex] = true;
            martingaleTradesOpened++;
         }
      }
   }

   ManageTrades();

   // Open new trades (only on new bars)
   if(Time[0] != lastBarTime)
   {
      lastBarTime = Time[0];

      if(OrdersTotal() < MaxMartingaleSteps + 1)
      {
         // First trade in a new basket (totalTradesInBasket == 0)
         if(totalTradesInBasket == 0)
         {
            int crossoverDirection = GetEMACrossoverDirection();
            if(crossoverDirection == 0 && lastEMACrossoverDirection != 0)
            {
               OpenBuyTrade(false);
            }
            else if(crossoverDirection == 1 && lastEMACrossoverDirection != 1)
            {
               OpenSellTrade(false);
            }
            lastEMACrossoverDirection = crossoverDirection;
         }
         // Second trade in profit (after the first trade)
         else if(totalTradesInBasket == 1 && !hasAddedSecondTrade)
         {
            if(basketProfit >= ProfitLevelForSecondTrade)
            {
               int crossoverDirection = GetEMACrossoverDirection();
               if(lastTradeDirection == 0 && crossoverDirection == 0)
               {
                  OpenBuyTrade(false);
                  hasAddedSecondTrade = true;
                  Print("Second buy trade added in profit. Lot Size: ", currentLotSize);
               }
               else if(lastTradeDirection == 1 && crossoverDirection == 1)
               {
                  OpenSellTrade(false);
                  hasAddedSecondTrade = true;
                  Print("Second sell trade added in profit. Lot Size: ", currentLotSize);
               }
            }
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Get the current 3 EMA crossover direction                          |
//+------------------------------------------------------------------+
int GetEMACrossoverDirection()
{
   double fastEMA = iMA(NULL, EMATimeframe, FastEMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
   double mediumEMA = iMA(NULL, EMATimeframe, MediumEMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
   double slowEMA = iMA(NULL, EMATimeframe, SlowEMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);

   if(fastEMA > mediumEMA && mediumEMA > slowEMA)
   {
      return 0; // Bullish
   }
   else if(fastEMA < mediumEMA && mediumEMA < slowEMA)
   {
      return 1; // Bearish
   }
   return -1; // No crossover
}

//+------------------------------------------------------------------+
//| Check if the trend continues in the same direction using 3 EMA crossover |
//+------------------------------------------------------------------+
bool CheckTrendContinuation()
{
   int crossoverDirection = GetEMACrossoverDirection();
   bool trendDirection = false;
   if(lastTradeDirection == 0)
   {
      trendDirection = (crossoverDirection == 0);
   }
   else if(lastTradeDirection == 1)
   {
      trendDirection = (crossoverDirection == 1);
   }
   return trendDirection;
}

//+------------------------------------------------------------------+
//| Calculate total profit of all open trades in base currency         |
//+------------------------------------------------------------------+
double CalculateBasketProfit()
{
   double totalProfit = 0.0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderCloseTime() == 0)
         {
            totalProfit += OrderProfit() + OrderSwap() + OrderCommission();
         }
      }
   }
   return NormalizeDouble(totalProfit, 2);
}

//+------------------------------------------------------------------+
//| Close all open trades                                              |
//+------------------------------------------------------------------+
void CloseAllTrades(double basketProfit)
{
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderCloseTime() == 0)
         {
            bool success = false;
            if(OrderType() == OP_BUY)
            {
               success = OrderClose(OrderTicket(), OrderLots(), Bid, 3, clrRed);
            }
            else if(OrderType() == OP_SELL)
            {
               success = OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrRed);
            }
            if(!success)
            {
               Print("Failed to close order #", OrderTicket(), ". Error: ", GetLastError());
            }
         }
      }
   }

   // Reset after basket closure
   totalTradesInBasket = 0;
   martingaleTradesOpened = 0;
   currentLotSize = InitialLotSize;
   lastTradePrice = 0;
   lastTradeDirection = -1;
   inTrade = false;
   currentProfitTarget = BasketTakeProfit;
   trailingStopLoss = BasketTakeProfit - ProfitCutoff;
   profitTargetReached = false;
   lastEMACrossoverDirection = -1;
   hasAddedSecondTrade = false;
   for(int i = 0; i < 3; i++) hasTriggered[i] = false;
   Print("Basket closed. Profit: ", basketProfit);
}

//+------------------------------------------------------------------+
//| Manage open trades                                                 |
//+------------------------------------------------------------------+
void ManageTrades()
{
   inTrade = false;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderCloseTime() == 0)
         {
            inTrade = true;
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Open a buy trade                                                   |
//+------------------------------------------------------------------+
void OpenBuyTrade(bool isMartingale)
{
   double lotSize = NormalizeDouble(currentLotSize, 2);
   int ticket = OrderSend(Symbol(), OP_BUY, lotSize, Ask, 3, 0, 0, 
                         "EMA Buy Step " + IntegerToString(totalTradesInBasket) + (isMartingale ? " (Martingale)" : ""), 
                         MagicNumber, 0, clrGreen);
   if(ticket > 0)
   {
      inTrade = true;
      lastTradePrice = Ask;
      lastTradeDirection = 0;
      currentLotSize = NormalizeDouble(currentLotSize * MartingaleMultiplier, 2);
      totalTradesInBasket++;
      Print("Buy order opened. Ticket: ", ticket, " Lot Size: ", lotSize, " Next Lot Size: ", currentLotSize);
   }
   else
   {
      Print("Error opening buy trade: ", GetLastError());
   }
}

//+------------------------------------------------------------------+
//| Open a sell trade                                                  |
//+------------------------------------------------------------------+
void OpenSellTrade(bool isMartingale)
{
   double lotSize = NormalizeDouble(currentLotSize, 2);
   int ticket = OrderSend(Symbol(), OP_SELL, lotSize, Bid, 3, 0, 0, 
                         "EMA Sell Step " + IntegerToString(totalTradesInBasket) + (isMartingale ? " (Martingale)" : ""), 
                         MagicNumber, 0, clrRed);
   if(ticket > 0)
   {
      inTrade = true;
      lastTradePrice = Bid;
      lastTradeDirection = 1;
      currentLotSize = NormalizeDouble(currentLotSize * MartingaleMultiplier, 2);
      totalTradesInBasket++;
      Print("Sell order opened. Ticket: ", ticket, " Lot Size: ", lotSize, " Next Lot Size: ", currentLotSize);
   }
   else
   {
      Print("Error opening sell trade: ", GetLastError());
   }
}

//+------------------------------------------------------------------+
//| Get current server hour                                            |
//+------------------------------------------------------------------+
int GetServerHour()
{
   return(TimeHour(TimeCurrent()));
}
Files: