English Русский Deutsch 日本語
preview
Desarrollo de un indicador personalizado de matriz de rendimiento de cuenta

Desarrollo de un indicador personalizado de matriz de rendimiento de cuenta

MetaTrader 5 — Ejemplos |
30 0
Hlomohang John Borotho
Hlomohang John Borotho

Introducción

Muchos traders pueden tener dificultades con la operativa excesiva, la falta de disciplina y la toma de decisiones emocionales, especialmente cuando operan bajo estrictas reglas de prop firm o gestionan su propio capital. La tentación de intentar recuperar pérdidas, aumentar el tamaño de los lotes tras una racha perdedora o ignorar los límites diarios suele llevar a incumplir las reglas de drawdown y a quemar las cuentas prematuramente. Incluso los traders experimentados pueden caer en la trampa de no respetar los umbrales de riesgo diarios, lo que se traduce en un rendimiento irregular y en no lograr la rentabilidad a largo plazo ni superar retos de prop firm.

El indicador de matriz de rendimiento de la cuenta ofrece una solución práctica al actuar como gestor de riesgos integrado y como herramienta de disciplina. Al permitir que los traders establezcan su propio porcentaje de riesgo diario, siempre dentro de los límites de las reglas de drawdown máximo, realiza un seguimiento automático de la equity de la cuenta, las ganancias y pérdidas diarias, y los drawdowns en tiempo real. Si se alcanza el umbral de riesgo diario, el indicador cierra todas las posiciones, bloquea la operativa y emite alertas hasta que comience la siguiente sesión, lo que elimina la posibilidad de operar por revancha o de sobreoperar por motivos emocionales. Esta estructura ayuda a los traders a desarrollar constancia, proteger su capital y aumentar sus posibilidades de superar retos de prop firm o de hacer crecer de forma constante sus cuentas personales.



Planificación y lógica

1. Configuración conservadora:

  • Saldo de la cuenta = 10.000 $
  • Drawdown máximo total (6 %) = 600 $
  • Drawdown máximo diario (8 %) = 800 $
  • Riesgo diario (1 %) = 100 $

El trader solo puede perder 100 $ al día. Esto le da seis días de pérdidas antes de alcanzar el drawdown máximo, lo cual queda ampliamente dentro de los límites de seguridad de la prop firm.

2. Configuración moderada:

  • Saldo de la cuenta = 10.000 $
  • Drawdown máximo total (6 %) = 600 $
  • Drawdown máximo diario (8 %) = 800 $
  • Riesgo diario (2 %) = 200 $

El trader arriesga 200 $ al día. Ahora tiene unos tres días antes de alcanzar el drawdown máximo. Esto permite una mayor agresividad, pero deja menos margen de maniobra.

3. Configuración agresiva (no recomendada):

  • Saldo de la cuenta = 10.000 $
  • Drawdown máximo total (6 %) = 600 $
  • Drawdown máximo diario (8 %) = 800 $
  • Riesgo diario (5 %) = 500 $

Un mal día podría hacer perder 500 $, dejando muy poco margen por debajo del drawdown máximo de 600 $. Esta configuración casi garantiza el fracaso si no se controla el riesgo.

Características del indicador:

  • El panel muestra las métricas de rendimiento de la cuenta
  • Estado visual del riesgo de la operativa
  • Ganancias/pérdidas (P/L) mostradas en el gráfico para las posiciones abiertas


Lógica de gestión de riesgos


Primeros pasos

//+------------------------------------------------------------------+
//|                                                   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

Empezamos por la sección de variables de entrada, que permite a los traders personalizar el aspecto y el comportamiento del indicador. Los traders pueden activar o desactivar la visualización de un panel, mostrar las ganancias o pérdidas directamente en el gráfico y ajustar propiedades visuales como el color de fondo, el color del texto, la posición y el tamaño de la fuente. Estas opciones ofrecen a los traders flexibilidad para adaptar la interfaz visual a sus preferencias personales, al tiempo que mantienen visibles en tiempo real los datos esenciales de la cuenta.

