Desarrollo de un indicador personalizado de matriz de rendimiento de cuenta
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
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
Utilizando redes neuronales en MetaTrader
Pipelines en MQL5
Particularidades del trabajo con números del tipo double en MQL4
Sincronización de gráficos para facilitar el análisis técnico
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso