Улыбка волатильности
OptionSmileWidget рисует улыбку волатильности одной серии опционов: подразумеваемая волатильность коллов и путов по страйкам, две линии на одной шкале. График строит движок из пакета @stocksharp/chart, объявленного как peer-зависимость.

Создание и обновление
import {
OptionSmileWidget,
type OptionStrike,
type TradingHost,
} from '@stocksharp/trading-controls';
declare const host: TradingHost;
const smile = OptionSmileWidget.create(
document.querySelector<HTMLElement>('#smile')!,
{},
{ host },
);
const chain: OptionStrike[] = [
{ strike: 67_000, call: { ivLast: 0.52 }, put: { ivBid: 0.55, ivAsk: 0.57 } },
{ strike: 67_500, call: { ivLast: 0.48 }, put: { ivLast: 0.50 } },
{ strike: 68_000, call: { ivBid: 0.45, ivAsk: 0.47 }, put: { ivLast: 0.47 } },
{ strike: 69_000, call: { ivLast: 0.49 }, put: {} },
];
smile.update(chain, { assetPrice: 68_120 });
Единственная зависимость — host; интерфейс OptionSmileDeps других полей не содержит. Второй аргумент create — сохранённое состояние экземпляра, улыбка его не читает и ничего в него не пишет.
update заменяет всю цепочку целиком. Второй параметр context необязателен и по умолчанию равен пустому объекту; он передаётся тем же типом OptionChainContext, что и у доски опционов, но улыбке из него нужна только цена базового актива assetPrice.
Статическое свойство OptionSmileWidget.TYPE равно ControlTypes.OptionSmile — идентификатору optionSmile.
Данные и отображение
Страйки сортируются по возрастанию, записи с нечисловым strike отбрасываются. Волатильность стороны берётся из ivLast, а если сделок не было — как среднее ivBid и ivAsk; учитываются только конечные положительные значения. Если ни одного из них нет, точка не рисуется: страйк остаётся на оси, а линия разрывается — так виден страйк, котируемый лишь одной стороной. На график значения выводятся в процентах.
Ось страйков работает в режиме ordinal: шаги равномерны по перечню листинга, а не по расстоянию между числами, поэтому пропуск между 67_500 и 68_000 не превращается в дыру. Подписи оси и метку перекрестья формирует один и тот же форматтер цены.
Цена базового актива не рисуется линией — на ординальной оси для неё нет ступени, — а выводится текстом в легенде рядом с ключами Call и Put. При наведении над графиком появляется строка со страйком и значениями обеих сторон в нём: улыбка читается по расстоянию между кривыми, поэтому показываются обе.
Пока ни один страйк не прокотирован, вместо графика отображается заглушка с текстом по ключу NoOptions.
Что делает контрол и что остаётся хосту
Контрол сам создаёт график при первых данных, берёт цвета, шрифт и цвет сетки из host.presentation.canvasPalette() (up — колл, down — пут), следит за размером контейнера через ResizeObserver и подгоняет холст, обрабатывает кнопку сброса масштаба и кнопку закрытия панели, которая вызывает host.close(). Весь видимый текст запрашивается через host.t: OptionSmile, ResetView, ClosePanel, ImpliedVolatility, Call, Put, OptionChain, NoOptions, Underlying.
Хост подаёт данные: подписок на рынок улыбка не оформляет, волатильность не вычисляет и одну серию от другой не отличает — что передано в update, то и нарисовано. Собственных настроек в host.preferences контрол не хранит, ключей у него нет.
Публичные методы
update(strikes, context)— показать цепочку и контекст, в котором она снята.resetZoom()— вернуть обзор всей цепочки после масштабирования.chart()— вернуть объект графика (IChartApi) илиnull, если график ещё не создан; нужен хосту, который добавляет на тот же холст вторую серию или маркер.dispose()— отключить наблюдатель размера, удалить график, вызватьhost.unregisterи убрать корневой элемент.
Вспомогательные функции
Пакет экспортирует и функции, на которых построена отрисовка, — их можно использовать отдельно:
sideVolatility(side)— волатильность стороны илиnull, если она неизвестна.sortedChain(strikes)— цепочка в порядке отрисовки: по возрастанию страйка, без некорректных записей.toSmileSeries(chain, put)— одна сторона в виде набора точек для графика.