Feat/815 auction conditions (#955)
* feat: add tooltip for market trading modes * fix: format * fix: remove log * fix: typo
This commit is contained in:
parent
2e644de413
commit
1c9cd3aa2a
1
apps/trading/components/trading-mode-tooltip/index.tsx
Normal file
1
apps/trading/components/trading-mode-tooltip/index.tsx
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './trading-mode-tooltip';
|
@ -0,0 +1,201 @@
|
|||||||
|
import type { ReactNode } from 'react';
|
||||||
|
import {
|
||||||
|
t,
|
||||||
|
getDateTimeFormat,
|
||||||
|
addDecimalsFormatNumber,
|
||||||
|
} from '@vegaprotocol/react-helpers';
|
||||||
|
import { Link } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { MarketTradingMode, AuctionTrigger } from '@vegaprotocol/types';
|
||||||
|
import type { Market_market } from '../../pages/markets/__generated__/Market';
|
||||||
|
|
||||||
|
type MarketDataGridProps = {
|
||||||
|
grid: {
|
||||||
|
label: string;
|
||||||
|
value?: ReactNode;
|
||||||
|
isEstimate?: boolean;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const MarketDataGrid = ({ grid }: MarketDataGridProps) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{grid.map(
|
||||||
|
({ label, value, isEstimate }, index) =>
|
||||||
|
value && (
|
||||||
|
<div key={index} className="grid grid-cols-2">
|
||||||
|
<span>{label}</span>
|
||||||
|
<span>
|
||||||
|
{isEstimate && <span className="ml-[-0.625em]">{'~'}</span>}
|
||||||
|
{value}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatStake = (value: string, market: Market_market) => {
|
||||||
|
const formattedValue = addDecimalsFormatNumber(
|
||||||
|
value,
|
||||||
|
market.positionDecimalPlaces
|
||||||
|
);
|
||||||
|
const asset =
|
||||||
|
market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
||||||
|
return `${formattedValue} ${asset}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const compileGridData = (market: Market_market) => {
|
||||||
|
const grid: MarketDataGridProps['grid'] = [];
|
||||||
|
const isLiquidityMonitoringAuction =
|
||||||
|
market.tradingMode === MarketTradingMode.MonitoringAuction &&
|
||||||
|
market.data?.trigger === AuctionTrigger.Liquidity;
|
||||||
|
|
||||||
|
if (!market.data) return grid;
|
||||||
|
|
||||||
|
if (market.data?.auctionStart) {
|
||||||
|
grid.push({
|
||||||
|
label: t('Auction start'),
|
||||||
|
value: getDateTimeFormat().format(new Date(market.data.auctionStart)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (market.data?.auctionEnd) {
|
||||||
|
grid.push({
|
||||||
|
label: isLiquidityMonitoringAuction
|
||||||
|
? t('Est auction end')
|
||||||
|
: t('Auction end'),
|
||||||
|
value: getDateTimeFormat().format(new Date(market.data.auctionEnd)),
|
||||||
|
isEstimate: isLiquidityMonitoringAuction ? true : false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLiquidityMonitoringAuction && market.data?.targetStake) {
|
||||||
|
grid.push({
|
||||||
|
label: t('Target liquidity'),
|
||||||
|
value: formatStake(market.data.targetStake, market),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLiquidityMonitoringAuction && market.data?.suppliedStake) {
|
||||||
|
grid.push({
|
||||||
|
label: t('Current liquidity'),
|
||||||
|
// @TODO: link this to liquidity view when https://github.com/vegaprotocol/frontend-monorepo/issues/491 is done
|
||||||
|
value: formatStake(market.data.suppliedStake, market),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (market.data?.indicativePrice) {
|
||||||
|
grid.push({
|
||||||
|
label: t('Est uncrossing price'),
|
||||||
|
value: addDecimalsFormatNumber(
|
||||||
|
market.data.indicativePrice,
|
||||||
|
market.positionDecimalPlaces
|
||||||
|
),
|
||||||
|
isEstimate: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (market.data?.indicativeVolume) {
|
||||||
|
grid.push({
|
||||||
|
label: t('Est uncrossing vol'),
|
||||||
|
value: addDecimalsFormatNumber(
|
||||||
|
market.data.indicativeVolume,
|
||||||
|
market.positionDecimalPlaces
|
||||||
|
),
|
||||||
|
isEstimate: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return grid;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TradingModeTooltipProps = {
|
||||||
|
market: Market_market;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TradingModeTooltip = ({ market }: TradingModeTooltipProps) => {
|
||||||
|
switch (market.tradingMode) {
|
||||||
|
case MarketTradingMode.Continuous: {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{t(
|
||||||
|
'This is the standard trading mode where trades are executed whenever orders are received.'
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case MarketTradingMode.OpeningAuction: {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p className="mb-16">
|
||||||
|
<span>
|
||||||
|
{t(
|
||||||
|
'This new market is in an opening auction to determine a fair mid-price before starting continuous trading.'
|
||||||
|
)}
|
||||||
|
</span>{' '}
|
||||||
|
<Link
|
||||||
|
href="https://docs.fairground.vega.xyz/docs/trading-questions/#auctions-what-happens-in-an-opening-auction"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{t('Find out more')}
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
<MarketDataGrid grid={compileGridData(market)} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case MarketTradingMode.MonitoringAuction: {
|
||||||
|
switch (market.data?.trigger) {
|
||||||
|
case AuctionTrigger.Liquidity: {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p className="mb-16">
|
||||||
|
<span>
|
||||||
|
{t(
|
||||||
|
'This market is in auction until it reaches sufficient liquidity.'
|
||||||
|
)}
|
||||||
|
</span>{' '}
|
||||||
|
<Link
|
||||||
|
href="https://docs.fairground.vega.xyz/docs/trading-questions/#auctions-what-is-a-liquidity-monitoring-auction"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{t('Find out more')}
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
<MarketDataGrid grid={compileGridData(market)} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case AuctionTrigger.Price: {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p className="mb-16">
|
||||||
|
<span>
|
||||||
|
{t('This market is in auction due to high price volatility.')}
|
||||||
|
</span>{' '}
|
||||||
|
<Link
|
||||||
|
href="https://docs.fairground.vega.xyz/docs/trading-questions/#auctions-what-is-a-price-monitoring-auction"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{t('Find out more')}
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
<MarketDataGrid grid={compileGridData(market)} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case MarketTradingMode.NoTrading: {
|
||||||
|
return <>{t('No trading enabled for this market.')}</>;
|
||||||
|
}
|
||||||
|
case MarketTradingMode.BatchAuction:
|
||||||
|
default: {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -25,13 +25,17 @@ const MARKET_QUERY = gql`
|
|||||||
market {
|
market {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
auctionStart
|
||||||
|
auctionEnd
|
||||||
markPrice
|
markPrice
|
||||||
indicativeVolume
|
indicativeVolume
|
||||||
|
indicativePrice
|
||||||
|
suppliedStake
|
||||||
|
targetStake
|
||||||
bestBidVolume
|
bestBidVolume
|
||||||
bestOfferVolume
|
bestOfferVolume
|
||||||
bestStaticBidVolume
|
bestStaticBidVolume
|
||||||
bestStaticOfferVolume
|
bestStaticOfferVolume
|
||||||
indicativeVolume
|
|
||||||
trigger
|
trigger
|
||||||
}
|
}
|
||||||
tradableInstrument {
|
tradableInstrument {
|
||||||
|
20
apps/trading/pages/markets/__generated__/Market.ts
generated
20
apps/trading/pages/markets/__generated__/Market.ts
generated
@ -23,6 +23,14 @@ export interface Market_market_data {
|
|||||||
* market id of the associated mark price
|
* market id of the associated mark price
|
||||||
*/
|
*/
|
||||||
market: Market_market_data_market;
|
market: Market_market_data_market;
|
||||||
|
/**
|
||||||
|
* RFC3339Nano time at which the next auction will start (null if none is scheduled)
|
||||||
|
*/
|
||||||
|
auctionStart: string | null;
|
||||||
|
/**
|
||||||
|
* RFC3339Nano time at which the auction will stop (null if not in auction mode)
|
||||||
|
*/
|
||||||
|
auctionEnd: string | null;
|
||||||
/**
|
/**
|
||||||
* the mark price (actually an unsigned int)
|
* the mark price (actually an unsigned int)
|
||||||
*/
|
*/
|
||||||
@ -31,6 +39,18 @@ export interface Market_market_data {
|
|||||||
* indicative volume if the auction ended now, 0 if not in auction mode
|
* indicative volume if the auction ended now, 0 if not in auction mode
|
||||||
*/
|
*/
|
||||||
indicativeVolume: string;
|
indicativeVolume: string;
|
||||||
|
/**
|
||||||
|
* indicative price if the auction ended now, 0 if not in auction mode
|
||||||
|
*/
|
||||||
|
indicativePrice: string;
|
||||||
|
/**
|
||||||
|
* the supplied stake for the market
|
||||||
|
*/
|
||||||
|
suppliedStake: string | null;
|
||||||
|
/**
|
||||||
|
* the amount of stake targeted for this market
|
||||||
|
*/
|
||||||
|
targetStake: string | null;
|
||||||
/**
|
/**
|
||||||
* the aggregated volume being bid at the best bid price.
|
* the aggregated volume being bid at the best bid price.
|
||||||
*/
|
*/
|
||||||
|
@ -25,12 +25,14 @@ import {
|
|||||||
Tab,
|
Tab,
|
||||||
Tabs,
|
Tabs,
|
||||||
PriceCellChange,
|
PriceCellChange,
|
||||||
|
Tooltip,
|
||||||
ResizablePanel,
|
ResizablePanel,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import type { CandleClose } from '@vegaprotocol/types';
|
import type { CandleClose } from '@vegaprotocol/types';
|
||||||
import { AuctionTrigger } from '@vegaprotocol/types';
|
import { AuctionTrigger } from '@vegaprotocol/types';
|
||||||
import { MarketTradingMode } from '@vegaprotocol/types';
|
import { MarketTradingMode } from '@vegaprotocol/types';
|
||||||
import { Allotment, LayoutPriority } from 'allotment';
|
import { Allotment, LayoutPriority } from 'allotment';
|
||||||
|
import { TradingModeTooltip } from '../../components/trading-mode-tooltip';
|
||||||
|
|
||||||
const TradingViews = {
|
const TradingViews = {
|
||||||
Candles: CandlesChartContainer,
|
Candles: CandlesChartContainer,
|
||||||
@ -102,18 +104,23 @@ export const TradeMarketHeader = ({
|
|||||||
: '-'}
|
: '-'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={headerItemClassName}>
|
<Tooltip
|
||||||
<span className={itemClassName}>{t('Trading mode')}</span>
|
align="start"
|
||||||
<span data-testid="trading-mode" className={itemValueClassName}>
|
description={<TradingModeTooltip market={market} />}
|
||||||
{market.tradingMode === MarketTradingMode.MonitoringAuction &&
|
>
|
||||||
market.data?.trigger &&
|
<div className={headerItemClassName}>
|
||||||
market.data.trigger !== AuctionTrigger.Unspecified
|
<span className={itemClassName}>{t('Trading mode')}</span>
|
||||||
? `${formatLabel(
|
<span data-testid="trading-mode" className={itemValueClassName}>
|
||||||
market.tradingMode
|
{market.tradingMode === MarketTradingMode.MonitoringAuction &&
|
||||||
)} - ${market.data?.trigger.toLowerCase()}`
|
market.data?.trigger &&
|
||||||
: formatLabel(market.tradingMode)}
|
market.data.trigger !== AuctionTrigger.Unspecified
|
||||||
</span>
|
? `${formatLabel(
|
||||||
</div>
|
market.tradingMode
|
||||||
|
)} - ${market.data?.trigger.toLowerCase()}`
|
||||||
|
: formatLabel(market.tradingMode)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
<div className={headerItemClassName}>
|
<div className={headerItemClassName}>
|
||||||
<span className={itemClassName}>{t('Price')}</span>
|
<span className={itemClassName}>{t('Price')}</span>
|
||||||
<span data-testid="mark-price" className={itemValueClassName}>
|
<span data-testid="mark-price" className={itemValueClassName}>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import type { ReactNode } from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
Provider,
|
Provider,
|
||||||
@ -9,7 +10,7 @@ import {
|
|||||||
|
|
||||||
export interface TooltipProps {
|
export interface TooltipProps {
|
||||||
children: React.ReactElement;
|
children: React.ReactElement;
|
||||||
description?: string;
|
description?: string | ReactNode;
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
align?: 'start' | 'center' | 'end';
|
align?: 'start' | 'center' | 'end';
|
||||||
}
|
}
|
||||||
@ -20,19 +21,19 @@ export const Tooltip = ({ children, description, open, align }: TooltipProps) =>
|
|||||||
<Provider delayDuration={200} skipDelayDuration={100}>
|
<Provider delayDuration={200} skipDelayDuration={100}>
|
||||||
<Root open={open}>
|
<Root open={open}>
|
||||||
<Trigger asChild>{children}</Trigger>
|
<Trigger asChild>{children}</Trigger>
|
||||||
<Content align={align} alignOffset={5}>
|
<Content align={align} alignOffset={8}>
|
||||||
<div className="relative z-0 p-8 bg-black-50 border border-black-60 text-white rounded-sm max-w-sm">
|
<div className="relative z-0 p-8 bg-black-50 border border-black-60 text-white rounded-sm max-w-sm">
|
||||||
{description}
|
{description}
|
||||||
</div>
|
</div>
|
||||||
<Arrow
|
<Arrow
|
||||||
width={10}
|
width={10}
|
||||||
height={5}
|
height={5}
|
||||||
className="z-[1] fill-black-60 dark:fill-white-60 z-0 translate-x-[1px] translate-y-[-1px]"
|
className="z-[1] mx-8 fill-black-60 dark:fill-white-60 z-0 translate-x-[1px] translate-y-[-1px]"
|
||||||
/>
|
/>
|
||||||
<Arrow
|
<Arrow
|
||||||
width={8}
|
width={8}
|
||||||
height={4}
|
height={4}
|
||||||
className="z-[1] translate-y-[-1px] fill-black-50"
|
className="z-[1] mx-8 translate-y-[-1px] fill-black-50"
|
||||||
/>
|
/>
|
||||||
</Content>
|
</Content>
|
||||||
</Root>
|
</Root>
|
||||||
|
Loading…
Reference in New Issue
Block a user