mirror of
https://github.com/c9s/bbgo.git
synced 2024-09-20 08:11:08 +00:00
Merge pull request #732 from c9s/refactor-grid-panel
Refactor grid panel
This commit is contained in:
commit
01202e353b
|
@ -131,9 +131,32 @@ export function queryTradingVolume(params, cb) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function queryStrategiesMetrics() {
|
export interface GridStrategy {
|
||||||
return [
|
id: string;
|
||||||
{
|
instanceID: string;
|
||||||
|
strategy: string;
|
||||||
|
grid: {
|
||||||
|
symbol: string;
|
||||||
|
};
|
||||||
|
stats: GridStats;
|
||||||
|
status: string;
|
||||||
|
startTime: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GridStats {
|
||||||
|
oneDayArbs: number;
|
||||||
|
totalArbs: number;
|
||||||
|
investment: number;
|
||||||
|
totalProfits: number;
|
||||||
|
gridProfits: number;
|
||||||
|
floatingPNL: number;
|
||||||
|
currentPrice: number;
|
||||||
|
lowestPrice: number;
|
||||||
|
highestPrice: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function queryStrategiesMetrics(): Promise<GridStrategy[]> {
|
||||||
|
const temp = {
|
||||||
id: 'uuid',
|
id: 'uuid',
|
||||||
instanceID: 'testInstanceID',
|
instanceID: 'testInstanceID',
|
||||||
strategy: 'grid',
|
strategy: 'grid',
|
||||||
|
@ -153,6 +176,15 @@ export async function queryStrategiesMetrics() {
|
||||||
},
|
},
|
||||||
status: 'RUNNING',
|
status: 'RUNNING',
|
||||||
startTime: 1654938187102,
|
startTime: 1654938187102,
|
||||||
},
|
};
|
||||||
];
|
|
||||||
|
const testArr = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < 11; i++) {
|
||||||
|
const cloned = { ...temp };
|
||||||
|
cloned.id = 'uuid' + i;
|
||||||
|
testArr.push(cloned);
|
||||||
|
}
|
||||||
|
|
||||||
|
return testArr;
|
||||||
}
|
}
|
||||||
|
|
56
frontend/components/Detail.tsx
Normal file
56
frontend/components/Detail.tsx
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import { styled } from '@mui/styles';
|
||||||
|
import type { GridStrategy } from '../api/bbgo';
|
||||||
|
|
||||||
|
import RunningTime from './RunningTime';
|
||||||
|
import Summary from './Summary';
|
||||||
|
import Stats from './Stats';
|
||||||
|
|
||||||
|
const StrategyContainer = styled('section')(() => ({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
width: '350px',
|
||||||
|
border: '1px solid rgb(248, 149, 35)',
|
||||||
|
borderRadius: '10px',
|
||||||
|
padding: '10px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Strategy = styled('div')(() => ({
|
||||||
|
fontSize: '20px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const Description = styled('div')(() => ({
|
||||||
|
color: 'rgb(140, 140, 140)',
|
||||||
|
'& .duration': {
|
||||||
|
marginLeft: '3px',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function Detail({ data }: { data: GridStrategy }) {
|
||||||
|
const { strategy, stats, startTime } = data;
|
||||||
|
const totalProfitsPercentage = (stats.totalProfits / stats.investment) * 100;
|
||||||
|
const gridProfitsPercentage = (stats.gridProfits / stats.investment) * 100;
|
||||||
|
const gridAprPercentage = (stats.gridProfits / 5) * 365;
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const durationMilliseconds = now - startTime;
|
||||||
|
const seconds = durationMilliseconds / 1000;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StrategyContainer>
|
||||||
|
<Strategy>{strategy}</Strategy>
|
||||||
|
<div>{data[strategy].symbol}</div>
|
||||||
|
<RunningTime seconds={seconds} />
|
||||||
|
<Description>
|
||||||
|
0 arbitrages in 24 hours / Total <span>{stats.totalArbs}</span>{' '}
|
||||||
|
arbitrages
|
||||||
|
</Description>
|
||||||
|
<Summary stats={stats} totalProfitsPercentage={totalProfitsPercentage} />
|
||||||
|
<Stats
|
||||||
|
stats={stats}
|
||||||
|
gridProfitsPercentage={gridProfitsPercentage}
|
||||||
|
gridAprPercentage={gridAprPercentage}
|
||||||
|
/>
|
||||||
|
</StrategyContainer>
|
||||||
|
);
|
||||||
|
}
|
34
frontend/components/RunningTime.tsx
Normal file
34
frontend/components/RunningTime.tsx
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { styled } from '@mui/styles';
|
||||||
|
import { Description } from './Detail';
|
||||||
|
|
||||||
|
const RunningTimeSection = styled('div')(() => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StatusSign = styled('span')(() => ({
|
||||||
|
width: '10px',
|
||||||
|
height: '10px',
|
||||||
|
display: 'block',
|
||||||
|
backgroundColor: 'rgb(113, 218, 113)',
|
||||||
|
borderRadius: '50%',
|
||||||
|
marginRight: '5px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function RunningTime({ seconds }: { seconds: number }) {
|
||||||
|
const day = Math.floor(seconds / (60 * 60 * 24));
|
||||||
|
const hour = Math.floor((seconds % (60 * 60 * 24)) / 3600);
|
||||||
|
const min = Math.floor(((seconds % (60 * 60 * 24)) % 3600) / 60);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RunningTimeSection>
|
||||||
|
<StatusSign />
|
||||||
|
<Description>
|
||||||
|
Running for
|
||||||
|
<span className="duration">{day}</span>D
|
||||||
|
<span className="duration">{hour}</span>H
|
||||||
|
<span className="duration">{min}</span>M
|
||||||
|
</Description>
|
||||||
|
</RunningTimeSection>
|
||||||
|
);
|
||||||
|
}
|
51
frontend/components/Stats.tsx
Normal file
51
frontend/components/Stats.tsx
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import { styled } from '@mui/styles';
|
||||||
|
import { StatsTitle, StatsValue, Percentage } from './Summary';
|
||||||
|
import { GridStats } from '../api/bbgo';
|
||||||
|
|
||||||
|
const StatsSection = styled('div')(() => ({
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: '1fr 1fr 1fr',
|
||||||
|
gap: '10px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function Stats({
|
||||||
|
stats,
|
||||||
|
gridProfitsPercentage,
|
||||||
|
gridAprPercentage,
|
||||||
|
}: {
|
||||||
|
stats: GridStats;
|
||||||
|
gridProfitsPercentage: number;
|
||||||
|
gridAprPercentage: number;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<StatsSection>
|
||||||
|
<div>
|
||||||
|
<StatsTitle>Grid Profits</StatsTitle>
|
||||||
|
<StatsValue>{stats.gridProfits}</StatsValue>
|
||||||
|
<Percentage>{gridProfitsPercentage}%</Percentage>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<StatsTitle>Floating PNL</StatsTitle>
|
||||||
|
<StatsValue>{stats.floatingPNL}</StatsValue>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<StatsTitle>Grid APR</StatsTitle>
|
||||||
|
<Percentage>{gridAprPercentage}%</Percentage>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<StatsTitle>Current Price</StatsTitle>
|
||||||
|
<div>{stats.currentPrice}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<StatsTitle>Price Range</StatsTitle>
|
||||||
|
<div>
|
||||||
|
{stats.lowestPrice}~{stats.highestPrice}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</StatsSection>
|
||||||
|
);
|
||||||
|
}
|
50
frontend/components/Summary.tsx
Normal file
50
frontend/components/Summary.tsx
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import { styled } from '@mui/styles';
|
||||||
|
import { GridStats } from '../api/bbgo';
|
||||||
|
|
||||||
|
const SummarySection = styled('div')(() => ({
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
backgroundColor: 'rgb(255, 245, 232)',
|
||||||
|
margin: '10px 0',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const SummaryBlock = styled('div')(() => ({
|
||||||
|
padding: '5px 0 5px 0',
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const StatsTitle = styled('div')(() => ({
|
||||||
|
margin: '0 0 10px 0',
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const StatsValue = styled('div')(() => ({
|
||||||
|
marginBottom: '10px',
|
||||||
|
color: 'rgb(123, 169, 90)',
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const Percentage = styled('div')(() => ({
|
||||||
|
color: 'rgb(123, 169, 90)',
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function Summary({
|
||||||
|
stats,
|
||||||
|
totalProfitsPercentage,
|
||||||
|
}: {
|
||||||
|
stats: GridStats;
|
||||||
|
totalProfitsPercentage: number;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<SummarySection>
|
||||||
|
<SummaryBlock>
|
||||||
|
<StatsTitle>Investment USDT</StatsTitle>
|
||||||
|
<div>{stats.investment}</div>
|
||||||
|
</SummaryBlock>
|
||||||
|
|
||||||
|
<SummaryBlock>
|
||||||
|
<StatsTitle>Total Profit USDT</StatsTitle>
|
||||||
|
<StatsValue>{stats.totalProfits}</StatsValue>
|
||||||
|
<Percentage>{totalProfitsPercentage}%</Percentage>
|
||||||
|
</SummaryBlock>
|
||||||
|
</SummarySection>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,77 +1,29 @@
|
||||||
import DashboardLayout from '../layouts/DashboardLayout';
|
|
||||||
import { styled } from '@mui/styles';
|
import { styled } from '@mui/styles';
|
||||||
import { queryStrategiesMetrics } from '../api/bbgo';
|
import DashboardLayout from '../layouts/DashboardLayout';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { queryStrategiesMetrics } from '../api/bbgo';
|
||||||
|
import type { GridStrategy } from '../api/bbgo';
|
||||||
|
|
||||||
const StrategyContainer = styled('section')(() => ({
|
import Detail from '../components/Detail';
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'space-around',
|
|
||||||
width: '400px',
|
|
||||||
height: '400px',
|
|
||||||
border: '1px solid rgb(248, 149, 35)',
|
|
||||||
borderRadius: '10px',
|
|
||||||
padding: '10px',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const Strategy = styled('div')(() => ({
|
const StrategiesContainer = styled('div')(() => ({
|
||||||
fontSize: '20px',
|
width: '100%',
|
||||||
}));
|
height: '100%',
|
||||||
|
padding: '40px 20px',
|
||||||
const StatusSign = styled('span')(() => ({
|
display: 'grid',
|
||||||
width: '10px',
|
gridTemplateColumns: 'repeat(3, 350px);',
|
||||||
height: '10px',
|
justifyContent: 'center',
|
||||||
display: 'block',
|
gap: '30px',
|
||||||
backgroundColor: 'rgb(113, 218, 113)',
|
'@media(max-width: 1400px)': {
|
||||||
borderRadius: '50%',
|
gridTemplateColumns: 'repeat(2, 350px)',
|
||||||
marginRight: '5px',
|
},
|
||||||
}));
|
'@media(max-width: 1000px)': {
|
||||||
|
gridTemplateColumns: '350px',
|
||||||
const RunningTime = styled('div')(() => ({
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const Description = styled('div')(() => ({
|
|
||||||
color: 'rgb(140, 140, 140)',
|
|
||||||
'& .duration': {
|
|
||||||
marginLeft: '3px',
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const Summary = styled('div')(() => ({
|
|
||||||
width: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-around',
|
|
||||||
backgroundColor: 'rgb(255, 245, 232)',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const SummaryBlock = styled('div')(() => ({
|
|
||||||
padding: '5px 0 5px 0',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StatsTitle = styled('div')(() => ({
|
|
||||||
margin: '0 0 10px 0',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StatsValue = styled('div')(() => ({
|
|
||||||
marginBottom: '10px',
|
|
||||||
color: 'rgb(123, 169, 90)',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const Percentage = styled('div')(() => ({
|
|
||||||
color: 'rgb(123, 169, 90)',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const Stats = styled('div')(() => ({
|
|
||||||
display: 'grid',
|
|
||||||
gridTemplateColumns: '1fr 1fr 1fr',
|
|
||||||
columnGap: '10px',
|
|
||||||
rowGap: '20px',
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default function Strategies() {
|
export default function Strategies() {
|
||||||
const [details, setDetails] = useState([]);
|
const [details, setDetails] = useState<GridStrategy[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
queryStrategiesMetrics().then((value) => {
|
queryStrategiesMetrics().then((value) => {
|
||||||
|
@ -81,88 +33,11 @@ export default function Strategies() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardLayout>
|
<DashboardLayout>
|
||||||
|
<StrategiesContainer>
|
||||||
{details.map((element) => {
|
{details.map((element) => {
|
||||||
return <Detail key={element.id} data={element} />;
|
return <Detail key={element.id} data={element} />;
|
||||||
})}
|
})}
|
||||||
|
</StrategiesContainer>
|
||||||
</DashboardLayout>
|
</DashboardLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Detail({ data }) {
|
|
||||||
const { strategy, stats, startTime } = data;
|
|
||||||
const totalProfitsPercentage = (stats.totalProfits / stats.investment) * 100;
|
|
||||||
const gridProfitsPercentage = (stats.gridProfits / stats.investment) * 100;
|
|
||||||
const gridAprPercentage = (stats.gridProfits / 5) * 365;
|
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
const durationMilliseconds = now - startTime;
|
|
||||||
const seconds = durationMilliseconds / 1000;
|
|
||||||
|
|
||||||
const day = Math.floor(seconds / (60 * 60 * 24));
|
|
||||||
const hour = Math.floor((seconds % (60 * 60 * 24)) / 3600);
|
|
||||||
const min = Math.floor(((seconds % (60 * 60 * 24)) % 3600) / 60);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StrategyContainer>
|
|
||||||
<Strategy>{strategy}</Strategy>
|
|
||||||
<div>{data[strategy].symbol}</div>
|
|
||||||
<RunningTime>
|
|
||||||
<StatusSign />
|
|
||||||
<Description>
|
|
||||||
Running for
|
|
||||||
<span className="duration">{day}</span>D
|
|
||||||
<span className="duration">{hour}</span>H
|
|
||||||
<span className="duration">{min}</span>M
|
|
||||||
</Description>
|
|
||||||
</RunningTime>
|
|
||||||
|
|
||||||
<Description>
|
|
||||||
0 arbitrages in 24 hours / Total <span>{stats.totalArbs}</span>{' '}
|
|
||||||
arbitrages
|
|
||||||
</Description>
|
|
||||||
|
|
||||||
<Summary>
|
|
||||||
<SummaryBlock>
|
|
||||||
<StatsTitle>Investment USDT</StatsTitle>
|
|
||||||
<div>{stats.investment}</div>
|
|
||||||
</SummaryBlock>
|
|
||||||
|
|
||||||
<SummaryBlock>
|
|
||||||
<StatsTitle>Total Profit USDT</StatsTitle>
|
|
||||||
<StatsValue>{stats.totalProfits}</StatsValue>
|
|
||||||
<Percentage>{totalProfitsPercentage}%</Percentage>
|
|
||||||
</SummaryBlock>
|
|
||||||
</Summary>
|
|
||||||
|
|
||||||
<Stats>
|
|
||||||
<div>
|
|
||||||
<StatsTitle>Grid Profits</StatsTitle>
|
|
||||||
<StatsValue>{stats.gridProfits}</StatsValue>
|
|
||||||
<Percentage>{gridProfitsPercentage}%</Percentage>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<StatsTitle>Floating PNL</StatsTitle>
|
|
||||||
<StatsValue>{stats.floatingPNL}</StatsValue>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<StatsTitle>Grid APR</StatsTitle>
|
|
||||||
<Percentage>{gridAprPercentage}%</Percentage>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<StatsTitle>Current Price</StatsTitle>
|
|
||||||
<div>{stats.currentPrice}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<StatsTitle>Price Range</StatsTitle>
|
|
||||||
<div>
|
|
||||||
{stats.lowestPrice}~{stats.highestPrice}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Stats>
|
|
||||||
</StrategyContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user