const readOrderByTrade = (
tradeId: string,
token: string,
): Promise<{data:Trade,orders:Array<Order>}|undefined> => {
return diaryClient(
/trades/${tradeId}/orders,
‘get’,
token,
);
}

const [trade, setTrade] = useState<{orders: Array<Order>, data: Trade} | undefined>(undefined);
const [orders, setOrders] = useState<Array<TradeEntity>>([]);
const fetchTrade = () => {
if (!tradeId || !diaryToken) {
return;
}

setWaiting(true);
readOrderByTrade(tradeId, diaryToken)
.then(data => {
setWaiting(false);
if (!data) return;

const newOrders: Array<TradeEntity> = [];

data.orders.forEach(order => {
const timestamp = Math.floor(order.msTimestamp) - timezoneOffset;

newOrders.push({
time: timestamp,
position: order.side,
value: parseFloat(order.price),
});
});

setTrade(data);
setOrders(newOrders);
});
}
const fetchCandleData = () => {
if (!tradeId || !diaryToken) {
return;
}

setWaiting(true);
readCandlesByTrade(tradeId, chartInterval, diaryToken)
.then(data => {
setWaiting(false);
if (!data) return;

// @ts-ignore
const candles = data.data;
const dataLength = candles.length;
const kLines = [];

for (let i = 0; i < dataLength; i += 1) {
const timestamp = Math.floor(candles[i][0]) - timezoneOffset;

kLines.push({
timestamp: timestamp,
open: parseFloat(candles[i][1]),
high: parseFloat(candles[i][2]),
low: parseFloat(candles[i][3]),
close: parseFloat(candles[i][4]),
volume: parseFloat(candles[i][5]),
});

}
setCandleData(kLines);
})
}
return <> <Box sx={{pr: 2}}>
{
trade?.data.id && candleData ? (<>
<CandleChart
images={images}
candles={candleData}
tradeId={trade?.data.id}
orders={orders}
interval={chartInterval}
openPrice={trade?.data.openPrice}
closePrice={trade?.data.closePrice}
pricePrecision={trade.data.pricePrecision}
quantityPrecision={trade.data.quantityPrecision}
createImage={createImage}
/>
</>) : (<>
<Skeleton variant=“rectangular” height={500} />
</>)
}
</Box>
</>);
}
import React, {useEffect, useRef, useState} from “react”;
import {
init,
dispose,
Chart,
DeepPartial,
IndicatorFigureStylesCallbackData,
Indicator,
IndicatorStyle,
KLineData,
utils,
} from “klinecharts”;
import {CandleChartProps} from “./CandleChart.props”;
import CandleChartToolbar from “./CandleChartToolbar”;
import {Style} from “util”;
import {Box, Icon, IconButton, Stack} from “@mui/material”;
import getMinutesTickSizeByInterval from “./utils/getMinutesTickSizeByInterval.util”;
import drawTrade from “./utils/drawTrade.util”;
import drawTradeLines from “./utils/drawTradeLines.util”;
import {BasketIcon, ScreenIcon} from “…/…/icons”;
import {FullScreen, useFullScreenHandle} from “react-full-screen”;;

interface Vol {
volume?: number
}

export const CandleChart = ({
images,
candles,
tradeId,
orders,
interval,
openPrice,
closePrice,
pricePrecision,
quantityPrecision,
createImage
}: CandleChartProps) => {
console.log(candles);

const chart = useRef<Chart|null>();
const paneId = useRef<string>(“”);
const [figureId, setFigureId] = useState<string>(“”)
const ref = useRef<HTMLDivElement>(null);
const handle = useFullScreenHandle();

useEffect(() => {
chart.current = init(chart-${tradeId}, {styles: chartStyles});

return () => dispose(chart-${tradeId});
}, [tradeId]);

useEffect(() => {
const onWindowResize = () => chart.current?.resize();
window.addEventListener(“resize”, onWindowResize);

return () => window.removeEventListener(“resize”, onWindowResize);
}, []);

useEffect(() => {
chart.current?.applyNewData(candles);
chart.current?.overrideIndicator({
name: “VOL”,
shortName: “Объем”,
calcParams: [],
figures: [
{
key: “volume”,
title: “”,
type: “bar”,
baseValue: 0,
styles: (data: IndicatorFigureStylesCallbackData<Vol>, indicator: Indicator, defaultStyles: IndicatorStyle) => {
const kLineData = data.current.kLineData as KLineData
let color: string
if (kLineData.close > kLineData.open) {
color = utils.formatValue(indicator.styles, “bars[0].upColor”, (defaultStyles.bars)[0].upColor) as string
} else if (kLineData.close < kLineData.open) {
color = utils.formatValue(indicator.styles, “bars[0].downColor”, (defaultStyles.bars)[0].downColor) as string
} else {
color = utils.formatValue(indicator.styles, “bars[0].noChangeColor”, (defaultStyles.bars)[0].noChangeColor) as string
}
return { color }
}
}
]
}, paneId.current);
chart.current?.createIndicator(“VOL”, false, { id: paneId.current });
chart.current?.setPriceVolumePrecision(+pricePrecision, +quantityPrecision);
}, [candles]);

useEffect(() => {
if (!orders || orders.length === 0 || candles.length === 0) return;

const minTime = orders[0].time;
const maxTime = orders[orders.length - 1].time;
const needleTime = minTime + (maxTime - minTime) / 2;

chart.current?.scrollToTimestamp(needleTime + 45 * getMinutesTickSizeByInterval(interval) * 60 * 1000);
drawTrade(chart, paneId, orders, interval);
if (openPrice && closePrice) {
let openTime = Infinity;
let closeTime = -Infinity;

orders.forEach(order => {
if (openTime > order.time) {
openTime = order.time;
}

if (closeTime < order.time) {
closeTime = order.time;
}
});

drawTradeLines(
chart,
openPrice,
openTime,
closePrice,
closeTime,
orders[0].position,
paneId,
pricePrecision,
quantityPrecision,
);
}
}, [orders, candles, tradeId]);

return (<>
<Stack direction=“row” height={!handle.active ? 550 : “100%”} width=“100%”>
<CandleChartToolbar
setFigureId={setFigureId}
chart={chart} paneId={paneId}
handle={handle}
/>
<Box
ref={ref}
id={chart-${tradeId}}
width=“calc(100% - 55px)”
height={!handle.active ? 550 : “100%”}
sx={{ borderLeft: “1px solid #ddd” }}
>
{
figureId.length > 0 &&
<Stack
sx={{
backgroundColor: “#CBD4E3”,
borderRadius: 1,
position: “absolute”,
zIndex: 10,
right: 80,
top: 30,
border: “1px solid #697669”,
}}
spacing={2}
>
<IconButton sx={{ borderRadius: 1 }} onClick={removeFigure}>
<Icon component={BasketIcon} />
</IconButton>
</Stack>
}
</Box>
</Stack>
</>);
}

В тех сделках, где нет закрытого ордера нужно отображать на графике свечи в реальном времени и по текущей цене рассчитывать процент. Это нужно, чтобы можно было следить за сделкой в реальном времени. Нужно чтобы график отображал текущую ситуацию на рынке, как здесь https://www.binance.com/ru/futures/DOGEUSDT