3D-визуализация без внешних библиотек: как MetaTrader 5 раскрывает результаты оптимизации через MQL5 + DX11
От красивой картинки к рабочему инструменту
Когда количество параметров стратегии перешагивает десяток, а отчет тестера превращается в многостраничную таблицу с числовыми рядами, трейдер и разработчик сталкиваются с проблемой: полезный сигнал начинает тонуть в шуме. Плоские графики и двумерные тепловые карты эффективно работают до определенного предела, но после него человеческий мозг закономерно «спотыкается» о многомерность данных. Мы пытаемся удержать в голове корреляцию между периодом индикатора, стоп-лоссом, волатильностью и максимальной просадкой, но когнитивная нагрузка растет быстрее, чем полезность информации.
3D-визуализация и интерактивные интерфейсы в MetaTrader 5 — это не попытка превратить торговый терминал в игровой движок. Это прием, направленный на снижение когнитивного трения. Объемная поверхность, где высота соответствует математическому ожиданию, а цветовой градиент отражает устойчивость к просадке, позволяет за секунды выделить «плато стабильности» и отсечь «иглы переоптимизации». То, что в табличном формате требует часов сопоставления, в трехмерном пространстве считывается как паттерн: наклоны плоскостей, перепады высот, плато/иглы и зоны контраста.
MetaTrader 5 предоставляет для этой задачи готовый технологический фундамент. Нативная поддержка DirectX 11, встроенный шейдерный конвейер и классы CDXCanvas / CChartObjectDX интегрированы непосредственно в среду MQL5. Разработчику не нужно подключать внешние графические библиотеки, писать обертки на C++ или бороться с зависимостями: весь цикл от создания устройства до вывода кадра доступен через стандартный 3D-API, а загрузка шейдеров и текстур работает напрямую из папки Files\DX\.
В этой статье мы последовательно разберем, как превратить массивы результатов оптимизации, кластерные объемы и сценарные модели в управляемые 3D-ландшафты. Обозначим критерии целесообразности: когда объемная графика добавляет возможности анализа сигнала, а когда генерирует визуальный шум. Затем перейдем к архитектуре DX-конвейера, разберем инициализацию, привязку метрик к вершинным буферам, механику камеры и UI-панелей, а в завершение оценим технологические ограничения среды.