Y lo más importante: los parámetros de gestión de riesgos hacen que el indicador sea algo más que una simple herramienta visual. Los traders pueden definir su porcentaje de riesgo diario, su porcentaje de drawdown máximo diario y su porcentaje de drawdown máximo total, lo que garantiza que el sistema imponga disciplina y evite operaciones imprudentes. Al activar la gestión de riesgos, el indicador puede supervisar las operaciones (mediante el «número mágico» para su identificación) y enviar alertas en cuanto se rebasen los límites. Esta función ayuda a los traders a mantener la coherencia, evitar la sobreoperación y ajustarse a las reglas de los retos de prop firm o a sus propias estrategias de crecimiento de la cuenta.

//+------------------------------------------------------------------+
//| 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;

En esta sección del código se definen las variables globales que utiliza el indicador para realizar un seguimiento del rendimiento, la gestión de riesgos y el historial de operaciones a lo largo de las sesiones. El primer grupo de variables se refiere a las métricas de rendimiento de la cuenta, como el beneficio actual, el saldo, la equity, el margen, el margen libre y el nivel de margen. Además, lleva un registro del número de órdenes abiertas, el beneficio total, el beneficio diario, la hora de la última operación y el recuento de operaciones ganadoras y perdedoras. Asimismo, supervisa el drawdown máximo tanto en valor absoluto como en porcentaje, lo cual es fundamental para evaluar la exposición al riesgo.

El segundo grupo de variables se centra en la gestión de riesgos. En este caso, el código almacena el saldo inicial cuando comienza el seguimiento, así como los niveles diarios de equity máxima, mínima e inicial. Estos valores ayudan a medir las fluctuaciones diarias del rendimiento y a mantener la disciplina al detectar incumplimientos de los límites diarios o generales. La variable booleana «tradingEnabled» actúa como un interruptor principal y, si se superan los umbrales de riesgo, envía alertas. Se incluye un elemento visual mediante la cadena «riskStatus» y la variable «riskStatusColor», que proporcionan al trader información clara directamente en el gráfico, por ejemplo mostrando «Trading Enabled» en verde o una advertencia en rojo.

El último grupo contiene variables de seguimiento del rendimiento para analizar las operaciones cerradas. Esto incluye el número total de operaciones cerradas, cuántas han sido ganadoras y perdedoras, las ganancias y pérdidas acumuladas, así como la mayor ganancia y la mayor pérdida registradas. Además, calcula los promedios de ganancias y pérdidas, así como el factor de beneficio, que es una métrica clave de rendimiento que compara las ganancias con las pérdidas. Para garantizar que las actualizaciones sean precisas, el sistema registra cuándo se actualizó por última vez el historial y si se trata de la primera actualización desde la inicialización. En conjunto, estas variables ofrecen a los traders una visión global de su rendimiento en las operaciones para mejorar la constancia.

//+------------------------------------------------------------------+
//| 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);
}

La función OnInit() inicializa el indicador personalizado estableciendo su nombre de visualización y su precisión, y preparando todas las variables de seguimiento del rendimiento para su uso. Restablece el beneficio actual, recupera el saldo y la equity de la cuenta, y determina el saldo inicial en función de si el usuario desea realizar un seguimiento del rendimiento desde el momento en que se adjunta el indicador o a lo largo de todo el historial de la cuenta. Además, establece la equity inicial del día y registra los valores máximo y mínimo de equity para medir el rendimiento intradía. Los datos históricos de operaciones se cargan mediante la función LoadHistory() para proporcionar contexto a los cálculos y, si la opción del panel está activada, se crea el panel visual de rendimiento con CreateDashboard(). Por último, la función activa un evento de temporizador con actualizaciones cada segundo para garantizar que todas las métricas de la cuenta y los elementos visuales del panel se mantengan sincronizados con la actividad de trading en tiempo real.

//+------------------------------------------------------------------+
//| 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();
}

La función OnDeinit() garantiza un cierre limpio del indicador eliminando todos los objetos del gráfico que ha creado y cancelando el evento del temporizador para detener las actualizaciones en segundo plano. Esto evita que queden elementos residuales en el gráfico tras eliminar el indicador y garantiza que no queden activos procesos innecesarios. La función OnTimer(), que se ejecuta cada segundo, es fundamental para el funcionamiento del indicador: actualiza continuamente la información de la cuenta, actualiza los datos históricos de operaciones cada cinco segundos (o en la primera ejecución) y gestiona el panel de rendimiento si está activado. Además, comprueba y aplica las normas de gestión de riesgos, garantizando que, una vez alcanzados los umbrales de riesgo, el trader reciba alertas en tiempo real.

