IC Markets

Custom volume and direction indicator for MT4

Share, develop, and backtest custom MQL4/MQL5 Expert Advisors, Python data-scraping scripts, trading bots, and automated market alert systems.
Post Reply
PTScalper
Site Admin
Posts: 210
Joined: Mon Jul 20, 2026 1:28 pm

Custom volume and direction indicator for MT4

Post by PTScalper »

Hi scalpers,

i would like to share my custom indicator for MetaTrader 4, because once you are scalping, you can have opened up to several hundreds of positions at that real time, so to be able to see direction and volume, plus Actual profit/loss per pair is very usefull.

Code: Select all

 #property copyright "Net Exposure Manager EA"
#property version   "2.00"
#property strict

//+------------------------------------------------------------------+
//| Inicializace                                                     |
//+------------------------------------------------------------------+
int OnInit()
  {
   EventSetTimer(1); // Aktualizace GUI každou vteřinu
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Úklid grafiky při odstranění EA z grafu                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
   ObjectsDeleteAll(0, "NET_EXP_");
  }

//+------------------------------------------------------------------+
//| Hlavní smyčky pro aktualizaci                                    |
//+------------------------------------------------------------------+
void OnTick()  { UpdateGUI(); }
void OnTimer() { UpdateGUI(); }

//+------------------------------------------------------------------+
//| Zpracování kliknutí na tlačítko                                  |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      // Pokud bylo kliknuto na naše tlačítko
      if(StringFind(sparam, "NET_EXP_BTN_") == 0)
        {
         // Z názvu tlačítka vyřízneme název instrumentu (od 12. znaku)
         string sym = StringSubstr(sparam, 12); 
         CloseAllBySymbol(sym);
         
         // Vizuální "odmáčknutí" tlačítka zpět
         ObjectSetInteger(0, sparam, OBJPROP_STATE, false);
         UpdateGUI();
        }
     }
  }

