@STaFFuRiA

Как добавить движущуюся линию на график?

Я пытался создать постоянно движущуюся вертикальную линию на графике, подобную той, что показана на фото. Несмотря на то что я попробовал уже более сотни различных методов, мне не удалось найти решение.
668fdd6a0994f249148393.png
import React, { useEffect, useRef, useState } from 'react';
import { createChart } from 'lightweight-charts';


const App = () => {
    const chartContainerRef = useRef(null);
    const chart = useRef(null);
    const lineSeries = useRef(null);
    const [selectedCurrency, setSelectedCurrency] = useState('');
    const [searchQuery, setSearchQuery] = useState('');
    const [isDropdownOpen, setIsDropdownOpen] = useState(false);
    const [demoBalance, setDemoBalance] = useState(100000);
    const [tradeDetails, setTradeDetails] = useState({
        amount: '',
        interval: '5',
    });
    const [orderHistory, setOrderHistory] = useState([]);
    const [notifications, setNotifications] = useState([]);
    const [activeMenu, setActiveMenu] = useState(null);
    const [currentPrice, setCurrentPrice] = useState(null);
    const [timeInterval, setTimeInterval] = useState(5);
    const [activeTradesTab, setActiveTradesTab] = useState('Active');
    const [messages, setMessages] = useState([]);
    const [newMessage, setNewMessage] = useState('');
    const verticalLine = useRef(null);

    const currencies = [
        'Asia Composite Index', 'Commodity Composite Index', 'Crypto Composite Index',
        'Europe Composite Index', 'AUD/USD OTC', 'USD/JPY OTC', 'Quickler',
        'EUR/USD OTC', 'GBP/USD OTC', 'AUD/CAD OTC'
    ];

    const { lastMessage } = useWebSocket('ws://docker181472-options.mircloud.host/price', {
        onOpen: () => console.log('WebSocket connection established.'),
        onClose: () => console.log('WebSocket connection closed.'),
        onError: (error) => console.log(`WebSocket error: ${error.message}`),
        shouldReconnect: (closeEvent) => true,
    });

    useEffect(() => {
        chart.current = createChart(chartContainerRef.current, {
            width: chartContainerRef.current.clientWidth,
            height: chartContainerRef.current.clientHeight,
            layout: {
                background: { color: "#301157" },
                textColor: "#C3BCDB",
            },
            grid: {
                vertLines: { color: "#56377D" },
                horzLines: { color: "#56377D" },
            },
            timeScale: {
                timeVisible: true,
                secondsVisible: true,
            },
        });

        lineSeries.current = chart.current.addLineSeries({
            color: '#EEA751',
            lineWidth: 2,
            priceLineVisible: false,
            crossHairMarkerVisible: false,
            priceLineColor: '#EEA751',
        });

        const currentLocale = window.navigator.languages[0];
        const myPriceFormatter = Intl.NumberFormat(currentLocale, {
            style: "currency",
            currency: "USD",
        }).format;

        const handleResize = () => {
            chart.current.resize(chartContainerRef.current.clientWidth, chartContainerRef.current.clientHeight);
        };

        window.addEventListener('resize', handleResize);

        return () => {
            window.removeEventListener('resize', handleResize);
            chart.current.remove();
        };
    }, []);

    useEffect(() => {
        if (lastMessage !== null) {
            const data = JSON.parse(lastMessage.data);
            const point = { time: data.time / 1000, value: data.price };
            if (lineSeries.current) {
                lineSeries.current.update(point);
                setCurrentPrice(data.price);
            }
        }
    }, [lastMessage]);

    const handleMenuItemClick = (menu) => {
        setActiveMenu(menu === activeMenu ? null : menu);
    };

    const filteredCurrencies = currencies.filter(currency =>
        currency.toLowerCase().includes(searchQuery.toLowerCase())
    );

    const handleTradeInputChange = (e) => {
        const { name, value } = e.target;
        setTradeDetails(prevDetails => ({
            ...prevDetails,
            [name]: value,
        }));

        if (name === 'interval') {
            setTimeInterval(parseInt(value, 10));
        }
    };

    const handleOpenTrade = (direction) => {
        const { amount, interval } = tradeDetails;
        if (amount && interval && currentPrice !== null) {
            const parsedAmount = parseFloat(amount);
            const parsedInterval = parseInt(interval, 10) * 1000;
            if (!isNaN(parsedAmount)) {
                if (parsedAmount > demoBalance) {
                    setNotifications(prevNotifications => [
                        ...prevNotifications,
                        'Insufficient balance. Please deposit funds.'
                    ]);
                    return;
                }

                const newBalance = demoBalance - parsedAmount;
                setDemoBalance(newBalance);
                const trade = {
                    startTime: Date.now(),
                    interval: parsedInterval,
                    amount: parsedAmount,
                    direction,
                    date: new Date().toLocaleString(),
                    id: Date.now(),
                    status: 'pending',
                    startPrice: currentPrice,
                };
                setOrderHistory(prevHistory => [...prevHistory, trade]);
                setNotifications(prevNotifications => [
                    ...prevNotifications,
                    `Trade opened: ${direction} ${amount} units`
                ]);

                // Adding vertical lines for trade start and end using markers
                const startMarker = {
                    time: Math.floor(Date.now() / 1000),
                    position: 'aboveBar',
                    color: direction === 'Buy' ? 'green' : 'red',
                    shape: 'arrowUp',
                    text: 'Start'
                };

                const endMarker = {
                    time: Math.floor((Date.now() + parsedInterval) / 1000),
                    position: 'belowBar',
                    color: direction === 'Buy' ? 'green' : 'red',
                    shape: 'arrowDown',
                    text: 'End'
                };

                lineSeries.current.setMarkers([startMarker, endMarker]);

                setTimeout(() => {
                    const endPrice = currentPrice;
                    const priceDifference = endPrice - trade.startPrice;
                    const profit = direction === 'Buy' ? parsedAmount * priceDifference : -parsedAmount * priceDifference;
                    const totalProfit = profit;
                    const newBalanceAfterTrade = newBalance + totalProfit;
                    setDemoBalance(newBalanceAfterTrade);
                    setOrderHistory(prevHistory => prevHistory.map(t =>
                        t.id === trade.id ? { ...t, profit, endPrice, status: 'completed' } : t
                    ));
                    setNotifications(prevNotifications => [
                        ...prevNotifications,
                        `Trade completed: ${direction} ${amount} units. Profit: ${profit > 0 ? '+' : ''}$${profit.toFixed(2)}`
                    ]);
                }, parsedInterval);
            } else {
                setNotifications(prevNotifications => [
                    ...prevNotifications,
                    'Please enter valid data.'
                ]);
            }
        } else {
            setNotifications(prevNotifications => [
                ...prevNotifications,
                'Please fill in all fields to open a trade.'
            ]);
        }
    };

    const handleQuickAmount = (amount) => {
        setTradeDetails(prevDetails => ({
            ...prevDetails,
            amount: amount.toString(),
        }));
    };

    const handleAmountChange = (delta) => {
        setTradeDetails(prevDetails => ({
            ...prevDetails,
            amount: Math.max(0, parseFloat(prevDetails.amount || 0) + delta).toString(),
        }));
    };

    const calculatePotentialPayout = () => {
        const amount = parseFloat(tradeDetails.amount || 0);
        return (amount + (amount * 0.95)).toFixed(2);
    };



    return (
        <div className="main-container">
            <div className="chart-container" ref={chartContainerRef} />
        </div>
    );
};

export default App;
  • Вопрос задан
  • 157 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы