mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
Improve backtest report ui
This commit is contained in:
parent
9f5575f1ef
commit
0ad62c5b58
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
bbgo.sqlite3
|
bbgo.sqlite3
|
||||||
node_modules
|
node_modules
|
||||||
|
output
|
||||||
|
|
||||||
otp*png
|
otp*png
|
||||||
|
|
||||||
|
|
|
@ -52,33 +52,32 @@ function StatsGridIcons({data}: StatsGridIconsProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper withBorder p="xs" radius="md" key={stat.title}>
|
<Paper withBorder p="xs" radius="md" key={stat.title}>
|
||||||
<Group position="apart">
|
<Group position="left">
|
||||||
<div>
|
<div>
|
||||||
<Text
|
<Text
|
||||||
color="dimmed"
|
color="dimmed"
|
||||||
transform="uppercase"
|
|
||||||
weight={700}
|
weight={700}
|
||||||
size="xs"
|
size="xs"
|
||||||
className={classes.label}
|
className={classes.label}
|
||||||
>
|
>
|
||||||
{stat.title}
|
{stat.title}
|
||||||
</Text>
|
|
||||||
<Text weight={700} size="xl">
|
|
||||||
{stat.value}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{stat.dir ?
|
{stat.dir ?
|
||||||
<ThemeIcon
|
<ThemeIcon
|
||||||
color="gray"
|
color="gray"
|
||||||
variant="light"
|
variant="light"
|
||||||
sx={(theme) => ({color: stat.dir == "up" ? theme.colors.teal[6] : theme.colors.red[6]})}
|
sx={(theme) => ({color: stat.dir == "up" ? theme.colors.teal[6] : theme.colors.red[6]})}
|
||||||
size={38}
|
size={16}
|
||||||
radius="md"
|
radius="sx"
|
||||||
>
|
>
|
||||||
<DirIcon size={28}/>
|
<DirIcon size={16}/>
|
||||||
</ThemeIcon>
|
</ThemeIcon>
|
||||||
: null}
|
: null}
|
||||||
|
</Text>
|
||||||
|
<Text weight={700} size="xs">
|
||||||
|
{stat.value}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{stat.diff ?
|
{stat.diff ?
|
||||||
<ThemeIcon
|
<ThemeIcon
|
||||||
|
@ -112,8 +111,8 @@ function StatsGridIcons({data}: StatsGridIconsProps) {
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div py="xl">
|
||||||
<SimpleGrid cols={4} breakpoints={[{maxWidth: 'sm', cols: 1}]}>
|
<SimpleGrid cols={5} breakpoints={[{maxWidth: 'sm', cols: 1, spacing: 'xl'}]}>
|
||||||
{stats}
|
{stats}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</div>
|
</div>
|
||||||
|
@ -151,7 +150,7 @@ const BalanceDetails = (props: BalanceDetailsProps) => {
|
||||||
</tr>;
|
</tr>;
|
||||||
});
|
});
|
||||||
|
|
||||||
return <Table>
|
return <Table verticalSpacing="xs" fontSize="xs">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Currency</th>
|
<th>Currency</th>
|
||||||
|
@ -177,6 +176,8 @@ const ReportDetails = (props: ReportDetailsProps) => {
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const strategyName = props.runID.split("_")[1]
|
||||||
|
const runID = props.runID.split("_").pop()
|
||||||
const totalProfit = Math.round(reportSummary.symbolReports.map((report) => report.pnl.profit).reduce((prev, cur) => prev + cur) * 100) / 100
|
const totalProfit = Math.round(reportSummary.symbolReports.map((report) => report.pnl.profit).reduce((prev, cur) => prev + cur) * 100) / 100
|
||||||
const totalUnrealizedProfit = Math.round(reportSummary.symbolReports.map((report) => report.pnl.unrealizedProfit).reduce((prev, cur) => prev + cur) * 100) / 100
|
const totalUnrealizedProfit = Math.round(reportSummary.symbolReports.map((report) => report.pnl.unrealizedProfit).reduce((prev, cur) => prev + cur) * 100) / 100
|
||||||
const totalTrades = reportSummary.symbolReports.map((report) => report.pnl.numTrades).reduce((prev, cur) => prev + cur) || 0
|
const totalTrades = reportSummary.symbolReports.map((report) => report.pnl.numTrades).reduce((prev, cur) => prev + cur) || 0
|
||||||
|
@ -187,36 +188,36 @@ const ReportDetails = (props: ReportDetailsProps) => {
|
||||||
const volumeUnit = reportSummary.symbolReports.length == 1 ? reportSummary.symbolReports[0].market.baseCurrency : '';
|
const volumeUnit = reportSummary.symbolReports.length == 1 ? reportSummary.symbolReports[0].market.baseCurrency : '';
|
||||||
|
|
||||||
return <div>
|
return <div>
|
||||||
<Container my="md" mx="xs">
|
<Container my="sx">
|
||||||
<Title order={2}>RUN {props.runID}</Title>
|
|
||||||
<div>
|
<div>
|
||||||
{reportSummary.sessions.map((session) => <Badge key={session}>Exchange {session}</Badge>)}
|
<Badge key={strategyName} color="teal">Strategy: {strategyName}</Badge>
|
||||||
{reportSummary.symbols.map((symbol) => <Badge key={symbol}>{symbol}</Badge>)}
|
{reportSummary.sessions.map((session) => <Badge key={session} color="teal">Exchange: {session}</Badge>)}
|
||||||
|
{reportSummary.symbols.map((symbol) => <Badge key={symbol} color="teal">Symbol: {symbol}</Badge>)}
|
||||||
|
|
||||||
<Badge>{reportSummary.startTime.toString()} ~ {reportSummary.endTime.toString()}</Badge>
|
<Badge color="teal">{reportSummary.startTime.toString()} — {reportSummary.endTime.toString()} ~ {
|
||||||
<Badge>{
|
|
||||||
moment.duration((new Date(reportSummary.endTime)).getTime() - (new Date(reportSummary.startTime)).getTime()).humanize()
|
moment.duration((new Date(reportSummary.endTime)).getTime() - (new Date(reportSummary.startTime)).getTime()).humanize()
|
||||||
}</Badge>
|
}</Badge>
|
||||||
|
<Badge key={runID} color="gray" size="xs">Run ID: {runID}</Badge>
|
||||||
</div>
|
</div>
|
||||||
<StatsGridIcons data={[
|
<StatsGridIcons data={[
|
||||||
{title: "Profit", value: "$" + totalProfit.toString(), dir: totalProfit > 0 ? "up" : "down"},
|
{title: "Profit", value: "$" + totalProfit.toString(), dir: totalProfit >= 0 ? "up" : "down"},
|
||||||
{
|
{
|
||||||
title: "Unrealized Profit",
|
title: "Unr. Profit",
|
||||||
value: "$" + totalUnrealizedProfit.toString(),
|
value: totalUnrealizedProfit.toString() + "$",
|
||||||
dir: totalUnrealizedProfit > 0 ? "up" : "down"
|
dir: totalUnrealizedProfit > 0 ? "up" : "down"
|
||||||
},
|
},
|
||||||
{title: "Trades", value: totalTrades.toString()},
|
{title: "Trades", value: totalTrades.toString()},
|
||||||
{title: "Buy Volume", value: totalBuyVolume.toString() + ` ${volumeUnit}`},
|
{title: "Buy Vol", value: totalBuyVolume.toString() + ` ${volumeUnit}`},
|
||||||
{title: "Sell Volume", value: totalSellVolume.toString() + ` ${volumeUnit}`},
|
{title: "Sell Vol", value: totalSellVolume.toString() + ` ${volumeUnit}`},
|
||||||
]}/>
|
]}/>
|
||||||
|
|
||||||
<Grid p={"xs"} mb={"lg"}>
|
<Grid py="xl">
|
||||||
<Grid.Col xs={6}>
|
<Grid.Col xs={6}>
|
||||||
<Title order={5}>Initial Total Balances</Title>
|
<Title order={6}>Initial Total Balances</Title>
|
||||||
<BalanceDetails balances={reportSummary.initialTotalBalances}/>
|
<BalanceDetails balances={reportSummary.initialTotalBalances}/>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col xs={6}>
|
<Grid.Col xs={6}>
|
||||||
<Title order={5}>Final Total Balances</Title>
|
<Title order={6}>Final Total Balances</Title>
|
||||||
<BalanceDetails balances={reportSummary.finalTotalBalances}/>
|
<BalanceDetails balances={reportSummary.finalTotalBalances}/>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -11,6 +11,7 @@ function fetchIndex(basePath: string, setter: (data: any) => void) {
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
console.log("reportIndex", data);
|
console.log("reportIndex", data);
|
||||||
|
data.runs.reverse() // last reports render first
|
||||||
setter(data);
|
setter(data);
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
|
@ -47,7 +48,7 @@ const ReportNavigator = (props: ReportNavigatorProps) => {
|
||||||
size="xs"
|
size="xs"
|
||||||
center
|
center
|
||||||
icon={
|
icon={
|
||||||
<ThemeIcon color="teal" size={24} radius="xl">
|
<ThemeIcon color="teal" size={16} radius="xl">
|
||||||
<CircleCheck size={16}/>
|
<CircleCheck size={16}/>
|
||||||
</ThemeIcon>
|
</ThemeIcon>
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,9 +173,9 @@ const ordersToMarkets = (interval: string, orders: Array<Order> | void): Array<M
|
||||||
time: t,
|
time: t,
|
||||||
position: 'belowBar',
|
position: 'belowBar',
|
||||||
color: '#239D10',
|
color: '#239D10',
|
||||||
shape: 'arrowDown',
|
shape: 'arrowUp',
|
||||||
// text: 'Buy @ ' + order.price
|
text: ''+order.price
|
||||||
text: 'B',
|
//text: 'B',
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "SELL":
|
case "SELL":
|
||||||
|
@ -184,8 +184,8 @@ const ordersToMarkets = (interval: string, orders: Array<Order> | void): Array<M
|
||||||
position: 'aboveBar',
|
position: 'aboveBar',
|
||||||
color: '#e91e63',
|
color: '#e91e63',
|
||||||
shape: 'arrowDown',
|
shape: 'arrowDown',
|
||||||
// text: 'Sell @ ' + order.price
|
text: ''+order.price
|
||||||
text: 'S',
|
//text: 'S',
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ const Home: NextPage = () => {
|
||||||
</Head>
|
</Head>
|
||||||
<main className={styles.main}>
|
<main className={styles.main}>
|
||||||
<AppShell
|
<AppShell
|
||||||
padding="md"
|
padding="xm"
|
||||||
navbar={<Navbar width={{base: 250}} height={500} p="xs">
|
navbar={<Navbar width={{base: 250}} height={500} p="xs">
|
||||||
|
|
||||||
<ReportNavigator onSelect={(reportEntry) => {
|
<ReportNavigator onSelect={(reportEntry) => {
|
||||||
|
@ -31,7 +31,7 @@ const Home: NextPage = () => {
|
||||||
|
|
||||||
</Navbar>}
|
</Navbar>}
|
||||||
header={
|
header={
|
||||||
<Header height={60} p="md">
|
<Header height={50} p="sm">
|
||||||
<Text>BBGO Back-Test Report</Text>
|
<Text>BBGO Back-Test Report</Text>
|
||||||
</Header>
|
</Header>
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user