mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
commit
aec1973953
|
@ -17,17 +17,17 @@ export function queryOutboundIP(cb) {
|
|||
|
||||
export async function triggerSync() {
|
||||
return axios.post<any>(baseURL + '/api/environment/sync');
|
||||
};
|
||||
}
|
||||
|
||||
export enum SyncStatus {
|
||||
SyncNotStarted = 0,
|
||||
Syncing = 1,
|
||||
SyncDone = 2
|
||||
SyncDone = 2,
|
||||
}
|
||||
|
||||
export async function querySyncStatus(): Promise<SyncStatus> {
|
||||
const resp = await axios.get<any>(baseURL + '/api/environment/syncing')
|
||||
return resp.data.syncing
|
||||
const resp = await axios.get<any>(baseURL + '/api/environment/syncing');
|
||||
return resp.data.syncing;
|
||||
}
|
||||
|
||||
export function testDatabaseConnection(params, cb) {
|
||||
|
@ -130,3 +130,29 @@ export function queryTradingVolume(params, cb) {
|
|||
cb(response.data.tradingVolumes || []);
|
||||
});
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -89,12 +89,14 @@ export default function SideBar() {
|
|||
<ListItemText primary="Trades" />
|
||||
</ListItem>
|
||||
</Link>
|
||||
<ListItem button>
|
||||
<ListItemIcon>
|
||||
<TrendingUpIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Strategies" />
|
||||
</ListItem>
|
||||
<Link href={'/strategies'}>
|
||||
<ListItem button>
|
||||
<ListItemIcon>
|
||||
<TrendingUpIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Strategies" />
|
||||
</ListItem>
|
||||
</Link>
|
||||
</List>
|
||||
</Drawer>
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {styled} from "@mui/styles";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {querySyncStatus, SyncStatus, triggerSync} from "../api/bbgo";
|
||||
import useInterval from "../hooks/useInterval";
|
||||
import { styled } from '@mui/styles';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { querySyncStatus, SyncStatus, triggerSync } from '../api/bbgo';
|
||||
import useInterval from '../hooks/useInterval';
|
||||
|
||||
const ToolbarButton = styled('button')(({ theme }) => ({
|
||||
padding: theme.spacing(1),
|
||||
|
@ -9,7 +9,7 @@ const ToolbarButton = styled('button')(({ theme }) => ({
|
|||
|
||||
export default function SyncButton() {
|
||||
const [syncing, setSyncing] = useState(false);
|
||||
|
||||
|
||||
const sync = async () => {
|
||||
try {
|
||||
setSyncing(true);
|
||||
|
@ -18,26 +18,22 @@ export default function SyncButton() {
|
|||
setSyncing(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
sync();
|
||||
}, [])
|
||||
|
||||
}, []);
|
||||
|
||||
useInterval(() => {
|
||||
querySyncStatus().then(s => {
|
||||
querySyncStatus().then((s) => {
|
||||
if (s !== SyncStatus.Syncing) {
|
||||
setSyncing(false);
|
||||
}
|
||||
})
|
||||
}, 2000)
|
||||
|
||||
});
|
||||
}, 2000);
|
||||
|
||||
return (
|
||||
<ToolbarButton
|
||||
disabled={syncing}
|
||||
onClick={sync}
|
||||
>
|
||||
<ToolbarButton disabled={syncing} onClick={sync}>
|
||||
{syncing ? 'Syncing...' : 'Sync'}
|
||||
</ToolbarButton>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import {useEffect, useRef} from "react";
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export default function useInterval(cb: Function, delayMs: number | null) {
|
||||
const savedCallback = useRef<Function>();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
savedCallback.current = cb
|
||||
}, [cb])
|
||||
|
||||
savedCallback.current = cb;
|
||||
}, [cb]);
|
||||
|
||||
useEffect(() => {
|
||||
function tick() {
|
||||
savedCallback.current();
|
||||
}
|
||||
|
||||
|
||||
if (delayMs !== null) {
|
||||
let timerId = setInterval(tick, delayMs)
|
||||
return () => clearInterval(timerId)
|
||||
let timerId = setInterval(tick, delayMs);
|
||||
return () => clearInterval(timerId);
|
||||
}
|
||||
}, [delayMs])
|
||||
}
|
||||
}, [delayMs]);
|
||||
}
|
||||
|
|
168
frontend/pages/strategies.tsx
Normal file
168
frontend/pages/strategies.tsx
Normal file
|
@ -0,0 +1,168 @@
|
|||
import DashboardLayout from '../layouts/DashboardLayout';
|
||||
import { styled } from '@mui/styles';
|
||||
import { queryStrategiesMetrics } from '../api/bbgo';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
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',
|
||||
}));
|
||||
|
||||
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 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([]);
|
||||
|
||||
useEffect(() => {
|
||||
queryStrategiesMetrics().then((value) => {
|
||||
setDetails(value);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
{details.map((element) => {
|
||||
return <Detail key={element.id} data={element} />;
|
||||
})}
|
||||
</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