BalanceBooster EA: The Ultimate Equity-Based Account Growth Tool for MT5

Maintaining trading discipline is one of the biggest challenges for any trader. Often, we let greed take over when in profit or fear freeze us when in a loss. The BalanceBooster EA is a sophisticated MetaTrader 5 Expert Advisor designed to eliminate these emotional hurdles by monitoring your Overall Account Equity instead of individual trade levels.

In this guide, we’ll dive into the features, logic, and the complete MQL5 source code of the BalanceBooster EA.

What is BalanceBooster EA?

BalanceBooster is a powerful equity-based trading assistant built to grow your trading account in controlled, consistent “steps.”

Unlike traditional Stop Loss (SL) or Take Profit (TP) that apply to a single trade, this EA looks at the health of your entire account. Once your total floating profit or loss reaches a pre-defined “Step” or distance from your starting balance, the EA automatically triggers a “Close All” command—securing your gains or protecting your capital instantly.

Key Features:

  • Equity-Based Management: Closes all positions based on total account equity.
  • Smart Trading Cycles: Operates in “Rounds.” Once a target is hit, it resets and starts a new cycle based on the new balance.
  • Compounding Logic: By resetting after every win, it naturally facilitates account compounding.
  • Live Dashboard: Features a professional on-chart display showing Initial Balance, Target TP, Target SL, and real-time Round statistics.
  • High-Reliability Closing: Includes a multi-retry system (MaxRetries) to ensure orders are closed even during high market volatility or “Off Quotes” errors.

How the “Step” Logic Works

The EA functions in a continuous loop of growth cycles:

  1. Initialization: Upon launch, it captures your current balance as the “Initial Balance.”
  2. Target Calculation: It calculates an Upper Target (TP) by adding the ProfitStep and a Lower Target (SL) by subtracting the LossStep.
  3. Real-Time Monitoring: It constantly tracks equity.
  4. Auto-Reset: Once a target is hit and trades are closed, the EA treats the new balance as the starting point and sets fresh targets.

BalanceBooster EA: MQL5 Source Code | Download

You can copy the code below and compile it in your MetaEditor 5:

//+------------------------------------------------------------------+
//|                                          BalanceBooster_EA.mq5   |
//|                         Copyright 2023, MetaQuotes Ltd.          |
//|                                        https://www.mql5.com      |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, appsportal.in"
#property link      "https://www.appsportal.in"
#property version   "1.00"
#property strict

//--- Input parameters
input double   ProfitStep = 5000.0;      // Profit Step Size (TP Distance)
input double   LossStep = 5000.0;        // Loss Step Size (SL Distance)
input string   DashboardPosition = "C1"; // Dashboard Position (C1,C2,C3,C4)
input int      MaxRetries = 3;           // Max retries for closing orders

//--- Global variables
double initialBalance;
double currentBalance;
double nextUpperTarget;
double nextLowerTarget;
int totalRounds = 0;
double totalProfit = 0;
double totalLoss = 0;
double runningProfit = 0;
bool firstRun = true;
int totalClosedOrders = 0;
int currentOpenTrades = 0;
double currentTradesProfit = 0;
bool isClosingProcess = false;

//--- Current open trade statistics
int currentBuyTrades = 0;
int currentSellTrades = 0;
double currentBuyProfit = 0.0;
double currentSellProfit = 0.0;

//--- Dashboard objects
long chartID;
int subWindow = 0;

//--- Line objects names
string tpLineName = "BalanceStepEA_TP_Line";
string slLineName = "BalanceStepEA_SL_Line";

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Initialize with current balance
   initialBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   currentBalance = initialBalance;
   nextUpperTarget = initialBalance + ProfitStep;
   nextLowerTarget = initialBalance - LossStep;
   
   // Set chart properties
   chartID = ChartID();
   ChartSetInteger(chartID, CHART_SHOW_GRID, false);
   
   // Create dashboard
   CreateDashboard();
   
   Print("EA Initialized. Initial Balance: ", initialBalance, 
         ", Upper Target (Profit): ", nextUpperTarget, 
         ", Lower Target (Loss): ", nextLowerTarget,
         ", Profit Step: ", ProfitStep,
         ", Loss Step: ", LossStep);
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   DeleteDashboard();
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Modified OnTick function with the new function call             |
//+------------------------------------------------------------------+
void OnTick()
{
   // Get current account values
   double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
   currentBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   
   // Count current open trades and calculate their profit
   CountOpenTrades();
   
   // CALL THE NEW FUNCTION HERE
   ResetSLTPIfNoTrades();
   
   // Check if this is first run
   if(firstRun)
   {
      firstRun = false;
      UpdateDashboard();
      return;
   }
   
   // Check for target hits - but not if we're already in closing process
   if(!isClosingProcess && (currentEquity >= nextUpperTarget || currentEquity <= nextLowerTarget))
   {
      Print("Target hit! Current Equity: ", currentEquity, 
            ", Upper Target (Profit): ", nextUpperTarget, 
            ", Lower Target (Loss): ", nextLowerTarget);
      
      // Set closing flag
      isClosingProcess = true;
      
      // Close ALL open orders (without magic number filter)
      if(CloseAllOrders())
      {
         // Update balance after closing
         currentBalance = AccountInfoDouble(ACCOUNT_BALANCE);
         
         // Calculate profit/loss for this round
         double roundResult = currentBalance - initialBalance;
         
         if(roundResult > 0)
         {
            totalProfit += roundResult;
            Print("Round completed with PROFIT: +", roundResult, " (Target hit: Profit Step)");
         }
         else
         {
            totalLoss += MathAbs(roundResult);
            Print("Round completed with LOSS: ", roundResult, " (Target hit: Loss Step)");
         }
         
         totalRounds++;
         runningProfit += roundResult;
         
         // Reset for next round with current balance
         initialBalance = currentBalance;
         nextUpperTarget = initialBalance + ProfitStep;
         nextLowerTarget = initialBalance - LossStep;
         
         Print("New round started. Current Balance: ", initialBalance, 
               ", New Upper Target (Profit): ", nextUpperTarget, 
               ", New Lower Target (Loss): ", nextLowerTarget);
         
         // Update dashboard and lines
         UpdateDashboard();
      }
      
      // Reset closing flag
      isClosingProcess = false;
   }
   
   // Update dashboard and lines every tick
   UpdateDashboard();
}

//+------------------------------------------------------------------+
//| Close ALL open orders with proper filling mode                   |
//+------------------------------------------------------------------+
bool CloseAllOrders()
{
   bool allClosed = true;
   int totalPositions = PositionsTotal();
   
   Print("Starting to close all orders. Total positions: ", totalPositions);
   
   if(totalPositions == 0)
   {
      Print("No positions to close.");
      return true;
   }
   
   // Try to close all positions
   for(int i = totalPositions-1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket > 0)
      {
         string symbol = PositionGetString(POSITION_SYMBOL);
         double volume = PositionGetDouble(POSITION_VOLUME);
         ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         double profit = PositionGetDouble(POSITION_PROFIT);
         
         Print("Closing position #", ticket, 
               " Symbol: ", symbol, 
               " Volume: ", volume, 
               " Type: ", EnumToString(type),
               " Profit: ", profit);
         
         // Try multiple times to close the position
         bool closed = false;
         for(int attempt = 1; attempt <= MaxRetries; attempt++)
         {
            MqlTradeRequest request;
            MqlTradeResult result;
            ZeroMemory(request);
            ZeroMemory(result);
            
            request.action = TRADE_ACTION_DEAL;
            request.position = ticket;
            request.symbol = symbol;
            request.volume = volume;
            request.deviation = 10;
            request.comment = "BalanceStepEA Auto-Close";
            request.magic = 0;
            
            // Set filling mode based on symbol
            int filling_mode = (int)SymbolInfoInteger(symbol, SYMBOL_FILLING_MODE);
            
            if(type == POSITION_TYPE_BUY)
            {
               request.type = ORDER_TYPE_SELL;
               request.price = SymbolInfoDouble(symbol, SYMBOL_BID);
            }
            else
            {
               request.type = ORDER_TYPE_BUY;
               request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
            }
            
            // Set appropriate filling mode for the symbol
            if((filling_mode & SYMBOL_FILLING_FOK) != 0)
               request.type_filling = ORDER_FILLING_FOK;
            else if((filling_mode & SYMBOL_FILLING_IOC) != 0)
               request.type_filling = ORDER_FILLING_IOC;
            else
               request.type_filling = ORDER_FILLING_RETURN;
            
            // Send order
            ResetLastError();
            bool sent = OrderSend(request, result);
            
            if(sent)
            {
               if(result.retcode == TRADE_RETCODE_DONE)
               {
                  Print("Successfully closed position #", ticket, " on attempt ", attempt);
                  totalClosedOrders++;
                  closed = true;
                  break;
               }
               else
               {
                  Print("Failed to close position #", ticket, 
                        " Attempt: ", attempt, 
                        " Error: ", result.retcode, 
                        " - ", GetRetcodeDescription(result.retcode));
               }
            }
            else
            {
               int lastError = GetLastError();
               Print("OrderSend failed for position #", ticket, 
                     " Attempt: ", attempt, 
                     " Error: ", lastError, 
                     " - ", ErrorDescription(lastError));
            }
            
            // Wait before retry
            Sleep(200);
         }
         
         if(!closed)
         {
            Print("Failed to close position #", ticket, " after ", MaxRetries, " attempts");
            
            // Try alternative closing method
            if(TryAlternativeClose(ticket, symbol, volume, type))
            {
               Print("Successfully closed position #", ticket, " using alternative method");
               closed = true;
               totalClosedOrders++;
            }
         }
         
         if(!closed)
         {
            allClosed = false;
         }
         
         // Small delay between closing different positions
         Sleep(100);
      }
   }
   
   // Check if all positions were closed
   int remainingPositions = PositionsTotal();
   if(remainingPositions > 0)
   {
      Print("Warning: ", remainingPositions, " positions remain open after closing attempt");
      allClosed = false;
   }
   else
   {
      Print("All positions successfully closed");
   }
   
   return allClosed;
}

//+------------------------------------------------------------------+
//| Alternative closing method for difficult symbols                |
//+------------------------------------------------------------------+
bool TryAlternativeClose(ulong ticket, string symbol, double volume, ENUM_POSITION_TYPE type)
{
   Print("Trying alternative close method for position #", ticket, " Symbol: ", symbol);
   
   // Method 1: Try with different filling modes
   for(int i = 0; i < 3; i++)
   {
      MqlTradeRequest request;
      MqlTradeResult result;
      ZeroMemory(request);
      ZeroMemory(result);
      
      request.action = TRADE_ACTION_DEAL;
      request.position = ticket;
      request.symbol = symbol;
      request.volume = volume;
      request.deviation = 50; // Higher deviation for difficult symbols
      request.comment = "BalanceStepEA Alt-Close";
      request.magic = 0;
      
      if(type == POSITION_TYPE_BUY)
      {
         request.type = ORDER_TYPE_SELL;
         request.price = SymbolInfoDouble(symbol, SYMBOL_BID);
      }
      else
      {
         request.type = ORDER_TYPE_BUY;
         request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
      }
      
      // Try different filling modes
      switch(i)
      {
         case 0:
            request.type_filling = ORDER_FILLING_RETURN;
            break;
         case 1:
            request.type_filling = ORDER_FILLING_IOC;
            break;
         case 2:
            request.type_filling = ORDER_FILLING_FOK;
            break;
      }
      
      ResetLastError();
      if(OrderSend(request, result))
      {
         if(result.retcode == TRADE_RETCODE_DONE)
         {
            Print("Alternative method succeeded with filling mode: ", request.type_filling);
            return true;
         }
      }
      Sleep(100);
   }
   
   return false;
}