Por otra parte, la función OnCalculate() integra el indicador con las actualizaciones del gráfico, lo que garantiza que, si se ha activado la visualización de ganancias/pérdidas, las líneas Bid y Ask se actualicen a través de los búferes de precios. La función UpdateAccountInfo() recupera datos en tiempo real de la cuenta, como el saldo, la equity, el margen y el margen libre, al tiempo que registra los valores diarios máximo y mínimo de equity para realizar un seguimiento preciso del rendimiento. Luego llama a funciones de apoyo como CalculateProfitMetrics() y CalculateTradeMetrics() para analizar el rendimiento con mayor detalle. En conjunto, estas funciones crean un panel que se actualiza automáticamente y tiene en cuenta el riesgo, lo que ofrece a los traders una visibilidad completa del estado de su cuenta al tiempo que hace cumplir activamente la disciplina.

//+------------------------------------------------------------------+
//| 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);
   }
}

La función UpdateAccountInfo() se encarga de recuperar datos de la cuenta en tiempo real y de realizar un seguimiento de los indicadores clave de rendimiento. Extrae el saldo actual, la equity, el margen, el margen libre y el nivel de margen de la cuenta de operaciones. Además, supervisa las fluctuaciones intradía de la equity actualizando los valores diarios máximo y mínimo de equity cada vez que se alcanza un nuevo extremo. Una vez actualizados los datos brutos de la cuenta, la función llama a CalculateProfitMetrics() y CalculateTradeMetrics(), que se encargan de realizar análisis más detallados, como el cálculo de beneficios, el seguimiento de operaciones ganadoras y perdedoras y la evaluación del rendimiento. Esto garantiza que el panel refleje siempre las condiciones más actualizadas de la cuenta.

La función UpdatePriceBuffers() se centra en la visualización de precios y de ganancias/pérdidas. En primer lugar, recupera los precios actuales Bid y Ask; a continuación, itera las posiciones abiertas para calcular el beneficio actual del símbolo activo. Si está activada la visualización de ganancias/pérdidas, rellena los búferes del indicador con los últimos valores Bid y Ask a lo largo del gráfico y crea una etiqueta situada ligeramente a la derecha de la barra actual. Esta etiqueta muestra una ganancia (azul) o una pérdida (rojo), dependiendo del resultado actual de la operación. Combinando el seguimiento del rendimiento de la cuenta con la visualización en tiempo real de precios y ganancias/pérdidas, esta función ofrece a los traders información tanto numérica como gráfica que mejora la conciencia situacional y la toma de decisiones.

//+------------------------------------------------------------------+
//| 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;
   }
}

La función UpdateAccountInfo() se encarga de recuperar datos de la cuenta en tiempo real y de realizar un seguimiento de los indicadores clave de rendimiento. Extrae el saldo actual, la equity, el margen, el margen libre y el nivel de margen de la cuenta de operaciones. Además, supervisa las fluctuaciones intradía de la equity actualizando los valores diarios máximo y mínimo de equity cada vez que se alcanza un nuevo extremo. Una vez actualizados los datos brutos de la cuenta, la función llama a CalculateProfitMetrics() y CalculateTradeMetrics(), que se encargan de realizar análisis más detallados, como el cálculo de beneficios, el seguimiento de las operaciones ganadoras y perdedoras, y la evaluación del rendimiento. De este modo, se garantiza que el panel refleje siempre las condiciones más actualizadas de la cuenta.

La función UpdatePriceBuffers() se centra en la visualización de precios y de ganancias y pérdidas. En primer lugar, recupera los precios actuales Bid y Ask; a continuación, recorre las posiciones abiertas para calcular el beneficio actual del símbolo activo. Si está activada la visualización de ganancias/pérdidas, rellena los búferes del indicador con los últimos valores Bid y Ask a lo largo del gráfico y crea una etiqueta situada ligeramente a la derecha de la barra actual. Esta etiqueta muestra una ganancia (azul) o una pérdida (rojo), dependiendo del resultado actual de la operación. Combinando el seguimiento del rendimiento de la cuenta con la visualización en tiempo real de precios y ganancias/pérdidas, esta función ofrece a los traders información tanto numérica como gráfica que mejora la conciencia situacional y la toma de decisiones.

