fix: deal ticket set market price (#2228)

This commit is contained in:
m.ray 2022-11-25 08:39:14 -05:00 committed by GitHub
parent d28ff4cfe7
commit 787a8ea1b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 94 additions and 85 deletions

View File

@ -70,11 +70,6 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
const step = toDecimal(market.positionDecimalPlaces);
const order = watch();
const { pubKey } = useVegaWallet();
const estMargin = useOrderMargin({
order,
market,
partyId: pubKey || '',
});
const { message: invalidText, isDisabled } = useOrderValidation({
market,
order,
@ -127,11 +122,18 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
);
return new BigNumber(market?.depth?.lastTrade?.price)
.multipliedBy(multiplier)
.toNumber();
.toString();
}
return null;
return undefined;
}, [market?.depth?.lastTrade?.price, order.side, slippage]);
const estMargin = useOrderMargin({
order,
market,
partyId: pubKey || '',
derivedPrice: price,
});
const formattedPrice =
price && addDecimalsFormatNumber(price, market.decimalPlaces);

View File

@ -17,7 +17,7 @@ export const MarginWarning = ({ margin, balance, asset }: Props) => {
return (
<>
<div
className="text-sm text-vega-orange mb-4"
className="text-xs text-vega-orange mb-4"
data-testid="dealticket-warning-margin"
>
<p className="mb-2">

View File

@ -5,8 +5,8 @@ import {
} from '@vegaprotocol/react-helpers';
import { Input, InputError, Tooltip } from '@vegaprotocol/ui-toolkit';
import { isMarketInAuction, validateAmount } from '../../utils';
import type { DealTicketAmountProps } from './deal-ticket-amount';
import { getMarketPrice } from '../../utils/get-price';
export type DealTicketMarketAmountProps = Omit<
DealTicketAmountProps,
@ -21,21 +21,7 @@ export const DealTicketMarketAmount = ({
const quoteName =
market.tradableInstrument.instrument.product.settlementAsset.symbol;
const sizeStep = toDecimal(market?.positionDecimalPlaces);
let price;
if (isMarketInAuction(market)) {
// 0 can never be a valid uncrossing price
// as it would require there being orders on the book at that price.
if (
market.data?.indicativePrice &&
market.data.indicativePrice !== '0' &&
BigInt(market.data?.indicativePrice) !== BigInt(0)
) {
price = market.data.indicativePrice;
}
} else {
price = market.depth?.lastTrade?.price;
}
const price = getMarketPrice(market);
const priceFormatted = price
? addDecimalsFormatNumber(price, market.decimalPlaces)

View File

@ -69,7 +69,7 @@ describe('DealTicket', () => {
// Assert last price is shown
expect(screen.getByTestId('last-price')).toHaveTextContent(
// eslint-disable-next-line
`~${addDecimal(market!.depth!.lastTrade!.price, market.decimalPlaces)} ${
`~${addDecimal(market!.data.markPrice, market.decimalPlaces)} ${
market.tradableInstrument.instrument.product.settlementAsset.symbol
}`
);

View File

@ -63,9 +63,11 @@ export const DealTicket = ({
const order = watch();
// When order state changes persist it in local storage
useEffect(() => setPersistedOrder(order), [order, setPersistedOrder]);
const hasNoBalance = useHasNoBalance(
market.tradableInstrument.instrument.product.settlementAsset.id
);
const onSubmit = useCallback(
(order: OrderSubmissionBody['orderSubmission']) => {
if (!pubKey) {

View File

@ -1,5 +1,6 @@
import { FeesBreakdown } from '@vegaprotocol/market-info';
import {
addDecimal,
addDecimalsFormatNumber,
formatNumber,
t,
@ -20,34 +21,39 @@ import { useCalculateSlippage } from './use-calculate-slippage';
import { useOrderCloseOut } from './use-order-closeout';
import { useOrderMargin } from './use-order-margin';
import type { OrderMargin } from './use-order-margin';
import { getDerivedPrice } from '../utils/get-price';
export const useFeeDealTicketDetails = (
order: OrderSubmissionBody['orderSubmission'],
market: MarketDealTicket
) => {
const { pubKey } = useVegaWallet();
const slippage = useCalculateSlippage({ marketId: market.id, order });
const price = useMemo(() => {
const estPrice = order.price || market.data.markPrice;
if (estPrice) {
const derivedPrice = useMemo(() => {
return getDerivedPrice(order, market);
}, [order, market]);
// Note this isn't currently used anywhere
const slippageAdjustedPrice = useMemo(() => {
if (derivedPrice) {
if (slippage && parseFloat(slippage) !== 0) {
const isLong = order.side === Schema.Side.SIDE_BUY;
const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus'](
parseFloat(slippage) / 100
);
return new BigNumber(estPrice).multipliedBy(multiplier).toNumber();
return new BigNumber(derivedPrice).multipliedBy(multiplier).toNumber();
}
return order.price;
return derivedPrice;
}
return null;
}, [market.data.markPrice, order.price, order.side, slippage]);
}, [derivedPrice, order.side, slippage]);
const estMargin: OrderMargin | null = useOrderMargin({
order,
market,
partyId: pubKey || '',
derivedPrice,
});
const { data: partyBalance } = usePartyBalanceQuery({
@ -62,11 +68,13 @@ export const useFeeDealTicketDetails = (
});
const notionalSize = useMemo(() => {
if (order.price && order.size) {
return new BigNumber(order.size).multipliedBy(order.price).toString();
if (derivedPrice && order.size) {
return new BigNumber(order.size)
.multipliedBy(addDecimal(derivedPrice, market.decimalPlaces))
.toString();
}
return null;
}, [order.price, order.size]);
}, [derivedPrice, order.size, market.decimalPlaces]);
const quoteName = market.tradableInstrument.instrument.product.quoteName;
@ -78,7 +86,7 @@ export const useFeeDealTicketDetails = (
estMargin,
estCloseOut,
slippage,
price,
slippageAdjustedPrice,
partyData: partyBalance,
};
}, [
@ -88,7 +96,7 @@ export const useFeeDealTicketDetails = (
estMargin,
estCloseOut,
slippage,
price,
slippageAdjustedPrice,
partyBalance,
]);
};
@ -100,7 +108,6 @@ export interface FeeDetails {
estMargin: OrderMargin | null;
estCloseOut: string | null;
slippage: string | null;
price?: string | number | null;
}
export const getFeeDetailsValues = ({

View File

@ -5,6 +5,7 @@ import type { PositionMargin } from './use-market-positions';
import type { Props } from './use-order-margin';
import { useOrderMargin } from './use-order-margin';
import { Schema } from '@vegaprotocol/types';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
let mockEstimateData = {
estimateOrder: {
@ -58,7 +59,7 @@ describe('useOrderMargin', () => {
indicativePrice: '100',
markPrice: '200',
},
},
} as MarketDealTicket,
partyId: 'partyId',
};

View File

@ -1,27 +1,16 @@
import { BigNumber } from 'bignumber.js';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { Schema } from '@vegaprotocol/types';
import { removeDecimal } from '@vegaprotocol/react-helpers';
import { useMarketPositions } from './use-market-positions';
import type { EstimateOrderQuery } from './__generated__/EstimateOrder';
import { useEstimateOrderQuery } from './__generated__/EstimateOrder';
import { isMarketInAuction } from '../utils';
interface Market {
id: string;
decimalPlaces: number;
positionDecimalPlaces: number;
tradingMode: Schema.MarketTradingMode;
data: {
indicativePrice: string;
markPrice: string;
};
}
import type { MarketDealTicket } from '@vegaprotocol/market-list';
export interface Props {
order: OrderSubmissionBody['orderSubmission'];
market: Market;
market: MarketDealTicket;
partyId: string;
derivedPrice?: string;
}
const addFees = (feeObj: EstimateOrderQuery['estimateOrder']['fee']) => {
@ -44,21 +33,21 @@ export const useOrderMargin = ({
order,
market,
partyId,
derivedPrice,
}: Props): OrderMargin | null => {
const marketPositions = useMarketPositions({ marketId: market.id, partyId });
const priceForEstimate = getPriceForEstimate(order, market);
const { data } = useEstimateOrderQuery({
variables: {
marketId: market.id,
partyId,
price: priceForEstimate,
price: derivedPrice,
size: removeDecimal(order.size, market.positionDecimalPlaces),
side: order.side,
timeInForce: order.timeInForce,
type: order.type,
},
skip: !partyId || !market.id || !order.size || !priceForEstimate,
skip: !partyId || !market.id || !order.size || !derivedPrice,
});
if (data?.estimateOrder.marginLevels.initialLevel) {
@ -86,32 +75,3 @@ export const useOrderMargin = ({
}
return null;
};
/**
* Gets a price to use for estimating order margin and fees.
* Market orders should use the markPrice or if in auction mode
* the indicative price. If its a limit order use user input price.
*/
const getPriceForEstimate = (
order: {
type: Schema.OrderType;
price?: string | undefined;
},
market: Market
) => {
// If order type is market we should use either the mark price
// or the uncrossing price. If order type is limit use the price
// the user has input
let price;
if (order.type === Schema.OrderType.TYPE_LIMIT && order.price) {
price = removeDecimal(order.price, market.decimalPlaces);
} else {
if (isMarketInAuction(market)) {
price = market.data.indicativePrice;
} else {
price = market.data.markPrice;
}
}
return price === '0' ? undefined : price;
};

View File

@ -0,0 +1,51 @@
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { removeDecimal } from '@vegaprotocol/react-helpers';
import { Schema } from '@vegaprotocol/types';
import { isMarketInAuction } from './is-market-in-auction';
/**
* Get the market price based on market mode (auction or not auction)
*/
export const getMarketPrice = (market: MarketDealTicket) => {
if (isMarketInAuction(market)) {
// 0 can never be a valid uncrossing price
// as it would require there being orders on the book at that price.
if (
market.data?.indicativePrice &&
market.data.indicativePrice !== '0' &&
BigInt(market.data?.indicativePrice) !== BigInt(0)
) {
return market.data.indicativePrice;
}
} else {
return market.data.markPrice;
}
return undefined;
};
/**
* Gets the price for an order, order limit this is the user
* entered value, for market this will be the mark price or
* if in auction the indicative uncrossing price
*/
export const getDerivedPrice = (
order: {
type: Schema.OrderType;
price?: string | undefined;
},
market: MarketDealTicket
) => {
// If order type is market we should use either the mark price
// or the uncrossing price. If order type is limit use the price
// the user has input
// Use the market price if order is a market order
let price;
if (order.type === Schema.OrderType.TYPE_LIMIT && order.price) {
price = removeDecimal(order.price, market.decimalPlaces);
} else {
price = getMarketPrice(market);
}
return price === '0' ? undefined : price;
};