fix(market-depth): fix depth chart data upate, use market depth as mid price source (#3242)

This commit is contained in:
Bartłomiej Głownia 2023-03-21 16:46:04 +01:00 committed by GitHub
parent faa359e2fb
commit 9f3026aa4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 23 deletions

View File

@ -74,7 +74,7 @@ describe('updateLevels', () => {
const updates = [{ price: '132', volume: '200' }]; 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.35, volume: 200 },
{ price: 1.32, volume: 200 }, { price: 1.32, volume: 200 },
{ price: 1.28, volume: 100 }, { price: 1.28, volume: 100 },

View File

@ -1,4 +1,6 @@
import { addDecimal } from '@vegaprotocol/utils'; import { addDecimal } from '@vegaprotocol/utils';
import uniqBy from 'lodash/uniqBy';
import reverse from 'lodash/reverse';
interface PriceLevel { interface PriceLevel {
price: number; price: number;
@ -41,9 +43,9 @@ export const updateLevels = (
updates: RawPriceLevel[], updates: RawPriceLevel[],
decimalPlaces: number, decimalPlaces: number,
positionDecimalPlaces: number, positionDecimalPlaces: number,
reverse = false ascending = true
) => { ) => {
updates.forEach((update) => { uniqBy(reverse(updates || []), 'price').forEach((update) => {
const updateLevel = parseLevel( const updateLevel = parseLevel(
update, update,
decimalPlaces, decimalPlaces,
@ -63,9 +65,9 @@ export const updateLevels = (
} }
} else if (update.volume !== '0') { } else if (update.volume !== '0') {
index = levels.findIndex((level) => index = levels.findIndex((level) =>
reverse ascending
? level.price < updateLevel.price ? level.price > updateLevel.price
: level.price > updateLevel.price : level.price < updateLevel.price
); );
if (index !== -1) { if (index !== -1) {
levels.splice(index, 0, updateLevel); levels.splice(index, 0, updateLevel);

View File

@ -9,6 +9,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list'; import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
import type { MarketData } from '@vegaprotocol/market-list'; import type { MarketData } from '@vegaprotocol/market-list';
import type { import type {
MarketDepthQuery,
MarketDepthUpdateSubscription, MarketDepthUpdateSubscription,
PriceLevelFieldsFragment, PriceLevelFieldsFragment,
} from './__generated__/MarketDepth'; } from './__generated__/MarketDepth';
@ -22,6 +23,18 @@ interface DepthChartManagerProps {
const formatMidPrice = (midPrice: string, decimalPlaces: number) => const formatMidPrice = (midPrice: string, decimalPlaces: number) =>
Number(addDecimal(midPrice, decimalPlaces)); 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<DepthChartProps, 'data' | 'midPrice'>; type DepthData = Pick<DepthChartProps, 'data' | 'midPrice'>;
export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => { export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
@ -30,6 +43,7 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
const [depthData, setDepthData] = useState<DepthData | null>(null); const [depthData, setDepthData] = useState<DepthData | null>(null);
const dataRef = useRef<DepthData | null>(null); const dataRef = useRef<DepthData | null>(null);
const marketDataRef = useRef<MarketData | null>(null); const marketDataRef = useRef<MarketData | null>(null);
const rawDataRef = useRef<MarketDepthQuery['market'] | null>(null);
const deltaRef = useRef<{ const deltaRef = useRef<{
sell: PriceLevelFieldsFragment[]; sell: PriceLevelFieldsFragment[];
buy: PriceLevelFieldsFragment[]; buy: PriceLevelFieldsFragment[];
@ -56,28 +70,28 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
} }
dataRef.current = { dataRef.current = {
...dataRef.current, ...dataRef.current,
midPrice: marketDataRef.current?.staticMidPrice midPrice: getMidPrice(
? formatMidPrice( rawDataRef.current?.depth.sell,
marketDataRef.current?.staticMidPrice, rawDataRef.current?.depth.buy,
market.decimalPlaces market.decimalPlaces
) ),
: undefined,
data: { data: {
buy: deltaRef.current.buy buy: deltaRef.current.buy.length
? updateLevels( ? updateLevels(
dataRef.current.data.buy, dataRef.current.data.buy,
deltaRef.current.buy, deltaRef.current.buy,
market.decimalPlaces, market.decimalPlaces,
market.positionDecimalPlaces, market.positionDecimalPlaces,
true false
) )
: dataRef.current.data.buy, : dataRef.current.data.buy,
sell: deltaRef.current.sell sell: deltaRef.current.sell.length
? updateLevels( ? updateLevels(
dataRef.current.data.sell, dataRef.current.data.sell,
deltaRef.current.sell, deltaRef.current.sell,
market.decimalPlaces, market.decimalPlaces,
market.positionDecimalPlaces market.positionDecimalPlaces,
true
) )
: dataRef.current.data.sell, : dataRef.current.data.sell,
}, },
@ -85,16 +99,23 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
deltaRef.current.buy = []; deltaRef.current.buy = [];
deltaRef.current.sell = []; deltaRef.current.sell = [];
setDepthData(dataRef.current); setDepthData(dataRef.current);
}, 1000), }, 250),
[market] [market]
); );
useEffect(() => {
deltaRef.current.buy = [];
deltaRef.current.sell = [];
}, [marketId]);
// Apply updates to the table // Apply updates to the table
const update = useCallback( const update = useCallback(
({ ({
delta: deltas, delta: deltas,
data: rawData,
}: { }: {
delta?: MarketDepthUpdateSubscription['marketsDepthUpdate']; delta?: MarketDepthUpdateSubscription['marketsDepthUpdate'] | null;
data: NonNullable<MarketDepthQuery['market']> | null;
}) => { }) => {
if (!dataRef.current) { if (!dataRef.current) {
return false; return false;
@ -109,6 +130,7 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
if (delta.buy) { if (delta.buy) {
deltaRef.current.buy.push(...delta.buy); deltaRef.current.buy.push(...delta.buy);
} }
rawDataRef.current = rawData;
updateDepthData(); updateDepthData();
} }
return true; return true;
@ -116,7 +138,11 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
[marketId, updateDepthData] [marketId, updateDepthData]
); );
const { data, error, loading } = useDataProvider({ const { data, error, loading } = useDataProvider<
NonNullable<MarketDepthQuery['market']> | null,
MarketDepthUpdateSubscription['marketsDepthUpdate'],
{ marketId: string }
>({
dataProvider: marketDepthProvider, dataProvider: marketDepthProvider,
update, update,
variables, variables,
@ -155,9 +181,11 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
return; return;
} }
dataRef.current = { dataRef.current = {
midPrice: marketData.staticMidPrice midPrice: getMidPrice(
? formatMidPrice(marketData.staticMidPrice, market.decimalPlaces) data.depth.sell,
: undefined, data.depth.buy,
market.decimalPlaces
),
data: { data: {
buy: buy:
data.depth.buy?.map((priceLevel) => data.depth.buy?.map((priceLevel) =>
@ -177,8 +205,12 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
) ?? [], ) ?? [],
}, },
}; };
rawDataRef.current = data;
setDepthData(dataRef.current); setDepthData(dataRef.current);
}, [data, marketData, market]); return () => {
updateDepthData.cancel();
};
}, [data, marketData, market, updateDepthData]);
const volumeFormat = useCallback( const volumeFormat = useCallback(
(volume: number) => (volume: number) =>

View File

@ -75,6 +75,11 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
}, 250) }, 250)
); );
useEffect(() => {
deltaRef.current.buy = [];
deltaRef.current.sell = [];
}, [marketId]);
const update = useCallback( const update = useCallback(
({ ({
delta: deltas, delta: deltas,