feat(trading): show total value of the valume traded in last 24hrs
This commit is contained in:
parent
3a8b40d7a5
commit
df3119555f
@ -19,6 +19,7 @@ import {
|
|||||||
useFundingRate,
|
useFundingRate,
|
||||||
useMarketTradingMode,
|
useMarketTradingMode,
|
||||||
useExternalTwap,
|
useExternalTwap,
|
||||||
|
getQuoteName,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import { MarketState as State } from '@vegaprotocol/types';
|
import { MarketState as State } from '@vegaprotocol/types';
|
||||||
import { HeaderStat } from '../../components/header';
|
import { HeaderStat } from '../../components/header';
|
||||||
@ -41,6 +42,7 @@ export const MarketHeaderStats = ({ market }: MarketHeaderStatsProps) => {
|
|||||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||||
|
|
||||||
const asset = getAsset(market);
|
const asset = getAsset(market);
|
||||||
|
const quoteUnit = getQuoteName(market);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -60,6 +62,8 @@ export const MarketHeaderStats = ({ market }: MarketHeaderStatsProps) => {
|
|||||||
<Last24hVolume
|
<Last24hVolume
|
||||||
marketId={market.id}
|
marketId={market.id}
|
||||||
positionDecimalPlaces={market.positionDecimalPlaces}
|
positionDecimalPlaces={market.positionDecimalPlaces}
|
||||||
|
marketDecimals={market.decimalPlaces}
|
||||||
|
quoteUnit={quoteUnit}
|
||||||
/>
|
/>
|
||||||
</HeaderStat>
|
</HeaderStat>
|
||||||
<HeaderStatMarketTradingMode
|
<HeaderStatMarketTradingMode
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
useDataGridEvents,
|
useDataGridEvents,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import type { MarketMaybeWithData } from '@vegaprotocol/markets';
|
import type { MarketMaybeWithData } from '@vegaprotocol/markets';
|
||||||
import { useColumnDefs } from './use-column-defs';
|
import { useMarketsColumnDefs } from './use-column-defs';
|
||||||
import type { DataGridStore } from '../../stores/datagrid-store-slice';
|
import type { DataGridStore } from '../../stores/datagrid-store-slice';
|
||||||
import { type StateCreator, create } from 'zustand';
|
import { type StateCreator, create } from 'zustand';
|
||||||
import { persist } from 'zustand/middleware';
|
import { persist } from 'zustand/middleware';
|
||||||
@ -50,7 +50,7 @@ export const useMarketsStore = create<DataGridSlice>()(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const MarketListTable = (props: Props) => {
|
export const MarketListTable = (props: Props) => {
|
||||||
const columnDefs = useColumnDefs();
|
const columnDefs = useMarketsColumnDefs();
|
||||||
const gridStore = useMarketsStore((store) => store.gridStore);
|
const gridStore = useMarketsStore((store) => store.gridStore);
|
||||||
const updateGridStore = useMarketsStore((store) => store.updateGridStore);
|
const updateGridStore = useMarketsStore((store) => store.updateGridStore);
|
||||||
|
|
||||||
|
@ -7,21 +7,31 @@ import type {
|
|||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import { COL_DEFS, SetFilter } from '@vegaprotocol/datagrid';
|
import { COL_DEFS, SetFilter } from '@vegaprotocol/datagrid';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import { addDecimalsFormatNumber, toBigNum } from '@vegaprotocol/utils';
|
import {
|
||||||
|
addDecimalsFormatNumber,
|
||||||
|
formatNumber,
|
||||||
|
toBigNum,
|
||||||
|
} from '@vegaprotocol/utils';
|
||||||
import { ButtonLink, Tooltip } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink, Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
import type {
|
import type {
|
||||||
|
MarketFieldsFragment,
|
||||||
MarketMaybeWithData,
|
MarketMaybeWithData,
|
||||||
MarketMaybeWithDataAndCandles,
|
MarketMaybeWithDataAndCandles,
|
||||||
} from '@vegaprotocol/markets';
|
} from '@vegaprotocol/markets';
|
||||||
import { MarketActionsDropdown } from './market-table-actions';
|
import { MarketActionsDropdown } from './market-table-actions';
|
||||||
import { calcCandleVolume, getAsset } from '@vegaprotocol/markets';
|
import {
|
||||||
|
calcCandleVolume,
|
||||||
|
calcCandleVolumePrice,
|
||||||
|
getAsset,
|
||||||
|
getQuoteName,
|
||||||
|
} from '@vegaprotocol/markets';
|
||||||
import { MarketCodeCell } from './market-code-cell';
|
import { MarketCodeCell } from './market-code-cell';
|
||||||
import { useT } from '../../lib/use-t';
|
import { useT } from '../../lib/use-t';
|
||||||
|
|
||||||
const { MarketTradingMode, AuctionTrigger } = Schema;
|
const { MarketTradingMode, AuctionTrigger } = Schema;
|
||||||
|
|
||||||
export const useColumnDefs = () => {
|
export const useMarketsColumnDefs = () => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||||
return useMemo<ColDef[]>(
|
return useMemo<ColDef[]>(
|
||||||
@ -158,11 +168,25 @@ export const useColumnDefs = () => {
|
|||||||
}: ValueFormatterParams<MarketMaybeWithDataAndCandles, 'candles'>) => {
|
}: ValueFormatterParams<MarketMaybeWithDataAndCandles, 'candles'>) => {
|
||||||
const candles = data?.candles;
|
const candles = data?.candles;
|
||||||
const vol = candles ? calcCandleVolume(candles) : '0';
|
const vol = candles ? calcCandleVolume(candles) : '0';
|
||||||
|
const quoteName = getQuoteName(data as MarketFieldsFragment);
|
||||||
|
const volPrice =
|
||||||
|
candles &&
|
||||||
|
calcCandleVolumePrice(
|
||||||
|
candles,
|
||||||
|
data.decimalPlaces,
|
||||||
|
data.positionDecimalPlaces
|
||||||
|
);
|
||||||
|
|
||||||
const volume =
|
const volume =
|
||||||
data && vol && vol !== '0'
|
data && vol && vol !== '0'
|
||||||
? addDecimalsFormatNumber(vol, data.positionDecimalPlaces)
|
? addDecimalsFormatNumber(vol, data.positionDecimalPlaces)
|
||||||
: '0.00';
|
: '0.00';
|
||||||
return volume;
|
const volumePrice =
|
||||||
|
volPrice && formatNumber(volPrice, data?.decimalPlaces);
|
||||||
|
|
||||||
|
return volumePrice
|
||||||
|
? `${volume} (${volumePrice} ${quoteName})`
|
||||||
|
: volume;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import { calcCandleVolume } from '../../market-utils';
|
import { calcCandleVolume, calcCandleVolumePrice } from '../../market-utils';
|
||||||
import { addDecimalsFormatNumber, isNumeric } from '@vegaprotocol/utils';
|
import {
|
||||||
|
addDecimalsFormatNumber,
|
||||||
|
formatNumber,
|
||||||
|
isNumeric,
|
||||||
|
} from '@vegaprotocol/utils';
|
||||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||||
import { useCandles } from '../../hooks';
|
import { useCandles } from '../../hooks';
|
||||||
import { useT } from '../../use-t';
|
import { useT } from '../../use-t';
|
||||||
@ -9,13 +13,17 @@ interface Props {
|
|||||||
positionDecimalPlaces?: number;
|
positionDecimalPlaces?: number;
|
||||||
formatDecimals?: number;
|
formatDecimals?: number;
|
||||||
initialValue?: string;
|
initialValue?: string;
|
||||||
|
marketDecimals?: number;
|
||||||
|
quoteUnit?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Last24hVolume = ({
|
export const Last24hVolume = ({
|
||||||
marketId,
|
marketId,
|
||||||
|
marketDecimals,
|
||||||
positionDecimalPlaces,
|
positionDecimalPlaces,
|
||||||
formatDecimals,
|
formatDecimals,
|
||||||
initialValue,
|
initialValue,
|
||||||
|
quoteUnit,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const { oneDayCandles, fiveDaysCandles } = useCandles({
|
const { oneDayCandles, fiveDaysCandles } = useCandles({
|
||||||
@ -28,6 +36,11 @@ export const Last24hVolume = ({
|
|||||||
(!oneDayCandles || oneDayCandles?.length === 0)
|
(!oneDayCandles || oneDayCandles?.length === 0)
|
||||||
) {
|
) {
|
||||||
const candleVolume = calcCandleVolume(fiveDaysCandles);
|
const candleVolume = calcCandleVolume(fiveDaysCandles);
|
||||||
|
const candleVolumePrice = calcCandleVolumePrice(
|
||||||
|
fiveDaysCandles,
|
||||||
|
marketDecimals,
|
||||||
|
positionDecimalPlaces
|
||||||
|
);
|
||||||
const candleVolumeValue =
|
const candleVolumeValue =
|
||||||
candleVolume && isNumeric(positionDecimalPlaces)
|
candleVolume && isNumeric(positionDecimalPlaces)
|
||||||
? addDecimalsFormatNumber(
|
? addDecimalsFormatNumber(
|
||||||
@ -42,8 +55,8 @@ export const Last24hVolume = ({
|
|||||||
<div>
|
<div>
|
||||||
<span className="flex flex-col">
|
<span className="flex flex-col">
|
||||||
{t(
|
{t(
|
||||||
'24 hour change is unavailable at this time. The volume change in the last 120 hours is {{candleVolumeValue}}',
|
'24 hour change is unavailable at this time. The volume change in the last 120 hours is {{candleVolumeValue}} ({{candleVolumePrice}} {{quoteUnit}})',
|
||||||
{ candleVolumeValue }
|
{ candleVolumeValue, candleVolumePrice, quoteUnit }
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -57,10 +70,18 @@ export const Last24hVolume = ({
|
|||||||
? calcCandleVolume(oneDayCandles)
|
? calcCandleVolume(oneDayCandles)
|
||||||
: initialValue;
|
: initialValue;
|
||||||
|
|
||||||
|
const candleVolumePrice = oneDayCandles
|
||||||
|
? calcCandleVolumePrice(
|
||||||
|
oneDayCandles,
|
||||||
|
marketDecimals,
|
||||||
|
positionDecimalPlaces
|
||||||
|
)
|
||||||
|
: 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. (Total value of contracts traded in the last 24 hours)'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
@ -70,7 +91,12 @@ export const Last24hVolume = ({
|
|||||||
positionDecimalPlaces,
|
positionDecimalPlaces,
|
||||||
formatDecimals
|
formatDecimals
|
||||||
)
|
)
|
||||||
: '-'}
|
: '-'}{' '}
|
||||||
|
(
|
||||||
|
{candleVolumePrice && isNumeric(positionDecimalPlaces)
|
||||||
|
? formatNumber(candleVolumePrice, formatDecimals)
|
||||||
|
: '-'}{' '}
|
||||||
|
{quoteUnit})
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
@ -155,6 +155,7 @@ export const MarketVolumeInfoPanel = ({ market }: MarketInfoProps) => {
|
|||||||
<Last24hVolume
|
<Last24hVolume
|
||||||
marketId={market.id}
|
marketId={market.id}
|
||||||
positionDecimalPlaces={market.positionDecimalPlaces}
|
positionDecimalPlaces={market.positionDecimalPlaces}
|
||||||
|
marketDecimals={market.decimalPlaces}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
openInterest: dash(data?.openInterest),
|
openInterest: dash(data?.openInterest),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import type { Market, MarketMaybeWithDataAndCandles } from './markets-provider';
|
import type { Market, MarketMaybeWithDataAndCandles } from './markets-provider';
|
||||||
import {
|
import {
|
||||||
|
calcCandleVolumePrice,
|
||||||
calcTradedFactor,
|
calcTradedFactor,
|
||||||
filterAndSortMarkets,
|
filterAndSortMarkets,
|
||||||
sumFeesFactors,
|
sumFeesFactors,
|
||||||
@ -145,3 +146,31 @@ describe('sumFeesFactors', () => {
|
|||||||
).toEqual(0.6);
|
).toEqual(0.6);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('calcCandleVolumePrice', () => {
|
||||||
|
it('calculates the volume price', () => {
|
||||||
|
const candles = [
|
||||||
|
{
|
||||||
|
volume: '1000',
|
||||||
|
high: '100',
|
||||||
|
low: '10',
|
||||||
|
open: '15',
|
||||||
|
close: '90',
|
||||||
|
periodStart: '2022-05-18T13:08:27.693537312Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
volume: '1000',
|
||||||
|
high: '100',
|
||||||
|
low: '10',
|
||||||
|
open: '15',
|
||||||
|
close: '90',
|
||||||
|
periodStart: '2022-05-18T14:08:27.693537312Z',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const marketDecimals = 3;
|
||||||
|
const positionDecimalPlaces = 2;
|
||||||
|
expect(
|
||||||
|
calcCandleVolumePrice(candles, marketDecimals, positionDecimalPlaces)
|
||||||
|
).toEqual('2');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
import { formatNumberPercentage, toBigNum } from '@vegaprotocol/utils';
|
import {
|
||||||
|
addDecimal,
|
||||||
|
formatNumberPercentage,
|
||||||
|
toBigNum,
|
||||||
|
} from '@vegaprotocol/utils';
|
||||||
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
|
import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import orderBy from 'lodash/orderBy';
|
import orderBy from 'lodash/orderBy';
|
||||||
@ -147,10 +151,51 @@ export const calcCandleHigh = (candles: Candle[]): string | undefined => {
|
|||||||
.toString();
|
.toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The total number of contracts traded in the last 24 hours.
|
||||||
|
*
|
||||||
|
* @param candles
|
||||||
|
* @returns the volume of a given set of candles
|
||||||
|
*/
|
||||||
export const calcCandleVolume = (candles: Candle[]): string | undefined =>
|
export const calcCandleVolume = (candles: Candle[]): string | undefined =>
|
||||||
candles &&
|
candles &&
|
||||||
candles.reduce((acc, c) => new BigNumber(acc).plus(c.volume).toString(), '0');
|
candles.reduce((acc, c) => new BigNumber(acc).plus(c.volume).toString(), '0');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The total number of contracts traded in the last 24 hours. (Total value of contracts traded in the last 24 hours)
|
||||||
|
* The volume is calculated as the sum of the product of the volume and the high price of each candle.
|
||||||
|
* The result is formatted using positionDecimalPlaces to account for the position size.
|
||||||
|
* The result is formatted using marketDecimals to account for the market precision.
|
||||||
|
*
|
||||||
|
* @param candles
|
||||||
|
* @param marketDecimals
|
||||||
|
* @param positionDecimalPlaces
|
||||||
|
* @returns the volume (in quote price) of a given set of candles
|
||||||
|
*/
|
||||||
|
export const calcCandleVolumePrice = (
|
||||||
|
candles: Candle[],
|
||||||
|
marketDecimals: number = 1,
|
||||||
|
positionDecimalPlaces: number = 1
|
||||||
|
): string | undefined =>
|
||||||
|
candles &&
|
||||||
|
candles.reduce(
|
||||||
|
(acc, c) =>
|
||||||
|
new BigNumber(acc)
|
||||||
|
.plus(
|
||||||
|
BigNumber(addDecimal(c.volume, positionDecimalPlaces)).times(
|
||||||
|
addDecimal(c.high, marketDecimals)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.toString(),
|
||||||
|
'0'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the traded factor of a given market.
|
||||||
|
*
|
||||||
|
* @param m
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export const calcTradedFactor = (m: MarketMaybeWithDataAndCandles) => {
|
export const calcTradedFactor = (m: MarketMaybeWithDataAndCandles) => {
|
||||||
const volume = Number(calcCandleVolume(m.candles || []) || 0);
|
const volume = Number(calcCandleVolume(m.candles || []) || 0);
|
||||||
const price = m.data?.markPrice ? Number(m.data.markPrice) : 0;
|
const price = m.data?.markPrice ? Number(m.data.markPrice) : 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user