fix: deal ticket set market price (#2228)
This commit is contained in:
parent
d28ff4cfe7
commit
787a8ea1b3
@ -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);
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}`
|
||||
);
|
||||
|
@ -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) {
|
||||
|
@ -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 = ({
|
||||
|
@ -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',
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
51
libs/deal-ticket/src/utils/get-price.ts
Normal file
51
libs/deal-ticket/src/utils/get-price.ts
Normal 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;
|
||||
};
|
Loading…
Reference in New Issue
Block a user