import React, {useRef, useState} from "react"; import { useQuoteData } from "../QueryOptions/apiQueryOptions"; import { useQueryContext } from "../context/querycontext"; import * as echarts from 'echarts'; import ReactECharts from 'echarts-for-react'; const ChartComponents: React.FC = () => { const chartRef = useRef(null); const { queryOptions, isLoadingBrokers, isErrorBrokers } = useQueryContext(); const { data: quoteData, isLoading: isLoadingQuotes, isError: isErrorQuotes } = useQuoteData(queryOptions); const [showMidline, setShowMidline] = useState(false); // console.log('quote data before render:', quoteData, // 'isLoadingQuotes:', isLoadingQuotes, // 'quotesError:', isErrorQuotes); if (isLoadingBrokers) return
Loading brokers...
; if (isErrorBrokers) return
Error loading brokers
; if (isErrorQuotes) return
Error loading quote data
; if (!quoteData?.records?.length) return
No quote data available
; const datasetSource = quoteData.records.filter(record => record.askA !== null || record.midlineA || record.bidA !== null || record.askB !== null || record.bidB !== null || record.midlineB) .map(record => ({ timestamp: record.timestamp, askA: record.askA, askB: record.askB, bidA: record.bidA, bidB: record.bidB, midlineA: record.midlineA, midlineB: record.midlineB, })); // console.log('datasetSource:', datasetSource); const valuesA = datasetSource .flatMap(record => [record.askA, record.bidA, record.midlineA]) .filter((value): value is number => value !== null); const valuesB = datasetSource .flatMap(record => [record.askB, record.bidB, record.midlineB]) .filter((value): value is number => value !== null); const buffer = 0.00001; // console.log('ValueA:', valuesA); // console.log('ValueB:', valuesB); // console.log('askA values:', datasetSource.map(r => r.askA).filter(v => v !== null)); // console.log('askB values:', datasetSource.map(r => r.askB).filter(v => v !== null)); // console.log('bidA values:', datasetSource.map(r => r.bidA).filter(v => v !== null)); // console.log('bidB values:', datasetSource.map(r => r.bidB).filter(v => v !== null)); const minValueA = valuesA.length ? Math.min(...valuesA) - buffer : 0; const maxValueA = valuesA.length ? Math.max(...valuesA) + buffer : 100; const minValueB = valuesB.length ? Math.min(...valuesB) - buffer : 0; const maxValueB = valuesB.length ? Math.max(...valuesB) + buffer : 100; // console.log('minValueA:', minValueA); // console.log('maxValueA:', maxValueA); // console.log('minValueB:', minValueB); // console.log('maxValueB:', maxValueB); // const option = { dataset: { source: datasetSource, dimensions: ['timestamp', 'askA', 'askB', 'bidA', 'bidB', 'midlineA', 'midlineB'], }, tooltip: { trigger: 'axis', formatter: (params: any) => { const date = new Date(params[0].value[0]); return ( `Time: ${date.toLocaleTimeString()}
` + params .map((p: any) => `${p.seriesName}: ${p.value[1] != null ? p.value[1].toFixed(5) : 'N/A'}`) .join('
') ); }, }, legend: { data: [ `Ask A (${quoteData.brokerA}/${quoteData.symbolA})`, `Bid A (${quoteData.brokerA}/${quoteData.symbolA})`, `Midline A (${quoteData.brokerA}/${quoteData.symbolA})`, `Ask B (${quoteData.brokerB}/${quoteData.symbolB})`, `Bid B (${quoteData.brokerB}/${quoteData.symbolB})`, `Midline B (${quoteData.brokerB}/${quoteData.symbolB})`, ], selected: { [`Ask A (${quoteData.brokerA}/${quoteData.symbolA})`]: !showMidline, [`Ask B (${quoteData.brokerB}/${quoteData.symbolB})`]: !showMidline, [`Bid A (${quoteData.brokerA}/${quoteData.symbolA})`]: !showMidline, [`Bid B (${quoteData.brokerB}/${quoteData.symbolB})`]: !showMidline, [`Midline A (${quoteData.brokerA}/${quoteData.symbolA})`]: showMidline, [`Midline B (${quoteData.brokerB}/${quoteData.symbolB})`]: showMidline, }, }, grid: { left: '5%', right: '5%', bottom: '15%', containLabel: true, }, toolbox: { feature: { saveAsImage: {}, }, }, dataZoom: [ { type: 'slider', xAxisIndex: 0, start: 80, end: 100, labelFormatter: (value: number) => { const date = new Date(value); return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`; }, }, { type: 'inside', xAxisIndex: 0, start: 80, end: 100, }, { type: 'slider', yAxisIndex: 0, start: 0, end: 100, labelFormatter: (value: number) => value.toFixed(5), }, { type: 'inside', yAxisIndex: 0, start: 0, end: 100, }, { type: 'slider', yAxisIndex: 1, start: 0, end: 100, labelFormatter: (value: number) => value.toFixed(5), }, { type: 'inside', yAxisIndex: 1, start: 0, end: 100, }, ], xAxis: { type: 'time', name: 'Timestamp', axisLabel: { formatter: (value: number) => { const date = new Date(value); return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`; }, }, }, yAxis: [ { type: 'value', name: `${quoteData.brokerA}/${quoteData.symbolA}`, min: minValueA, max: maxValueA, axisLabel: { formatter: (value: number) => value.toFixed(5), }, // alignTicks:true, scale: true, splitNumber: 10, }, { type: 'value', name: `${quoteData.brokerB}/${quoteData.symbolB}`, min: minValueB, max: maxValueB, position: 'right', axisLabel: { formatter: (value: number) => value.toFixed(5), }, // alignTicks:true, scale: true, splitNumber: 10, }, ], series: [ { name: `Ask A (${quoteData.brokerA}/${quoteData.symbolA})`, type: 'line', data: datasetSource .filter(record => record.askA !== null) .map(record => [record.timestamp, record.askA]), yAxisIndex: 0, lineStyle: { color: '#007bff', width: 2 }, itemStyle: { color: '#007bff' }, showSymbol: true, symbol: 'circle', symbolSize: 4, connectNulls: false, }, { name: `Bid A (${quoteData.brokerA}/${quoteData.symbolA})`, type: 'line', data: datasetSource .filter(record => record.bidA !== null) .map(record => [record.timestamp, record.bidA]), yAxisIndex: 0, lineStyle: { color: '#00b7eb', type: 'dashed', width: 2 }, itemStyle: { color: '#00b7eb' }, showSymbol: true, symbol: 'circle', symbolSize: 4, connectNulls: false, }, { name: `Ask B (${quoteData.brokerB}/${quoteData.symbolB})`, type: 'line', data: datasetSource .filter(record => record.askB !== null) .map(record => [record.timestamp, record.askB]), yAxisIndex: 1, lineStyle: { color: '#ff4500', width: 2 }, itemStyle: { color: '#ff4500' }, showSymbol: true, symbol: 'square', symbolSize: 4, connectNulls: false, }, { name: `Bid B (${quoteData.brokerB}/${quoteData.symbolB})`, type: 'line', data: datasetSource .filter(record => record.bidB !== null) .map(record => [record.timestamp, record.bidB]), yAxisIndex: 1, lineStyle: { color: '#ff8c00', type: 'dashed', width: 2 }, itemStyle: { color: '#ff8c00' }, showSymbol: true, symbol: 'square', symbolSize: 4, connectNulls: false, }, { name: `Midline A (${quoteData.brokerA}/${quoteData.symbolA})`, type: 'line', data: datasetSource .filter(record => record.midlineA !== null) .map(record => [record.timestamp, record.midlineA]), yAxisIndex: 0, lineStyle: { color: '#28a745', width: 2 }, itemStyle: { color: '#28a745' }, showSymbol: true, symbol: 'circle', symbolSize: 4, connectNulls: false, }, { name: `Midline B (${quoteData.brokerB}/${quoteData.symbolB})`, type: 'line', data: datasetSource .filter(record => record.midlineB !== null) .map(record => [record.timestamp, record.midlineB]), yAxisIndex: 1, lineStyle: { color: '#9932cc', width: 2 }, itemStyle: { color: '#9932cc' }, showSymbol: true, symbol: 'square', symbolSize: 4, connectNulls: false, }, ], }; return (

Quote Chart

) }; export default ChartComponents;