English Deutsch 日本語
preview
Разработка пользовательского индикатора матрицы эффективности торгового счёта

Разработка пользовательского индикатора матрицы эффективности торгового счёта

MetaTrader 5Примеры |
82 0
Hlomohang John Borotho
Hlomohang John Borotho

Введение

Многие трейдеры часто сталкиваются с проблемой чрезмерной торговли, недостаточной дисциплиной и принятием решений на эмоциональном уровне, особенно при торговле в соответствии со строгими правилами проп-трейдинговой фирмы или при управлении собственным капиталом. Искушение отыграть убытки, увеличить размер лотов после серии проигрышей или игнорировать дневные лимиты часто приводит к нарушению правил просадки и преждевременному обнулению счетов. Даже опытные трейдеры могут попасть в ловушку несоблюдения ежедневных пороговых значений риска, что приводит к нестабильной доходности и неспособности достичь долгосрочной прибыльности или пройти отбор для проп-трейдинга.

Матрица показателей эффективности счета представляет собой практическое решение, выступая в качестве встроенного менеджера рисков и наставника по вопросам дисциплины. Предоставляя трейдерам возможность устанавливать собственный ежедневный процент риска, всегда в пределах правил максимальной просадки, система в режиме реального времени автоматически отслеживает состояние счета, ежедневную прибыль/убыток и просадки. При достижении дневного порога риска индикатор закрывает все позиции и блокирует торговлю до начала следующей торговой сессии, исключая возможность торговли «из мести» или чрезмерной торговли «на эмоциях». Эта структура помогает трейдерам добиваться последовательности, защищать свой капитал и повышать шансы на успешное прохождение проверок со стороны проп-фирм или на стабильный рост личных счетов.



Планирование и логика

1. Настройка системы сохранения:

  • Баланс счета = 10 000 долларов США
  • Максимальная общая просадка (6%) = 600 долларов США
  • Максимальная суточная просадка (8%) = 800 долларов США
  • Ежедневный риск (1%) = 100 долларов США

Торговая операция может приносить убытки в размере не более 100 долларов в день. Это дает им 6 убыточных дней до достижения максимальной просадки, что находится в пределах допустимых значений, установленных инвестиционной компанией.

2. Умеренная настройка:

  • Баланс счета = 10 000 долларов США
  • Максимальная общая просадка (6%) = 600 долларов США
  • Максимальная дневная просадка (8%) = 800 долларов США
  • Ежедневный риск (2%) = 200 долларов США

Трейдер рискует 200 долларами в день. Теперь у них осталось около 3 дней до достижения максимальной просадки. Это позволяет торговать более агрессивно, но ограничивает свободу действий.

3. Агрессивная настройка (не рекомендуется):

  • Баланс счета = 10 000 долларов США
  • Максимальная общая просадка (6%) = 600 долларов США
  • Максимальная дневная просадка (8%) = 800 долларов США
  • Ежедневный риск (2%) = 200 долларов США

Один неудачный день может лишить вас 500 долларов, оставив очень мало места ниже максимального лимита просадки в 600 долларов. Такая схема практически гарантирует провал, если не контролировать риски.

Характеристики индикатора:

  • На панели управления отображаются показатели эффективности работы аккаунта.
  • Визуальный статус риска торговли
  • Прибыль/убыток (P/L) отображается на графике для открытых позиций.


Логика управления рисками


Начало работы

//+------------------------------------------------------------------+
//|                                                   Acc_Matrix.mq5 |
//|                        GIT under Copyright 2025, MetaQuotes Ltd. |
//|                     https://www.mql5.com/en/users/johnhlomohang/ |
//+------------------------------------------------------------------+
#property copyright "GIT under Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/johnhlomohang/"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrCrimson
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
#include <Trade\Trade.mqh>

//+------------------------------------------------------------------+
//| Input variables                                                  |
//+------------------------------------------------------------------+
input bool     ShowDashboard = true;           // Show performance dashboard
input bool     ShowProfit_Loss = true;         // Show Profit and Loss on the chart
input color    DashboardBGColor = clrWhiteSmoke; // Dashboard background color
input color    TextColor = clrBlack;           // Text color
input int      DashboardX = 20;                // Dashboard X position
input int      DashboardY = 20;                // Dashboard Y position
input int      DashboardWidth = 280;           // Dashboard width
input int      FontSize = 10;                  // Font size

// Performance tracking mode
input bool     TrackFromIndicatorStart = true; // Track from indicator start (true) or overall (false)

// Risk management parameters
input double   DailyRiskPercent = 1.0;         // Daily risk percentage
input double   MaxDailyDrawdownPercent = 10.0; // Max daily drawdown percentage
input double   MaxOverallDrawdownPercent = 8.0; // Max overall drawdown percentage
input bool     EnableRiskManagement = true;    // Enable risk management
input ulong    MagicNumber = 123456;           // Magic number for position identification

Начнем с раздела входных переменных, который позволяет трейдерам настраивать внешний вид и поведение индикатора. Они могут переключаться между отображением панели мониторинга, показом прибыли или убытка непосредственно на графике, а также настройкой визуальных свойств, таких как цвет фона, цвет текста, его положение и размер шрифта. Эти опции предоставляют трейдерам возможность гибко адаптировать визуальный интерфейс к своим личным предпочтениям, сохраняя при этом доступ к основным данным счета в режиме реального времени.

Самое важное, что параметры управления рисками превращают индикатор в нечто большее, чем просто инструмент визуализации. Трейдеры могут задавать свой ежедневный процент риска, максимальный ежедневный процент просадки и максимальный общий процент просадки, гарантируя тем самым, что система будет поддерживать дисциплину и предотвращать безрассудную торговлю. С помощью включения функции управления рисками индикатор может отслеживать сделки (с помощью идентификации «магическим числом») и отправлять оповещения при превышении лимитов. Эта возможность помогает трейдерам поддерживать стабильность, избегать чрезмерной торговли и соблюдать правила проверки сделок, установленным проп-фирмами или следовать стратегиям роста личного счета.

//+------------------------------------------------------------------+
//| Indicator buffers                                                |
//+------------------------------------------------------------------+
double         BidBuffer[];
double         AskBuffer[];

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
double         currentProfit;
double         balance;
double         equity;
double         margin;
double         freeMargin;
double         marginLevel;
int            totalOrders;
double         totalProfit;
double         dailyProfit;
datetime       lastTradeTime;
int            winCount;
int            lossCount;
double         maxDrawdown;
double         maxDrawdownPercent;

// Risk management variables
double         initialBalance;
double         dailyHighEquity;
double         dailyLowEquity;
double         dailyStartEquity;
bool           tradingEnabled = true;
string         riskStatus = "Trading Enabled";
color          riskStatusColor = clrGreen;

// Performance tracking variables
int            totalClosedTrades;
int            closedWinCount;
int            closedLossCount;
double         totalGains;
double         totalLosses;
double         largestWin;
double         largestLoss;
double         averageWin;
double         averageLoss;
double         profitFactor;

// Track the last time history was updated
datetime       lastHistoryUpdate;
bool           firstUpdate = true;

В этом разделе кода определены глобальные переменные, которые индикатор использует для отслеживания эффективности, управления рисками и истории торгов по всем торговым сессиям. Первая группа переменных касается показателей эффективности работы счета, таких как текущая прибыль, остаток на счете, собственный капитал, маржа, свободная маржа и уровень маржи. Она также отслеживает количество открытых ордеров, общую прибыль, дневную прибыль, время последней сделки, а также количество выигрышных и проигрышных сделок. Кроме того, с их помощью отслеживают максимальную просадку стоимости активов как в абсолютном выражении, так и в процентах, что имеет решающее значение для оценки степени риска.

Вторая группа переменных выделена для управления рисками. Здесь код хранит исходный баланс на момент начала отслеживания, а также ежедневные максимальные, минимальные и начальные уровни собственного капитала. Эти показатели помогают измерять ежедневные колебания производительности и обеспечивать дисциплину, выявляя нарушения дневных или общих лимитов. Флаг tradingEnabled действует как главный переключатель: при превышении пороговых значений риска он отправляет оповещения. Визуальный элемент, реализованный с помощью строкового параметра riskStatus и параметра riskStatusColor, обеспечивает трейдеру четкую обратную связь на графике, показывая, например, сообщение «Торговля разрешена» зеленым цветом или предупреждения красным.

В заключительную группу входят переменные отслеживания эффективности для анализа закрытых сделок. Это включает в себя общее количество закрытых сделок, количество выигрышных и проигрышных сделок, совокупные прибыли и совокупные убытки, а также крупнейший зафиксированный выигрыш и крупнейший зафиксированный убыток. Кроме того, в ней рассчитываются средние значения выигрышей и проигрышей, а также профит-фактор (коэффициент прибыли), который является ключевым показателем эффективности, сравнивающим прибыли и убытки. Для обеспечения точности обновлений система отслеживает, когда история обновлялась в последний раз и является ли это первым обновлением с момента инициализации. Все вместе эти переменные дают трейдерам всестороннее представление об эффективности их торговли, что повышает согласованность результатов.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{

   IndicatorSetString(INDICATOR_SHORTNAME, "ACCOUNT PERFORMANCE MATRIX");
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
   
   // Initialize variables
   currentProfit = 0.0;
   balance = AccountInfoDouble(ACCOUNT_BALANCE);
   equity = AccountInfoDouble(ACCOUNT_EQUITY);
   
   // Set initial balance based on tracking mode
   if(TrackFromIndicatorStart)
   {
      initialBalance = balance;
   }
   else
   {
      // For overall tracking, use the actual account balance
      initialBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   }
   
   dailyStartEquity = equity;
   dailyHighEquity = equity;
   dailyLowEquity = equity;
   lastHistoryUpdate = TimeCurrent();
   
   // Load historical trade data based on tracking mode
   LoadHistory();
   
   // Create dashboard objects if enabled
   if(ShowDashboard)
   {
      CreateDashboard();
   }
   
   // Set timer to update every second
   EventSetTimer(1);
   
   return(INIT_SUCCEEDED);
}

Функция OnInit() инициализирует пользовательский индикатор, устанавливая его отображаемое имя, точность и подготавливая к использованию все переменные для отслеживания производительности. Она сбрасывает текущую прибыль, восстанавливает баланс и капитал счета, а также определяет начальный баланс в зависимости от того, хочет пользователь отслеживать результаты с момента установки индикатора или на протяжении всей истории счета. Кроме того, она устанавливает начальный уровень капитала на день, одновременно регистрируя максимальные и минимальные значения капитала для оценки внутридневной доходности. Исторические данные о сделках загружаются с помощью функции LoadHistory() для обеспечения контекста для расчетов, а если включена опция панели мониторинга, визуальная панель производительности создается с помощью функции CreateDashboard(). Наконец, эта функция активирует событие таймера с обновлением каждую одну секунду, чтобы обеспечить сохранение синхронизации всех показателей счета и визуальных инструментов панели управления с торговой активностью в реальном времени.

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // Delete all objects created by the indicator
   ObjectsDeleteAll(0, 0, -1);
   EventKillTimer();
}

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
{
   // Update account information
   UpdateAccountInfo();
   
   // Update historical data periodically to capture new closed trades
   if(TimeCurrent() - lastHistoryUpdate >= 5 || firstUpdate) // Update every 5 seconds or on first run
   {
      LoadHistory();
      lastHistoryUpdate = TimeCurrent();
      firstUpdate = false;
   }
   
   // Update dashboard if enabled
   if(ShowDashboard)
   {
      UpdateDashboard();
   }
   
   // Check risk management rules
   if(EnableRiskManagement)
   {
      CheckRiskManagement();
   }
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   // Update bid and ask buffers
   if(ShowProfit_Loss)
   {
      UpdatePriceBuffers(rates_total, BidBuffer, AskBuffer, time);
   }
   
   return(rates_total);
}

//+------------------------------------------------------------------+
//| Update account information function                              |
//+------------------------------------------------------------------+
void UpdateAccountInfo()
{
   balance = AccountInfoDouble(ACCOUNT_BALANCE);
   equity = AccountInfoDouble(ACCOUNT_EQUITY);
   margin = AccountInfoDouble(ACCOUNT_MARGIN);
   freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   marginLevel = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
   
   // Update daily high/low equity
   if(equity > dailyHighEquity) dailyHighEquity = equity;
   if(equity < dailyLowEquity) dailyLowEquity = equity;
   
   CalculateProfitMetrics();
   CalculateTradeMetrics();
}

Функция OnDeinit() обеспечивает корректное завершение работы индикатора путем удаления всех созданных им объектов на графике и отключения события таймера для остановки фоновых обновлений. Это предотвращает загромождение графика после удаления индикатора и гарантирует, что никакие ненужные процессы не останутся активными. Функция OnTimer(), которая запускается каждую секунду, является центральной для функциональности индикатора: она непрерывно обновляет информацию об учетной записи, обновляет исторические данные о сделках каждые пять секунд (или при первом запуске) и управляет панелью мониторинга производительности, если она включена. Кроме того, она проверяет и обеспечивает соблюдение правил управления рисками, гарантируя, что при достижении пороговых значений риска трейдер получает оповещения в режиме реального времени.

Между тем, функция OnCalculate() интегрирует индикатор с обновлениями графика, гарантируя, что если отображение прибыли/убытка включено, то линии Bid и Ask обновляются через ценовые буферы. Функция UpdateAccountInfo() получает актуальные данные по счету, такие как баланс, капитал, маржа и свободная маржа, а также записывает ежедневные максимальные и минимальные значения капитала для точного отслеживания эффективности. Затем она вызывает вспомогательные функции, такие как CalculateProfitMetrics() и CalculateTradeMetrics(), для дальнейшего анализа производительности. Вместе эти функции создают самообновляющуюся, учитывающую риски панель мониторинга, которая предоставляет трейдерам полную информацию о состоянии их счета и активно способствует соблюдению дисциплины.

//+------------------------------------------------------------------+
//| Update account information function                              |
//+------------------------------------------------------------------+
void UpdateAccountInfo()
{
   balance = AccountInfoDouble(ACCOUNT_BALANCE);
   equity = AccountInfoDouble(ACCOUNT_EQUITY);
   margin = AccountInfoDouble(ACCOUNT_MARGIN);
   freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   marginLevel = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
   
   // Update daily high/low equity
   if(equity > dailyHighEquity) dailyHighEquity = equity;
   if(equity < dailyLowEquity) dailyLowEquity = equity;
   
   CalculateProfitMetrics();
   CalculateTradeMetrics();
}

//+------------------------------------------------------------------+
//| Update price buffers with Bid and Ask values                     |
//+------------------------------------------------------------------+
void UpdatePriceBuffers(int rates_total, double &bidBuffer[], double &askBuffer[], const datetime &time[])
{
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   
   // Calculate current profit for open positions
   currentProfit = 0.0;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if(PositionGetSymbol(i) == _Symbol)
      {
         currentProfit += PositionGetDouble(POSITION_PROFIT);
      }
   }
   
   // Fill buffers with current bid and ask values
   if(ShowProfit_Loss && rates_total > 0)
   {
      for(int i = 0; i < rates_total; i++)
      {
         bidBuffer[i] = bid;
         askBuffer[i] = ask;
      }
      
      // Calculate position for labels (2 bars to the right of current candle)
      int currentBar = rates_total - 1;
      datetime labelTime = (currentBar + 2 < rates_total) ? time[currentBar + 2] : time[currentBar] + PeriodSeconds() * 2;
      
      // Add profit/loss label with color coding
      string plLabelText;
      color plColor;
      if(currentProfit >= 0)
      {
         plLabelText = "Profit: " + DoubleToString(currentProfit, 2);
         plColor = clrBlue;
      }
      else
      {
         plLabelText = "Loss: " + DoubleToString(currentProfit, 2);
         plColor = clrRed;
      }
      
      CreateOrUpdateLabel("PLLabel", plLabelText, labelTime, (bid + ask) / 2, plColor, ANCHOR_RIGHT);
   }
}

