@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradejs/app",
3
- "version": "3.1.27-beta.250",
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.27-beta.250",
60
- "@tradejs/indicators": "^3.1.27-beta.250",
61
- "@tradejs/infra": "^3.1.27-beta.250",
62
- "@tradejs/node": "^3.1.27-beta.250",
63
- "@tradejs/types": "^3.1.27-beta.250",
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
- <Text fontSize="lg" fontWeight="bold" color="gray.200">
119
- {strategy.strategyName}
120
- </Text>
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={`${strategy.strategyName} orders`}
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: 'Deployment', value: strategy.deploymentId },
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>{strategy.strategyName} configuration</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>{strategy.strategyName} revisions</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>{strategy.strategyName}</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.filter((strategy) => {
205
- if (
206
- selectedStrategy !== ALL_STRATEGIES &&
207
- strategy.strategyName !== selectedStrategy
208
- ) {
209
- return false;
210
- }
211
- if (
212
- runtimeUniverse !== ALL_RUNTIME_SCOPES &&
213
- strategy.universe !== runtimeUniverse
214
- ) {
215
- return false;
216
- }
217
- if (runtimeStatusFilter === 'enabled') {
218
- return strategy.enabled;
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
- if (runtimeStatusFilter === 'disabled') {
222
- return !strategy.enabled;
223
- }
234
+ if (runtimeStatusFilter === 'disabled') {
235
+ return !strategy.enabled;
236
+ }
224
237
 
225
- return true;
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"