@tradejs/app 3.1.27-beta.250 → 3.1.28-beta.251
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/package.json +6 -6
- package/src/app/components/Strategies/RuntimeStrategyCard.tsx +55 -4
- package/src/app/components/Strategies/RuntimeStrategyConfigDrawer.tsx +13 -2
- package/src/app/components/Strategies/RuntimeStrategyRevisionsDrawer.tsx +3 -1
- package/src/app/components/Strategies/RuntimeStrategyStatsDrawer.tsx +3 -1
- package/src/app/routes/strategies/StrategiesPageClient.tsx +66 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/app",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.28-beta.251",
|
|
4
4
|
"description": "Installable Next.js UI for the TradeJS TypeScript framework: dashboards, backtests, charts, and runtime data.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -56,11 +56,11 @@
|
|
|
56
56
|
"@chakra-ui/charts": "3.36.1",
|
|
57
57
|
"@chakra-ui/react": "3.36.1",
|
|
58
58
|
"@emotion/react": "^11.14.0",
|
|
59
|
-
"@tradejs/core": "^3.1.
|
|
60
|
-
"@tradejs/indicators": "^3.1.
|
|
61
|
-
"@tradejs/infra": "^3.1.
|
|
62
|
-
"@tradejs/node": "^3.1.
|
|
63
|
-
"@tradejs/types": "^3.1.
|
|
59
|
+
"@tradejs/core": "^3.1.28-beta.251",
|
|
60
|
+
"@tradejs/indicators": "^3.1.28-beta.251",
|
|
61
|
+
"@tradejs/infra": "^3.1.28-beta.251",
|
|
62
|
+
"@tradejs/node": "^3.1.28-beta.251",
|
|
63
|
+
"@tradejs/types": "^3.1.28-beta.251",
|
|
64
64
|
"@types/bcryptjs": "2.4.6",
|
|
65
65
|
"@types/lodash": "4.17.24",
|
|
66
66
|
"@types/node": "24.13.3",
|
|
@@ -29,6 +29,21 @@ import {
|
|
|
29
29
|
} from './RuntimeStrategyCard.presenter';
|
|
30
30
|
import { toaster } from '#ui';
|
|
31
31
|
|
|
32
|
+
const DEPLOYMENT_PRESENTATIONS = [
|
|
33
|
+
{ accent: 'blue.400', colorPalette: 'blue' },
|
|
34
|
+
{ accent: 'purple.400', colorPalette: 'purple' },
|
|
35
|
+
{ accent: 'pink.400', colorPalette: 'pink' },
|
|
36
|
+
{ accent: 'cyan.400', colorPalette: 'cyan' },
|
|
37
|
+
] as const;
|
|
38
|
+
|
|
39
|
+
const getDeploymentPresentation = (deploymentId: string) => {
|
|
40
|
+
const hash = [...deploymentId].reduce(
|
|
41
|
+
(value, character) => (value * 31 + character.charCodeAt(0)) >>> 0,
|
|
42
|
+
0,
|
|
43
|
+
);
|
|
44
|
+
return DEPLOYMENT_PRESENTATIONS[hash % DEPLOYMENT_PRESENTATIONS.length];
|
|
45
|
+
};
|
|
46
|
+
|
|
32
47
|
const StatItem = ({
|
|
33
48
|
stat,
|
|
34
49
|
id,
|
|
@@ -73,6 +88,11 @@ export const RuntimeStrategyCard = ({
|
|
|
73
88
|
[strategy],
|
|
74
89
|
);
|
|
75
90
|
const { lastTrade, runtimeOrders } = viewModel;
|
|
91
|
+
const deploymentPresentation = getDeploymentPresentation(
|
|
92
|
+
strategy.deploymentId,
|
|
93
|
+
);
|
|
94
|
+
const strategyInstanceLabel = `${strategy.strategyName}, ${strategy.deploymentLabel}`;
|
|
95
|
+
const maxLossValue = strategy.config.MAX_LOSS_VALUE;
|
|
76
96
|
const setControlState = async (controlState: 'active' | 'entries_paused') => {
|
|
77
97
|
setControlSaving(true);
|
|
78
98
|
try {
|
|
@@ -112,12 +132,43 @@ export const RuntimeStrategyCard = ({
|
|
|
112
132
|
shadow="sm"
|
|
113
133
|
borderWidth="1px"
|
|
114
134
|
borderColor={strategy.connected ? 'gray.800' : 'orange.900'}
|
|
135
|
+
borderLeftWidth="4px"
|
|
136
|
+
borderLeftColor={deploymentPresentation.accent}
|
|
115
137
|
overflowX="auto"
|
|
116
138
|
>
|
|
117
139
|
<Flex gap="4" p={4} mb={3} alignItems="center" wrap="wrap">
|
|
118
|
-
<
|
|
119
|
-
{
|
|
120
|
-
|
|
140
|
+
<Flex direction="column" gap={1} minW="280px">
|
|
141
|
+
<Flex gap={2} alignItems="center" wrap="wrap">
|
|
142
|
+
<Text fontSize="lg" fontWeight="bold" color="gray.200">
|
|
143
|
+
{strategy.strategyName}
|
|
144
|
+
</Text>
|
|
145
|
+
<Badge
|
|
146
|
+
colorPalette={deploymentPresentation.colorPalette}
|
|
147
|
+
variant="subtle"
|
|
148
|
+
>
|
|
149
|
+
{strategy.deploymentLabel}
|
|
150
|
+
</Badge>
|
|
151
|
+
</Flex>
|
|
152
|
+
<Flex gap={3} alignItems="center" wrap="wrap">
|
|
153
|
+
<Text fontSize="xs" color="gray.400">
|
|
154
|
+
account: {strategy.accountLabel ?? strategy.accountId ?? 'none'}
|
|
155
|
+
</Text>
|
|
156
|
+
<Text fontSize="xs" color="gray.400">
|
|
157
|
+
version: {strategy.strategyPackageVersion}
|
|
158
|
+
</Text>
|
|
159
|
+
{strategy.generation ? (
|
|
160
|
+
<Text fontSize="xs" color="gray.400">
|
|
161
|
+
generation: {strategy.generation}
|
|
162
|
+
</Text>
|
|
163
|
+
) : null}
|
|
164
|
+
{typeof maxLossValue === 'number' &&
|
|
165
|
+
Number.isFinite(maxLossValue) ? (
|
|
166
|
+
<Text fontSize="xs" color="gray.400">
|
|
167
|
+
max loss: {maxLossValue}
|
|
168
|
+
</Text>
|
|
169
|
+
) : null}
|
|
170
|
+
</Flex>
|
|
171
|
+
</Flex>
|
|
121
172
|
<Badge
|
|
122
173
|
colorPalette={strategy.enabled ? 'teal' : 'gray'}
|
|
123
174
|
variant="subtle"
|
|
@@ -225,7 +276,7 @@ export const RuntimeStrategyCard = ({
|
|
|
225
276
|
</Flex>
|
|
226
277
|
|
|
227
278
|
<OrdersDrawerPanel
|
|
228
|
-
title={`${
|
|
279
|
+
title={`${strategyInstanceLabel} orders`}
|
|
229
280
|
open={ordersOpen}
|
|
230
281
|
orders={runtimeOrders}
|
|
231
282
|
rowHeight={RUNTIME_ORDER_ROW_HEIGHT}
|
|
@@ -30,7 +30,15 @@ export const RuntimeStrategyConfigDrawer = ({
|
|
|
30
30
|
const serviceInfo = [
|
|
31
31
|
{ label: 'Strategy revision', value: strategy.strategyRevision },
|
|
32
32
|
{ label: 'Runtime key', value: strategy.runtimeKey },
|
|
33
|
-
{ label: '
|
|
33
|
+
{ label: 'Strategy module', value: strategy.strategyModule },
|
|
34
|
+
{ label: 'Strategy package', value: strategy.strategyPackage },
|
|
35
|
+
{
|
|
36
|
+
label: 'Package version',
|
|
37
|
+
value: strategy.strategyPackageVersion,
|
|
38
|
+
},
|
|
39
|
+
{ label: 'Generation', value: strategy.generation ?? 'Not set' },
|
|
40
|
+
{ label: 'Deployment label', value: strategy.deploymentLabel },
|
|
41
|
+
{ label: 'Deployment ID', value: strategy.deploymentId },
|
|
34
42
|
{
|
|
35
43
|
label: 'Configured tickers',
|
|
36
44
|
value: strategy.selection?.tickers?.length ?? 'All available',
|
|
@@ -70,7 +78,10 @@ export const RuntimeStrategyConfigDrawer = ({
|
|
|
70
78
|
<Drawer.Positioner>
|
|
71
79
|
<Drawer.Content bg="gray.950">
|
|
72
80
|
<Drawer.Header>
|
|
73
|
-
<Drawer.Title>
|
|
81
|
+
<Drawer.Title>
|
|
82
|
+
{strategy.strategyName}, {strategy.deploymentLabel}{' '}
|
|
83
|
+
configuration
|
|
84
|
+
</Drawer.Title>
|
|
74
85
|
<Drawer.CloseTrigger asChild>
|
|
75
86
|
<CloseButton size="sm" />
|
|
76
87
|
</Drawer.CloseTrigger>
|
|
@@ -85,7 +85,9 @@ export const RuntimeStrategyRevisionsDrawer = ({
|
|
|
85
85
|
<Drawer.Positioner>
|
|
86
86
|
<Drawer.Content bg="gray.950">
|
|
87
87
|
<Drawer.Header>
|
|
88
|
-
<Drawer.Title>
|
|
88
|
+
<Drawer.Title>
|
|
89
|
+
{strategy.strategyName}, {strategy.deploymentLabel} revisions
|
|
90
|
+
</Drawer.Title>
|
|
89
91
|
<Drawer.CloseTrigger asChild>
|
|
90
92
|
<CloseButton size="sm" />
|
|
91
93
|
</Drawer.CloseTrigger>
|
|
@@ -206,7 +206,9 @@ export const RuntimeStrategyStatsDrawer = ({
|
|
|
206
206
|
bg="gray.950"
|
|
207
207
|
>
|
|
208
208
|
<Drawer.Header>
|
|
209
|
-
<Drawer.Title>
|
|
209
|
+
<Drawer.Title>
|
|
210
|
+
{strategy.strategyName}, {strategy.deploymentLabel}
|
|
211
|
+
</Drawer.Title>
|
|
210
212
|
<Drawer.CloseTrigger asChild>
|
|
211
213
|
<CloseButton size="sm" />
|
|
212
214
|
</Drawer.CloseTrigger>
|
|
@@ -27,6 +27,7 @@ import { EmptyState, Segment, Select, toaster } from '#ui';
|
|
|
27
27
|
|
|
28
28
|
const ALL_STRATEGIES = '__all__';
|
|
29
29
|
const ALL_RUNTIME_SCOPES = '__all_runtime_scopes__';
|
|
30
|
+
const ALL_RUNTIME_DEPLOYMENTS = '__all_runtime_deployments__';
|
|
30
31
|
type StrategyMode = 'runtime' | 'replay' | 'ai' | 'backtest';
|
|
31
32
|
type RuntimeStatusFilter = 'all' | 'enabled' | 'disabled';
|
|
32
33
|
|
|
@@ -75,6 +76,9 @@ const RuntimeStrategiesContent = () => {
|
|
|
75
76
|
const [runtimeStatusFilter, setRuntimeStatusFilter] =
|
|
76
77
|
useState<RuntimeStatusFilter>('all');
|
|
77
78
|
const [runtimeUniverse, setRuntimeUniverse] = useState(ALL_RUNTIME_SCOPES);
|
|
79
|
+
const [runtimeDeployment, setRuntimeDeployment] = useState(
|
|
80
|
+
ALL_RUNTIME_DEPLOYMENTS,
|
|
81
|
+
);
|
|
78
82
|
const [isDeleteSelectedOpen, setIsDeleteSelectedOpen] = useState(false);
|
|
79
83
|
const [isDeletingSelected, setIsDeletingSelected] = useState(false);
|
|
80
84
|
const [pendingSnapshotDelete, setPendingSnapshotDelete] =
|
|
@@ -110,6 +114,7 @@ const RuntimeStrategiesContent = () => {
|
|
|
110
114
|
setMode(modeFromPathname(window.location.pathname));
|
|
111
115
|
setSelectedStrategy(ALL_STRATEGIES);
|
|
112
116
|
setRuntimeStatusFilter('all');
|
|
117
|
+
setRuntimeDeployment(ALL_RUNTIME_DEPLOYMENTS);
|
|
113
118
|
};
|
|
114
119
|
|
|
115
120
|
window.addEventListener('popstate', handlePopState);
|
|
@@ -122,6 +127,7 @@ const RuntimeStrategiesContent = () => {
|
|
|
122
127
|
setMode(nextMode);
|
|
123
128
|
setSelectedStrategy(ALL_STRATEGIES);
|
|
124
129
|
setRuntimeStatusFilter('all');
|
|
130
|
+
setRuntimeDeployment(ALL_RUNTIME_DEPLOYMENTS);
|
|
125
131
|
|
|
126
132
|
window.history.pushState(null, '', `/routes/strategies/${nextMode}`);
|
|
127
133
|
}, []);
|
|
@@ -201,31 +207,44 @@ const RuntimeStrategiesContent = () => {
|
|
|
201
207
|
const filteredRuntimeStrategies = useMemo(() => {
|
|
202
208
|
const strategies = runtimeData?.strategies ?? [];
|
|
203
209
|
|
|
204
|
-
return strategies
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
210
|
+
return strategies
|
|
211
|
+
.filter((strategy) => {
|
|
212
|
+
if (
|
|
213
|
+
selectedStrategy !== ALL_STRATEGIES &&
|
|
214
|
+
strategy.strategyName !== selectedStrategy
|
|
215
|
+
) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
if (
|
|
219
|
+
runtimeUniverse !== ALL_RUNTIME_SCOPES &&
|
|
220
|
+
strategy.universe !== runtimeUniverse
|
|
221
|
+
) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
if (
|
|
225
|
+
runtimeDeployment !== ALL_RUNTIME_DEPLOYMENTS &&
|
|
226
|
+
strategy.deploymentId !== runtimeDeployment
|
|
227
|
+
) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
if (runtimeStatusFilter === 'enabled') {
|
|
231
|
+
return strategy.enabled;
|
|
232
|
+
}
|
|
220
233
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
234
|
+
if (runtimeStatusFilter === 'disabled') {
|
|
235
|
+
return !strategy.enabled;
|
|
236
|
+
}
|
|
224
237
|
|
|
225
|
-
|
|
226
|
-
|
|
238
|
+
return true;
|
|
239
|
+
})
|
|
240
|
+
.sort(
|
|
241
|
+
(left, right) =>
|
|
242
|
+
left.strategyName.localeCompare(right.strategyName) ||
|
|
243
|
+
left.deploymentLabel.localeCompare(right.deploymentLabel),
|
|
244
|
+
);
|
|
227
245
|
}, [
|
|
228
246
|
runtimeData?.strategies,
|
|
247
|
+
runtimeDeployment,
|
|
229
248
|
runtimeStatusFilter,
|
|
230
249
|
runtimeUniverse,
|
|
231
250
|
selectedStrategy,
|
|
@@ -241,6 +260,21 @@ const RuntimeStrategiesContent = () => {
|
|
|
241
260
|
];
|
|
242
261
|
}, [runtimeData?.strategies]);
|
|
243
262
|
|
|
263
|
+
const runtimeDeploymentItems = useMemo(() => {
|
|
264
|
+
const deployments = new Map(
|
|
265
|
+
(runtimeData?.strategies ?? []).map((strategy) => [
|
|
266
|
+
strategy.deploymentId,
|
|
267
|
+
strategy.deploymentLabel,
|
|
268
|
+
]),
|
|
269
|
+
);
|
|
270
|
+
return [
|
|
271
|
+
{ label: 'All deployments', value: ALL_RUNTIME_DEPLOYMENTS },
|
|
272
|
+
...[...deployments]
|
|
273
|
+
.sort(([, left], [, right]) => left.localeCompare(right))
|
|
274
|
+
.map(([value, label]) => ({ label, value })),
|
|
275
|
+
];
|
|
276
|
+
}, [runtimeData?.strategies]);
|
|
277
|
+
|
|
244
278
|
const filteredSnapshotStrategies = useMemo(() => {
|
|
245
279
|
const strategies = snapshotData?.strategies ?? [];
|
|
246
280
|
|
|
@@ -491,6 +525,17 @@ const RuntimeStrategiesContent = () => {
|
|
|
491
525
|
width="180px"
|
|
492
526
|
/>
|
|
493
527
|
) : null}
|
|
528
|
+
{mode === 'runtime' ? (
|
|
529
|
+
<Select
|
|
530
|
+
value={[runtimeDeployment]}
|
|
531
|
+
defaultValue={[runtimeDeployment]}
|
|
532
|
+
onChange={(value) =>
|
|
533
|
+
setRuntimeDeployment(value[0] || ALL_RUNTIME_DEPLOYMENTS)
|
|
534
|
+
}
|
|
535
|
+
items={runtimeDeploymentItems}
|
|
536
|
+
width="180px"
|
|
537
|
+
/>
|
|
538
|
+
) : null}
|
|
494
539
|
{mode === 'runtime' ? (
|
|
495
540
|
<Segment
|
|
496
541
|
defaultValue="all"
|