Тепловая карта оптимизации
OptimizationHeatmapWidget рисует одну метрику по двум параметрам: значения первого параметра идут по горизонтали, второго — по вертикали, на пересечении лежит ячейка, окрашенная тем, что этот набор параметров показал. Про саму оптимизацию контрол ничего не знает — карта метрики по двум осям одинакова, чем бы пары ни были посчитаны, — поэтому пары передаёт хост вместе с названиями осей и метрики.

Создание и обновление
import {
HeatDirections,
OptimizationHeatmapWidget,
type HeatCell,
type TradingHost,
} from '@stocksharp/trading-controls';
declare const host: TradingHost;
const heatmap = OptimizationHeatmapWidget.create(
document.querySelector<HTMLElement>('#heatmap')!,
{},
{ host },
);
const cells: HeatCell[] = [
{ x: '10', y: '00:05:00', value: 12_400 },
{ x: '10', y: '00:15:00', value: 9_150 },
{ x: '20', y: '00:05:00', value: -1_800 },
{ x: '20', y: '00:15:00', value: 15_900 },
];
heatmap.update({
xLabel: 'Length',
yLabel: 'Timeframe',
metricLabel: 'Net profit',
betterWhen: HeatDirections.Higher,
cells,
});
Единственная зависимость — host; интерфейс OptimizationHeatmapDeps других полей не содержит. Обработчиков карта не принимает: ячейка — это среднее по прогонам одной пары, а не прогон, поэтому открывать по щелчку нечего. Второй аргумент create — сохранённое состояние экземпляра; контрол его не читает и ничего в него не пишет.
update заменяет карту целиком: пара, выбывшая из набора, перестаёт существовать, и оставленная от неё ячейка сообщала бы о прогоне, которого в отчёте больше нет.
Аргумент update — объект HeatmapData с полями:
| Поле | Назначение |
|---|---|
xLabel |
Название горизонтальной оси, подписывается под картой. |
yLabel |
Название вертикальной оси, подписывается над картой. |
metricLabel |
Название метрики, выводится в заголовке панели. |
betterWhen |
Куда лучше: HeatDirections.Higher ('higher') или HeatDirections.Lower ('lower'). Поле обязательное — без него карта просадок выкрасила бы худший угол в цвет победы. |
cells |
Измерения HeatCell: x и y — значения осей строками, value — число. |
Тип HeatmapData объявлен в модуле контрола, а корневой экспорт пакета его не переэкспортирует: при явной типизации импортируйте его из подпути @stocksharp/trading-controls/optimization-heatmap-widget.
Статическое свойство OptimizationHeatmapWidget.TYPE равно ControlTypes.OptimizationHeatmap — идентификатору optimizationHeatmap.
Данные и отображение
Оси дискретны, поэтому их значения передаются строками: 10, 00:05:00 и True — равноправные позиции на оси. Порядок значений числовой, если каждое из них — число (иначе 10 встало бы перед 2 и форма карты стала бы следствием записи чисел), и текстовый в остальных случаях; для строк фиксированной ширины, какими .NET пишет интервалы времени, текстовый порядок совпадает с хронологическим. Первая строка сетки лежит у основания карты: это график, и ось Y растёт вверх.
Несколько прогонов на одной паре сворачиваются в одну ячейку — среднее с числом прогонов; запись с нечисловой метрикой отбрасывается, а не портит всю ячейку. Цвет считается от опорного значения: если измерения пересекают ноль, опорным становится ноль, иначе — середина диапазона, потому что привязка к нулю, до которого перебор не дошёл, дала бы одно ровное пятно без контраста. Размах до полного цвета одинаков по обе стороны, поэтому одинаковая насыщенность всюду означает одинаковое отклонение метрики. Направление betterWhen учтено в знаке: лучший результат всегда красится цветом роста.
Числа в ячейках не печатаются: при переборе сорок на сорок цифры в ячейке нечитаемы, а чтение цвета и есть смысл карты. Пара, которую никто не прогонял, не остаётся пустой, а перечёркивается диагональю: непроверенная пара и пара с нулевым результатом — разные факты, которые шкала с нулём в нейтральной точке нарисовала бы одинаково. Лучшая ячейка обводится рамкой цветом сетки — единственным ненаправленным цветом палитры.
Над картой рисуется ключ из тех же двух цветов с тремя подписями: нижний край, опорное значение и верхний край. Подписи осей прореживаются, если значения перестают помещаться, но крайнее значение оси подписывается всегда. Числа выводятся через formatStatistic — тот же формат, что и в панели статистики: округление до двух знаков.
При наведении на измеренную ячейку появляется подсказка со значением обеих осей и метрики. Число прогонов добавляется в неё только когда усреднялось больше одного прогона, а отметка Best — только у лучшей ячейки. Над перечёркнутой ячейкой подсказки нет: она уже видна как непроверенная. Подсказка прижимается к границам холста, чтобы не уехать за край у крайних ячеек.
Пока измерений нет ни одного, вместо карты показывается заглушка с текстом по ключу NoOptimizationResults.
Что делает контрол и что остаётся хосту
Контрол сам строит разметку панели, подгоняет холст под контейнер через ResizeObserver и заводит буфер в физических пикселях по devicePixelRatio, иначе карта рисовалась бы с сеткой волосяных линий. Цвета и шрифт он запрашивает у host.presentation.canvasPalette() при каждой отрисовке: up и down — две стороны шкалы, grid — сетка, перечёркивания, рамка лучшей ячейки и подписи, font — шрифт текста на холсте. Собственной палитры пакет здесь не выбирает, поэтому смена темы у хоста перерисовывает карту в новых цветах. Прозрачность — единственное, чем распоряжается сама карта.
Кнопка закрытия панели вызывает host.close(), экземпляр регистрируется через host.register и снимается с регистрации в dispose. Весь видимый текст запрашивается через host.t: OptimizationHeatmap, OptimizationHeatmapChart, ClosePanel, NoOptimizationResults, Runs, Best. Собственных настроек в host.preferences контрол не хранит, ключей у него нет.
Хост подаёт данные: перебор карта не запускает, метрику не выбирает и не считает, направление «лучше» не угадывает — что передано в update, то и нарисовано.
Публичные методы
update(data)— показать карту целиком.dispose()— отключить наблюдатель размера, вызватьhost.unregisterи убрать корневой элемент.
Вспомогательные функции
Вся геометрия карты вынесена в отдельный модуль и экспортируется пакетом — её можно использовать без контрола:
layoutHeatmap(input)— разметка карты: сетка, пропуски, подписи, ключ и шкала;null, если измерений нет.hitHeatmap(layout, x, y)— ячейка под точкой илиnull.heatScale(buckets)— опорное значение, размах и границы диапазона.tintOf(value, scale, betterWhen)— насыщенность от −1 до 1, где положительное всегда лучше.valueAt(tint, scale, betterWhen)— обратное преобразование, для подписей ключа.HeatDirections— направленияHigherиLower.