532ad3a4b9
Co-authored-by: bwallacee <ben@vega.xyz>
265 lines
8.1 KiB
TypeScript
265 lines
8.1 KiB
TypeScript
import { useMemo } from 'react';
|
|
import type { ColDef, ValueFormatterParams } from 'ag-grid-community';
|
|
import type {
|
|
VegaICellRendererParams,
|
|
VegaValueFormatterParams,
|
|
VegaValueGetterParams,
|
|
} from '@vegaprotocol/datagrid';
|
|
import { COL_DEFS, SetFilter } from '@vegaprotocol/datagrid';
|
|
import * as Schema from '@vegaprotocol/types';
|
|
import {
|
|
addDecimalsFormatNumber,
|
|
formatNumber,
|
|
toBigNum,
|
|
} from '@vegaprotocol/utils';
|
|
import { ButtonLink, Tooltip } from '@vegaprotocol/ui-toolkit';
|
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
|
import type {
|
|
MarketFieldsFragment,
|
|
MarketMaybeWithData,
|
|
MarketMaybeWithDataAndCandles,
|
|
} from '@vegaprotocol/markets';
|
|
import { MarketActionsDropdown } from './market-table-actions';
|
|
import {
|
|
calcCandleVolume,
|
|
calcCandleVolumePrice,
|
|
getAsset,
|
|
getQuoteName,
|
|
} from '@vegaprotocol/markets';
|
|
import { MarketCodeCell } from './market-code-cell';
|
|
import { useT } from '../../lib/use-t';
|
|
|
|
const { MarketTradingMode, AuctionTrigger } = Schema;
|
|
|
|
export const useMarketsColumnDefs = () => {
|
|
const t = useT();
|
|
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
|
return useMemo<ColDef[]>(
|
|
() => [
|
|
{
|
|
headerName: t('Market'),
|
|
field: 'tradableInstrument.instrument.code',
|
|
pinned: true,
|
|
cellRenderer: ({
|
|
value,
|
|
data,
|
|
}: VegaICellRendererParams<
|
|
MarketMaybeWithData,
|
|
'tradableInstrument.instrument.code'
|
|
>) => (
|
|
<MarketCodeCell
|
|
value={value}
|
|
data={{
|
|
productType:
|
|
data?.tradableInstrument.instrument.product.__typename,
|
|
successorMarketID: data?.successorMarketID,
|
|
parentMarketID: data?.parentMarketID,
|
|
}}
|
|
/>
|
|
),
|
|
},
|
|
{
|
|
headerName: t('Description'),
|
|
field: 'tradableInstrument.instrument.name',
|
|
},
|
|
{
|
|
headerName: t('Settlement asset'),
|
|
field: 'tradableInstrument.instrument.product.settlementAsset.symbol',
|
|
cellRenderer: ({
|
|
data,
|
|
}: VegaICellRendererParams<
|
|
MarketMaybeWithData,
|
|
'tradableInstrument.instrument.product.settlementAsset.symbol'
|
|
>) => {
|
|
const value = data && getAsset(data);
|
|
return value ? (
|
|
<ButtonLink
|
|
onClick={(e) => {
|
|
openAssetDetailsDialog(value.id, e.target as HTMLElement);
|
|
}}
|
|
>
|
|
{value.symbol}
|
|
</ButtonLink>
|
|
) : (
|
|
''
|
|
);
|
|
},
|
|
},
|
|
{
|
|
headerName: t('Trading mode'),
|
|
field: 'tradingMode',
|
|
cellRenderer: ({
|
|
data,
|
|
}: VegaICellRendererParams<MarketMaybeWithData, 'data'>) => {
|
|
if (!data?.data) return '-';
|
|
const { trigger, marketTradingMode } = data.data;
|
|
|
|
const withTriggerInfo =
|
|
marketTradingMode ===
|
|
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
|
|
trigger &&
|
|
trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED;
|
|
|
|
if (withTriggerInfo) {
|
|
return (
|
|
<Tooltip
|
|
description={`${Schema.MarketTradingModeMapping[marketTradingMode]}
|
|
- ${Schema.AuctionTriggerMapping[trigger]}`}
|
|
>
|
|
<span>
|
|
{Schema.MarketTradingModeMapping[marketTradingMode]}
|
|
</span>
|
|
</Tooltip>
|
|
);
|
|
}
|
|
|
|
return Schema.MarketTradingModeMapping[marketTradingMode];
|
|
},
|
|
filter: SetFilter,
|
|
filterParams: {
|
|
set: Schema.MarketTradingModeMapping,
|
|
},
|
|
},
|
|
{
|
|
headerName: t('Status'),
|
|
field: 'state',
|
|
valueFormatter: ({
|
|
data,
|
|
}: VegaValueFormatterParams<MarketMaybeWithData, 'state'>) => {
|
|
return data?.state ? Schema.MarketStateMapping[data.state] : '-';
|
|
},
|
|
filter: SetFilter,
|
|
filterParams: {
|
|
set: Schema.MarketStateMapping,
|
|
},
|
|
},
|
|
{
|
|
headerName: t('Mark price'),
|
|
field: 'data.markPrice',
|
|
type: 'rightAligned',
|
|
cellRenderer: 'PriceFlashCell',
|
|
filter: 'agNumberColumnFilter',
|
|
valueGetter: ({ data }: VegaValueGetterParams<MarketMaybeWithData>) => {
|
|
return data?.data?.markPrice === undefined
|
|
? undefined
|
|
: toBigNum(data?.data?.markPrice, data.decimalPlaces).toNumber();
|
|
},
|
|
valueFormatter: ({
|
|
data,
|
|
}: VegaValueFormatterParams<MarketMaybeWithData, 'data.markPrice'>) =>
|
|
data?.data?.bestOfferPrice === undefined
|
|
? '-'
|
|
: addDecimalsFormatNumber(data.data.markPrice, data.decimalPlaces),
|
|
},
|
|
{
|
|
headerName: t('24h volume'),
|
|
type: 'rightAligned',
|
|
field: 'data.candles',
|
|
valueGetter: ({
|
|
data,
|
|
}: VegaValueGetterParams<MarketMaybeWithDataAndCandles>) => {
|
|
if (!data) return 0;
|
|
const candles = data?.candles;
|
|
const vol = candles ? calcCandleVolume(candles) : '0';
|
|
return Number(vol);
|
|
},
|
|
valueFormatter: ({
|
|
data,
|
|
}: ValueFormatterParams<MarketMaybeWithDataAndCandles, 'candles'>) => {
|
|
const candles = data?.candles;
|
|
const vol = candles ? calcCandleVolume(candles) : '0';
|
|
const quoteName = getQuoteName(data as MarketFieldsFragment);
|
|
const volPrice =
|
|
candles &&
|
|
calcCandleVolumePrice(
|
|
candles,
|
|
data.decimalPlaces,
|
|
data.positionDecimalPlaces
|
|
);
|
|
|
|
const volume =
|
|
data && vol && vol !== '0'
|
|
? addDecimalsFormatNumber(vol, data.positionDecimalPlaces)
|
|
: '0.00';
|
|
const volumePrice =
|
|
volPrice && formatNumber(volPrice, data?.decimalPlaces);
|
|
|
|
return volumePrice
|
|
? `${volume} (${volumePrice} ${quoteName})`
|
|
: volume;
|
|
},
|
|
},
|
|
{
|
|
headerName: t('Open Interest'),
|
|
field: 'data.openInterest',
|
|
type: 'rightAligned',
|
|
valueFormatter: ({
|
|
data,
|
|
}: VegaValueFormatterParams<
|
|
MarketMaybeWithData,
|
|
'data.openInterest'
|
|
>) =>
|
|
data?.data?.openInterest === undefined
|
|
? '-'
|
|
: addDecimalsFormatNumber(
|
|
data?.data?.openInterest,
|
|
data?.positionDecimalPlaces
|
|
),
|
|
},
|
|
{
|
|
headerName: t('Spread'),
|
|
field: 'data.bestBidPrice',
|
|
type: 'rightAligned',
|
|
filter: 'agNumberColumnFilter',
|
|
cellRenderer: 'PriceFlashCell',
|
|
valueGetter: ({ data }: VegaValueGetterParams<MarketMaybeWithData>) => {
|
|
if (!data || !data.data?.bestOfferPrice || !data.data?.bestBidPrice) {
|
|
return undefined;
|
|
}
|
|
|
|
const offer = toBigNum(data.data.bestOfferPrice, data.decimalPlaces);
|
|
const bid = toBigNum(data.data.bestBidPrice, data.decimalPlaces);
|
|
|
|
const spread = offer.minus(bid).toNumber();
|
|
|
|
// The calculation above can result in '-0' being rendered after formatting
|
|
// so return Math.abs to remove it and just render '0'
|
|
if (spread === 0) {
|
|
return Math.abs(spread);
|
|
}
|
|
|
|
return spread;
|
|
},
|
|
valueFormatter: ({
|
|
value,
|
|
}: VegaValueFormatterParams<
|
|
MarketMaybeWithData,
|
|
'data.bestBidPrice'
|
|
>) => {
|
|
if (!value) return '-';
|
|
return value.toString();
|
|
},
|
|
},
|
|
{
|
|
colId: 'market-actions',
|
|
field: 'id',
|
|
...COL_DEFS.actions,
|
|
cellRenderer: ({
|
|
data,
|
|
}: VegaICellRendererParams<MarketMaybeWithData>) => {
|
|
if (!data) return null;
|
|
return (
|
|
<MarketActionsDropdown
|
|
marketId={data.id}
|
|
assetId={getAsset(data).id}
|
|
successorMarketID={data.successorMarketID}
|
|
parentMarketID={data.parentMarketID}
|
|
/>
|
|
);
|
|
},
|
|
},
|
|
],
|
|
[openAssetDetailsDialog, t]
|
|
);
|
|
};
|