Visualisation 3D sans bibliothèques externes : comment MetaTrader 5 révèle les résultats d’optimisation avec MQL5 et DirectX 11
D'une belle image à un outil fonctionnel
Lorsque le nombre de paramètres de stratégie dépasse dix et que le rapport du Testeur de Stratégie se transforme en un tableau de plusieurs pages contenant des séries numériques, les traders et les développeurs sont confrontés à un problème : le signal utile se perd dans le bruit. Les graphiques plats et les cartes thermiques bidimensionnelles sont efficaces jusqu'à un certain point. Mais au-delà, le cerveau humain se heurte inévitablement à la multidimensionnalité des données. Nous essayons de garder à l'esprit la corrélation entre la période de l'indicateur, le stop-loss, la volatilité et le drawdown maximal. Mais la charge cognitive augmente plus vite que l'utilité de l'information.
La visualisation 3D et les interfaces interactives de MetaTrader 5 ne sont pas une tentative de transformer le terminal de trading en un moteur de jeu. Il s’agit d’une technique visant à réduire la friction cognitive. Une surface 3D, où la hauteur correspond à la valeur attendue et le dégradé de couleur reflète la robustesse face aux drawdowns, nous permet de mettre en évidence le « plateau de stabilité » et de repérer et écarter les pics étroits typiques du sur-ajustement en quelques secondes. Ce qui nécessite des heures de comparaison sous forme de tableau se lit comme un motif dans l'espace tridimensionnel : pentes planes, changements d'altitude, plateaux/pics étroits en aiguille et zones de contraste.
MetaTrader 5 fournit une base technologique prête à l'emploi pour cette tâche. La prise en charge native de DirectX 11, le pipeline de shaders intégré ainsi que les classes CDXCanvas / CChartObjectDX sont directement intégrés dans l'environnement MQL5. Le développeur n'a pas besoin de connecter des bibliothèques graphiques externes, d'écrire des wrappers en C++ ou de gérer des dépendances : le cycle complet, de la création du périphérique à la sortie de l'image, est accessible via l'API 3D standard, et le chargement des shaders et des textures fonctionne directement à partir du dossier Files\DX\.
Dans cet article, nous allons détailler comment transformer les tableaux de résultats d'optimisation, les volumes de clusters et les modèles de scénarios en paysages 3D exploitables. Nous définirons les critères de pertinence : quand les graphiques 3D ajoutent des capacités d’analyse du signal et quand ils génèrent du bruit visuel. Nous passerons ensuite à l'architecture du pipeline DX, en examinant l'initialisation, la liaison des métriques aux buffers de sommets, les mécanismes de la caméra et les panneaux d'interface utilisateur, et enfin en évaluant les limitations technologiques de l'environnement.

Fig. 1 : texte vs. visualisation
Quand la 3D et l'interactivité sont vraiment utiles
Un trader et un développeur de stratégies disposent d'un outil puissant, mais souvent sous-estimé, dans leur arsenal : la perception visuelle. Les tableaux de rapports, les listes de métriques et les graphiques 2D permettent de bien documenter les résultats. Mais lorsqu'il s'agit de comprendre des relations complexes, le cerveau humain passe à un autre mode d’analyse : il recherche des schémas sous forme d'images, de volume et de contexte. C’est là que la visualisation 3D et l’interactivité cessent d’être un simple élément décoratif et deviennent un outil d’analyse.
L'ajout d'un troisième axe se justifie lorsqu'il existe une hypothèse analytique claire dans les données. Par exemple, la dépendance de la valeur attendue à l'égard de deux paramètres clés du système à un niveau de risque fixe. Dans ce cas, la surface 3D transforme les coordonnées abstraites en un terrain, où les « montagnes » vertes indiquent des zones de profit stable et les « creux » rouges indiquent des drawdowns. La représentation 3D agit comme un filtre : elle élimine le bruit et ne laisse subsister que les combinaisons significatives.
Non pas pour des raisons esthétiques, mais pour des raisons analytiques.
Il ne s'agit pas de graphismes décoratifs, mais de couches visuelles qui révèlent directement ce qui est caché dans les lignes du rapport d’optimisation. Un tableau plat répond à la question : « Quel est le résultat de cette combinaison de paramètres ? »
Une surface 3D répond à la question : « Comment le résultat évolue-t-il en fonction des variations progressives de deux paramètres, et où se situent les zones de stabilité ? » Il s'agit d'un niveau d'analyse stratégique fondamentalement différent. La stabilité du résultat lorsque le contexte externe change est l'objectif principal à atteindre lors du test de toute idée de stratégie. Tout le reste est secondaire.
Il existe au moins trois scénarios où la visualisation 3D offre un avantage :
1. Paysage d'optimisation
Imaginez que vous sélectionniez deux paramètres : la période de la moyenne mobile et la taille du stop loss. Le tableau comporte 100 lignes avec les valeurs de Profit et de Drawdown. Sur une surface 3D présentant un dégradé de couleurs, vous verrez instantanément :
- les plateaux de robustesse sont de vastes zones vertes où la stratégie est constamment rentable même avec des paramètres variables
- les pics aigus sont des maxima locaux étroits qui sont souvent le signe d'un sur-ajustement
- les pentes abruptes sont des zones où une petite modification d'un paramètre entraîne une forte augmentation du drawdown
Cette surface 3D permet de prendre des décisions éclairées quant au choix d'un ensemble de paramètres, non pas en fonction du profit maximal, mais de la robustesse.
2. Les conditions de marché en tant qu'espace multidimensionnel
Le regroupement des régimes de marché (tendance, phase latérale, volatilité accrue) nécessite souvent l'analyse simultanée de plus de trois indicateurs. Ici, la visualisation 3D permet de :
- représenter chaque état du marché comme un point dans l'espace des variables
- coder par couleur l'efficacité de la stratégie dans ce mode (ce point)
- faire pivoter interactivement le nuage de points pour révéler des groupements cachés
Ceci est particulièrement pratique lors du paramétrage adaptatif : vous pouvez voir dans quelles conditions la stratégie échoue et dans quelles conditions elle fonctionne de manière robuste.
3. Modélisation de scénarios et tests de résistance
Lors de l'exécution de la stratégie sur divers scénarios synthétiques (méthode de Monte Carlo, génération de trajectoires de prix, ou encore des hypothèses du type : « que se passe-t-il si la volatilité augmente de 30 % ? »), la 3e dimension peut afficher :
- axe X — paramètre de stratégie
- axe Y – niveau de stress du marché (volatilité, écarts)
- axe Z / couleur — métrique finale (facteur de récupération, valeur attendue)
Par conséquent, nous n'observons pas seulement un scénario catastrophe, mais bien les limites de la robustesse de la stratégie face à la détérioration des conditions de marché.
Critères de sélection : quand la 3D est excessive
Établissons une règle : La visualisation 3D se justifie lorsque vous étudiez la dépendance d'un résultat par rapport à deux variables continues ou plus et qu'il est important pour vous de visualiser la géométrie de cette dépendance.
Si vous êtes prêt à remplacer des heures passées à éplucher des rapports par une analyse visuelle intuitive, commençons par le pipeline de rendu.
Pipeline DX de base en MQL5 : de l'initialisation à la première image
La création de graphismes 3D dans MetaTrader 5 est un processus séquentiel, où chaque étape a son propre objectif. Comprendre l'architecture des objets DirectX et la boucle de rendu nous permet d'éviter les pièges courants, tels que les fuites de mémoire, les effets de clignotement et la dégradation des performances lors du traitement de grandes quantités de données.
Architecture objet DirectX en MQL5
La base des graphismes 3D en MQL5 est la classe CCanvas3D, qui encapsule toute la complexité du fonctionnement avec DirectX 11. Elle fournit une API de haut niveau au développeur, masquant les détails de bas niveau liés à la création de périphériques, de contextes et de buffers.
Hiérarchie des objets :
- CCanvas3D — une classe qui gère la scène, la caméra et le rendu
- CDXMesh et ses descendants (CDXBox, CDXSphere, CDXTorus) — objets géométriques
- DXVertex — structure de sommet contenant les coordonnées, les normales, les coordonnées de texture et la couleur
struct DXVertex { DXVector4 position; // vertex coordinates DXVector4 normal; // normal vector DXVector2 tcoord; // texture coordinates DXColor vcolor; // color };
Cette structure est compatible avec le shader de vertex standard, éliminant ainsi le besoin d'écrire des shaders personnalisés pour les tâches de base. Pour les projets complexes, nous recommandons d'utiliser les méthodes et utilitaires présentés dans le fichier MQL5\Include\Canvas\DX\DXUtils.mqh.
Fig. 2 : hiérarchie des graphismes 3D en MQL5
Toutes les ressources (shaders, textures, buffers) sont gérées via DXDispatcher. Chaque objet créé doit être explicitement détruit via Destroy() ou Shutdown() dans le destructeur. MetaTrader 5 ne dispose pas de garbage collector pour les ressources DirectX, et les fuites de mémoire s'accumulent jusqu'au redémarrage du terminal.
Initialisation du pipeline
La première étape consiste à créer un canevas et à configurer la matrice de projection :
//+------------------------------------------------------------------+ //+ canvas creation and projection matrix setup | //+------------------------------------------------------------------+ virtual bool Create(const int width, const int height) { //--- save canvas dimensions m_width = width; m_height = height; //--- create a canvas to render a 3D scene ResetLastError(); if(!m_canvas.CreateBitmapLabel("3D Sample_1", 0, 0, m_width, m_height, COLOR_FORMAT_ARGB_NORMALIZE)) { Print("Error creating canvas: ", GetLastError()); return(false); } //--- set the projection matrix parameters m_canvas.ProjectionMatrixSet((float)M_PI/6, (float)m_width/m_height, 0.1f, 100.0f); //--- create a 3D object if(!m_box.Create(m_canvas.DXDispatcher(), m_canvas.InputScene(),DXVector3(-1.0, -1.0, -1.0), DXVector3(1.0, 1.0, 1.0))) { m_canvas.Destroy(); return(false); } //--- add a cube to the scene m_canvas.ObjectAdd(&m_box); Redraw(); return(true); }
Principaux paramètres de projection :
- le champ de vision (« Field of View » ou FOV) - 30 degrés (M_PI/6), équilibre entre perspective et distorsion
- le rapport d'aspect — le rapport entre la largeur et la hauteur (m_largeur/m_hauteur), le préserver empêche l'étirement en hauteur/largeur
- Les plans de découpage sont de 0,1f (le plus proche) et de 100,0f (le plus éloigné) ; les objets situés en dehors de ces limites ne sont pas rendus
Ces paramètres définissent la pyramide de visibilité : seuls les objets situés entre deux murs virtuels et dans l’angle de vision horizontal sont inclus dans la matrice de projection.
Compilation des shaders - pour les primitives standard, les shaders sont compilés automatiquement. Si vous appliquez des effets personnalisés, utilisez DXCompileShader() avec une gestion des erreurs :
string error_log; if(!DXCompileShader("shader.hlsl", "vs_main", "vs_5_0", shader_blob, error_log)) { Print("Shader compilation failed: ", error_log); return(false); }
Données → Sommets → Image
Après l'initialisation, le cycle de rendu commence. Chaque image passe par un pipeline de transformation :
Modèle objet — Le modèle tridimensionnel est décrit par un maillage de polygones. En pratique, on utilise la triangulation : chaque polygone est divisé en triangles, puisqu'un triangle décrit de manière unique un plan dans l'espace. Un cube, par exemple, possède 8 sommets, mais pour un éclairage correct, 24 sommets sont créés (4 pour chaque face avec des normales uniques).
//--- preparing vertices and indices for the sphere DXVertex vertices[]; uint indices[]; if(!DXComputeSphere(0.3f, 50, vertices, indices)) return(false); //--- create the sphere object if(!m_sphere.Create(m_canvas.DXDispatcher(), m_canvas.InputScene(), vertices, indices)) { m_canvas.Destroy(); return(false); }
Transformations — Chaque objet passe par les matrices :
- matrice du modèle — coordonnées locales → monde (rotation, échelle, translation)
- matrice de vue — coordonnées mondiales → coordonnées de la caméra
- matrice de projection — coordonnées de la caméra → coordonnées de l'écran
//--- calculate the cube position and the transfer matrix DXMatrix rotation, translation; //--- rotate the cube sequentially along the X, Y and Z axes DXMatrixRotationYawPitchRoll(rotation, (float)M_PI/4, (float)M_PI/3, (float)M_PI/6); //--- shift the cube to the right-down-into the depth DXMatrixTranslation(translation, 1.0, -2.0, 5.0); //--- get the transformation matrix as a product of rotation and transfer DXMatrix transform; DXMatrixMultiply(transform, rotation, translation); //--- set the transformation matrix m_box.TransformMatrixSet(transform);
Éclairage (modèle de Phong) — une image réaliste nécessite le calcul de trois composantes d'éclairage :
- Ambiant (arrière-plan) — une composante constante qui simule la lumière diffuse ;
- Diffuse (dispersée) — dépend de l'angle d'incidence de la lumière sur la surface ;
- Spéculaire (miroir) — reflets qui créent un effet brillant.
//--- set the source color to yellow and direct it from top to bottom m_canvas.LightColorSet(DXColor(1.0, 1.0, 0.0, 0.8f)); m_canvas.LightDirectionSet(DXVector3(0.0, -1.0, 0.0)); //--- set the blue color for the ambient light m_canvas.AmbientColorSet(DXColor(0.0, 0.0, 1.0, 0.4f)); //--- set the cube color to white with a green glow m_box.DiffuseColorSet(DXColor(1.0, 1.0, 1.0, 1.0)); m_box.EmissionColorSet(DXColor(0.0, 1.0, 0.0, 0.2f));
Rendu et mise à jour du canevas — toutes les opérations sont effectuées dans la méthode Render(). Ensuite, l'image est transférée sur le canevas via Update() :
//--- calculate the 3D scene m_canvas.Render(DX_CLEAR_COLOR | DX_CLEAR_DEPTH, ColorToARGB(clrBlack)); //--- update the picture on the canvas in accordance with the current scene m_canvas.Update();
Gestion de la mémoire — chaque objet DX consomme de la mémoire vidéo. Lors de la création de scènes dynamiques (par exemple, la mise à jour de la surface d'optimisation), il est nécessaire de :
- effacer les anciens buffers avant d'en créer de nouveaux
- utiliser DXResourceRelease() pour libérer explicitement les ressources
- contrôler le nombre de sommets : des milliers de polygones sont autorisés pour les objets statiques, des centaines pour les objets animés (le nombre exact dépend des performances de l’ordinateur)
Diagnostic et vérification des erreurs — vérifiez toujours les valeurs de retour et utilisez GetLastError() pour le diagnostic en cas d'erreur :
if(!m_canvas.CreateBitmapLabel(...)) { int err = GetLastError(); Print("DX Error code: ", err); //--- typical errors: //--- 1: device does not support DX11 //--- 2: insufficient video memory //--- 3: shader compilation error }
Accélération matérielle ou rendu logiciel :
MT5 détecte automatiquement les capacités de votre carte vidéo. Si DirectX 11 n'est pas disponible, les graphismes ne s'afficheront pas. Exigences de vérification :
- carte vidéo compatible avec DX11 et la version 5.0 des shaders
- pilotes à jour (les versions obsolètes peuvent provoquer des artefacts)
- activer l'accélération matérielle dans les paramètres du terminal
Pour savoir quelle version de DirectX est installée sur votre ordinateur, suivez les étapes suivantes :
- dans la zone de recherche de la barre d'outils Windows, tapez « dxdiag », et sélectionnez ensuite « dxdiag » dans la liste des résultats
- dans l'outil de diagnostic DirectX, sélectionnez l'onglet Système - la version de DirectX doit être au moins 11

Fig. 3 : vérification de la version de DirectX
Note :
Lors de votre première utilisation de l'outil de diagnostic DirectX, il se peut que vous soyez invité à vérifier les signatures numériques de vos pilotes. Il est recommandé de sélectionner Oui pour garantir que vos pilotes sont signés par un éditeur qui a vérifié leur authenticité.
Optimisation de la consommation des ressources informatiques pour la boucle de rendu :
- OnTimer() ou OnChartEvent() — pour les scènes statiques, appelez la fonction Redraw() uniquement lorsque les données changent, et non à chaque tick
- niveau de détail (« Level of Detail » ou LOD) — réduit le niveau de détail des objets à mesure que la caméra s'éloigne ;
- Instanciation - pour plusieurs objets identiques (clusters, marqueurs), utilisez un seul maillage avec des matrices de transformation différentes.
Le pipeline de base est prêt. Nous avons créé un canevas, configuré une projection, défini des objets avec des sommets et des normales, appliqué des transformations et un éclairage. L'étape suivante consiste à alimenter ce cadre avec du contenu analytique : transformer les résultats d'optimisation en surfaces 3D, les clusters de liquidité en structures volumétriques et les modèles de scénarios en rapports interactifs.
Visualisation de données complexes — surfaces, clusters, scénarios
Une fois le pipeline DX de base mis en place, nous disposons d'un espace vide prêt à visualiser les données. La prochaine étape consiste à transformer les chiffres du rapport du Testeur de Stratégie en primitives géométriques compréhensibles par l'œil humain. Nous passons des matrices brutes aux paysages visuels.
La création d'une surface d'optimisation 3D est probablement la manière la plus utile d'utiliser la 3D dans le trading. Le Testeur de Stratégie produit un tableau où les lignes représentent les exécutions et les colonnes les paramètres et les métriques. La visualisation des résultats d'optimisation en 3D transforme ce tableau en un terrain.
Mathématiques de visualisation simples : les axes X et Z deviennent les paramètres de la stratégie (par exemple, la période de moyenne mobile et la taille du stop), et l'axe Y (hauteur) devient la fonction cible (par exemple, le facteur de récupération, la valeur attendue). Pour construire cette surface, nous devons générer un maillage triangulaire (Mesh) basé sur le tableau de résultats.
Algorithme de construction :
- collecte des données – parcourir l’ensemble des résultats d’optimisation, sélectionner et structurer les données nécessaires
- normalisation - normaliser les valeurs des paramètres à une échelle commune afin d’éviter un rendu visuellement écrasé
- génération des sommets - pour chaque point de données, nous créons le sommet DXVertex
- triangulation - relier les sommets adjacents par leurs indices pour former des triangles
//+------------------------------------------------------------------+ //| example of creating a surface from a data array | //+------------------------------------------------------------------+ void CreateOptimizationSurface(const double &data[],const int width,const int height) { DXVertex vertices[]; uint indices[]; int v_count = 0; int i_count = 0; //--- allocate memory for vertices (width*height of points) ArrayResize(vertices,width*height); for(int y=0;y<height;y++) { for(int x=0;x<width;x++) { int idx=y*width+x; //--- X and Z are the coordinates of the parameters, Y is the value of the metric (profit) vertices[idx].position=DXVector3(x, data[idx], y); vertices[idx].normal=DXVector3(0, 1, 0); // simplified normal vertices[idx].vcolor=ColorToVector4(ColorFromValue(data[idx])); // color depends on value vertices[idx].tcoord=DXVector2((float)x/width, (float)y/height); } } //--- next, we form an array of indices for triangles and create an object using m_mesh.Create(...) }
Sur une telle surface, des « plateaux » apparaissent immédiatement — de vastes zones où la stratégie fonctionne de manière relativement stable lorsque les paramètres changent. À l'inverse, des pics de profit étroits (semblables à des aiguilles) sont clairement visibles, ce qui indique un sur-ajustement. Il est beaucoup plus facile de repérer visuellement une telle « aiguille » que de la remarquer dans un tableau de 1.000 lignes, étant donné que les dépendances multidimensionnelles sont difficilement visibles sous forme tabulaire.
Analyse de clusters dans l'espace
Les données de marché incluent non seulement le prix et le temps, mais aussi le volume. En 2D, on dessine généralement un histogramme de volume en bas de l'écran, mais en 3D, le volume devient une dimension à part entière. Au lieu de barres plates, nous pouvons utiliser des blocs de volume (voxels) ou des cylindres, dont la hauteur et l'épaisseur dépendent du volume des échanges ou de la densité du cluster :
- axe X - le temps
- axe Z - le prix
- axe Y — le volume / nombre de transactions (rayon du voxel)
Visualisation de la liquidité : à l’aide de DXComputeSphere ou de maillages personnalisés, vous pouvez dessiner de grands groupes de transactions sous forme de sphères de tailles et de transparences variables. Superposées les unes aux autres, elles créent un nuage de liquidité, où le trader voit des « vides » (zones où le prix a évolué rapidement) et des « zones de concentration » (niveaux de support/résistance).
//--- setting color based on volume (heatmap effect) //--- the larger the volume, the redder the color (from blue to red) color cluster_color=ColorInterpolate(clrBlue,clrRed,volume_ratio); m_cluster.MeshColorSet(ColorToVector4(cluster_color,0.7)); // 0.7 - transparency
Génération de surface via DXComputeSurface()
Pour les tâches typiques de visualisation de données bidimensionnelles (cartes thermiques, résultats d'optimisation, matrices de corrélation), la bibliothèque DirectX MQL5 fournit la fonction modèle prête à l'emploi DXComputeSurface(). Cette fonction se trouve dans le fichier DXUtils.mqh.
Déclaration :
//+------------------------------------------------------------------+ //| Surface | //| TVertex must have | //| DXVector4 position, DXVector4 normal and DXVector2 tcoord members| //+------------------------------------------------------------------+ template <typename TVertex> bool DXComputeSurface(double &data[],uint data_width,uint data_height,double data_range, const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size, bool two_sided,bool use_normals, TVertex &vertices[],uint &indices[])
But :
Générer automatiquement les sommets et les indices d'une surface 3D à partir d'un tableau de données 2D. Cette fonction dispense le développeur de la nécessité de calculer manuellement les coordonnées, la triangulation du maillage et les normales.
Entrées :
| Paramètre | Type | Description |
|---|---|---|
| [in] data[] | double& | Tableau unidimensionnel de valeurs de hauteur (données d'optimisation, corrélations, etc.) |
| [in] data_width | uint | Largeur de la matrice de données d'origine (nombre de colonnes) |
| [in] data_height | uint | Hauteur de la matrice de données originale (nombre de lignes) |
| [in] data_range | double | Plage d'échelle pour les valeurs le long de l'axe Z (hauteur) |
| [in] from | const DXVector3& | Coordonnées du coin inférieur gauche de la surface dans l'espace 3D |
| [in] to | const DXVector3& | Coordonnées du coin supérieur droit de la surface dans l'espace 3D |
| [in] texture_size | DXVector2& | Taille des coordonnées de texture (pour le mappage de texture ou les dégradés) |
| [in] two_sided | bool | Indicateur de rendu double face (utile pour les surfaces transparentes) |
| [in] use_normals | bool | Indicateur de calcul des normales pour un éclairage correct |
| [out] vertices[] | TVertex& | Tableau des sommets de sortie (rempli par la fonction) |
| [out] indices[] | uint& | Tableau de sortie des indices pour la triangulation (rempli par la fonction) |
Exigences relatives au type TVertex - le paramètre de modèle TVertex doit être une structure contenant au moins trois champs :
struct MyVertex { DXVector4 position; // vertex coordinates (x,y,z,w) DXVector4 normal; // normal vector (nx,ny,nz,0) DXVector2 tcoord; // texture coordinates (u,v) // additional fields as needed: color, binormal, etc. };
Valeur renvoyée :
- true — la surface a été générée avec succès
- false — erreur (vérifiez la taille des tableaux et la validité des données d'entrée)
Exemple d'utilisation :
Supposons que nous ayons les résultats de l'optimisation de stratégie sous la forme d'une matrice 20x20, où chaque valeur représente la valeur attendue d'une transaction. Nous souhaitons visualiser ces données sous forme de surface 3D.
//+------------------------------------------------------------------+ //| Generate optimization surface via DXComputeSurface | //+------------------------------------------------------------------+ void BuildOptimizationSurface(double &optimization_data[],uint width,uint height) { //--- define the vertex type with an additional color field struct SVertex { DXVector4 position; DXVector4 normal; DXVector2 tcoord; DXColor vcolor; // vertex color for gradient }; SVertex vertices[]; uint indices[]; //--- surface parameters DXVector3 from(-10.0,-5.0,0.0); // lower left corner DXVector3 to(10.0,5.0,1.0); // upper right corner DXVector2 texture_size(1.0,1.0); // full coverage of texture coordinates double data_range=2.0; // height scaling //--- generate geometry if(!DXComputeSurface(optimization_data,width,height,data_range, from,to,texture_size, false,true, // one-sided, with normals vertices,indices)) { Print("surface generation error: ",GetLastError()); return; } //--- color the vertices by height (gradient: red → green) for(uint i=0;i<ArraySize(vertices);i++) { double t=MathMax(0.0,MathMin(1.0,vertices[i].position.z/data_range)); vertices[i].vcolor=DXColor(1.0f-(float)t,(float)t,0.2f,1.0f); } //--- create a mesh and add it to the scene if(!mesh.Create(canvas.DXDispatcher(),canvas.InputScene(),vertices,indices)) Print("error creating mesh: ",GetLastError()); mesh.DiffuseColorSet(DXColor(1.0f,1.0f,1.0f,1.0f)); canvas.ObjectAdd(&mesh); }
Avantages de DXComputeSurface() :
- vitesse de développement : plus besoin d’écrire manuellement les cycles de triangulation et de calcul normal
- optimisation - l'implémentation interne utilise des algorithmes de génération de maillage efficaces
- flexibilité - le type de sommet du modèle permet d'ajouter tous les attributs supplémentaires (couleur, texture, données personnalisées)
Limitations de DXComputeSurface() :
- grilles régulières uniquement - la fonction suppose que les données sont une matrice rectangulaire ; pour les nuages de points irréguliers ou les topologies arbitraires, une génération manuelle sera nécessaire
- interpolation par défaut : les hauteurs des sommets sont interpolées linéairement entre les nœuds de la grille, un pré-filtrage des données peut être nécessaire pour lisser les aspérités
- mémoire - la fonction alloue dynamiquement les tableaux de sommets et d'indices (lorsque vous travaillez avec de grandes matrices (par exemple 100x100 et plus), surveiller la consommation de mémoire et la fréquence de reconstruction de la surface)
Intégration avec le contrôle interactif :
Étant donné que DXComputeSurface() génère une géométrie statique, les mises à jour dynamiques (par exemple lors de la modification des paramètres d'optimisation en temps réel) nécessitent :
- l’enregistrement d’une référence à l'objet CDXMesh
- un appel à mesh.Shutdown() lorsque les données changent pour libérer les anciens buffers
- un nouvel appel à DXComputeSurface() et mesh.Create() avec les nouvelles données
- un appel à RedrawScene() pour afficher les modifications
Pour une animation fluide, il est recommandé de déplacer les opérations lourdes vers le gestionnaire OnTimer, comme cela est fait dans l'EA DX_OptimizationSurface (voir la description ci-dessous). L'utilisation de DXComputeSurface() dans de nombreux cas typiques réduit la quantité de code de 30 à 40% lors de la construction de surfaces typiques, ce qui nous permet de nous concentrer sur la logique analytique plutôt que sur les graphismes de bas niveau.
Modélisation de scénarios et rapports interactifs
L'un des avantages de DirectX dans MQL5 est la possibilité de mettre à jour dynamiquement la scène sans recharger l'indicateur. Cela ouvre la voie à la modélisation de scénarios hypothétiques. Par exemple, le panneau où vous déplacez le curseur intitulé « Volatilité » ou « Commission ». Le tableau data[] est recalculé en temps réel, et la fonction de mise à jour du buffer de sommets VertexSet() modifie dynamiquement la surface 3D.
//+------------------------------------------------------------------+ //| dynamic update example | //+------------------------------------------------------------------+ void OnSliderChange(const double new_vol) { //--- recalculate the strategy metrics with the new volatility RecalculateStrategyMetrics(new_vol); //--- update only the Y-coordinate of the vertices (height), without recreating the mesh for(int i=0;i<ArraySize(m_vertices);i++) { m_vertices[i].position.y=m_new_metrics[i]; //--- recalculate normals for correct lighting m_vertices[i].normal=CalculateNormal(i); } //--- send updated data to video memory m_mesh.VertexSet(m_vertices); Redraw(); }
Cela permet au trader d'évaluer la robustesse de la stratégie : si une petite variation de la volatilité transforme un résultat rentable en résultat perdant, il est peu probable que la stratégie soit viable à long terme.
Les shaders en tant que filtre analytique
Les shaders standard de MetaTrader 5 sont responsables de l'éclairage (modèle de Phong). Mais pour l'analyse, nous avons besoin de shaders qui fonctionnent avec les données. Nous pouvons écrire un simple Pixel Shader qui servira de filtre.
Par exemple, vous devez mettre en évidence sur le graphique 3D uniquement les zones où le drawdown dépasse 20%, ou celles où le facteur de profit est inférieur à un :
//+------------------------------------------------------------------+ //| example of logic in HLSL shader | //+------------------------------------------------------------------+ float4 PS_Main(PS_INPUT input) : SV_TARGET { //--- input.color contains the metric information encoded in the vertex float profit=input.color.r; //--- if the profit is below the threshold, make the object transparent if(profit<threshold) return float4(0.5,0.5,0.5,0.2); // gray and transparent else return float4(0.0,1.0,0.0,1.0); // bright green }
Dans le shader, nous vérifions la valeur d'un attribut de sommet (tel que la hauteur ou la couleur transmise) et, si elle ne répond pas aux critères, nous rendons le pixel transparent ou gris. Cette approche nous permet d'éliminer le « bruit » du graphique, ne laissant apparaître que les zones significatives. Ceci est important lors de l'analyse de grands ensembles de données d'optimisation.
Interactivité - contrôle de la souris, des boutons et de la caméra
Une image 3D statique est belle, mais elle est peu utile en trading si vous ne pouvez pas la faire pivoter, zoomer ou la filtrer. Le véritable avantage de DirectX dans MQL5 apparaît lorsque nous avons la possibilité d'explorer activement les données. Voyons comment donner vie à une scène en liant les événements de la souris et du clavier aux calculs de la caméra.
Gestion des événements en MQL5 — donner vie au canevas
Par défaut, le canevas (CDXCanvas) est simplement une image raster qui ne répond pas au curseur. Pour permettre l'interaction avec l'utilisateur, il faut s'abonner aux événements du graphique. Cela se fait via les modificateurs CHART_EVENT_MOUSE_... dans la fonction OnInit() :
//+------------------------------------------------------------------+ //| subscribe to mouse events | //+------------------------------------------------------------------+ int OnInit() { //--- enable receiving mouse events ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,1); ChartSetInteger(0,CHART_EVENT_MOUSE_WHEEL,1); //--- timer for animation EventSetMillisecondTimer(16); return(INIT_SUCCEEDED); }
Après cela, tous les mouvements du curseur seront traités par le gestionnaire OnChartEvent(). La prochaine étape consiste à filtrer les identifiants requis (CHARTEVENT_MOUSE_MOVE, CHARTEVENT_MOUSE_WHEEL) et à transmettre les coordonnées au module de rendu.
Remarques :
Dans OnDeinit(), assurez-vous de désactiver ces événements (en appelant ChartSetInteger(..., 0)), sinon après la suppression de l'indicateur, le terminal continuera à les générer et créera une charge supplémentaire.
Contrôle de la caméra — orbite et zoom
La méthode la plus courante pour interagir avec des graphismes 3D consiste à faire pivoter un objet (orbite) et à zoomer/dézoomer. Dans DirectX, cela se réalise non pas en faisant pivoter l'objet lui-même, mais en déplaçant la caméra sur une sphère autour du centre de la scène.
Trois méthodes interdépendantes sont utilisées pour contrôler la caméra dans la classe CCanvas3D :
- ViewPositionSet() — définit l'emplacement de l'œil de l'observateur (coordonnées de la caméra)
- ViewTargetSet() — définit où l'observateur regarde (généralement le centre de la scène est 0,0,0)
- ViewUpDirectionSet() — définit la direction du haut du cadre (afin que la caméra ne se retourne pas)
Mise en œuvre de la rotation
La rotation s'effectue en déplaçant le curseur de la souris tout en maintenant le bouton gauche de la souris enfoncé. Pour faire pivoter la scène, nous suivons le delta de déplacement du curseur : la différence entre la position actuelle et la position précédente. Nous convertissons ce delta en angles de rotation autour des axes X et Y.
//+------------------------------------------------------------------+ //| mouse movement event handler | //+------------------------------------------------------------------+ void OnMouseMove(int x, int y, uint flags) { //--- check that the left mouse button is pressed if((flags&1)==1) { //--- calculate the change in angles based on the mouse offset //--- divide by the coefficient (for example, 300.0f) for sensitivity m_camera_angles.y+=(x-m_mouse_x)/300.0f; m_camera_angles.x+=(y-m_mouse_y)/300.0f; //--- limit the vertical angle if(m_camera_angles.x<-DX_PI*0.49f) m_camera_angles.x=-DX_PI*0.49f; if(m_camera_angles.x>DX_PI*0.49f) m_camera_angles.x=DX_PI*0.49f; //--- recalculate the camera position UpdateCameraPosition(); Redraw(); } //--- save the current coordinates for the next step m_mouse_x=x; m_mouse_y=y; }
Dans la fonction UpdateCameraPosition(), nous utilisons les matrices de rotation DXMatrixRotationX et DXMatrixRotationY pour faire pivoter le vecteur de direction de la caméra et mettre à jour sa position dans l'espace.
Mise en œuvre du zoom
La rotation de la molette de la souris modifie la distance entre la caméra et le centre de la scène (m_camera_distance).
//+------------------------------------------------------------------+ //| mouse wheel rotation event handler | //+------------------------------------------------------------------+ void OnMouseWheel(double delta) { //--- decrease or increase the distance m_camera_distance*=1.0-delta*0.001; //--- limit the zoom to reasonable values if(m_camera_distance>50.0) m_camera_distance=50.0; if(m_camera_distance<3.0) m_camera_distance=3.0; UpdateCameraPosition(); Redraw(); }
Panneau d'interface utilisateur au-dessus de la scène 3D
Les graphismes 3D sont responsables de l'affichage des données, mais pour contrôler les paramètres, nous avons besoin d'éléments d'interface MQL5 standard et familiers. Pour éviter de réinventer la roue, utilisez les classes de la bibliothèque de contrôles MQL5 standard (CAppDialog, CSlider, CComboBox, etc.), qui sont dessinées au-dessus ou sur le côté du canevas graphique. Vous pouvez également utiliser d'autres classes pour construire l'interface.
Lorsque la valeur du curseur change (par exemple, « Seuil de profit »), une fonction est appelée qui met à jour les données dans le buffer de sommets ou modifie les variables du shader, après quoi la fonction Redraw() est appelée. Cela nous permet de créer un outil analytique complet. Par exemple : à gauche se trouve un paysage 3D interactif affichant les résultats de l’optimisation, à droite se trouve un panneau de contrôle avec des filtres.
Optimisation du cycle interactif
L'interactivité ne doit pas réduire significativement les performances du terminal et de l'ordinateur dans son ensemble. Si vous appelez la fonction Redraw() à chaque micro-mouvement de la souris sans maintenir le bouton enfoncé, l'interface du terminal commencera à ralentir.
Énonçons les règles de base pour optimiser l'interactivité :
- appelez Redraw() uniquement lorsque cela est nécessaire - appelez le dessin de la scène uniquement à l'intérieur des blocs de vérification : if((flags & 1) == 1) (vérifiez lorsque le bouton est pressé) ou lors de la modification des paramètres d'interface utilisateur
- filtrez les événements inutiles - si les données de dessin arrivent trop souvent (par exemple, à partir des ticks dans le gestionnaire OnTick()), ne mettez pas à jour le buffer de sommets plus de 10 à 15 fois par seconde
- asynchronisme des calculs lourds - si la modification d'un paramètre nécessite le recalcul de milliers de sommets (par exemple, la reconstruction de l'ensemble de la surface d'optimisation), effectuez-le dans le gestionnaire d'événements de minuterie OnTimer() ou déplacez-le vers un thread séparé via une DLL pour éviter de bloquer l'interface
Expert Advisor de test pour la validation des technologies 3D
Nous développerons un EA mettant en œuvre les technologies 3D décrites. L'EA est un outil de visualisation tridimensionnelle des données analytiques dans le terminal de trading MetaTrader 5. L'objectif principal est de transformer les résultats numériques de l'optimisation de la stratégie de trading en surfaces tridimensionnelles, permettant ainsi au trader et/ou au développeur d'évaluer rapidement la qualité et la stabilité de la stratégie.
L'EA résout les problèmes suivants :
- la visualisation de la surface d'optimisation est une représentation de la dépendance de la fonction objectif (profit, valeur attendue, ratio de Sharpe) sur deux paramètres de stratégie optimisés sous la forme d'un paysage tridimensionnel
- l’analyse de la stabilité de la stratégie – identification des « plateaux de stabilité » (zones de variations progressives des résultats) et des « aiguilles de sur-ajustement » (pics étroits et isolés indiquant un sur-ajustement des données historiques)
- l’exploration interactive des données – permettant de faire pivoter, de zoomer et d'explorer la surface en détail à l'aide d'une souris
- la comparaison des modes – pour basculer entre différents modes d'affichage (par exemple, mode profit et mode bruit) pour évaluer la qualité de l'optimisation
Caractéristiques :
Visualisation 3D — l'EA crée un canevas 3D interactif sur le graphique mesurant 640×480 pixels, qui affiche une surface générée sur la base de la fonction analytique. La surface est un maillage de 25x25 sommets, triangulé pour un affichage correct.
Codage couleur — le schéma de couleurs suivant a été appliqué :
- la partie supérieure (valeurs maximales) est d'un vert intense
- la base (valeurs minimales) - couleur rouge riche
- les valeurs intermédiaires présentent un dégradé progressif avec une transition par des nuances jaune-orange
Ce codage nous permet d'identifier avec précision les zones de profit maximal (les « collines » vertes) et les zones de pertes (les « creux » rouges).
Contrôle de la caméra — un contrôle complet du point de vue a été implémenté :
- rotation - maintenir le bouton gauche de la souris enfoncé et déplacer le curseur permet de faire pivoter la caméra autour du centre de la scène sur une orbite sphérique
- zoom - faire défiler la molette de la souris permet de zoomer ou de dézoomer la caméra (distance de 5,0 à 40,0 unités)
- limitations - l'angle vertical est limité à ±0,9×π/2 pour éviter que la caméra ne se retourne
Contrôle interactif
Il y a un bouton de changement de mode sur le canevas :
- mode profit - affiche une surface de courbe gaussienne lisse (simulant une stratégie stable)
- mode bruit - affiche la surface avec du bruit aléatoire ajouté (simulant une stratégie sur-optimisée)
Lors du changement de mode, le texte du bouton est automatiquement mis à jour.
Éclairage et matériaux
Pour créer une image volumétrique réaliste, un modèle d'éclairage Phong à trois composantes a été utilisé :
- source de lumière directionnelle - couleur jaune (1,0, 0,95, 0,8), direction (0,5, -0,8, 0,3)
- éclairage ambiant - couleur grise (0,55, 0,55, 0,55) avec une intensité accrue pour une meilleure visibilité des zones d'ombre
- matériau diffus - couleur blanche (1.0, 1.0, 1.0, 1.0) pour se combiner correctement avec les couleurs des sommets
Caractéristiques de l'implémentation
Gestion des événements asynchrones :
- réaction aux mouvements du curseur de la souris et à la rotation de la molette - le programme reçoit l'appel de fonction OnChartEvent() et le traite immédiatement (l'orientation du modèle 3D, ses dimensions, etc. sont modifiées) - aucun calcul complexe n'est nécessaire
- réaction à l'appui sur le bouton de changement de mode - le programme reçoit l'appel de fonction OnChartEvent() et définit l'indicateur need_rebuild, la fonction BuildSurface() chargée de détruire l'ancien maillage, de générer une nouvelle surface 3D et d'effectuer le rendu est appelée dans le gestionnaire OnTimer(), qui vérifie l'état de l'indicateur need_rebuild toutes les 50 ms
Cette approche garantit que même si le recalcul du modèle 3D consomme des ressources du processeur, le graphique du terminal et les commandes restent pleinement réactifs.
La bibliothèque MQL5\Include\Canvas\DX\DXMath.mqh est utilisée pour calculer correctement l'éclairage et l'orientation de la caméra :
- normales - pour chaque sommet de la surface, le vecteur normal est calculé à l'aide de la fonction de produit vectoriel DXVec3Cross(), nécessaire pour que la surface ait du volume et réagisse à la source lumineuse, créant ainsi des ombres et des reflets réalistes
- caméra - la position de l'observateur est calculée à l'aide de coordonnées sphériques, ce qui permet une rotation intuitive autour d'un objet (« orbite ») sans l'effet de retournement de la caméra, limitant ainsi l'angle vertical
Le code complet de l'EA est contenu dans le fichier DX_OptimizationSurface.mq5 joint à l'article.
Des exemples du fonctionnement de l'EA dans différents modes sont présentés dans les figures ci-dessous :

Fig. 4 : mode de profit

Fig. 5 : mode bruit
Nous disposons désormais d'une panoplie complète d'outils : nous pouvons créer une scène, la remplir de données d'optimisation et donner à l'utilisateur la possibilité d'explorer ces données en effectuant des rotations et des zooms. Mais avant de nous précipiter pour implémenter la 3D partout où c'est possible, examinons d'abord où cette technologie est inutile et où il est préférable de s'en tenir aux graphiques conventionnels.
Quand vaut-il mieux s'en tenir aux graphiques classiques ?
Un outil n'est utile que s'il résout un problème plus rapidement et avec plus de précision que son prédécesseur. Nous avons exploré l'architecture du pipeline DX, appris à générer des surfaces et à contrôler la caméra. Mais en matière de trading, il faut faire la distinction entre une visualisation analytique utile et le bruit visuel. L'intégration de graphismes 3D dans MetaTrader 5 n'est pas une fin en soi, mais un moyen de résoudre des problèmes. Examinons les cas où l'abandon de la 3D au profit de la 2D classique se justifiera techniquement et économiquement.
Règle de dimensionnalité des données
Établissons une règle justifiant la nécessité de la visualisation 3D : la troisième dimension doit véhiculer des informations uniques :
- la 3D est inutile si vous essayez d'afficher une série temporelle (Prix/Temps) dans un espace 3D - ajouter un axe Z qui duplique le prix ou le temps ne fera que compliquer la perception, obligeant le trader à faire pivoter la scène pour voir la ligne de tendance classique.
- la 3D est nécessaire pour analyser les résultats d'optimisation - ici, nous avons deux entrées indépendantes (par exemple, la période de moyenne mobile et la taille du stop) et une mesure de sortie (le profit ou le facteur de profit) ; sans surface 3D, nous ne verrons qu'un ensemble de points : la 3D nous permet de visualiser la relation entre deux variables et le résultat
si votre ensemble de données se résume à une paire de coordonnées, un graphique 2D classique (DRAW_LINE, DRAW_HISTOGRAM) sera plus efficace
Limitations matérielles et VPS
Les graphismes 3D en MQL5 sont basés sur DirectX 11. Cela nécessite la prise en charge du Shader Model 5.0 et un certain niveau de performances CPU/GPU.
La plupart des développeurs professionnels exécutent leurs EA sur des serveurs privés virtuels (VPS). De nombreuses configurations VPS standard ne disposent pas de cartes graphiques puissantes ni d'accélération matérielle DirectX. Dans de tels environnements, l'appel à CreateBitmapLabel() peut provoquer une erreur critique de l’EA et/ou un plantage.
Par conséquent, si votre programme est conçu pour fonctionner en mode « aveugle », c’est-à-dire sans graphismes, ou sur un serveur bon marché, le module 3D doit être désactivé ou remplacé par une journalisation dans un fichier/une base de données. Les graphismes 2D peuvent être facilement rendus par le processeur, même sans carte vidéo.
Vitesse de perception — Surface 3D comparée à une carte thermique
L'une des principales alternatives à une surface 3D est une carte thermique bidimensionnelle (HeatMap). Les différences fondamentales entre eux sont les suivantes :
- 3D - affiche la hauteur (Z) comme élévation physique : une rotation est nécessaire pour analyser avec précision toutes les faces et les pentes cachées
- carte thermique — affiche la valeur (Z) comme la couleur d'une cellule sur le plan (X, Y)
Si l'objectif est de trouver rapidement l'optimisation maximale (la zone la plus verte), la carte thermique de l'indicateur standard fonctionnera plus rapidement et nécessitera moins de code.
Interactivité vs surveillance
Les scènes 3D interactives (comme notre DX_OptimizationSurface EA) nécessitent une participation humaine active. Vous devez survoler la zone avec votre souris, maintenir le bouton enfoncé et faire pivoter la scène.
Si l'objectif du graphique est la surveillance passive, les graphiques 3D interactifs peuvent être une source de distraction et ralentir le processus.
Si l'objectif est une présentation ou une analyse approfondie avant le lancement d'une stratégie, alors la 3D est indispensable.
Conclusion :
N’utilisez la 3D que lorsque le volume des données ou leur structure rendent l’analyse en 2D impossible. Si votre objectif est de trouver rapidement le maximum dans un tableau d'optimisation, une carte thermique sera plus efficace. La 3D est nécessaire lorsqu'il faut visualiser la forme de la relation, et pas seulement sa valeur.
Dans d'autres cas, les classes MQL5 standard (CCanvas pour les objets 2D ou graphiques) constitueront une solution plus simple.
Conclusion
Nous sommes passés de la justification théorique du besoin de graphismes 3D à la création d'un EA interactif à part entière. L'Expert Advisor DX_OptimizationSurface démontre que MetaTrader 5 n'est pas seulement un terminal d'exécution d'ordres, mais une plateforme puissante pour l'analyse visuelle des données.
Principales conclusions :
- efficacité cognitive – la visualisation 3D nous permet de transformer des ensembles infinis de chiffres en paysages visuels, ce qui réduit la charge cognitive du trader, lui permettant de distinguer visuellement les plateaux de profit stables des dangereuses fluctuations dues au sur-ajustement
- accessibilité technologique – la prise en charge intégrée de DirectX 11 et les classes natives CCanvas3D et CDXMesh offrent aux développeurs les outils nécessaires pour résoudre les problèmes de trading, il n'est pas nécessaire d'écrire du code C++ ni d'inclure des bibliothèques externes : tout est déjà intégré à MQL5 - il ne reste plus qu'à en profiter.
- l’importance de l’architecture — comme nous l’avons vu, l’intégration graphique exige une attention particulière aux cycles de vie des ressources et à l’asynchronisme : le fait de déporter les opérations de calcul vers une minuterie et d'effacer correctement la mémoire garantit l'absence de problèmes de performance du terminal
La visualisation est une lentille, pas un ornement. Elle doit répondre à une question analytique précise.
Nous avons créé cet outil non pas pour produire un effet externe, mais pour accélérer la prise de décision. Si les graphismes 3D vous aident à comprendre rapidement le comportement d'une stratégie et à éliminer les options non viables, alors ils ont rempli leur rôle. Si ce n'est qu'une distraction, n'hésitez pas à revenir aux méthodes 2D éprouvées. La valeur d'un outil ne réside pas dans son apparence, mais dans les décisions qu'il permet de prendre plus rapidement.
Prochaines étapes – pour ceux qui souhaitent approfondir le sujet, nous recommandons ce qui suit :
- exploration de la bibliothèque DXMath pour travailler avec les quaternions et les transformations complexes
- développement de shaders personnalisés (HLSL) pour créer des effets de rendu uniques
- intégration avec Python via MetaTrader 5 pour le prétraitement des données avant leur visualisation dans le terminal
MetaTrader 5 fournit la base technologique. Les outils analytiques que vous développerez à partir de ces données ne dépendent que de votre imagination et de la nécessité de rechercher des « perles » dans l’immensité des données de marché.
Ressources recommandées pour apprendre à utiliser DirectX dans MetaTrader 5 :
- aide DirectX pour MetaEditor
- Comment créer des graphismes 3D à l'aide de DirectX dans MetaTrader 5
- Tutoriel DirectX (partie I) : tracer le premier triangle
- Visualiser une stratégie dans le Testeur de Stratégie MetaTrader 5
Liste des fichiers joints à l'article :
| Nom de fichier | Description |
|---|---|
| DX_OptimizationSurface.mq5 | Un fichier contenant le code d'un EA de test avec visualisation 3D interactive |
Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/22393
Avertissement: Tous les droits sur ces documents sont réservés par MetaQuotes Ltd. La copie ou la réimpression de ces documents, en tout ou en partie, est interdite.
Comment Échanger des Données : Une DLL pour MQL5 en 10 minutes
Architecture événementielle en MQL5 : Comment transformer un Expert Advisor en un système de trading à part entière
L'Histogramme des prix (Profile du Marché) et son implémentation en MQL5
MetaTrader 5 : créez un marché adapté à votre stratégie — barres Renko, Range et Volume Egal, instruments synthétiques et tests de résistance sur symboles personnalisés
- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation
Waouh. C'est vraiment génial ! Merci. Je vais le démonter…
INCROYABLE..........