Feat/625 market info more details - open interest, liquidity info, market and instrument ids, price and settlement asset in the header - Part 1 (#823)

* fix: #625 update the info market query with new fields

* fix: #625 generate code for info market query and fix pagination being removed from globalTypes

* fix:  add id and filter no trading auctions

* fix: add id and format labels

* fix: add name and code to instrument

* fix: add name and code to instrument

* fix: format check

* feat: add settlement asset and mark price

* feat: add liquidity parameters

* fix: remove settings.json

* fix: price instead of mark price label

* fix: add instrument metadata

* fix: remove unused set lodash

* fix: move Liquidity monitoring parameters after price monitoring

* fix: rename instrument metadata to metadata

* fix: settlement asset could be undefined

* Merge branch 'master' of github.com:vegaprotocol/frontend-monorepo into feat/625-market-info-more-details-open-interest-liquidity-ids-risk

* fix: format market id and trading mode label in key details

* fix: display settlement asset if defined

* fix: format trade-grid.tsx
This commit is contained in:
m.ray 2022-07-21 11:57:30 +02:00 committed by GitHub
parent f7c869674a
commit 8ce51dddbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 317 additions and 33 deletions

View File

@ -41,6 +41,16 @@ const MARKET_QUERY = gql`
metadata { metadata {
tags tags
} }
product {
... on Future {
quoteName
settlementAsset {
id
symbol
name
}
}
}
} }
} }
marketTimestamps { marketTimestamps {

View File

@ -61,6 +61,34 @@ export interface Market_market_tradableInstrument_instrument_metadata {
tags: string[] | null; tags: string[] | null;
} }
export interface Market_market_tradableInstrument_instrument_product_settlementAsset {
__typename: "Asset";
/**
* The id of the asset
*/
id: string;
/**
* The symbol of the asset (e.g: GBP)
*/
symbol: string;
/**
* The full name of the asset (e.g: Great British Pound)
*/
name: string;
}
export interface Market_market_tradableInstrument_instrument_product {
__typename: "Future";
/**
* String representing the quote (e.g. BTCUSD -> USD is quote)
*/
quoteName: string;
/**
* The name of the asset (string)
*/
settlementAsset: Market_market_tradableInstrument_instrument_product_settlementAsset;
}
export interface Market_market_tradableInstrument_instrument { export interface Market_market_tradableInstrument_instrument {
__typename: "Instrument"; __typename: "Instrument";
/** /**
@ -75,6 +103,10 @@ export interface Market_market_tradableInstrument_instrument {
* Metadata for this instrument * Metadata for this instrument
*/ */
metadata: Market_market_tradableInstrument_instrument_metadata; metadata: Market_market_tradableInstrument_instrument_metadata;
/**
* A reference to or instance of a fully specified product, including all required product parameters for that product (Product union)
*/
product: Market_market_tradableInstrument_instrument_product;
} }
export interface Market_market_tradableInstrument { export interface Market_market_tradableInstrument {

View File

@ -85,14 +85,14 @@ export const TradeMarketHeader = ({
className="flex flex-auto items-start gap-64 overflow-x-auto whitespace-nowrap" className="flex flex-auto items-start gap-64 overflow-x-auto whitespace-nowrap"
> >
<div className={headerItemClassName}> <div className={headerItemClassName}>
<span className={itemClassName}>Change (24h)</span> <span className={itemClassName}>{t('Change (24h)')}</span>
<PriceCellChange <PriceCellChange
candles={candlesClose} candles={candlesClose}
decimalPlaces={market.decimalPlaces} decimalPlaces={market.decimalPlaces}
/> />
</div> </div>
<div className={headerItemClassName}> <div className={headerItemClassName}>
<span className={itemClassName}>Volume</span> <span className={itemClassName}>{t('Volume')}</span>
<span data-testid="trading-volume" className={itemValueClassName}> <span data-testid="trading-volume" className={itemValueClassName}>
{market.data && market.data.indicativeVolume !== '0' {market.data && market.data.indicativeVolume !== '0'
? addDecimalsFormatNumber( ? addDecimalsFormatNumber(
@ -103,7 +103,7 @@ export const TradeMarketHeader = ({
</span> </span>
</div> </div>
<div className={headerItemClassName}> <div className={headerItemClassName}>
<span className={itemClassName}>Trading mode</span> <span className={itemClassName}>{t('Trading mode')}</span>
<span data-testid="trading-mode" className={itemValueClassName}> <span data-testid="trading-mode" className={itemValueClassName}>
{market.tradingMode === MarketTradingMode.MonitoringAuction && {market.tradingMode === MarketTradingMode.MonitoringAuction &&
market.data?.trigger && market.data?.trigger &&
@ -114,6 +114,29 @@ export const TradeMarketHeader = ({
: formatLabel(market.tradingMode)} : formatLabel(market.tradingMode)}
</span> </span>
</div> </div>
<div className={headerItemClassName}>
<span className={itemClassName}>{t('Price')}</span>
<span data-testid="mark-price" className={itemValueClassName}>
{market.data && market.data.markPrice !== '0'
? addDecimalsFormatNumber(
market.data.markPrice,
market.decimalPlaces
)
: '-'}
</span>
</div>
{market.tradableInstrument.instrument.product?.settlementAsset
?.symbol && (
<div className={headerItemClassName}>
<span className={itemClassName}>{t('Settlement asset')}</span>
<span data-testid="trading-mode" className={itemValueClassName}>
{
market.tradableInstrument.instrument.product?.settlementAsset
?.symbol
}
</span>
</div>
)}
</div> </div>
</div> </div>
</header> </header>
@ -159,7 +182,7 @@ export const TradeGrid = ({ market }: TradeGridProps) => {
<TradeGridChild className="h-full px-4 bg-black-10 dark:bg-black-70"> <TradeGridChild className="h-full px-4 bg-black-10 dark:bg-black-70">
<Tabs> <Tabs>
<Tab id="ticket" name={t('Ticket')}> <Tab id="ticket" name={t('Ticket')}>
<TradingViews.Ticket marketId={market.id}/> <TradingViews.Ticket marketId={market.id} />
</Tab> </Tab>
<Tab id="info" name={t('Info')}> <Tab id="info" name={t('Info')}>
<TradingViews.Info marketId={market.id} /> <TradingViews.Info marketId={market.id} />

View File

@ -3,12 +3,36 @@
// @generated // @generated
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { MarketState, MarketTradingMode } from "@vegaprotocol/types"; import { MarketState, MarketTradingMode, AccountType } from "@vegaprotocol/types";
// ==================================================== // ====================================================
// GraphQL query operation: MarketInfoQuery // GraphQL query operation: MarketInfoQuery
// ==================================================== // ====================================================
export interface MarketInfoQuery_market_accounts_asset {
__typename: "Asset";
/**
* The id of the asset
*/
id: string;
}
export interface MarketInfoQuery_market_accounts {
__typename: "Account";
/**
* Account type (General, Margin, etc)
*/
type: AccountType;
/**
* Asset, the 'currency'
*/
asset: MarketInfoQuery_market_accounts_asset;
/**
* Balance as string - current account balance (approx. as balances can be updated several times per second)
*/
balance: string;
}
export interface MarketInfoQuery_market_fees_factors { export interface MarketInfoQuery_market_fees_factors {
__typename: "FeeFactors"; __typename: "FeeFactors";
/** /**
@ -125,6 +149,42 @@ export interface MarketInfoQuery_market_data {
* the aggregated volume being offered at the best static offer price, excluding pegged orders. * the aggregated volume being offered at the best static offer price, excluding pegged orders.
*/ */
bestStaticOfferVolume: string; bestStaticOfferVolume: string;
/**
* the sum of the size of all positions greater than 0.
*/
openInterest: string;
}
export interface MarketInfoQuery_market_liquidityMonitoringParameters_targetStakeParameters {
__typename: "TargetStakeParameters";
/**
* Specifies length of time window expressed in seconds for target stake calculation
*/
timeWindow: number;
/**
* Specifies scaling factors used in target stake calculation
*/
scalingFactor: number;
}
export interface MarketInfoQuery_market_liquidityMonitoringParameters {
__typename: "LiquidityMonitoringParameters";
/**
* Specifies the triggering ratio for entering liquidity auction
*/
triggeringRatio: number;
/**
* Specifies parameters related to target stake calculation
*/
targetStakeParameters: MarketInfoQuery_market_liquidityMonitoringParameters_targetStakeParameters;
}
export interface MarketInfoQuery_market_tradableInstrument_instrument_metadata {
__typename: "InstrumentMetadata";
/**
* An arbitrary list of tags to associated to associate to the Instrument (string list)
*/
tags: string[] | null;
} }
export interface MarketInfoQuery_market_tradableInstrument_instrument_product_settlementAsset { export interface MarketInfoQuery_market_tradableInstrument_instrument_product_settlementAsset {
@ -143,6 +203,28 @@ export interface MarketInfoQuery_market_tradableInstrument_instrument_product_se
name: string; name: string;
} }
export interface MarketInfoQuery_market_tradableInstrument_instrument_product_oracleSpecForSettlementPrice {
__typename: "OracleSpec";
/**
* id is a hash generated from the OracleSpec data.
*/
id: string;
}
export interface MarketInfoQuery_market_tradableInstrument_instrument_product_oracleSpecForTradingTermination {
__typename: "OracleSpec";
/**
* id is a hash generated from the OracleSpec data.
*/
id: string;
}
export interface MarketInfoQuery_market_tradableInstrument_instrument_product_oracleSpecBinding {
__typename: "OracleSpecToFutureBinding";
settlementPriceProperty: string;
tradingTerminationProperty: string;
}
export interface MarketInfoQuery_market_tradableInstrument_instrument_product { export interface MarketInfoQuery_market_tradableInstrument_instrument_product {
__typename: "Future"; __typename: "Future";
/** /**
@ -153,10 +235,38 @@ export interface MarketInfoQuery_market_tradableInstrument_instrument_product {
* The name of the asset (string) * The name of the asset (string)
*/ */
settlementAsset: MarketInfoQuery_market_tradableInstrument_instrument_product_settlementAsset; settlementAsset: MarketInfoQuery_market_tradableInstrument_instrument_product_settlementAsset;
/**
* The oracle spec describing the oracle data of interest for settlement price.
*/
oracleSpecForSettlementPrice: MarketInfoQuery_market_tradableInstrument_instrument_product_oracleSpecForSettlementPrice;
/**
* The oracle spec describing the oracle data of interest for trading termination.
*/
oracleSpecForTradingTermination: MarketInfoQuery_market_tradableInstrument_instrument_product_oracleSpecForTradingTermination;
/**
* The binding between the oracle spec and the settlement price
*/
oracleSpecBinding: MarketInfoQuery_market_tradableInstrument_instrument_product_oracleSpecBinding;
} }
export interface MarketInfoQuery_market_tradableInstrument_instrument { export interface MarketInfoQuery_market_tradableInstrument_instrument {
__typename: "Instrument"; __typename: "Instrument";
/**
* Uniquely identify an instrument across all instruments available on Vega (string)
*/
id: string;
/**
* Full and fairly descriptive name for the instrument
*/
name: string;
/**
* A short non necessarily unique code used to easily describe the instrument (e.g: FX:BTCUSD/DEC18) (string)
*/
code: string;
/**
* Metadata for this instrument
*/
metadata: MarketInfoQuery_market_tradableInstrument_instrument_metadata;
/** /**
* A reference to or instance of a fully specified product, including all required product parameters for that product (Product union) * A reference to or instance of a fully specified product, including all required product parameters for that product (Product union)
*/ */
@ -286,6 +396,10 @@ export interface MarketInfoQuery_market {
* Current mode of execution of the market * Current mode of execution of the market
*/ */
tradingMode: MarketTradingMode; tradingMode: MarketTradingMode;
/**
* Get account for a party or market
*/
accounts: MarketInfoQuery_market_accounts[] | null;
/** /**
* Fees related data * Fees related data
*/ */
@ -302,6 +416,10 @@ export interface MarketInfoQuery_market {
* marketData for the given market * marketData for the given market
*/ */
data: MarketInfoQuery_market_data | null; data: MarketInfoQuery_market_data | null;
/**
* Liquidity monitoring parameters for the market
*/
liquidityMonitoringParameters: MarketInfoQuery_market_liquidityMonitoringParameters;
/** /**
* An instance of or reference to a tradable instrument. * An instance of or reference to a tradable instrument.
*/ */

View File

@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { import {
addDecimalsFormatNumber, addDecimalsFormatNumber,
formatLabel,
formatNumber, formatNumber,
formatNumberPercentage, formatNumberPercentage,
t, t,
@ -15,10 +16,7 @@ import {
import startCase from 'lodash/startCase'; import startCase from 'lodash/startCase';
import pick from 'lodash/pick'; import pick from 'lodash/pick';
import omit from 'lodash/omit'; import omit from 'lodash/omit';
import type { import type { MarketInfoQuery, MarketInfoQuery_market } from './__generated__';
MarketInfoQuery,
MarketInfoQuery_market,
} from './__generated__/MarketInfoQuery';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { gql, useQuery } from '@apollo/client'; import { gql, useQuery } from '@apollo/client';
@ -31,6 +29,13 @@ const MARKET_INFO_QUERY = gql`
positionDecimalPlaces positionDecimalPlaces
state state
tradingMode tradingMode
accounts {
type
asset {
id
}
balance
}
fees { fees {
factors { factors {
makerFee makerFee
@ -53,6 +58,13 @@ const MARKET_INFO_QUERY = gql`
short short
long long
} }
accounts {
type
asset {
id
}
balance
}
data { data {
market { market {
id id
@ -64,9 +76,23 @@ const MARKET_INFO_QUERY = gql`
bestStaticBidVolume bestStaticBidVolume
bestStaticOfferVolume bestStaticOfferVolume
indicativeVolume indicativeVolume
openInterest
}
liquidityMonitoringParameters {
triggeringRatio
targetStakeParameters {
timeWindow
scalingFactor
}
} }
tradableInstrument { tradableInstrument {
instrument { instrument {
id
name
code
metadata {
tags
}
product { product {
... on Future { ... on Future {
quoteName quoteName
@ -75,6 +101,16 @@ const MARKET_INFO_QUERY = gql`
symbol symbol
name name
} }
oracleSpecForSettlementPrice {
id
}
oracleSpecForTradingTermination {
id
}
oracleSpecBinding {
settlementPriceProperty
tradingTerminationProperty
}
} }
} }
} }
@ -159,19 +195,28 @@ export const Info = ({ market }: InfoProps) => {
), ),
}, },
]; ];
const keyDetails = pick(
market,
'name',
'decimalPlaces',
'positionDecimalPlaces',
'tradingMode',
'state',
'id' as 'marketId'
);
const marketSpecPanels = [ const marketSpecPanels = [
{ {
title: t('Key details'), title: t('Key details'),
content: ( content: (
<MarketInfoTable <MarketInfoTable
data={pick( data={{
market, ...keyDetails,
'name', marketId: keyDetails.id,
'decimalPlaces', id: undefined,
'positionDecimalPlaces', tradingMode:
'tradingMode', keyDetails.tradingMode && formatLabel(keyDetails.tradingMode),
'state' }}
)}
/> />
), ),
}, },
@ -180,8 +225,28 @@ export const Info = ({ market }: InfoProps) => {
content: ( content: (
<MarketInfoTable <MarketInfoTable
data={{ data={{
product: market.tradableInstrument.instrument.product, marketName: market.tradableInstrument.instrument.name,
...market.tradableInstrument.instrument.product.settlementAsset, code: market.tradableInstrument.instrument.code,
productType:
market.tradableInstrument.instrument.product.__typename,
...market.tradableInstrument.instrument.product,
...(market.tradableInstrument.instrument.product?.settlementAsset ??
{}),
}}
/>
),
},
{
title: t('Metadata'),
content: (
<MarketInfoTable
data={{
...market.tradableInstrument.instrument.metadata.tags
?.map((tag) => {
const [key, value] = tag.split(':');
return { [key]: value };
})
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
}} }}
/> />
), ),
@ -212,6 +277,18 @@ export const Info = ({ market }: InfoProps) => {
content: <MarketInfoTable data={trigger} />, content: <MarketInfoTable data={trigger} />,
}) })
), ),
{
title: t('Liquidity monitoring parameters'),
content: (
<MarketInfoTable
data={{
triggeringRatio:
market.liquidityMonitoringParameters.triggeringRatio,
...market.liquidityMonitoringParameters.targetStakeParameters,
}}
/>
),
},
]; ];
return ( return (
@ -261,7 +338,7 @@ const Row = ({
? decimalPlaces ? decimalPlaces
? addDecimalsFormatNumber(value, decimalPlaces) ? addDecimalsFormatNumber(value, decimalPlaces)
: asPercentage : asPercentage
? formatNumberPercentage(new BigNumber(value)) ? formatNumberPercentage(new BigNumber(value * 100))
: formatNumber(Number(value)) : formatNumber(Number(value))
: value} : value}
</KeyValueTableRow> </KeyValueTableRow>
@ -283,7 +360,7 @@ export const MarketInfoTable = ({
decimalPlaces, decimalPlaces,
asPercentage, asPercentage,
unformatted, unformatted,
omits = ['id', '__typename'], omits = ['__typename'],
}: MarketInfoTableProps) => { }: MarketInfoTableProps) => {
return ( return (
<KeyValueTable muted={true}> <KeyValueTable muted={true}>

View File

@ -3,7 +3,7 @@
// @generated // @generated
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { Interval, MarketState } from "@vegaprotocol/types"; import { Interval, MarketState, MarketTradingMode } from "@vegaprotocol/types";
// ==================================================== // ====================================================
// GraphQL query operation: MarketList // GraphQL query operation: MarketList
@ -112,6 +112,10 @@ export interface MarketList_markets {
* Current state of the market * Current state of the market
*/ */
state: MarketState; state: MarketState;
/**
* Current mode of execution of the market
*/
tradingMode: MarketTradingMode;
/** /**
* marketData for the given market * marketData for the given market
*/ */

View File

@ -54,6 +54,7 @@ export const MARKET_LIST_QUERY = gql`
id id
decimalPlaces decimalPlaces
state state
tradingMode
data { data {
market { market {
id id

View File

@ -1,4 +1,4 @@
import { MarketState } from '@vegaprotocol/types'; import { MarketState, MarketTradingMode } from '@vegaprotocol/types';
import orderBy from 'lodash/orderBy'; import orderBy from 'lodash/orderBy';
import type { import type {
MarketList, MarketList,
@ -13,7 +13,11 @@ export const lastPrice = ({ candles }: MarketList_markets) =>
export const mapDataToMarketList = ({ markets }: MarketList) => export const mapDataToMarketList = ({ markets }: MarketList) =>
orderBy( orderBy(
markets markets
?.filter((m) => m.state !== MarketState.Rejected) ?.filter(
(m) =>
m.state !== MarketState.Rejected &&
m.tradingMode !== MarketTradingMode.NoTrading
)
.map((m) => { .map((m) => {
return { return {
id: m.id, id: m.id,

View File

@ -1,5 +1,9 @@
import { act, render, screen } from '@testing-library/react'; import { act, render, screen } from '@testing-library/react';
import { addDecimal, getDateTimeFormat } from '@vegaprotocol/react-helpers'; import {
addDecimal,
formatLabel,
getDateTimeFormat,
} from '@vegaprotocol/react-helpers';
import type { Orders_party_orders } from '../__generated__/Orders'; import type { Orders_party_orders } from '../__generated__/Orders';
import { OrderStatus, OrderRejectionReason } from '@vegaprotocol/types'; import { OrderStatus, OrderRejectionReason } from '@vegaprotocol/types';
import { OrderListTable } from './order-list'; import { OrderListTable } from './order-list';
@ -118,7 +122,7 @@ describe('OrderListTable', () => {
}); });
const cells = screen.getAllByRole('gridcell'); const cells = screen.getAllByRole('gridcell');
expect(cells[3]).toHaveTextContent( expect(cells[3]).toHaveTextContent(
`${rejectedOrder.status}: ${rejectedOrder.rejectionReason}` `${rejectedOrder.status}: ${formatLabel(rejectedOrder.rejectionReason)}`
); );
}); });
}); });

View File

@ -1,6 +1,11 @@
import { OrderTimeInForce, OrderStatus, Side } from '@vegaprotocol/types'; import { OrderTimeInForce, OrderStatus, Side } from '@vegaprotocol/types';
import type { Orders_party_orders } from '../__generated__/Orders'; import type { Orders_party_orders } from '../__generated__/Orders';
import { addDecimal, getDateTimeFormat, t } from '@vegaprotocol/react-helpers'; import {
addDecimal,
formatLabel,
getDateTimeFormat,
t,
} from '@vegaprotocol/react-helpers';
import { AgGridDynamic as AgGrid, Button } from '@vegaprotocol/ui-toolkit'; import { AgGridDynamic as AgGrid, Button } from '@vegaprotocol/ui-toolkit';
import type { import type {
ICellRendererParams, ICellRendererParams,
@ -139,7 +144,7 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
field="status" field="status"
valueFormatter={({ value, data }: ValueFormatterParams) => { valueFormatter={({ value, data }: ValueFormatterParams) => {
if (value === OrderStatus.Rejected) { if (value === OrderStatus.Rejected) {
return `${value}: ${data.rejectionReason}`; return `${value}: ${formatLabel(data.rejectionReason)}`;
} }
return value; return value;

1
libs/types/src/__generated__/index.ts generated Normal file
View File

@ -0,0 +1 @@
export * from './globalTypes';

View File

@ -1,3 +1,3 @@
export * from './__generated__/globalTypes'; export * from './__generated__';
export * from './candle'; export * from './candle';
export * from './pagination'; export * from './pagination';

View File

@ -4,7 +4,11 @@ import type { VegaTxState } from '../use-vega-transaction';
import { VegaTxStatus } from '../use-vega-transaction'; import { VegaTxStatus } from '../use-vega-transaction';
import { Icon, Loader } from '@vegaprotocol/ui-toolkit'; import { Icon, Loader } from '@vegaprotocol/ui-toolkit';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers'; import {
addDecimalsFormatNumber,
formatLabel,
t,
} from '@vegaprotocol/react-helpers';
import { useEnvironment } from '@vegaprotocol/environment'; import { useEnvironment } from '@vegaprotocol/environment';
import { OrderType } from '@vegaprotocol/types'; import { OrderType } from '@vegaprotocol/types';
import type { Order } from '../wallet-types'; import type { Order } from '../wallet-types';
@ -169,7 +173,8 @@ export const VegaDialog = ({
icon={<Icon name="warning-sign" size={20} />} icon={<Icon name="warning-sign" size={20} />}
> >
<p data-testid="error-reason"> <p data-testid="error-reason">
{t(`Reason: ${finalizedOrder.rejectionReason}`)} {finalizedOrder.rejectionReason &&
t(`Reason: ${formatLabel(finalizedOrder.rejectionReason)}`)}
</p> </p>
</OrderDialogWrapper> </OrderDialogWrapper>
); );