chore(trading,positions): update estimatePosition query to use market decimals for liquidation price (#5005)

This commit is contained in:
Matthew Russell 2023-10-24 17:30:17 -07:00 committed by GitHub
parent c7d0025b4f
commit d85f413e41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 103 additions and 35 deletions

View File

@ -33,7 +33,7 @@ import BigNumber from 'bignumber.js';
import classNames from 'classnames';
import { AccountsActionsDropdown } from './accounts-actions-dropdown';
const colorClass = (percentageUsed: number, neutral = false) => {
const colorClass = (percentageUsed: number) => {
return classNames('text-right', {
'text-vega-orange': percentageUsed >= 75 && percentageUsed < 90,
'text-vega-red': percentageUsed >= 90,
@ -210,7 +210,7 @@ export const AccountTable = ({
},
cellClass: ({ data }) => {
const percentageUsed = percentageValue(data?.used, data?.total);
return colorClass(percentageUsed, true);
return colorClass(percentageUsed);
},
valueFormatter: ({
value,
@ -270,7 +270,8 @@ export const AccountTable = ({
onClickDeposit && onClickDeposit(assetId);
}}
>
<VegaIcon name={VegaIconNames.DEPOSIT} /> {t('Deposit')}
<VegaIcon name={VegaIconNames.DEPOSIT} size={14} />{' '}
{t('Deposit')}
</TradingButton>
</CenteredGridCellWrapper>
);

View File

@ -259,11 +259,9 @@ export const DealTicketMarginDetails = ({
? liquidationEstimateWorstCaseIncludingBuyOrders
: 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(
liquidationEstimateWorstCase.toString(),
assetDecimals,
market.decimalPlaces,
undefined,
market.decimalPlaces
);
@ -276,7 +274,7 @@ export const DealTicketMarginDetails = ({
? liquidationEstimateBestCase
: liquidationEstimateWorstCase
).toString(),
assetDecimals,
market.decimalPlaces,
undefined,
market.decimalPlaces
);
@ -308,7 +306,7 @@ export const DealTicketMarginDetails = ({
key={'value-dropdown'}
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)}>
<span className="text-muted">{t('Margin required')}</span>
</Tooltip>

View File

@ -49,6 +49,11 @@ query EstimatePosition(
openVolume: $openVolume
orders: $orders
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 {
worstCase {

View File

@ -130,6 +130,7 @@ export const EstimatePositionDocument = gql`
openVolume: $openVolume
orders: $orders
collateralAvailable: $collateralAvailable
scaleLiquidationPriceToMarketDecimals: true
) {
margin {
worstCase {

View 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)
);
});
});

View File

@ -8,20 +8,12 @@ export const LiquidationPrice = ({
openVolume,
collateralAvailable,
decimalPlaces,
formatDecimals,
}: {
marketId: string;
openVolume: string;
collateralAvailable: string;
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({
variables: {
marketId,
@ -38,21 +30,11 @@ export const LiquidationPrice = ({
return <span>-</span>;
}
let bestCase = '-';
let worstCase = '-';
let bestCase = data.estimatePosition.liquidation.bestCase.open_volume_only;
let worstCase = data.estimatePosition.liquidation.worstCase.open_volume_only;
bestCase =
data.estimatePosition?.liquidation?.bestCase.open_volume_only.replace(
/\..*/,
''
);
worstCase =
data.estimatePosition?.liquidation?.worstCase.open_volume_only.replace(
/\..*/,
''
);
worstCase = addDecimalsFormatNumber(worstCase, decimalPlaces, formatDecimals);
bestCase = addDecimalsFormatNumber(bestCase, decimalPlaces, formatDecimals);
worstCase = addDecimalsFormatNumber(worstCase, decimalPlaces, decimalPlaces);
bestCase = addDecimalsFormatNumber(bestCase, decimalPlaces, decimalPlaces);
return (
<Tooltip

View File

@ -339,16 +339,12 @@ export const PositionsTable = ({
if (!data) {
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 (
<LiquidationPrice
marketId={data.marketId}
openVolume={data.openVolume}
collateralAvailable={data.totalBalance}
decimalPlaces={data.assetDecimals}
formatDecimals={data.marketDecimalPlaces}
decimalPlaces={data.marketDecimalPlaces}
/>
);
},