//+------------------------------------------------------------------+
//| 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;
}

La función CalcculateTradeMetrics() ofrece una instantánea en tiempo real de las posiciones de trading abiertas, contando cuántas están actualmente en ganancias y cuántas en pérdidas. Empieza por obtener el número total de posiciones abiertas y, a continuación, recorre cada una de ellas comprobando su valor de ganancia o pérdida. Si la posición tiene ganancias, incrementa el contador de operaciones ganadoras; si tiene pérdidas, incrementa el contador de operaciones perdedoras. Esta función ofrece a los traders información inmediata sobre la calidad de sus operaciones abiertas, lo que les ayuda a evaluar en tiempo real si sus posiciones se ajustan a su plan de trading.

La función LoadHistory() profundiza en el rendimiento histórico mediante el análisis de las operaciones cerradas dentro de un periodo de tiempo determinado. Si el seguimiento se configura desde el inicio del indicador, este carga el historial de las últimas 24 horas para garantizar que se incluyan las operaciones recientes. A continuación, analiza todas las operaciones históricas, filtrando únicamente las operaciones de cierre de compra o venta e ignorando los depósitos, las retiradas o las entradas. Por cada operación cerrada, registra la ganancia o pérdida, actualiza el recuento de operaciones ganadoras y perdedoras, suma las ganancias y pérdidas totales y lleva un registro de la mayor ganancia o pérdida individual. Por último, calcula los promedios y el factor de beneficio, un indicador clave que compara las ganancias con las pérdidas. Este análisis exhaustivo de los resultados permite a los traders identificar patrones en su comportamiento a la hora de operar, evaluar la rentabilidad y mantener una gestión disciplinada del riesgo a lo largo del tiempo.

//+------------------------------------------------------------------+
//| 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);
}

La función CheckRiskManagement() es el mecanismo de control que garantiza que los traders se ciñan a su plan de riesgo y eviten sobrepasar los límites de la cuenta. Después calcula los porcentajes de drawdown diario y total, gestionando con cuidado la división por cero para evitar errores. La función compara la equity con el límite de riesgo diario predefinido por el trader, el drawdown máximo diario y el drawdown máximo total. Si se supera alguno de estos umbrales, el mensaje de estado se vuelve rojo y se activan alertas para avisar al trader. Este enfoque no solo ayuda a evitar pérdidas catastróficas, sino que también fomenta la disciplina al eliminar la tentación de seguir operando una vez alcanzados los límites.

La función CreateDashboard() crea la interfaz en pantalla que muestra todas las métricas registradas en un panel organizado y visualmente claro. Empieza creando un rectángulo de fondo, con colores, tamaños y bordes definidos por el usuario, que sirve de contenedor para todos los datos de rendimiento. A continuación, se añaden un título y una etiqueta del modo de seguimiento para indicar si el panel supervisa los resultados desde el inicio del indicador o desde todo el historial de la cuenta. Debajo de esto, se muestran en filas estructuradas una serie de campos etiquetados, como saldo, equity, ganancias/pérdidas diarias y totales, porcentaje de aciertos, drawdowns, factor de beneficio y promedio de ganancia/pérdida. Este panel visual permite a los traders evaluar al instante tanto el estado de su cuenta como su nivel de riesgo sin tener que consultar múltiples informes, lo que lo convierte en una herramienta muy útil para mantener la claridad y la disciplina en el trading.

//+------------------------------------------------------------------+
//| 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);
}

La función CreateDashboardLabel() sirve como función auxiliar para generar rápidamente campos etiquetados en el panel. Cada etiqueta se crea con un nombre, un texto y unos desplazamientos de posición específicos, y se le aplica un estilo uniforme, como el tamaño y el color de la fuente. De este modo, se garantiza que todas las métricas del panel sean claramente visibles y tengan un formato uniforme, lo que ofrece a los traders una visión general organizada del rendimiento de la cuenta y del estado de riesgo.