Функция UpdateAccountInfo() отвечает за получение актуальных данных об учетной записи и отслеживание важных показателей производительности. Эта функция извлекает из торгового счета текущий баланс, капитал, маржу, свободную маржу и уровень маржи. Более того, она отслеживает внутридневные колебания цен на акции, обновляя дневные максимумы и минимумы цен акций всякий раз, когда достигается новый крайний уровень. После обновления исходных данных счета эта функция вызывает функции CalculateProfitMetrics() и CalculateTradeMetrics(), которые выполняют более глубокий анализ, такой как расчет прибыли, отслеживание выигрышных/проигрышных сделок и оценка эффективности. Это обеспечивает постоянное отображение на панели управления самых актуальных данных об учетной записи.

Функция UpdatePriceBuffers() ориентирована на визуализацию цен и прибылей/убытков. Сначала она получает текущие цены Bid и Ask, затем перебирает открытые позиции, чтобы рассчитать текущую прибыль для активного символа. Если включена визуализация прибылей/убытков, она заполняет буферы индикатора последними значениями Bid и Ask по всему графику и создает метку, расположенную немного правее текущего бара. Эта метка отображает либо прибыль (синий цвет), либо убыток (красный цвет) в зависимости от текущего результата сделки. Сочетая отслеживание эффективности счета с визуализацией цен и прибыли в реальном времени, эта функция предоставляет трейдерам как числовую, так и графическую обратную связь, что улучшает осведомленность о ситуации и облегчает принятие решений.

//+------------------------------------------------------------------+
//| Create or update text label                                      |
//+------------------------------------------------------------------+
void CreateOrUpdateLabel(string name, string text, datetime time, double price, color clr, ENUM_ANCHOR_POINT anchor)
{
   if(ObjectFind(0, name) < 0)
   {
      ObjectCreate(0, name, OBJ_TEXT, 0, time, price);
      ObjectSetString(0, name, OBJPROP_TEXT, text);
      ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0, name, OBJPROP_ANCHOR, anchor);
      ObjectSetInteger(0, name, OBJPROP_FONTSIZE, FontSize);
   }
   else
   {
      ObjectMove(0, name, 0, time, price);
      ObjectSetString(0, name, OBJPROP_TEXT, text);
      ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
   }
}

//+------------------------------------------------------------------+
//| Calculate profit metrics                                         |
//+------------------------------------------------------------------+
void CalculateProfitMetrics()
{
   totalProfit = equity - initialBalance;
   
   // Calculate max drawdown - FIXED: Prevent division by zero
   double drawdown = dailyHighEquity - equity;
   if(drawdown > maxDrawdown)
   {
      maxDrawdown = drawdown;
      // Avoid division by zero - use a small epsilon if dailyHighEquity is zero
      double denominator = (dailyHighEquity == 0) ? 0.000001 : dailyHighEquity;
      maxDrawdownPercent = (drawdown / denominator) * 100;
   }
}

Функция UpdateAccountInfo() отвечает за получение актуальных данных об учетной записи и отслеживание важных показателей производительности. Эта функция извлекает из торгового счета текущий баланс, капитал, маржу, свободную маржу и уровень маржи. Более того, она отслеживает внутридневные колебания цен на акции, обновляя дневные максимумы и минимумы цен акций всякий раз, когда достигается новый крайний уровень. После обновления исходных данных счета функция вызывает функции CalculateProfitMetrics() и CalculateTradeMetrics(), которые выполняют более углубленный анализ, такой как расчет прибыли, отслеживание выигрышных/проигрышных сделок и оценка эффективности. Это обеспечивает постоянное отображение на панели управления самых актуальных данных об учетной записи.<br0/>

Функция UpdatePriceBuffers() ориентирована на визуализацию цен и прибылей/убытков. Сначала она получает текущие цены Bid и Ask, затем перебирает открытые позиции, чтобы рассчитать текущую прибыль для активного символа. Если включена визуализация прибылей/убытков, она заполняет буферы индикатора последними значениями Bid и Ask по всему графику и создает метку, расположенную немного правее текущего бара. Эта метка отображает либо прибыль (синий цвет), либо убыток (красный цвет) в зависимости от текущего результата сделки. Сочетая отслеживание эффективности счета с визуализацией цен и прибыли в реальном времени, эта функция предоставляет трейдерам как числовую, так и графическую обратную связь, что улучшает осведомленность о ситуации и облегчает принятие решений.

