fix(trading): market selector volume update (#3989)
This commit is contained in:
parent
878bed9c7a
commit
aae5c44fa4
@ -57,7 +57,6 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
|||||||
|
|
||||||
it('market volume displayed', () => {
|
it('market volume displayed', () => {
|
||||||
cy.getByTestId(marketTitle).contains('Market volume').click();
|
cy.getByTestId(marketTitle).contains('Market volume').click();
|
||||||
validateMarketDataRow(0, '24 Hour Volume', 'Unknown');
|
|
||||||
validateMarketDataRow(1, 'Open Interest', '-');
|
validateMarketDataRow(1, 'Open Interest', '-');
|
||||||
validateMarketDataRow(2, 'Best Bid Volume', '1');
|
validateMarketDataRow(2, 'Best Bid Volume', '1');
|
||||||
validateMarketDataRow(3, 'Best Offer Volume', '3');
|
validateMarketDataRow(3, 'Best Offer Volume', '3');
|
||||||
|
@ -40,26 +40,26 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
|||||||
{
|
{
|
||||||
code: 'SOLUSD',
|
code: 'SOLUSD',
|
||||||
markPrice: '84.41XYZalpha',
|
markPrice: '84.41XYZalpha',
|
||||||
change: '+200.00%',
|
change: '',
|
||||||
vol: '324h vol',
|
vol: '0.0024h vol',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: 'ETHBTC.QM21',
|
code: 'ETHBTC.QM21',
|
||||||
markPrice: '46,126.90058tBTC',
|
markPrice: '46,126.90058tBTC',
|
||||||
change: '+200.00%',
|
change: '',
|
||||||
vol: '324h vol',
|
vol: '0.0024h vol',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: 'BTCUSD.MF21',
|
code: 'BTCUSD.MF21',
|
||||||
markPrice: '46,126.90058tDAI',
|
markPrice: '46,126.90058tDAI',
|
||||||
change: '+200.00%',
|
change: '',
|
||||||
vol: '324h vol',
|
vol: '0.0024h vol',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: 'AAPL.MF21',
|
code: 'AAPL.MF21',
|
||||||
markPrice: '46,126.90058tUSDC',
|
markPrice: '46,126.90058tUSDC',
|
||||||
change: '+200.00%',
|
change: '',
|
||||||
vol: '324h vol',
|
vol: '0.0024h vol',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
cy.getByTestId(list)
|
cy.getByTestId(list)
|
||||||
@ -80,7 +80,7 @@ describe('markets selector', { tags: '@smoke' }, () => {
|
|||||||
market.change
|
market.change
|
||||||
);
|
);
|
||||||
// 6001-MARK-025
|
// 6001-MARK-025
|
||||||
expect(item.find('[data-testid="sparkline-svg"]')).to.exist;
|
expect(item.find('[data-testid="sparkline-svg"]')).to.not.exist;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,25 +6,32 @@ import { MemoryRouter } from 'react-router-dom';
|
|||||||
import type { MockedResponse } from '@apollo/client/testing';
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
import type {
|
import type {
|
||||||
|
MarketCandlesQuery,
|
||||||
|
MarketCandlesQueryVariables,
|
||||||
MarketDataUpdateFieldsFragment,
|
MarketDataUpdateFieldsFragment,
|
||||||
MarketDataUpdateSubscription,
|
MarketDataUpdateSubscription,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
|
import { MarketCandlesDocument } from '@vegaprotocol/markets';
|
||||||
import { MarketDataUpdateDocument } from '@vegaprotocol/markets';
|
import { MarketDataUpdateDocument } from '@vegaprotocol/markets';
|
||||||
import {
|
import {
|
||||||
AuctionTrigger,
|
AuctionTrigger,
|
||||||
|
Interval,
|
||||||
MarketState,
|
MarketState,
|
||||||
MarketTradingMode,
|
MarketTradingMode,
|
||||||
} from '@vegaprotocol/types';
|
} from '@vegaprotocol/types';
|
||||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
|
import { subDays } from 'date-fns';
|
||||||
|
|
||||||
describe('MarketSelectorItem', () => {
|
describe('MarketSelectorItem', () => {
|
||||||
|
const yesterday = new Date();
|
||||||
|
yesterday.setHours(yesterday.getHours() - 20);
|
||||||
const market = createMarketFragment({
|
const market = createMarketFragment({
|
||||||
id: 'market-0',
|
id: 'market-0',
|
||||||
decimalPlaces: 2,
|
decimalPlaces: 2,
|
||||||
// @ts-ignore fragment doesn't contain candles
|
// @ts-ignore fragment doesn't contain candles
|
||||||
candles: [
|
candles: [
|
||||||
{ close: '5', volume: '50' },
|
{ close: '5', volume: '50', periodStart: yesterday.toISOString() },
|
||||||
{ close: '10', volume: '50' },
|
{ close: '10', volume: '50', periodStart: yesterday.toISOString() },
|
||||||
],
|
],
|
||||||
tradableInstrument: {
|
tradableInstrument: {
|
||||||
instrument: {
|
instrument: {
|
||||||
@ -36,6 +43,7 @@ describe('MarketSelectorItem', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const marketData: MarketDataUpdateFieldsFragment = {
|
const marketData: MarketDataUpdateFieldsFragment = {
|
||||||
__typename: 'ObservableMarketData',
|
__typename: 'ObservableMarketData',
|
||||||
marketId: market.id,
|
marketId: market.id,
|
||||||
@ -63,26 +71,32 @@ describe('MarketSelectorItem', () => {
|
|||||||
trigger: AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
|
trigger: AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
|
||||||
priceMonitoringBounds: null,
|
priceMonitoringBounds: null,
|
||||||
};
|
};
|
||||||
const mock: MockedResponse<MarketDataUpdateSubscription> = {
|
|
||||||
request: {
|
const candles = [
|
||||||
query: MarketDataUpdateDocument,
|
{
|
||||||
variables: {
|
open: '5',
|
||||||
marketId: market.id,
|
close: '5',
|
||||||
},
|
high: '5',
|
||||||
|
low: '5',
|
||||||
|
volume: '50',
|
||||||
|
periodStart: yesterday.toISOString(),
|
||||||
},
|
},
|
||||||
result: {
|
{
|
||||||
data: {
|
open: '10',
|
||||||
marketsData: [marketData],
|
close: '10',
|
||||||
},
|
high: '10',
|
||||||
|
low: '10',
|
||||||
|
volume: '50',
|
||||||
|
periodStart: yesterday.toISOString(),
|
||||||
},
|
},
|
||||||
};
|
];
|
||||||
|
|
||||||
const mockOnSelect = jest.fn();
|
const mockOnSelect = jest.fn();
|
||||||
|
|
||||||
const renderJsx = () => {
|
const renderJsx = (mocks: MockedResponse[]) => {
|
||||||
return render(
|
return render(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<MockedProvider mocks={[mock]}>
|
<MockedProvider mocks={mocks}>
|
||||||
<MarketSelectorItem
|
<MarketSelectorItem
|
||||||
market={market}
|
market={market}
|
||||||
currentMarketId={market.id}
|
currentMarketId={market.id}
|
||||||
@ -94,11 +108,66 @@ describe('MarketSelectorItem', () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let dateSpy: jest.SpyInstance;
|
||||||
|
const ts = 1685577600000; // 2023-06-01
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
dateSpy = jest.spyOn(Date, 'now').mockImplementation(() => ts);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
dateSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
it('renders market information', async () => {
|
it('renders market information', async () => {
|
||||||
const symbol =
|
const symbol =
|
||||||
market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
||||||
|
|
||||||
renderJsx();
|
const mock: MockedResponse<MarketDataUpdateSubscription> = {
|
||||||
|
request: {
|
||||||
|
query: MarketDataUpdateDocument,
|
||||||
|
variables: {
|
||||||
|
marketId: market.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
marketsData: [marketData],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const since = subDays(Date.now(), 5).toISOString();
|
||||||
|
const variables: MarketCandlesQueryVariables = {
|
||||||
|
marketId: market.id,
|
||||||
|
interval: Interval.INTERVAL_I1H,
|
||||||
|
since,
|
||||||
|
};
|
||||||
|
const mockCandles: MockedResponse<MarketCandlesQuery> = {
|
||||||
|
request: {
|
||||||
|
query: MarketCandlesDocument,
|
||||||
|
variables,
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
marketsConnection: {
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
candlesConnection: {
|
||||||
|
edges: candles.map((c) => ({
|
||||||
|
node: c,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
renderJsx([mock, mockCandles]);
|
||||||
|
|
||||||
const link = screen.getByRole('link');
|
const link = screen.getByRole('link');
|
||||||
// link renders and is styled
|
// link renders and is styled
|
||||||
@ -106,18 +175,17 @@ describe('MarketSelectorItem', () => {
|
|||||||
|
|
||||||
expect(link).toHaveClass('ring-1');
|
expect(link).toHaveClass('ring-1');
|
||||||
|
|
||||||
expect(screen.getByTitle('24h vol')).toHaveTextContent('100');
|
expect(screen.getByTitle('24h vol')).toHaveTextContent('0.00');
|
||||||
expect(screen.getByTitle(symbol)).toHaveTextContent('-');
|
expect(screen.getByTitle(symbol)).toHaveTextContent('-');
|
||||||
|
|
||||||
// candles are loaded immediately
|
|
||||||
expect(screen.getByTestId('market-item-change')).toHaveTextContent(
|
|
||||||
'+100.00%'
|
|
||||||
);
|
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTitle('24h vol')).toHaveTextContent('100');
|
||||||
expect(screen.getByTitle(symbol)).toHaveTextContent(
|
expect(screen.getByTitle(symbol)).toHaveTextContent(
|
||||||
addDecimalsFormatNumber(marketData.markPrice, market.decimalPlaces)
|
addDecimalsFormatNumber(marketData.markPrice, market.decimalPlaces)
|
||||||
);
|
);
|
||||||
|
expect(screen.getByTestId('market-item-change')).toHaveTextContent(
|
||||||
|
'+100.00%'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
await userEvent.click(link);
|
await userEvent.click(link);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { CSSProperties } from 'react';
|
import type { CSSProperties, ReactNode } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import {
|
import {
|
||||||
@ -8,6 +8,7 @@ import {
|
|||||||
} from '@vegaprotocol/utils';
|
} from '@vegaprotocol/utils';
|
||||||
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/markets';
|
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/markets';
|
||||||
import { calcCandleVolume } from '@vegaprotocol/markets';
|
import { calcCandleVolume } from '@vegaprotocol/markets';
|
||||||
|
import { useCandles } from '@vegaprotocol/markets';
|
||||||
import { useMarketDataUpdateSubscription } from '@vegaprotocol/markets';
|
import { useMarketDataUpdateSubscription } from '@vegaprotocol/markets';
|
||||||
import { Sparkline } from '@vegaprotocol/ui-toolkit';
|
import { Sparkline } from '@vegaprotocol/ui-toolkit';
|
||||||
import {
|
import {
|
||||||
@ -80,8 +81,9 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
|
|||||||
: '';
|
: '';
|
||||||
|
|
||||||
const instrument = market.tradableInstrument.instrument;
|
const instrument = market.tradableInstrument.instrument;
|
||||||
|
const { oneDayCandles } = useCandles({ marketId: market.id });
|
||||||
|
|
||||||
const vol = market.candles ? calcCandleVolume(market.candles) : '0';
|
const vol = oneDayCandles ? calcCandleVolume(oneDayCandles) : '0';
|
||||||
const volume =
|
const volume =
|
||||||
vol && vol !== '0'
|
vol && vol !== '0'
|
||||||
? addDecimalsFormatNumber(vol, market.positionDecimalPlaces)
|
? addDecimalsFormatNumber(vol, market.positionDecimalPlaces)
|
||||||
@ -111,20 +113,20 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
|
|||||||
value={price}
|
value={price}
|
||||||
label={instrument.product.settlementAsset.symbol}
|
label={instrument.product.settlementAsset.symbol}
|
||||||
/>
|
/>
|
||||||
<div className="relative">
|
<div className="relative text-xs p-1">
|
||||||
{market.candles && (
|
{oneDayCandles && (
|
||||||
<PriceChange candles={market.candles.map((c) => c.close)} />
|
<PriceChange candles={oneDayCandles.map((c) => c.close)} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
// absolute so height is not larger than price change value
|
// absolute so height is not larger than price change value
|
||||||
className="absolute right-0 bottom-0 w-[120px]"
|
className="absolute right-0 bottom-0 w-[120px]"
|
||||||
>
|
>
|
||||||
{market.candles && (
|
{oneDayCandles && (
|
||||||
<Sparkline
|
<Sparkline
|
||||||
width={120}
|
width={120}
|
||||||
height={20}
|
height={20}
|
||||||
data={market.candles.filter(Boolean).map((c) => Number(c.close))}
|
data={oneDayCandles.map((c) => Number(c.close))}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -133,7 +135,13 @@ const MarketData = ({ market }: { market: MarketMaybeWithDataAndCandles }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const DataRow = ({ value, label }: { value: string; label: string }) => {
|
const DataRow = ({
|
||||||
|
value,
|
||||||
|
label,
|
||||||
|
}: {
|
||||||
|
value: string | ReactNode;
|
||||||
|
label: string;
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="text-ellipsis whitespace-nowrap overflow-hidden leading-tight"
|
className="text-ellipsis whitespace-nowrap overflow-hidden leading-tight"
|
||||||
|
@ -53,7 +53,7 @@ export const useMarketSelectorList = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (sort === Sort.None) {
|
if (sort === Sort.None) {
|
||||||
// Sort by market state primarilly and AtoZ secondarilly
|
// Sort by market state primarily and AtoZ secondarily
|
||||||
return orderBy(
|
return orderBy(
|
||||||
markets,
|
markets,
|
||||||
[
|
[
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
import type { RefObject } from 'react';
|
|
||||||
import { useInView } from 'react-intersection-observer';
|
|
||||||
import { isNumeric } from '@vegaprotocol/utils';
|
import { isNumeric } from '@vegaprotocol/utils';
|
||||||
import { useFiveDaysAgo, useYesterday } from '@vegaprotocol/react-helpers';
|
|
||||||
import { useThrottledDataProvider } from '@vegaprotocol/data-provider';
|
|
||||||
import { PriceChangeCell } from '@vegaprotocol/datagrid';
|
import { PriceChangeCell } from '@vegaprotocol/datagrid';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
|
||||||
import type { CandleClose } from '@vegaprotocol/types';
|
|
||||||
import { marketCandlesProvider } from '../../market-candles-provider';
|
|
||||||
import type { MarketCandlesFieldsFragment } from '../../__generated__/market-candles';
|
|
||||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { useCandles } from '../../hooks/use-candles';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
marketId?: string;
|
marketId?: string;
|
||||||
@ -17,38 +10,16 @@ interface Props {
|
|||||||
initialValue?: string[];
|
initialValue?: string[];
|
||||||
isHeader?: boolean;
|
isHeader?: boolean;
|
||||||
noUpdate?: boolean;
|
noUpdate?: boolean;
|
||||||
inViewRoot?: RefObject<Element>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Last24hPriceChange = ({
|
export const Last24hPriceChange = ({
|
||||||
marketId,
|
marketId,
|
||||||
decimalPlaces,
|
decimalPlaces,
|
||||||
initialValue,
|
initialValue,
|
||||||
inViewRoot,
|
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
const { oneDayCandles, error, fiveDaysCandles } = useCandles({
|
||||||
const fiveDaysAgo = useFiveDaysAgo();
|
marketId,
|
||||||
const yesterday = useYesterday();
|
|
||||||
const { data, error } = useThrottledDataProvider({
|
|
||||||
dataProvider: marketCandlesProvider,
|
|
||||||
variables: {
|
|
||||||
marketId: marketId || '',
|
|
||||||
interval: Schema.Interval.INTERVAL_I1H,
|
|
||||||
since: new Date(fiveDaysAgo).toISOString(),
|
|
||||||
},
|
|
||||||
skip: !marketId || !inView,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const fiveDaysCandles = data?.filter((candle) => Boolean(candle));
|
|
||||||
|
|
||||||
const candles = fiveDaysCandles?.filter((candle) =>
|
|
||||||
isCandleLessThan24hOld(candle, yesterday)
|
|
||||||
);
|
|
||||||
const oneDayCandles =
|
|
||||||
candles
|
|
||||||
?.map((candle) => candle?.close)
|
|
||||||
.filter((c): c is CandleClose => c !== null) || initialValue;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
fiveDaysCandles &&
|
fiveDaysCandles &&
|
||||||
fiveDaysCandles.length > 0 &&
|
fiveDaysCandles.length > 0 &&
|
||||||
@ -68,30 +39,18 @@ export const Last24hPriceChange = ({
|
|||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span ref={ref}>{t('Unknown')} </span>
|
<span>-</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error || !isNumeric(decimalPlaces)) {
|
if (error || !isNumeric(decimalPlaces)) {
|
||||||
return <span ref={ref}>-</span>;
|
return <span>-</span>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<PriceChangeCell
|
<PriceChangeCell
|
||||||
candles={oneDayCandles || []}
|
candles={oneDayCandles?.map((c) => c.close) || initialValue || []}
|
||||||
decimalPlaces={decimalPlaces}
|
decimalPlaces={decimalPlaces}
|
||||||
ref={ref}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isCandleLessThan24hOld = (
|
|
||||||
candle: MarketCandlesFieldsFragment | undefined,
|
|
||||||
yesterday: number
|
|
||||||
) => {
|
|
||||||
if (!candle?.open) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const candleDate = new Date(candle.close);
|
|
||||||
return candleDate > new Date(yesterday);
|
|
||||||
};
|
|
||||||
|
@ -1,20 +1,13 @@
|
|||||||
import type { RefObject } from 'react';
|
|
||||||
import { useInView } from 'react-intersection-observer';
|
|
||||||
import { marketCandlesProvider } from '../../market-candles-provider';
|
|
||||||
import { calcCandleVolume } from '../../market-utils';
|
import { calcCandleVolume } from '../../market-utils';
|
||||||
import { addDecimalsFormatNumber, isNumeric } from '@vegaprotocol/utils';
|
import { addDecimalsFormatNumber, isNumeric } from '@vegaprotocol/utils';
|
||||||
import { useFiveDaysAgo, useYesterday } from '@vegaprotocol/react-helpers';
|
|
||||||
import { useThrottledDataProvider } from '@vegaprotocol/data-provider';
|
|
||||||
import * as Schema from '@vegaprotocol/types';
|
|
||||||
import { isCandleLessThan24hOld } from '../last-24h-price-change';
|
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useCandles } from '../../hooks';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
marketId?: string;
|
marketId?: string;
|
||||||
positionDecimalPlaces?: number;
|
positionDecimalPlaces?: number;
|
||||||
formatDecimals?: number;
|
formatDecimals?: number;
|
||||||
inViewRoot?: RefObject<Element>;
|
|
||||||
initialValue?: string;
|
initialValue?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,29 +15,12 @@ export const Last24hVolume = ({
|
|||||||
marketId,
|
marketId,
|
||||||
positionDecimalPlaces,
|
positionDecimalPlaces,
|
||||||
formatDecimals,
|
formatDecimals,
|
||||||
inViewRoot,
|
|
||||||
initialValue,
|
initialValue,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const yesterday = useYesterday();
|
const { oneDayCandles, fiveDaysCandles } = useCandles({
|
||||||
const fiveDaysAgo = useFiveDaysAgo();
|
marketId,
|
||||||
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
|
||||||
|
|
||||||
const { data } = useThrottledDataProvider({
|
|
||||||
dataProvider: marketCandlesProvider,
|
|
||||||
variables: {
|
|
||||||
marketId: marketId || '',
|
|
||||||
interval: Schema.Interval.INTERVAL_I1H,
|
|
||||||
since: new Date(fiveDaysAgo).toISOString(),
|
|
||||||
},
|
|
||||||
skip: !(inView && marketId),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const fiveDaysCandles = data?.filter((candle) => Boolean(candle));
|
|
||||||
|
|
||||||
const oneDayCandles = fiveDaysCandles?.filter((candle) =>
|
|
||||||
isCandleLessThan24hOld(candle, yesterday)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
fiveDaysCandles &&
|
fiveDaysCandles &&
|
||||||
fiveDaysCandles.length > 0 &&
|
fiveDaysCandles.length > 0 &&
|
||||||
@ -72,20 +48,21 @@ export const Last24hVolume = ({
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span ref={ref}>{t('Unknown')} </span>
|
<span>-</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const candleVolume = oneDayCandles
|
const candleVolume = oneDayCandles
|
||||||
? calcCandleVolume(oneDayCandles)
|
? calcCandleVolume(oneDayCandles)
|
||||||
: initialValue;
|
: initialValue;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
description={t(
|
description={t(
|
||||||
'The total number of contracts traded in the last 24 hours.'
|
'The total number of contracts traded in the last 24 hours.'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span ref={ref}>
|
<span>
|
||||||
{candleVolume && isNumeric(positionDecimalPlaces)
|
{candleVolume && isNumeric(positionDecimalPlaces)
|
||||||
? addDecimalsFormatNumber(
|
? addDecimalsFormatNumber(
|
||||||
candleVolume,
|
candleVolume,
|
||||||
|
@ -2,3 +2,4 @@ export * from './use-market-oracle';
|
|||||||
export * from './use-oracle-markets';
|
export * from './use-oracle-markets';
|
||||||
export * from './use-oracle-proofs';
|
export * from './use-oracle-proofs';
|
||||||
export * from './use-oracle-spec-binding-data';
|
export * from './use-oracle-spec-binding-data';
|
||||||
|
export * from './use-candles';
|
||||||
|
105
libs/markets/src/lib/hooks/use-candles.spec.ts
Normal file
105
libs/markets/src/lib/hooks/use-candles.spec.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { renderHook } from '@testing-library/react';
|
||||||
|
import { useCandles } from './use-candles';
|
||||||
|
|
||||||
|
const today = new Date();
|
||||||
|
const fiveDaysAgo = new Date();
|
||||||
|
fiveDaysAgo.setDate(today.getDate() - 5);
|
||||||
|
|
||||||
|
const mockData = [
|
||||||
|
{
|
||||||
|
high: '6293819',
|
||||||
|
low: '6263737',
|
||||||
|
open: '6266893',
|
||||||
|
close: '6293819',
|
||||||
|
volume: '72447',
|
||||||
|
periodStart: today.toISOString(),
|
||||||
|
__typename: 'Candle',
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
high: '6309988',
|
||||||
|
low: '6296335',
|
||||||
|
open: '6307451',
|
||||||
|
close: '6296335',
|
||||||
|
volume: '73657',
|
||||||
|
periodStart: today.toISOString(),
|
||||||
|
__typename: 'Candle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
high: '6315153',
|
||||||
|
low: '6294001',
|
||||||
|
open: '6296335',
|
||||||
|
close: '6315152',
|
||||||
|
volume: '89395',
|
||||||
|
periodStart: today.toISOString(),
|
||||||
|
__typename: 'Candle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
high: '6309988',
|
||||||
|
low: '6296335',
|
||||||
|
open: '6307451',
|
||||||
|
close: '6296335',
|
||||||
|
volume: '73657',
|
||||||
|
periodStart: fiveDaysAgo.toISOString(),
|
||||||
|
__typename: 'Candle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
high: '6315153',
|
||||||
|
low: '6294001',
|
||||||
|
open: '6296335',
|
||||||
|
close: '6315152',
|
||||||
|
volume: '89395',
|
||||||
|
periodStart: fiveDaysAgo.toISOString(),
|
||||||
|
__typename: 'Candle',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
jest.mock('@vegaprotocol/data-provider', () => {
|
||||||
|
return {
|
||||||
|
...jest.requireActual('@vegaprotocol/data-provider'),
|
||||||
|
useThrottledDataProvider: jest.fn(() => ({
|
||||||
|
data: mockData,
|
||||||
|
error: false,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('useCandles', () => {
|
||||||
|
it('should return one day candles and five day candles', () => {
|
||||||
|
const { result } = renderHook(() => useCandles({ marketId: '3456789' }));
|
||||||
|
const expectedOneDayCandles = [
|
||||||
|
{
|
||||||
|
high: '6293819',
|
||||||
|
low: '6263737',
|
||||||
|
open: '6266893',
|
||||||
|
close: '6293819',
|
||||||
|
volume: '72447',
|
||||||
|
periodStart: today.toISOString(),
|
||||||
|
__typename: 'Candle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
high: '6309988',
|
||||||
|
low: '6296335',
|
||||||
|
open: '6307451',
|
||||||
|
close: '6296335',
|
||||||
|
volume: '73657',
|
||||||
|
periodStart: today.toISOString(),
|
||||||
|
__typename: 'Candle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
high: '6315153',
|
||||||
|
low: '6294001',
|
||||||
|
open: '6296335',
|
||||||
|
close: '6315152',
|
||||||
|
volume: '89395',
|
||||||
|
periodStart: today.toISOString(),
|
||||||
|
__typename: 'Candle',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
expect(result.current).toStrictEqual({
|
||||||
|
oneDayCandles: expectedOneDayCandles,
|
||||||
|
fiveDaysCandles: mockData.filter(Boolean),
|
||||||
|
error: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
37
libs/markets/src/lib/hooks/use-candles.ts
Normal file
37
libs/markets/src/lib/hooks/use-candles.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { useThrottledDataProvider } from '@vegaprotocol/data-provider';
|
||||||
|
import { useFiveDaysAgo, useYesterday } from '@vegaprotocol/react-helpers';
|
||||||
|
import type { MarketCandlesFieldsFragment } from '../__generated__';
|
||||||
|
import { marketCandlesProvider } from '../market-candles-provider';
|
||||||
|
import { Interval } from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
export const useCandles = ({ marketId }: { marketId?: string }) => {
|
||||||
|
const fiveDaysAgo = useFiveDaysAgo();
|
||||||
|
const yesterday = useYesterday();
|
||||||
|
const { data, error } = useThrottledDataProvider({
|
||||||
|
dataProvider: marketCandlesProvider,
|
||||||
|
variables: {
|
||||||
|
marketId: marketId || '',
|
||||||
|
interval: Interval.INTERVAL_I1H,
|
||||||
|
since: new Date(fiveDaysAgo).toISOString(),
|
||||||
|
},
|
||||||
|
skip: !marketId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fiveDaysCandles = data?.filter(Boolean);
|
||||||
|
|
||||||
|
const oneDayCandles = fiveDaysCandles?.filter((candle) =>
|
||||||
|
isCandleLessThan24hOld(candle, yesterday)
|
||||||
|
);
|
||||||
|
return { oneDayCandles, error, fiveDaysCandles };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isCandleLessThan24hOld = (
|
||||||
|
candle: MarketCandlesFieldsFragment | undefined,
|
||||||
|
yesterday: number
|
||||||
|
) => {
|
||||||
|
if (!candle?.periodStart) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const candleDate = new Date(candle.periodStart);
|
||||||
|
return candleDate > new Date(yesterday);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user