La función UpdateDashboard() actualiza continuamente el panel con datos en tiempo real sobre la cuenta y el rendimiento. Actualiza todas las métricas clave, incluidos el saldo, la equity, las ganancias/pérdidas diarias y totales, las posiciones abiertas, el porcentaje de aciertos, los drawdowns, el riesgo diario, el factor de beneficio, el número total de operaciones y la ganancia/pérdida media. La función también utiliza un código de colores para la información crítica, como las ganancias/pérdidas y el estado de las operaciones, con el fin de ofrecer información visual inmediata. Reflejando constantemente las condiciones de la cuenta en tiempo real, ayuda a los traders a tomar decisiones fundamentadas, refuerza la disciplina y evita que sobreoperen al mostrar claramente cuándo se alcanzan los límites de riesgo.

Demostración del indicador:



Conclusión

En resumen, hemos desarrollado un indicador personalizado Account Performance Matrix que realiza un seguimiento del rendimiento de trading tanto en tiempo real como histórico. El indicador supervisa métricas clave de la cuenta, como el saldo, la equity, el margen, las posiciones abiertas, las ganancias/pérdidas diarias y totales, el porcentaje de aciertos, los drawdowns, el factor de beneficio y la ganancia/pérdida media. Incorpora un panel dinámico con etiquetas visuales y alertas codificadas por colores para ofrecer a los traders una visión clara y organizada del rendimiento de su cuenta. Se han integrado reglas de gestión de riesgos para aplicar los límites de riesgo diarios y los drawdowns máximos; cuando se alcanzan dichos límites, se alerta al trader sobre el rendimiento actual de la cuenta.

En conclusión, este indicador ayuda a los traders a mantener la disciplina, evitar sobreoperar y tomar decisiones más fundamentadas al ofrecer una visión general transparente del estado de la cuenta y la exposición al riesgo. Al mostrar claramente cuándo se acercan o se superan los umbrales de riesgo, fomenta un comportamiento de trading coherente y contribuye a un crecimiento sostenible. Tanto si un trader está trabajando para superar un reto de prop firm como si gestiona una cuenta de trading personal, esta herramienta ofrece una orientación estructurada para gestionar el riesgo, optimizar las decisiones de trading y, en última instancia, mejorar la rentabilidad a largo plazo.

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/19508

Archivos adjuntos |
Acc_Matrix.mq5 (25.52 KB)
Utilizando redes neuronales en MetaTrader Utilizando redes neuronales en MetaTrader
En el artículo se muestra la aplicación de las redes neuronales en los programas de MQL, usando la biblioteca de libre difusión FANN. Usando como ejemplo una estrategia que utiliza el indicador MACD se ha construido un experto que usa el filtrado con red neuronal de las operaciones. Dicho filtrado ha mejorado las características del sistema comercial.
Pipelines en MQL5 Pipelines en MQL5
En este artículo, analizaremos un paso clave en la preparación de datos para el aprendizaje automático que está cobrando cada vez más importancia: los pipelines de preprocesamiento de datos. En esencia, supone una secuencia optimizada de pasos de transformación de datos que preparan los datos brutos antes de introducirlos en un modelo. Por muy poco interesante que pueda parecer a primera vista para quienes no estén familiarizados con el tema, esta «estandarización de datos» no solo ahorra tiempo de entrenamiento y costos de ejecución, sino que contribuye en gran medida a garantizar una mejor generalización. En este artículo nos centraremos en algunas funciones de preprocesamiento de SCIKIT-LEARN y, aunque no vamos a utilizar el asistente de MQL5, volveremos a él en próximos artículos.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Sincronización de gráficos para facilitar el análisis técnico Sincronización de gráficos para facilitar el análisis técnico
La «Sincronización de gráficos para facilitar el análisis técnico» es una herramienta que garantiza que todos los marcos temporales de los gráficos muestren objetos gráficos coherentes, como líneas de tendencia, rectángulos o indicadores, en los distintos marcos temporales de un mismo valor. Acciones como el desplazamiento, el zoom o los cambios de símbolos se reflejan en todos los gráficos sincronizados, lo que permite a los operadores visualizar y comparar sin problemas el mismo contexto de evolución de los precios en varios marcos temporales.