//+------------------------------------------------------------------+
//| Calculate trade metrics                                          |
//+------------------------------------------------------------------+
void CalculateTradeMetrics()
{
   totalOrders = PositionsTotal();
   winCount = 0;
   lossCount = 0;
   
   // Count winning and losing positions
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket))
      {
         double profit = PositionGetDouble(POSITION_PROFIT);
         if(profit > 0) winCount++;
         else if(profit < 0) lossCount++;
      }
   }
}

//+------------------------------------------------------------------+
//| Load historical trade data                                       |
//+------------------------------------------------------------------+
void LoadHistory()
{
   datetime startDate = 0;
   if(TrackFromIndicatorStart)
   {
      // Only load history from when the indicator was started
      startDate = TimeCurrent() - 86400; // Load from 24 hours ago to ensure we capture all recent trades
   }
   
   HistorySelect(startDate, TimeCurrent());
   int totalHistory = HistoryDealsTotal();
   
   // Reset counters
   int newClosedTrades = 0;
   int newClosedWinCount = 0;
   int newClosedLossCount = 0;
   double newTotalGains = 0;
   double newTotalLosses = 0;
   double newLargestWin = 0;
   double newLargestLoss = 0;
   
   for(int i = 0; i < totalHistory; i++)
   {
      ulong ticket = HistoryDealGetTicket(i);
      if(ticket > 0)
      {
         // Check if this is a closing deal (not a deposit/withdrawal or opening trade)
         long dealType = HistoryDealGetInteger(ticket, DEAL_TYPE);
         if(dealType == DEAL_TYPE_BUY || dealType == DEAL_TYPE_SELL)
         {
            double profit = HistoryDealGetDouble(ticket, DEAL_PROFIT);
            if(profit != 0)
            {
               newClosedTrades++;
               if(profit > 0)
               {
                  newClosedWinCount++;
                  newTotalGains += profit;
                  if(profit > newLargestWin) newLargestWin = profit;
               }
               else
               {
                  newClosedLossCount++;
                  newTotalLosses += MathAbs(profit);
                  if(profit < newLargestLoss) newLargestLoss = profit;
               }
            }
         }
      }
   }
   
   // Update the global variables
   totalClosedTrades = newClosedTrades;
   closedWinCount = newClosedWinCount;
   closedLossCount = newClosedLossCount;
   totalGains = newTotalGains;
   totalLosses = newTotalLosses;
   largestWin = newLargestWin;
   largestLoss = newLargestLoss;
   
   // Calculate averages and profit factor
   averageWin = (closedWinCount > 0) ? totalGains / closedWinCount : 0;
   averageLoss = (closedLossCount > 0) ? totalLosses / closedLossCount : 0;
   profitFactor = (totalLosses > 0) ? totalGains / totalLosses : (totalGains > 0) ? 1000 : 0;
}

Функция CalcculateTradeMetrics() предоставляет актуальную информацию об открытых торговых позициях, подсчитывая, сколько из них в данный момент находятся в плюсе, а сколько — в минусе. Процесс начинается с получения общего количества открытых позиций, затем проходит цикл по каждой из них, проверяя значение прибыли или убытка. Если позиция прибыльная, она увеличивает счетчик выигрышей, а если убыточная, увеличивается счетчик проигрышей. Эта функция предоставляет трейдерам мгновенную обратную связь относительно качества открытых ими сделок, помогая оценить в режиме реального времени, соответствуют ли их позиции торговому плану.

Функция LoadHistory() позволяет глубже изучить историческую динамику, анализируя закрытые сделки в пределах указанного периода времени. Если отслеживание настроено с момента запуска индикатора, она загружает историю за последние 24 часа, чтобы гарантировать включение в нее недавних сделок. Затем система сканирует все исторические сделки, отфильтровывая только закрываемые сделки купли-продажи, игнорируя депозиты, снятия средств или записи. Для каждой закрытой сделки она регистрирует прибыль или убыток, обновляет данные о выигрышах и проигрышах, суммирует общие прибыли и убытки, а также отслеживает крупнейший отдельный выигрыш или проигрыш. Наконец, программа рассчитывает средние значения и профит-фактор — ключевой показатель, позволяющий сравнивать прибыли и убытки. Этот всесторонний анализ эффективности позволяет трейдерам выявлять закономерности в своем торговом поведении, оценивать прибыльность и в течение длительного времени поддерживать дисциплинированное управление рисками.

//+------------------------------------------------------------------+
//| Check risk management rules                                      |
//+------------------------------------------------------------------+
void CheckRiskManagement()
{
   // Check if it's a new day (reset daily equity)
   MqlDateTime today, lastCheck;
   TimeToStruct(TimeCurrent(), today);
   TimeToStruct(TimeCurrent(), lastCheck);
   
   static int lastDay = -1;
   if(today.day != lastDay)
   {
      dailyStartEquity = equity;
      dailyHighEquity = equity;
      dailyLowEquity = equity;
      lastDay = today.day;
      
      // Re-enable trading at the start of a new day
      if(!tradingEnabled)
      {
         tradingEnabled = true;
         riskStatus = "Trading Enabled";
         riskStatusColor = clrGreen;
      }
   }
   
   // Calculate daily drawdown percentage - FIXED: Prevent division by zero
   double dailyDrawdownPercent = 0;
   if(dailyHighEquity > 0) 
   {
      dailyDrawdownPercent = (dailyHighEquity - equity) / dailyHighEquity * 100;
   }
   
   // Calculate overall drawdown percentage - FIXED: Prevent division by zero
   double overallDrawdownPercent = 0;
   if(initialBalance > 0) 
   {
      overallDrawdownPercent = (initialBalance - equity) / initialBalance * 100;
   }
   
   double dailyRiskEquity = dailyStartEquity * (1 - DailyRiskPercent / 100);
   
   // Check if we've hit risk limits
   if(tradingEnabled)
   {
      if(equity <= dailyRiskEquity)
      {
         riskStatus = "Daily Risk Limit Reached";
         riskStatusColor = clrRed;
         tradingEnabled = false;
         Alert("Daily Risk Limit Reached, Consider Closing Open Positions!!!");
         
      }
      else if(dailyDrawdownPercent >= MaxDailyDrawdownPercent)
      {
         riskStatus = "Max Daily Drawdown Reached";
         riskStatusColor = clrRed;
         tradingEnabled = false;
         Alert("Max Daily Drawdown Reached!!!");
         
      }
      else if(overallDrawdownPercent >= MaxOverallDrawdownPercent)
      {
         riskStatus = "Max Overall Drawdown Reached";
         riskStatusColor = clrRed;
         tradingEnabled = false;
         Alert("Max Overall Drawdown Reached!!!");
         
      }
   }
}

//+------------------------------------------------------------------+
//| Create dashboard function                                        |
//+------------------------------------------------------------------+
void CreateDashboard()
{
   // Create background rectangle
   ObjectCreate(0, "DashboardBG", OBJ_RECTANGLE_LABEL, 0, 0, 0);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_XDISTANCE, DashboardX);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_YDISTANCE, DashboardY);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_XSIZE, DashboardWidth);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_YSIZE, 320);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_BGCOLOR, DashboardBGColor);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_BORDER_TYPE, BORDER_FLAT);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_BORDER_COLOR, clrGray);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_BACK, true);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_SELECTED, false);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_HIDDEN, true);
   ObjectSetInteger(0, "DashboardBG", OBJPROP_ZORDER, 0);
   
   // Create title
   ObjectCreate(0, "DashboardTitle", OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, "DashboardTitle", OBJPROP_XDISTANCE, DashboardX + 10);
   ObjectSetInteger(0, "DashboardTitle", OBJPROP_YDISTANCE, DashboardY + 10);
   ObjectSetString(0, "DashboardTitle", OBJPROP_TEXT, "ACCOUNT PERFORMANCE MATRIX");
   ObjectSetInteger(0, "DashboardTitle", OBJPROP_COLOR, TextColor);
   ObjectSetInteger(0, "DashboardTitle", OBJPROP_FONTSIZE, FontSize + 2);
   
   // Create tracking mode indicator
   string trackingMode = TrackFromIndicatorStart ? "From Indicator Start" : "Overall Account";
   ObjectCreate(0, "TrackingModeLabel", OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, "TrackingModeLabel", OBJPROP_XDISTANCE, DashboardX + 10);
   ObjectSetInteger(0, "TrackingModeLabel", OBJPROP_YDISTANCE, DashboardY + 30);
   ObjectSetString(0, "TrackingModeLabel", OBJPROP_TEXT, "Tracking: " + trackingMode);
   ObjectSetInteger(0, "TrackingModeLabel", OBJPROP_COLOR, clrDarkBlue);
   ObjectSetInteger(0, "TrackingModeLabel", OBJPROP_FONTSIZE, FontSize);
   
   // Create information labels
   CreateDashboardLabel("RiskStatusLabel", "Trading Status: ", 50, DashboardX, DashboardY);
   CreateDashboardLabel("BalanceLabel", "Balance: ", 70, DashboardX, DashboardY);
   CreateDashboardLabel("EquityLabel", "Equity: ", 90, DashboardX, DashboardY);
   CreateDashboardLabel("DailyProfitLabel", "Daily P/L: ", 110, DashboardX, DashboardY);
   CreateDashboardLabel("TotalProfitLabel", "Total P/L: ", 130, DashboardX, DashboardY);
   CreateDashboardLabel("PositionsLabel", "Open Positions: ", 150, DashboardX, DashboardY);
   CreateDashboardLabel("WinRateLabel", "Win Rate: ", 170, DashboardX, DashboardY);
   CreateDashboardLabel("DailyRiskLabel", "Daily Risk: ", 190, DashboardX, DashboardY);
   CreateDashboardLabel("DailyDrawdownLabel", "Daily Drawdown: ", 210, DashboardX, DashboardY);
   CreateDashboardLabel("TotalDrawdownLabel", "Total Drawdown: ", 230, DashboardX, DashboardY);
   CreateDashboardLabel("ProfitFactorLabel", "Profit Factor: ", 250, DashboardX, DashboardY);
   CreateDashboardLabel("TradesLabel", "Total Trades: ", 270, DashboardX, DashboardY);
   CreateDashboardLabel("AvgWinLossLabel", "Avg Win/Loss: ", 290, DashboardX, DashboardY);
}

Функция CheckRiskManagement() — это механизм контроля, который обеспечивает соблюдение трейдерами своего плана управления рисками и не позволяют превышать лимиты счета. Затем программа рассчитывает ежедневный и общий проценты просадки, тщательно проверяя наличие деления на ноль во избежание ошибок. Функция сравнивает текущий остаток на счете с предварительно заданным трейдером дневным лимитом риска, максимальной дневной просадкой и максимальной общей просадкой. При превышении какого-либо из этих пороговых значений сообщение о состоянии станет красным, и сработают оповещения, предупреждающие трейдера. Такой подход не только помогает предотвратить катастрофические потери, но и прививает дисциплину, устраняя соблазн продолжать торговлю после достижения лимитных значений.

Функция CreateDashboard() создает экранный интерфейс, отображающий все отслеживаемые показатели на организованной и визуально понятной панели. Процесс начинается с создания фонового прямоугольника, оформленного заданными пользователем цветами, размерами и границами, который будет служить контейнером для всех данных об эффективности. Затем добавляются заголовок и метка режима отслеживания, чтобы указать, отслеживает панель мониторинга результаты с момента запуска индикатора или за всю историю учетной записи. Ниже, в структурированных строках, расположен ряд полей с соответствующими метками, таких как баланс, капитал, ежедневная и общая прибыль/убыток, процент выигрышей, просадки, профит-фактор и средний выигрыш/убыток. Эта визуальная панель мониторинга позволяет трейдерам мгновенно оценивать как состояние своего счета, так и уровень риска, не углубляясь в многочисленные отчеты, что делает ее мощным инструментом для поддержания ясности и дисциплины в торговле.

//+------------------------------------------------------------------+
//| Create dashboard label helper function                           |
//+------------------------------------------------------------------+
void CreateDashboardLabel(string name, string text, int yOffset, int x, int y)
{
   ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x + 10);
   ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y + yOffset);
   ObjectSetString(0, name, OBJPROP_TEXT, text);
   ObjectSetInteger(0, name, OBJPROP_COLOR, TextColor);
   ObjectSetInteger(0, name, OBJPROP_FONTSIZE, FontSize);
}

//+------------------------------------------------------------------+
//| Update dashboard function                                        |
//+------------------------------------------------------------------+
void UpdateDashboard()
{
   // Update risk status with color coding
   ObjectSetString(0, "RiskStatusLabel", OBJPROP_TEXT, "Trading Status: " + riskStatus);
   ObjectSetInteger(0, "RiskStatusLabel", OBJPROP_COLOR, riskStatusColor);
   
   // Update values for all dashboard labels
   UpdateDashboardLabel("BalanceLabel", "Balance: " + DoubleToString(balance, 2));
   UpdateDashboardLabel("EquityLabel", "Equity: " + DoubleToString(equity, 2));
   
   // Color code profit values
   double dailyPL = equity - dailyStartEquity;
   string dailyPLText = "Daily P/L: ";
   if(dailyPL >= 0) dailyPLText += "+" + DoubleToString(dailyPL, 2);
   else dailyPLText += DoubleToString(dailyPL, 2);
   UpdateDashboardLabel("DailyProfitLabel", dailyPLText);
   
   string totalPLText = "Total P/L: ";
   if(totalProfit >= 0) totalPLText += "+" + DoubleToString(totalProfit, 2);
   else totalPLText += DoubleToString(totalProfit, 2);
   UpdateDashboardLabel("TotalProfitLabel", totalPLText);
   
   UpdateDashboardLabel("PositionsLabel", "Open Positions: " + IntegerToString(totalOrders));
   
   // Calculate and display win rate from closed trades
   int totalTrades = closedWinCount + closedLossCount;
   string winRateText = "Win Rate: ";
   if(totalTrades > 0) 
   {
      double winRate = (double)closedWinCount / totalTrades * 100;
      winRateText += DoubleToString(winRate, 1) + "% (" + IntegerToString(closedWinCount) + 
                    "/" + IntegerToString(totalTrades) + ")";
   }
   else winRateText += "N/A";
   UpdateDashboardLabel("WinRateLabel", winRateText);
   
   // Risk metrics
   double dailyRiskEquity = dailyStartEquity * (1 - DailyRiskPercent / 100);
   
   // Calculate drawdown percentages with zero division protection
   double dailyDrawdownPercent = 0;
   if(dailyHighEquity > 0) 
   {
      dailyDrawdownPercent = (dailyHighEquity - equity) / dailyHighEquity * 100;
   }
   
   double overallDrawdownPercent = 0;
   if(initialBalance > 0) 
   {
      overallDrawdownPercent = (initialBalance - equity) / initialBalance * 100;
   }
   
   UpdateDashboardLabel("DailyRiskLabel", "Daily Risk: " + DoubleToString(DailyRiskPercent, 1) + 
                       "% (" + DoubleToString(dailyRiskEquity, 2) + ")");
   
   string dailyDrawdownText = "Daily Drawdown: " + DoubleToString(dailyDrawdownPercent, 1) + "%";
   UpdateDashboardLabel("DailyDrawdownLabel", dailyDrawdownText);
   
   string totalDrawdownText = "Total Drawdown: " + DoubleToString(overallDrawdownPercent, 1) + "%";
   UpdateDashboardLabel("TotalDrawdownLabel", totalDrawdownText);
   
   // Performance metrics
   UpdateDashboardLabel("ProfitFactorLabel", "Profit Factor: " + DoubleToString(profitFactor, 2));
   UpdateDashboardLabel("TradesLabel", "Total Trades: " + IntegerToString(totalClosedTrades));
   UpdateDashboardLabel("AvgWinLossLabel", "Avg Win/Loss: " + DoubleToString(averageWin, 2) + 
                       "/" + DoubleToString(MathAbs(averageLoss), 2));
}

