chore(trading,positions): update estimatePosition query to use market decimals for liquidation price (#5005)
This commit is contained in:
parent
c7d0025b4f
commit
d85f413e41
@ -33,7 +33,7 @@ import BigNumber from 'bignumber.js';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { AccountsActionsDropdown } from './accounts-actions-dropdown';
|
import { AccountsActionsDropdown } from './accounts-actions-dropdown';
|
||||||
|
|
||||||
const colorClass = (percentageUsed: number, neutral = false) => {
|
const colorClass = (percentageUsed: number) => {
|
||||||
return classNames('text-right', {
|
return classNames('text-right', {
|
||||||
'text-vega-orange': percentageUsed >= 75 && percentageUsed < 90,
|
'text-vega-orange': percentageUsed >= 75 && percentageUsed < 90,
|
||||||
'text-vega-red': percentageUsed >= 90,
|
'text-vega-red': percentageUsed >= 90,
|
||||||
@ -210,7 +210,7 @@ export const AccountTable = ({
|
|||||||
},
|
},
|
||||||
cellClass: ({ data }) => {
|
cellClass: ({ data }) => {
|
||||||
const percentageUsed = percentageValue(data?.used, data?.total);
|
const percentageUsed = percentageValue(data?.used, data?.total);
|
||||||
return colorClass(percentageUsed, true);
|
return colorClass(percentageUsed);
|
||||||
},
|
},
|
||||||
valueFormatter: ({
|
valueFormatter: ({
|
||||||
value,
|
value,
|
||||||
@ -270,7 +270,8 @@ export const AccountTable = ({
|
|||||||
onClickDeposit && onClickDeposit(assetId);
|
onClickDeposit && onClickDeposit(assetId);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<VegaIcon name={VegaIconNames.DEPOSIT} /> {t('Deposit')}
|
<VegaIcon name={VegaIconNames.DEPOSIT} size={14} />{' '}
|
||||||
|
{t('Deposit')}
|
||||||
</TradingButton>
|
</TradingButton>
|
||||||
</CenteredGridCellWrapper>
|
</CenteredGridCellWrapper>
|
||||||
);
|
);
|
||||||
|
@ -259,11 +259,9 @@ export const DealTicketMarginDetails = ({
|
|||||||
? liquidationEstimateWorstCaseIncludingBuyOrders
|
? liquidationEstimateWorstCaseIncludingBuyOrders
|
||||||
: liquidationEstimateWorstCaseIncludingSellOrders;
|
: liquidationEstimateWorstCaseIncludingSellOrders;
|
||||||
|
|
||||||
// The estimate order query API gives us the liquidation price in formatted by asset decimals.
|
|
||||||
// We need to calculate it with asset decimals, but display it with market decimals precision until the API changes.
|
|
||||||
liquidationPriceEstimate = formatValue(
|
liquidationPriceEstimate = formatValue(
|
||||||
liquidationEstimateWorstCase.toString(),
|
liquidationEstimateWorstCase.toString(),
|
||||||
assetDecimals,
|
market.decimalPlaces,
|
||||||
undefined,
|
undefined,
|
||||||
market.decimalPlaces
|
market.decimalPlaces
|
||||||
);
|
);
|
||||||
@ -276,7 +274,7 @@ export const DealTicketMarginDetails = ({
|
|||||||
? liquidationEstimateBestCase
|
? liquidationEstimateBestCase
|
||||||
: liquidationEstimateWorstCase
|
: liquidationEstimateWorstCase
|
||||||
).toString(),
|
).toString(),
|
||||||
assetDecimals,
|
market.decimalPlaces,
|
||||||
undefined,
|
undefined,
|
||||||
market.decimalPlaces
|
market.decimalPlaces
|
||||||
);
|
);
|
||||||
@ -308,7 +306,7 @@ export const DealTicketMarginDetails = ({
|
|||||||
key={'value-dropdown'}
|
key={'value-dropdown'}
|
||||||
className="flex items-center justify-between w-full gap-2"
|
className="flex items-center justify-between w-full gap-2"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-1 text-left">
|
<div className="flex items-center text-left gap-1">
|
||||||
<Tooltip description={MARGIN_DIFF_TOOLTIP_TEXT(assetSymbol)}>
|
<Tooltip description={MARGIN_DIFF_TOOLTIP_TEXT(assetSymbol)}>
|
||||||
<span className="text-muted">{t('Margin required')}</span>
|
<span className="text-muted">{t('Margin required')}</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -49,6 +49,11 @@ query EstimatePosition(
|
|||||||
openVolume: $openVolume
|
openVolume: $openVolume
|
||||||
orders: $orders
|
orders: $orders
|
||||||
collateralAvailable: $collateralAvailable
|
collateralAvailable: $collateralAvailable
|
||||||
|
# Everywhere in the codebase we expect price values of the underlying to have the right
|
||||||
|
# number of digits for formatting with market.decimalPlaces. By default the estimatePosition
|
||||||
|
# query will return a full value requiring formatting using asset.decimals. For consistency
|
||||||
|
# we can set this variable to true so that we can format with market.decimalPlaces
|
||||||
|
scaleLiquidationPriceToMarketDecimals: true
|
||||||
) {
|
) {
|
||||||
margin {
|
margin {
|
||||||
worstCase {
|
worstCase {
|
||||||
|
@ -130,6 +130,7 @@ export const EstimatePositionDocument = gql`
|
|||||||
openVolume: $openVolume
|
openVolume: $openVolume
|
||||||
orders: $orders
|
orders: $orders
|
||||||
collateralAvailable: $collateralAvailable
|
collateralAvailable: $collateralAvailable
|
||||||
|
scaleLiquidationPriceToMarketDecimals: true
|
||||||
) {
|
) {
|
||||||
margin {
|
margin {
|
||||||
worstCase {
|
worstCase {
|
||||||
|
85
libs/positions/src/lib/liquidation-price.spec.tsx
Normal file
85
libs/positions/src/lib/liquidation-price.spec.tsx
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import type { MockedResponse } from '@apollo/client/testing';
|
||||||
|
import { render, screen, within } from '@testing-library/react';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { EstimatePositionDocument } from './__generated__/Positions';
|
||||||
|
import type { EstimatePositionQuery } from './__generated__/Positions';
|
||||||
|
import { LiquidationPrice } from './liquidation-price';
|
||||||
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
|
describe('LiquidationPrice', () => {
|
||||||
|
const props = {
|
||||||
|
marketId: 'market-id',
|
||||||
|
openVolume: '100',
|
||||||
|
collateralAvailable: '1000',
|
||||||
|
decimalPlaces: 2,
|
||||||
|
};
|
||||||
|
const worstCaseOpenVolume = '200';
|
||||||
|
const bestCaseOpenVolume = '100';
|
||||||
|
const mock: MockedResponse<EstimatePositionQuery> = {
|
||||||
|
request: {
|
||||||
|
query: EstimatePositionDocument,
|
||||||
|
variables: {
|
||||||
|
marketId: props.marketId,
|
||||||
|
openVolume: props.openVolume,
|
||||||
|
collateralAvailable: props.collateralAvailable,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
data: {
|
||||||
|
estimatePosition: {
|
||||||
|
margin: {
|
||||||
|
worstCase: {
|
||||||
|
maintenanceLevel: '100',
|
||||||
|
searchLevel: '100',
|
||||||
|
initialLevel: '100',
|
||||||
|
collateralReleaseLevel: '100',
|
||||||
|
},
|
||||||
|
bestCase: {
|
||||||
|
maintenanceLevel: '100',
|
||||||
|
searchLevel: '100',
|
||||||
|
initialLevel: '100',
|
||||||
|
collateralReleaseLevel: '100',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
liquidation: {
|
||||||
|
worstCase: {
|
||||||
|
open_volume_only: worstCaseOpenVolume,
|
||||||
|
including_buy_orders: '100',
|
||||||
|
including_sell_orders: '100',
|
||||||
|
},
|
||||||
|
bestCase: {
|
||||||
|
open_volume_only: bestCaseOpenVolume,
|
||||||
|
including_buy_orders: '100',
|
||||||
|
including_sell_orders: '100',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
it('correctly formats best and worst case values for the tooltip', async () => {
|
||||||
|
render(
|
||||||
|
<MockedProvider mocks={[mock]}>
|
||||||
|
<LiquidationPrice {...props} />
|
||||||
|
</MockedProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('-')).toBeInTheDocument();
|
||||||
|
const el = await screen.findByTestId('liquidation-price');
|
||||||
|
expect(el).toHaveTextContent(
|
||||||
|
addDecimalsFormatNumber(worstCaseOpenVolume, props.decimalPlaces)
|
||||||
|
);
|
||||||
|
await userEvent.hover(el);
|
||||||
|
const tooltip = within(await screen.findByRole('tooltip'));
|
||||||
|
expect(
|
||||||
|
tooltip.getByText('Worst case').nextElementSibling
|
||||||
|
).toHaveTextContent(
|
||||||
|
addDecimalsFormatNumber(worstCaseOpenVolume, props.decimalPlaces)
|
||||||
|
);
|
||||||
|
expect(tooltip.getByText('Best case').nextElementSibling).toHaveTextContent(
|
||||||
|
addDecimalsFormatNumber(bestCaseOpenVolume, props.decimalPlaces)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -8,20 +8,12 @@ export const LiquidationPrice = ({
|
|||||||
openVolume,
|
openVolume,
|
||||||
collateralAvailable,
|
collateralAvailable,
|
||||||
decimalPlaces,
|
decimalPlaces,
|
||||||
formatDecimals,
|
|
||||||
}: {
|
}: {
|
||||||
marketId: string;
|
marketId: string;
|
||||||
openVolume: string;
|
openVolume: string;
|
||||||
collateralAvailable: string;
|
collateralAvailable: string;
|
||||||
decimalPlaces: number;
|
decimalPlaces: number;
|
||||||
formatDecimals: number;
|
|
||||||
}) => {
|
}) => {
|
||||||
// NOTE!
|
|
||||||
//
|
|
||||||
// The estimate order query API gives us the liquidation price unformatted but expecting to be converted
|
|
||||||
// using asset decimal placse.
|
|
||||||
//
|
|
||||||
// We need to convert it with asset decimals, but display it formatted with market decimals precision until the API changes.
|
|
||||||
const { data: currentData, previousData } = useEstimatePositionQuery({
|
const { data: currentData, previousData } = useEstimatePositionQuery({
|
||||||
variables: {
|
variables: {
|
||||||
marketId,
|
marketId,
|
||||||
@ -38,21 +30,11 @@ export const LiquidationPrice = ({
|
|||||||
return <span>-</span>;
|
return <span>-</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bestCase = '-';
|
let bestCase = data.estimatePosition.liquidation.bestCase.open_volume_only;
|
||||||
let worstCase = '-';
|
let worstCase = data.estimatePosition.liquidation.worstCase.open_volume_only;
|
||||||
|
|
||||||
bestCase =
|
worstCase = addDecimalsFormatNumber(worstCase, decimalPlaces, decimalPlaces);
|
||||||
data.estimatePosition?.liquidation?.bestCase.open_volume_only.replace(
|
bestCase = addDecimalsFormatNumber(bestCase, decimalPlaces, decimalPlaces);
|
||||||
/\..*/,
|
|
||||||
''
|
|
||||||
);
|
|
||||||
worstCase =
|
|
||||||
data.estimatePosition?.liquidation?.worstCase.open_volume_only.replace(
|
|
||||||
/\..*/,
|
|
||||||
''
|
|
||||||
);
|
|
||||||
worstCase = addDecimalsFormatNumber(worstCase, decimalPlaces, formatDecimals);
|
|
||||||
bestCase = addDecimalsFormatNumber(bestCase, decimalPlaces, formatDecimals);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
@ -339,16 +339,12 @@ export const PositionsTable = ({
|
|||||||
if (!data) {
|
if (!data) {
|
||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
// The estimate order query API gives us the liquidation price unformatted but expecting
|
|
||||||
// conversion using asset decimals. We need to convert it with asset decimals, but format
|
|
||||||
// it with market decimals precision until the API changes.
|
|
||||||
return (
|
return (
|
||||||
<LiquidationPrice
|
<LiquidationPrice
|
||||||
marketId={data.marketId}
|
marketId={data.marketId}
|
||||||
openVolume={data.openVolume}
|
openVolume={data.openVolume}
|
||||||
collateralAvailable={data.totalBalance}
|
collateralAvailable={data.totalBalance}
|
||||||
decimalPlaces={data.assetDecimals}
|
decimalPlaces={data.marketDecimalPlaces}
|
||||||
formatDecimals={data.marketDecimalPlaces}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user