@tradejs/app 2.0.18 → 2.0.19

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 (48) hide show
  1. package/package.json +14 -8
  2. package/src/app/actions/backtest.ts +2 -1
  3. package/src/app/actions/scanner.ts +2 -1
  4. package/src/app/api/backtest/files/route.ts +2 -1
  5. package/src/app/api/backtest/test/[strategy]/[name]/route.ts +1 -1
  6. package/src/app/api/derivatives/[symbol]/[interval]/route.ts +1 -1
  7. package/src/app/api/derivatives/summary/route.ts +1 -1
  8. package/src/app/api/spread/[symbol]/[interval]/route.ts +1 -1
  9. package/src/app/api/spread/summary/route.ts +1 -1
  10. package/src/app/api/strategies/runtime/route.ts +4 -674
  11. package/src/app/api/user/runtime-deployments/[deploymentId]/route.ts +1 -1
  12. package/src/app/api/user/runtime-deployments/route.ts +2 -2
  13. package/src/app/api/user/runtime-strategy-configs/route.ts +22 -212
  14. package/src/app/api/user/trading-accounts/[accountId]/route.ts +1 -1
  15. package/src/app/components/Backtest/TestList/index.tsx +1 -1
  16. package/src/app/components/Dashboard/KlineChart/figures/circle.ts +1 -1
  17. package/src/app/components/Dashboard/KlineChart/figures/diamond.ts +1 -1
  18. package/src/app/components/Dashboard/KlineChart/figures/label.ts +1 -1
  19. package/src/app/components/Dashboard/KlineChart/figures/rectangle.ts +1 -1
  20. package/src/app/components/Dashboard/KlineChart/figures/star.ts +1 -1
  21. package/src/app/components/Dashboard/KlineChart/index.tsx +2 -1
  22. package/src/app/components/Shared/Filters/Root/index.tsx +1 -1
  23. package/src/app/components/Shared/Filters/context.ts +1 -1
  24. package/src/app/components/Strategies/RuntimeStrategyCard.tsx +81 -858
  25. package/src/app/components/Strategies/StrategyPerformanceCharts.tsx +419 -0
  26. package/src/app/components/Strategies/StrategySnapshotCard.tsx +122 -937
  27. package/src/app/components/UI/Segment/index.tsx +1 -1
  28. package/src/app/components/UI/Select/index.tsx +1 -1
  29. package/src/app/components/UI/SelectWithSearch/index.tsx +1 -1
  30. package/src/app/lib/backtestJobContracts.ts +67 -0
  31. package/src/app/lib/backtestJobProgress.ts +28 -0
  32. package/src/app/lib/backtestJobRequest.ts +107 -0
  33. package/src/app/lib/backtestJobs.ts +25 -257
  34. package/src/app/lib/runtimeDashboard.ts +684 -0
  35. package/src/app/lib/runtimeStrategies.ts +24 -454
  36. package/src/app/lib/runtimeStrategyConfigService.ts +279 -0
  37. package/src/app/lib/runtimeStrategyLineage.ts +264 -0
  38. package/src/app/lib/runtimeTradeReconciliation.ts +113 -0
  39. package/src/app/lib/runtimeTradeSync.ts +1 -1
  40. package/src/app/lib/strategyPerformance.ts +387 -0
  41. package/src/app/routes/dashboard/Dashboard.tsx +2 -6
  42. package/src/app/routes/derivatives/derivativesViewModel.ts +253 -0
  43. package/src/app/routes/derivatives/page.tsx +70 -262
  44. package/src/app/store/filters.ts +2 -1
  45. package/src/app/store/indicators.ts +2 -1
  46. package/src/app/store/tests.ts +1 -1
  47. package/src/app/store/tickers.ts +2 -1
  48. package/src/app/types/ui.ts +20 -0
@@ -42,76 +42,25 @@ import { buildKlinePath } from '#app/lib/marketRoutes';
42
42
  import { formatTimeSeriesTooltipTimestamp } from '#app/lib/timeSeriesChart';
