From 9f3026aa4b6b596e082a2d92238985e10054d50d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20G=C5=82ownia?= Date: Tue, 21 Mar 2023 16:46:04 +0100 Subject: [PATCH] fix(market-depth): fix depth chart data upate, use market depth as mid price source (#3242) --- .../src/lib/depth-chart-utils.spec.ts | 2 +- .../market-depth/src/lib/depth-chart-utils.ts | 12 ++-- libs/market-depth/src/lib/depth-chart.tsx | 66 ++++++++++++++----- .../src/lib/orderbook-manager.tsx | 5 ++ 4 files changed, 62 insertions(+), 23 deletions(-) diff --git a/libs/market-depth/src/lib/depth-chart-utils.spec.ts b/libs/market-depth/src/lib/depth-chart-utils.spec.ts index cccd82600..2ca1b623f 100644 --- a/libs/market-depth/src/lib/depth-chart-utils.spec.ts +++ b/libs/market-depth/src/lib/depth-chart-utils.spec.ts @@ -74,7 +74,7 @@ describe('updateLevels', () => { const updates = [{ price: '132', volume: '200' }]; - expect(updateLevels(priceLevels, updates, 2, 0, true)).toEqual([ + expect(updateLevels(priceLevels, updates, 2, 0, false)).toEqual([ { price: 1.35, volume: 200 }, { price: 1.32, volume: 200 }, { price: 1.28, volume: 100 }, diff --git a/libs/market-depth/src/lib/depth-chart-utils.ts b/libs/market-depth/src/lib/depth-chart-utils.ts index 3e2a936cb..8266ab977 100644 --- a/libs/market-depth/src/lib/depth-chart-utils.ts +++ b/libs/market-depth/src/lib/depth-chart-utils.ts @@ -1,4 +1,6 @@ import { addDecimal } from '@vegaprotocol/utils'; +import uniqBy from 'lodash/uniqBy'; +import reverse from 'lodash/reverse'; interface PriceLevel { price: number; @@ -41,9 +43,9 @@ export const updateLevels = ( updates: RawPriceLevel[], decimalPlaces: number, positionDecimalPlaces: number, - reverse = false + ascending = true ) => { - updates.forEach((update) => { + uniqBy(reverse(updates || []), 'price').forEach((update) => { const updateLevel = parseLevel( update, decimalPlaces, @@ -63,9 +65,9 @@ export const updateLevels = ( } } else if (update.volume !== '0') { index = levels.findIndex((level) => - reverse - ? level.price < updateLevel.price - : level.price > updateLevel.price + ascending + ? level.price > updateLevel.price + : level.price < updateLevel.price ); if (index !== -1) { levels.splice(index, 0, updateLevel); diff --git a/libs/market-depth/src/lib/depth-chart.tsx b/libs/market-depth/src/lib/depth-chart.tsx index 7bbc0b4e5..be7d74119 100644 --- a/libs/market-depth/src/lib/depth-chart.tsx +++ b/libs/market-depth/src/lib/depth-chart.tsx @@ -9,6 +9,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list'; import type { MarketData } from '@vegaprotocol/market-list'; import type { + MarketDepthQuery, MarketDepthUpdateSubscription, PriceLevelFieldsFragment, } from './__generated__/MarketDepth'; @@ -22,6 +23,18 @@ interface DepthChartManagerProps { const formatMidPrice = (midPrice: string, decimalPlaces: number) => Number(addDecimal(midPrice, decimalPlaces)); +const getMidPrice = ( + sell: PriceLevelFieldsFragment[] | null | undefined, + buy: PriceLevelFieldsFragment[] | null | undefined, + decimalPlaces: number +) => + buy?.length && sell?.length + ? formatMidPrice( + ((BigInt(buy[0].price) + BigInt(sell[0].price)) / BigInt(2)).toString(), + decimalPlaces + ) + : undefined; + type DepthData = Pick; export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => { @@ -30,6 +43,7 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => { const [depthData, setDepthData] = useState(null); const dataRef = useRef(null); const marketDataRef = useRef(null); + const rawDataRef = useRef(null); const deltaRef = useRef<{ sell: PriceLevelFieldsFragment[]; buy: PriceLevelFieldsFragment[]; @@ -56,28 +70,28 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => { } dataRef.current = { ...dataRef.current, - midPrice: marketDataRef.current?.staticMidPrice - ? formatMidPrice( - marketDataRef.current?.staticMidPrice, - market.decimalPlaces - ) - : undefined, + midPrice: getMidPrice( + rawDataRef.current?.depth.sell, + rawDataRef.current?.depth.buy, + market.decimalPlaces + ), data: { - buy: deltaRef.current.buy + buy: deltaRef.current.buy.length ? updateLevels( dataRef.current.data.buy, deltaRef.current.buy, market.decimalPlaces, market.positionDecimalPlaces, - true + false ) : dataRef.current.data.buy, - sell: deltaRef.current.sell + sell: deltaRef.current.sell.length ? updateLevels( dataRef.current.data.sell, deltaRef.current.sell, market.decimalPlaces, - market.positionDecimalPlaces + market.positionDecimalPlaces, + true ) : dataRef.current.data.sell, }, @@ -85,16 +99,23 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => { deltaRef.current.buy = []; deltaRef.current.sell = []; setDepthData(dataRef.current); - }, 1000), + }, 250), [market] ); + useEffect(() => { + deltaRef.current.buy = []; + deltaRef.current.sell = []; + }, [marketId]); + // Apply updates to the table const update = useCallback( ({ delta: deltas, + data: rawData, }: { - delta?: MarketDepthUpdateSubscription['marketsDepthUpdate']; + delta?: MarketDepthUpdateSubscription['marketsDepthUpdate'] | null; + data: NonNullable | null; }) => { if (!dataRef.current) { return false; @@ -109,6 +130,7 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => { if (delta.buy) { deltaRef.current.buy.push(...delta.buy); } + rawDataRef.current = rawData; updateDepthData(); } return true; @@ -116,7 +138,11 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => { [marketId, updateDepthData] ); - const { data, error, loading } = useDataProvider({ + const { data, error, loading } = useDataProvider< + NonNullable | null, + MarketDepthUpdateSubscription['marketsDepthUpdate'], + { marketId: string } + >({ dataProvider: marketDepthProvider, update, variables, @@ -155,9 +181,11 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => { return; } dataRef.current = { - midPrice: marketData.staticMidPrice - ? formatMidPrice(marketData.staticMidPrice, market.decimalPlaces) - : undefined, + midPrice: getMidPrice( + data.depth.sell, + data.depth.buy, + market.decimalPlaces + ), data: { buy: data.depth.buy?.map((priceLevel) => @@ -177,8 +205,12 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => { ) ?? [], }, }; + rawDataRef.current = data; setDepthData(dataRef.current); - }, [data, marketData, market]); + return () => { + updateDepthData.cancel(); + }; + }, [data, marketData, market, updateDepthData]); const volumeFormat = useCallback( (volume: number) => diff --git a/libs/market-depth/src/lib/orderbook-manager.tsx b/libs/market-depth/src/lib/orderbook-manager.tsx index 552be50f1..3f853ffbd 100644 --- a/libs/market-depth/src/lib/orderbook-manager.tsx +++ b/libs/market-depth/src/lib/orderbook-manager.tsx @@ -75,6 +75,11 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => { }, 250) ); + useEffect(() => { + deltaRef.current.buy = []; + deltaRef.current.sell = []; + }, [marketId]); + const update = useCallback( ({ delta: deltas,