//+------------------------------------------------------------------+
//| Logika výpočtu a vykreslení GUI                                  |
//+------------------------------------------------------------------+
void UpdateGUI()
  {
   double totalBuy = 0.0, totalSell = 0.0, totalNet = 0.0;
   double totalBuyPnL = 0.0, totalSellPnL = 0.0, totalNetPnL = 0.0;
   
   string symbols[];
   double netLots[];
   double netPnL[];
   int symbolCount = 0;
   string accCurrency = AccountCurrency();

   // 1. Agregace dat o pozicích
   for(int i = 0; i < OrdersTotal(); i++)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderType() == OP_BUY || OrderType() == OP_SELL)
           {
            string sym = OrderSymbol();
            double lots = OrderLots();
            double pnl = OrderProfit() + OrderSwap() + OrderCommission();
            
            double calcLots = (OrderType() == OP_SELL) ? -lots : lots;
            
            totalNet += calcLots;
            totalNetPnL += pnl;
            
            if(OrderType() == OP_BUY)  { totalBuy += lots; totalBuyPnL += pnl; }
            if(OrderType() == OP_SELL) { totalSell += lots; totalSellPnL += pnl; }
            
            int foundIdx = -1;
            for(int j = 0; j < symbolCount; j++) 
              {
               if(symbols[j] == sym) { foundIdx = j; break; }
              }
              
            if(foundIdx == -1) 
              {
               ArrayResize(symbols, symbolCount + 1);
               ArrayResize(netLots, symbolCount + 1);
               ArrayResize(netPnL, symbolCount + 1);
               symbols[symbolCount] = sym;
               netLots[symbolCount] = calcLots;
               netPnL[symbolCount] = pnl;
               symbolCount++;
              } 
            else 
              {
               netLots[foundIdx] += calcLots;
               netPnL[foundIdx] += pnl;
              }
           }
        }
     }

   // 2. Vykreslení hlavičky
   int yPos = 30;
   DrawLabel("NET_EXP_HDR1", "--- AKTUÁLNÍ EXPOZICE ---", 20, yPos); yPos += 20;
   DrawLabel("NET_EXP_BUY", StringFormat("Celkový nákup: %.2f lotů  (%.2f %s)", totalBuy, totalBuyPnL, accCurrency), 20, yPos); yPos += 20;
   DrawLabel("NET_EXP_SELL", StringFormat("Celkový prodej: %.2f lotů  (%.2f %s)", totalSell, totalSellPnL, accCurrency), 20, yPos); yPos += 20;
   
   string netDir = (totalNet >= 0) ? "LONG" : "SHORT";
   DrawLabel("NET_EXP_NET", StringFormat("ČISTÁ EXPOZICE: %s %.2f lotů  (%.2f %s)", netDir, MathAbs(totalNet), totalNetPnL, accCurrency), 20, yPos); yPos += 30;
   
   DrawLabel("NET_EXP_HDR2", "--- Dle instrumentů ---", 20, yPos); yPos += 20;
   
   // 3. Vykreslení řádků s tlačítky pro jednotlivé páry
   for(int i = 0; i < symbolCount; i++) 
     {
      string dir = (netLots[i] >= 0) ? "Long" : "Short";
      string text = StringFormat("%s: %s %.2f  (%.2f %s)", symbols[i], dir, MathAbs(netLots[i]), netPnL[i], accCurrency);
      
      DrawLabel("NET_EXP_TXT_" + symbols[i], text, 20, yPos);
      DrawButton("NET_EXP_BTN_" + symbols[i], "Zavřít " + symbols[i], 300, yPos - 3);
      yPos += 25;
     }

   // 4. Úklid grafiky - smazání tlačítek párů, které už nemají otevřené pozice
   for(int obj = ObjectsTotal() - 1; obj >= 0; obj--)
     {
      string objName = ObjectName(0, obj);
      if(StringFind(objName, "NET_EXP_TXT_") == 0 || StringFind(objName, "NET_EXP_BTN_") == 0)
        {
         string sym = StringSubstr(objName, 12);
         bool isActive = false;
         for(int i = 0; i < symbolCount; i++)
           {
            if(symbols[i] == sym) { isActive = true; break; }
           }
         if(!isActive) ObjectDelete(0, objName);
        }
     }
  }

//+------------------------------------------------------------------+
//| Funkce pro hromadné zavření pozic dle symbolu                    |
//+------------------------------------------------------------------+
void CloseAllBySymbol(string sym)
  {
   // Smyčka musí jít vždy odzadu dopředu (OrderTotal-1 do 0)
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderSymbol() == sym)
           {
            int type = OrderType();
            if(type == OP_BUY || type == OP_SELL)
              {
               RefreshRates(); // Důležité pro získání nejčerstvější ceny
               double price = (type == OP_BUY) ? MarketInfo(sym, MODE_BID) : MarketInfo(sym, MODE_ASK);
               OrderClose(OrderTicket(), OrderLots(), price, 10, clrRed);
              }
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| Pomocné funkce pro rychlé vykreslení GUI                         |
//+------------------------------------------------------------------+
void DrawLabel(string name, string text, int x, int y)
  {
   if(ObjectFind(0, name) < 0)
     {
      ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
      ObjectSetString(0, name, OBJPROP_FONT, "Arial");
      ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
      
      // Adaptace barvy textu podle toho, zda je graf černý nebo bílý
      color textColor = (ChartGetInteger(0, CHART_COLOR_BACKGROUND) == clrBlack) ? clrWhite : clrBlack;
      ObjectSetInteger(0, name, OBJPROP_COLOR, textColor);
     }
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
  }

void DrawButton(string name, string text, int x, int y)
  {
   if(ObjectFind(0, name) < 0)
     {
      ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0);
      ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0, name, OBJPROP_XSIZE, 100);
      ObjectSetInteger(0, name, OBJPROP_YSIZE, 20);
      ObjectSetString(0, name, OBJPROP_FONT, "Arial");
      ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9);
      ObjectSetInteger(0, name, OBJPROP_COLOR, clrBlack);
      ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clrLightGray);
     }
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
  }
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply