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() {
return [
{
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,
},
];
export interface GridStrategy {
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',
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 { queryStrategiesMetrics } from '../api/bbgo';
import DashboardLayout from '../layouts/DashboardLayout';
import { useEffect, useState } from 'react';
import { queryStrategiesMetrics } from '../api/bbgo';
import type { GridStrategy } from '../api/bbgo';
const StrategyContainer = styled('section')(() => ({
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-around',
width: '400px',
height: '400px',
border: '1px solid rgb(248, 149, 35)',
borderRadius: '10px',
padding: '10px',
}));
import Detail from '../components/Detail';
const Strategy = styled('div')(() => ({
fontSize: '20px',
}));
const StatusSign = styled('span')(() => ({
width: '10px',
height: '10px',
display: 'block',
backgroundColor: 'rgb(113, 218, 113)',
borderRadius: '50%',
marginRight: '5px',
}));
const RunningTime = styled('div')(() => ({
display: 'flex',
alignItems: 'center',
}));
const Description = styled('div')(() => ({
color: 'rgb(140, 140, 140)',
'& .duration': {
marginLeft: '3px',
const StrategiesContainer = styled('div')(() => ({
width: '100%',
height: '100%',
padding: '40px 20px',
display: 'grid',
gridTemplateColumns: 'repeat(3, 350px);',
justifyContent: 'center',
gap: '30px',
'@media(max-width: 1400px)': {
gridTemplateColumns: 'repeat(2, 350px)',
},
'@media(max-width: 1000px)': {
gridTemplateColumns: '350px',
},
}));
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() {
const [details, setDetails] = useState([]);
const [details, setDetails] = useState<GridStrategy[]>([]);
useEffect(() => {
queryStrategiesMetrics().then((value) => {
@ -81,88 +33,11 @@ export default function Strategies() {
return (
<DashboardLayout>
{details.map((element) => {
return <Detail key={element.id} data={element} />;
})}
<StrategiesContainer>
{details.map((element) => {
return <Detail key={element.id} data={element} />;
})}
</StrategiesContainer>
</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>
);
}