Рис.1: Текст против визуализации
Когда 3D и интерактивность действительно полезны
В арсенале трейдера и разработчика стратегий есть мощный, но часто недооцениваемый инструмент — визуальное восприятие. Таблицы отчетов, списки метрик и плоские графики хорошо справляются с задачей документирования результатов. Но когда нужно понять сложные зависимости, человеческий мозг переключается на другой режим: он ищет паттерны в виде образов, объем и контекст. Именно здесь 3D-визуализация и интерактивность перестают быть украшением и становятся инструментом аналитики.
Добавление третьей оси оправдано тогда, когда в данных есть четкая аналитическая гипотеза. Например, зависимость математического ожидания сделки от двух ключевых параметров системы при фиксированном уровне риска. В таком случае 3D-поверхность превращает абстрактные координаты в рельеф, где зеленые «горы» означают зоны устойчивой прибыли, а красные «провалы» — просадки. Трехмерное представление работает как фильтр: отсекает шум и оставляет только те комбинации, которые имеют значимость.
Не ради красоты, а ради смысла
Важно уточнить: речь не о декоративной графике, а о визуальных слоях, которые раскрывают напрямую то, что скрыто в строках отчета оптимизации. Плоская таблица отвечает на вопрос: «Какой результат у этой комбинации параметров?»
3D-поверхность отвечает на вопрос: «Как меняется результат при плавном изменении двух параметров, и где находятся зоны устойчивости?» Это принципиально иной уровень анализа стратегии. Потому что устойчивость результата при изменении внешнего контекста — это главное, чего стоит добиваться при проверке той или иной идеи. Все остальное вторично.
Есть, по крайней мере, три сценария, где 3D-визуализация дает преимущество:
1. Ландшафт оптимизации
Представьте, что вы подбираете два параметра: период скользящей средней и размер стоп-лосса. В таблице вы видите 100 строк со значениями Профит и Просадка. На 3D-поверхности с цветовым градиентом вы мгновенно увидите:
- Плато робастности — обширные зеленые зоны, где стратегия стабильно прибыльна даже при вариации параметров;
- Острые пики — узкие локальные максимумы, которые часто являются признаком переоптимизации;
- Крутые склоны — области, где небольшое изменение параметра приводит к резкому росту просадки.
Такая 3D-поверхность позволяет принимать обоснованные решения о выборе рабочего набора параметров не по максимальному профиту, а по критерию устойчивости.
2. Состояние рынка как многомерное пространство
Кластеризация рыночных режимов (тренд, флэт, повышенная волатильность) часто требует анализа более трех индикаторов одновременно. И здесь 3D-визуализация позволяет:
- Отобразить каждое состояние рынка как точку в пространстве признаков;
- Цветом кодировать эффективность стратегии в этом режиме (этой точке);
- Интерактивно вращать облако точек, чтобы выявить скрытые группировки.
Это особенно удобно при адаптивной настройке параметров: видно, в каких условиях стратегия сбоит, а где работает устойчиво.
3. Сценарное моделирование и стресс-тесты
При прогоне стратегии на множестве синтетических сценариев (метод Монте Карло, генерация путей цены, вопросы вида: что, если волатильность вырастет на 30%?) 3-е измерение может отображать:
- Ось X — параметр стратегии;
- Ось Y — уровень стресса рынка (волатильность, гэпы);
- Ось Z / цвет — итоговая метрика (фактор восстановления, мат.ожидание).
В результате вы наблюдаете не просто некий худший случай, а границу устойчивости стратегии к деградации рыночных условий.
Критерии выбора: когда 3D избыточно
Сформулируем правило: 3D оправдано, когда вы исследуете зависимость результата от двух и более непрерывных переменных и вам важно увидеть геометрию этой зависимости.
Если вы готовы попробовать заменить многочасовой перебор отчетов на интуитивный визуальный анализ, давайте начнем с конвейера рендеринга.
Базовый DX-конвейер в MQL5: от инициализации до первого кадра
Создание 3D-графики в MetaTrader 5 — последовательный конвейер, где каждый этап имеет свое назначение. Понимание архитектуры DirectX-объектов и цикла рендеринга позволяет избежать типичных ошибок: утечек памяти, мерцания графики и падения производительности при работе с большими объемами данных.
Архитектура объектов DirectX в MQL5
В основе 3D-графики в MQL5 лежит класс CCanvas3D, который инкапсулирует всю сложность работы с DirectX 11. Он предоставляет разработчику высокоуровневый API, скрывая низкоуровневые детали создания устройств, контекстов и буферов обмена.
Иерархия объектов:
- CCanvas3D — класс, управляющий сценой, камерой и рендерингом
- CDXMesh и его наследники (CDXBox, CDXSphere, CDXTorus) — геометрические объекты
- DXVertex — структура вершины, содержащая координаты, нормали, текстурные координаты и цвет
struct DXVertex { DXVector4 position; // координаты вершины DXVector4 normal; // вектор нормали DXVector2 tcoord; // координаты грани для натягивания текстуры DXColor vcolor; // цвет };
Эта структура работает со стандартным вершинным шейдером, что избавляет от необходимости писать собственные шейдеры для базовых задач. Для сложных проектов рекомендуем использовать методы и утилиты, представленные в файле «MQL5\Include\Canvas\DX\DXUtils.mqh».

Рис.2: Иерархия 3D-графики в MQL5
Все ресурсы (шейдеры, текстуры, буферы) управляются через DXDispatcher. Каждый созданный объект должен быть явно уничтожен через Destroy() или Shutdown() в деструкторе. В MT5 нет сборщика мусора для DirectX-ресурсов и утечки памяти накапливаются до перезапуска терминала.
Инициализация конвейера
Первый шаг — создание холста и настройка проекционной матрицы:
//+------------------------------------------------------------------+ //+ создание холста и настройка проекционной матрицы | //+------------------------------------------------------------------+ virtual bool Create(const int width, const int height) { //--- сохраним размеры холста m_width = width; m_height = height; //--- создадим холст для отрисовки на нем 3D сцены 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); } //--- установим параметры матрицы проекции m_canvas.ProjectionMatrixSet((float)M_PI/6, (float)m_width/m_height, 0.1f, 100.0f); //--- создаем 3D-объект 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); } //--- добавим куб на сцену m_canvas.ObjectAdd(&m_box); Redraw(); return(true); }
Основные параметры проекции:
- Угол зрения (FOV) — 30 градусов (M_PI/6), баланс между перспективой и искажениями;
- Aspect ratio — отношение ширины к высоте (m_width/m_height), сохранение его предотвращает растягивание по высоте/ширине;
- Плоскости отсечения — ближняя 0.1f и дальняя 100.0f, за этими пределами объекты не рендерятся.
Эти параметры определяют пирамиду видимости: в матрицу проекции попадают только объекты, находящиеся между двумя виртуальными стенками и в горизонтальном угле зрения.
Компиляция шейдеров — для стандартных примитивов шейдеры компилируются автоматически. Если вы используете кастомные эффекты, используйте DXCompileShader() с обработкой ошибок:
string error_log; if(!DXCompileShader("shader.hlsl", "vs_main", "vs_5_0", shader_blob, error_log)) { Print("Shader compilation failed: ", error_log); return(false); }
Данные → Вершины → Кадр
После инициализации начинается цикл рендеринга. Каждый кадр проходит через конвейер трансформаций:
Модель объекта — Трехмерная модель описывается сеткой полигонов. На практике используется триангуляция: каждый полигон делится на треугольники, так как треугольник однозначно описывает плоскость в пространстве. Куб, например, имеет 8 вершин, но для корректного освещения создается 24 вершины (по 4 на каждую грань с уникальными нормалями).
//--- подготовка вершин и индексов для сферы DXVertex vertices[]; uint indices[]; if(!DXComputeSphere(0.3f, 50, vertices, indices)) return(false); //--- создаем объект сфера if(!m_sphere.Create(m_canvas.DXDispatcher(), m_canvas.InputScene(), vertices, indices)) { m_canvas.Destroy(); return(false); }
Трансформации — Каждый объект проходит через матрицы:
- Model matrix — локальные координаты → мировые (поворот, масштаб, перемещение);
- View matrix — мировые координаты → координаты камеры;
- Projection matrix — координаты камеры → экранные координаты.
//--- вычислим позицию куба и матрицу переноса DXMatrix rotation, translation; //--- поворачиваем куб последовательно вокруг осей X, Y и Z DXMatrixRotationYawPitchRoll(rotation, (float)M_PI/4, (float)M_PI/3, (float)M_PI/6); //--- сдвигаем куб вправо-вниз-вглубь DXMatrixTranslation(translation, 1.0, -2.0, 5.0); //--- получим матрицу трансформации как произведение поворота и переноса DXMatrix transform; DXMatrixMultiply(transform, rotation, translation); //--- установим матрицу трансформации m_box.TransformMatrixSet(transform);
Освещение (модель Фонга) — Реалистичное изображение требует расчета трех компонент освещения:
- Ambient (фоновое) — постоянная составляющая, имитирующая рассеянный свет;
- Diffuse (рассеянное) — зависит от угла падения света на поверхность;
- Specular (зеркальное) — блики, создающие эффект глянца.
//--- установим желтый цвет источника и направим его сверху вниз m_canvas.LightColorSet(DXColor(1.0, 1.0, 0.0, 0.8f)); m_canvas.LightDirectionSet(DXVector3(0.0, -1.0, 0.0)); //--- установим цвет окружающего освещения синим m_canvas.AmbientColorSet(DXColor(0.0, 0.0, 1.0, 0.4f)); //--- установим белый цвет куба с зеленым свечением m_box.DiffuseColorSet(DXColor(1.0, 1.0, 1.0, 1.0)); m_box.EmissionColorSet(DXColor(0.0, 1.0, 0.0, 0.2f));
Рендеринг и обновление холста — Все операции производятся в методе Render(), после чего изображение переносится на холст через Update():
//--- расчет 3D сцены m_canvas.Render(DX_CLEAR_COLOR | DX_CLEAR_DEPTH, ColorToARGB(clrBlack)); //--- обновить картинку на холсте в соответствии с текущей сценой m_canvas.Update();
Управление памятью — Каждый DX-объект потребляет видеопамять. При создании динамических сцен (например, обновление поверхности оптимизации) необходимо:
- Очищать старые буферы перед созданием новых;
- Использовать DXResourceRelease() для явного освобождения ресурсов;
- Контролировать количество вершин: для статичных объектов допустимы тысячи полигонов, для анимированных — сотни (конкретные цифры зависят от мощности компьютера).
Диагностика и проверка ошибок — всегда проверяйте возвращаемые значения и используйте GetLastError() для диагностики при возникновении ошибок:
if(!m_canvas.CreateBitmapLabel(...)) { int err = GetLastError(); Print("DX Error code: ", err); //--- типичные ошибки: //--- 1: устройство не поддерживает DX11 //--- 2: нехватка видеопамяти //--- 3: ошибка компиляции шейдера }
Аппаратное ускорение или программный рендеринг:
MT5 автоматически определяет возможности видеокарты. Если DirectX 11 недоступен, графика не отобразится. Проверка требований:
- Видеокарта с поддержкой DX11 и шейдеров версии 5.0;
- Актуальные драйверы (устаревшие версии могут вызывать артефакты);
- Включение аппаратного ускорения в настройках терминала.
Чтобы узнать какая версия DirectX у вас установлена проделайте следующие шаги:
- В поле Поиск на панели инструментов Windows введите «dxdiag». Затем выберите «dxdiag» в списке результатов;
- В средстве диагностики DirectX выберите вкладку Система — версия DirectX должна быть не ниже 11.

Рис.3: Проверка версии DirectX
Примечание:
При первом использовании средства диагностики DirectX может появиться запрос на проверку наличия цифровой подписи драйверов. Рекомендуется выбрать Да , чтобы убедиться, что ваши драйверы подписаны издателем, который подтвердил их подлинность.
Оптимизация потребления ресурсов компьютера для цикла рендеринга:
- OnTimer() или OnChartEvent() — для статичных сцен вызывайте функцию Redraw() только при изменении данных, а не каждый тик;
- Уровень детализации (Level of Detail: LOD) — уменьшайте детализацию объектов при удалении камеры;
- Создание объектов (Instancing) — для множественных одинаковых объектов (кластеры, маркеры) используйте один меш с разными матрицами трансформации.
Базовый конвейер готов. Мы создали холст, настроили проекцию, определили объекты с вершинами и нормалями, применили трансформации и освещение. Следующий шаг — наполнить этот каркас аналитическим содержанием: результаты оптимизации превратить в 3D-поверхности, кластеры ликвидности — в объемные структуры, а сценарные модели — в интерактивные отчеты.
Визуализация сложных данных — Поверхности, кластеры, сценарии
Когда базовый DX-конвейер настроен, перед нами открывается пустое пространство, готовое визуализировать данные. Следующая задача — трансформировать числа из отчета тестера в геометрические примитивы, понятные человеческому глазу. Мы переходим от матриц к визуальным ландшафтам.
Построение 3D-поверхности оптимизации, наверное, самый полезный способ использования 3D в трейдинге. Тестер стратегий выдает таблицу, где строки — это прогоны, а столбцы — параметры и метрики. Визуализация результатов оптимизации в 3D превращает эту таблицу в рельеф.
Простая математика визуализации — оси X и Z становятся параметрами стратегии (например, период скользящей средней и размер стопа), а ось Y (высота) — целевой функцией (например, фактор восстановления, мат.ожидание). Чтобы построить такую поверхность, нам нужно сгенерировать сетку треугольников (Mesh) на основе массива результатов.
Алгоритм построения:
- Сбор данных — проходим по массиву результатов оптимизации, выбираем и структурируем необходимые данные;
- Нормализация — приводим значения параметров к единому масштабу, чтобы график не выглядел сплюснутым;
- Генерация вершин — для каждой точки данных создаем вершину DXVertex;
- Триангуляция — соединяем соседние вершины индексами в треугольники.
//+------------------------------------------------------------------+ //| пример создания поверхности из массива данных | //+------------------------------------------------------------------+ void CreateOptimizationSurface(const double &data[],const int width,const int height) { DXVertex vertices[]; uint indices[]; int v_count = 0; int i_count = 0; //--- выделяем память под вершины (width*height точек) ArrayResize(vertices,width*height); for(int y=0;y<height;y++) { for(int x=0;x<width;x++) { int idx=y*width+x; //--- X и Z — координаты параметров, Y — значение метрики (прибыль) vertices[idx].position=DXVector3(x, data[idx], y); vertices[idx].normal=DXVector3(0, 1, 0); // упрощенная нормаль vertices[idx].vcolor=ColorToVector4(ColorFromValue(data[idx])); // цвет зависит от значения vertices[idx].tcoord=DXVector2((float)x/width, (float)y/height); } } //--- далее формируем массив индексов для треугольников и создаем объект через m_mesh.Create(...) }
На такой поверхности сразу видны «плато» — широкие зоны, где стратегия работает относительно стабильно при изменении параметров. И наоборот — хорошо видны узкие пики прибыли (похожие на иглы), которые означают переоптимизацию (по-английски: overfitting). Визуально отсечь такую «иглу» гораздо проще, чем заметить ее в таблице из 1000 строк, учитывая что в табличном виде многомерные зависимости слабо видны.
Кластерный анализ в пространстве
Рыночные данные включают в себя не только цену и время, но и объем. В 2D мы рисуем гистограмму объема обычно внизу экрана, но в 3D объем становится полноценным измерением. Вместо плоских баров мы можем использовать объемные блоки (воксели) или цилиндры, высота и толщина которых зависят от объема торгов или плотности кластера:
- Ось X — Время;
- Ось Z — Цена;
- Ось Y — Объем / Количество сделок (радиус вокселя).
Визуализация ликвидности — используя DXComputeSphere или кастомные меши, можно нарисовать крупные кластеры сделок как сферы разного размера и прозрачности. Наложенные друг на друга, они создают облако ликвидности, где трейдер видит «пустоты» (зоны, где цена пролетела быстро) и «сгустки» (уровни поддержки/сопротивления).
//--- установка цвета на основе объема (heatmap-эффект) //--- чем больше объем, тем краснее цвет (от синего к красному) color cluster_color=ColorInterpolate(clrBlue,clrRed,volume_ratio); m_cluster.MeshColorSet(ColorToVector4(cluster_color,0.7)); // 0.7 - прозрачность
Генерация поверхностей через DXComputeSurface()
Для типовых задач визуализации двумерных данных (тепловые карты, результаты оптимизации, матрицы корреляций) библиотека DirectX MQL5 предоставляет готовую функцию-шаблон DXComputeSurface(). Функция находится в файле «DXUtils.mqh».
Декларация:
//+------------------------------------------------------------------+ //| 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[])
Назначение:
Автоматически генерирует вершины и индексы для 3D-поверхности на основе двумерного массива данных. Функция избавляет разработчика от ручного расчёта координат, триангуляции сетки и вычисления нормалей.
Входные параметры:
| Параметр | Тип | Описание |
|---|---|---|
| [in] data[] | double& | Одномерный массив значений высоты (данные оптимизации, корреляции и т.д.) |
| [in] data_width | uint | Ширина исходной матрицы данных (количество столбцов) |
| [in] data_height | uint | Высота исходной матрицы данных (количество строк) |
| [in] data_range | double | Диапазон масштабирования значений по оси Z (высота) |
| [in] from | const DXVector3& | Координаты левого нижнего угла поверхности в 3D-пространстве |
| [in] to | const DXVector3& | Координаты правого верхнего угла поверхности в 3D-пространстве |
| [in] texture_size | DXVector2& | Размер текстурных координат (для наложения текстур или градиентов) |
| [in] two_sided | bool | Флаг двусторонней отрисовки (полезно для прозрачных поверхностей) |
| [in] use_normals | bool | Флаг расчёта нормалей для корректного освещения |
| [out] vertices[] | TVertex& | Выходной массив вершин (заполняется функцией) |
| [out] indices[] | uint& | Выходной массив индексов для триангуляции (заполняется функцией) |
Требования к типу TVertex — шаблонный параметр TVertex должен быть структурой, содержащей как минимум три поля:
struct MyVertex { DXVector4 position; // координаты вершины (x,y,z,w) DXVector4 normal; // вектор нормали (nx,ny,nz,0) DXVector2 tcoord; // текстурные координаты (u,v) // дополнительные поля по необходимости: цвет, бинормаль и т.д. };
Возвращаемое значение:
- true — поверхность успешно сгенерирована;
- false — ошибка (проверьте размеры массивов и валидность входных данных).
Пример использования:
Допустим, у нас есть результаты оптимизации стратегии в виде матрицы 20×20, где каждое значение — это математическое ожидание сделки. Мы хотим визуализировать эти данные как 3D-поверхность.
//+------------------------------------------------------------------+ //| Генерация поверхности оптимизации через DXComputeSurface | //+------------------------------------------------------------------+ void BuildOptimizationSurface(double &optimization_data[],uint width,uint height) { //--- определяем тип вершины с дополнительным полем цвета struct SVertex { DXVector4 position; DXVector4 normal; DXVector2 tcoord; DXColor vcolor; // цвет вершины для градиента }; SVertex vertices[]; uint indices[]; //--- параметры поверхности DXVector3 from(-10.0,-5.0,0.0); // левый нижний угол DXVector3 to(10.0,5.0,1.0); // правый верхний угол DXVector2 texture_size(1.0,1.0); // полный охват текстурных координат double data_range=2.0; // масштабирование высоты //--- генерируем геометрию if(!DXComputeSurface(optimization_data,width,height,data_range, from,to,texture_size, false,true, // односторонняя, с нормалями vertices,indices)) { Print("ошибка генерации поверхности: ",GetLastError()); return; } //--- раскрашиваем вершины по высоте (градиент: красный→зелёный) 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); } //--- создаём меш и добавляем в сцену if(!mesh.Create(canvas.DXDispatcher(),canvas.InputScene(),vertices,indices)) Print("ошибка создания меша: ",GetLastError()); mesh.DiffuseColorSet(DXColor(1.0f,1.0f,1.0f,1.0f)); canvas.ObjectAdd(&mesh); }
Преимущества DXComputeSurface():
- Скорость разработки — не нужно писать циклы триангуляции и расчёта нормалей вручную;
- Оптимизация — внутренняя реализация использует эффективные алгоритмы построения сетки;
- Гибкость — шаблонный тип вершины позволяет добавлять любые дополнительные атрибуты (цвет, текстуру, пользовательские данные).
Ограничения DXComputeSurface():
- Только регулярные сетки — функция предполагает, что данные представляют собой прямоугольную матрицу. Для нерегулярных облаков точек или произвольной топологии потребуется ручная генерация;
- Интерполяция по умолчанию — высота вершин интерполируется линейно между узлами сетки. Для сглаживания ступенчатых поверхностей может потребоваться предварительная фильтрация данных;
- Память — функция выделяет массивы вершин и индексов динамически. При работе с большими матрицами (например, 100×100 и более) следите за потреблением памяти и частотой перестроения поверхности.
Интеграция с интерактивным управлением:
Поскольку DXComputeSurface() генерирует статическую геометрию, для динамического обновления (например, при изменении параметров оптимизации в реальном времени) необходимо:
- Сохранить ссылку на объект CDXMesh,
- При изменении данных вызвать mesh.Shutdown() для освобождения старых буферов,
- Повторно вызвать DXComputeSurface() и mesh.Create() с новыми данными,
- Вызвать RedrawScene() для отображения изменений.
Для плавной анимации рекомендуется выносить тяжёлые операции в обработчик OnTimer, как это сделано в эксперте DX_OptimizationSurface (см. описание ниже). Использование DXComputeSurface() во многих типовых случаях сокращает объём кода на 30–40% при построении типовых поверхностей, позволяя сосредоточиться на аналитической логике, а не на низкоуровневой графике.
Сценарное моделирование и интерактивные отчеты
Одно из преимуществ DirectX в MQL5 — возможность динамического обновления сцены без перезагрузки индикатора. Это открывает путь к моделированию сценариев вида: «Что если?». Например панель, где вы двигаете ползунок с надписью «Волатильность» или «Комиссия». В реальном времени пересчитывается массив data[], и функция обновления вершинного буфера VertexSet() динамически изменяет 3D-поверхность.
//+------------------------------------------------------------------+ //| пример динамического обновления | //+------------------------------------------------------------------+ void OnSliderChange(const double new_vol) { //--- пересчитываем метрики стратегии с новой волатильностью RecalculateStrategyMetrics(new_vol); //--- обновляем только Y-координату вершин (высоту), не пересоздавая меш for(int i=0;i<ArraySize(m_vertices);i++) { m_vertices[i].position.y=m_new_metrics[i]; //--- пересчитываем нормали для корректного освещения m_vertices[i].normal=CalculateNormal(i); } //--- отправляем обновленные данные в видеопамять m_mesh.VertexSet(m_vertices); Redraw(); }
Это позволяет трейдеру видеть устойчивость стратегии — если небольшое изменение волатильности превращают прибыльный график в убыточный, стратегия вряд ли жизнеспособна на дистанции.
Шейдеры как аналитический фильтр
Стандартные шейдеры MT5 отвечают за освещение (модель Фонга). Но для аналитики нам нужны шейдеры, которые работают с данными. Мы можем написать простой пиксельный шейдер (Pixel Shader), который будет выполнять роль фильтра.
Например, нужно подсветить на 3D-графике только те зоны, где просадка превышает 20%, или где профит фактор меньше единицы:
//+------------------------------------------------------------------+ //| пример логики в HLSL шейдере | //+------------------------------------------------------------------+ float4 PS_Main(PS_INPUT input) : SV_TARGET { //--- input.color содержит информацию о метрике, закодированную в вершине float profit=input.color.r; //--- если прибыль ниже порога, делаем объект полупрозрачным if(profit<threshold) return float4(0.5,0.5,0.5,0.2); // серый и прозрачный else return float4(0.0,1.0,0.0,1.0); // ярко-зеленый }
В шейдере мы проверяем значение атрибута вершины (например, высоту или переданный цвет) и, если оно не соответствует критерию, делаем пиксель прозрачным или серым. Такой подход позволяет убрать «шум» на графике, оставив только значимые области. Это важно при анализе больших массивов данных оптимизации.
Интерактивность — мышь, кнопки и управление камерой
Статичная 3D-картинка красива, но в трейдинге она мало полезна, если ее нельзя покрутить, приблизить и отфильтровать. Настоящая польза DirectX в MQL5 раскрывается, когда мы получаем возможность активно исследовать данные. Разберем, как оживить сцену, связав события мыши и клавиатуры с математикой камеры.
Обработка событий в MQL5 — оживление холста
По умолчанию, холст (CDXCanvas) — это просто растровое изображение, которое не реагирует на курсор. Чтобы заставить его взаимодействовать с пользователем, нужно подписаться на события графика. Это делается через модификаторы CHART_EVENT_MOUSE_... в функции OnInit():
//+------------------------------------------------------------------+ //| подписка на события от мыши | //+------------------------------------------------------------------+ int OnInit() { //--- включаем получение событий мыши ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,1); ChartSetInteger(0,CHART_EVENT_MOUSE_WHEEL,1); //--- таймер для анимации EventSetMillisecondTimer(16); return(INIT_SUCCEEDED); }
После этого все движения курсора будут попадать в обработчик OnChartEvent(). Следующая задача — отфильтровать нужные идентификаторы (CHARTEVENT_MOUSE_MOVE, CHARTEVENT_MOUSE_WHEEL) и передать координаты в часть кода для рендеринга.
Замечание:
В OnDeinit() обязательно отключайте эти события (вызовом ChartSetInteger(..., 0)), иначе после удаления индикатора терминал продолжит их генерировать и создавать лишнюю нагрузку.
Управление камерой — орбита и зум
Самый часто используемый способ взаимодействия с 3D-графиком — вращение вокруг объекта (орбита) и приближение/удаление (зум). В DirectX это реализуется не вращением самого объекта, а перемещением камеры по сфере вокруг центра сцены.
Для управления камерой в CCanvas3D используются три взаимосвязанных метода:
- ViewPositionSet() — задаем где находится глаз наблюдателя (координаты камеры);
- ViewTargetSet() — задаем куда смотрит наблюдатель (обычно центр сцены 0,0,0);
- ViewUpDirectionSet() — задаем куда направлен верх кадра (чтобы камера не переворачивалась).
Реализация вращения
Вращение выполняется при перемещении курсора мыши с зажатой ее левой кнопкой. Чтобы вращать сцену, мы отслеживаем дельту перемещения курсора: разницу между текущей и предыдущей позицией. Эту дельту мы конвертируем в углы поворота вокруг осей X и Y.
//+------------------------------------------------------------------+ //| обработчик событий движения мыши | //+------------------------------------------------------------------+ void OnMouseMove(int x, int y, uint flags) { //--- проверяем, что левая кнопка мыши нажата if((flags&1)==1) { //--- вычисляем изменение углов на основе смещения мыши //--- делим на коэффициент (например, 300.0f) для чувствительности m_camera_angles.y+=(x-m_mouse_x)/300.0f; m_camera_angles.x+=(y-m_mouse_y)/300.0f; //--- ограничиваем вертикальный угол 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; //--- пересчитываем позицию камеры UpdateCameraPosition(); Redraw(); } //--- сохраняем текущие координаты для следующего шага m_mouse_x=x; m_mouse_y=y; }
В функции UpdateCameraPosition() мы используем матрицы вращения DXMatrixRotationX и DXMatrixRotationY, чтобы повернуть вектор направления камеры и обновить ее позицию в пространстве.
Реализация зума
Вращение колесика мыши меняет дистанцию от камеры до центра сцены (m_camera_distance).
//+------------------------------------------------------------------+ //| обработчик событий вращения колеса мыши| //+------------------------------------------------------------------+ void OnMouseWheel(double delta) { //--- уменьшаем или увеличиваем дистанцию m_camera_distance*=1.0-delta*0.001; //--- ограничиваем зум разумными значениями if(m_camera_distance>50.0) m_camera_distance=50.0; if(m_camera_distance<3.0) m_camera_distance=3.0; UpdateCameraPosition(); Redraw(); }
UI-панель поверх 3D-сцены
3D-графика отвечает за отображение данных, но для управления параметрами нам нужны стандартные и привычные элементы интерфейса MQL5. Чтобы не изобретать велосипед, используйте классы стандартной библиотеки контролов MQL5 (CAppDialog, CSlider, CComboBox и т.д.), которые рисуются поверх или сбоку графического холста. Также можно использовать любые другие классы для построения интерфейса.
При изменении значения слайдера (например, «Порог прибыли») вызывается функция, которая обновляет данные в вершинном буфере или меняет переменные шейдера, после чего вызывается функция Redraw(). Это позволяет создать полноценный аналитический инструмент. Например: слева — интерактивный 3D-ландшафт отображающий результаты оптимизации, справа — панель управления с фильтрами.
Оптимизация интерактивного цикла
Интерактивность не должна сильно снижать производительность терминала и компьютера в целом. Если вы будете вызывать функцию Redraw() при каждом микродвижении мыши без зажатой кнопки, интерфейс терминала начнет тормозить.
Сформулируем основные правила оптимизации интерактивности:
- Вызов Redraw() только по необходимости — вызывайте перерисовку сцены только внутри блоков проверки вида: if((flags & 1) == 1) (проверка когда кнопка зажата) или при изменении параметров UI;
- Отсев лишних событий — если данные для перерисовки приходят слишком часто (например, от тиков в обработчике OnTick()), обновляйте буфер вершин не чаще 10-15 раз в секунду;
- Асинхронность тяжелых расчетов — если изменение параметра требует пересчета тысяч вершин (например, перестройка всей поверхности оптимизации), делайте это в обработчике событий таймера OnTimer() или выносите в отдельный поток через DLL, чтобы не замораживать интерфейс.
Тестовый эксперт для проверки 3D-технологий
Разработаем эксперт, реализующий описанные 3D-технологии. Эксперт представляет собой инструмент для трехмерной визуализации аналитических данных в торговом терминале MetaTrader 5. Основное назначение — преобразование числовых результатов оптимизации торговых стратегий в трехмерные поверхности, позволяющие трейдеру и/или разработчику быстро оценивать качество и устойчивость стратегии.
Эксперт решает следующие задачи:
- Визуализация поверхности оптимизации — отображение зависимости целевой функции (прибыли, математического ожидания, коэффициента Шарпа) от двух оптимизируемых параметров стратегии в виде трехмерного ландшафта.
- Анализ устойчивости стратегии — выявление «плато стабильности» (областей с плавным изменением результатов) и «игл переоптимизации» (изолированных пиков, указывающих на подгонку под исторические данные).
- Интерактивное исследование данных — предоставление возможности вращения, масштабирования и детального изучения поверхности с помощью мыши.
- Сравнительный анализ режимов — переключение между различными режимами отображения (например, «прибыль» и «шум») для оценки качества оптимизации.
Функциональные возможности:
Трехмерная визуализация — эксперт создает на графике интерактивный 3D-холст размером 640×480 пикселей, на котором отображается поверхность, сгенерированная на основе аналитической функции. Поверхность представляет собой сетку 25×25 вершин, триангулированную для корректного отображения.
Цветовое кодирование — применена следующая цветовая схема:
- Вершина (максимальные значения) — насыщенный зеленый цвет;
- Основание (минимальные значения) — насыщенный красный цвет;
- Промежуточные значения — плавный градиент с переходом через желто-оранжевые оттенки.
Такое кодирование позволяет уверенно идентифицировать зоны максимальной прибыли (зеленые «холмы») и зоны убытков (красные «впадины»).
Управление камерой — реализовано полное управление точкой обзора:
- Вращение — зажатие левой кнопки мыши и перемещение курсора вращает камеру вокруг центра сцены по сферической орбите;
- Масштабирование — прокрутка колесика мыши приближает или отдаляет камеру (дистанция от 5.0 до 40.0 единиц);
- Ограничения — вертикальный угол ограничен диапазоном ±0.9×π/2 для предотвращения переворота камеры.
Интерактивное управление
На холсте размещена кнопка переключения режимов:
- Режим «Прибыль» — отображает гладкую поверхность гауссовой кривой (имитация устойчивой стратегии);
- Режим «Шум» — отображает поверхность с добавленным случайным шумом (имитация переоптимизированной стратегии).
При переключении режима текст кнопки автоматически обновляется.
Освещение и материалы
Для создания реалистичного объемного изображения применена модель освещения Фонга с тремя компонентами:
- Направленный источник света — желтый цвет (1.0, 0.95, 0.8), направление (0.5, -0.8, 0.3);
- Окружающее освещение — серый цвет (0.55, 0.55, 0.55) с повышенной интенсивностью для лучшей видимости теневых зон;
- Диффузный материал — белый цвет (1.0, 1.0, 1.0, 1.0) для корректного смешивания с вершинными цветами.
Особенности реализации
Асинхронная обработка событий:
- Реакция на перемещения курсора мыши и вращение колеса — программа получает вызов функции OnChartEvent() и сразу обрабатывает его (меняется ориентация 3D-модели, ее размеры и т.п.). При этом не происходит сложных вычислений.
- Реакция на нажатие кнопки переключения режима — программа получает вызов функции OnChartEvent() и устанавливает флаг need_rebuild. Функция BuildSurface(), ответственная за уничтожение старого меша, генерацию новой 3D-поверхности и рендеринг, вызывается внутри функции-обработчика OnTimer(), которая каждые 50мс проверяет состояние флага need_rebuild.
Такой подход гарантирует, что даже если пересчет 3D-модели займет ресурсы процессора, чарт терминала и элементы управления останутся полностью отзывчивыми.
Для корректного расчета освещения и ориентации камеры использована библиотека в «MQL5\Include\Canvas\DX\DXMath.mqh»:
- Нормали — для каждой вершины поверхности вычисляется вектор нормали через векторное произведение функцией DXVec3Cross(). Это нужно для того, чтобы поверхность была объемной и реагировала на источник света, создавая реалистичные тени и блики.
- Камера — позиция наблюдателя рассчитывается через сферические координаты, что позволяет реализовать интуитивное вращение вокруг объекта («орбиту») без эффекта переворота камеры, ограничивая вертикальный угол.
Полный код эксперта содержится в файле «DX_OptimizationSurface.mq5», приложенном к статье.
Примеры работы эксперта в разных режимах представлены на рисунках ниже:

Рис.4: Режим «Прибыль»

Рис.5: Режим «Шум»
Теперь у нас есть полный набор инструментов: мы умеем строить сцену, наполнять ее данными оптимизации и давать пользователю возможность исследовать эти данные вращением и зумом. Но прежде чем бежать внедрять 3D везде где только можно придумать, давайте сначала посмотрим, где эта технология излишня и лучше остановиться на обычных графиках.
Когда лучше остановиться на обычных графиках
Инструмент полезен только тогда, когда он решает задачу быстрее и точнее, чем его предшественник. Мы разобрали архитектуру DX-конвейера, научились генерировать поверхности и управлять камерой. Однако в трейдинге надо различать полезную аналитическую визуализацию и хаос визуального шума. Интеграция 3D-графики в MetaTrader 5 — это не самоцель, а способ решения проблем. Рассмотрим случаи, когда отказ от 3D в пользу классических 2D будет технически и экономически оправдан.
Правило размерности данных
Сформулируем правило необходимости 3D-визуализации — третье измерение должно нести уникальную информацию:
- 3D бесполезно — если вы пытаетесь отобразить временной ряд (Цена/Время) в 3D-пространстве. Добавление оси Z, которая дублирует цену или время, лишь усложнит восприятие, заставив трейдера вращать сцену, чтобы увидеть обычную линию тренда.
- 3D необходимо — при анализе результатов оптимизации. Здесь у нас есть два независимых входных параметра (например, период мувинга и размер стопа) и одна выходная метрика (прибыль или профит фактор). Без 3D-поверхности мы увидим лишь набор точек. 3D позволяет увидеть взаимосвязь между двумя переменными и результатом.
Если ваш набор данных сводится к паре координат, стандартный 2D-график (DRAW_LINE, DRAW_HISTOGRAM) будет эффективнее.
Аппаратные ограничения и VPS
3D-графика в MQL5 базируется на DirectX 11. Это требует поддержки шейдеров версии 5.0 и определенного уровня производительности CPU/GPU.
Большинство профессиональных разработчиков запускают своих экспертов на виртуальных серверах (VPS). Многие стандартные конфигурации VPS не имеют мощных видеокарт или аппаратного ускорения DirectX. В таких средах вызов CreateBitmapLabel() может привести к ошибке и/или падению эксперта.
Поэтому, если ваша программа предназначена для работы в «слепом», то есть без графики, режиме или на дешевом сервере, 3D-модуль нужно отключать или заменять на логирование в файл/базу данных. 2D-графика легко отрисуется процессором даже без видеокарты.
Скорость восприятия — 3D-поверхность против Тепловой карты
Одной из главных альтернатив 3D-поверхности является двумерная тепловая карта (HeatMap). Принципиальные различия между ними в следующем:
- 3D — показывает высоту (Z) как физическое возвышение. Требует вращения для точного анализа всех сторон и скрытых склонов.
- HeatMap — показывает значение (Z) как цвет ячейки на плоскости (X, Y).
Если задача стоит в том, чтобы быстро найти максимум оптимизации (самую зеленую зону), HeatMap в стандартном индикаторе отработает быстрее и потребует меньше кода.
Интерактивность против Мониторинга
Интерактивные 3D-сцены (как наш эксперт DX_OptimizationSurface) требуют активного участия человека. Вы должны навести мышь, зажать кнопку, повернуть.
Если цель графика — мониторинг (фоновое отслеживание ситуации), то интерактивная 3D-графика может отвлекать и тормозить процесс.
Если цель — презентация или глубокий анализ перед запуском стратегии, то 3D незаменима.
Вывод:
Используйте 3D только тогда, когда объем данных или их структура делают невозможным анализ в 2D. Если ваша задача — быстро найти максимум в таблице оптимизации, тепловая карта справится с этим лучше. 3D нужно там, где нужно увидеть форму зависимости, а не просто значение.
В остальных случаях стандартные классы MQL5 (CCanvas для 2D или графические объекты) будут более простым решением.
Заключение
Мы прошли путь от теоретического обоснования необходимости объемной графики до создания полноценного интерактивного эксперта. Разработанный советник DX_OptimizationSurface демонстрирует, что MetaTrader 5 — это не просто терминал для исполнения ордеров, а мощная платформа для визуального анализа данных.
Основные выводы:
- Когнитивная эффективность — 3D-визуализация позволяет превратить бесконечные массивы чисел в визуальные ландшафты. Это снижает когнитивную нагрузку на трейдера, позволяя визуально отличать устойчивые плато прибыли от опасных игл переоптимизации.
- Технологическая доступность — встроенная поддержка DirectX 11 и нативные классы CCanvas3D и CDXMesh дают разработчикам инструменты для решения задач трейдинга. Не нужно писать на C++ или подключать внешние библиотеки — все уже внутри есть MQL5. Остается только воспользоваться.
- Важность архитектуры — как мы увидели на примере нашего эксперта, интеграция графики требует внимательного отношения к жизненному циклу ресурсов и асинхронности. Вынесение вычислительных операций в таймер и корректная очистка памяти — это залог того, что не будет проблем с производительностью терминала.
Визуализация — это линза, а не украшение. Она должна отвечать на конкретный аналитический вопрос.
Мы создали этот инструмент не ради внешнего эффекта, а ради ускорения принятия решений. Если 3D-графика помогает вам быстрее понять поведение стратегии и отфильтровать нежизнеспособные варианты, значит, она выполнила свою задачу. Если же она лишь отвлекает — смело возвращайтесь к проверенным 2D-методам. Инструмент ценен не тем, как он выглядит, а тем, какие решения он ускоряет.
Дальнейшие шаги — для тех, кто хочет углубиться в тему, рекомендуем следующие направления:
- Изучение библиотеки DXMath для работы с кватернионами и сложными трансформациями.
- Написание собственных шейдеров (HLSL) для создания уникальных эффектов рендеринга.
- Интеграция с Python через MT5 для предварительной обработки данных перед их визуализацией в терминале.
MetaTrader 5 предоставляет технологический фундамент. То, какие аналитические инструменты вы на нем построите, зависит только от вашей фантазии и потребности в поисках «зерен жемчуга» в бесконечных рыночных данных.
Рекомендуемые материалы для изучения работы с DirectX в MetaTrader 5:
- Справка MetaEditor по DirectX,
- Статья Как создать 3D-графику на DirectX в MetaTrader 5,
- Статья Уроки по DirectX (Часть I): Рисуем первый треугольник,
- Статья Визуализируй стратегию в тестере MetaTrader 5.
Список файлов, приложенных к статье:
| Название файла | Описание |
|---|---|
| DX_OptimizationSurface.mq5 | Файл, содержащий код тестового эксперта с интерактивной 3D-визуализацией |
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Архитектура машинного обучения для MetaTrader 5 (Часть 11): Критерий Келли, интеграция правил проп-фирмы и динамический бэктест по CPCV
Нейросети в трейдинге: Принятие торговых решений с учётом неопределенности (UncAD)
Архитектура машинного обучения для MetaTrader 5 (Часть 10): Определение размера позиции в финансовом машинном обучении
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования