@stocksharp/trading-controls 0.1.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 (59) hide show
  1. package/LICENSE +30 -0
  2. package/NOTICE +21 -0
  3. package/README.md +240 -0
  4. package/dist/esm/active-orders-widget.js +382 -0
  5. package/dist/esm/active-orders-widget.js.map +1 -0
  6. package/dist/esm/control-types.js +23 -0
  7. package/dist/esm/control-types.js.map +1 -0
  8. package/dist/esm/dom.js +55 -0
  9. package/dist/esm/dom.js.map +1 -0
  10. package/dist/esm/formatters.js +69 -0
  11. package/dist/esm/formatters.js.map +1 -0
  12. package/dist/esm/index.js +12 -0
  13. package/dist/esm/index.js.map +1 -0
  14. package/dist/esm/positions-widget.js +258 -0
  15. package/dist/esm/positions-widget.js.map +1 -0
  16. package/dist/esm/trade-history-widget.js +197 -0
  17. package/dist/esm/trade-history-widget.js.map +1 -0
  18. package/dist/esm/trading-data.js +26 -0
  19. package/dist/esm/trading-data.js.map +1 -0
  20. package/dist/esm/trading-host.js +79 -0
  21. package/dist/esm/trading-host.js.map +1 -0
  22. package/dist/esm/watchlist-widget.js +481 -0
  23. package/dist/esm/watchlist-widget.js.map +1 -0
  24. package/dist/sstradingcontrols.js +1740 -0
  25. package/dist/sstradingcontrols.js.map +7 -0
  26. package/dist/types/active-orders-widget.d.ts +52 -0
  27. package/dist/types/active-orders-widget.d.ts.map +1 -0
  28. package/dist/types/control-types.d.ts +8 -0
  29. package/dist/types/control-types.d.ts.map +1 -0
  30. package/dist/types/dom.d.ts +6 -0
  31. package/dist/types/dom.d.ts.map +1 -0
  32. package/dist/types/formatters.d.ts +8 -0
  33. package/dist/types/formatters.d.ts.map +1 -0
  34. package/dist/types/index.d.ts +16 -0
  35. package/dist/types/index.d.ts.map +1 -0
  36. package/dist/types/positions-widget.d.ts +37 -0
  37. package/dist/types/positions-widget.d.ts.map +1 -0
  38. package/dist/types/trade-history-widget.d.ts +25 -0
  39. package/dist/types/trade-history-widget.d.ts.map +1 -0
  40. package/dist/types/trading-data.d.ts +55 -0
  41. package/dist/types/trading-data.d.ts.map +1 -0
  42. package/dist/types/trading-host.d.ts +62 -0
  43. package/dist/types/trading-host.d.ts.map +1 -0
  44. package/dist/types/watchlist-widget.d.ts +60 -0
  45. package/dist/types/watchlist-widget.d.ts.map +1 -0
  46. package/package.json +129 -0
  47. package/src/active-orders-widget.ts +411 -0
  48. package/src/control-types.ts +24 -0
  49. package/src/dom.ts +68 -0
  50. package/src/formatters.ts +72 -0
  51. package/src/index.ts +52 -0
  52. package/src/positions-widget.ts +305 -0
  53. package/src/trade-history-widget.ts +221 -0
  54. package/src/trading-data.ts +121 -0
  55. package/src/trading-host.ts +300 -0
  56. package/src/watchlist-widget.ts +513 -0
  57. package/styles/theme.css +86 -0
  58. package/styles/trading-controls.css +469 -0
  59. package/translation-keys.json +58 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts", "../src/trading-host.ts", "../src/control-types.ts", "../src/formatters.ts", "../src/dom.ts", "../node_modules/@stocksharp/grids/src/table-sort.ts", "../node_modules/@stocksharp/grids/src/table-export.ts", "../node_modules/@stocksharp/grids/src/data-grid.ts", "../src/active-orders-widget.ts", "../src/positions-widget.ts", "../src/trade-history-widget.ts", "../src/watchlist-widget.ts"],
4
+ "sourcesContent": ["export { MarketDataLevels, PRESENTATION_CLASSES, assertHost } from './trading-host.js';\n\nexport type {\n HostStore,\n MarketDataClient,\n MarketDataLevel,\n TickerSink,\n TradingApi,\n TradingContext,\n TradingControl,\n TradingHost,\n TradingPresentation,\n} from './trading-host.js';\n\nexport type {\n BalanceRow,\n InstrumentRow,\n OrderRow,\n OrderSide,\n OrderStatus,\n OrderType,\n PositionRow,\n QuoteStats,\n TradeRow,\n} from './trading-data.js';\n\nexport { ControlTypes } from './control-types.js';\n\nexport type { ControlType } from './control-types.js';\n\nexport { cleanRejectReason, formatPnl, formatPrice, formatQty, formatTime } from './formatters.js';\n\n// A host that renders its own chrome around these controls builds it with the\n// same helpers, so the panel it wraps and the panel it wraps them in agree on\n// class names.\nexport { makeElement, makeIcon, makeIconButton, makePanelId, makePanelRoot } from './dom.js';\n\nexport { ActiveOrdersWidget, OrderStates } from './active-orders-widget.js';\n\nexport type { ActiveOrdersDeps } from './active-orders-widget.js';\n\nexport { PositionsWidget } from './positions-widget.js';\n\nexport type { PositionsDeps } from './positions-widget.js';\n\nexport { TradeHistoryWidget } from './trade-history-widget.js';\n\nexport type { TradeHistoryDeps } from './trade-history-widget.js';\n\nexport { WatchlistWidget } from './watchlist-widget.js';\n\nexport type { WatchlistDeps } from './watchlist-widget.js';\n", "// The host port \u2014 the whole of what a trading control needs from whoever\r\n// embeds it.\r\n//\r\n// A control is written against this interface and nothing else: it never\r\n// imports a translator, a preference singleton, a panel registry or a docking\r\n// manager, and it never reaches a window global. A host \u2014 a terminal page, a\r\n// backoffice screen, a demo harness \u2014 supplies one object shaped like\r\n// `TradingHost` per control instance, and that object is the only way out of\r\n// the control.\r\n//\r\n// This module imports nothing but the row shapes it names. It is the contract,\r\n// so it must be readable by a host that shares none of the package's internals.\r\n//\r\n// Everything here is REQUIRED, and `assertHost` proves it at construction.\r\n// There is no optional member and no default, because a half-supplied host is\r\n// how a control half-works: it renders, it looks alive, and the one capability\r\n// nobody wired is discovered by a user clicking something that does nothing.\r\n// A missing member has to be a loud failure at wiring time, not a quiet one at\r\n// click time.\r\n//\r\n// Seven members have no call site among the four controls this package ships \u2014\r\n// `spawn`, `persistState`, `saveLayout`, `log`, `trading.pickInstrument`,\r\n// `marketData.resubscribe` and `marketData.getOrders`. They are required\r\n// anyway, and the reason is not a future one:\r\n//\r\n// The port was extracted from a terminal that has SEVEN controls, four of\r\n// which now live here. The other three \u2014 the order book, the order entry\r\n// pad and the trade feed \u2014 are already written against THIS interface, in\r\n// this repository's sibling host, importing `TradingHost` and `assertHost`\r\n// from this module today. Every one of the seven members above is called by\r\n// them: the order book alone accounts for `resubscribe` (recovering from a\r\n// sequence gap without unsubscribing its neighbours), `getOrders` (its \"your\r\n// size is here\" badge), `log` (wire anomalies the user cannot see) and\r\n// `pickInstrument`; the order book and the trade feed both `spawn` and both\r\n// `persistState` + `saveLayout`.\r\n//\r\n// So this is one port with three of its consumers still on the host's side\r\n// of the boundary, not a port padded with speculation. Narrowing it now and\r\n// widening it again as each of those three moves in would break every host\r\n// twice for the sake of a window in which no control is missing.\r\n//\r\n// The cost is real and worth stating: a host adopting only the four shipped\r\n// controls must still supply seven members nothing will call. They are cheap\r\n// (a no-op `spawn`, a `log` that forwards to the console) \u2014 but they are not\r\n// free, and an adopter who supplies stubs is not doing anything wrong.\r\nimport type { InstrumentRow, OrderRow, OrderSide, OrderStatus, OrderType, QuoteStats, TradeRow } from './trading-data.js';\r\n\r\n/// How a host words and colours the trading vocabulary. The control owns the\r\n/// data; the host owns the language and the stylesheet, so it says what a side\r\n/// or a status reads as and which CSS class carries its colour.\r\n///\r\n/// The two class methods are the one place a host has to agree with the shipped\r\n/// stylesheet rather than merely supply values to it. A control puts whatever\r\n/// string comes back straight onto the cell without inspecting it, so nothing\r\n/// in `src/` ever emits these names and `styles/trading-controls.css` cannot be\r\n/// read to discover them. They are named here, and `PRESENTATION_CLASSES` below\r\n/// is the same list as data \u2014 `tools/check-style-contract.mjs` asserts the\r\n/// stylesheet styles every one of them, so the agreement is checked rather than\r\n/// discovered by a cell that came out unstyled.\r\nexport interface TradingPresentation {\r\n /// Localized \"Buy\" / \"Sell\".\r\n sideText(side: OrderSide): string;\r\n /// Localized short order type \u2014 \"LMT\", \"MKT\", \"STP\", \"STP-LMT\". Needs both\r\n /// prices because a conditional order is only a stop-limit when it carries\r\n /// a limit price as well as a stop price.\r\n typeText(type: OrderType, limitPrice: number, stopPrice: number): string;\r\n /// Localized order status.\r\n statusText(status: OrderStatus): string;\r\n /// CSS class colouring a cell by side. The shipped stylesheet styles\r\n /// `side-buy` and `side-sell`; a host on its own palette may answer with\r\n /// its own names and style those instead.\r\n sideClass(side: OrderSide): string;\r\n /// CSS class colouring a cell by the sign of a P&L figure. The shipped\r\n /// stylesheet styles `pnl-positive` and `pnl-negative`; the empty string is\r\n /// a legitimate answer for \"no colour\".\r\n pnlClass(pnl: number): string;\r\n}\r\n\r\n/// The class names `TradingPresentation` is expected to return, as data.\r\n///\r\n/// Exported because it is a contract, not a detail: a host writing its own\r\n/// presentation reads this to know which names the shipped stylesheet already\r\n/// paints, and the style-contract check reads it to prove they are all styled.\r\nexport const PRESENTATION_CLASSES = {\r\n sideClass: ['side-buy', 'side-sell'],\r\n pnlClass: ['pnl-positive', 'pnl-negative'],\r\n} as const;\r\n\r\n/// A string-keyed store. Two of these reach a control and they are NOT\r\n/// interchangeable \u2014 see `TradingHost.preferences` and `TradingHost.cache`.\r\nexport interface HostStore {\r\n /// The stored value, or `fallback` when the key was never written.\r\n get(key: string, fallback: string | null): string | null;\r\n /// Write, or clear by writing null.\r\n set(key: string, value: string | null): void;\r\n}\r\n\r\n/// The read side of the trading account, as far as a control is concerned.\r\n/// Narrow on purpose: a control asks for the few calls it makes rather than\r\n/// being handed a whole API client to explore.\r\nexport interface TradingApi {\r\n /// Executed trades, newest first, for one portfolio. A null `symbol` means\r\n /// every instrument \u2014 the argument is stated either way rather than being\r\n /// left off, so a call site says which of the two it wants.\r\n getExecutions(portfolioId: number, symbol: string | null, limit: number): Promise<TradeRow[]>;\r\n /// Instruments matching a query; the empty query means \"everything\".\r\n searchInstruments(query: string): Promise<InstrumentRow[]>;\r\n}\r\n\r\n/// How much of a symbol a control wants streamed. A quote row needs the last\r\n/// price, a tape needs every print, a ladder needs the book as well \u2014 and each\r\n/// costs the wire something different, so a control states which it is asking\r\n/// for rather than leaving the argument off and taking a default.\r\nexport const MarketDataLevels = {\r\n /// Level 1 only: best bid/ask and last price.\r\n Quotes: 'l1only',\r\n /// Level 1 plus every tick.\r\n Tape: 'tape',\r\n /// Level 1, ticks and market depth.\r\n Full: 'full',\r\n} as const;\r\n\r\nexport type MarketDataLevel = typeof MarketDataLevels[keyof typeof MarketDataLevels];\r\n\r\n/// The live market-data connection. `addSymbol` / `removeSymbol` are\r\n/// refcounted by the implementation, so two controls watching one symbol hold\r\n/// one subscription between them and neither can unsubscribe the other.\r\nexport interface MarketDataClient {\r\n addSymbol(symbol: string, level: MarketDataLevel): Promise<unknown>;\r\n removeSymbol(symbol: string): Promise<unknown>;\r\n /// Make the server resend `symbol` from scratch, without touching the\r\n /// refcount. A control applying diffs against a sequence cannot recover\r\n /// from a missed frame on its own \u2014 the only cure is a fresh snapshot, and\r\n /// asking for one must not unsubscribe the other controls watching the\r\n /// same symbol.\r\n resubscribe(symbol: string, level: MarketDataLevel): Promise<void>;\r\n /// The client's cache of this session's own orders. The order book paints\r\n /// its \"you have size here\" badge from this rather than subscribing again.\r\n getOrders(): OrderRow[];\r\n}\r\n\r\n/// What a control reads about the account and the instrument universe.\r\nexport interface TradingContext {\r\n readonly api: TradingApi;\r\n readonly marketData: MarketDataClient;\r\n /// The portfolio a control should load against, read per use rather than\r\n /// captured \u2014 the user can switch portfolio under a control that is\r\n /// already on screen.\r\n portfolioId(): number | null;\r\n /// Ask the host to let the user pick an instrument. The host owns the\r\n /// picker UI; the control only learns what was chosen, and learns nothing\r\n /// if the user dismisses it.\r\n pickInstrument(onPicked: (symbol: string) => void): void;\r\n}\r\n\r\n/// Where a control's summary of what it is showing goes. A status-bar ticker is\r\n/// page chrome outside any control, so a control reports and the host decides\r\n/// what to do with the report.\r\nexport interface TickerSink {\r\n publish(symbols: string[], stats: Map<string, QuoteStats>): void;\r\n}\r\n\r\n/// One live control instance, from the host's side. Deliberately opaque: the\r\n/// host holds a heterogeneous set and only ever hands instances back to the\r\n/// control that asked for them, which is what `broadcast<T>` expresses.\r\nexport type TradingControl = object;\r\n\r\n/// Everything a trading control needs from its host.\r\nexport interface TradingHost {\r\n // -- this instance's role on the page ---------------------------------\r\n /// True when this instance is the one that speaks for the page. A page has\r\n /// one status-bar ticker and a control can be duplicated, so somebody has\r\n /// to decide which duplicate feeds it \u2014 and that is host policy, not\r\n /// something a control can work out about itself.\r\n readonly isPrimary: boolean;\r\n\r\n // -- language and wording ---------------------------------------------\r\n /// Translate. `key` is the English source text; `{0}`, `{1}` \u2026 in the\r\n /// translation are replaced positionally from `args`.\r\n t(key: string, ...args: unknown[]): string;\r\n readonly presentation: TradingPresentation;\r\n\r\n // -- storage ------------------------------------------------------------\r\n /// Settings that belong to the user and are expected to survive \u2014 a chosen\r\n /// depth, a view mode, a favourites list. May be slow and may be shared\r\n /// across devices.\r\n readonly preferences: HostStore;\r\n /// Local scratch that may be thrown away \u2014 a per-day price baseline, a\r\n /// memoised computation. Deliberately a different store from\r\n /// `preferences`: writing high-churn per-symbol keys into a synced\r\n /// per-user settings blob is how a settings row becomes a cache.\r\n readonly cache: HostStore;\r\n\r\n // -- the trading context it reads ---------------------------------------\r\n readonly trading: TradingContext;\r\n\r\n // -- where its ticker updates go ----------------------------------------\r\n readonly ticker: TickerSink;\r\n\r\n // -- permission and diagnostics -----------------------------------------\r\n /// May the user do this? `action` is the English name of the attempt\r\n /// (\"add to favorites\"); the host translates it and may show a sign-in\r\n /// prompt before answering false.\r\n allow(action: string): boolean;\r\n /// Send a diagnostic line wherever this host collects them. Controls use\r\n /// it for wire anomalies the user cannot see and support has to.\r\n log(message: string): void;\r\n\r\n // -- lifecycle calls it makes back --------------------------------------\r\n /// This control wants to go away.\r\n close(): void;\r\n /// The `+` gesture: another control of the same kind, starting from\r\n /// `state`. The host knows what kind this one is, so the control does not\r\n /// name its own type.\r\n spawn(state: Record<string, unknown>): void;\r\n /// Remember this control's per-instance state. Recording only \u2014 call\r\n /// `saveLayout` when the change is worth flushing.\r\n persistState(patch: Record<string, unknown>): void;\r\n /// Write the layout out now, bypassing any debounce the host applies.\r\n saveLayout(): void;\r\n\r\n // -- the host's handle on live instances --------------------------------\r\n /// Announce this instance. A host fans incoming data to every live control\r\n /// of a kind, so an unregistered control is a control that never updates.\r\n register(control: TradingControl): void;\r\n unregister(control: TradingControl): void;\r\n /// Apply something to every live control of this kind, this one included.\r\n /// The caller knows what its own siblings are, which is why `T` is its to\r\n /// name.\r\n broadcast<T>(apply: (control: T) => void): void;\r\n}\r\n\r\n/// Prove a host object satisfies the port, and say precisely what is missing\r\n/// when it does not.\r\n///\r\n/// Called from every control's constructor before anything else, so a\r\n/// mis-wired host fails at construction with the member named, instead of at\r\n/// the first click that needed it.\r\nexport function assertHost(host: TradingHost, controlName: string): TradingHost {\r\n _required(host, 'host', 'object', controlName);\r\n\r\n _required(host.isPrimary, 'host.isPrimary', 'boolean', controlName);\r\n _required(host.t, 'host.t', 'function', controlName);\r\n\r\n _required(host.presentation, 'host.presentation', 'object', controlName);\r\n _required(host.presentation.sideText, 'host.presentation.sideText', 'function', controlName);\r\n _required(host.presentation.typeText, 'host.presentation.typeText', 'function', controlName);\r\n _required(host.presentation.statusText, 'host.presentation.statusText', 'function', controlName);\r\n _required(host.presentation.sideClass, 'host.presentation.sideClass', 'function', controlName);\r\n _required(host.presentation.pnlClass, 'host.presentation.pnlClass', 'function', controlName);\r\n\r\n _required(host.preferences, 'host.preferences', 'object', controlName);\r\n _required(host.preferences.get, 'host.preferences.get', 'function', controlName);\r\n _required(host.preferences.set, 'host.preferences.set', 'function', controlName);\r\n\r\n _required(host.cache, 'host.cache', 'object', controlName);\r\n _required(host.cache.get, 'host.cache.get', 'function', controlName);\r\n _required(host.cache.set, 'host.cache.set', 'function', controlName);\r\n\r\n _required(host.trading, 'host.trading', 'object', controlName);\r\n _required(host.trading.api, 'host.trading.api', 'object', controlName);\r\n // The calls, not just the objects holding them. An `api: {}` is the shape a\r\n // half-wired host actually has \u2014 the object gets built, the methods get\r\n // forgotten \u2014 so stopping at the object would skip exactly the members this\r\n // function exists to catch.\r\n _required(host.trading.api.getExecutions, 'host.trading.api.getExecutions', 'function', controlName);\r\n _required(host.trading.api.searchInstruments, 'host.trading.api.searchInstruments', 'function', controlName);\r\n _required(host.trading.marketData, 'host.trading.marketData', 'object', controlName);\r\n _required(host.trading.marketData.addSymbol, 'host.trading.marketData.addSymbol', 'function', controlName);\r\n _required(host.trading.marketData.removeSymbol, 'host.trading.marketData.removeSymbol', 'function', controlName);\r\n _required(host.trading.marketData.resubscribe, 'host.trading.marketData.resubscribe', 'function', controlName);\r\n _required(host.trading.marketData.getOrders, 'host.trading.marketData.getOrders', 'function', controlName);\r\n _required(host.trading.portfolioId, 'host.trading.portfolioId', 'function', controlName);\r\n _required(host.trading.pickInstrument, 'host.trading.pickInstrument', 'function', controlName);\r\n\r\n _required(host.ticker, 'host.ticker', 'object', controlName);\r\n _required(host.ticker.publish, 'host.ticker.publish', 'function', controlName);\r\n\r\n _required(host.allow, 'host.allow', 'function', controlName);\r\n _required(host.log, 'host.log', 'function', controlName);\r\n\r\n _required(host.close, 'host.close', 'function', controlName);\r\n _required(host.spawn, 'host.spawn', 'function', controlName);\r\n _required(host.persistState, 'host.persistState', 'function', controlName);\r\n _required(host.saveLayout, 'host.saveLayout', 'function', controlName);\r\n\r\n _required(host.register, 'host.register', 'function', controlName);\r\n _required(host.unregister, 'host.unregister', 'function', controlName);\r\n _required(host.broadcast, 'host.broadcast', 'function', controlName);\r\n\r\n return host;\r\n}\r\n\r\n// `typeof null` is 'object', which would let a null store through the object\r\n// checks \u2014 the one case worth spelling out, because null is exactly what an\r\n// unwired dependency looks like.\r\nfunction _required(value: unknown, path: string, kind: string, controlName: string): void {\r\n if (value === null || value === undefined || typeof value !== kind)\r\n throw new Error(`${controlName}: ${path} is required`);\r\n}\r\n", "// The identifiers a host and a control agree on for each kind of control this\n// package ships.\n//\n// These strings used to be spelled out independently in four places \u2014 a docking\n// manager's panel table, its default layouts, each control's static TYPE\n// literal and a Razor panels menu \u2014 so a typo in any one of them produced a\n// panel that opened but never received data, with nothing to compare against.\n//\n// The VALUES are load-bearing and must not be edited. A host writes them into\n// whatever it persists its layout as, so renaming one orphans every saved\n// layout that mentions it.\n//\n// Only the kinds this package implements are named here. A host that has more\n// control kinds of its own declares those itself and merges the two sets; that\n// keeps every identifier declared exactly once, by whoever owns the control it\n// names.\nexport const ControlTypes = {\n Watchlist: 'watchlist',\n ActiveOrders: 'activeOrders',\n TradeHistory: 'tradeHistory',\n Positions: 'positions',\n} as const;\n\nexport type ControlType = typeof ControlTypes[keyof typeof ControlTypes];\n", "// Value formatters \u2014 pure functions over numbers, prices, quantities, times\n// and one venue string.\n//\n// Nothing here reaches a translator, the DOM, a singleton or a window global,\n// and the module has no import and no side effect. That is why it is its own\n// file: this is the half of the presentation a control needs in ANY host. The\n// other half \u2014 a host's own vocabulary for a side, a type, a status \u2014 is\n// `TradingPresentation`, which is handed to a control rather than imported by\n// it.\ntype Numeric = number | string | null | undefined;\n\n/// Digits chosen from the magnitude of the price. A fixed two decimals\n/// collapses distinct ticks of a penny instrument onto the same \"0.44\" \u2014\n/// on the Y axis, in the order book, in the price header, everywhere \u2014 while\n/// six decimals on a $76,000 print is noise.\nexport function formatPrice(price: Numeric): string {\n if (price == null || isNaN(Number(price))) return '--';\n const n = Number(price);\n const a = Math.abs(n);\n let prec = 2;\n if (a < 1) prec = 4;\n if (a < 0.1) prec = 5;\n if (a < 0.001) prec = 6;\n if (a >= 1000) prec = 1;\n if (a >= 10000) prec = 0;\n return n.toFixed(prec);\n}\n\n/// Crypto quantities carry up to 8 decimals, so the cap is 8 rather than the\n/// locale default of 3; trailing zeros are trimmed because a size of \"1\" reads\n/// better than \"1.00000000\" in a ladder.\nexport function formatQty(qty: Numeric): string {\n if (qty == null) return '--';\n const n = Number(qty);\n if (!isFinite(n)) return '--';\n return n.toLocaleString(undefined, { maximumFractionDigits: 8 });\n}\n\n/// Wall-clock time of day, 24h, seconds included \u2014 a trade blotter is read by\n/// eye against the tape, so the format is fixed rather than locale-driven.\nexport function formatTime(dateStr: string | number | Date | null | undefined): string {\n const d = new Date(dateStr as string);\n return d.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\n/// A signed figure: profit carries an explicit `+` so a gain and a loss are\n/// told apart by the number alone, without relying on the colour class.\nexport function formatPnl(pnl: Numeric): string {\n if (pnl == null) return '--';\n const val = Number(pnl);\n const sign = val >= 0 ? '+' : '';\n return sign + val.toFixed(2);\n}\n\n/// Some venue adapters hand us a wrapped error string like\n/// \"failed to complete request (err=Forbidden): {\"code\":40310000,\"message\":\"cost basis must be >= ...\"}\"\n/// The raw form is stored for audit, but users should see the human-readable\n/// message only. Pull `message` out of the embedded JSON when present;\n/// otherwise return the reason as-is.\nexport function cleanRejectReason(reason: string | null | undefined): string {\n if (!reason) return '';\n const i = reason.indexOf('{');\n const j = reason.lastIndexOf('}');\n if (i >= 0 && j > i) {\n try {\n const parsed = JSON.parse(reason.substring(i, j + 1));\n if (parsed && typeof parsed.message === 'string' && parsed.message.length > 0)\n return parsed.message;\n } catch { /* fall through to raw */ }\n }\n return reason;\n}\n", "// Element construction for controls that build their own DOM.\n//\n// A control that clones a <template> out of the page it happens to live on\n// cannot render anywhere else, so the markup has to move into the control. It\n// then has to stay readable as markup, which four lines of createElement /\n// className / setAttribute / appendChild per element does not.\n//\n// Nothing here has an import, touches a global or knows what a trading control\n// is \u2014 it is a spelling of `document.createElement`, and the shape of the call\n// mirrors the shape of the tag it replaces:\n//\n// <div class=\"panel-header\"><span>Positions</span></div>\n// makeElement('div', 'panel-header', {}, [makeElement('span', '', {}, ['Positions'])])\n\n/// One element. `className` may be empty and `attrs` may be empty \u2014 both are\n/// then left off entirely, so the result matches markup that never carried\n/// them. Children are appended in order; a string child becomes a text node.\nexport function makeElement(\n tag: string,\n className: string,\n attrs: Record<string, string>,\n children: Array<Node | string>,\n): HTMLElement {\n const element = document.createElement(tag);\n if (className) element.className = className;\n for (const [name, value] of Object.entries(attrs)) element.setAttribute(name, value);\n for (const child of children)\n element.appendChild(typeof child === 'string' ? document.createTextNode(child) : child);\n return element;\n}\n\n/// A Bootstrap icon glyph \u2014 `<i class=\"bi bi-x\"></i>`. Every icon in a control's\n/// panel chrome is one of these, always with the `bi` base class.\nexport function makeIcon(iconClass: string): HTMLElement {\n return makeElement('i', `bi ${iconClass}`, {}, []);\n}\n\n/// An icon button from the panel chrome: one glyph, and the same text as both\n/// tooltip and accessible name. `className` carries the full class list\n/// because the buttons differ by more than one modifier\n/// (`bt-icon-btn bt-icon-cancel panel-close-btn`).\nexport function makeIconButton(\n className: string,\n label: string,\n iconClass: string,\n attrs: Record<string, string>,\n): HTMLButtonElement {\n return makeElement('button', className, { title: label, 'aria-label': label, ...attrs },\n [makeIcon(iconClass)]) as HTMLButtonElement;\n}\n\n/// The panel root every control builds: `.terminal-panel` plus the control's own\n/// modifier class, carrying the region role and its accessible name.\n///\n/// The structure is a contract in two directions and both are load-bearing. A\n/// host stylesheet targets these class names, and a docking host may lift\n/// `.panel-header`'s children into its own tab strip, which needs\n/// `.terminal-panel` to be the root's only element child.\nexport function makePanelRoot(modifierClass: string, label: string, children: Array<Node | string>): HTMLElement {\n return makeElement('div', `terminal-panel ${modifierClass}`, { role: 'region', 'aria-label': label }, children);\n}\n\n/// A unique element id for one control instance. Time plus a random tail: the\n/// time alone collides when a host restores a saved layout, which creates every\n/// panel inside one millisecond.\nexport function makePanelId(type: string): string {\n return `panel-${type}-${Date.now().toString(36)}-${Math.floor(Math.random() * 1000).toString(36)}`;\n}\n", "// Column-sort controller \u2014 the sort state behind DataGrid.\n//\n// Attach to the table's <thead>: clicking a <th data-sort=\"key\"> cycles\n// asc -> desc -> default. There is no \"unsorted\" state: a table always has a\n// deterministic order. Each table declares its default (e.g. orders newest-\n// first, trades most-recent-first) so the resting view is meaningful instead of\n// exposing the raw cache/insertion order (storage hydration + snapshot + live\n// updates land in an order that means nothing to the user). Clicking a header\n// overrides the default; cycling past desc returns to it. The owner re-renders\n// through onChange and passes its row array through apply(), which returns a\n// sorted copy, so live inserts land in the active order on the next render.\n//\n// DataGrid builds the accessors from its column declarations and owns the\n// instance; it is separate from the grid because sort state is a self-contained\n// concern with its own semantics worth pinning down on its own.\n\n/**\n * The two directions a column can be sorted in. Spelled as a const object so the\n * values have names at the call site and the union stays derived from one place.\n */\nexport const SortDirections = {\n Asc: 'asc',\n Desc: 'desc',\n} as const;\n\nexport type SortDir = typeof SortDirections[keyof typeof SortDirections];\n\nexport interface SortSpec { col: string; dir: SortDir; }\n\n// A column with no declared accessor is read off the row by its own key, which\n// needs a shape TRow never promised \u2014 so the widening happens here, once, instead\n// of loosening the row type of the whole controller.\nfunction readByKey(row: unknown, key: string): unknown {\n return row === null || row === undefined ? undefined : (row as Record<string, unknown>)[key];\n}\n\nexport class TableSort<TRow = unknown> {\n col: string | null;\n dir: SortDir;\n private _headerEl: HTMLElement | null;\n private _accessors: Record<string, (row: TRow) => unknown>;\n private _onChange: () => void;\n private _default: SortSpec | null;\n\n // `defaultSort` is the order applied when no header is explicitly selected \u2014 the table's\n // resting sort. Pass null only for a table that genuinely has no meaningful default (raw row\n // order); every real blotter should name one so its first paint is deterministic.\n constructor(headerEl: HTMLElement | null, accessors: Record<string, (row: TRow) => unknown>, onChange: () => void, defaultSort: SortSpec | null) {\n this.col = null;\n this.dir = SortDirections.Asc;\n this._headerEl = headerEl;\n this._accessors = accessors || {};\n this._onChange = onChange;\n this._default = defaultSort;\n this._updateHeader();\n\n headerEl?.addEventListener('click', (e) => {\n const tgt = e.target as Element | null;\n const th = tgt?.closest('[data-sort]') as HTMLElement | null;\n if (!th) return;\n const col = th.dataset.sort!;\n if (this.col !== col) { this.col = col; this.dir = SortDirections.Asc; }\n else if (this.dir === SortDirections.Asc) this.dir = SortDirections.Desc;\n else { this.col = null; this.dir = SortDirections.Asc; } // back to the table default\n this._updateHeader();\n this._onChange();\n });\n }\n\n // The order actually in effect: the explicitly-picked column, else the table's default.\n private _effective(): SortSpec | null {\n return this.col ? { col: this.col, dir: this.dir } : this._default;\n }\n\n /**\n * Sorted copy of rows by the effective sort (explicit column or table default). Rows with no\n * value for the sort column group at the end. Always a copy: a caller told its array is never\n * reordered must be able to rely on that for one row and no sort as much as for a sorted many.\n */\n apply(rows: TRow[]): TRow[] {\n if (!Array.isArray(rows)) return rows;\n const eff = this._effective();\n if (!eff || rows.length < 2) return [...rows];\n const col = eff.col;\n const acc = this._accessors[col] || ((r: TRow) => readByKey(r, col));\n const factor = eff.dir === SortDirections.Asc ? 1 : -1;\n return [...rows].sort((a, b) => {\n const av = acc(a);\n const bv = acc(b);\n const aEmpty = av === null || av === undefined || av === '';\n const bEmpty = bv === null || bv === undefined || bv === '';\n if (aEmpty && bEmpty) return 0;\n if (aEmpty) return 1; // empties sink regardless of direction\n if (bEmpty) return -1;\n return TableSort._compare(av, bv) * factor;\n });\n }\n\n private static _compare(a: unknown, b: unknown): number {\n const an = typeof a === 'number' ? a : Number(a);\n const bn = typeof b === 'number' ? b : Number(b);\n if (isFinite(an) && isFinite(bn)) return an - bn;\n return String(a).localeCompare(String(b));\n }\n\n private _updateHeader() {\n if (!this._headerEl) return;\n // Reflect the effective sort \u2014 including the table default \u2014 so the resting view shows why\n // the rows are ordered the way they are, not a blank header over a sorted table.\n const eff = this._effective();\n this._headerEl.querySelectorAll('[data-sort]').forEach((el: Element) => {\n const th = el as HTMLElement;\n const active = !!eff && eff.col === th.dataset.sort;\n th.classList.toggle('sort-asc', active && eff!.dir === SortDirections.Asc);\n th.classList.toggle('sort-desc', active && eff!.dir === SortDirections.Desc);\n });\n }\n}\n", "// Client-side .xlsx export \u2014 the sheet DataGrid hands its rows to, and usable on\n// its own by any web bundle. No dependency on a host app: the caller passes\n// generic (baseName, sheetName, headers, rows) and gets a real workbook.\n//\n// Builds a real OOXML workbook (not CSV renamed): a store-only ZIP with the\n// minimal SpreadsheetML part set. Strings are written as inline strings,\n// finite numbers as native numeric cells, so Excel / LibreOffice / Numbers\n// open the file without conversion warnings. No third-party libraries.\n\nconst XML_DECL = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\\r\\n';\n\nconst CONTENT_TYPES = XML_DECL\n + '<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">'\n + '<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>'\n + '<Default Extension=\"xml\" ContentType=\"application/xml\"/>'\n + '<Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\"/>'\n + '<Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"/>'\n + '</Types>';\n\nconst ROOT_RELS = XML_DECL\n + '<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">'\n + '<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"xl/workbook.xml\"/>'\n + '</Relationships>';\n\nconst WORKBOOK_RELS = XML_DECL\n + '<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">'\n + '<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"worksheets/sheet1.xml\"/>'\n + '</Relationships>';\n\nfunction workbookXml(sheetName: string): string {\n return XML_DECL\n + '<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">'\n + `<sheets><sheet name=\"${escapeXml(sheetName)}\" sheetId=\"1\" r:id=\"rId1\"/></sheets>`\n + '</workbook>';\n}\n\nfunction escapeXml(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n}\n\n// 0 -> \"A\", 25 -> \"Z\", 26 -> \"AA\", ...\nfunction colRef(i: number): string {\n let ref = '';\n for (let n = i; n >= 0; n = Math.floor(n / 26) - 1)\n ref = String.fromCharCode(65 + (n % 26)) + ref;\n return ref;\n}\n\nfunction cellXml(ref: string, value: unknown): string {\n if (value === null || value === undefined || value === '') return '';\n if (typeof value === 'number' && isFinite(value))\n return `<c r=\"${ref}\"><v>${value}</v></c>`;\n return `<c r=\"${ref}\" t=\"inlineStr\"><is><t xml:space=\"preserve\">${escapeXml(String(value))}</t></is></c>`;\n}\n\nfunction sheetXml(headers: string[], rows: unknown[][]): string {\n let xml = XML_DECL\n + '<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><sheetData>';\n const all: unknown[][] = [headers, ...rows];\n for (let r = 0; r < all.length; r++) {\n xml += `<row r=\"${r + 1}\">`;\n for (let c = 0; c < all[r].length; c++)\n xml += cellXml(colRef(c) + (r + 1), all[r][c]);\n xml += '</row>';\n }\n return xml + '</sheetData></worksheet>';\n}\n\n// --- store-only ZIP writer -------------------------------------------------\n\nconst CRC_TABLE = (() => {\n const table = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++)\n c = (c & 1) ? 0xEDB88320 ^ (c >>> 1) : c >>> 1;\n table[n] = c >>> 0;\n }\n return table;\n})();\n\nfunction crc32(data: Uint8Array): number {\n let crc = 0xFFFFFFFF;\n for (let i = 0; i < data.length; i++)\n crc = CRC_TABLE[(crc ^ data[i]) & 0xFF] ^ (crc >>> 8);\n return (crc ^ 0xFFFFFFFF) >>> 0;\n}\n\nfunction zip(entries: { name: string; text: string }[]): Blob {\n const encoder = new TextEncoder();\n const parts: Uint8Array[] = [];\n const central: Uint8Array[] = [];\n let offset = 0;\n\n for (const entry of entries) {\n const name = encoder.encode(entry.name);\n const data = encoder.encode(entry.text);\n const crc = crc32(data);\n\n const local = new Uint8Array(30 + name.length);\n const lv = new DataView(local.buffer);\n lv.setUint32(0, 0x04034b50, true); // local file header signature\n lv.setUint16(4, 20, true); // version needed\n lv.setUint32(14, crc, true);\n lv.setUint32(18, data.length, true); // compressed (stored) size\n lv.setUint32(22, data.length, true); // uncompressed size\n lv.setUint16(26, name.length, true);\n local.set(name, 30);\n parts.push(local, data);\n\n const dir = new Uint8Array(46 + name.length);\n const dv = new DataView(dir.buffer);\n dv.setUint32(0, 0x02014b50, true); // central directory signature\n dv.setUint16(4, 20, true); // version made by\n dv.setUint16(6, 20, true); // version needed\n dv.setUint32(16, crc, true);\n dv.setUint32(20, data.length, true);\n dv.setUint32(24, data.length, true);\n dv.setUint16(28, name.length, true);\n dv.setUint32(42, offset, true); // local header offset\n dir.set(name, 46);\n central.push(dir);\n\n offset += local.length + data.length;\n }\n\n const dirSize = central.reduce((sum, d) => sum + d.length, 0);\n const eocd = new Uint8Array(22);\n const ev = new DataView(eocd.buffer);\n ev.setUint32(0, 0x06054b50, true); // end of central directory\n ev.setUint16(8, entries.length, true);\n ev.setUint16(10, entries.length, true);\n ev.setUint32(12, dirSize, true);\n ev.setUint32(16, offset, true);\n\n return new Blob([...parts, ...central, eocd] as BlobPart[], {\n type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n });\n}\n\n// --- public API ------------------------------------------------------------\n\nexport const TableExport = {\n /**\n * Build the workbook and trigger a browser download as\n * `<baseName>-YYYYMMDD-HHMMSS.xlsx`. Rows are exported exactly as the\n * caller passes them (i.e. in the currently rendered/sorted order).\n */\n download(baseName: string, sheetName: string, headers: string[], rows: unknown[][]): void {\n // Sheet names are capped at 31 chars and reject []:*?/\\ \u2014 sanitize\n // localized captions so a long/exotic translation can't corrupt the file.\n const safeSheet = (sheetName || '').replace(/[\\[\\]:*?/\\\\]/g, ' ').slice(0, 31).trim() || 'Sheet1';\n const blob = zip([\n { name: '[Content_Types].xml', text: CONTENT_TYPES },\n { name: '_rels/.rels', text: ROOT_RELS },\n { name: 'xl/workbook.xml', text: workbookXml(safeSheet) },\n { name: 'xl/_rels/workbook.xml.rels', text: WORKBOOK_RELS },\n { name: 'xl/worksheets/sheet1.xml', text: sheetXml(headers, rows) },\n ]);\n const stamp = new Date().toISOString().slice(0, 19).replace(/[-:]/g, '').replace('T', '-');\n const a = document.createElement('a');\n a.href = URL.createObjectURL(blob);\n a.download = `${baseName}-${stamp}.xlsx`;\n document.body.appendChild(a);\n a.click();\n a.remove();\n setTimeout(() => URL.revokeObjectURL(a.href), 5000);\n },\n};\n", "// DataGrid \u2014 a column-driven table.\n//\n// A blotter used to declare its columns three times: the <thead> cells in the\n// server-rendered markup, the sort accessors in the widget constructor, and the\n// export header/row arrays in its export routine. Nothing kept the three in\n// step, and the body was built by concatenating innerHTML, which forces every\n// interactive cell into an inline `onclick=\"someGlobal.doThing(id)\"` attribute\n// because a string cannot carry a listener.\n//\n// Here a column is declared once \u2014 key, header, how to read the value, how to\n// render it, how to class it, whether it exports \u2014 and the grid owns the header,\n// the body, the sort state and the sheet. Two things a naive column pipeline\n// cannot express are first-class:\n//\n// * `render()` may return a Node. That is how a cell holds a real control with\n// its own addEventListener instead of an inline handler reaching a global.\n// * Pinned rows sit outside the sort and outside the export \u2014 a positions\n// balance summary stays on top no matter which column the user sorts by.\n//\n// The grid renders elements, never HTML strings, so nothing here can be an\n// injection site. Colour stays where it was: the caller returns class names\n// (`cellClass` / `rowClass`) and the host stylesheet decides what they look\n// like.\n//\n// Three class names come out of the package itself, and an adopting site has to\n// style them: `grid-empty` on the cell that spans the table when there is\n// nothing to show, `visually-hidden` on a header whose caption is for screen\n// readers only, and `sort-asc` / `sort-desc` on the sorted header (emitted by\n// TableSort). The first is ours; the other two are spelled the way Bootstrap\n// spells them, which is a coupling worth knowing about before adopting.\nimport { TableSort, type SortSpec } from './table-sort.js';\nimport { TableExport } from './table-export.js';\n\n/** Where a pinned row sits relative to the sorted body rows. */\nexport const GridPinnedPlacements = {\n Top: 'top',\n Bottom: 'bottom',\n} as const;\n\nexport type GridPinnedPlacement = typeof GridPinnedPlacements[keyof typeof GridPinnedPlacements];\n\nexport interface GridColumn<TRow> {\n /**\n * Stable identity of the column: stamped as `data-sort` on the header cell\n * (which is what TableSort keys off) and as `data-col` on every body cell,\n * and the key `cellElement()` takes.\n */\n key: string;\n\n /**\n * Caption, already localized. The grid does no translation \u2014 a host with a\n * translator resolves the string before declaring the column.\n */\n header: string;\n\n /** Class list for the header cell (alignment, width hints). */\n headerClass?: string;\n\n /**\n * Render the caption into a `.visually-hidden` span instead of visible text:\n * the column is announced to a screen reader but shows no header, which is\n * what an actions column wants.\n */\n headerHidden?: boolean;\n\n /**\n * This row's value for the column. Drives the sort, and is both the default\n * cell content and the default exported value. A column that declares no\n * value has nothing to sort by, so its header is not clickable.\n */\n value?(row: TRow): unknown;\n\n /**\n * Display content. A string becomes the cell's text; a Node is appended as\n * it is, so the cell can hold a button, an icon or any element carrying its\n * own listeners.\n */\n render?(row: TRow): string | Node;\n\n /**\n * Class list for this row's cell \u2014 the colouring third (`side-buy`,\n * `pnl-negative`, `cell-editable`, \u2026). The host stylesheet owns the looks.\n */\n cellClass?(row: TRow): string;\n\n /**\n * Wire behaviour onto the whole cell once its content is in place. For an\n * interaction that belongs to the cell rather than to a control inside it \u2014\n * double-clicking a price cell to edit it. A control gets its own listener\n * in `render()` instead.\n */\n bindCell?(td: HTMLTableCellElement, row: TRow): void;\n\n /**\n * Whether the column appears in the exported sheet. An exportable column\n * must be able to produce a value (`value` or `exportValue`).\n */\n exportable: boolean;\n\n /**\n * Exported value, when it differs from `value`: the localized text the user\n * reads rather than the raw enum behind it, or the raw number rather than\n * the formatted string on screen.\n */\n exportValue?(row: TRow): unknown;\n}\n\nexport interface GridPinnedCell {\n content: string | Node;\n className: string;\n}\n\n/**\n * A row the grid renders but does not own the data of: it is not sorted, not\n * exported, and its cells are supplied ready-made because it does not share the\n * shape the columns read (a balance summary under position columns).\n */\nexport interface GridPinnedRow {\n key: string;\n className: string;\n place: GridPinnedPlacement;\n /**\n * One cell per column, in column order. A shorter list leaves the remaining\n * columns empty; a longer one is a declaration mistake and throws.\n */\n cells: GridPinnedCell[];\n}\n\nexport interface GridExportData {\n headers: string[];\n rows: unknown[][];\n}\n\nexport interface GridOptions<TRow> {\n /** The `<thead>` the grid renders the header row into. Emptied on construction. */\n head: HTMLElement;\n /** The `<tbody>` the grid renders rows into. Emptied on every render. */\n body: HTMLElement;\n columns: GridColumn<TRow>[];\n /**\n * The order in effect while no header is selected. Null only for a table with\n * genuinely no meaningful resting order \u2014 see TableSort.\n */\n defaultSort: SortSpec | null;\n /**\n * Stable identity of a row, used to find its element again after a render\n * (patch a single cell, start an inline edit). Must be unique per row; when\n * two rows share a key the later one wins the lookup.\n */\n rowKey(row: TRow): string;\n /** Localized text for the row shown when there is nothing to display. */\n emptyText: string;\n rowClass?(row: TRow): string;\n /** Wire behaviour onto the whole row (selecting an instrument by clicking it). */\n bindRow?(tr: HTMLTableRowElement, row: TRow): void;\n /** Rows outside the sort, re-read on every render so they can track live data. */\n pinnedRows?(): GridPinnedRow[];\n /**\n * Cap on how many sorted rows are painted. Only rendering is capped \u2014 the\n * export still covers every row the grid holds, which is what a watchlist\n * wants: a screen-sized table over a full sheet.\n */\n renderLimit?: number;\n /**\n * Called once the body has been repainted. The grid owns the header\n * listener, so a sort click re-renders without the caller being involved \u2014\n * this is the only hook a caller has for work that depends on *which rows\n * are now on screen* (a watchlist re-subscribing to the visible symbols).\n *\n * Not called for the paint the constructor does: the grid holds no rows\n * yet, so there is nothing on screen to react to, and the caller does not\n * hold its own reference to the grid until the constructor returns.\n */\n afterRender?(): void;\n}\n\nexport class DataGrid<TRow> {\n readonly options: GridOptions<TRow>;\n readonly sort: TableSort<TRow>;\n private _rows: TRow[];\n private _rowEls: Map<string, HTMLTableRowElement>;\n private _cellEls: Map<string, Map<string, HTMLTableCellElement>>;\n\n constructor(options: GridOptions<TRow>) {\n for (const col of options.columns) {\n if (col.exportable && !col.value && !col.exportValue)\n throw new Error(`DataGrid: column \"${col.key}\" is exportable but declares no value to export`);\n }\n\n this.options = options;\n this._rows = [];\n this._rowEls = new Map();\n this._cellEls = new Map();\n\n const accessors: Record<string, (row: TRow) => unknown> = {};\n for (const col of options.columns) {\n if (col.value) accessors[col.key] = col.value;\n }\n\n // The header has to exist before TableSort is constructed: it marks the\n // active column on the cells it finds under `head` right away, so that the\n // resting sort is visible on first paint and not only after a click.\n this._renderHead();\n this.sort = new TableSort<TRow>(options.head, accessors, () => this.render(), options.defaultSort);\n this._paint();\n }\n\n /**\n * The rows the grid holds, in the order they were handed over. The grid keeps\n * the caller's array by reference: a caller that merges a live delta into it\n * and calls `render()` repaints from the current contents.\n */\n get rows(): TRow[] {\n return this._rows;\n }\n\n /**\n * Rows in the order currently in effect (the picked column, else the table\n * default). A sorted copy \u2014 the held array is never reordered.\n */\n sortedRows(): TRow[] {\n return this.sort.apply(this._rows);\n }\n\n setRows(rows: TRow[]): void {\n this._rows = rows || [];\n this.render();\n }\n\n render(): void {\n this._paint();\n if (this.options.afterRender) this.options.afterRender();\n }\n\n private _paint(): void {\n this._rowEls.clear();\n this._cellEls.clear();\n\n const pinned = this.options.pinnedRows ? this.options.pinnedRows() : [];\n const sorted = this.sortedRows();\n const painted = this.options.renderLimit != null ? sorted.slice(0, this.options.renderLimit) : sorted;\n\n const children: Node[] = [];\n for (const row of pinned) {\n if (row.place === GridPinnedPlacements.Top) children.push(this._pinnedRow(row));\n }\n // A pinned row is content, so a table showing only a balance summary is not\n // empty \u2014 the \"nothing here\" row would read as a contradiction next to it.\n if (painted.length === 0 && pinned.length === 0) children.push(this._emptyRow());\n for (const row of painted) children.push(this._bodyRow(row));\n for (const row of pinned) {\n if (row.place === GridPinnedPlacements.Bottom) children.push(this._pinnedRow(row));\n }\n\n this.options.body.replaceChildren(...children);\n }\n\n /**\n * The rendered row with this key, or null when it is not on screen (filtered\n * out, or past `renderLimit`).\n */\n rowElement(rowKey: string): HTMLTableRowElement | null {\n return this._rowEls.get(rowKey) || null;\n }\n\n /**\n * The rendered cell at (row, column) \u2014 how a caller patches one cell in place\n * instead of repainting the table, and how it finds the cell to edit.\n */\n cellElement(rowKey: string, columnKey: string): HTMLTableCellElement | null {\n return this._cellEls.get(rowKey)?.get(columnKey) || null;\n }\n\n /**\n * Header captions and cell values of the exportable columns, over every held\n * row in the order in effect. Pure \u2014 separate from `download` so the sheet\n * content can be asserted without a browser.\n */\n exportData(): GridExportData {\n const columns = this.options.columns.filter(col => col.exportable);\n return {\n headers: columns.map(col => col.header),\n rows: this.sortedRows().map(row => columns.map(col => {\n const accessor = col.exportValue || col.value;\n return accessor ? accessor(row) : null;\n })),\n };\n }\n\n /** Export to `<baseName>-<timestamp>.xlsx` in the order on screen. */\n download(baseName: string, sheetName: string): void {\n const data = this.exportData();\n TableExport.download(baseName, sheetName, data.headers, data.rows);\n }\n\n private _renderHead(): void {\n const tr = document.createElement('tr');\n for (const col of this.options.columns) {\n const th = document.createElement('th');\n th.setAttribute('scope', 'col');\n if (col.headerClass) th.className = col.headerClass;\n // Sortable exactly when there is a value to sort by. TableSort binds to\n // the cells carrying `data-sort`, so a column without one is inert.\n if (col.value) th.dataset.sort = col.key;\n if (col.headerHidden) {\n const label = document.createElement('span');\n label.className = 'visually-hidden';\n label.textContent = col.header;\n th.appendChild(label);\n } else {\n th.textContent = col.header;\n }\n tr.appendChild(th);\n }\n this.options.head.replaceChildren(tr);\n }\n\n private _bodyRow(row: TRow): HTMLTableRowElement {\n const tr = document.createElement('tr') as HTMLTableRowElement;\n const key = this.options.rowKey(row);\n const rowClass = this.options.rowClass ? this.options.rowClass(row) : '';\n if (rowClass) tr.className = rowClass;\n tr.dataset.rowKey = key;\n\n const cells = new Map<string, HTMLTableCellElement>();\n for (const col of this.options.columns) {\n const td = document.createElement('td') as HTMLTableCellElement;\n td.dataset.col = col.key;\n const cellClass = col.cellClass ? col.cellClass(row) : '';\n if (cellClass) td.className = cellClass;\n const content = col.render ? col.render(row) : DataGrid._text(col.value ? col.value(row) : null);\n // A renderer is declared to return a string or a Node, but a value that\n // fell through a formatter's branches arrives as whatever it was - a raw\n // status number, say. Passing that to appendChild throws and takes the\n // whole table down over one unexpected row, so anything that is not a Node\n // is rendered as text. nodeType rather than instanceof Node: the tests run\n // against a fake DOM with no Node constructor in scope.\n if (content !== null && typeof content === 'object' && 'nodeType' in content) td.appendChild(content);\n else td.textContent = DataGrid._text(content);\n if (col.bindCell) col.bindCell(td, row);\n tr.appendChild(td);\n cells.set(col.key, td);\n }\n\n if (this.options.bindRow) this.options.bindRow(tr, row);\n this._rowEls.set(key, tr);\n this._cellEls.set(key, cells);\n return tr;\n }\n\n private _pinnedRow(pinned: GridPinnedRow): HTMLTableRowElement {\n if (pinned.cells.length > this.options.columns.length) {\n throw new Error(`DataGrid: pinned row \"${pinned.key}\" declares ${pinned.cells.length} cells `\n + `for ${this.options.columns.length} columns`);\n }\n\n const tr = document.createElement('tr') as HTMLTableRowElement;\n if (pinned.className) tr.className = pinned.className;\n tr.dataset.rowKey = pinned.key;\n\n const cells = new Map<string, HTMLTableCellElement>();\n for (let i = 0; i < this.options.columns.length; i++) {\n const col = this.options.columns[i];\n const td = document.createElement('td') as HTMLTableCellElement;\n td.dataset.col = col.key;\n const cell = pinned.cells[i];\n if (cell) {\n if (cell.className) td.className = cell.className;\n if (typeof cell.content === 'string') td.textContent = cell.content;\n else td.appendChild(cell.content);\n }\n tr.appendChild(td);\n cells.set(col.key, td);\n }\n\n this._rowEls.set(pinned.key, tr);\n this._cellEls.set(pinned.key, cells);\n return tr;\n }\n\n private _emptyRow(): HTMLTableRowElement {\n const tr = document.createElement('tr') as HTMLTableRowElement;\n const td = document.createElement('td') as HTMLTableCellElement;\n td.className = 'grid-empty';\n td.colSpan = this.options.columns.length;\n td.textContent = this.options.emptyText;\n tr.appendChild(td);\n return tr;\n }\n\n private static _text(value: unknown): string {\n return value === null || value === undefined ? '' : String(value);\n }\n}\n", "// Active orders \u2014 multi-instance.\n//\n// Builds its own DOM (see `_buildRoot`) rather than cloning a <template> out of\n// the page, so it can be constructed by any host that supplies a `TradingHost`.\n// Every instance shares the same data source (a host refresh / an order update\n// off the socket); each update fans through the host's broadcast so duplicates\n// stay in sync.\n//\n// The table itself is `DataGrid` from `@stocksharp/grids`: the columns below are\n// the single declaration of this blotter \u2014 caption, value, rendering, colour\n// class and export all live together, and the <thead> is left empty for the\n// grid to fill. Cells that hold a control return a real Node with its own\n// listener, so nothing here reaches a global through an inline onclick\n// attribute; the callbacks arrive as deps instead.\nimport { cleanRejectReason, formatPrice, formatQty } from './formatters.js';\nimport { makeElement, makeIconButton, makePanelId, makePanelRoot } from './dom.js';\nimport { ControlTypes } from './control-types.js';\nimport { TradingHost, assertHost } from './trading-host.js';\nimport type { OrderRow } from './trading-data.js';\nimport { DataGrid, GridColumn } from '@stocksharp/grids/source/data-grid';\n\n/// StockSharp order states as they arrive on the wire. The blotter branches on\n/// them for row colour, for whether a cell can be edited in place and for what\n/// the \u00D7 button does, so they are named once here instead of appearing as bare\n/// numbers at each branch.\nexport const OrderStates = {\n PendingRisk: 1,\n Sent: 2,\n Active: 3,\n PartiallyFilled: 4,\n Filled: 5,\n Rejected: 6,\n Cancelled: 7,\n} as const;\n\n/// What the blotter needs beyond the host port. All required: a panel that\n/// cannot cancel, modify or reload its orders is not this panel.\nexport interface ActiveOrdersDeps {\n host: TradingHost;\n cancelOrder(orderId: number): void;\n dismissOrder(orderId: number): void;\n editOrderField(orderId: number, field: string): void;\n replaceOrder(orderId: number, quantity: number, limitPrice: number, stopPrice: number): void;\n cancelAllOrders(): void;\n refreshOrders(): void;\n}\n\nexport class ActiveOrdersWidget {\n static TYPE = ControlTypes.ActiveOrders;\n\n rootEl: HTMLElement;\n el: HTMLElement | null;\n // `//` rather than `///` from here down \u2014 see the note in positions-widget.\n _host: TradingHost;\n _deps: ActiveOrdersDeps;\n _closeBtn: HTMLElement | null;\n _cancelAllBtn: HTMLElement | null;\n _refreshBtn: HTMLElement | null;\n _exportBtn: HTMLElement | null;\n _orders: OrderRow[];\n _grid: DataGrid<OrderRow> | null;\n\n static create(hostEl: HTMLElement, state: Record<string, unknown>, deps: ActiveOrdersDeps): ActiveOrdersWidget {\n // Assert before building: the markup below is localized through the\n // host, so a missing host has to fail here rather than render a panel\n // captioned with raw English keys.\n const host = assertHost(deps?.host, 'ActiveOrdersWidget');\n const root = ActiveOrdersWidget._buildRoot(host);\n root.id = makePanelId(ActiveOrdersWidget.TYPE);\n hostEl.appendChild(root);\n return new ActiveOrdersWidget(root, state || {}, deps);\n }\n\n // The panel's markup. The host stylesheet reads this structure, and a\n // docking host lifts `.panel-header`'s children into its tab strip.\n //\n // The rail's first two buttons are the ones that could not come across\n // unchanged from the terminal's Razor template: they were inline\n // `onclick=\"terminalApp.cancelAll()\"` / `refreshOrders()`, references to a\n // global this control must not have. They carry `.panel-cancel-all-btn` and\n // `.panel-refresh-btn` now \u2014 the latter the name the other blotters' rails\n // already give the identical button \u2014 and are wired to deps. Cancel-all\n // keeps a distinct accessible name from its tooltip, which is why it states\n // `aria-label` rather than taking the tooltip for both.\n static _buildRoot(host: TradingHost): HTMLElement {\n return makePanelRoot('active-orders-panel', host.t('ActiveOrders'), [\n makeElement('div', 'panel-header', {}, [\n makeElement('span', '', {}, [host.t('OpenOrders')]),\n makeIconButton('bt-icon-btn bt-icon-cancel panel-close-btn', host.t('ClosePanel'), 'bi-x', { type: 'button' }),\n ]),\n makeElement('div', 'panel-body panel-body-with-rail', {}, [\n makeElement('div', 'panel-body-content', {}, [\n makeElement('table', 'terminal-table active-orders-table', { role: 'table', 'aria-label': host.t('ActiveOrdersList') }, [\n makeElement('thead', '', {}, []),\n makeElement('tbody', 'active-orders-body', {}, []),\n ]),\n ]),\n makeElement('div', 'panel-rail', { role: 'toolbar', 'aria-label': host.t('ActiveOrdersActions') }, [\n makeIconButton('bt-icon-btn bt-icon-cancel-all panel-cancel-all-btn', host.t('CancelAll'), 'bi-x-circle',\n { 'aria-label': host.t('CancelAllOrders') }),\n makeIconButton('bt-icon-btn panel-refresh-btn', host.t('Refresh'), 'bi-arrow-clockwise', {}),\n makeIconButton('bt-icon-btn panel-export-btn', host.t('ExportToExcel'), 'bi-file-earmark-spreadsheet', {}),\n ]),\n ]),\n ]);\n }\n\n constructor(rootEl: HTMLElement, _state: Record<string, unknown>, deps: ActiveOrdersDeps) {\n this._host = assertHost(deps?.host, 'ActiveOrdersWidget');\n for (const name of ['cancelOrder', 'dismissOrder', 'editOrderField', 'replaceOrder', 'cancelAllOrders', 'refreshOrders'] as const) {\n if (typeof deps?.[name] !== 'function')\n throw new Error(`ActiveOrdersWidget: dep \"${name}\" is required`);\n }\n\n this.rootEl = rootEl;\n this._deps = deps;\n this.el = this.rootEl.querySelector('.active-orders-body');\n this._closeBtn = this.rootEl.querySelector('.panel-close-btn');\n this._cancelAllBtn = this.rootEl.querySelector('.panel-cancel-all-btn');\n this._refreshBtn = this.rootEl.querySelector('.panel-refresh-btn');\n this._exportBtn = this.rootEl.querySelector('.panel-export-btn');\n this._orders = [];\n\n this._closeBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n this._host.close();\n });\n\n this._cancelAllBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n this._deps.cancelAllOrders();\n });\n\n this._refreshBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n this._deps.refreshOrders();\n });\n\n this._exportBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n this._export();\n });\n\n const head = this.rootEl.querySelector('.active-orders-table thead');\n this._grid = head && this.el\n ? new DataGrid<OrderRow>({\n head: head as HTMLElement,\n body: this.el,\n columns: this._columns(),\n // Newest order on top by default (localId is monotonic) \u2014 the resting view puts the\n // user's most recent actions where they look, instead of raw cache order. Natural\n // array order is \"newest first\" too (deltas unshift), but only by accident; any\n // header click re-renders the same array through the sorter.\n defaultSort: { col: 'id', dir: 'desc' },\n // The register tx, not the friendly localId shown in the ID column: it is what\n // cancel / replace / inline edit address an order by.\n rowKey: (o) => String(o.id),\n emptyText: this._host.t('NoActiveOrders'),\n // Terminal rows are greyed out so the live ones stay visually prominent.\n rowClass: (o) => ActiveOrdersWidget._rowClass(o),\n })\n : null;\n\n this._host.register(this);\n }\n\n dispose(): void {\n this._host.unregister(this);\n try { this.rootEl.remove(); } catch { /* already detached */ }\n }\n\n update(orders: OrderRow[]): void {\n this._orders = orders || [];\n this._grid?.setRows(this._orders);\n }\n\n // Export the table to .xlsx in the currently rendered (sorted) order, with the\n // same localized side/type/status texts the user sees on screen \u2014 the columns\n // carry both forms, so the sheet cannot drift from the table.\n _export(): void {\n this._grid?.download('orders', this._host.t('OpenOrders'));\n }\n\n /// Apply a single order delta from the feed. Insert if new, merge if known.\n /// Nothing drops out of the list: Filled and Cancelled rows stay so the user\n /// can watch an order's transitions instead of having a row vanish, and a\n /// Rejected row stays so its reason can be read on hover and dismissed\n /// explicitly through the \u00D7 button.\n applyDelta(order: OrderRow): void {\n if (!order || order.id == null) return;\n const idx = this._orders.findIndex(o => o.id === order.id);\n if (idx >= 0)\n this._orders[idx] = { ...this._orders[idx], ...order };\n else\n this._orders.unshift(order);\n this.update(this._orders);\n }\n\n /// Remove a row from the local view without touching the server. Used by the\n /// \u00D7 button on a terminal order (nothing left to cancel), and in any other\n /// client-side dismiss path.\n removeOrder(orderId: number): void {\n const idx = this._orders.findIndex(o => o.id === orderId);\n if (idx >= 0) {\n this._orders.splice(idx, 1);\n this.update(this._orders);\n }\n }\n\n getOrder(orderId: number): OrderRow | undefined {\n return this._orders.find(o => o.id === orderId);\n }\n\n startInlineEdit(orderId: number, field: 'quantity' | 'limitPrice' | 'stopPrice'): void {\n const order = this.getOrder(orderId);\n if (!order) return;\n // Addressed by the grid's row key (the register tx) and the column key, so\n // the edit lands on the right cell whatever the sort is. A lookup that\n // scanned the rendered ID column for the order id would never match, because\n // that column shows the friendly counter.\n const cell = this._grid?.cellElement(String(orderId), field);\n if (!cell || cell.querySelector('input')) return;\n const currentValue = order[field];\n const input = document.createElement('input');\n input.type = 'number';\n input.className = 'inline-edit-input';\n input.value = String(currentValue ?? '');\n input.step = field === 'quantity' ? '1' : '0.01';\n input.min = field === 'quantity' ? '1' : '0.01';\n cell.textContent = '';\n cell.appendChild(input);\n input.focus();\n input.select();\n const commit = () => {\n const newVal = parseFloat(input.value);\n if (isNaN(newVal) || newVal <= 0) { this.update(this._orders); return; }\n if (newVal === currentValue) { this.update(this._orders); return; }\n const updated = { quantity: order.quantity, limitPrice: order.limitPrice, stopPrice: order.stopPrice };\n updated[field] = newVal;\n this._deps.replaceOrder(orderId, updated.quantity!, updated.limitPrice!, updated.stopPrice!);\n };\n input.addEventListener('blur', commit);\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') { e.preventDefault(); input.blur(); }\n if (e.key === 'Escape') { this.update(this._orders); }\n });\n }\n\n // The blotter's single column declaration: what the header says, what the\n // grid sorts on, what the cell shows, how it is coloured, and what reaches\n // the exported sheet.\n _columns(): GridColumn<OrderRow>[] {\n // `label`, not `t` \u2014 every row lambda below binds `o` for the order,\n // but keeping the translator under a name of its own reads clearer\n // next to the presentation object it sits beside.\n const label = (key: string) => this._host.t(key);\n const presentation = this._host.presentation;\n return [\n {\n key: 'id',\n header: label('ID'),\n exportable: true,\n // Per-user friendly counter (1, 2, 3, \u2026) issued by the host. `o.id`\n // keeps the register tx for cancel / replace routing; `o.localId` is\n // just the badge the user wants to see. Rows cached from before the\n // counter shipped have no localId \u2014 fall back to id so they don't go\n // blank until the next snapshot replay reassigns one.\n value: (o) => o.localId ?? o.id,\n },\n {\n key: 'instrument',\n header: label('Sym'),\n exportable: true,\n value: (o) => o.instrument,\n },\n {\n key: 'side',\n header: label('Side'),\n exportable: true,\n value: (o) => o.side,\n render: (o) => presentation.sideText(o.side!),\n cellClass: (o) => presentation.sideClass(o.side!),\n exportValue: (o) => presentation.sideText(o.side!),\n },\n {\n key: 'type',\n header: label('Type'),\n exportable: true,\n value: (o) => o.type,\n render: (o) => presentation.typeText(o.type!, o.limitPrice!, o.stopPrice!),\n exportValue: (o) => presentation.typeText(o.type!, o.limitPrice!, o.stopPrice!),\n },\n {\n key: 'quantity',\n header: label('Qty'),\n exportable: true,\n value: (o) => o.quantity,\n render: (o) => formatQty(o.quantity),\n cellClass: (o) => ActiveOrdersWidget._editableClass(o, 'quantity'),\n bindCell: (td, o) => this._bindInlineEdit(td, o, 'quantity'),\n },\n {\n key: 'limitPrice',\n header: label('Price'),\n exportable: true,\n value: (o) => o.limitPrice,\n render: (o) => o.limitPrice ? formatPrice(o.limitPrice) : label('MKT'),\n cellClass: (o) => ActiveOrdersWidget._editableClass(o, 'limitPrice'),\n bindCell: (td, o) => this._bindInlineEdit(td, o, 'limitPrice'),\n exportValue: (o) => o.limitPrice ?? label('MKT'),\n },\n {\n key: 'stopPrice',\n header: label('Stop'),\n exportable: true,\n value: (o) => o.stopPrice,\n render: (o) => o.stopPrice ? formatPrice(o.stopPrice) : '--',\n cellClass: (o) => ActiveOrdersWidget._editableClass(o, 'stopPrice'),\n bindCell: (td, o) => this._bindInlineEdit(td, o, 'stopPrice'),\n exportValue: (o) => o.stopPrice ?? '',\n },\n {\n key: 'status',\n header: label('Status'),\n exportable: true,\n value: (o) => o.status,\n render: (o) => this._statusCell(o),\n exportValue: (o) => presentation.statusText(o.status!),\n },\n {\n key: 'actions',\n header: label('Actions'),\n headerHidden: true,\n exportable: false,\n cellClass: () => 'position-actions',\n render: (o) => this._actionButton(o),\n },\n ];\n }\n\n static _rowClass(order: OrderRow): string {\n if (order.status === OrderStates.Filled) return 'order-filled';\n if (order.status === OrderStates.Rejected) return 'order-rejected';\n if (order.status === OrderStates.Cancelled) return 'order-cancelled';\n return '';\n }\n\n // An order can still be modified while the venue holds it. A market order has\n // no limit price and an unconditional order no stop price, so those cells have\n // nothing to edit even then.\n static _canEdit(order: OrderRow, field: 'quantity' | 'limitPrice' | 'stopPrice'): boolean {\n const modifiable = order.status === OrderStates.Active || order.status === OrderStates.Sent;\n return modifiable && (field === 'quantity' || !!order[field]);\n }\n\n static _editableClass(order: OrderRow, field: 'quantity' | 'limitPrice' | 'stopPrice'): string {\n return ActiveOrdersWidget._canEdit(order, field) ? 'cell-editable' : '';\n }\n\n // Double-click to edit belongs to the whole cell rather than to a control\n // inside it, which is why it is wired here instead of returned by render().\n _bindInlineEdit(td: HTMLTableCellElement, order: OrderRow, field: 'quantity' | 'limitPrice' | 'stopPrice'): void {\n if (!ActiveOrdersWidget._canEdit(order, field)) return;\n td.addEventListener('dblclick', () => this._deps.editOrderField(order.id!, field));\n }\n\n // Status text, plus a hoverable icon carrying the rejection reason. Some\n // venues wrap the human-readable rejection inside a JSON blob;\n // cleanRejectReason extracts `.message` and falls back to the raw string.\n // The reason goes on the element's title property, so no quote escaping is\n // involved the way it was when this row was built as markup.\n _statusCell(order: OrderRow): string | Node {\n const text = this._host.presentation.statusText(order.status!);\n const reason = order.status === OrderStates.Rejected ? cleanRejectReason(order.rejectReason) : '';\n if (!reason) return text;\n\n const cell = document.createDocumentFragment();\n cell.appendChild(document.createTextNode(text + ' '));\n const icon = document.createElement('i');\n icon.className = 'bi bi-question-circle reject-reason-icon';\n icon.title = reason;\n cell.appendChild(icon);\n return cell;\n }\n\n // The \u00D7 button, wired to the controller through deps. Status decides what it\n // means: Pending / Active is a real cancel over the wire, while Filled /\n // Rejected / Cancelled have nothing left to cancel \u2014 the row is history kept\n // around so the user can read its final state, so the button dismisses it\n // locally.\n _actionButton(order: OrderRow): Node {\n const isTerminal = order.status === OrderStates.Filled\n || order.status === OrderStates.Rejected\n || order.status === OrderStates.Cancelled;\n const title = isTerminal ? this._host.t('Dismiss') : this._host.t('Cancel order');\n\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'bt-icon-btn bt-icon-cancel';\n button.title = title;\n button.setAttribute('aria-label', `${title} #${order.id}`);\n const icon = document.createElement('i');\n icon.className = 'bi bi-x-circle';\n button.appendChild(icon);\n button.addEventListener('click', () => {\n if (isTerminal) this._deps.dismissOrder(order.id!);\n else this._deps.cancelOrder(order.id!);\n });\n return button;\n }\n}\n", "// Positions \u2014 multi-instance.\n//\n// Builds its own DOM (see `_buildRoot`) rather than cloning a <template> out of\n// the page it happens to be rendered on, so it can be constructed by any host\n// that supplies a `TradingHost`. Every instance shares the same data source\n// (the host's refresh / a position update off the socket); the host broadcasts\n// each update to every live instance so duplicates of the panel render in\n// lockstep.\n//\n// The table is `DataGrid` from `@stocksharp/grids`: the columns below are this\n// blotter's single declaration and the <thead> is left empty for the grid to\n// fill. The cash balance is a pinned row \u2014 a different shape from a position,\n// so it supplies its own cells, sits outside the sort and stays out of the\n// exported sheet.\nimport { formatPnl, formatPrice } from './formatters.js';\nimport { makeElement, makeIconButton, makePanelId, makePanelRoot } from './dom.js';\nimport { ControlTypes } from './control-types.js';\nimport { TradingHost, assertHost } from './trading-host.js';\nimport type { BalanceRow, PositionRow } from './trading-data.js';\nimport { DataGrid, GridColumn, GridPinnedRow, GridPinnedPlacements } from '@stocksharp/grids/source/data-grid';\n\n/// Everything the blotter needs beyond the host port. All required: the action\n/// buttons live in the cells and in the rail now, so a panel that cannot\n/// close, reverse or reload a position is not this panel.\nexport interface PositionsDeps {\n host: TradingHost;\n closePosition(portfolioId: number, instrumentId: number, symbol: string): void;\n reversePosition(portfolioId: number, instrumentId: number, symbol: string): void;\n refreshPositions(): void;\n}\n\nexport class PositionsWidget {\n static TYPE = ControlTypes.Positions;\n\n rootEl: HTMLElement;\n el: HTMLElement | null;\n // Comment style is `//` on purpose below the public members: the declaration\n // emitter keeps a private member's doc comment while dropping its body, so a\n // `///` here would reattach to the next public member in the API snapshot.\n _host: TradingHost;\n _deps: PositionsDeps;\n _closeBtn: HTMLElement | null;\n _refreshBtn: HTMLElement | null;\n _exportBtn: HTMLElement | null;\n _positions: PositionRow[];\n _balance: BalanceRow | null;\n _grid: DataGrid<PositionRow> | null;\n\n static create(hostEl: HTMLElement, state: Record<string, unknown>, deps: PositionsDeps): PositionsWidget {\n // Assert before building: the markup below is localized through the\n // host, so a missing host has to fail here rather than render a panel\n // captioned with raw English keys.\n const host = assertHost(deps?.host, 'PositionsWidget');\n const root = PositionsWidget._buildRoot(host);\n root.id = makePanelId(PositionsWidget.TYPE);\n hostEl.appendChild(root);\n return new PositionsWidget(root, state || {}, deps);\n }\n\n // The panel's markup. The host stylesheet reads this structure, and a\n // docking host lifts `.panel-header`'s children into its tab strip.\n //\n // The rail's refresh button is the one thing that could not come across\n // unchanged from the terminal's Razor template: it used to be an inline\n // `onclick=\"terminalApp.refreshPositions()\"`, which is a reference to a\n // global this control must not have. It carries `.panel-refresh-btn` now \u2014\n // the name the trade-history rail already gave the identical button \u2014 and\n // is wired to the `refreshPositions` dep.\n static _buildRoot(host: TradingHost): HTMLElement {\n const title = host.t('OpenPositions');\n return makePanelRoot('positions-panel', title, [\n makeElement('div', 'panel-header', {}, [\n makeElement('span', '', {}, [host.t('Positions')]),\n makeIconButton('bt-icon-btn bt-icon-cancel panel-close-btn', host.t('ClosePanel'), 'bi-x', { type: 'button' }),\n ]),\n makeElement('div', 'panel-body panel-body-with-rail', {}, [\n makeElement('div', 'panel-body-content', {}, [\n makeElement('table', 'terminal-table positions-table', { role: 'table', 'aria-label': title }, [\n makeElement('thead', '', {}, []),\n makeElement('tbody', 'positions-body', {}, []),\n ]),\n ]),\n makeElement('div', 'panel-rail', { role: 'toolbar', 'aria-label': host.t('PositionsActions') }, [\n makeIconButton('bt-icon-btn panel-refresh-btn', host.t('Refresh'), 'bi-arrow-clockwise', {}),\n makeIconButton('bt-icon-btn panel-export-btn', host.t('ExportToExcel'), 'bi-file-earmark-spreadsheet', {}),\n ]),\n ]),\n ]);\n }\n\n constructor(rootEl: HTMLElement, _state: Record<string, unknown>, deps: PositionsDeps) {\n this._host = assertHost(deps?.host, 'PositionsWidget');\n for (const name of ['closePosition', 'reversePosition', 'refreshPositions'] as const) {\n if (typeof deps?.[name] !== 'function')\n throw new Error(`PositionsWidget: dep \"${name}\" is required`);\n }\n\n this.rootEl = rootEl;\n this._deps = deps;\n this.el = this.rootEl.querySelector('.positions-body');\n this._closeBtn = this.rootEl.querySelector('.panel-close-btn');\n this._refreshBtn = this.rootEl.querySelector('.panel-refresh-btn');\n this._exportBtn = this.rootEl.querySelector('.panel-export-btn');\n this._positions = [];\n this._balance = null;\n\n this._closeBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n this._host.close();\n });\n\n this._refreshBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n this._deps.refreshPositions();\n });\n\n this._exportBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n this._export();\n });\n\n const head = this.rootEl.querySelector('.positions-table thead');\n this._grid = head && this.el\n ? new DataGrid<PositionRow>({\n head: head as HTMLElement,\n body: this.el,\n columns: this._columns(),\n // Alphabetical by instrument at rest \u2014 a stable, predictable order (positions have no\n // natural \"newest\") the user can scan by symbol.\n defaultSort: { col: 'instrument', dir: 'asc' },\n // Same identity applyDelta matches on: id alone isn't unique (id=0 for\n // unsaved snapshots), and a portfolio can hold one position per instrument.\n rowKey: (p) => PositionsWidget._key(p),\n emptyText: this._host.t('No positions'),\n // Re-read on every render, so the cash figures track the live balance\n // without the widget having to repaint the position rows itself.\n pinnedRows: () => this._pinnedRows(),\n })\n : null;\n\n this._host.register(this);\n\n // If the host already has a positions snapshot it will broadcast it on\n // demand; new instances start empty until the first refresh tick.\n }\n\n dispose(): void {\n this._host.unregister(this);\n try { this.rootEl.remove(); } catch { /* already detached */ }\n }\n\n update(positions: PositionRow[]): void {\n this._positions = positions || [];\n this._grid?.setRows(this._positions);\n }\n\n /// Null clears the pinned row \u2014 which is not the same as an all-zero\n /// balance, and reads differently: no row at all versus a row of zeros.\n updateBalance(balance: BalanceRow | null): void {\n this._balance = balance;\n this._grid?.render();\n }\n\n /// Apply a single position delta. Match by (portfolioId, instrumentId) \u2014 id\n /// alone isn't unique (id=0 for unsaved snapshots). Quantity hitting zero\n /// closes the row.\n applyDelta(position: PositionRow): void {\n if (!position) return;\n const idx = this._positions.findIndex(p =>\n p.portfolioId === position.portfolioId &&\n ((position.instrumentId != null && p.instrumentId === position.instrumentId) ||\n (position.instrumentId == null && p.instrument === position.instrument)));\n const closed = (position.quantity || 0) === 0;\n\n if (idx >= 0) {\n if (closed) this._positions.splice(idx, 1);\n else this._positions[idx] = { ...this._positions[idx], ...position };\n } else if (!closed) {\n this._positions.push(position);\n }\n this.update(this._positions);\n }\n\n // Export the table to .xlsx in the currently rendered (sorted) order. The\n // balance summary is a pinned row \u2014 a different shape from a position \u2014 so\n // the grid keeps it out of the sheet.\n _export(): void {\n this._grid?.download('positions', this._host.t('Positions'));\n }\n\n // The blotter's single column declaration: what the header says, what the\n // grid sorts on, what the cell shows, how it is coloured, and what reaches\n // the exported sheet. Prices are formatted on screen but exported raw, so\n // the sheet stays numeric.\n _columns(): GridColumn<PositionRow>[] {\n const label = (key: string) => this._host.t(key);\n return [\n {\n key: 'instrument',\n header: label('Symbol'),\n exportable: true,\n value: (p) => p.instrument,\n },\n {\n key: 'quantity',\n header: label('Qty'),\n exportable: true,\n value: (p) => p.quantity,\n cellClass: (p) => ((p.quantity ?? 0) > 0 ? 'side-buy' : 'side-sell'),\n },\n {\n key: 'avgPrice',\n header: label('AvgPrice'),\n exportable: true,\n value: (p) => p.avgPrice,\n render: (p) => formatPrice(p.avgPrice),\n },\n {\n key: 'currentPrice',\n header: label('Current'),\n exportable: true,\n value: (p) => p.currentPrice,\n render: (p) => formatPrice(p.currentPrice),\n },\n {\n key: 'pnl',\n header: label('PnL'),\n exportable: true,\n value: (p) => PositionsWidget._totalPnl(p),\n render: (p) => formatPnl(PositionsWidget._totalPnl(p)),\n cellClass: (p) => this._host.presentation.pnlClass(PositionsWidget._totalPnl(p)),\n },\n {\n key: 'actions',\n header: label('Actions'),\n headerHidden: true,\n exportable: false,\n cellClass: () => 'position-actions',\n render: (p) => this._actionButtons(p),\n },\n ];\n }\n\n // The cash balance, pinned above the positions. It does not share the shape\n // the position columns read, so it supplies its own cells; it is not a row\n // of data, so it is neither sorted nor exported. Being content, it also\n // suppresses the \"no positions\" row \u2014 a table showing a balance is not empty.\n _pinnedRows(): GridPinnedRow[] {\n const balance = this._balance;\n if (!balance) return [];\n\n const fmt = (v: number | null | undefined) => (v || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });\n return [{\n key: 'balance',\n className: 'balance-row',\n place: GridPinnedPlacements.Top,\n cells: [\n { content: this._host.t('USD'), className: 'balance-ccy' },\n { content: '$' + fmt(balance.available), className: 'balance-available' },\n { content: this._host.t('Locked: ${0}', fmt(balance.locked)), className: 'balance-locked' },\n { content: '', className: '' },\n { content: '$' + fmt(balance.total), className: 'balance-total' },\n ],\n }];\n }\n\n // Realized and unrealized together \u2014 what the PnL column shows, sorts and\n // exports, so the three cannot drift apart.\n static _totalPnl(position: PositionRow): number {\n return (position.unrealizedPnl || 0) + (position.realizedPnl || 0);\n }\n\n static _key(position: PositionRow): string {\n return `${position.portfolioId}:${position.instrumentId ?? position.instrument}`;\n }\n\n // Close and reverse, wired to the controller through deps. Real buttons with\n // their own listeners \u2014 the symbol used to be interpolated into an inline\n // onclick attribute, which is why it needed quote-escaping first.\n _actionButtons(position: PositionRow): Node {\n const cell = document.createDocumentFragment();\n cell.appendChild(this._actionButton(\n 'bt-icon-cancel', 'bi-x-circle',\n this._host.t('Close position'), this._host.t('Close position on {0}', position.instrument),\n () => this._deps.closePosition(position.portfolioId!, position.instrumentId!, position.instrument!)));\n cell.appendChild(this._actionButton(\n 'bt-icon-reverse', 'bi-arrow-left-right',\n this._host.t('Reverse position'), this._host.t('Reverse position on {0}', position.instrument),\n () => this._deps.reversePosition(position.portfolioId!, position.instrumentId!, position.instrument!)));\n return cell;\n }\n\n _actionButton(styleClass: string, iconClass: string, title: string, label: string, onClick: () => void): HTMLButtonElement {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = `bt-icon-btn ${styleClass}`;\n button.title = title;\n button.setAttribute('aria-label', label);\n const icon = document.createElement('i');\n icon.className = `bi ${iconClass}`;\n button.appendChild(icon);\n button.addEventListener('click', onClick);\n return button;\n }\n}\n", "// Trade history \u2014 multi-instance.\n//\n// Read-only table of executed trades for the active portfolio. Builds its own\n// DOM (see `_buildRoot`) rather than cloning a <template> out of the page, so\n// it can be constructed by any host that supplies a `TradingHost`.\n//\n// Which portfolio to load and what to load it through both come off the host's\n// trading context rather than being read out of a singleton here: the panel\n// renders what it is given, and the host decides what \"the active portfolio\"\n// means.\n//\n// The table is `DataGrid` from `@stocksharp/grids`: the columns below are this\n// blotter's single declaration and the <thead> is left empty for the grid to\n// fill.\nimport { formatPrice, formatQty, formatTime } from './formatters.js';\nimport { makeElement, makeIconButton, makePanelId, makePanelRoot } from './dom.js';\nimport { ControlTypes } from './control-types.js';\nimport { TradingHost, assertHost } from './trading-host.js';\nimport type { TradeRow } from './trading-data.js';\nimport { DataGrid, GridColumn } from '@stocksharp/grids/source/data-grid';\n\n/// The panel needs nothing beyond the host port: its data source, its\n/// portfolio and its lifecycle all arrive through it.\nexport interface TradeHistoryDeps {\n host: TradingHost;\n}\n\nexport class TradeHistoryWidget {\n static TYPE = ControlTypes.TradeHistory;\n\n rootEl: HTMLElement;\n bodyEl: HTMLElement | null;\n // `//` rather than `///` from here down \u2014 see the note in positions-widget.\n _host: TradingHost;\n _closeBtn: HTMLElement | null;\n _refreshBtn: HTMLElement | null;\n _exportBtn: HTMLElement | null;\n _rows: TradeRow[];\n _grid: DataGrid<TradeRow> | null;\n\n static create(hostEl: HTMLElement, state: Record<string, unknown>, deps: TradeHistoryDeps): TradeHistoryWidget {\n // Assert before building: the markup below is localized through the\n // host, so a missing host has to fail here rather than render a panel\n // captioned with raw English keys.\n const host = assertHost(deps?.host, 'TradeHistoryWidget');\n const root = TradeHistoryWidget._buildRoot(host);\n root.id = makePanelId(TradeHistoryWidget.TYPE);\n hostEl.appendChild(root);\n return new TradeHistoryWidget(root, state || {}, deps);\n }\n\n // The panel's markup. The host stylesheet reads this structure, and a\n // docking host lifts `.panel-header`'s children into its tab strip.\n static _buildRoot(host: TradingHost): HTMLElement {\n const title = host.t('TradeHistory');\n return makePanelRoot('trade-history-panel', title, [\n makeElement('div', 'panel-header', {}, [\n makeElement('span', '', {}, [title]),\n makeIconButton('bt-icon-btn bt-icon-cancel panel-close-btn', host.t('ClosePanel'), 'bi-x', { type: 'button' }),\n ]),\n makeElement('div', 'panel-body panel-body-with-rail', {}, [\n makeElement('div', 'panel-body-content', {}, [\n makeElement('table', 'terminal-table trade-history-table', { role: 'table', 'aria-label': host.t('TradeHistoryList') }, [\n makeElement('thead', '', {}, []),\n makeElement('tbody', 'trade-history-body', {}, []),\n ]),\n ]),\n makeElement('div', 'panel-rail', { role: 'toolbar', 'aria-label': host.t('TradeHistoryActions') }, [\n makeIconButton('bt-icon-btn panel-refresh-btn', host.t('Refresh'), 'bi-arrow-clockwise', {}),\n makeIconButton('bt-icon-btn panel-export-btn', host.t('ExportToExcel'), 'bi-file-earmark-spreadsheet', {}),\n ]),\n ]),\n ]);\n }\n\n constructor(rootEl: HTMLElement, _state: Record<string, unknown>, deps: TradeHistoryDeps) {\n this._host = assertHost(deps?.host, 'TradeHistoryWidget');\n\n this.rootEl = rootEl;\n this.bodyEl = this.rootEl.querySelector('.trade-history-body');\n this._closeBtn = this.rootEl.querySelector('.panel-close-btn');\n this._refreshBtn = this.rootEl.querySelector('.panel-refresh-btn');\n this._exportBtn = this.rootEl.querySelector('.panel-export-btn');\n\n this._closeBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n this.dispose();\n this._host.close();\n });\n this._refreshBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n void this.refresh();\n });\n\n this._exportBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n this._export();\n });\n\n this._rows = [];\n\n const head = this.rootEl.querySelector('.trade-history-table thead');\n this._grid = head && this.bodyEl\n ? new DataGrid<TradeRow>({\n head: head as HTMLElement,\n body: this.bodyEl,\n columns: this._columns(),\n // Most recent fill on top by default \u2014 the natural way to read a trade blotter.\n defaultSort: { col: 'time', dir: 'desc' },\n rowKey: (t) => String(t.id),\n emptyText: this._host.t('No trade history'),\n })\n : null;\n\n this._host.register(this);\n }\n\n dispose(): void {\n this._host.unregister(this);\n try { this.rootEl.remove(); } catch { /* already detached */ }\n }\n\n /// Reload against whichever portfolio the host says is active right now.\n ///\n /// Two guards, and they are not the same one. No portfolio means there is\n /// nothing to show \u2014 a guest session has none. A portfolio the host will\n /// not `allow` reading means the session cannot make the call at all: this\n /// is somebody's executed trades, so a page that has a portfolio id lying\n /// around but no live credential must not fire the request and collect a\n /// 401 for it. The panel asks the host rather than inspecting a token,\n /// because what counts as a usable session is the host's to know.\n ///\n /// Order matters: the portfolio check runs first, so a session with no\n /// portfolio is simply quiet \u2014 `allow` is the one that may put a sign-in\n /// prompt on screen, and reaching it means the page did have an account to\n /// load.\n async refresh(): Promise<void> {\n const pf = this._host.trading.portfolioId();\n if (!pf || !this._grid) return;\n if (!this._host.allow('load trade history')) return;\n try {\n this._rows = await this._host.trading.api.getExecutions(pf, null, 200) || [];\n this._grid.setRows(this._rows);\n } catch (err) {\n // Through the port, not the console: this is the diagnostic the\n // user cannot see and support has to, and routing it here is also\n // what makes it assertable.\n this._host.log(`TradeHistoryWidget: failed to load trade history: ${err}`);\n }\n }\n\n // Export the table to .xlsx in the currently rendered (sorted) order.\n _export(): void {\n this._grid?.download('trades', this._host.t('TradeHistory'));\n }\n\n // The blotter's single column declaration. The two id columns read `#42` on\n // screen and export the bare number, so the sheet stays sortable as a number.\n _columns(): GridColumn<TradeRow>[] {\n // `label`, not `t` \u2014 every row lambda below already binds `t` as the\n // trade it is rendering, and a translator sharing that name would be\n // shadowed inside exactly the callbacks that read it.\n const label = (key: string) => this._host.t(key);\n const presentation = this._host.presentation;\n return [\n {\n key: 'id',\n header: label('ID'),\n exportable: true,\n value: (t) => t.id,\n render: (t) => '#' + t.id,\n cellClass: () => 'mono-id',\n },\n {\n key: 'time',\n header: label('Time'),\n exportable: true,\n value: (t) => t.executedAt || t.time,\n render: (t) => formatTime(t.executedAt || t.time),\n exportValue: (t) => formatTime(t.executedAt || t.time),\n },\n {\n key: 'symbol',\n header: label('Sym'),\n exportable: true,\n value: (t) => t.instrumentSymbol || t.symbol,\n },\n {\n key: 'side',\n header: label('Side'),\n exportable: true,\n value: (t) => t.side,\n render: (t) => presentation.sideText(t.side!),\n cellClass: (t) => presentation.sideClass(t.side!),\n exportValue: (t) => presentation.sideText(t.side!),\n },\n {\n key: 'quantity',\n header: label('Qty'),\n exportable: true,\n value: (t) => t.quantity,\n render: (t) => formatQty(t.quantity),\n },\n {\n key: 'price',\n header: label('Price'),\n exportable: true,\n value: (t) => t.price,\n render: (t) => formatPrice(t.price),\n },\n {\n key: 'order',\n header: label('Order'),\n exportable: true,\n value: (t) => t.order || t.orderId,\n render: (t) => '#' + (t.order || t.orderId || ''),\n cellClass: () => 'mono-id',\n },\n ];\n }\n}\n", "// Watchlist \u2014 multi-instance.\n//\n// Builds its own DOM (see `_buildRoot`) rather than cloning a <template> out of\n// the page, so it can be constructed by any host that supplies a `TradingHost`.\n// Each instance has its own search/filter/sort state; favourites are shared,\n// held under one key in the host's preference store.\n//\n// The table is `DataGrid` from `@stocksharp/grids`. The grid holds the FILTERED\n// instruments and does the sorting, which is what makes the two caps mean\n// different things: `renderLimit` caps what gets painted while the export and\n// the subscription sync read the whole filtered set. A live quote patches one\n// cell through the grid's (rowKey, columnKey) lookup instead of repainting \u2014 a\n// repaint would restart the flash animation it just triggered.\nimport { makeElement, makeIconButton, makePanelId, makePanelRoot } from './dom.js';\nimport { ControlTypes } from './control-types.js';\nimport { MarketDataClient, MarketDataLevels, TradingApi, TradingHost, assertHost } from './trading-host.js';\nimport type { InstrumentRow, QuoteStats } from './trading-data.js';\nimport { DataGrid, GridColumn } from '@stocksharp/grids/source/data-grid';\n\n/// What the panel needs beyond the host port. Picking an instrument is the one\n/// thing it reports that is not the ticker: the panel does not switch the\n/// host's instrument itself, it says what the user chose and the host acts.\nexport interface WatchlistDeps {\n host: TradingHost;\n onSelect(symbol: string): void;\n}\n\nexport class WatchlistWidget {\n static FAVORITES_KEY = 'terminal_watchlist_favorites';\n // Cache-key prefix for the per-session baseline price used to compute the\n // change %. Day-scoped so the baseline resets every UTC day and the\n // percent matches \"since today open\" intuitively. (Without a REST bars\n // endpoint there is no broker-side day-open available, and the watchlist\n // deliberately avoids REST \u2014 the live stream is its only source.) It goes\n // in the host's cache rather than its preferences: one key per symbol per\n // day is scratch, not a setting worth syncing.\n static BASELINE_KEY_PREFIX = 'wlBaseline:';\n static VISIBLE_CAP = 30;\n static RENDER_CAP = 300;\n static TYPE = ControlTypes.Watchlist;\n\n rootEl: HTMLElement;\n api: TradingApi;\n instruments: InstrumentRow[];\n stats: Map<string, QuoteStats>;\n favorites: Set<string>;\n filter: string;\n search: string;\n currentSymbol: string | null;\n wsClient: MarketDataClient;\n bodyEl: HTMLElement | null;\n searchEl: HTMLInputElement | null;\n tabsEl: HTMLElement | null;\n sortHeaderEl: HTMLElement | null;\n // `//` rather than `///` from here down \u2014 see the note in positions-widget.\n _host: TradingHost;\n _deps: WatchlistDeps;\n // Symbols this widget currently holds a live-quote subscription for.\n // Re-synced from the visible list on every render \u2014 see _syncSubs.\n _subscribedSyms: Set<string>;\n _closeBtn: HTMLElement | null;\n _exportBtn: HTMLElement | null;\n _grid: DataGrid<InstrumentRow> | null;\n\n static create(hostEl: HTMLElement, state: Record<string, unknown>, deps: WatchlistDeps): WatchlistWidget {\n // Assert before building: the markup below is localized through the\n // host, so a missing host has to fail here rather than render a panel\n // captioned with raw English keys.\n const host = assertHost(deps?.host, 'WatchlistWidget');\n const root = WatchlistWidget._buildRoot(host);\n root.id = makePanelId(WatchlistWidget.TYPE);\n hostEl.appendChild(root);\n return new WatchlistWidget(root, state || {}, deps);\n }\n\n // The panel's markup. The host stylesheet reads this structure, and a\n // docking host lifts `.panel-header`'s children \u2014 and, for this panel,\n // `.watchlist-search-row` as well \u2014 into its tab strip, which is why the\n // search row is a sibling of the header rather than a child of it.\n //\n // \"All\" and \"Favorites\" are the built-in tabs. The rest are appended at\n // runtime from the distinct categories of the loaded instruments, so the\n // tab set is configured through whatever assigns those categories rather\n // than being spelled out here \u2014 see _renderCategoryTabs.\n static _buildRoot(host: TradingHost): HTMLElement {\n const search = host.t('SearchInstruments');\n const favorites = host.t('Favorites');\n return makePanelRoot('watchlist-panel', host.t('Watchlist'), [\n makeElement('div', 'panel-header', {}, [\n makeElement('span', '', {}, [host.t('Markets')]),\n makeIconButton('bt-icon-btn panel-export-btn', host.t('ExportToExcel'), 'bi-file-earmark-spreadsheet', { type: 'button' }),\n makeIconButton('bt-icon-btn bt-icon-cancel panel-close-btn', host.t('ClosePanel'), 'bi-x', { type: 'button' }),\n ]),\n makeElement('div', 'watchlist-search-row', {}, [\n makeElement('input', 'form-control form-control-sm watchlist-search-input watchlist-search',\n { type: 'text', placeholder: search, autocomplete: 'off', 'aria-label': search }, []),\n ]),\n makeElement('div', 'watchlist-tabs', { role: 'tablist', 'aria-label': host.t('WatchlistFilter') }, [\n makeElement('button', 'wl-tab active', { 'data-filter': 'all', role: 'tab', 'aria-selected': 'true' }, [host.t('All')]),\n makeElement('button', 'wl-tab', { 'data-filter': 'favorites', role: 'tab', 'aria-selected': 'false', 'aria-label': favorites, title: favorites }, ['\u2605']),\n ]),\n makeElement('div', 'watchlist-pane', {}, [\n makeElement('table', 'watchlist-table', {}, [\n makeElement('thead', 'watchlist-headers', {}, []),\n makeElement('tbody', 'watchlist-body', {}, []),\n ]),\n ]),\n ]);\n }\n\n constructor(rootEl: HTMLElement, _state: Record<string, unknown>, deps: WatchlistDeps) {\n this._host = assertHost(deps?.host, 'WatchlistWidget');\n if (typeof deps?.onSelect !== 'function')\n throw new Error('WatchlistWidget: dep \"onSelect\" is required');\n\n this.rootEl = rootEl;\n this._deps = deps;\n this.api = this._host.trading.api;\n\n this.instruments = [];\n this.stats = new Map();\n this.favorites = new Set(this._loadFavorites());\n this.filter = 'all';\n this.search = '';\n this.currentSymbol = null;\n this._subscribedSyms = new Set();\n this.wsClient = this._host.trading.marketData;\n\n this.bodyEl = this.rootEl.querySelector('.watchlist-body');\n this.searchEl = this.rootEl.querySelector('.watchlist-search');\n this.tabsEl = this.rootEl.querySelector('.watchlist-tabs');\n this.sortHeaderEl = this.rootEl.querySelector('.watchlist-headers');\n this._closeBtn = this.rootEl.querySelector('.panel-close-btn');\n this._exportBtn = this.rootEl.querySelector('.panel-export-btn');\n\n this._closeBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n this.dispose();\n this._host.close();\n });\n this._exportBtn?.addEventListener('click', (e) => {\n e.preventDefault();\n this._export();\n });\n\n this._grid = this.sortHeaderEl && this.bodyEl\n ? new DataGrid<InstrumentRow>({\n head: this.sortHeaderEl,\n body: this.bodyEl,\n columns: this._columns(),\n // Symbol A\u2192Z at rest \u2014 an instrument list has no natural \"newest\",\n // and alphabetical is what the user scans by.\n defaultSort: { col: 'symbol', dir: 'asc' },\n rowKey: (i) => String(i.symbol),\n emptyText: this._host.t('No instruments'),\n rowClass: (i) => (i.symbol === this.currentSymbol ? 'wl-row wl-current' : 'wl-row'),\n bindRow: (tr, i) => tr.addEventListener('click', () => this._deps.onSelect(i.symbol!)),\n // Paint a screenful, export and subscribe over the whole filtered set.\n renderLimit: WatchlistWidget.RENDER_CAP,\n // A header click re-renders through the grid, so this is the only\n // place that sees every change to the visible set \u2014 including a sort\n // the widget was never told about.\n afterRender: () => {\n this._syncSubs();\n this._publishVisible();\n },\n })\n : null;\n\n this._bind();\n\n this._host.register(this);\n\n // Auto-init data load: a caller that creates the panel expects a working\n // widget without further ceremony. Unconditional \u2014 the host port\n // guarantees an API client, so there is no \"maybe we can load\" state\n // left to branch on.\n void this.init();\n }\n\n dispose(): void {\n // Release every live subscription this widget held \u2014 the market-data\n // client refcounts them, so another control's subscription survives if\n // it happened to share a symbol with us.\n for (const sym of this._subscribedSyms) {\n try { void this.wsClient?.removeSymbol(sym); } catch { /* socket may be torn down */ }\n }\n this._subscribedSyms.clear();\n this._host.unregister(this);\n try { this.rootEl.remove(); } catch { /* already detached */ }\n }\n\n async init(): Promise<void> {\n try {\n this.instruments = await this.api.searchInstruments('');\n } catch (err) {\n // Through the port, not the console: this is the diagnostic the\n // user cannot see and support has to, and routing it here is also\n // what makes it assertable.\n this._host.log(`WatchlistWidget: failed to load instruments: ${err}`);\n this.instruments = [];\n }\n this._renderCategoryTabs();\n this._render();\n }\n\n // Build the filter tabs from the assigned instrument categories. \"All\" and\n // \"Favorites\" are built into the markup; here we append one tab per distinct\n // non-empty category found in the loaded instruments. Re-runnable: clears\n // any category tabs a previous load added.\n _renderCategoryTabs(): void {\n if (!this.tabsEl) return;\n this.tabsEl.querySelectorAll('.wl-tab[data-category]').forEach(el => el.remove());\n\n const cats = Array.from(new Set(\n this.instruments\n .map(i => (i.category || '').trim())\n .filter(c => c.length > 0)))\n .sort((a, b) => a.localeCompare(b));\n\n for (const cat of cats) {\n const btn = document.createElement('button');\n btn.className = 'wl-tab';\n btn.setAttribute('role', 'tab');\n btn.setAttribute('aria-selected', 'false');\n btn.dataset.filter = cat;\n btn.dataset.category = '1';\n btn.textContent = cat;\n this.tabsEl.appendChild(btn);\n }\n }\n\n /// Highlight the instrument the rest of the page is showing. Patches the two\n /// affected rows rather than repainting: a repaint here would restart any\n /// flash animation currently running in a price cell.\n setCurrentSymbol(symbol: string | null): void {\n const previous = this.currentSymbol;\n this.currentSymbol = symbol;\n if (!this._grid) return;\n if (previous) this._grid.rowElement(String(previous))?.classList.remove('wl-current');\n if (symbol) this._grid.rowElement(String(symbol))?.classList.add('wl-current');\n }\n\n onPriceUpdate(symbol: string, price: number): void {\n if (price == null || !isFinite(price)) return;\n let full = symbol;\n if (!full.includes('@')) {\n const match = this.instruments.find(i => String(i.symbol).split('@')[0] === symbol);\n if (match?.symbol) full = match.symbol;\n }\n const cur = this.stats.get(full);\n const prev = cur?.lastPrice;\n\n // Session-day baseline: first observed live price per (UTC-day, symbol).\n // Kept in the host's cache so reloading the page doesn't jump the\n // baseline mid-day. New UTC day = fresh baseline.\n const baselineKey = WatchlistWidget._baselineKey(full);\n let baseline = cur?.baseline;\n if (baseline == null) {\n const stored = this._host.cache.get(baselineKey, null);\n baseline = stored ? Number(stored) : undefined;\n }\n if (baseline == null || !isFinite(baseline) || baseline === 0) {\n baseline = price;\n this._host.cache.set(baselineKey, String(price));\n }\n const chgPct = baseline ? ((price - baseline) / baseline) * 100 : 0;\n\n this.stats.set(full, { ...(cur || {}), lastPrice: price, baseline, chgPct });\n this._updateRow(full, prev);\n }\n\n static _baselineKey(symbol: string): string {\n const day = new Date().toISOString().slice(0, 10); // YYYY-MM-DD (UTC)\n return WatchlistWidget.BASELINE_KEY_PREFIX + day + ':' + symbol;\n }\n\n _bind(): void {\n if (this.searchEl) {\n this.searchEl.addEventListener('input', () => {\n this.search = (this.searchEl!.value || '').trim().toLowerCase();\n this._render();\n });\n }\n if (this.tabsEl) {\n this.tabsEl.addEventListener('click', (e) => {\n const tgt = e.target as Element | null;\n const btn = tgt?.closest('.wl-tab') as HTMLElement | null;\n if (!btn) return;\n this.filter = btn.dataset.filter || 'all';\n this.tabsEl!.querySelectorAll('.wl-tab').forEach(b => b.classList.toggle('active', b === btn));\n this._render();\n });\n }\n // Sort header clicks are handled by the grid (wired in the constructor).\n }\n\n // The instruments matching the search box and the active tab, unsorted \u2014\n // the grid owns the order.\n _filtered(): InstrumentRow[] {\n const q = this.search;\n const rows: InstrumentRow[] = [];\n for (const inst of this.instruments) {\n const sym = (inst.symbol || '').toUpperCase();\n // Match the \"symbol/exchange\" (and \"symbol@exchange\") display form too, so a\n // full \"BTC/IMEX\" query resolves \u2014 not only the bare symbol \"BTC\".\n const symL = sym.toLowerCase();\n const shortSym = symL.split('@')[0];\n const exch = (inst.exchange || '').toLowerCase();\n const qualified = `${shortSym}/${exch}`;\n const qualifiedAt = `${shortSym}@${exch}`;\n if (q && !symL.includes(q) && !(inst.name || '').toLowerCase().includes(q) && !qualified.includes(q) && !qualifiedAt.includes(q)) continue;\n if (this.filter === 'favorites') {\n if (!this.favorites.has(sym)) continue;\n } else if (this.filter !== 'all') {\n // Any other filter value is an assigned instrument category,\n // matched case-insensitively.\n if ((inst.category || '').toLowerCase() !== this.filter.toLowerCase()) continue;\n }\n rows.push(inst);\n }\n return rows;\n }\n\n _render(): void {\n this._grid?.setRows(this._filtered());\n }\n\n // The blotter's single column declaration. Prices and percentages come off\n // the live stats map rather than the instrument row, so a quote arriving\n // between two renders is picked up by the next one.\n _columns(): GridColumn<InstrumentRow>[] {\n const label = (key: string) => this._host.t(key);\n return [\n {\n key: 'symbol',\n header: label('Symbol'),\n exportable: true,\n value: (i) => i.symbol,\n cellClass: () => 'wl-sym-cell',\n render: (i) => this._symbolCell(i),\n exportValue: (i) => String(i.symbol).split('@')[0],\n },\n {\n key: 'last',\n header: label('Last'),\n headerClass: 'ta-right',\n exportable: true,\n value: (i) => this._statsOf(i).lastPrice,\n cellClass: () => 'wl-last',\n render: (i) => WatchlistWidget._priceText(this._statsOf(i).lastPrice),\n exportValue: (i) => this._statsOf(i).lastPrice ?? '',\n },\n {\n key: 'chgPct',\n header: label('Change24hPct'),\n headerClass: 'ta-right',\n exportable: true,\n value: (i) => this._statsOf(i).chgPct,\n cellClass: (i) => ('wl-chg ' + WatchlistWidget._changeClass(this._statsOf(i).chgPct)).trim(),\n render: (i) => WatchlistWidget._changeText(this._statsOf(i).chgPct),\n exportValue: (i) => this._statsOf(i).chgPct ?? '',\n },\n ];\n }\n\n _statsOf(instrument: InstrumentRow): QuoteStats {\n return this.stats.get(String(instrument.symbol)) ?? {};\n }\n\n // The favourite star plus the short symbol. The star stops the click from\n // reaching the row, whose own listener switches the host's instrument.\n _symbolCell(instrument: InstrumentRow): Node {\n const cell = document.createDocumentFragment();\n\n const star = document.createElement('button');\n star.type = 'button';\n star.className = this.favorites.has(instrument.symbol!) ? 'wl-fav active' : 'wl-fav';\n star.title = this._host.t('Favorite');\n star.textContent = '\u2605';\n star.addEventListener('click', (e) => {\n e.stopPropagation();\n this._toggleFavorite(instrument.symbol!);\n });\n cell.appendChild(star);\n\n const label = document.createElement('span');\n label.className = 'wl-sym';\n label.textContent = String(instrument.symbol).split('@')[0];\n cell.appendChild(label);\n\n return cell;\n }\n\n // Export the current filtered+sorted view to .xlsx \u2014 every matching\n // instrument, without the RENDER_CAP truncation applied to the DOM.\n _export(): void {\n this._grid?.download('watchlist', this._host.t('Markets'));\n }\n\n // Patch the price and change cells of one row in place. A full render would\n // replace the cell element and so cancel the flash animation started here.\n _updateRow(symbol: string, prevPrice: number | null | undefined): void {\n if (!this._grid) return;\n const st = this.stats.get(symbol) || {};\n const lastEl = this._grid.cellElement(String(symbol), 'last');\n const chgEl = this._grid.cellElement(String(symbol), 'chgPct');\n if (lastEl && st.lastPrice != null) {\n lastEl.textContent = WatchlistWidget._priceText(st.lastPrice);\n if (prevPrice != null && st.lastPrice !== prevPrice) {\n lastEl.classList.remove('flash-up', 'flash-down');\n void lastEl.offsetWidth;\n lastEl.classList.add(st.lastPrice > prevPrice ? 'flash-up' : 'flash-down');\n }\n }\n if (chgEl && st.chgPct != null && isFinite(Number(st.chgPct))) {\n chgEl.textContent = WatchlistWidget._changeText(st.chgPct);\n chgEl.classList.remove('up', 'down');\n chgEl.classList.add(WatchlistWidget._changeClass(st.chgPct));\n }\n }\n\n _toggleFavorite(symbol: string): void {\n if (!this._host.allow('add to favorites')) return;\n if (this.favorites.has(symbol)) this.favorites.delete(symbol);\n else this.favorites.add(symbol);\n this._saveFavorites();\n // Broadcast the change to every other watchlist instance so they reflect\n // the new state without a fresh fetch.\n this._host.broadcast<WatchlistWidget>(w => {\n if (w !== this) { w.favorites = new Set(this.favorites); w._render(); }\n });\n this._render();\n }\n\n _loadFavorites(): string[] {\n try {\n const raw = this._host.preferences.get(WatchlistWidget.FAVORITES_KEY, null);\n return raw ? JSON.parse(raw) : [];\n } catch { return []; }\n }\n\n _saveFavorites(): void {\n try { this._host.preferences.set(WatchlistWidget.FAVORITES_KEY, JSON.stringify(Array.from(this.favorites))); }\n catch { /* store may be unavailable */ }\n }\n\n // The symbols at the top of the current order \u2014 the ones a user is actually\n // looking at, and the set both the subscriptions and the host's ticker are\n // sized to.\n _visible(): InstrumentRow[] {\n return this._grid ? this._grid.sortedRows().slice(0, WatchlistWidget.VISIBLE_CAP) : [];\n }\n\n // Diff the desired set of visible symbols against currently-held live-price\n // subscriptions, then add/remove to converge. Called after every render that\n // may have changed the visible list (filter, sort, search). add/removeSymbol\n // refcount internally, so another control's subscription on the same symbol\n // is not affected.\n _syncSubs(): void {\n if (!this.wsClient) return;\n const desired = new Set(this._visible().map(i => String(i.symbol).split('@')[0]));\n\n for (const sym of this._subscribedSyms) {\n if (!desired.has(sym)) {\n try { void this.wsClient.removeSymbol(sym); } catch { /* socket race */ }\n this._subscribedSyms.delete(sym);\n }\n }\n // Stagger the subscribe burst \u2014 firing every watchlist symbol\n // simultaneously while a chart is fetching its history starves the\n // adapter and stalls the chart's snapshot. 80ms between calls keeps the\n // pipe quiet enough for that fetch to return on time, while still\n // feeling instant to the user.\n let i = 0;\n for (const sym of desired) {\n if (this._subscribedSyms.has(sym)) continue;\n this._subscribedSyms.add(sym);\n setTimeout(() => {\n try { void this.wsClient.addSymbol(sym, MarketDataLevels.Quotes); } catch { /* socket race */ }\n }, i * 80);\n i++;\n }\n }\n\n // Tell the host which symbols are on screen. Only the primary instance\n // speaks for the page: duplicated watchlist panels have their own filters,\n // and the page has one ticker for them to fight over.\n _publishVisible(): void {\n if (!this._host.isPrimary) return;\n this._host.ticker.publish(this._visible().map(i => String(i.symbol)), this.stats);\n }\n\n static _priceText(price: number | null | undefined): string {\n const n = Number(price);\n if (price == null || !isFinite(n) || n === 0) return '--';\n if (n >= 1) return n.toFixed(2);\n if (n >= 0.01) return n.toFixed(4);\n return n.toFixed(6);\n }\n\n static _changeText(chgPct: number | null | undefined): string {\n const pct = Number(chgPct);\n if (chgPct == null || !isFinite(pct)) return '--';\n return `${pct >= 0 ? '+' : ''}${pct.toFixed(2)}%`;\n }\n\n static _changeClass(chgPct: number | null | undefined): string {\n const pct = Number(chgPct);\n if (chgPct == null || !isFinite(pct)) return '';\n return pct >= 0 ? 'up' : 'down';\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["i"]
7
+ }
@@ -0,0 +1,52 @@
1
+ import { TradingHost } from './trading-host.js';
2
+ import type { OrderRow } from './trading-data.js';
3
+ import { DataGrid, GridColumn } from '@stocksharp/grids/data-grid';
4
+ export declare const OrderStates: {
5
+ readonly PendingRisk: 1;
6
+ readonly Sent: 2;
7
+ readonly Active: 3;
8
+ readonly PartiallyFilled: 4;
9
+ readonly Filled: 5;
10
+ readonly Rejected: 6;
11
+ readonly Cancelled: 7;
12
+ };
13
+ export interface ActiveOrdersDeps {
14
+ host: TradingHost;
15
+ cancelOrder(orderId: number): void;
16
+ dismissOrder(orderId: number): void;
17
+ editOrderField(orderId: number, field: string): void;
18
+ replaceOrder(orderId: number, quantity: number, limitPrice: number, stopPrice: number): void;
19
+ cancelAllOrders(): void;
20
+ refreshOrders(): void;
21
+ }
22
+ export declare class ActiveOrdersWidget {
23
+ static TYPE: "activeOrders";
24
+ rootEl: HTMLElement;
25
+ el: HTMLElement | null;
26
+ _host: TradingHost;
27
+ _deps: ActiveOrdersDeps;
28
+ _closeBtn: HTMLElement | null;
29
+ _cancelAllBtn: HTMLElement | null;
30
+ _refreshBtn: HTMLElement | null;
31
+ _exportBtn: HTMLElement | null;
32
+ _orders: OrderRow[];
33
+ _grid: DataGrid<OrderRow> | null;
34
+ static create(hostEl: HTMLElement, state: Record<string, unknown>, deps: ActiveOrdersDeps): ActiveOrdersWidget;
35
+ static _buildRoot(host: TradingHost): HTMLElement;
36
+ constructor(rootEl: HTMLElement, _state: Record<string, unknown>, deps: ActiveOrdersDeps);
37
+ dispose(): void;
38
+ update(orders: OrderRow[]): void;
39
+ _export(): void;
40
+ applyDelta(order: OrderRow): void;
41
+ removeOrder(orderId: number): void;
42
+ getOrder(orderId: number): OrderRow | undefined;
43
+ startInlineEdit(orderId: number, field: 'quantity' | 'limitPrice' | 'stopPrice'): void;
44
+ _columns(): GridColumn<OrderRow>[];
45
+ static _rowClass(order: OrderRow): string;
46
+ static _canEdit(order: OrderRow, field: 'quantity' | 'limitPrice' | 'stopPrice'): boolean;
47
+ static _editableClass(order: OrderRow, field: 'quantity' | 'limitPrice' | 'stopPrice'): string;
48
+ _bindInlineEdit(td: HTMLTableCellElement, order: OrderRow, field: 'quantity' | 'limitPrice' | 'stopPrice'): void;
49
+ _statusCell(order: OrderRow): string | Node;
50
+ _actionButton(order: OrderRow): Node;
51
+ }
52
+ //# sourceMappingURL=active-orders-widget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-orders-widget.d.ts","sourceRoot":"","sources":["../../src/active-orders-widget.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,WAAW,EAAc,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAM1E,eAAO,MAAM,WAAW;;;;;;;;CAQd,CAAC;AAIX,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrD,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7F,eAAe,IAAI,IAAI,CAAC;IACxB,aAAa,IAAI,IAAI,CAAC;CACzB;AAED,qBAAa,kBAAkB;IAC3B,MAAM,CAAC,IAAI,iBAA6B;IAExC,MAAM,EAAE,WAAW,CAAC;IACpB,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAEvB,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,gBAAgB,CAAC;IACxB,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,WAAW,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAEjC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,gBAAgB,GAAG,kBAAkB;IAsB9G,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW;gBAuBrC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,gBAAgB;IA2DxF,OAAO,IAAI,IAAI;IAKf,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI;IAQhC,OAAO,IAAI,IAAI;IASf,UAAU,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAajC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQlC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI/C,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,IAAI;IAsCtF,QAAQ,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE;IAyFlC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM;IAUzC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO;IAKzF,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,MAAM;IAM9F,eAAe,CAAC,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,IAAI;IAUhH,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI;IAmB3C,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;CAoBvC"}
@@ -0,0 +1,8 @@
1
+ export declare const ControlTypes: {
2
+ readonly Watchlist: "watchlist";
3
+ readonly ActiveOrders: "activeOrders";
4
+ readonly TradeHistory: "tradeHistory";
5
+ readonly Positions: "positions";
6
+ };
7
+ export type ControlType = typeof ControlTypes[keyof typeof ControlTypes];
8
+ //# sourceMappingURL=control-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-types.d.ts","sourceRoot":"","sources":["../../src/control-types.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,YAAY;;;;;CAKf,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function makeElement(tag: string, className: string, attrs: Record<string, string>, children: Array<Node | string>): HTMLElement;
2
+ export declare function makeIcon(iconClass: string): HTMLElement;
3
+ export declare function makeIconButton(className: string, label: string, iconClass: string, attrs: Record<string, string>): HTMLButtonElement;
4
+ export declare function makePanelRoot(modifierClass: string, label: string, children: Array<Node | string>): HTMLElement;
5
+ export declare function makePanelId(type: string): string;
6
+ //# sourceMappingURL=dom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/dom.ts"],"names":[],"mappings":"AAiBA,wBAAgB,WAAW,CACvB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7B,QAAQ,EAAE,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,GAC/B,WAAW,CAOb;AAID,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAEvD;AAMD,wBAAgB,cAAc,CAC1B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,iBAAiB,CAGnB;AASD,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,WAAW,CAE/G;AAKD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD"}
@@ -0,0 +1,8 @@
1
+ type Numeric = number | string | null | undefined;
2
+ export declare function formatPrice(price: Numeric): string;
3
+ export declare function formatQty(qty: Numeric): string;
4
+ export declare function formatTime(dateStr: string | number | Date | null | undefined): string;
5
+ export declare function formatPnl(pnl: Numeric): string;
6
+ export declare function cleanRejectReason(reason: string | null | undefined): string;
7
+ export {};
8
+ //# sourceMappingURL=formatters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../../src/formatters.ts"],"names":[],"mappings":"AASA,KAAK,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAMlD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAWlD;AAKD,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAK9C;AAID,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGrF;AAID,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAK9C;AAOD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAY3E"}
@@ -0,0 +1,16 @@
1
+ export { MarketDataLevels, PRESENTATION_CLASSES, assertHost } from './trading-host.js';
2
+ export type { HostStore, MarketDataClient, MarketDataLevel, TickerSink, TradingApi, TradingContext, TradingControl, TradingHost, TradingPresentation, } from './trading-host.js';
3
+ export type { BalanceRow, InstrumentRow, OrderRow, OrderSide, OrderStatus, OrderType, PositionRow, QuoteStats, TradeRow, } from './trading-data.js';
4
+ export { ControlTypes } from './control-types.js';
5
+ export type { ControlType } from './control-types.js';
6
+ export { cleanRejectReason, formatPnl, formatPrice, formatQty, formatTime } from './formatters.js';
7
+ export { makeElement, makeIcon, makeIconButton, makePanelId, makePanelRoot } from './dom.js';
8
+ export { ActiveOrdersWidget, OrderStates } from './active-orders-widget.js';
9
+ export type { ActiveOrdersDeps } from './active-orders-widget.js';
10
+ export { PositionsWidget } from './positions-widget.js';
11
+ export type { PositionsDeps } from './positions-widget.js';
12
+ export { TradeHistoryWidget } from './trade-history-widget.js';
13
+ export type { TradeHistoryDeps } from './trade-history-widget.js';
14
+ export { WatchlistWidget } from './watchlist-widget.js';
15
+ export type { WatchlistDeps } from './watchlist-widget.js';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEvF,YAAY,EACR,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,WAAW,EACX,mBAAmB,GACtB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACR,UAAU,EACV,aAAa,EACb,QAAQ,EACR,SAAS,EACT,WAAW,EACX,SAAS,EACT,WAAW,EACX,UAAU,EACV,QAAQ,GACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAKnG,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE7F,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE5E,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { TradingHost } from './trading-host.js';
2
+ import type { BalanceRow, PositionRow } from './trading-data.js';
3
+ import { DataGrid, GridColumn, GridPinnedRow } from '@stocksharp/grids/data-grid';
4
+ export interface PositionsDeps {
5
+ host: TradingHost;
6
+ closePosition(portfolioId: number, instrumentId: number, symbol: string): void;
7
+ reversePosition(portfolioId: number, instrumentId: number, symbol: string): void;
8
+ refreshPositions(): void;
9
+ }
10
+ export declare class PositionsWidget {
11
+ static TYPE: "positions";
12
+ rootEl: HTMLElement;
13
+ el: HTMLElement | null;
14
+ _host: TradingHost;
15
+ _deps: PositionsDeps;
16
+ _closeBtn: HTMLElement | null;
17
+ _refreshBtn: HTMLElement | null;
18
+ _exportBtn: HTMLElement | null;
19
+ _positions: PositionRow[];
20
+ _balance: BalanceRow | null;
21
+ _grid: DataGrid<PositionRow> | null;
22
+ static create(hostEl: HTMLElement, state: Record<string, unknown>, deps: PositionsDeps): PositionsWidget;
23
+ static _buildRoot(host: TradingHost): HTMLElement;
24
+ constructor(rootEl: HTMLElement, _state: Record<string, unknown>, deps: PositionsDeps);
25
+ dispose(): void;
26
+ update(positions: PositionRow[]): void;
27
+ updateBalance(balance: BalanceRow | null): void;
28
+ applyDelta(position: PositionRow): void;
29
+ _export(): void;
30
+ _columns(): GridColumn<PositionRow>[];
31
+ _pinnedRows(): GridPinnedRow[];
32
+ static _totalPnl(position: PositionRow): number;
33
+ static _key(position: PositionRow): string;
34
+ _actionButtons(position: PositionRow): Node;
35
+ _actionButton(styleClass: string, iconClass: string, title: string, label: string, onClick: () => void): HTMLButtonElement;
36
+ }
37
+ //# sourceMappingURL=positions-widget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"positions-widget.d.ts","sourceRoot":"","sources":["../../src/positions-widget.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,WAAW,EAAc,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAwB,MAAM,oCAAoC,CAAC;AAK/G,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/E,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACjF,gBAAgB,IAAI,IAAI,CAAC;CAC5B;AAED,qBAAa,eAAe;IACxB,MAAM,CAAC,IAAI,cAA0B;IAErC,MAAM,EAAE,WAAW,CAAC;IACpB,EAAE,EAAE,WAAW,GAAG,IAAI,CAAC;IAIvB,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/B,UAAU,EAAE,WAAW,EAAE,CAAC;IAC1B,QAAQ,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;IAEpC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,GAAG,eAAe;IAoBxG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW;gBAsBrC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa;IAwDrF,OAAO,IAAI,IAAI;IAKf,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,IAAI;IAOtC,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI;IAQ/C,UAAU,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI;IAoBvC,OAAO,IAAI,IAAI;IAQf,QAAQ,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE;IAqDrC,WAAW,IAAI,aAAa,EAAE;IAqB9B,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM;IAI/C,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM;IAO1C,cAAc,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI;IAa3C,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,iBAAiB;CAY7H"}