Merge pull request #732 from c9s/refactor-grid-panel

Refactor grid panel
This commit is contained in:
Yo-An Lin 2022-06-17 18:54:16 +08:00 committed by GitHub
commit 01202e353b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 270 additions and 172 deletions

View File

@ -131,28 +131,60 @@ export function queryTradingVolume(params, cb) {
}); });
} }
export async function queryStrategiesMetrics() { export interface GridStrategy {
return [ id: string;
{ instanceID: string;
id: 'uuid', strategy: string;
instanceID: 'testInstanceID', grid: {
strategy: 'grid', symbol: string;
grid: { };
symbol: 'BTCUSDT', stats: GridStats;
}, status: string;
stats: { startTime: number;
oneDayArbs: 0, }
totalArbs: 3,
investment: 100, export interface GridStats {
totalProfits: 5.6, oneDayArbs: number;
gridProfits: 2.5, totalArbs: number;
floatingPNL: 3.1, investment: number;
currentPrice: 29000, totalProfits: number;
lowestPrice: 25000, gridProfits: number;
highestPrice: 35000, floatingPNL: number;
}, currentPrice: number;
status: 'RUNNING', lowestPrice: number;
startTime: 1654938187102, highestPrice: number;
}, }
];
export async function queryStrategiesMetrics(): Promise<GridStrategy[]> {
const temp = {
id: 'uuid',
instanceID: 'testInstanceID',
strategy: 'grid',
grid: {
symbol: 'BTCUSDT',
},
stats: {
oneDayArbs: 0,
totalArbs: 3,
investment: 100,
totalProfits: 5.6,
gridProfits: 2.5,
floatingPNL: 3.1,
currentPrice: 29000,
lowestPrice: 25000,
highestPrice: 35000,
},
status: 'RUNNING',
startTime: 1654938187102,
};
const testArr = [];
for (let i = 0; i < 11; i++) {
const cloned = { ...temp };
cloned.id = 'uuid' + i;
testArr.push(cloned);
}
return testArr;
} }

View 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>
);
}

View 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>
);
}

View 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>
);
}

View 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>
);
}

View File

@ -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>
{details.map((element) => { <StrategiesContainer>
return <Detail key={element.id} data={element} />; {details.map((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>
);
}