//+------------------------------------------------------------------+
//| Update dashboard label helper function                           |
//+------------------------------------------------------------------+
void UpdateDashboardLabel(string name, string text)
{
   ObjectSetString(0, name, OBJPROP_TEXT, text);
}

Функция CreateDashboardLabel() служит вспомогательным инструментом для быстрого создания полей с метками на панели мониторинга. Каждая метка создается с заданными именем, текстом и смещением позиции, и к ней применяется единообразный стиль, например размер и цвет шрифта. Это гарантирует, что все показатели на панели управления будут четко видны и отформатированы в едином стиле, предоставляя трейдерам упорядоченный обзор эффективности счета и состояния риска.

Функция UpdateDashboard() непрерывно обновляет панель мониторинга, отображая актуальные данные об учетных записях и показателях эффективности. Она обновляет все ключевые показатели, включая баланс, капитал, ежедневную и общую прибыль/убыток, открытые позиции, процент выигрышных сделок, просадки, ежедневный риск, профит-фактор, общее количество сделок и средний процент выигрышных/проигрышных сделок. Кроме того, эта функция использует цветовую кодировку для важной информации, такой как прибыль/убыток и статус сделки, обеспечивая мгновенную визуальную обратную связь. Постоянно отражая состояние счета в режиме реального времени, система помогает трейдерам принимать обоснованные решения, укрепляет дисциплину и предотвращает чрезмерную торговлю, четко отображая моменты достижения лимитов по рискам.

Демонстрационный индикатор:



Заключение

Резюмируя все сказанное выше: мы разработали собственный индикатор матрицы эффективности счета, который отслеживает как показатели торговой активности в реальном времени, так и исторические данные. Этот индикатор отслеживает ключевые показатели счета, такие как баланс, собственный капитал, маржа, открытые позиции, ежедневная и общая прибыль/убыток, процент выигрышных сделок, просадки, коэффициент прибыльности (профит-фактор) и среднее соотношение выигрышных и проигрышных сделок. Он включает в себя динамическую панель управления с визуальными метками и цветовыми оповещениями, предоставляющую трейдерам четкое и систематизированное представление о результатах работы их счета. В систему интегрированы правила управления рисками, обеспечивающие соблюдение ежедневных лимитов по рискам и максимальных просадок; при достижении этих лимитов система оповещает трейдера о текущей динамике счета.

В заключение скажем, что этот индикатор помогает трейдерам поддерживать дисциплину, избегать чрезмерной торговли и принимать более обоснованные решения, предоставляя прозрачный обзор состояния счета и степени подверженности риску. Четко указывая на приближение к пороговым значениям риска или их превышении, он стимулирует последовательное торговое поведение и способствует устойчивому росту. Независимо от того, готовится трейдер к сдаче экзамена в проп-трейдерской фирме или управляет личным торговым счетом, этот инструмент дает структурированные рекомендации по управлению рисками, оптимизации торговых решений и, в конечном итоге, повышению долгосрочной прибыльности.

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/19508

Прикрепленные файлы |
Acc_Matrix.mq5 (25.52 KB)
Знакомство с языком MQL5 (Часть 32): Освоение API и функции WebRequest в языке MQL5 (VI) Знакомство с языком MQL5 (Часть 32): Освоение API и функции WebRequest в языке MQL5 (VI)
В этой статье мы покажем, как визуализировать свечные данные, полученные с помощью функции WebRequest и API, в свечном формате. Мы будем использовать язык MQL5, чтобы считывать свечные данные из CSV-файла и отображать их на графике в виде пользовательских свечей, поскольку индикаторы не могут напрямую использовать функцию WebRequest.
От новичка до эксперта: Разработка стратегии торговли по зонам ликвидности От новичка до эксперта: Разработка стратегии торговли по зонам ликвидности
Торговля в зонах ликвидности обычно ведется путем ожидания возврата цены и повторного тестирования интересующей зоны, часто путем размещения отложенных ордеров в этих областях. В этой статье мы используем MQL5, чтобы воплотить эту концепцию в жизнь, демонстрируя, как такие зоны могут быть определены программно и как можно систематически применять управление рисками. Присоединяйтесь к обсуждению, поскольку мы исследуем как логику торговли на основе ликвидности, так и ее практическую реализацию.
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
Знакомство с языком MQL5 (Часть 30): Освоение API и функции WebRequest в языке MQL5 (IV) Знакомство с языком MQL5 (Часть 30): Освоение API и функции WebRequest в языке MQL5 (IV)
Ознакомьтесь с пошаговым руководством, которое упрощает извлечение, преобразование и организацию свечных данных из ответов API в среде MQL5. Это руководство отлично подходит новичкам, которые хотят улучшить навыки программирования и научиться эффективно управлять рыночными данными.