最適化ヒートマップ
OptimizationHeatmapWidget は、1 つの指標を 2 つのパラメーターに沿って描画します。1 つ目のパラメーターの値が横方向、2 つ目が縦方向に並び、その交点にはそのパラメーターの組み合わせが示した結果で着色されたセルが置かれます。コントロール自体は最適化について何も知りません。2 軸に沿った指標のマップは、その組み合わせがどのように計算されたものであっても同じだからです。そのため、組み合わせは軸と指標の名前とともにホストが渡します。

作成と更新
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 インターフェイスに他のフィールドはありません。マップはハンドラーを受け取りません。セルは 1 つの組み合わせに対する実行結果の平均であって実行そのものではないため、クリックして開くものが何もないからです。create の第 2 引数はインスタンスの保存状態ですが、コントロールはこれを読み取らず、書き込みもしません。
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 が時間間隔を書き出すときのような固定幅の文字列であれば、テキスト順は時系列順と一致します。グリッドの 1 行目はマップの下端にあります。これはグラフであり、Y 軸は上に向かって伸びるからです。
同じ組み合わせに対する複数の実行結果は 1 つのセルにまとめられ、実行回数を伴う平均になります。指標が数値でないレコードは破棄され、セル全体を台無しにすることはありません。色は基準値から計算されます。測定値がゼロをまたぐ場合は基準値がゼロになり、そうでなければ範囲の中央になります。探索が到達していないゼロを基準にすると、コントラストのない一様な面になってしまうからです。フルカラーまでの振れ幅は左右で同じなので、同じ濃さはどこでも指標の同じ偏差を意味します。betterWhen の方向は符号に反映されており、最良の結果は常に上昇側の色で塗られます。
セルに数値は印字されません。40 × 40 の探索ではセル内の数字は読めませんし、色を読むことこそがマップの目的だからです。誰も実行していない組み合わせは空白のままにはならず、斜線で消されます。未検証の組み合わせと結果がゼロの組み合わせは別の事実であり、ゼロを中立点とするスケールでは同じように描かれてしまうからです。最良のセルはグリッド色の枠で囲まれます。これはパレットの中で唯一、方向を持たない色です。
マップの上には、同じ 2 色からなるキーが、下端、基準値、上端の 3 つのラベルとともに描かれます。軸のラベルは、値が入りきらなくなると間引かれますが、軸の両端の値には必ずラベルが付きます。数値は formatStatistic で出力されます。統計パネルと同じ書式、つまり小数第 2 位への丸めです。
測定済みのセルにカーソルを合わせると、両軸の値と指標を示すツールチップが表示されます。実行回数がツールチップに加わるのは、2 回以上の実行を平均した場合だけで、Best の印が付くのは最良のセルだけです。斜線で消されたセルの上にツールチップは出ません。未検証であることはすでに見て取れるからです。ツールチップはキャンバスの境界に沿って配置され、端のセルでも外へはみ出しません。
測定値が 1 つもない間は、マップの代わりに 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。