43
43
  import { TimeSeriesXAxis } from '#shared/Charts/TimeSeriesXAxis';
44
44
  import { EmptyState, Segment, Select, toaster } from '#ui';
45
-
46
- type SummaryItem = {
47
- symbol: string;
48
- interval: '15m' | '1h';
49
- points: number;
50
- last_ts: string;
51
- first_ts: string;
52
- latest_open_interest: number | null;
53
- first_open_interest: number | null;
54
- oi_change: number | null;
55
- oi_change_pct: number | null;
56
- latest_funding_rate: number | null;
57
- first_funding_rate: number | null;
58
- funding_change: number | null;
59
- sum_liq_long: number | null;
60
- sum_liq_short: number | null;
61
- sum_liq_total: number | null;
62
- };
63
-
64
- type SummaryResponse = {
65
- hours: number;
66
- items: SummaryItem[];
67
- };
68
-
69
- type DetailRow = {
70
- symbol: string;
71
- interval: '15m' | '1h';
72
- ts: string;
73
- open_interest: number | null;
74
- funding_rate: number | null;
75
- liq_long: number | null;
76
- liq_short: number | null;
77
- liq_total: number | null;
78
- };
79
-
80
- type DetailResponse = {
81
- rows: DetailRow[];
82
- symbol: string;
83
- interval: '15m' | '1h';
84
- };
85
-
86
- type PriceRow = {
87
- close: number;
88
- timestamp: number;
89
- };
90
-
91
- type PriceResponse = {
92
- data?: PriceRow[];
93
- };
45
+ import {
46
+ buildDerivativesDashboardViewModel,
47
+ toFiniteNumber,
48
+ type DerivativesChartRow,
49
+ type DerivativesInterval,
50
+ type DetailResponse,
51
+ type DetailRow,
52
+ type PriceChartRow,
53
+ type PriceResponse,
54
+ type PriceRow,
55
+ type SummaryResponse,
56
+ type SymbolMetrics,
57
+ } from './derivativesViewModel';
94
58
 
95
59
  type ChartWindow = {
96
60
  startTimestamp: number;
97
61
  endTimestamp: number;
98
62
  };
99
63
 
100
- type BiasTone = 'teal' | 'green' | 'red' | 'orange' | 'gray';
101
-
102
- type SymbolMetrics = {
103
- symbol: string;
104
- lastTs: string | null;
105
- currentOpenInterest: number | null;
106
- oiChange: number | null;
107
- oiChangePct: number | null;
108
- currentFundingRate: number | null;
109
- fundingChange: number | null;
110
- sumLiqLong: number | null;
111
- sumLiqShort: number | null;
112
- sumLiqTotal: number | null;
113
- };
114
-
115
64
  type SymbolChartTheme = {
116
65
  primary: string;
117
66
  primaryNegative: string;
@@ -159,9 +108,6 @@ const compactSignedFormatter = new Intl.NumberFormat('en-US', {
159
108
  signDisplay: 'always',
160
109
  });
161
110
 
162
- const toFiniteNumber = (value: number | null | undefined) =>
163
- typeof value === 'number' && Number.isFinite(value) ? value : null;
164
-
165
111
  const formatCompact = (value: number | null | undefined) => {
166
112
  const parsed = toFiniteNumber(value);
167
113
  if (parsed == null) return 'n/a';
@@ -252,94 +198,6 @@ const getFundingColor = (value: number | null | undefined) => {
252
198
  const getSymbolLabel = (symbol: string) =>
253
199
  symbol === 'BTCUSDT' ? 'BTC' : symbol === 'ETHUSDT' ? 'ETH' : symbol;
254
200
 
255
- const getBias = (item: {
256
- latest_funding_rate: number | null;
257
- oi_change_pct: number | null;
258
- sum_liq_long: number | null;
259
- sum_liq_short: number | null;
260
- }) => {
261
- const funding = toFiniteNumber(item.latest_funding_rate) ?? 0;
262
- const oiChangePct = toFiniteNumber(item.oi_change_pct) ?? 0;
263
- const longLiq = toFiniteNumber(item.sum_liq_long) ?? 0;
264
- const shortLiq = toFiniteNumber(item.sum_liq_short) ?? 0;
265
-
266
- if (shortLiq > longLiq * 1.35) {
267
- return { label: 'Short squeeze', tone: 'green' as BiasTone };
268
- }
269
-
270
- if (longLiq > shortLiq * 1.35) {
271
- return { label: 'Long flush', tone: 'red' as BiasTone };
272
- }
273
-
274
- if (oiChangePct > 1 && funding > 0) {
275
- return { label: 'Crowded longs', tone: 'orange' as BiasTone };
276
- }
277
-
278
- if (oiChangePct > 1 && funding < 0) {
279
- return { label: 'Crowded shorts', tone: 'teal' as BiasTone };
280
- }
281
-
282
- return { label: 'Balanced', tone: 'gray' as BiasTone };
283
- };
284
-
285
- const buildMetricsFromRows = (
286
- symbol: string,
287
- rows: DetailRow[],
288
- summaryRow?: SummaryItem,
289
- ): SymbolMetrics => {
290
- if (!rows.length) {
291
- return {
292
- symbol,
293
- lastTs: summaryRow?.last_ts ?? null,
294
- currentOpenInterest: summaryRow?.latest_open_interest ?? null,
295
- oiChange: summaryRow?.oi_change ?? null,
296
- oiChangePct: summaryRow?.oi_change_pct ?? null,
297
- currentFundingRate: summaryRow?.latest_funding_rate ?? null,
298
- fundingChange: summaryRow?.funding_change ?? null,
299
- sumLiqLong: summaryRow?.sum_liq_long ?? null,
300
- sumLiqShort: summaryRow?.sum_liq_short ?? null,
301
- sumLiqTotal: summaryRow?.sum_liq_total ?? null,
302
- };
303
- }
304
-
305
- const first = rows[0];
306
- const last = rows[rows.length - 1];
307
- const firstOi = toFiniteNumber(first.open_interest);
308
- const lastOi = toFiniteNumber(last.open_interest);
309
- const oiChange = firstOi != null && lastOi != null ? lastOi - firstOi : null;
310
- const oiChangePct =
311
- oiChange != null && firstOi != null && Math.abs(firstOi) > 0
312
- ? (oiChange / Math.abs(firstOi)) * 100
313
- : null;
314
- const firstFunding = toFiniteNumber(first.funding_rate);
315
- const lastFunding = toFiniteNumber(last.funding_rate);
316
- const fundingChange =
317
- firstFunding != null && lastFunding != null
318
- ? lastFunding - firstFunding
319
- : null;
320
-
321
- return rows.reduce<SymbolMetrics>(
322
- (acc, row) => {
323
- acc.sumLiqLong = (acc.sumLiqLong ?? 0) + Number(row.liq_long || 0);
324
- acc.sumLiqShort = (acc.sumLiqShort ?? 0) + Number(row.liq_short || 0);
325
- acc.sumLiqTotal = (acc.sumLiqTotal ?? 0) + Number(row.liq_total || 0);
326
- return acc;
327
- },
328
- {
329
- symbol,
330
- lastTs: last.ts,
331
- currentOpenInterest: lastOi,
332
- oiChange,
333
- oiChangePct,
334
- currentFundingRate: lastFunding,
335
- fundingChange,
336
- sumLiqLong: 0,
337
- sumLiqShort: 0,
338
- sumLiqTotal: 0,
339
- },
340
- );
341
- };
342
-
343
201
  const DashboardSkeleton = () => (
344
202
  <>
345
203
  <SimpleGrid columns={{ base: 1, lg: 2 }} gap={4} mb={6}>
@@ -570,33 +428,17 @@ const ChartCard = ({
570
428
  </Card.Root>
571
429
  );
572
430
 
573
- const mapRowsToChartRows = (rows: DetailRow[]) =>
574
- rows.map((row) => ({
575
- timestamp: new Date(row.ts).getTime(),
576
- openInterest: toFiniteNumber(row.open_interest) ?? 0,
577
- funding: (toFiniteNumber(row.funding_rate) ?? 0) * 10_000,
578
- longLiquidations: -(toFiniteNumber(row.liq_long) ?? 0),
579
- shortLiquidations: toFiniteNumber(row.liq_short) ?? 0,
580
- }));
581
-
582
- const mapPriceRowsToChartRows = (rows: PriceRow[]) =>
583
- rows.map((row) => ({
584
- price: toFiniteNumber(row.close) ?? 0,
585
- timestamp: row.timestamp,
586
- }));
587
-
588
431
  const SymbolPriceCard = ({
589
432
  symbol,
590
- rows,
433
+ chartRows,
591
434
  window,
592
435
  }: {
593
436
  symbol: string;
594
- rows: PriceRow[];
437
+ chartRows: PriceChartRow[];
595
438
  window: ChartWindow;
596
439
  }) => {
597
440
  const theme = SYMBOL_THEMES[symbol];
598
441
  const symbolLabel = getSymbolLabel(symbol);
599
- const chartRows = useMemo(() => mapPriceRowsToChartRows(rows), [rows]);
600
442
 
601
443
  const priceChartConfig = useMemo(
602
444
  () => ({
@@ -607,7 +449,7 @@ const SymbolPriceCard = ({
607
449
  );
608
450
 
609
451
  const priceChart = useChart(priceChartConfig as never);
610
- const latestPrice = rows[rows.length - 1]?.close ?? null;
452
+ const latestPrice = chartRows[chartRows.length - 1]?.price ?? null;
611
453
  const priceDomain = useMemo(
612
454
  () => getChartDomain(chartRows.map((row) => row.price)),
613
455
  [chartRows],
@@ -680,16 +522,15 @@ const SymbolPriceCard = ({
680
522
 
681
523
  const SymbolOpenInterestCard = ({
682
524
  symbol,
683
- rows,
525
+ chartRows,
684
526
  window,
685
527
  }: {
686
528
  symbol: string;
687
- rows: DetailRow[];
529
+ chartRows: DerivativesChartRow[];
688
530
  window: ChartWindow;
689
531
  }) => {
690
532
  const theme = SYMBOL_THEMES[symbol];
691
533
  const symbolLabel = getSymbolLabel(symbol);
692
- const chartRows = useMemo(() => mapRowsToChartRows(rows), [rows]);
693
534
 
694
535
  const oiChartConfig = useMemo(
695
536
  () => ({
@@ -772,16 +613,15 @@ const SymbolOpenInterestCard = ({
772
613
 
773
614
  const SymbolFundingCard = ({
774
615
  symbol,
775
- rows,
616
+ chartRows,
776
617
  window,
777
618
  }: {
778
619
  symbol: string;
779
- rows: DetailRow[];
620
+ chartRows: DerivativesChartRow[];
780
621
  window: ChartWindow;
781
622
  }) => {
782
623
  const theme = SYMBOL_THEMES[symbol];
783
624
  const symbolLabel = getSymbolLabel(symbol);
784
- const chartRows = useMemo(() => mapRowsToChartRows(rows), [rows]);
785
625
 
786
626
  const fundingChartConfig = useMemo(
787
627
  () => ({
@@ -851,16 +691,15 @@ const SymbolFundingCard = ({
851
691
 
852
692
  const SymbolLiquidationCard = ({
853
693
  symbol,
854
- rows,
694
+ chartRows,
855
695
  window,
856
696
  }: {
857
697
  symbol: string;
858
- rows: DetailRow[];
698
+ chartRows: DerivativesChartRow[];
859
699
  window: ChartWindow;
860
700
  }) => {
861
701
  const theme = SYMBOL_THEMES[symbol];
862
702
  const symbolLabel = getSymbolLabel(symbol);
863
- const chartRows = useMemo(() => mapRowsToChartRows(rows), [rows]);
864
703
 
865
704
  const liquidationChartConfig = useMemo(
866
705
  () => ({
@@ -931,7 +770,8 @@ const SymbolLiquidationCard = ({
931
770
 
932
771
  const DerivativesPage = () => {
933
772
  const [hours, setHours] = useState('24');
934
- const [selectedInterval, setSelectedInterval] = useState<'15m' | '1h'>('1h');
773
+ const [selectedInterval, setSelectedInterval] =
774
+ useState<DerivativesInterval>('1h');
935
775
  const [summary, setSummary] = useState<SummaryResponse | null>(null);
936
776
  const [detailsBySymbol, setDetailsBySymbol] = useState<
937
777
  Record<string, DetailRow[]>
@@ -1045,48 +885,38 @@ const DerivativesPage = () => {
1045
885
  void loadDetails();
1046
886
  }, [loadDetails]);
1047
887
 
1048
- const filteredSummary = useMemo(
1049
- () =>
1050
- (summary?.items ?? []).filter(
1051
- (item) =>
1052
- item.interval === selectedInterval &&
1053
- FIXED_SYMBOLS.includes(item.symbol as (typeof FIXED_SYMBOLS)[number]),
1054
- ),
1055
- [selectedInterval, summary?.items],
1056
- );
1057
-
1058
- const summaryBySymbol = useMemo(
888
+ const dashboard = useMemo(
1059
889
  () =>
1060
- Object.fromEntries(
1061
- filteredSummary.map((item) => [item.symbol, item]),
1062
- ) as Record<string, SummaryItem | undefined>,
1063
- [filteredSummary],
890
+ buildDerivativesDashboardViewModel({
891
+ symbols: FIXED_SYMBOLS,
892
+ selectedInterval,
893
+ summary,
894
+ detailsBySymbol,
895
+ pricesBySymbol,
896
+ summaryLoading,
897
+ detailLoading,
898
+ summaryError,
899
+ detailError,
900
+ }),
901
+ [
902
+ detailError,
903
+ detailLoading,
904
+ detailsBySymbol,
905
+ pricesBySymbol,
906
+ selectedInterval,
907
+ summary,
908
+ summaryError,
909
+ summaryLoading,
910
+ ],
1064
911
  );
1065
-
1066
- const metricsBySymbol = useMemo(
1067
- () =>
1068
- Object.fromEntries(
1069
- FIXED_SYMBOLS.map((symbol) => [
1070
- symbol,
1071
- buildMetricsFromRows(
1072
- symbol,
1073
- detailsBySymbol[symbol] ?? [],
1074
- summaryBySymbol[symbol],
1075
- ),
1076
- ]),
1077
- ) as Record<string, SymbolMetrics>,
1078
- [detailsBySymbol, summaryBySymbol],
1079
- );
1080
-
1081
- const noSummaryData =
1082
- !summaryLoading && !summaryError && filteredSummary.length === 0;
1083
- const noDetailData =
1084
- !detailLoading &&
1085
- !detailError &&
1086
- FIXED_SYMBOLS.every(
1087
- (symbol) => (detailsBySymbol[symbol] ?? []).length === 0,
1088
- );
1089
- const showSkeleton = (summaryLoading || detailLoading) && !summary;
912
+ const {
913
+ chartDataBySymbol,
914
+ metricsBySymbol,
915
+ noDetailData,
916
+ noSummaryData,
917
+ overviewRows,
918
+ showSkeleton,
919
+ } = dashboard;
1090
920
 
1091
921
  return (
1092
922
  <ClientOnly>
@@ -1117,7 +947,9 @@ const DerivativesPage = () => {
1117
947
  defaultValue={selectedInterval}
1118
948
  value={selectedInterval}
1119
949
  onChange={(value) =>
1120
- setSelectedInterval((value as '15m' | '1h' | null) ?? '1h')
950
+ setSelectedInterval(
951
+ (value as DerivativesInterval | null) ?? '1h',
952
+ )
1121
953
  }
1122
954
  items={INTERVAL_OPTIONS.map((value) => ({
1123
955
  label: value,
@@ -1164,7 +996,7 @@ const DerivativesPage = () => {
1164
996
  <SymbolPriceCard
1165
997
  key={`${symbol}:price`}
1166
998
  symbol={symbol}
1167
- rows={pricesBySymbol[symbol] ?? []}
999
+ chartRows={chartDataBySymbol[symbol].prices}
1168
1000
  window={chartWindow}
1169
1001
  />
1170
1002
  ))}
@@ -1175,7 +1007,7 @@ const DerivativesPage = () => {
1175
1007
  <SymbolOpenInterestCard
1176
1008
  key={`${symbol}:oi`}
1177
1009
  symbol={symbol}
1178
- rows={detailsBySymbol[symbol] ?? []}
1010
+ chartRows={chartDataBySymbol[symbol].derivatives}
1179
1011
  window={chartWindow}
1180
1012
  />
1181
1013
  ))}
@@ -1186,7 +1018,7 @@ const DerivativesPage = () => {
1186
1018
  <SymbolFundingCard
1187
1019
  key={`${symbol}:funding`}
1188
1020
  symbol={symbol}
1189
- rows={detailsBySymbol[symbol] ?? []}
1021
+ chartRows={chartDataBySymbol[symbol].derivatives}
1190
1022
  window={chartWindow}
1191
1023
  />
1192
1024
  ))}
@@ -1197,7 +1029,7 @@ const DerivativesPage = () => {
1197
1029
  <SymbolLiquidationCard
1198
1030
  key={`${symbol}:liq`}
1199
1031
  symbol={symbol}
1200
- rows={detailsBySymbol[symbol] ?? []}
1032
+ chartRows={chartDataBySymbol[symbol].derivatives}
1201
1033
  window={chartWindow}
1202
1034
  />
1203
1035
  ))}
@@ -1243,16 +1075,7 @@ const DerivativesPage = () => {
1243
1075
  </Table.Row>
1244
1076
  </Table.Header>
1245
1077
  <Table.Body>
1246
- {FIXED_SYMBOLS.map((symbol) => {
1247
- const row = summaryBySymbol[symbol];
1248
- const bias = getBias({
1249
- latest_funding_rate:
1250
- metricsBySymbol[symbol].currentFundingRate,
1251
- oi_change_pct: metricsBySymbol[symbol].oiChangePct,
1252
- sum_liq_long: metricsBySymbol[symbol].sumLiqLong,
1253
- sum_liq_short: metricsBySymbol[symbol].sumLiqShort,
1254
- });
1255
-
1078
+ {overviewRows.map(({ symbol, metrics, bias }) => {
1256
1079
  return (
1257
1080
  <Table.Row key={symbol}>
1258
1081
  <Table.Cell>
@@ -1261,41 +1084,29 @@ const DerivativesPage = () => {
1261
1084
  </Text>
1262
1085
  </Table.Cell>
1263
1086
  <Table.Cell textAlign="right">
1264
- {formatCompact(
1265
- metricsBySymbol[symbol].currentOpenInterest,
1266
- )}
1087
+ {formatCompact(metrics.currentOpenInterest)}
1267
1088
  </Table.Cell>
1268
1089
  <Table.Cell textAlign="right">
1269
1090
  <Text
1270
- color={getValueColor(
1271
- metricsBySymbol[symbol].oiChangePct,
1272
- )}
1091
+ color={getValueColor(metrics.oiChangePct)}
1273
1092
  >
1274
- {formatPercent(
1275
- metricsBySymbol[symbol].oiChangePct,
1276
- )}
1093
+ {formatPercent(metrics.oiChangePct)}
1277
1094
  </Text>
1278
1095
  </Table.Cell>
1279
1096
  <Table.Cell textAlign="right">
1280
1097
  <Text
1281
1098
  color={getFundingColor(
1282
- metricsBySymbol[symbol].currentFundingRate,
1099
+ metrics.currentFundingRate,
1283
1100
  )}
1284
1101
  >
1285
- {formatFunding(
1286
- metricsBySymbol[symbol].currentFundingRate,
1287
- )}
1102
+ {formatFunding(metrics.currentFundingRate)}
1288
1103
  </Text>
1289
1104
  </Table.Cell>
1290
1105
  <Table.Cell textAlign="right">
1291
- {formatCompact(
1292
- metricsBySymbol[symbol].sumLiqLong,
1293
- )}
1106
+ {formatCompact(metrics.sumLiqLong)}
1294
1107
  </Table.Cell>
1295
1108
  <Table.Cell textAlign="right">
1296
- {formatCompact(
1297
- metricsBySymbol[symbol].sumLiqShort,
1298
- )}
1109
+ {formatCompact(metrics.sumLiqShort)}
1299
1110
  </Table.Cell>
1300
1111
  <Table.Cell>
1301
1112
  <Badge colorPalette={bias.tone}>
@@ -1303,10 +1114,7 @@ const DerivativesPage = () => {
1303
1114
  </Badge>
1304
1115
  </Table.Cell>
1305
1116
  <Table.Cell>
1306
- {formatFullTime(
1307
- metricsBySymbol[symbol].lastTs ??
1308
- row?.last_ts,
1309
- )}
1117
+ {formatFullTime(metrics.lastTs)}
1310
1118
  </Table.Cell>
1311
1119
  </Table.Row>
1312
1120
  );
@@ -1,7 +1,8 @@
1
1
  import { create } from 'zustand';
2
2
  import { DASHBOARD_PRELOAD_DAYS } from '@tradejs/core/constants';
3
3
  import { getTimestamp } from '@tradejs/core/time';
4
- import { Interval, UIFilters } from '@tradejs/types';
4
+ import { Interval } from '@tradejs/types';
5
+ import type { UIFilters } from '#app/types/ui';
5
6
 
6
7
  interface FiltersState {
7
8
  filters: UIFilters;
@@ -2,7 +2,8 @@ import { useEffect, useMemo, useRef } from 'react';
2
2
  import _ from 'lodash';
3
3
  import { create } from 'zustand';
4
4
  import { persist } from 'zustand/middleware';
5
- import { Indicators, Items } from '@tradejs/types';
5
+ import { Indicators } from '@tradejs/types';
6
+ import type { Items } from '#app/types/ui';
6
7
 
7
8
  const LOCAL_STORAGE_KEY = 'indicators';
8
9
 
@@ -9,8 +9,8 @@ import {
9
9
  TestCompareList,
10
10
  OrderLogData,
11
11
  OnChangeCompare,
12
- Items,
13
12
  } from '@tradejs/types';
13
+ import type { Items } from '#app/types/ui';
14
14
  import { delay } from '@tradejs/core/async';
15
15
  import { parseTestName } from '@tradejs/core/backtest';
16
16
 
@@ -4,7 +4,8 @@ import { persist } from 'zustand/middleware';
4
4
  import { get, set } from 'idb-keyval';
5
5
  import _ from 'lodash';
6
6
  import { scan } from '#actions/scanner';
7
- import { Items, MarketUniverse } from '@tradejs/types';
7
+ import { MarketUniverse } from '@tradejs/types';
8
+ import type { Items } from '#app/types/ui';
8
9
 
9
10
  const LOCAL_STORAGE_KEY = 'tickers';
10
11
  const TICKERS_CACHE_TTL_MS = 10 * 60 * 1000;
@@ -0,0 +1,20 @@
1
+ import type { Filters, Item, Items } from '@tradejs/types';
2
+
3
+ export type { Item, Items };
4
+
5
+ export interface Figure {
6
+ ctx: CanvasRenderingContext2D;
7
+ x: number;
8
+ y: number;
9
+ color: string;
10
+ width: number;
11
+ height: number;
12
+ text?: string;
13
+ }
14
+
15
+ export interface UIFilters extends Filters {
16
+ backtestId: string | null;
17
+ backtestStrategy: string | null;
18
+ }
19
+
20
+ export type OnChangeFilters = (filters: Partial<UIFilters>) => void;