
Creación de un Panel de administración de operaciones en MQL5 (Parte VIII): Panel de análisis
Introducción
Este artículo marca el desarrollo del tercer subpanel dentro del EA del Panel de Administración (Admin Panel EA), centrado en superar las limitaciones actuales y mejorar su funcionalidad. Si bien el diseño existente ya admite la comunicación y la gestión comercial, la expansión de hoy introduce herramientas estadísticas para agilizar el análisis de métricas vitales del mercado. Al automatizar la investigación y los cálculos, estas herramientas eliminan la dependencia de métodos manuales, simplificando el proceso para los administradores comerciales. Inspirados por la simplicidad y claridad de los datos visualizados a través de PieCharts, nos concentraremos en dos aspectos clave de la distribución del desempeño comercial: la relación entre ganancias y pérdidas y la categorización del tipo de operación. Estas métricas brindan información inmediata sobre el éxito comercial y la asignación de operaciones entre diferentes clases de activos, como Forex, acciones u opciones.
El panel de análisis aprovecha la visualización de datos en tiempo real para abordar las ineficiencias del análisis manual. Al incorporar gráficos circulares, el panel permite a los usuarios evaluar rápidamente sus relaciones de ganancias y pérdidas y las distribuciones de tipos de operaciones sin demoras en la toma de decisiones. Esta característica representa un salto significativo en eficiencia, permitiendo a los administradores tomar decisiones informadas con precisión y rapidez.
A través de este desarrollo, utilizaremos las clases PieChart y ChartCanvas de MQL5 para automatizar estos procesos, mostrando el potencial de las herramientas estadísticas avanzadas. Con esta mejora, el Panel de administración EA evoluciona hacia un sistema aún más sólido, que ofrece información valiosa de un vistazo y al mismo tiempo resalta los beneficios educativos y prácticos de esta serie de desarrollo.
Para el éxito del proyecto, tengo estos subtemas como nuestro contenido principal:
- Descripción general del panel de análisis
- Preparación del panel de análisis mediante la clase CDialog
- Obtener datos del historial comercial para visualizar
- Implementación de las clases PieChart y ChartCanvas para presentar datos
- Probando las nuevas funciones
- Conclusión
Descripción general del panel de análisis
El Panel de Análisis será una interfaz dinámica e interactiva diseñada para proporcionar información visual sobre el rendimiento comercial y la distribución de la actividad. Para el debate de hoy, este panel presenta dos gráficos circulares principales: el gráfico circular de ganancias vs. pérdidas, que ilustra la proporción de operaciones ganadoras y perdedoras, y el gráfico de distribución de tipos de operaciones, que clasifica las operaciones en Forex, acciones y futuros. Estos gráficos están perfectamente integrados en el panel, ofreciendo un diseño limpio e intuitivo para una fácil interpretación. Al aprovechar los datos en tiempo real del historial comercial, el Panel de análisis ofrece una instantánea completa de los resultados comerciales, lo que permite a los usuarios evaluar el rendimiento comercial.
El Panel de análisis se puede mejorar aún más con visualizaciones y métricas adicionales para proporcionar un análisis más completo del rendimiento y la actividad comercial. A continuación se muestran algunas características que podrían incorporarse:
- Gráfico de líneas de rendimiento
- Gráfico de barras de volumen comercial
- Tabla de métricas de rentabilidad
- Sección de activos de alto rendimiento
- Mapa de calor de los horarios de negociación
- Rastreador de rachas de victorias y derrotas
- Cuadro de exposición al riesgo
- Alertas y umbrales personalizables
- Integración del análisis de sentimientos
- Filtros interactivos, etc.
En otras palabras, el Panel de análisis proporciona una descripción general completa del rendimiento comercial, lo que permite a los usuarios identificar patrones, evaluar la rentabilidad y monitorear el progreso a lo largo del tiempo. Esto ayuda a los traders a mantenerse informados sobre sus fortalezas y debilidades, garantizando que realicen ajustes basados en datos a sus estrategias. Ahora, pasamos a la etapa de preparación de nuestra versión antigua del Panel de administración para una actualización. También me tomé el tiempo de refinar cada línea del código anterior para asegurar que sea fácil de seguir.
Preparación del panel de análisis utilizando la clase CDialog
Actualizar un programa grande a menudo puede resultar abrumador, especialmente cuando implica repetir tareas realizadas anteriormente. Por eso es esencial tener una plantilla bien definida que rija el diseño y la estructura del programa. Con una plantilla sólida en su lugar y mediante el uso repetido, esta se integra a su flujo de trabajo, lo que le permite realizar tareas de desarrollo completas sin tener que recurrir a ella constantemente. Nuestro programa ha crecido significativamente y, para gestionar esta complejidad, me concentro en lo que pretendo lograr y cómo fluye, alineando estos objetivos con las secciones modulares del programa.
Por ejemplo, considere nuestro Panel de inicio de administración, que sirve como interfaz central después de que se inicia el programa. Desde allí podremos acceder a otros paneles. Para incluir un panel de análisis, imagino un botón dentro del panel de inicio de administración que crea y abre el panel de análisis al hacer clic. Dentro del Panel de Análisis, imagino botones de control y funcionalidades específicas para su propósito. Con esta visión en mente, el proceso de desarrollo gana claridad y dirección, proporcionando un punto de partida justificado. Permítame explicarle el enfoque que aplicamos.
Para resumir, la historia comienza aquí;
Primero consideramos la inclusión de las clases necesarias que vamos a utilizar:
#include <Controls\Dialog.mqh> #include <Controls\Button.mqh>
Declaración de la clase CDialog y del botón para el panel de análisis:
// Global variables for the Analytics Panel CDialog analyticsPanel; // The main panel for analytics CButton adminHomeAnalyticsButton; // Button for accessing analytics from the Home panel CButton minimizeAnalyticsButton; // Minimize button for the Analytics panel CButton closeAnalyticsButton; // Close button for the Analytics panel CButton analyticsPanelAccessButton; // The first Button that will take us a next step
Creación de paneles de análisis y controladores de botones:
Para crear el Panel de análisis al hacer clic en analyticsPanelAccessButton, implementamos esta funcionalidad utilizando una función de controlador de botones. Un enfoque similar se ha aplicado también a otros paneles. Anteriormente, estos paneles se creaban y ocultaban durante la fase de inicialización, lo que agregaba una carga innecesaria a la función de inicialización. Ahora, los paneles se crean dinámicamente a pedido a través de los clics de sus respectivos botones, optimizando el rendimiento y el uso de recursos. A continuación se muestra el fragmento de código que demuestra esta mejora:
//+------------------------------------------------------------------+ //| Analytics Panel Event Handling | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_OBJECT_CLICK) { if (sparam == "AnalyticsPanelAccessButton") { analyticsPanel.Show(); adminHomePanel.Hide(); if (!analyticsPanel.Create(ChartID(), "Analytics Panel", 0, 500, 450, 1280, 650) || !CreateAnalyticsPanelControls()) {} CreateAnalyticsPanel(); } else if (sparam == "MinimizeAnalyticsButton") { analyticsPanel.Hide(); adminHomePanel.Show(); } else if (sparam == "CloseAnalyticsButton") { analyticsPanel.Destroy(); adminHomePanel.Show(); } } }
Este fragmento de código gestiona los eventos relacionados con el panel de análisis dentro de la función OnChartEvent, concretamente cuando se detectan clics del usuario en objetos del gráfico (CHARTEVENT_OBJECT_CLICK). Si se hace clic en el botón de acceso al panel de análisis, se muestra el panel, se oculta el panel de inicio de administración y se crea dinámicamente el panel de análisis junto con sus controles mediante la función CreateAnalyticsPanel. Si se hace clic en el botón Minimizar análisis, el Panel de análisis se oculta y se muestra nuevamente el Panel de inicio de administración. Por último, si se hace clic en el botón Cerrar análisis, el panel de análisis se destruye por completo y se restaura el Panel de inicio de administración en la pantalla. Este manejo dinámico garantiza que los paneles adecuados se muestren u oculten en función de las acciones del usuario, lo que mejora tanto la funcionalidad como la experiencia del usuario.
Creación de controles del Panel de análisis:
Este fragmento de código define una función, CreateAnalyticsPanelControls, que inicializa y añade controles a un panel de análisis en una aplicación MQL5. Comienza obteniendo el ID del gráfico actual con ChartID() e intenta crear un botón de minimizar (minimizeAnalyticsButton) en coordenadas específicas. Si la creación falla, registra un mensaje de error y devuelve falso. Si se realiza correctamente, el botón se etiqueta con un guión bajo («_») y se añade al contenedor analyticsPanel. Del mismo modo, crea un botón de cierre (closeAnalyticsButton) etiquetado con una «X» en otro conjunto de coordenadas, siguiendo el mismo proceso de comprobación de errores. La función termina con un comentario marcador de posición que sugiere dónde se podrían añadir controles adicionales relacionados con el análisis, como gráficos o elementos de entrada. Si todos los controles se crean correctamente, la función devuelve verdadero.
bool CreateAnalyticsPanelControls() { long chart_id = ChartID(); // Create Minimize Button if (!minimizeAnalyticsButton.Create(chart_id, "MinimizeAnalyticsButton", 0, 210, -22, 240, 0)) { Print("Failed to create minimize button for Analytics Panel"); return false; } minimizeAnalyticsButton.Text("_"); analyticsPanel.Add(minimizeAnalyticsButton); // Create Close Button if (!closeAnalyticsButton.Create(chart_id, "CloseAnalyticsButton", 0, 240, -22, 270, 0)) { Print("Failed to create close button for Analytics Panel"); return false; } closeAnalyticsButton.Text("X"); analyticsPanel.Add(closeAnalyticsButton); // Add additional controls specific to analytics as needed // For example, charts, labels, or input elements for data representation return true; }
También trasladamos la creación de muchos paneles desde las funciones de inicialización para que se activen a través de controladores de botones. Desde que hice este cambio, he notado una mejora significativa en el rendimiento del Asesor Experto (EA), especialmente en cuanto a la velocidad al navegar entre los distintos paneles.
Aquí está la función principal del controlador OnChartEvent combinada:
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_OBJECT_CLICK) { if (sparam == "HomeButtonComm") { adminHomePanel.Show(); communicationsPanel.Hide(); } else if (sparam == "HomeButtonTrade") { adminHomePanel.Show(); tradeManagementPanel.Hide(); } else if (sparam == "AdminHomeAnalyticsButton") { adminHomePanel.Show(); analyticsPanel.Hide(); } else if (sparam == "MinimizeAnalyticsButton") { analyticsPanel.Hide(); adminHomePanel.Show(); } else if (sparam == "CloseAnalyticsButton") { analyticsPanel.Destroy(); adminHomePanel.Show(); } else if (sparam == "TradeMgmtAccessButton") { tradeManagementPanel.Show(); adminHomePanel.Hide(); if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0, 500, 30, 1280, 170) || !CreateTradeManagementControls()) {} } else if (sparam == "CommunicationsPanelAccessButton") { communicationsPanel.Show(); adminHomePanel.Hide(); if (!communicationsPanel.Create(ChartID(), "Communications Panel", 0, 20, 150, 490, 650) || !CreateCommunicationsPanelControls()) {} } else if (sparam == "CloseHomeButton") { adminHomePanel.Destroy(); } else if (sparam == "MinimizeHomeButton") { adminHomePanel.Hide(); maximizeHomeButton.Show(); } else if (sparam == "MaximizeHomeButton") { adminHomePanel.Show(); maximizeHomeButton.Show(); } else if (sparam == "AnalyticsPanelAccessButton") { analyticsPanel.Show(); adminHomePanel.Hide(); if (!analyticsPanel.Create(ChartID(), "Analytics Panel", 0, 500, 450, 1280, 650) || !CreateAnalyticsPanelControls()) {}; CreateAnalyticsPanel(); } else if (sparam == "ShowAllButton") { analyticsPanel.Show(); communicationsPanel.Show(); tradeManagementPanel.Show(); adminHomePanel.Hide(); } else if (sparam == "MinimizeComsButton") { OnMinimizeComsButtonClick(); } else if (sparam == "CloseComsButton") { communicationsPanel.Destroy(); } else if (sparam == "LoginButton") { OnLoginButtonClick(); } else if (sparam == "CloseAuthButton") { OnCloseAuthButtonClick(); } else if (sparam == "TwoFALoginButton") { OnTwoFALoginButtonClick(); } else if (sparam == "Close2FAButton") { OnClose2FAButtonClick(); } } switch (id) { case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") OnSendButtonClick(); else if (sparam == "ClearButton") OnClearButtonClick(); else if (sparam == "ChangeFontButton") OnChangeFontButtonClick(); else if (sparam == "ToggleThemeButton") OnToggleThemeButtonClick(); else if (sparam == "MinimizeComsButton") OnMinimizeComsButtonClick(); else if (sparam == "CloseComsButton") OnCloseComsButtonClick(); else if (StringFind(sparam, "QuickMessageButton") != -1) { long index = StringToInteger(StringSubstr(sparam, 18)); OnQuickMessageButtonClick(index - 1); } break; case CHARTEVENT_OBJECT_ENDEDIT: if (sparam == "InputBox") OnInputChange(); break; } }
Por último, también consideré ajustar el Panel de inicio de administración, como lo muestran sus coordenadas y ancho en este fragmento de código a continuación:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { if (!ShowAuthenticationPrompt()) { Print("Authorization failed. Exiting..."); return INIT_FAILED; } if (!adminHomePanel.Create(ChartID(), "Admin Home Panel", 0, 30, 80,330, 550)) { Print("Failed to create Admin Home Panel"); return INIT_FAILED; } if (!CreateAdminHomeControls()) { Print("Home panel control creation failed"); return INIT_FAILED; } adminHomePanel.Hide(); // Hide home panel by default on initialization return INIT_SUCCEEDED; }
Obtener datos del historial comercial para visualizar
Ahora necesitamos obtener datos del historial del terminal que podamos presentar a través de Piechart en nuestro nuevo panel. La función GetTradeData está diseñada para analizar datos históricos de operaciones y clasificarlos en categorías específicas, lo que proporciona una base para el análisis detallado del rendimiento de las operaciones. Primero inicializa los contadores de ganancias, pérdidas y tres tipos de operaciones: Forex, acciones y futuros. La función se basa en la función HistorySelect para recuperar los datos comerciales desde el inicio del historial de la cuenta comercial hasta el momento actual. Si este proceso de selección falla, la función registra un error y se cierra, lo que garantiza la solidez frente a datos históricos no disponibles. A continuación, recorre todas las ofertas disponibles utilizando HistoryDealGetTicket para recuperar el identificador único de cada oferta. Para cada operación válida, la función evalúa su rentabilidad analizando el valor de la ganancia e incrementando el contador de ganancias o pérdidas en función de si la ganancia fue positiva o negativa.
La categorización de las operaciones se determina por sus símbolos. Las operaciones con divisas se identifican por la ausencia de un punto en los nombres de sus símbolos, mientras que las operaciones con acciones y futuros se clasifican comprobando la propiedad SYMBOL_PATH del símbolo. El nombre del grupo del símbolo determina si pertenece a la categoría «Acciones» (Stocks) o «Futuros» (Futures). Este paso garantiza que las operaciones se agrupen con precisión según sus instrumentos financieros. Al agregar esta información, la función proporciona un desglose completo del rendimiento comercial, que puede utilizarse para análisis o visualización adicionales.
En el escenario actual, esta función se puede integrar en un panel de análisis para generar un gráfico circular que muestre la distribución de categorías comerciales y la relación entre ganancias y pérdidas. Por ejemplo, un comerciante podría usar la función para visualizar que el 60% de sus operaciones son en Forex, el 30% en acciones y el 10% en futuros, mientras que su tasa de éxito general es del 70%. Estos conocimientos son invaluables para evaluar el desempeño comercial e identificar áreas de mejora. Además, las capacidades de análisis de datos en tiempo real de la función la hacen adecuada para crear paneles de control interactivos que ayudan a los operadores a adaptar estrategias en función de las tendencias históricas.
Más allá de su implementación actual, la función GetTradeData tiene potencial para aplicaciones más amplias. Podría ampliarse para analizar rangos de tiempo específicos o incorporar métricas adicionales, como la ganancia o la reducción promedio. Estos datos podrían luego integrarse en herramientas externas, como modelos de aprendizaje automático para análisis predictivos o informes interactivos para presentaciones a inversores. Con estas extensiones, la función se convierte en una herramienta versátil tanto para traders individuales como para sistemas comerciales más grandes que buscan maximizar la eficiencia y la rentabilidad.
Aquí está el código tal como se implementó:
//+------------------------------------------------------------------+ //| Data for Pie Chart | //+------------------------------------------------------------------+ void GetTradeData(int &wins, int &losses, int &forexTrades, int &stockTrades, int &futuresTrades) { wins = 0; losses = 0; forexTrades = 0; stockTrades = 0; futuresTrades = 0; if (!HistorySelect(0, TimeCurrent())) { Print("Failed to select trade history."); return; } int totalDeals = HistoryDealsTotal(); for (int i = 0; i < totalDeals; i++) { ulong dealTicket = HistoryDealGetTicket(i); if (dealTicket > 0) { double profit = HistoryDealGetDouble(dealTicket, DEAL_PROFIT); if (profit > 0) wins++; else if (profit < 0) losses++; string symbol = HistoryDealGetString(dealTicket, DEAL_SYMBOL); if (SymbolInfoInteger(symbol, SYMBOL_SELECT)) { if (StringFind(symbol, ".") == -1) forexTrades++; else { string groupName; if (SymbolInfoString(symbol, SYMBOL_PATH, groupName)) { if (StringFind(groupName, "Stocks") != -1) stockTrades++; else if (StringFind(groupName, "Futures") != -1) futuresTrades++; } } } } } }
Implementación de las clases PieChart y ChartCanvas para presentar datos
Comenzamos incluyendo las clases:
#include <Canvas\Charts\PieChart.mqh> #include <Canvas\Charts\ChartCanvas.mqh>
Clase de gráfico circular (Pie) personalizado:
Comenzamos derivando la clase CCustomPieChart de la clase base CPieChart. El objetivo era exponer el método protegido DrawPie, que normalmente es inaccesible fuera de la clase principal. Al crear un método público DrawPieSegment que envuelve DrawPie, hemos ganado flexibilidad para dibujar segmentos individuales de gráficos circulares de forma dinámica. Esto resultó especialmente útil al implementar la lógica de renderizado personalizada en el método DrawPieChart de la clase CAnalyticsChart. Este paso nos permitió controlar con gran precisión la representación visual de cada porción del gráfico circular, lo que nos permitió crear gráficos circulares más dinámicos y visualmente personalizados para nuestro panel de análisis.
//+------------------------------------------------------------------+ //| Custom Pie Chart Class | //+------------------------------------------------------------------+ class CCustomPieChart : public CPieChart { public: void DrawPieSegment(double fi3, double fi4, int idx, CPoint &p[], const uint clr) { DrawPie(fi3, fi4, idx, p, clr); // Expose protected method } };
Clase de gráfico de análisis:
A continuación, ampliamos la clase CWnd para crear CAnalyticsChart, un contenedor de gráficos especializado. En esta clase hemos integrado CCustomPieChart como miembro, lo que le permite servir como base para dibujar gráficos circulares. Implementamos métodos como CreatePieChart para inicializar el widget del gráfico circular dentro de un área definida y SetPieChartData para vincular los valores de los datos, las etiquetas y los colores al gráfico. Además, el método DrawPieChart se codificó cuidadosamente para calcular el ángulo de cada segmento basándose en el conjunto de datos y para llamar a DrawPieSegment para su representación. Al trabajar con esta lógica, garantizamos que el gráfico circular pudiera dibujarse dinámicamente, reflejando los datos subyacentes de una manera visualmente atractiva.
//+------------------------------------------------------------------+ //| Analytics Chart Class | //+------------------------------------------------------------------+ class CAnalyticsChart : public CWnd { private: CCustomPieChart pieChart; // Declare pieChart as a member of this class public: bool CreatePieChart(string label, int x, int y, int width, int height) { if (!pieChart.CreateBitmapLabel(label, x, y, width, height)) { Print("Error creating Pie Chart: ", label); return false; } return true; } void SetPieChartData(const double &values[], const string &labels[], const uint &colors[]) { pieChart.SeriesSet(values, labels, colors); pieChart.ShowPercent(); } void DrawPieChart(const double &values[], const uint &colors[], int x0, int y0, int radius) { double total = 0; int seriesCount = ArraySize(values); if (seriesCount == 0) { Print("No data for pie chart."); return; } for (int i = 0; i < seriesCount; i++) total += values[i]; double currentAngle = 0.0; // Resize the points array CPoint points[]; ArrayResize(points, seriesCount + 1); for (int i = 0; i < seriesCount; i++) { double segmentValue = values[i] / total * 360.0; double nextAngle = currentAngle + segmentValue; // Define points for the pie slice points[i].x = x0 + (int)(radius * cos(currentAngle * M_PI / 180.0)); points[i].y = y0 - (int)(radius * sin(currentAngle * M_PI / 180.0)); pieChart.DrawPieSegment(currentAngle, nextAngle, i, points, colors[i]); currentAngle = nextAngle; } // Define the last point to close the pie points[seriesCount].x = x0 + (int)(radius * cos(0)); // Back to starting point points[seriesCount].y = y0 - (int)(radius * sin(0)); } };
Crear función de panel de análisis:
Para unir todo, escribimos la función CreateAnalyticsPanel para gestionar la implementación real del panel de análisis. En primer lugar, obtuvimos los datos de las operaciones (como ganancias, pérdidas y recuentos de tipos de operaciones) utilizando nuestra función GetTradeData . A continuación, instanciamos dos objetos CAnalyticsChart para diferentes visualizaciones. Para el primer gráfico, utilizamos los datos recuperados sobre ganancias y pérdidas para crear un gráfico circular titulado «Win vs. Loss Pie Chart». Del mismo modo, para el segundo gráfico, utilizamos los datos sobre tipos de operaciones para crear un gráfico circular titulado «Distribución por tipo de operación». Al llamar a SetPieChartData y DrawPieChart para cada gráfico, los representamos dinámicamente y los añadimos al analyticsPanel. Este enfoque nos permitió dividir el código en componentes modulares y reutilizables, garantizando claridad y facilidad de mantenimiento.
//+------------------------------------------------------------------+ //| Create Analytics Panel | //+------------------------------------------------------------------+ void CreateAnalyticsPanel() { int wins, losses, forexTrades, stockTrades, futuresTrades; GetTradeData(wins, losses, forexTrades, stockTrades, futuresTrades); // Declare pieChart1 and pieChart2 as local variables CAnalyticsChart pieChart1; CAnalyticsChart pieChart2; // Win vs Loss Pie Chart if (!pieChart1.CreatePieChart("Win vs. Loss Pie Chart", 20, 20, 300, 300)) { Print("Error creating Win/Loss Pie Chart"); return; } double winLossValues[] = {wins, losses}; string winLossLabels[] = {"Wins", "Losses"}; uint winLossColors[] = {clrGreen, clrRed}; pieChart1.SetPieChartData(winLossValues, winLossLabels, winLossColors); pieChart1.DrawPieChart(winLossValues, winLossColors, 150, 150, 140); // Add pieChart1 to the analyticsPanel analyticsPanel.Add(pieChart1); // Trade Type Pie Chart if (!pieChart2.CreatePieChart("Trade Type Distribution", 350, 20, 300, 300)) { Print("Error creating Trade Type Pie Chart"); return; } double tradeTypeValues[] = {forexTrades, stockTrades, futuresTrades}; string tradeTypeLabels[] = {"Forex", "Stocks", "Futures"}; uint tradeTypeColors[] = {clrBlue, clrOrange, clrYellow}; pieChart2.SetPieChartData(tradeTypeValues, tradeTypeLabels, tradeTypeColors); pieChart2.DrawPieChart(tradeTypeValues, tradeTypeColors, 500, 150, 140); // Add pieChart2 to the analyticsPanel analyticsPanel.Add(pieChart2); // Show the analyticsPanel analyticsPanel.Show(); }
¿Por qué lo hicimos de esta manera?
Al codificar el sistema de esta manera, garantizamos que la creación de gráficos fuera dinámica y flexible. Derivar CCustomPieChart nos permitió controlar la representación de los gráficos circulares, mientras que CAnalyticsChart nos permitió encapsular la funcionalidad de los gráficos circulares en una clase autónoma. Esto facilitó la adición de nuevos gráficos o el ajuste de su comportamiento sin afectar a otras partes del programa. Por ejemplo, en el proyecto de hoy, si quisiéramos añadir otro gráfico para el análisis de la curva de capital, podríamos reutilizar la misma estructura CAnalyticsChart con un esfuerzo mínimo. Este enfoque modular no solo agiliza el desarrollo sino que también hace que el panel de análisis sea altamente extensible para futuras mejoras.
Cómo evitar errores de matriz fuera de rango:
Para evitar un error de «matriz fuera de rango» en el método CPieChart::DrawPie de PieChart.mqh, hemos añadido una comprobación de rango para garantizar que el index (idx + 1) esté dentro de los límites de la matriz CPoint (p[]) antes de acceder a ella. Esta protección garantiza que la matriz tenga el tamaño adecuado antes de su uso y evita operaciones no válidas. Si el índice está fuera de los límites, la función sale antes e imprime un mensaje de error para depuración. Además, durante la representación del gráfico circular, la matriz CPoint se redimensiona adecuadamente para dar cabida a todos los segmentos del gráfico, lo que garantiza que la estructura de datos sea siempre lo suficientemente grande para los cálculos. La condición añadida if (idx + 1 >= ArraySize(p)) comprueba si el siguiente índice es válido y, en caso contrario, muestra un mensaje de error y regresa antes de tiempo para evitar que se siga procesando. Esta comprobación evita que la función intente acceder a un elemento de la matriz fuera de los límites, evitando así el error.
if (idx + 1 >= ArraySize(p)) { Print("Array out of range error: idx = ", idx, ", ArraySize = ", ArraySize(p)); return; }
Tenga en cuenta que hemos tenido que modificar la clase Pie Chart integrada para evitar el error mencionado anteriormente durante la prueba del Asesor Experto (EA).
//+------------------------------------------------------------------+ //| Draw pie | //+------------------------------------------------------------------+ void CPieChart::DrawPie(double fi3, double fi4, int idx, CPoint &p[], const uint clr) { // Ensure array index is within bounds if (idx + 1 >= ArraySize(p)) { Print("Array out of range error: idx = ", idx, ", ArraySize = ", ArraySize(p)); return; } //--- draw arc Arc(m_x0, m_y0, m_r, m_r, fi3, fi4, p[idx].x, p[idx].y, p[idx + 1].x, p[idx + 1].y, clr); //--- variables int x3 = p[idx].x; int y3 = p[idx].y; int x4 = p[idx + 1].x; int y4 = p[idx + 1].y; //--- draw radii if (idx == 0) Line(m_x0, m_y0, x3, y3, clr); if (idx != m_data_total - 1) Line(m_x0, m_y0, x4, y4, clr); //--- fill double fi = (fi3 + fi4) / 2; int xf = m_x0 + (int)(0.99 * m_r * cos(fi)); int yf = m_y0 - (int)(0.99 * m_r * sin(fi)); Fill(xf, yf, clr); //--- for small pie if (fi4 - fi3 <= M_PI_4) Line(m_x0, m_y0, xf, yf, clr); }
Probando las nuevas funciones
En esta sección, presentamos el resultado de nuestras mejoras, mostrando la versión actualizada de nuestro programa y sus características. A continuación se muestra una serie de imágenes que ilustran las mejoras. En primer lugar, destacamos el panel de inicio de administración rediseñado junto con el botón recién añadido. A continuación, mostramos el Panel de análisis, que incluye visualizaciones de la distribución de los datos de negociación. A continuación, se muestra una vista completa del Panel de administración con todos sus subpaneles visibles. Por último, incluimos una captura de pantalla animada que muestra la implementación de la aplicación en el gráfico del terminal para una integración perfecta.
Nuevo panel de inicio de administración
Panel de análisis
Admin Panel V1.23 (Vista completa)
Índice Boom 300, H4: Lanzamiento del EA Admin Panel V1.24
Conclusión
En la discusión de hoy, exploramos el desarrollo de características avanzadas en MQL5, centrándonos en la integración de nuevas clases y técnicas para mejorar el Panel de administración y su funcionalidad. Al utilizar las capacidades de MQL5, implementamos con éxito paneles dinámicos y elementos visuales basados en datos, como gráficos circulares, para representar el rendimiento comercial de manera efectiva. Este proyecto demuestra el inmenso potencial de MQL5 para crear herramientas sofisticadas y fáciles de usar, diseñadas tanto para comerciantes como para desarrolladores.
El Panel de análisis recientemente implementado brinda a los traders información útil sobre su desempeño comercial, al tiempo que ofrece a los desarrolladores un marco sólido sobre el cual construir. Al abordar desafíos como el desorden de paneles, la superposición de objetos y la creación de controles dinámicos, hemos sentado las bases para una interfaz más eficiente e intuitiva. Estas mejoras son fundamentales y un trampolín para futuras innovaciones. Los desarrolladores pueden ampliar este marco para incorporar análisis adicionales, funciones interactivas o incluso funcionalidades completamente nuevas. Los archivos fuente y las imágenes adjuntos muestran el resultado de nuestros esfuerzos y ofrecen inspiración para que otros exploren las posibilidades ilimitadas de MQL5. ¡Feliz negociación, y que esta guía despierte tu creatividad para impulsar tus proyectos!
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/16356
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.





- 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
Hola, me gustaría ver este trabajo, pero tengo algunos errores en la compilación. ¿Qué me perdí?
Hola, me gustaría ver este trabajo, pero tengo algunos errores en la compilación. ¿Qué me perdí?
¡Hola, mi buen amigo!
En la Parte III de la serie, extendimos la Clase Dialog para incluir características de gestión de temas. Para resolver los errores que estás encontrando, simplemente descarga los archivos extendidos y cópialos en la ubicación apropiada:
Una vez hecho esto, intente compilar de nuevo. Los errores deberían estar resueltos. Si encuentras algún otro error, por favor no dudes en contactarnos.