fix chart reload issue

This commit is contained in:
c9s 2022-05-19 12:02:42 +08:00
parent fd45f801e2
commit 0a4c637209
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
3 changed files with 115 additions and 99 deletions

View File

@ -186,8 +186,6 @@ 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 : '';
// reportSummary.startTime
return <div> return <div>
<Container my="md" mx="xs"> <Container my="md" mx="xs">
<Title order={2}>RUN {props.runID}</Title> <Title order={2}>RUN {props.runID}</Title>

View File

@ -1,6 +1,6 @@
import React, {useEffect, useRef, useState} from 'react'; import React, {useEffect, useRef, useState} from 'react';
import {tsvParse} from "d3-dsv"; import {tsvParse} from "d3-dsv";
import { Button } from '@mantine/core'; import {Button} from '@mantine/core';
// https://github.com/tradingview/lightweight-charts/issues/543 // https://github.com/tradingview/lightweight-charts/issues/543
// const createChart = dynamic(() => import('lightweight-charts')); // const createChart = dynamic(() => import('lightweight-charts'));
@ -194,6 +194,7 @@ const removeDuplicatedKLines = (klines) => {
const k = klines[i]; const k = klines[i];
if (i > 0 && k.time === klines[i - 1].time) { if (i > 0 && k.time === klines[i - 1].time) {
console.warn(`duplicated kline at index ${i}`, k)
continue continue
} }
@ -234,6 +235,11 @@ const positionBaseHistoryToLineData = (interval, hs) => {
const intervalSeconds = parseInterval(interval); const intervalSeconds = parseInterval(interval);
for (let i = 0; i < hs.length; i++) { for (let i = 0; i < hs.length; i++) {
const pos = hs[i]; const pos = hs[i];
if (!pos.time) {
console.warn('position history record missing time field', pos)
continue
}
let t = pos.time.getTime() / 1000; let t = pos.time.getTime() / 1000;
t = (t - t % intervalSeconds) t = (t - t % intervalSeconds)
@ -255,6 +261,12 @@ const positionAverageCostHistoryToLineData = (interval, hs) => {
const intervalSeconds = parseInterval(interval); const intervalSeconds = parseInterval(interval);
for (let i = 0; i < hs.length; i++) { for (let i = 0; i < hs.length; i++) {
const pos = hs[i]; const pos = hs[i];
if (!pos.time) {
console.warn('position history record missing time field', pos)
continue
}
let t = pos.time.getTime() / 1000; let t = pos.time.getTime() / 1000;
t = (t - t % intervalSeconds) t = (t - t % intervalSeconds)
@ -279,14 +291,45 @@ const positionAverageCostHistoryToLineData = (interval, hs) => {
return avgCosts; return avgCosts;
} }
const createBaseChart = (chartContainerRef) => {
return createChart(chartContainerRef.current, {
width: chartContainerRef.current.clientWidth,
height: chartContainerRef.current.clientHeight,
timeScale: {
timeVisible: true,
borderColor: '#D1D4DC',
},
rightPriceScale: {
borderColor: '#D1D4DC',
},
leftPriceScale: {
visible: true,
borderColor: 'rgba(197, 203, 206, 1)',
},
layout: {
backgroundColor: '#ffffff',
textColor: '#000',
},
crosshair: {
mode: CrosshairMode.Normal,
},
grid: {
horzLines: {
color: '#F0F3FA',
},
vertLines: {
color: '#F0F3FA',
},
},
});
};
const TradingViewChart = (props) => { const TradingViewChart = (props) => {
const chartContainerRef = useRef(); const chartContainerRef = useRef();
const chart = useRef(); const chart = useRef();
const resizeObserver = useRef(); const resizeObserver = useRef();
const [data, setData] = useState(null); const [data, setData] = useState(null);
const [orders, setOrders] = useState(null);
const [markers, setMarkers] = useState(null);
const [positionHistory, setPositionHistory] = useState(null);
const [currentInterval, setCurrentInterval] = useState('5m'); const [currentInterval, setCurrentInterval] = useState('5m');
const intervals = props.intervals || []; const intervals = props.intervals || [];
@ -296,111 +339,86 @@ const TradingViewChart = (props) => {
return; return;
} }
if (!data) { const chartData = {};
const fetchers = []; const fetchers = [];
const ordersFetcher = fetchOrders(props.basePath, props.runID, (orders) => { const ordersFetcher = fetchOrders(props.basePath, props.runID, (orders) => {
const markers = ordersToMarkets(currentInterval, orders); const markers = ordersToMarkets(currentInterval, orders);
setOrders(orders); chartData.orders = orders;
setMarkers(markers); chartData.markers = markers;
}); });
fetchers.push(ordersFetcher); fetchers.push(ordersFetcher);
if (props.reportSummary && props.reportSummary.manifests && props.reportSummary.manifests.length === 1) { if (props.reportSummary && props.reportSummary.manifests && props.reportSummary.manifests.length === 1) {
const manifest = props.reportSummary?.manifests[0]; const manifest = props.reportSummary?.manifests[0];
if (manifest && manifest.type === "strategyProperty" && manifest.strategyProperty === "position") { if (manifest && manifest.type === "strategyProperty" && manifest.strategyProperty === "position") {
const positionHistoryFetcher = fetchPositionHistory(props.basePath, props.runID, manifest.filename).then((data) => { const positionHistoryFetcher = fetchPositionHistory(props.basePath, props.runID, manifest.filename).then((data) => {
setPositionHistory(data); chartData.positionHistory = data;
}); });
fetchers.push(positionHistoryFetcher); fetchers.push(positionHistoryFetcher);
} }
}
const kLinesFetcher = fetchKLines(props.basePath, props.runID, props.symbol, currentInterval).then((klines) => {
chartData.klines = removeDuplicatedKLines(klines)
});
fetchers.push(kLinesFetcher);
Promise.all(fetchers).then(() => {
console.log("createChart")
if (chart.current) {
chart.current.remove();
} }
Promise.all(fetchers).then(() => { chart.current = createBaseChart(chartContainerRef);
fetchKLines(props.basePath, props.runID, props.symbol, currentInterval).then((data) => {
setData(removeDuplicatedKLines(data)); const series = chart.current.addCandlestickSeries({
}) upColor: 'rgb(38,166,154)',
downColor: 'rgb(255,82,82)',
wickUpColor: 'rgb(38,166,154)',
wickDownColor: 'rgb(255,82,82)',
borderVisible: false,
}); });
series.setData(chartData.klines);
series.setMarkers(chartData.markers);
return; const volumeData = klinesToVolumeData(chartData.klines);
} const volumeSeries = chart.current.addHistogramSeries({
color: '#182233',
console.log("createChart") lineWidth: 2,
priceFormat: {
chart.current = createChart(chartContainerRef.current, { type: 'volume',
width: chartContainerRef.current.clientWidth,
height: chartContainerRef.current.clientHeight,
timeScale: {
timeVisible: true,
borderColor: '#D1D4DC',
},
rightPriceScale: {
borderColor: '#D1D4DC',
},
leftPriceScale: {
visible: true,
borderColor: 'rgba(197, 203, 206, 1)',
},
layout: {
backgroundColor: '#ffffff',
textColor: '#000',
},
crosshair: {
mode: CrosshairMode.Normal,
},
grid: {
horzLines: {
color: '#F0F3FA',
}, },
vertLines: { overlay: true,
color: '#F0F3FA', scaleMargins: {
top: 0.8,
bottom: 0,
}, },
},
});
const series = chart.current.addCandlestickSeries({
upColor: 'rgb(38,166,154)',
downColor: 'rgb(255,82,82)',
wickUpColor: 'rgb(38,166,154)',
wickDownColor: 'rgb(255,82,82)',
borderVisible: false,
});
series.setData(data);
series.setMarkers(markers);
if (positionHistory) {
const lineSeries = chart.current.addLineSeries();
const costLine = positionAverageCostHistoryToLineData(currentInterval, positionHistory);
lineSeries.setData(costLine);
const baseLineSeries = chart.current.addLineSeries({
priceScaleId: 'left',
color: '#98338C',
}); });
const baseLine = positionBaseHistoryToLineData(currentInterval, positionHistory) volumeSeries.setData(volumeData);
baseLineSeries.setData(baseLine);
}
const volumeData = klinesToVolumeData(data); if (chartData.positionHistory) {
const volumeSeries = chart.current.addHistogramSeries({ const lineSeries = chart.current.addLineSeries();
color: '#182233', const costLine = positionAverageCostHistoryToLineData(currentInterval, chartData.positionHistory);
lineWidth: 2, lineSeries.setData(costLine);
priceFormat: {
type: 'volume', const baseLineSeries = chart.current.addLineSeries({
}, priceScaleId: 'left',
overlay: true, color: '#98338C',
scaleMargins: { });
top: 0.8, const baseLine = positionBaseHistoryToLineData(currentInterval, chartData.positionHistory)
bottom: 0, baseLineSeries.setData(baseLine);
}, }
chart.current.timeScale().fitContent();
}); });
volumeSeries.setData(volumeData);
chart.current.timeScale().fitContent();
return () => { return () => {
chart.current.remove(); if (chart.current) {
setData(null); chart.current.remove();
}
}; };
}, [props.runID, props.reportSummary, currentInterval, data]) }, [props.runID, props.reportSummary, currentInterval])
// see: // see:
// https://codesandbox.io/s/9inkb?file=/src/styles.css // https://codesandbox.io/s/9inkb?file=/src/styles.css

View File

@ -27,7 +27,7 @@ const withTM = require('next-transpile-modules')([
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
reactStrictMode: true, reactStrictMode: false,
} }
module.exports = withTM(nextConfig); module.exports = withTM(nextConfig);