@stocksharp/trading-controls 1.1.0 → 1.2.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.
- package/dist/esm/active-orders-widget.js +38 -25
- package/dist/esm/active-orders-widget.js.map +1 -1
- package/dist/esm/trade-history-widget.js +14 -6
- package/dist/esm/trade-history-widget.js.map +1 -1
- package/dist/esm/tradefeed-widget.js +3 -3
- package/dist/esm/tradefeed-widget.js.map +1 -1
- package/dist/esm/trading-host.js +1 -0
- package/dist/esm/trading-host.js.map +1 -1
- package/dist/sstradingcontrols.js +51 -31
- package/dist/sstradingcontrols.js.map +2 -2
- package/dist/types/active-orders-widget.d.ts +11 -3
- package/dist/types/active-orders-widget.d.ts.map +1 -1
- package/dist/types/trade-history-widget.d.ts +3 -1
- package/dist/types/trade-history-widget.d.ts.map +1 -1
- package/dist/types/trading-host.d.ts +1 -0
- package/dist/types/trading-host.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/active-orders-widget.ts +49 -25
- package/src/trade-history-widget.ts +19 -6
- package/src/tradefeed-widget.ts +3 -3
- package/src/trading-host.ts +8 -0
|
@@ -10,8 +10,7 @@ export declare const OrderStates: {
|
|
|
10
10
|
readonly Rejected: 6;
|
|
11
11
|
readonly Cancelled: 7;
|
|
12
12
|
};
|
|
13
|
-
export interface
|
|
14
|
-
host: TradingHost;
|
|
13
|
+
export interface ActiveOrdersActions {
|
|
15
14
|
cancelOrder(orderId: number): void;
|
|
16
15
|
dismissOrder(orderId: number): void;
|
|
17
16
|
editOrderField(orderId: number, field: string): void;
|
|
@@ -19,12 +18,21 @@ export interface ActiveOrdersDeps {
|
|
|
19
18
|
cancelAllOrders(): void;
|
|
20
19
|
refreshOrders(): void;
|
|
21
20
|
}
|
|
21
|
+
export type ActiveOrdersDeps = ({
|
|
22
|
+
host: TradingHost;
|
|
23
|
+
readOnly?: false;
|
|
24
|
+
} & ActiveOrdersActions) | {
|
|
25
|
+
host: TradingHost;
|
|
26
|
+
readOnly: true;
|
|
27
|
+
};
|
|
22
28
|
export declare class ActiveOrdersWidget {
|
|
23
29
|
static TYPE: "activeOrders";
|
|
24
30
|
rootEl: HTMLElement;
|
|
25
31
|
el: HTMLElement | null;
|
|
26
32
|
_host: TradingHost;
|
|
27
33
|
_deps: ActiveOrdersDeps;
|
|
34
|
+
_readOnly: boolean;
|
|
35
|
+
_actions: ActiveOrdersActions | null;
|
|
28
36
|
_closeBtn: HTMLElement | null;
|
|
29
37
|
_cancelAllBtn: HTMLElement | null;
|
|
30
38
|
_refreshBtn: HTMLElement | null;
|
|
@@ -32,7 +40,7 @@ export declare class ActiveOrdersWidget {
|
|
|
32
40
|
_orders: OrderRow[];
|
|
33
41
|
_grid: DataGrid<OrderRow> | null;
|
|
34
42
|
static create(hostEl: HTMLElement, state: Record<string, unknown>, deps: ActiveOrdersDeps): ActiveOrdersWidget;
|
|
35
|
-
static _buildRoot(host: TradingHost): HTMLElement;
|
|
43
|
+
static _buildRoot(host: TradingHost, readOnly?: boolean): HTMLElement;
|
|
36
44
|
constructor(rootEl: HTMLElement, _state: Record<string, unknown>, deps: ActiveOrdersDeps);
|
|
37
45
|
dispose(): void;
|
|
38
46
|
update(orders: OrderRow[]): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"active-orders-widget.d.ts","sourceRoot":"","sources":["../../src/active-orders-widget.ts"],"names":[],"mappings":"AAkBA,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,
|
|
1
|
+
{"version":3,"file":"active-orders-widget.d.ts","sourceRoot":"","sources":["../../src/active-orders-widget.ts"],"names":[],"mappings":"AAkBA,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,mBAAmB;IAChC,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;AAUD,MAAM,MAAM,gBAAgB,GACtB,CAAC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG,mBAAmB,CAAC,GAC/D;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,CAAC;AAE5C,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,OAAO,CAAC;IACnB,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,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,EAAE,QAAQ,UAAQ,GAAG,WAAW;gBAyBvD,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,gBAAgB;IAuExF,OAAO,IAAI,IAAI;IAQf,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;IAWhH,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI;IAmB3C,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;CAqBvC"}
|
|
@@ -3,6 +3,7 @@ import type { TradeRow } from './trading-data.js';
|
|
|
3
3
|
import { DataGrid, GridColumn } from '@stocksharp/grids/data-grid';
|
|
4
4
|
export interface TradeHistoryDeps {
|
|
5
5
|
host: TradingHost;
|
|
6
|
+
readOnly?: boolean;
|
|
6
7
|
}
|
|
7
8
|
export declare class TradeHistoryWidget {
|
|
8
9
|
static TYPE: "tradeHistory";
|
|
@@ -15,10 +16,11 @@ export declare class TradeHistoryWidget {
|
|
|
15
16
|
_rows: TradeRow[];
|
|
16
17
|
_grid: DataGrid<TradeRow> | null;
|
|
17
18
|
static create(hostEl: HTMLElement, state: Record<string, unknown>, deps: TradeHistoryDeps): TradeHistoryWidget;
|
|
18
|
-
static _buildRoot(host: TradingHost): HTMLElement;
|
|
19
|
+
static _buildRoot(host: TradingHost, readOnly?: boolean): HTMLElement;
|
|
19
20
|
constructor(rootEl: HTMLElement, _state: Record<string, unknown>, deps: TradeHistoryDeps);
|
|
20
21
|
dispose(): void;
|
|
21
22
|
refresh(): Promise<void>;
|
|
23
|
+
update(rows: TradeRow[]): void;
|
|
22
24
|
_export(): void;
|
|
23
25
|
_columns(): GridColumn<TradeRow>[];
|
|
24
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trade-history-widget.d.ts","sourceRoot":"","sources":["../../src/trade-history-widget.ts"],"names":[],"mappings":"AAkBA,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;AAI1E,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"trade-history-widget.d.ts","sourceRoot":"","sources":["../../src/trade-history-widget.ts"],"names":[],"mappings":"AAkBA,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;AAI1E,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,WAAW,CAAC;IAIlB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,qBAAa,kBAAkB;IAC3B,MAAM,CAAC,IAAI,iBAA6B;IAExC,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAE3B,KAAK,EAAE,WAAW,CAAC;IACnB,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,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;IAa9G,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,UAAQ,GAAG,WAAW;gBAsBvD,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,gBAAgB;IA8CxF,OAAO,IAAI,IAAI;IAsBT,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB9B,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI;IAM9B,OAAO,IAAI,IAAI;IAMf,QAAQ,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE;CA8DrC"}
|
|
@@ -10,6 +10,7 @@ export interface TradingPresentation {
|
|
|
10
10
|
isBuy(side: OrderSide): boolean;
|
|
11
11
|
typeText(type: OrderType, limitPrice: number, stopPrice: number): string;
|
|
12
12
|
statusText(status: OrderStatus): string;
|
|
13
|
+
timeText(value: string | number | Date): string;
|
|
13
14
|
sideClass(side: OrderSide): string;
|
|
14
15
|
pnlClass(pnl: number): string;
|
|
15
16
|
canvasPalette(): CanvasPalette;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trading-host.d.ts","sourceRoot":"","sources":["../../src/trading-host.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAY1H,MAAM,WAAW,aAAa;IAE1B,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,EAAE,MAAM,CAAC;IAEb,IAAI,EAAE,MAAM,CAAC;IAMb,IAAI,EAAE,MAAM,CAAC;CAChB;AAcD,MAAM,WAAW,mBAAmB;IAEhC,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IAMlC,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAIhC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAEzE,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"trading-host.d.ts","sourceRoot":"","sources":["../../src/trading-host.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stocksharp/trading-controls",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Browser trading controls for StockSharp: order blotters, positions, trade history, watchlist and trade feed, each built against one host port and rendering its own DOM.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "git+https://github.com/StockSharp/JS-TradingControls.git"
|
|
13
13
|
},
|
|
14
|
-
"homepage": "https://
|
|
14
|
+
"homepage": "https://stocksharp.com",
|
|
15
15
|
"bugs": {
|
|
16
16
|
"url": "https://github.com/StockSharp/JS-TradingControls/issues"
|
|
17
17
|
},
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
"release:major": "npm version major -m \"chore: release v%s\""
|
|
137
137
|
},
|
|
138
138
|
"dependencies": {
|
|
139
|
-
"@stocksharp/grids": "^1.1.
|
|
139
|
+
"@stocksharp/grids": "^1.1.1"
|
|
140
140
|
},
|
|
141
141
|
"devDependencies": {
|
|
142
142
|
"@stocksharp/chart": "^0.2.3",
|
|
@@ -34,10 +34,9 @@ export const OrderStates = {
|
|
|
34
34
|
Cancelled: 7,
|
|
35
35
|
} as const;
|
|
36
36
|
|
|
37
|
-
///
|
|
38
|
-
///
|
|
39
|
-
export interface
|
|
40
|
-
host: TradingHost;
|
|
37
|
+
/// The gestures that reach a venue. All required together: a panel that can
|
|
38
|
+
/// cancel one order but not all of them is a panel half-wired.
|
|
39
|
+
export interface ActiveOrdersActions {
|
|
41
40
|
cancelOrder(orderId: number): void;
|
|
42
41
|
dismissOrder(orderId: number): void;
|
|
43
42
|
editOrderField(orderId: number, field: string): void;
|
|
@@ -46,6 +45,18 @@ export interface ActiveOrdersDeps {
|
|
|
46
45
|
refreshOrders(): void;
|
|
47
46
|
}
|
|
48
47
|
|
|
48
|
+
/// What the blotter needs beyond the host port, in one of two shapes.
|
|
49
|
+
///
|
|
50
|
+
/// A live blotter carries every action, because a panel that cannot cancel,
|
|
51
|
+
/// modify or reload its orders is not that panel. A read-only one carries none:
|
|
52
|
+
/// over a finished run - a backtest report, an archived session - there is no
|
|
53
|
+
/// venue left to reach, and the gestures that would reach it are not rendered
|
|
54
|
+
/// rather than rendered and wired to nothing. The union states that, so a live
|
|
55
|
+
/// consumer still cannot omit an action by accident.
|
|
56
|
+
export type ActiveOrdersDeps =
|
|
57
|
+
| ({ host: TradingHost; readOnly?: false } & ActiveOrdersActions)
|
|
58
|
+
| { host: TradingHost; readOnly: true };
|
|
59
|
+
|
|
49
60
|
export class ActiveOrdersWidget {
|
|
50
61
|
static TYPE = ControlTypes.ActiveOrders;
|
|
51
62
|
|
|
@@ -54,6 +65,8 @@ export class ActiveOrdersWidget {
|
|
|
54
65
|
// `//` rather than `///` from here down — see the note in positions-widget.
|
|
55
66
|
_host: TradingHost;
|
|
56
67
|
_deps: ActiveOrdersDeps;
|
|
68
|
+
_readOnly: boolean;
|
|
69
|
+
_actions: ActiveOrdersActions | null;
|
|
57
70
|
_closeBtn: HTMLElement | null;
|
|
58
71
|
_cancelAllBtn: HTMLElement | null;
|
|
59
72
|
_refreshBtn: HTMLElement | null;
|
|
@@ -66,7 +79,7 @@ export class ActiveOrdersWidget {
|
|
|
66
79
|
// host, so a missing host has to fail here rather than render a panel
|
|
67
80
|
// captioned with raw English keys.
|
|
68
81
|
const host = assertHost(deps?.host, 'ActiveOrdersWidget');
|
|
69
|
-
const root = ActiveOrdersWidget._buildRoot(host);
|
|
82
|
+
const root = ActiveOrdersWidget._buildRoot(host, deps?.readOnly === true);
|
|
70
83
|
root.id = makePanelId(ActiveOrdersWidget.TYPE);
|
|
71
84
|
hostEl.appendChild(root);
|
|
72
85
|
return new ActiveOrdersWidget(root, state || {}, deps);
|
|
@@ -83,7 +96,7 @@ export class ActiveOrdersWidget {
|
|
|
83
96
|
// already give the identical button — and are wired to deps. Cancel-all
|
|
84
97
|
// keeps a distinct accessible name from its tooltip, which is why it states
|
|
85
98
|
// `aria-label` rather than taking the tooltip for both.
|
|
86
|
-
static _buildRoot(host: TradingHost): HTMLElement {
|
|
99
|
+
static _buildRoot(host: TradingHost, readOnly = false): HTMLElement {
|
|
87
100
|
return makePanelRoot('active-orders-panel', host.t('ActiveOrders'), [
|
|
88
101
|
makeElement('div', 'panel-header', {}, [
|
|
89
102
|
makeElement('span', '', {}, [host.t('OpenOrders')]),
|
|
@@ -97,9 +110,11 @@ export class ActiveOrdersWidget {
|
|
|
97
110
|
]),
|
|
98
111
|
]),
|
|
99
112
|
makeElement('div', 'panel-rail', { role: 'toolbar', 'aria-label': host.t('ActiveOrdersActions') }, [
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
113
|
+
...(readOnly ? [] : [
|
|
114
|
+
makeIconButton('bt-icon-btn bt-icon-cancel-all panel-cancel-all-btn', host.t('CancelAll'), 'bi-x-circle',
|
|
115
|
+
{ 'aria-label': host.t('CancelAllOrders') }),
|
|
116
|
+
makeIconButton('bt-icon-btn panel-refresh-btn', host.t('Refresh'), 'bi-arrow-clockwise', {}),
|
|
117
|
+
]),
|
|
103
118
|
makeIconButton('bt-icon-btn panel-export-btn', host.t('ExportToExcel'), 'bi-file-earmark-spreadsheet', {}),
|
|
104
119
|
]),
|
|
105
120
|
]),
|
|
@@ -108,9 +123,16 @@ export class ActiveOrdersWidget {
|
|
|
108
123
|
|
|
109
124
|
constructor(rootEl: HTMLElement, _state: Record<string, unknown>, deps: ActiveOrdersDeps) {
|
|
110
125
|
this._host = assertHost(deps?.host, 'ActiveOrdersWidget');
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
126
|
+
this._readOnly = deps?.readOnly === true;
|
|
127
|
+
if (this._readOnly) {
|
|
128
|
+
this._actions = null;
|
|
129
|
+
} else {
|
|
130
|
+
const actions = deps as ActiveOrdersActions;
|
|
131
|
+
for (const name of ['cancelOrder', 'dismissOrder', 'editOrderField', 'replaceOrder', 'cancelAllOrders', 'refreshOrders'] as const) {
|
|
132
|
+
if (typeof actions?.[name] !== 'function')
|
|
133
|
+
throw new Error(`ActiveOrdersWidget: dep "${name}" is required`);
|
|
134
|
+
}
|
|
135
|
+
this._actions = actions;
|
|
114
136
|
}
|
|
115
137
|
|
|
116
138
|
this.rootEl = rootEl;
|
|
@@ -129,12 +151,12 @@ export class ActiveOrdersWidget {
|
|
|
129
151
|
|
|
130
152
|
this._cancelAllBtn?.addEventListener('click', (e) => {
|
|
131
153
|
e.preventDefault();
|
|
132
|
-
this.
|
|
154
|
+
this._actions?.cancelAllOrders();
|
|
133
155
|
});
|
|
134
156
|
|
|
135
157
|
this._refreshBtn?.addEventListener('click', (e) => {
|
|
136
158
|
e.preventDefault();
|
|
137
|
-
this.
|
|
159
|
+
this._actions?.refreshOrders();
|
|
138
160
|
});
|
|
139
161
|
|
|
140
162
|
this._exportBtn?.addEventListener('click', (e) => {
|
|
@@ -246,7 +268,7 @@ export class ActiveOrdersWidget {
|
|
|
246
268
|
if (newVal === currentValue) { this.update(this._orders); return; }
|
|
247
269
|
const updated = { quantity: order.quantity, limitPrice: order.limitPrice, stopPrice: order.stopPrice };
|
|
248
270
|
updated[field] = newVal;
|
|
249
|
-
this.
|
|
271
|
+
this._actions?.replaceOrder(orderId, updated.quantity!, updated.limitPrice!, updated.stopPrice!);
|
|
250
272
|
};
|
|
251
273
|
input.addEventListener('blur', commit);
|
|
252
274
|
input.addEventListener('keydown', (e) => {
|
|
@@ -305,7 +327,7 @@ export class ActiveOrdersWidget {
|
|
|
305
327
|
exportable: true,
|
|
306
328
|
value: (o) => o.quantity,
|
|
307
329
|
render: (o) => formatQty(o.quantity),
|
|
308
|
-
cellClass: (o) => ActiveOrdersWidget._editableClass(o, 'quantity'),
|
|
330
|
+
cellClass: (o) => this._readOnly ? '' : ActiveOrdersWidget._editableClass(o, 'quantity'),
|
|
309
331
|
bindCell: (td, o) => this._bindInlineEdit(td, o, 'quantity'),
|
|
310
332
|
},
|
|
311
333
|
{
|
|
@@ -314,7 +336,7 @@ export class ActiveOrdersWidget {
|
|
|
314
336
|
exportable: true,
|
|
315
337
|
value: (o) => o.limitPrice,
|
|
316
338
|
render: (o) => o.limitPrice ? formatPrice(o.limitPrice) : label('MKT'),
|
|
317
|
-
cellClass: (o) => ActiveOrdersWidget._editableClass(o, 'limitPrice'),
|
|
339
|
+
cellClass: (o) => this._readOnly ? '' : ActiveOrdersWidget._editableClass(o, 'limitPrice'),
|
|
318
340
|
bindCell: (td, o) => this._bindInlineEdit(td, o, 'limitPrice'),
|
|
319
341
|
exportValue: (o) => o.limitPrice ?? label('MKT'),
|
|
320
342
|
},
|
|
@@ -324,7 +346,7 @@ export class ActiveOrdersWidget {
|
|
|
324
346
|
exportable: true,
|
|
325
347
|
value: (o) => o.stopPrice,
|
|
326
348
|
render: (o) => o.stopPrice ? formatPrice(o.stopPrice) : '--',
|
|
327
|
-
cellClass: (o) => ActiveOrdersWidget._editableClass(o, 'stopPrice'),
|
|
349
|
+
cellClass: (o) => this._readOnly ? '' : ActiveOrdersWidget._editableClass(o, 'stopPrice'),
|
|
328
350
|
bindCell: (td, o) => this._bindInlineEdit(td, o, 'stopPrice'),
|
|
329
351
|
exportValue: (o) => o.stopPrice ?? '',
|
|
330
352
|
},
|
|
@@ -336,14 +358,14 @@ export class ActiveOrdersWidget {
|
|
|
336
358
|
render: (o) => this._statusCell(o),
|
|
337
359
|
exportValue: (o) => presentation.statusText(o.status!),
|
|
338
360
|
},
|
|
339
|
-
{
|
|
361
|
+
...(this._readOnly ? [] : [{
|
|
340
362
|
key: 'actions',
|
|
341
363
|
header: label('Actions'),
|
|
342
364
|
headerHidden: true,
|
|
343
365
|
exportable: false,
|
|
344
366
|
cellClass: () => 'position-actions',
|
|
345
|
-
render: (o) => this._actionButton(o),
|
|
346
|
-
},
|
|
367
|
+
render: (o: OrderRow) => this._actionButton(o),
|
|
368
|
+
} as GridColumn<OrderRow>]),
|
|
347
369
|
];
|
|
348
370
|
}
|
|
349
371
|
|
|
@@ -369,8 +391,9 @@ export class ActiveOrdersWidget {
|
|
|
369
391
|
// Double-click to edit belongs to the whole cell rather than to a control
|
|
370
392
|
// inside it, which is why it is wired here instead of returned by render().
|
|
371
393
|
_bindInlineEdit(td: HTMLTableCellElement, order: OrderRow, field: 'quantity' | 'limitPrice' | 'stopPrice'): void {
|
|
372
|
-
if (!ActiveOrdersWidget._canEdit(order, field)) return;
|
|
373
|
-
|
|
394
|
+
if (this._actions === null || !ActiveOrdersWidget._canEdit(order, field)) return;
|
|
395
|
+
const edit = this._actions.editOrderField;
|
|
396
|
+
td.addEventListener('dblclick', () => edit(order.id!, field));
|
|
374
397
|
}
|
|
375
398
|
|
|
376
399
|
// Status text, plus a hoverable icon carrying the rejection reason. Some
|
|
@@ -412,8 +435,9 @@ export class ActiveOrdersWidget {
|
|
|
412
435
|
icon.className = 'bi bi-x-circle';
|
|
413
436
|
button.appendChild(icon);
|
|
414
437
|
button.addEventListener('click', () => {
|
|
415
|
-
if (
|
|
416
|
-
|
|
438
|
+
if (this._actions === null) return;
|
|
439
|
+
if (isTerminal) this._actions.dismissOrder(order.id!);
|
|
440
|
+
else this._actions.cancelOrder(order.id!);
|
|
417
441
|
});
|
|
418
442
|
return button;
|
|
419
443
|
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// The table is `DataGrid` from `@stocksharp/grids`: the columns below are this
|
|
13
13
|
// blotter's single declaration and the <thead> is left empty for the grid to
|
|
14
14
|
// fill.
|
|
15
|
-
import { formatPrice, formatQty
|
|
15
|
+
import { formatPrice, formatQty } from './formatters.js';
|
|
16
16
|
import { makeElement, makeIconButton, makePanelId, makePanelRoot } from './dom.js';
|
|
17
17
|
import { ControlTypes } from './control-types.js';
|
|
18
18
|
import { makeGridMenu } from './grid-menu.js';
|
|
@@ -24,6 +24,10 @@ import { DataGrid, GridColumn } from '@stocksharp/grids/source/data-grid';
|
|
|
24
24
|
/// portfolio and its lifecycle all arrive through it.
|
|
25
25
|
export interface TradeHistoryDeps {
|
|
26
26
|
host: TradingHost;
|
|
27
|
+
/// A blotter over a finished run - a backtest report, an archived session.
|
|
28
|
+
/// There is no account to load from and nothing to reload, so the rows come
|
|
29
|
+
/// in through `update` and the refresh gesture is not rendered.
|
|
30
|
+
readOnly?: boolean;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
export class TradeHistoryWidget {
|
|
@@ -44,7 +48,7 @@ export class TradeHistoryWidget {
|
|
|
44
48
|
// host, so a missing host has to fail here rather than render a panel
|
|
45
49
|
// captioned with raw English keys.
|
|
46
50
|
const host = assertHost(deps?.host, 'TradeHistoryWidget');
|
|
47
|
-
const root = TradeHistoryWidget._buildRoot(host);
|
|
51
|
+
const root = TradeHistoryWidget._buildRoot(host, deps?.readOnly === true);
|
|
48
52
|
root.id = makePanelId(TradeHistoryWidget.TYPE);
|
|
49
53
|
hostEl.appendChild(root);
|
|
50
54
|
return new TradeHistoryWidget(root, state || {}, deps);
|
|
@@ -52,7 +56,7 @@ export class TradeHistoryWidget {
|
|
|
52
56
|
|
|
53
57
|
// The panel's markup. The host stylesheet reads this structure, and a
|
|
54
58
|
// docking host lifts `.panel-header`'s children into its tab strip.
|
|
55
|
-
static _buildRoot(host: TradingHost): HTMLElement {
|
|
59
|
+
static _buildRoot(host: TradingHost, readOnly = false): HTMLElement {
|
|
56
60
|
const title = host.t('TradeHistory');
|
|
57
61
|
return makePanelRoot('trade-history-panel', title, [
|
|
58
62
|
makeElement('div', 'panel-header', {}, [
|
|
@@ -67,7 +71,7 @@ export class TradeHistoryWidget {
|
|
|
67
71
|
]),
|
|
68
72
|
]),
|
|
69
73
|
makeElement('div', 'panel-rail', { role: 'toolbar', 'aria-label': host.t('TradeHistoryActions') }, [
|
|
70
|
-
makeIconButton('bt-icon-btn panel-refresh-btn', host.t('Refresh'), 'bi-arrow-clockwise', {}),
|
|
74
|
+
...(readOnly ? [] : [makeIconButton('bt-icon-btn panel-refresh-btn', host.t('Refresh'), 'bi-arrow-clockwise', {})]),
|
|
71
75
|
makeIconButton('bt-icon-btn panel-export-btn', host.t('ExportToExcel'), 'bi-file-earmark-spreadsheet', {}),
|
|
72
76
|
]),
|
|
73
77
|
]),
|
|
@@ -157,6 +161,15 @@ export class TradeHistoryWidget {
|
|
|
157
161
|
}
|
|
158
162
|
}
|
|
159
163
|
|
|
164
|
+
/// Show these rows. The push path, for a consumer that already holds the
|
|
165
|
+
/// trades - a finished run's report - rather than an account to load them
|
|
166
|
+
/// from. `refresh` is the pull path and the two do not mix: whichever ran
|
|
167
|
+
/// last is what the grid shows.
|
|
168
|
+
update(rows: TradeRow[]): void {
|
|
169
|
+
this._rows = rows || [];
|
|
170
|
+
this._grid?.setRows(this._rows);
|
|
171
|
+
}
|
|
172
|
+
|
|
160
173
|
// Export the table to .xlsx in the currently rendered (sorted) order.
|
|
161
174
|
_export(): void {
|
|
162
175
|
this._grid?.download('trades', this._host.t('TradeHistory'));
|
|
@@ -184,8 +197,8 @@ export class TradeHistoryWidget {
|
|
|
184
197
|
header: label('Time'),
|
|
185
198
|
exportable: true,
|
|
186
199
|
value: (t) => t.executedAt || t.time,
|
|
187
|
-
render: (t) =>
|
|
188
|
-
exportValue: (t) =>
|
|
200
|
+
render: (t) => presentation.timeText(t.executedAt || t.time!),
|
|
201
|
+
exportValue: (t) => presentation.timeText(t.executedAt || t.time!),
|
|
189
202
|
},
|
|
190
203
|
{
|
|
191
204
|
key: 'symbol',
|
package/src/tradefeed-widget.ts
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
// geometry comes out of `tradefeed-bubbles.ts` as numbers and its colours out
|
|
21
21
|
// of the host's `canvasPalette()`, so the package still paints nothing from a
|
|
22
22
|
// palette of its own.
|
|
23
|
-
import { formatPrice, formatQty
|
|
23
|
+
import { formatPrice, formatQty } from './formatters.js';
|
|
24
24
|
import { makeElement, makeIconButton, makePanelId, makePanelRoot } from './dom.js';
|
|
25
25
|
import { ControlTypes } from './control-types.js';
|
|
26
26
|
import { makeGridMenu } from './grid-menu.js';
|
|
@@ -372,7 +372,7 @@ export class TradeFeedWidget {
|
|
|
372
372
|
header: label('Time'),
|
|
373
373
|
exportable: true,
|
|
374
374
|
value: (t) => String(t.time || t.executedAt || ''),
|
|
375
|
-
render: (t) =>
|
|
375
|
+
render: (t) => this._host.presentation.timeText(t.time || t.executedAt!),
|
|
376
376
|
},
|
|
377
377
|
{
|
|
378
378
|
key: 'symbol',
|
|
@@ -708,7 +708,7 @@ export class TradeFeedWidget {
|
|
|
708
708
|
|
|
709
709
|
const lines: HTMLElement[] = [];
|
|
710
710
|
if (this._extraSymbols.size > 0) lines.push(this._tooltipLine(this._host.t('Symbol'), bubble.symbol, ''));
|
|
711
|
-
lines.push(this._tooltipLine(this._host.t('Time'),
|
|
711
|
+
lines.push(this._tooltipLine(this._host.t('Time'), this._host.presentation.timeText(bubble.time), ''));
|
|
712
712
|
lines.push(this._tooltipLine(aggregated ? this._host.t('VWAP') : this._host.t('Price'), formatPrice(bubble.price), ''));
|
|
713
713
|
lines.push(this._tooltipLine(aggregated ? this._host.t('Total qty') : this._host.t('Qty'), formatQty(bubble.quantity), ''));
|
|
714
714
|
lines.push(this._tooltipLine(this._host.t('Side'), presentation.sideText(side), presentation.sideClass(side)));
|
package/src/trading-host.ts
CHANGED
|
@@ -86,6 +86,13 @@ export interface TradingPresentation {
|
|
|
86
86
|
typeText(type: OrderType, limitPrice: number, stopPrice: number): string;
|
|
87
87
|
/// Localized order status.
|
|
88
88
|
statusText(status: OrderStatus): string;
|
|
89
|
+
/// A moment, worded. The host owns this for the same reason it owns a side or a
|
|
90
|
+
/// status: what a time should read as is not a property of the data. A live tape wants
|
|
91
|
+
/// the time of day in the reader's own zone; a blotter over a finished run wants the
|
|
92
|
+
/// date too, and in the zone the run was recorded in, or every row reads as the same
|
|
93
|
+
/// unplaceable day. `formatTime` is this package's tape answer, exported so a host that
|
|
94
|
+
/// wants exactly that need not restate it.
|
|
95
|
+
timeText(value: string | number | Date): string;
|
|
89
96
|
/// CSS class colouring a cell by side. The shipped stylesheet styles
|
|
90
97
|
/// `side-buy` and `side-sell`; a host on its own palette may answer with
|
|
91
98
|
/// its own names and style those instead.
|
|
@@ -271,6 +278,7 @@ export function assertHost(host: TradingHost, controlName: string): TradingHost
|
|
|
271
278
|
_required(host.presentation.isBuy, 'host.presentation.isBuy', 'function', controlName);
|
|
272
279
|
_required(host.presentation.typeText, 'host.presentation.typeText', 'function', controlName);
|
|
273
280
|
_required(host.presentation.statusText, 'host.presentation.statusText', 'function', controlName);
|
|
281
|
+
_required(host.presentation.timeText, 'host.presentation.timeText', 'function', controlName);
|
|
274
282
|
_required(host.presentation.sideClass, 'host.presentation.sideClass', 'function', controlName);
|
|
275
283
|
_required(host.presentation.pnlClass, 'host.presentation.pnlClass', 'function', controlName);
|
|
276
284
|
_required(host.presentation.canvasPalette, 'host.presentation.canvasPalette', 'function', controlName);
|