@tradejs/app 2.0.17 → 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.
- package/package.json +14 -8
- package/src/app/actions/backtest.ts +2 -1
- package/src/app/actions/scanner.ts +2 -1
- package/src/app/api/backtest/files/route.ts +2 -1
- package/src/app/api/backtest/test/[strategy]/[name]/route.ts +1 -1
- package/src/app/api/derivatives/[symbol]/[interval]/route.ts +1 -1
- package/src/app/api/derivatives/summary/route.ts +1 -1
- package/src/app/api/spread/[symbol]/[interval]/route.ts +1 -1
- package/src/app/api/spread/summary/route.ts +1 -1
- package/src/app/api/strategies/runtime/route.ts +4 -674
- package/src/app/api/user/runtime-deployments/[deploymentId]/route.ts +1 -1
- package/src/app/api/user/runtime-deployments/route.ts +2 -2
- package/src/app/api/user/runtime-strategy-configs/route.ts +22 -212
- package/src/app/api/user/trading-accounts/[accountId]/route.ts +1 -1
- package/src/app/components/Backtest/TestList/index.tsx +1 -1
- package/src/app/components/Dashboard/KlineChart/figures/circle.ts +1 -1
- package/src/app/components/Dashboard/KlineChart/figures/diamond.ts +1 -1
- package/src/app/components/Dashboard/KlineChart/figures/label.ts +1 -1
- package/src/app/components/Dashboard/KlineChart/figures/rectangle.ts +1 -1
- package/src/app/components/Dashboard/KlineChart/figures/star.ts +1 -1
- package/src/app/components/Dashboard/KlineChart/index.tsx +2 -1
- package/src/app/components/Shared/Filters/Root/index.tsx +1 -1
- package/src/app/components/Shared/Filters/context.ts +1 -1
- package/src/app/components/Strategies/RuntimeStrategyCard.tsx +81 -858
- package/src/app/components/Strategies/StrategyPerformanceCharts.tsx +419 -0
- package/src/app/components/Strategies/StrategySnapshotCard.tsx +122 -937
- package/src/app/components/UI/Segment/index.tsx +1 -1
- package/src/app/components/UI/Select/index.tsx +1 -1
- package/src/app/components/UI/SelectWithSearch/index.tsx +1 -1
- package/src/app/lib/backtestJobContracts.ts +67 -0
- package/src/app/lib/backtestJobProgress.ts +28 -0
- package/src/app/lib/backtestJobRequest.ts +107 -0
- package/src/app/lib/backtestJobs.ts +25 -257
- package/src/app/lib/runtimeDashboard.ts +684 -0
- package/src/app/lib/runtimeStrategies.ts +24 -454
- package/src/app/lib/runtimeStrategyConfigService.ts +279 -0
- package/src/app/lib/runtimeStrategyLineage.ts +264 -0
- package/src/app/lib/runtimeTradeReconciliation.ts +113 -0
- package/src/app/lib/runtimeTradeSync.ts +1 -1
- package/src/app/lib/strategyPerformance.ts +387 -0
- package/src/app/routes/dashboard/Dashboard.tsx +2 -6
- package/src/app/routes/derivatives/derivativesViewModel.ts +253 -0
- package/src/app/routes/derivatives/page.tsx +70 -262
- package/src/app/store/filters.ts +2 -1
- package/src/app/store/indicators.ts +2 -1
- package/src/app/store/tests.ts +1 -1
- package/src/app/store/tickers.ts +2 -1
- 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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
433
|
+
chartRows,
|
|
591
434
|
window,
|
|
592
435
|
}: {
|
|
593
436
|
symbol: string;
|
|
594
|
-
|
|
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 =
|
|
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
|
-
|
|
525
|
+
chartRows,
|
|
684
526
|
window,
|
|
685
527
|
}: {
|
|
686
528
|
symbol: string;
|
|
687
|
-
|
|
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
|
-
|
|
616
|
+
chartRows,
|
|
776
617
|
window,
|
|
777
618
|
}: {
|
|
778
619
|
symbol: string;
|
|
779
|
-
|
|
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
|
-
|
|
694
|
+
chartRows,
|
|
855
695
|
window,
|
|
856
696
|
}: {
|
|
857
697
|
symbol: string;
|
|
858
|
-
|
|
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] =
|
|
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
|
|
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
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
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
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
{
|
|
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
|
-
|
|
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
|
);
|
package/src/app/store/filters.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
package/src/app/store/tests.ts
CHANGED
package/src/app/store/tickers.ts
CHANGED
|
@@ -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 {
|
|
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;
|