//+------------------------------------------------------------------+
//| Count all open trades and calculate their profit                 |
//+------------------------------------------------------------------+
void CountOpenTrades()
{
   currentOpenTrades = 0;
   currentTradesProfit = 0;
   currentBuyTrades = 0;
   currentSellTrades = 0;
   currentBuyProfit = 0.0;
   currentSellProfit = 0.0;
   
   for(int i = 0; i < PositionsTotal(); i++)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket > 0)
      {
         ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         double profit = PositionGetDouble(POSITION_PROFIT);
         
         currentOpenTrades++;
         currentTradesProfit += profit;
         
         if(type == POSITION_TYPE_BUY)
         {
            currentBuyTrades++;
            currentBuyProfit += profit;
         }
         else if(type == POSITION_TYPE_SELL)
         {
            currentSellTrades++;
            currentSellProfit += profit;
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Create dashboard objects                                         |
//+------------------------------------------------------------------+
void CreateDashboard()
{
   // Background
   ObjectCreate(0, "Dashboard_BG", OBJ_RECTANGLE_LABEL, 0, 0, 0);
   ObjectSetInteger(0, "Dashboard_BG", OBJPROP_XDISTANCE, 20);
   ObjectSetInteger(0, "Dashboard_BG", OBJPROP_YDISTANCE, 20);
   ObjectSetInteger(0, "Dashboard_BG", OBJPROP_XSIZE, 320);
   ObjectSetInteger(0, "Dashboard_BG", OBJPROP_YSIZE, 420); // Increased height for new stats
   ObjectSetInteger(0, "Dashboard_BG", OBJPROP_BGCOLOR, clrBlack);
   ObjectSetInteger(0, "Dashboard_BG", OBJPROP_BORDER_TYPE, BORDER_FLAT);
   ObjectSetInteger(0, "Dashboard_BG", OBJPROP_BORDER_COLOR, clrGray);
   ObjectSetInteger(0, "Dashboard_BG", OBJPROP_CORNER, CORNER_LEFT_UPPER);
   
   // Title
   CreateLabel("Title", "BALANCE STEP EA", 40, 30, clrGold, 12);
   CreateLabel("SepLine", "????????????????????????", 40, 55, clrGray, 10);
   
   // Balance Info
   CreateLabel("InitBal_Label", "Initial Balance:", 40, 80, clrWhite, 10);
   CreateLabel("InitBal_Value", DoubleToString(initialBalance, 2), 200, 80, clrLime, 10);
   
   CreateLabel("CurrBal_Label", "Current Balance:", 40, 105, clrWhite, 10);
   CreateLabel("CurrBal_Value", DoubleToString(currentBalance, 2), 200, 105, clrLime, 10);
   
   CreateLabel("CurrEquity_Label", "Current Equity:", 40, 130, clrWhite, 10);
   CreateLabel("CurrEquity_Value", "0.00", 200, 130, clrYellow, 10);
   
   // Targets
   CreateLabel("UpperTarget_Label", "Upper (TP):", 40, 155, clrWhite, 10);
   CreateLabel("UpperTarget_Value", DoubleToString(nextUpperTarget, 2), 200, 155, clrLime, 10);
   
   CreateLabel("LowerTarget_Label", "Lower (SL):", 40, 180, clrWhite, 10);
   CreateLabel("LowerTarget_Value", DoubleToString(nextLowerTarget, 2), 200, 180, clrRed, 10);
   
   // Steps
   CreateLabel("ProfitStep_Label", "Profit Step:", 40, 205, clrWhite, 10);
   CreateLabel("ProfitStep_Value", DoubleToString(ProfitStep, 2), 200, 205, clrLime, 10);
   
   CreateLabel("LossStep_Label", "Loss Step:", 40, 230, clrWhite, 10);
   CreateLabel("LossStep_Value", DoubleToString(LossStep, 2), 200, 230, clrRed, 10);
   
   // Trade Statistics
   CreateLabel("OpenTrades_Label", "Open Trades:", 40, 255, clrWhite, 10);
   CreateLabel("OpenTrades_Value", "0", 200, 255, clrCyan, 10);
   
   CreateLabel("TradesProfit_Label", "Trades P/L:", 40, 280, clrWhite, 10);
   CreateLabel("TradesProfit_Value", "0.00", 200, 280, clrYellow, 10);
   
   // Round Statistics
   CreateLabel("Rounds_Label", "Completed :", 40, 305, clrWhite, 10);
   CreateLabel("Rounds_Value", "0", 200, 305, clrCyan, 10);
   
   CreateLabel("ClosedOrders_Label", "Total Closed:", 40, 330, clrWhite, 10);
   CreateLabel("ClosedOrders_Value", "0", 200, 330, clrCyan, 10);
   
   // P/L Statistics
   CreateLabel("TotalProfit_Label", "Total Profit:", 40, 355, clrWhite, 10);
   CreateLabel("TotalProfit_Value", "0.00", 200, 355, clrLime, 10);
   
   CreateLabel("TotalLoss_Label", "Total Loss:", 40, 380, clrWhite, 10);
   CreateLabel("TotalLoss_Value", "0.00", 200, 380, clrRed, 10);
   
   CreateLabel("RunningPL_Label", "Running P/L:", 40, 405, clrWhite, 10);
   CreateLabel("RunningPL_Value", "0.00", 200, 405, clrYellow, 10);
   
   // NEW: Current Open Trade Statistics
   CreateLabel("CurrentBuyTrades_Label", "OpenBuy Trades:", 40, 430, clrWhite, 10);
   CreateLabel("CurrentBuyTrades_Value", "0", 200, 430, clrCyan, 10);
   
   CreateLabel("CurrentSellTrades_Label", "OpenSell Trades:", 40, 455, clrWhite, 10);
   CreateLabel("CurrentSellTrades_Value", "0", 200, 455, clrCyan, 10);
   
   CreateLabel("CurrentBuyProfit_Label", "OpenBuy Profit:", 40, 480, clrWhite, 10);
   CreateLabel("CurrentBuyProfit_Value", "0.00", 200, 480, clrLime, 10);
   
   CreateLabel("CurrentSellProfit_Label", "OpenSell Profit:", 40, 505, clrWhite, 10);
   CreateLabel("CurrentSellProfit_Value", "0.00", 200, 505, clrLime, 10);
}

//+------------------------------------------------------------------+
//| Create label helper function                                     |
//+------------------------------------------------------------------+
void CreateLabel(string name, string text, int x, int y, color clr, int fontSize = 10)
{
   ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
   ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
}

//+------------------------------------------------------------------+
//| Update dashboard values                                          |
//+------------------------------------------------------------------+
void UpdateDashboard()
{
   double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
   
   // Update values
   ObjectSetString(0, "CurrBal_Value", OBJPROP_TEXT, DoubleToString(currentBalance, 2));
   ObjectSetString(0, "CurrEquity_Value", OBJPROP_TEXT, DoubleToString(currentEquity, 2));
   ObjectSetString(0, "UpperTarget_Value", OBJPROP_TEXT, DoubleToString(nextUpperTarget, 2));
   ObjectSetString(0, "LowerTarget_Value", OBJPROP_TEXT, DoubleToString(nextLowerTarget, 2));
   ObjectSetString(0, "ProfitStep_Value", OBJPROP_TEXT, DoubleToString(ProfitStep, 2));
   ObjectSetString(0, "LossStep_Value", OBJPROP_TEXT, DoubleToString(LossStep, 2));
   ObjectSetString(0, "OpenTrades_Value", OBJPROP_TEXT, IntegerToString(currentOpenTrades));
   ObjectSetString(0, "TradesProfit_Value", OBJPROP_TEXT, DoubleToString(currentTradesProfit, 2));
   ObjectSetString(0, "Rounds_Value", OBJPROP_TEXT, IntegerToString(totalRounds));
   ObjectSetString(0, "ClosedOrders_Value", OBJPROP_TEXT, IntegerToString(totalClosedOrders));
   ObjectSetString(0, "TotalProfit_Value", OBJPROP_TEXT, DoubleToString(totalProfit, 2));
   ObjectSetString(0, "TotalLoss_Value", OBJPROP_TEXT, DoubleToString(totalLoss, 2));
   ObjectSetString(0, "RunningPL_Value", OBJPROP_TEXT, DoubleToString(runningProfit, 2));
   
   // Update current open trade statistics
   ObjectSetString(0, "CurrentBuyTrades_Value", OBJPROP_TEXT, IntegerToString(currentBuyTrades));
   ObjectSetString(0, "CurrentSellTrades_Value", OBJPROP_TEXT, IntegerToString(currentSellTrades));
   ObjectSetString(0, "CurrentBuyProfit_Value", OBJPROP_TEXT, DoubleToString(currentBuyProfit, 2));
   ObjectSetString(0, "CurrentSellProfit_Value", OBJPROP_TEXT, DoubleToString(currentSellProfit, 2));
   
   // Color coding for equity
   color equityColor = clrYellow;
   if(currentEquity >= nextUpperTarget)
      equityColor = clrLime;
   else if(currentEquity <= nextLowerTarget)
      equityColor = clrRed;
   
   ObjectSetInteger(0, "CurrEquity_Value", OBJPROP_COLOR, equityColor);
   
   // Color coding for trades profit
   color tradesProfitColor = (currentTradesProfit >= 0) ? clrLime : clrRed;
   ObjectSetInteger(0, "TradesProfit_Value", OBJPROP_COLOR, tradesProfitColor);
   
   // Color coding for buy/sell profits
   color buyProfitColor = (currentBuyProfit >= 0) ? clrLime : clrRed;
   color sellProfitColor = (currentSellProfit >= 0) ? clrLime : clrRed;
   ObjectSetInteger(0, "CurrentBuyProfit_Value", OBJPROP_COLOR, buyProfitColor);
   ObjectSetInteger(0, "CurrentSellProfit_Value", OBJPROP_COLOR, sellProfitColor);
   
   // Update the initial balance value
   ObjectSetString(0, "InitBal_Value", OBJPROP_TEXT, DoubleToString(initialBalance, 2));
   
   ChartRedraw();
}

//+------------------------------------------------------------------+
//| Delete dashboard objects                                         |
//+------------------------------------------------------------------+
void DeleteDashboard()
{
   string objects[] = {
      "Dashboard_BG", "Title", "SepLine",
      "InitBal_Label", "InitBal_Value",
      "CurrBal_Label", "CurrBal_Value",
      "CurrEquity_Label", "CurrEquity_Value",
      "UpperTarget_Label", "UpperTarget_Value",
      "LowerTarget_Label", "LowerTarget_Value",
      "ProfitStep_Label", "ProfitStep_Value",
      "LossStep_Label", "LossStep_Value",
      "OpenTrades_Label", "OpenTrades_Value",
      "TradesProfit_Label", "TradesProfit_Value",
      "Rounds_Label", "Rounds_Value",
      "ClosedOrders_Label", "ClosedOrders_Value",
      "TotalProfit_Label", "TotalProfit_Value",
      "TotalLoss_Label", "TotalLoss_Value",
      "RunningPL_Label", "RunningPL_Value",
      "CurrentBuyTrades_Label", "CurrentBuyTrades_Value",
      "CurrentSellTrades_Label", "CurrentSellTrades_Value",
      "CurrentBuyProfit_Label", "CurrentBuyProfit_Value",
      "CurrentSellProfit_Label", "CurrentSellProfit_Value"
   };
   
   for(int i = 0; i < ArraySize(objects); i++)
   {
      ObjectDelete(0, objects[i]);
   }
}

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   // Redraw chart on events
   if(id == CHARTEVENT_CHART_CHANGE)
   {
      UpdateDashboard();
   }
}

//+------------------------------------------------------------------+
//| Helper: Get error description                                    |
//+------------------------------------------------------------------+
string ErrorDescription(int errorCode)
{
   switch(errorCode)
   {
      case 0:   return "No error";
      case 1:   return "No error returned, but the result is unknown";
      case 2:   return "Common error";
      case 3:   return "Invalid trade parameters";
      case 4:   return "Trade server is busy";
      case 5:   return "Old version of the client terminal";
      case 6:   return "No connection with trade server";
      case 7:   return "Not enough rights";
      case 8:   return "Too frequent requests";
      case 9:   return "Malfunctional trade operation";
      case 64:  return "Account disabled";
      case 65:  return "Invalid account";
      case 128: return "Trade timeout";
      case 129: return "Invalid price";
      case 130: return "Invalid stops";
      case 131: return "Invalid trade volume";
      case 132: return "Market is closed";
      case 133: return "Trade is disabled";
      case 134: return "Not enough money";
      case 135: return "Price changed";
      case 136: return "Off quotes";
      case 137: return "Broker is busy";
      case 138: return "Requote";
      case 139: return "Order is locked";
      case 140: return "Long positions only allowed";
      case 141: return "Too many requests";
      case 145: return "Modification denied because order is too close to market";
      case 146: return "Trade context is busy";
      case 147: return "Expirations are denied by broker";
      case 148: return "Too many pending orders";
      case 149: return "Hedging is prohibited";
      case 150: return "Prohibited by FIFO rules";
      case 4756: return "Incorrect filling mode for the symbol (Error 4756)";
      default:  return "Unknown error: " + IntegerToString(errorCode);
   }
}

//+------------------------------------------------------------------+
//| Helper: Get retcode description                                  |
//+------------------------------------------------------------------+
string GetRetcodeDescription(int retcode)
{
   switch(retcode)
   {
      case 10004: return "TRADE_RETCODE_REQUOTE";
      case 10006: return "TRADE_RETCODE_REJECT";
      case 10007: return "TRADE_RETCODE_CANCEL";
      case 10008: return "TRADE_RETCODE_PLACED";
      case 10009: return "TRADE_RETCODE_DONE";
      case 10010: return "TRADE_RETCODE_DONE_PARTIAL";
      case 10011: return "TRADE_RETCODE_ERROR";
      case 10012: return "TRADE_RETCODE_TIMEOUT";
      case 10013: return "TRADE_RETCODE_INVALID";
      case 10014: return "TRADE_RETCODE_INVALID_VOLUME";
      case 10015: return "TRADE_RETCODE_INVALID_PRICE";
      case 10016: return "TRADE_RETCODE_INVALID_STOPS";
      case 10017: return "TRADE_RETCODE_TRADE_DISABLED";
      case 10018: return "TRADE_RETCODE_MARKET_CLOSED";
      case 10019: return "TRADE_RETCODE_NO_MONEY";
      case 10020: return "TRADE_RETCODE_PRICE_CHANGED";
      case 10021: return "TRADE_RETCODE_PRICE_OFF";
      case 10022: return "TRADE_RETCODE_INVALID_EXPIRATION";
      case 10023: return "TRADE_RETCODE_ORDER_CHANGED";
      case 10024: return "TRADE_RETCODE_TOO_MANY_REQUESTS";
      case 10025: return "TRADE_RETCODE_NO_CHANGES";
      case 10026: return "TRADE_RETCODE_SERVER_DISABLES_AT";
      case 10027: return "TRADE_RETCODE_CLIENT_DISABLES_AT";
      case 10028: return "TRADE_RETCODE_LOCKED";
      case 10029: return "TRADE_RETCODE_FROZEN";
      case 10030: return "TRADE_RETCODE_INVALID_FILL";
      case 10031: return "TRADE_RETCODE_CONNECTION";
      case 10032: return "TRADE_RETCODE_ONLY_REAL";
      case 10033: return "TRADE_RETCODE_LIMIT_ORDERS";
      case 10034: return "TRADE_RETCODE_LIMIT_VOLUME";
      case 10035: return "TRADE_RETCODE_INVALID_ORDER";
      case 10036: return "TRADE_RETCODE_POSITION_CLOSED";
      case 10038: return "TRADE_RETCODE_INVALID_CLOSE_VOLUME";
      case 10039: return "TRADE_RETCODE_CLOSE_ORDER_EXIST";
      case 10040: return "TRADE_RETCODE_LIMIT_POSITIONS";
      case 10041: return "TRADE_RETCODE_REJECT_CANCEL";
      case 10042: return "TRADE_RETCODE_LONG_ONLY";
      case 10043: return "TRADE_RETCODE_SHORT_ONLY";
      case 10044: return "TRADE_RETCODE_CLOSE_ONLY";
      case 10045: return "TRADE_RETCODE_FIFO_CLOSE";
      case 10046: return "TRADE_RETCODE_HEDGE_PROHIBITED";
      default:    return "Unknown retcode: " + IntegerToString(retcode);
   }
}

//+------------------------------------------------------------------+
//| Reset SL/TP levels when open trades are 0 or under 3            |
//+------------------------------------------------------------------+
void ResetSLTPIfNoTrades()
{
   // Check if closing process is not active
   if(isClosingProcess) return;
   
   // Count current open trades
   CountOpenTrades();
   
   // Check if open trades are 0 or less than 3
   if(currentOpenTrades < 3 && currentOpenTrades >= 0)
   {
      // Get current balance
      double newBalance = AccountInfoDouble(ACCOUNT_BALANCE);
      double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
      
      // Check if balance has changed significantly from initial balance
      // (0.01 tolerance to avoid floating point comparison issues)
      if(MathAbs(newBalance - initialBalance) > 0.01)
      {
         Print("Resetting SL/TP levels - Open Trades: ", currentOpenTrades);
         Print("Previous Balance: ", initialBalance, ", New Balance: ", newBalance);
         
         // Reset all levels like EA reload
         initialBalance = newBalance;
         nextUpperTarget = initialBalance + ProfitStep;
         nextLowerTarget = initialBalance - LossStep;
         
         // Update dashboard
         UpdateDashboard();
         
         // Optional: Print confirmation
         Print("SL/TP Levels Reset Complete:");
         Print("  New Initial Balance: ", initialBalance);
         Print("  New Upper Target (TP): ", nextUpperTarget);
         Print("  New Lower Target (SL): ", nextLowerTarget);
         Print("  Profit Step: ", ProfitStep);
         Print("  Loss Step: ", LossStep);
      }
   }
}

Understanding the Input Parameters

When you attach BalanceBooster to your chart, you can customize these settings:

  1. ProfitStep: The amount of profit (in your account currency) you want to gain before closing all trades (e.g., $500 or ₹5000).
  2. LossStep: The maximum amount of loss you are willing to tolerate for the entire account before the EA cuts all positions.
  3. MaxRetries: If the broker server is busy, the EA will attempt to close the trades up to this many times.

Installation and Setup

  1. Open MT5: Launch your terminal.
  2. Open MetaEditor: Press F4, create a “New Expert Advisor,” and name it BalanceBooster.
  3. Paste & Compile: Replace the template code with the code above and press Compile (F7).
  4. Deploy: Find the EA in your Navigator window and drag it onto any active chart.
  5. Enable Trading: Ensure the “Algo Trading” button at the top of MT5 is green.

Final Thoughts

The BalanceBooster EA is a must-have tool for basket traders, grid traders, or anyone managing multiple positions simultaneously. It removes the stress of manual monitoring and ensures that you walk away with your profits once your targets are achieved.


Disclaimer: Trading involve significant risk. Always test Expert Advisors on a Demo account before using them on a Live account.

Developed by Sandip Pawar for AppsPortal.in

Leave a Reply

Your email address will not be published. Required fields are marked *