diff --git a/apps/trading-e2e/src/integration/market-summary.cy.ts b/apps/trading-e2e/src/integration/market-summary.cy.ts index 84c2cf570..bce5267f8 100644 --- a/apps/trading-e2e/src/integration/market-summary.cy.ts +++ b/apps/trading-e2e/src/integration/market-summary.cy.ts @@ -67,7 +67,7 @@ describe('Market trading page', () => { it('must see market volume', () => { cy.getByTestId(marketSummaryBlock).within(() => { cy.getByTestId(marketVolume).within(() => { - cy.getByTestId(itemHeader).should('have.text', 'Volume'); + cy.getByTestId(itemHeader).should('have.text', 'Volume (24h)'); cy.getByTestId(itemValue).should('not.be.empty'); }); }); diff --git a/apps/trading/components/last-24h-volume/index.ts b/apps/trading/components/last-24h-volume/index.ts new file mode 100644 index 000000000..14d12f818 --- /dev/null +++ b/apps/trading/components/last-24h-volume/index.ts @@ -0,0 +1 @@ +export * from './last-24h-volume'; diff --git a/apps/trading/components/last-24h-volume/last-24h-volume.tsx b/apps/trading/components/last-24h-volume/last-24h-volume.tsx new file mode 100644 index 000000000..70be5872a --- /dev/null +++ b/apps/trading/components/last-24h-volume/last-24h-volume.tsx @@ -0,0 +1,90 @@ +import { + calcCandleVolume, + marketCandlesProvider, + marketProvider, +} from '@vegaprotocol/market-list'; +import { + addDecimalsFormatNumber, + t, + useDataProvider, + useYesterday, +} from '@vegaprotocol/react-helpers'; +import { Interval } from '@vegaprotocol/types'; +import throttle from 'lodash/throttle'; +import { useCallback, useMemo, useRef, useState } from 'react'; + +import * as constants from '../constants'; +import { HeaderStat } from '../header'; + +import type { + SingleMarketFieldsFragment, + Candle, +} from '@vegaprotocol/market-list'; +export const Last24hVolume = ({ marketId }: { marketId: string }) => { + const [candleVolume, setCandleVolume] = useState(); + const yesterday = useYesterday(); + // Cache timestamp for yesterday to prevent full unmount of market page when + // a rerender occurs + const yTimestamp = useMemo(() => { + return new Date(yesterday).toISOString(); + }, [yesterday]); + + const marketVariables = useMemo( + () => ({ + marketId: marketId, + }), + [marketId] + ); + + const variables = useMemo( + () => ({ + marketId: marketId, + interval: Interval.INTERVAL_I1H, + since: yTimestamp, + }), + [marketId, yTimestamp] + ); + + const { data, error } = useDataProvider({ + dataProvider: marketProvider, + variables: marketVariables, + skip: !marketId, + }); + + const throttledSetCandles = useRef( + throttle((data: Candle[]) => { + setCandleVolume(calcCandleVolume(data)); + }, constants.DEBOUNCE_UPDATE_TIME) + ).current; + const update = useCallback( + ({ data }: { data: Candle[] }) => { + throttledSetCandles(data); + return true; + }, + [throttledSetCandles] + ); + + useDataProvider({ + dataProvider: marketCandlesProvider, + update, + variables, + skip: !marketId || !data, + updateOnInit: true, + }); + + return ( + + {!error && candleVolume && data?.positionDecimalPlaces + ? addDecimalsFormatNumber(candleVolume, data.positionDecimalPlaces) + : '-'} + + ); +}; diff --git a/apps/trading/components/select-market/select-market-columns.tsx b/apps/trading/components/select-market/select-market-columns.tsx index 8c42dec1b..bbe5fc010 100644 --- a/apps/trading/components/select-market/select-market-columns.tsx +++ b/apps/trading/components/select-market/select-market-columns.tsx @@ -1,4 +1,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import { FeesCell } from '@vegaprotocol/market-info'; +import { + calcCandleHigh, + calcCandleLow, + calcCandleVolume, +} from '@vegaprotocol/market-list'; import { addDecimalsFormatNumber, PriceCell, @@ -12,16 +18,14 @@ import { MarketTradingModeMapping, } from '@vegaprotocol/types'; import { PriceCellChange, Sparkline, Tooltip } from '@vegaprotocol/ui-toolkit'; +import isNil from 'lodash/isNil'; import Link from 'next/link'; -import { calcCandleHigh, calcCandleLow } from '@vegaprotocol/market-list'; + import type { CandleClose } from '@vegaprotocol/types'; import type { MarketWithData, MarketWithCandles, } from '@vegaprotocol/market-list'; -import isNil from 'lodash/isNil'; -import { FeesCell } from '@vegaprotocol/market-info'; - type Market = MarketWithData & MarketWithCandles; export const cellClassNames = 'py-1 first:text-left text-right'; @@ -103,28 +107,28 @@ const headers: Column[] = [ }, { kind: ColumnKind.High24, - value: t('24h high'), + value: t('24h High'), className: `${cellClassNames} hidden xl:table-cell`, onlyOnDetailed: true, }, { kind: ColumnKind.Low24, - value: t('24h low'), + value: t('24h Low'), className: `${cellClassNames} hidden xl:table-cell`, onlyOnDetailed: true, }, + { + kind: ColumnKind.Volume, + value: t('24h Volume'), + className: `${cellClassNames} hidden lg:table-cell`, + onlyOnDetailed: true, + }, { kind: ColumnKind.TradingMode, value: t('Trading mode'), className: `${cellClassNames} hidden lg:table-cell`, onlyOnDetailed: true, }, - { - kind: ColumnKind.Volume, - value: t('Volume'), - className: `${cellClassNames} hidden lg:table-cell`, - onlyOnDetailed: true, - }, { kind: ColumnKind.Fee, value: , @@ -169,6 +173,7 @@ export const columns = ( .filter((c: string | undefined): c is CandleClose => !isNil(c)); const candleLow = market.candles && calcCandleLow(market.candles); const candleHigh = market.candles && calcCandleHigh(market.candles); + const candleVolume = market.candles && calcCandleVolume(market.candles); const selectMarketColumns: Column[] = [ { kind: ColumnKind.Market, @@ -273,6 +278,19 @@ export const columns = ( className: `${cellClassNames} hidden xl:table-cell font-mono`, onlyOnDetailed: true, }, + { + kind: ColumnKind.Volume, + value: candleVolume + ? addDecimalsFormatNumber( + candleVolume.toString(), + market.positionDecimalPlaces, + 2 + ) + : '-', + className: `${cellClassNames} hidden lg:table-cell font-mono`, + onlyOnDetailed: true, + dataTestId: 'market-volume', + }, { kind: ColumnKind.TradingMode, value: @@ -287,19 +305,6 @@ export const columns = ( onlyOnDetailed: true, dataTestId: 'trading-mode-col', }, - { - kind: ColumnKind.Volume, - value: - market.data?.indicativeVolume && market.data.indicativeVolume !== '0' - ? addDecimalsFormatNumber( - market.data.indicativeVolume, - market.positionDecimalPlaces - ) - : '-', - className: `${cellClassNames} hidden lg:table-cell font-mono`, - onlyOnDetailed: true, - dataTestId: 'market-volume', - }, { kind: ColumnKind.Fee, value: , @@ -337,6 +342,7 @@ export const columnsPositionMarkets = ( return onSelect(id); } }; + const candleVolume = market.candles && calcCandleVolume(market.candles); const selectMarketColumns: Column[] = [ { kind: ColumnKind.Market, @@ -454,6 +460,19 @@ export const columnsPositionMarkets = ( className: `${cellClassNames} hidden xl:table-cell font-mono`, onlyOnDetailed: true, }, + { + kind: ColumnKind.Volume, + value: candleVolume + ? addDecimalsFormatNumber( + candleVolume.toString(), + market.positionDecimalPlaces, + 2 + ) + : '-', + className: `${cellClassNames} hidden lg:table-cell font-mono`, + onlyOnDetailed: true, + dataTestId: 'market-volume', + }, { kind: ColumnKind.TradingMode, value: @@ -468,18 +487,6 @@ export const columnsPositionMarkets = ( onlyOnDetailed: true, dataTestId: 'trading-mode-col', }, - { - kind: ColumnKind.Volume, - value: - market.data && market.data.indicativeVolume !== '0' - ? addDecimalsFormatNumber( - market.data.indicativeVolume, - market.positionDecimalPlaces - ) - : '-', - className: `${cellClassNames} hidden lg:table-cell font-mono`, - onlyOnDetailed: true, - }, { kind: ColumnKind.Fee, value: , diff --git a/apps/trading/pages/markets/trade-grid.tsx b/apps/trading/pages/markets/trade-grid.tsx index 8a45b357f..12a82fdaf 100644 --- a/apps/trading/pages/markets/trade-grid.tsx +++ b/apps/trading/pages/markets/trade-grid.tsx @@ -33,8 +33,8 @@ import type { OnCellClickHandler } from '../../components/select-market'; import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list'; import { Last24hPriceChange } from '../../components/last-24h-price-change'; import { MarketMarkPrice } from '../../components/market-mark-price'; -import { MarketVolume } from '../../components/market-volume'; import { MarketTradingModeComponent } from '../../components/market-trading-mode'; +import { Last24hVolume } from '../../components/last-24h-volume'; const TradingViews = { Candles: CandlesChartContainer, @@ -138,7 +138,7 @@ export const TradeMarketHeader = ({ - + {symbol ? ( { }, new BigNumber(0)) .toString(); }; + +export const calcCandleVolume = (candles: Candle[]): string | undefined => + candles && + candles.reduce((acc, c) => new BigNumber(acc).plus(c.volume).toString(), '0'); diff --git a/libs/orders/src/lib/components/order-list/order-list.tsx b/libs/orders/src/lib/components/order-list/order-list.tsx index 9ddc1373d..aae945363 100644 --- a/libs/orders/src/lib/components/order-list/order-list.tsx +++ b/libs/orders/src/lib/components/order-list/order-list.tsx @@ -1,41 +1,42 @@ -import { - OrderTimeInForce, - OrderStatus, - Side, - OrderType, - OrderTypeMapping, - OrderStatusMapping, - OrderTimeInForceMapping, - OrderRejectionReasonMapping, -} from '@vegaprotocol/types'; import { addDecimal, getDateTimeFormat, - t, - positiveClassNames, - negativeClassNames, isNumeric, + negativeClassNames, + positiveClassNames, + t, } from '@vegaprotocol/react-helpers'; -import type { - VegaICellRendererParams, - VegaValueFormatterParams, -} from '@vegaprotocol/ui-toolkit'; +import { + OrderRejectionReasonMapping, + OrderStatus, + OrderStatusMapping, + OrderTimeInForce, + OrderTimeInForceMapping, + OrderType, + OrderTypeMapping, + Side, +} from '@vegaprotocol/types'; import { AgGridDynamic as AgGrid, Button, Intent, + Link, } from '@vegaprotocol/ui-toolkit'; -import type { AgGridReact, AgGridReactProps } from 'ag-grid-react'; import { AgGridColumn } from 'ag-grid-react'; -import { forwardRef, useState } from 'react'; import BigNumber from 'bignumber.js'; +import { forwardRef, useState } from 'react'; import { useOrderCancel } from '../../order-hooks/use-order-cancel'; import { useOrderEdit } from '../../order-hooks/use-order-edit'; -import { OrderEditDialog } from './order-edit-dialog'; -import type { Order } from '../'; import { OrderFeedback } from '../order-feedback'; +import { OrderEditDialog } from './order-edit-dialog'; +import type { + VegaICellRendererParams, + VegaValueFormatterParams, +} from '@vegaprotocol/ui-toolkit'; +import type { AgGridReact, AgGridReactProps } from 'ag-grid-react'; +import type { Order } from '../'; type OrderListProps = AgGridReactProps; export const OrderList = forwardRef( @@ -113,6 +114,21 @@ export const OrderListTable = forwardRef( ) => + data?.market?.id ? ( + + {value} + + ) : ( + value + ) + } />