@tradejs/app 3.1.25 → 3.1.26-beta.244
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.
|
|
3
|
+
"version": "3.1.26-beta.244",
|
|
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.26-beta.244",
|
|
60
|
+
"@tradejs/indicators": "^3.1.26-beta.244",
|
|
61
|
+
"@tradejs/infra": "^3.1.26-beta.244",
|
|
62
|
+
"@tradejs/node": "^3.1.26-beta.244",
|
|
63
|
+
"@tradejs/types": "^3.1.26-beta.244",
|
|
64
64
|
"@types/bcryptjs": "2.4.6",
|
|
65
65
|
"@types/lodash": "4.17.24",
|
|
66
66
|
"@types/node": "24.13.3",
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from '#components/Shared/OrdersDrawer';
|
|
21
21
|
import { RuntimeStrategyChart } from './RuntimeStrategyChart';
|
|
22
22
|
import { RuntimeStrategyConfigDrawer } from './RuntimeStrategyConfigDrawer';
|
|
23
|
+
import { RuntimeStrategyRevisionsDrawer } from './RuntimeStrategyRevisionsDrawer';
|
|
23
24
|
import { RuntimeStrategyStatsDrawer } from './RuntimeStrategyStatsDrawer';
|
|
24
25
|
import {
|
|
25
26
|
buildRuntimeStrategyCardViewModel,
|
|
@@ -65,6 +66,7 @@ export const RuntimeStrategyCard = ({
|
|
|
65
66
|
const [configOpen, setConfigOpen] = useState(false);
|
|
66
67
|
const [ordersOpen, setOrdersOpen] = useState(false);
|
|
67
68
|
const [statsOpen, setStatsOpen] = useState(false);
|
|
69
|
+
const [revisionsOpen, setRevisionsOpen] = useState(false);
|
|
68
70
|
const [controlSaving, setControlSaving] = useState(false);
|
|
69
71
|
const viewModel = useMemo(
|
|
70
72
|
() => buildRuntimeStrategyCardViewModel(strategy),
|
|
@@ -209,6 +211,12 @@ export const RuntimeStrategyCard = ({
|
|
|
209
211
|
<Menu.Item value="stat" onClick={() => setStatsOpen(true)}>
|
|
210
212
|
Stat
|
|
211
213
|
</Menu.Item>
|
|
214
|
+
<Menu.Item
|
|
215
|
+
value="revisions"
|
|
216
|
+
onClick={() => setRevisionsOpen(true)}
|
|
217
|
+
>
|
|
218
|
+
Revisions
|
|
219
|
+
</Menu.Item>
|
|
212
220
|
</Menu.Content>
|
|
213
221
|
</Menu.Positioner>
|
|
214
222
|
</Portal>
|
|
@@ -239,6 +247,12 @@ export const RuntimeStrategyCard = ({
|
|
|
239
247
|
viewModel={viewModel}
|
|
240
248
|
/>
|
|
241
249
|
|
|
250
|
+
<RuntimeStrategyRevisionsDrawer
|
|
251
|
+
open={revisionsOpen}
|
|
252
|
+
strategy={strategy}
|
|
253
|
+
onOpenChange={setRevisionsOpen}
|
|
254
|
+
/>
|
|
255
|
+
|
|
242
256
|
<RuntimeStrategyChart
|
|
243
257
|
orderLog={strategy.orderLog}
|
|
244
258
|
revisionChanges={strategy.revisionChanges}
|
|
@@ -109,14 +109,6 @@ export const RuntimeStrategyChart = ({
|
|
|
109
109
|
x={change.timestamp}
|
|
110
110
|
stroke={chart.color('orange.400')}
|
|
111
111
|
strokeDasharray="4 4"
|
|
112
|
-
label={{
|
|
113
|
-
value: `Revision ${change.strategyRevision
|
|
114
|
-
.replace(/^sr1:/, '')
|
|
115
|
-
.slice(0, 8)}`,
|
|
116
|
-
offset: 8,
|
|
117
|
-
fill: chart.color('orange.300'),
|
|
118
|
-
position: 'insideTopRight',
|
|
119
|
-
}}
|
|
120
112
|
/>
|
|
121
113
|
))}
|
|
122
114
|
<TimeSeriesXAxis
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import {
|
|
5
|
+
Badge,
|
|
6
|
+
Box,
|
|
7
|
+
Button,
|
|
8
|
+
CloseButton,
|
|
9
|
+
Drawer,
|
|
10
|
+
Flex,
|
|
11
|
+
Portal,
|
|
12
|
+
Text,
|
|
13
|
+
} from '@chakra-ui/react';
|
|
14
|
+
import type {
|
|
15
|
+
RuntimeStrategyRevisionChange,
|
|
16
|
+
RuntimeStrategyView,
|
|
17
|
+
} from '@tradejs/types';
|
|
18
|
+
import { formatDateTime } from '#components/Shared/OrdersDrawer';
|
|
19
|
+
|
|
20
|
+
interface RuntimeStrategyRevisionItem {
|
|
21
|
+
strategyRevision: string;
|
|
22
|
+
changedAt: number | null;
|
|
23
|
+
current: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const buildRuntimeStrategyRevisionItems = ({
|
|
27
|
+
strategyRevision,
|
|
28
|
+
revisionChanges,
|
|
29
|
+
}: {
|
|
30
|
+
strategyRevision: string;
|
|
31
|
+
revisionChanges: RuntimeStrategyRevisionChange[];
|
|
32
|
+
}): RuntimeStrategyRevisionItem[] => {
|
|
33
|
+
const changedAtByRevision = new Map<string, number>();
|
|
34
|
+
|
|
35
|
+
for (const change of revisionChanges) {
|
|
36
|
+
const previousTimestamp = changedAtByRevision.get(change.strategyRevision);
|
|
37
|
+
if (
|
|
38
|
+
Number.isFinite(change.timestamp) &&
|
|
39
|
+
(previousTimestamp == null || change.timestamp > previousTimestamp)
|
|
40
|
+
) {
|
|
41
|
+
changedAtByRevision.set(change.strategyRevision, change.timestamp);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const revisions = new Set([strategyRevision, ...changedAtByRevision.keys()]);
|
|
46
|
+
|
|
47
|
+
return [...revisions]
|
|
48
|
+
.map((revision) => ({
|
|
49
|
+
strategyRevision: revision,
|
|
50
|
+
changedAt: changedAtByRevision.get(revision) ?? null,
|
|
51
|
+
current: revision === strategyRevision,
|
|
52
|
+
}))
|
|
53
|
+
.sort((left, right) => {
|
|
54
|
+
if (left.current !== right.current) return left.current ? -1 : 1;
|
|
55
|
+
return (right.changedAt ?? 0) - (left.changedAt ?? 0);
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const RuntimeStrategyRevisionsDrawer = ({
|
|
60
|
+
open,
|
|
61
|
+
strategy,
|
|
62
|
+
onOpenChange,
|
|
63
|
+
}: {
|
|
64
|
+
open: boolean;
|
|
65
|
+
strategy: RuntimeStrategyView;
|
|
66
|
+
onOpenChange: (open: boolean) => void;
|
|
67
|
+
}) => {
|
|
68
|
+
const revisions = useMemo(
|
|
69
|
+
() =>
|
|
70
|
+
buildRuntimeStrategyRevisionItems({
|
|
71
|
+
strategyRevision: strategy.strategyRevision,
|
|
72
|
+
revisionChanges: strategy.revisionChanges,
|
|
73
|
+
}),
|
|
74
|
+
[strategy.revisionChanges, strategy.strategyRevision],
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<Drawer.Root
|
|
79
|
+
size="md"
|
|
80
|
+
open={open}
|
|
81
|
+
onOpenChange={(event) => onOpenChange(event.open)}
|
|
82
|
+
>
|
|
83
|
+
<Portal>
|
|
84
|
+
<Drawer.Backdrop />
|
|
85
|
+
<Drawer.Positioner>
|
|
86
|
+
<Drawer.Content bg="gray.950">
|
|
87
|
+
<Drawer.Header>
|
|
88
|
+
<Drawer.Title>{strategy.strategyName} revisions</Drawer.Title>
|
|
89
|
+
<Drawer.CloseTrigger asChild>
|
|
90
|
+
<CloseButton size="sm" />
|
|
91
|
+
</Drawer.CloseTrigger>
|
|
92
|
+
</Drawer.Header>
|
|
93
|
+
<Drawer.Body
|
|
94
|
+
display="flex"
|
|
95
|
+
flexDirection="column"
|
|
96
|
+
gap={3}
|
|
97
|
+
overflowY="auto"
|
|
98
|
+
>
|
|
99
|
+
<Text color="gray.400">
|
|
100
|
+
Current revision and all revision changes recorded in the
|
|
101
|
+
selected runtime window.
|
|
102
|
+
</Text>
|
|
103
|
+
|
|
104
|
+
{revisions.map((revision) => (
|
|
105
|
+
<Box
|
|
106
|
+
key={revision.strategyRevision}
|
|
107
|
+
p={4}
|
|
108
|
+
borderWidth="1px"
|
|
109
|
+
borderColor={revision.current ? 'teal.800' : 'gray.800'}
|
|
110
|
+
borderRadius="md"
|
|
111
|
+
bg="gray.900"
|
|
112
|
+
>
|
|
113
|
+
<Flex
|
|
114
|
+
alignItems="center"
|
|
115
|
+
justifyContent="space-between"
|
|
116
|
+
gap={3}
|
|
117
|
+
>
|
|
118
|
+
<Text fontSize="xs" color="gray.500">
|
|
119
|
+
Strategy revision
|
|
120
|
+
</Text>
|
|
121
|
+
{revision.current ? (
|
|
122
|
+
<Badge colorPalette="teal" variant="subtle">
|
|
123
|
+
Current
|
|
124
|
+
</Badge>
|
|
125
|
+
) : null}
|
|
126
|
+
</Flex>
|
|
127
|
+
<Text
|
|
128
|
+
mt={2}
|
|
129
|
+
fontFamily="mono"
|
|
130
|
+
fontSize="sm"
|
|
131
|
+
color="gray.200"
|
|
132
|
+
overflowWrap="anywhere"
|
|
133
|
+
>
|
|
134
|
+
{revision.strategyRevision}
|
|
135
|
+
</Text>
|
|
136
|
+
<Text mt={2} fontSize="xs" color="gray.500">
|
|
137
|
+
{revision.changedAt == null
|
|
138
|
+
? 'No revision change recorded in this window'
|
|
139
|
+
: `Changed at ${formatDateTime(revision.changedAt)}`}
|
|
140
|
+
</Text>
|
|
141
|
+
</Box>
|
|
142
|
+
))}
|
|
143
|
+
</Drawer.Body>
|
|
144
|
+
<Drawer.Footer>
|
|
145
|
+
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
|
146
|
+
Close
|
|
147
|
+
</Button>
|
|
148
|
+
</Drawer.Footer>
|
|
149
|
+
</Drawer.Content>
|
|
150
|
+
</Drawer.Positioner>
|
|
151
|
+
</Portal>
|
|
152
|
+
</Drawer.Root>
|
|
153
|
+
);
|
|
154
|
+
};
|