@stocksharp/trading-controls 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +113 -5
  2. package/dist/esm/chart-engine.js +15 -0
  3. package/dist/esm/chart-engine.js.map +1 -0
  4. package/dist/esm/control-types.js +4 -0
  5. package/dist/esm/control-types.js.map +1 -1
  6. package/dist/esm/equity-widget.js +261 -0
  7. package/dist/esm/equity-widget.js.map +1 -0
  8. package/dist/esm/heatmap-grid.js +271 -0
  9. package/dist/esm/heatmap-grid.js.map +1 -0
  10. package/dist/esm/index.js +19 -0
  11. package/dist/esm/index.js.map +1 -1
  12. package/dist/esm/optimization-heatmap-widget.js +303 -0
  13. package/dist/esm/optimization-heatmap-widget.js.map +1 -0
  14. package/dist/esm/option-smile-widget.js +252 -0
  15. package/dist/esm/option-smile-widget.js.map +1 -0
  16. package/dist/esm/pnl-curve.js +5 -1
  17. package/dist/esm/pnl-curve.js.map +1 -1
  18. package/dist/esm/surface-grid.js +282 -0
  19. package/dist/esm/surface-grid.js.map +1 -0
  20. package/dist/esm/surface-widget.js +379 -0
  21. package/dist/esm/surface-widget.js.map +1 -0
  22. package/dist/sstradingcontrols.js +1595 -168
  23. package/dist/sstradingcontrols.js.map +4 -4
  24. package/dist/types/chart-engine.d.ts +3 -0
  25. package/dist/types/chart-engine.d.ts.map +1 -0
  26. package/dist/types/control-types.d.ts +4 -0
  27. package/dist/types/control-types.d.ts.map +1 -1
  28. package/dist/types/equity-widget.d.ts +34 -0
  29. package/dist/types/equity-widget.d.ts.map +1 -0
  30. package/dist/types/heatmap-grid.d.ts +88 -0
  31. package/dist/types/heatmap-grid.d.ts.map +1 -0
  32. package/dist/types/index.d.ts +15 -0
  33. package/dist/types/index.d.ts.map +1 -1
  34. package/dist/types/optimization-heatmap-widget.d.ts +45 -0
  35. package/dist/types/optimization-heatmap-widget.d.ts.map +1 -0
  36. package/dist/types/option-smile-widget.d.ts +39 -0
  37. package/dist/types/option-smile-widget.d.ts.map +1 -0
  38. package/dist/types/pnl-curve.d.ts +3 -0
  39. package/dist/types/pnl-curve.d.ts.map +1 -1
  40. package/dist/types/surface-grid.d.ts +64 -0
  41. package/dist/types/surface-grid.d.ts.map +1 -0
  42. package/dist/types/surface-widget.d.ts +64 -0
  43. package/dist/types/surface-widget.d.ts.map +1 -0
  44. package/package.json +28 -2
  45. package/screenshots/equity.png +0 -0
  46. package/screenshots/optimization-surface.png +0 -0
  47. package/screenshots/optimization.png +0 -0
  48. package/screenshots/option-smile.png +0 -0
  49. package/screenshots/panels.jpg +0 -0
  50. package/src/chart-engine.global.ts +64 -0
  51. package/src/chart-engine.ts +29 -0
  52. package/src/control-types.ts +4 -0
  53. package/src/equity-widget.ts +289 -0
  54. package/src/heatmap-grid.ts +405 -0
  55. package/src/index.ts +46 -0
  56. package/src/optimization-heatmap-widget.ts +347 -0
  57. package/src/option-smile-widget.ts +281 -0
  58. package/src/pnl-curve.ts +13 -1
  59. package/src/surface-grid.ts +410 -0
  60. package/src/surface-widget.ts +457 -0
  61. package/styles/trading-controls.css +281 -0
  62. package/translation-keys.json +14 -1
package/README.md CHANGED
@@ -5,10 +5,12 @@
5
5
  [![License](https://img.shields.io/badge/license-StockSharp%20EULA-c8202f.svg)](LICENSE)
6
6
 
7
7
  **StockSharp JS Trading Controls** are the browser panels a trading screen is made
8
- of. Eleven of them: the **active orders**, **positions** and **trade history**
8
+ of. Fifteen of them: the **active orders**, **positions** and **trade history**
9
9
  blotters, a **watchlist** with live quotes and category tabs, an **order entry**
10
10
  pad, a **trade feed**, an **order book** ladder, a **statistics** table, a
11
- **strategies** dashboard, a **log monitor**, and an **option desk**.
11
+ **strategies** dashboard, a **log monitor**, an **option desk** and its
12
+ **smile**, an **equity** curve, and an optimisation **heatmap** with the same
13
+ sweep as a turnable 3D **surface**.
12
14
 
13
15
  Each control builds its own DOM, renders its own table through
14
16
  [`@stocksharp/grids`](https://www.npmjs.com/package/@stocksharp/grids), and reaches
@@ -19,7 +21,7 @@ the outside world through exactly one object — a `TradingHost`.
19
21
  [GitHub repository](https://github.com/StockSharp/JS-TradingControls) ·
20
22
  [Issue tracker](https://github.com/StockSharp/JS-TradingControls/issues)
21
23
 
22
- ![The demo board: a candlestick chart, the trade feed, the order book, the watchlist, the order entry pad and the tabbed blotters, docked the way the terminal docks them](screenshots/panels.jpg)
24
+ ![The demo board: a candlestick chart with two moving averages and a legend, the trade feed, the order book, the watchlist, the order entry pad and the tabbed blotters, docked the way the terminal docks them](screenshots/panels.jpg)
23
25
 
24
26
  The page above is `demo/` — the published bundle over a demo `TradingHost`, no
25
27
  server and no network, laid out by the same dockview-core the StockSharp web
@@ -28,12 +30,28 @@ candlestick panel fed by the same simulated prices. The **Host port traffic**
28
30
  tab records every call the controls made into that host, which is the whole of
29
31
  what they can reach.
30
32
 
33
+ It is three boards over one set of data, because these controls do not all belong
34
+ on one screen. `index.html` is the trading screen: chart, ladder, tape, watchlist,
35
+ order pad, blotters and the option desk. `strategies.html` is a running strategy —
36
+ the dashboard, its equity, its statistics and what it said. `optimization.html` is
37
+ one parameter sweep read two ways, as a map of pairs and as the landscape they
38
+ make. The panels, the host and the tape are shared; a board decides only which
39
+ panels are on it and where.
40
+
31
41
  ## Quick start
32
42
 
33
43
  ```sh
34
44
  npm install @stocksharp/trading-controls
35
45
  ```
36
46
 
47
+ `@stocksharp/chart` is a peer dependency, needed by two panels: the equity curve
48
+ and the option smile are charts, and they are built on the engine rather than on
49
+ canvases of their own. Install it beside this package if you use either:
50
+
51
+ ```sh
52
+ npm install @stocksharp/chart
53
+ ```
54
+
37
55
  ```ts
38
56
  import { PositionsWidget } from '@stocksharp/trading-controls';
39
57
  import '@stocksharp/trading-controls/styles.css';
@@ -61,6 +79,17 @@ The package also ships a ready-to-use browser bundle exposed as
61
79
  </script>
62
80
  ```
63
81
 
82
+ The bundle does not carry the chart engine — a page that loads both would
83
+ otherwise hold two copies of it, and two registries of series definitions that do
84
+ not recognise each other's. `EquityWidget` and `OptionSmileWidget` read it off the
85
+ `SSChart` global instead, so load the chart's own bundle (and the indicators
86
+ bundle it needs) alongside:
87
+
88
+ ```html
89
+ <script src="https://cdn.jsdelivr.net/npm/@stocksharp/indicators/dist/ssindicators.js"></script>
90
+ <script src="https://cdn.jsdelivr.net/npm/@stocksharp/chart/dist/sschart.js"></script>
91
+ ```
92
+
64
93
  ## The host port is the whole API surface
65
94
 
66
95
  A control imports no translator, no settings singleton, no panel registry and no
@@ -125,7 +154,7 @@ Two pairs are deliberately separate rather than merged:
125
154
  reads the port names (`getExecutions`, `searchInstruments`), which the host
126
155
  implements.
127
156
 
128
- ### The 222 keys a host has to answer
157
+ ### The 235 keys a host has to answer
129
158
 
130
159
  `t()` cannot fail. A key the host does not know is rendered to the user as
131
160
  itself, so `NoActiveOrders` appears in the empty blotter and `ClosePanel`
@@ -134,7 +163,7 @@ error. The complete list ships with the package:
134
163
 
135
164
  ```ts
136
165
  import keys from '@stocksharp/trading-controls/translation-keys.json';
137
- // { count: 222, keys: ['Actions', 'ActiveOrders', …] }
166
+ // { count: 235, keys: ['Actions', 'ActiveOrders', …] }
138
167
  ```
139
168
 
140
169
  It is **generated from the sources** (`npm run i18n:update`) and re-checked by
@@ -383,6 +412,85 @@ strike as nothing.
383
412
 
384
413
  ![The option desk: a BTC chain mirrored around the strike, its smile, per-side volume bars and a green-to-red split at the money](screenshots/option-desk.png)
385
414
 
415
+ ### `OptionSmileWidget`
416
+
417
+ The same chain the desk tabulates, drawn as the shape a trader is actually looking
418
+ for: implied volatility against strike, one curve per side, both on one scale
419
+ because the distance between them is the skew. It takes the desk's own
420
+ `OptionStrike[]` and `OptionChainContext`, so a host feeding one feeds the other
421
+ with no conversion.
422
+
423
+ A strike quoted on one side and not the other leaves a gap rather than a straight
424
+ line through it - a curve drawn across missing data invents a quote that nobody
425
+ made. The underlying's price is marked, since where the money sits is what makes
426
+ a smile a smile rather than a squiggle.
427
+
428
+ Drawn by `@stocksharp/chart`, which is a time-series engine and this axis is a
429
+ ladder of strikes — one `timeScale.formatter` is all that stands between the two,
430
+ and the axis carries the strike itself, so the label and the value cannot drift
431
+ apart. Spacing is ordinal, because a listed chain is evenly spaced by listing: a
432
+ venue that lists 67000, 67250 and then 68000 means three rungs, not a hole. The
433
+ crosshair, the wheel zoom, the drag and the tick steps come with the engine; the
434
+ readout above the chart is worded here, naming the strike and both sides at it,
435
+ because a smile is read by the distance between the two curves.
436
+
437
+ ![The option smile: call and put volatility by strike on one scale, the crosshair naming the strike and both sides at it, the underlying marked](screenshots/option-smile.png)
438
+
439
+ ### `EquityWidget`
440
+
441
+ A run's cumulative P&L at the size of a chart. It is the same curve
442
+ `StrategiesWidget` draws in a column and the same arithmetic behind it - the
443
+ package computes that curve once, in `pnl-curve.ts`, and a host that wants an
444
+ equity panel gets it rather than reimplementing the layout for the third time.
445
+
446
+ What the panel affords that a sparkline cannot: a crosshair that names the moment
447
+ and the figure under the pointer, a wheel that zooms about it, a drag that pans,
448
+ and an axis that picks its own step. All of that is `@stocksharp/chart`'s, which
449
+ is why the panel is built on it; what stays here is the part that is this
450
+ package's — turning a run into a series, wording the moment through
451
+ `presentation.timeText`, and taking the curve's colours from
452
+ `presentation.canvasPalette()` so a panel matches the sparkline in the table
453
+ beside it. The colour follows where the run *ended*: a run that peaked and gave it
454
+ all back is a loss, and the fill says so.
455
+
456
+ The sparkline is not this. A cell forty pixels tall gets a canvas — a chart engine
457
+ per table row is absurd — so the two draw the same run with different machinery at
458
+ sizes that want different things.
459
+
460
+ ![The equity panel: a run's cumulative P&L filled to the water line, the crosshair naming the moment and the figure under the pointer](screenshots/equity.png)
461
+
462
+ ### `OptimizationHeatmapWidget`
463
+
464
+ One metric over two parameters. It knows nothing about optimisation - a grid of
465
+ `{x, y, value}` is the same object whatever produced it - so a backtest sweep and
466
+ anything else that varies two things share a control.
467
+
468
+ `betterWhen` is required rather than assumed: without it the same map of drawdowns
469
+ would paint its worst corner in the winning colour. A pair with no run leaves a
470
+ gap, drawn as one, because an absent result and a zero result are different
471
+ things. Two runs at one pair are two samples of one cell, so the cell is their
472
+ mean and says how many it is the mean of.
473
+
474
+ ![The optimisation heatmap: net profit over a moving-average pair, gaps where no run exists and the best cell marked](screenshots/optimization.png)
475
+
476
+ ### `SurfaceWidget`
477
+
478
+ The same sweep as a landscape: the metric as height as well as colour, so the
479
+ shape a set of parameters makes is read directly instead of being inferred from a
480
+ grid of tints. It takes the heatmap's own input, so one set of results feeds both
481
+ panels and a consumer offers either.
482
+
483
+ It is turned, tipped and zoomed by hand, and there is no library under it. The
484
+ projection is six multiplications and the ordering is a sort by depth, both in
485
+ `surface-grid.ts` as arithmetic that is checked against numbers rather than
486
+ against pixels. The gestures are pointer events, so a mouse, a pen and a thumb
487
+ take the same path: one pointer turns, two pinch to zoom, a wheel zooms.
488
+ Orthographic rather than perspective, because a surface is read by comparing
489
+ heights across it and perspective makes the far side of a ridge shorter than the
490
+ near side of the same ridge.
491
+
492
+ ![The optimisation surface: the same sweep as a landscape, turned by hand, with the losing corner in red](screenshots/optimization-surface.png)
493
+
386
494
  ## Exported sheets say what the screen says
387
495
 
388
496
  Every blotter exports to `.xlsx` through the grid, and a column states both
@@ -0,0 +1,15 @@
1
+ // The chart engine, in one place.
2
+ //
3
+ // Two panels here are charts rather than drawings - an equity curve over time and a smile over
4
+ // strike - and @stocksharp/chart already does what a chart does: a crosshair that names the
5
+ // point under the pointer, a wheel that zooms about it, a drag that pans, tick labels that pick
6
+ // their own step. Re-implementing that was two engines and a poorer result, so it is a peer
7
+ // dependency now and the panels are built on it.
8
+ //
9
+ // Every import of it goes through this module, for one reason: the IIFE bundle must NOT inline
10
+ // the engine. A page that loads `sschart.js` and `sstradingcontrols.js` would otherwise hold two
11
+ // copies of it - a megabyte twice over, and two registries of series definitions that do not
12
+ // recognise each other's. `build.mjs` points this specifier at `chart-engine.global.ts` for that
13
+ // build, which reads the engine off the global the chart's own bundle publishes.
14
+ export { AreaSeries, CrosshairMode, LineSeries, createChart, } from '@stocksharp/chart';
15
+ //# sourceMappingURL=chart-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-engine.js","sourceRoot":"","sources":["../../src/chart-engine.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,+FAA+F;AAC/F,4FAA4F;AAC5F,gGAAgG;AAChG,4FAA4F;AAC5F,iDAAiD;AACjD,EAAE;AACF,+FAA+F;AAC/F,iGAAiG;AACjG,6FAA6F;AAC7F,iGAAiG;AACjG,iFAAiF;AACjF,OAAO,EACH,UAAU,EACV,aAAa,EACb,UAAU,EACV,WAAW,GACd,MAAM,mBAAmB,CAAC"}
@@ -26,5 +26,9 @@ export const ControlTypes = {
26
26
  LogMonitor: 'logMonitor',
27
27
  Strategies: 'strategies',
28
28
  OptionDesk: 'optionDesk',
29
+ OptionSmile: 'optionSmile',
30
+ Equity: 'equity',
31
+ OptimizationHeatmap: 'optimizationHeatmap',
32
+ OptimizationSurface: 'optimizationSurface',
29
33
  };
30
34
  //# sourceMappingURL=control-types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"control-types.js","sourceRoot":"","sources":["../../src/control-types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,iBAAiB;AACjB,EAAE;AACF,gFAAgF;AAChF,yEAAyE;AACzE,4EAA4E;AAC5E,8EAA8E;AAC9E,EAAE;AACF,8EAA8E;AAC9E,0EAA0E;AAC1E,2BAA2B;AAC3B,EAAE;AACF,8EAA8E;AAC9E,+EAA+E;AAC/E,+EAA+E;AAC/E,SAAS;AACT,MAAM,CAAC,MAAM,YAAY,GAAG;IACxB,SAAS,EAAE,WAAW;IACtB,YAAY,EAAE,cAAc;IAC5B,YAAY,EAAE,cAAc;IAC5B,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;CAClB,CAAC"}
1
+ {"version":3,"file":"control-types.js","sourceRoot":"","sources":["../../src/control-types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,iBAAiB;AACjB,EAAE;AACF,gFAAgF;AAChF,yEAAyE;AACzE,4EAA4E;AAC5E,8EAA8E;AAC9E,EAAE;AACF,8EAA8E;AAC9E,0EAA0E;AAC1E,2BAA2B;AAC3B,EAAE;AACF,8EAA8E;AAC9E,+EAA+E;AAC/E,+EAA+E;AAC/E,SAAS;AACT,MAAM,CAAC,MAAM,YAAY,GAAG;IACxB,SAAS,EAAE,WAAW;IACtB,YAAY,EAAE,cAAc;IAC5B,YAAY,EAAE,cAAc;IAC5B,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;IACxB,UAAU,EAAE,YAAY;IACxB,WAAW,EAAE,aAAa;IAC1B,MAAM,EAAE,QAAQ;IAChB,mBAAmB,EAAE,qBAAqB;IAC1C,mBAAmB,EAAE,qBAAqB;CACpC,CAAC"}
@@ -0,0 +1,261 @@
1
+ // Equity curve — multi-instance.
2
+ //
3
+ // A run's cumulative P&L at the size of a chart, drawn by @stocksharp/chart. It used to be a
4
+ // canvas of its own with a crosshair, a legend and a zoom written here; all three are the
5
+ // engine's, better than the versions this file had, and an equity curve over time is exactly
6
+ // what a time-series engine is for.
7
+ //
8
+ // What is left here is the part that is this package's: turning a run into a series, wording the
9
+ // readout through the host, and taking the engine's colours from `presentation.canvasPalette()`
10
+ // so a curve in a panel matches the sparkline in a table cell beside it.
11
+ //
12
+ // The sparkline is NOT this. A cell forty pixels tall gets `pnl-curve.ts` and a canvas, because
13
+ // a chart engine per table row is absurd - the two draw the same run at sizes that want
14
+ // different machinery.
15
+ import { formatPnl } from './formatters.js';
16
+ import { makeElement, makeIconButton, makePanelId, makePanelRoot } from './dom.js';
17
+ import { ControlTypes } from './control-types.js';
18
+ import { assertHost } from './trading-host.js';
19
+ import { AreaSeries, CrosshairMode, createChart, } from './chart-engine.js';
20
+ // How solid the area under the curve is drawn. Not a colour - the two colours are the host's -
21
+ // but how far they are faded, which is this chart's own business.
22
+ const FILL_TOP_ALPHA = 0.28;
23
+ const FILL_BOTTOM_ALPHA = 0.02;
24
+ const LINE_WIDTH = 2;
25
+ /// One sample as the engine takes it. Time is unix milliseconds on the way in and seconds on the
26
+ /// way through: the engine counts in seconds, and a host that hands over milliseconds - which is
27
+ /// what `Date.now()` and `presentation.timeText` both deal in - should not have to know that.
28
+ function toSeries(points) {
29
+ const seen = new Set();
30
+ const out = [];
31
+ for (const point of [...points].sort((a, b) => a.time - b.time)) {
32
+ if (!Number.isFinite(point.time) || !Number.isFinite(point.value))
33
+ continue;
34
+ // The engine holds one value per moment. Two fills in the same second are two samples of
35
+ // one instant, and the later one is where the run actually stood.
36
+ const second = Math.floor(point.time / 1000);
37
+ if (seen.has(second))
38
+ out[out.length - 1] = { time: second, value: point.value };
39
+ else
40
+ out.push({ time: second, value: point.value });
41
+ seen.add(second);
42
+ }
43
+ return out;
44
+ }
45
+ export class EquityWidget {
46
+ static create(hostEl, state, deps) {
47
+ const host = assertHost(deps?.host, 'EquityWidget');
48
+ const root = EquityWidget._buildRoot(host);
49
+ root.id = makePanelId(EquityWidget.TYPE);
50
+ hostEl.appendChild(root);
51
+ return new EquityWidget(root, state || {}, deps);
52
+ }
53
+ static _buildRoot(host) {
54
+ const title = host.t('Equity');
55
+ return makePanelRoot('equity-panel', title, [
56
+ makeElement('div', 'panel-header', {}, [
57
+ makeElement('span', '', {}, [title]),
58
+ makeElement('span', 'equity-last', {}, []),
59
+ makeIconButton('bt-icon-btn equity-reset-btn', host.t('ResetView'), 'bi-arrow-clockwise', { type: 'button' }),
60
+ makeIconButton('bt-icon-btn bt-icon-cancel panel-close-btn', host.t('ClosePanel'), 'bi-x', { type: 'button' }),
61
+ ]),
62
+ makeElement('div', 'panel-body', {}, [
63
+ makeElement('div', 'equity-chart', { role: 'img', 'aria-label': host.t('PnLChart') }, [
64
+ // Over the curve rather than in the panel header, for the same reason the
65
+ // smile's is: a reading about a moment belongs beside that moment, and a host
66
+ // that lifts panel headers into a tab strip would put it in a tab title.
67
+ makeElement('div', 'equity-hover', {}, []),
68
+ makeElement('div', 'equity-empty', {}, [host.t('NoEquity')]),
69
+ ]),
70
+ ]),
71
+ ]);
72
+ }
73
+ constructor(rootEl, _state, deps) {
74
+ this._host = assertHost(deps?.host, 'EquityWidget');
75
+ this.rootEl = rootEl;
76
+ this._closeBtn = this.rootEl.querySelector('.panel-close-btn');
77
+ this._resetBtn = this.rootEl.querySelector('.equity-reset-btn');
78
+ this._lastEl = this.rootEl.querySelector('.equity-last');
79
+ this._hoverEl = this.rootEl.querySelector('.equity-hover');
80
+ this._emptyEl = this.rootEl.querySelector('.equity-empty');
81
+ this._chartEl = this.rootEl.querySelector('.equity-chart');
82
+ this._chart = null;
83
+ this._series = null;
84
+ this._points = [];
85
+ this._resizeObserver = null;
86
+ this._closeBtn?.addEventListener('click', (e) => { e.preventDefault(); this._host.close(); });
87
+ this._resetBtn?.addEventListener('click', (e) => { e.preventDefault(); this.resetZoom(); });
88
+ // The panel has no size until it is laid out, and a docked one is resized afterwards.
89
+ // The engine sizes its canvases only through resize(), so it is told rather than left to
90
+ // notice.
91
+ if (this._chartEl !== null && typeof ResizeObserver !== 'undefined') {
92
+ this._resizeObserver = new ResizeObserver(() => this._fit());
93
+ this._resizeObserver.observe(this._chartEl);
94
+ }
95
+ this._render();
96
+ this._host.register(this);
97
+ }
98
+ dispose() {
99
+ try {
100
+ this._resizeObserver?.disconnect();
101
+ }
102
+ catch { /* already torn down */ }
103
+ this._resizeObserver = null;
104
+ try {
105
+ this._chart?.remove();
106
+ }
107
+ catch { /* already gone */ }
108
+ this._chart = null;
109
+ this._series = null;
110
+ this._host.unregister(this);
111
+ try {
112
+ this.rootEl.remove();
113
+ }
114
+ catch { /* already detached */ }
115
+ }
116
+ /// Show this run. The whole curve at once: it is a cumulative figure, so a set of points that
117
+ /// no longer contains an earlier sample is a different run rather than a longer one.
118
+ ///
119
+ /// `time` is unix milliseconds.
120
+ update(points) {
121
+ this._points = points || [];
122
+ this._render();
123
+ }
124
+ /// Show the whole run again, after a zoom.
125
+ resetZoom() {
126
+ try {
127
+ this._chart?.timeScale().fitContent();
128
+ }
129
+ catch { /* no chart yet */ }
130
+ }
131
+ /// The engine, for a host that wants to add to this chart - a benchmark line, a marker at a
132
+ /// drawdown. Null until there is something to draw.
133
+ chart() {
134
+ return this._chart;
135
+ }
136
+ // Built on first use rather than in the constructor: the engine measures its container, and
137
+ // a panel that has not been laid out yet has none.
138
+ _ensureChart() {
139
+ if (this._chart !== null)
140
+ return true;
141
+ if (this._chartEl === null)
142
+ return false;
143
+ const palette = this._host.presentation.canvasPalette();
144
+ this._chart = createChart(this._chartEl, {
145
+ layout: {
146
+ background: { type: 'solid', color: 'transparent' },
147
+ textColor: palette.grid,
148
+ fontFamily: palette.font,
149
+ fontSize: 11,
150
+ attributionLogo: false,
151
+ },
152
+ grid: { vertLines: { color: palette.grid }, horzLines: { color: palette.grid } },
153
+ crosshair: { mode: CrosshairMode.Normal },
154
+ rightPriceScale: { borderColor: palette.grid },
155
+ timeScale: {
156
+ borderColor: palette.grid,
157
+ timeVisible: true,
158
+ secondsVisible: true,
159
+ // The engine dates an axis in UTC unless told otherwise, and everything else on
160
+ // the page - the readout beside this one included - reads in the browser's zone.
161
+ // Two labels for one instant, three hours apart, is worse than either.
162
+ timeZone: browserTimeZone(),
163
+ },
164
+ });
165
+ this._series = this._chart.addSeries(AreaSeries, {
166
+ lineWidth: LINE_WIDTH,
167
+ lineColor: palette.up,
168
+ topColor: withAlpha(palette.up, FILL_TOP_ALPHA),
169
+ bottomColor: withAlpha(palette.up, FILL_BOTTOM_ALPHA),
170
+ });
171
+ // The readout. The engine says which point the pointer is over; wording it is the host's,
172
+ // which is why this is here rather than in the engine's own crosshair label.
173
+ this._chart.subscribeCrosshairMove((param) => this._renderHover(param));
174
+ return true;
175
+ }
176
+ _render() {
177
+ const series = toSeries(this._points);
178
+ const empty = series.length < 2;
179
+ if (this._emptyEl !== null)
180
+ this._emptyEl.hidden = !empty;
181
+ this._renderLast(empty ? null : series[series.length - 1].value);
182
+ if (empty)
183
+ return;
184
+ if (!this._ensureChart() || this._series === null)
185
+ return;
186
+ // Coloured by where the run ended, the way the sparkline is: a run that peaked and gave
187
+ // it all back is a loss, and the colour says so.
188
+ const palette = this._host.presentation.canvasPalette();
189
+ const last = series[series.length - 1].value;
190
+ const colour = last >= 0 ? palette.up : palette.down;
191
+ this._series.applyOptions({
192
+ lineColor: colour,
193
+ topColor: withAlpha(colour, FILL_TOP_ALPHA),
194
+ bottomColor: withAlpha(colour, FILL_BOTTOM_ALPHA),
195
+ });
196
+ this._series.setData(series);
197
+ this._fit();
198
+ }
199
+ _fit() {
200
+ if (this._chart === null || this._chartEl === null)
201
+ return;
202
+ const rect = this._chartEl.getBoundingClientRect();
203
+ if (rect.width <= 0 || rect.height <= 0)
204
+ return;
205
+ try {
206
+ this._chart.resize(rect.width, rect.height);
207
+ }
208
+ catch { /* the engine is between frames */ }
209
+ }
210
+ // Where the run stands, in the header.
211
+ _renderLast(value) {
212
+ const el = this._lastEl;
213
+ if (el === null)
214
+ return;
215
+ el.textContent = value === null ? '' : formatPnl(value);
216
+ el.className = value === null
217
+ ? 'equity-last'
218
+ : `equity-last ${this._host.presentation.pnlClass(value)}`;
219
+ }
220
+ // What the pointer is over. The engine hands over the moment and the value at it; the moment
221
+ // is worded by the host, because what a time reads as is the page's business and not this
222
+ // package's.
223
+ _renderHover(param) {
224
+ const el = this._hoverEl;
225
+ if (el === null)
226
+ return;
227
+ const point = this._series === null ? undefined : param.seriesData.get(this._series);
228
+ const value = point?.value;
229
+ // Off the series entirely: the engine reports a crosshair with no time when the pointer
230
+ // has left the plot, and a stale readout is worse than none.
231
+ if (param.time === null || value === undefined || !Number.isFinite(value)) {
232
+ el.textContent = '';
233
+ el.className = 'equity-hover';
234
+ return;
235
+ }
236
+ // Back to milliseconds for the host: the engine counts in seconds, and every other moment
237
+ // this package hands over is a Date.
238
+ const moment = new Date(Number(param.time) * 1000);
239
+ el.textContent = `${this._host.presentation.timeText(moment)} ${formatPnl(value)}`;
240
+ el.className = `equity-hover ${this._host.presentation.pnlClass(value)}`;
241
+ }
242
+ }
243
+ EquityWidget.TYPE = ControlTypes.Equity;
244
+ /// The zone a moment reads in: the browser's own, which is the zone
245
+ /// `presentation.timeText` words one in. UTC when the environment cannot say.
246
+ function browserTimeZone() {
247
+ try {
248
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
249
+ }
250
+ catch {
251
+ return 'UTC';
252
+ }
253
+ }
254
+ /// A colour at a given opacity.
255
+ ///
256
+ /// The host answers with whatever CSS understands, so this cannot take it apart - it wraps it
257
+ /// instead, which `color-mix` accepts for every form a token can be written in.
258
+ function withAlpha(colour, alpha) {
259
+ return `color-mix(in srgb, ${colour} ${Math.round(alpha * 100)}%, transparent)`;
260
+ }
261
+ //# sourceMappingURL=equity-widget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"equity-widget.js","sourceRoot":"","sources":["../../src/equity-widget.ts"],"names":[],"mappings":"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"}