Feat/1003 update size (#1041)
* feat(console-lite): add notional position size to trade size selector * feat(console-lite): add estimated fees to size selector * feat(console-lite): add estimated fees to review-trade and create shared estimates component * feat(console-lite): add estimated fees as percentage
This commit is contained in:
parent
83982ee3d8
commit
900205ed12
@ -152,26 +152,68 @@ describe('Market trade', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('notional position size should be present', () => {
|
||||||
|
if (markets?.length) {
|
||||||
|
cy.visit(`/trading/${markets[1].id}`);
|
||||||
|
connectVegaWallet();
|
||||||
|
cy.get('#step-1-control [aria-label^="Selected value"]').click();
|
||||||
|
cy.get('button[aria-label="Open short position"]').click();
|
||||||
|
cy.get('#step-2-control').click();
|
||||||
|
cy.get('#step-2-panel')
|
||||||
|
.find('dd')
|
||||||
|
.eq(0)
|
||||||
|
.find('button')
|
||||||
|
.should('have.text', '1');
|
||||||
|
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
|
||||||
|
cy.get('#step-2-panel')
|
||||||
|
.find('dd')
|
||||||
|
.eq(0)
|
||||||
|
.find('input')
|
||||||
|
.type('{backspace}2');
|
||||||
|
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
|
||||||
|
cy.get('#step-2-panel')
|
||||||
|
.find('dt')
|
||||||
|
.eq(2)
|
||||||
|
.should('have.text', 'Est. Position Size (tDAI)');
|
||||||
|
cy.get('#step-2-panel').find('dd').eq(2).should('have.text', '197.86012');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('total fees should be displayed', () => {
|
||||||
|
if (markets?.length) {
|
||||||
|
cy.visit(`/trading/${markets[1].id}`);
|
||||||
|
connectVegaWallet();
|
||||||
|
cy.get('#step-1-control [aria-label^="Selected value"]').click();
|
||||||
|
cy.get('button[aria-label="Open short position"]').click();
|
||||||
|
cy.get('#step-2-control').click();
|
||||||
|
cy.get('#step-2-panel')
|
||||||
|
.find('dt')
|
||||||
|
.eq(3)
|
||||||
|
.should('have.text', 'Est. Fees (tDAI)');
|
||||||
|
cy.get('#step-2-panel')
|
||||||
|
.find('dd')
|
||||||
|
.eq(3)
|
||||||
|
.should('have.text', '3.00000 (3.03%)');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('order review should display proper calculations', () => {
|
it('order review should display proper calculations', () => {
|
||||||
if (markets?.length) {
|
if (markets?.length) {
|
||||||
cy.visit(`/trading/${markets[0].id}`);
|
cy.visit(`/trading/${markets[0].id}`);
|
||||||
connectVegaWallet();
|
connectVegaWallet();
|
||||||
cy.get('h3').contains('Review Trade').click();
|
cy.get('h3').contains('Review Trade').click();
|
||||||
cy.getByTestId('key-value-table')
|
|
||||||
.find('dl')
|
cy.get('#step-3-panel').find('dd').eq(1).should('have.text', '1');
|
||||||
.eq(1)
|
|
||||||
.find('dd div')
|
cy.get('#step-3-panel').find('dd').eq(2).should('have.text', '98.93006');
|
||||||
.should('have.text', '25.78726');
|
|
||||||
cy.getByTestId('key-value-table')
|
cy.get('#step-3-panel')
|
||||||
.find('dl')
|
.find('dd')
|
||||||
.eq(2)
|
|
||||||
.find('dd div')
|
|
||||||
.should('have.text', '1.00000');
|
|
||||||
cy.getByTestId('key-value-table')
|
|
||||||
.find('dl')
|
|
||||||
.eq(3)
|
.eq(3)
|
||||||
.find('dd div')
|
.should('have.text', '3.00000 (3.03%)');
|
||||||
.should('have.text', ' - ');
|
|
||||||
|
cy.get('#step-3-panel').find('dd').eq(4).should('have.text', ' - ');
|
||||||
|
|
||||||
cy.getByTestId('place-order').click();
|
cy.getByTestId('place-order').click();
|
||||||
cy.getByTestId('dialog-title').should(
|
cy.getByTestId('dialog-title').should(
|
||||||
'have.text',
|
'have.text',
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
export const generateEstimateOrder = () => {
|
export const generateEstimateOrder = () => {
|
||||||
return {
|
return {
|
||||||
estimateOrder: {
|
estimateOrder: {
|
||||||
totalFeeAmount: '16085.09240212.7380425.46',
|
fee: {
|
||||||
|
__typename: 'TradeFee',
|
||||||
|
makerFee: '100000',
|
||||||
|
liquidityFee: '100000',
|
||||||
|
infrastructureFee: '100000',
|
||||||
|
},
|
||||||
marginLevels: {
|
marginLevels: {
|
||||||
initialLevel: '2844054.80937741220203',
|
initialLevel: '2844054.80937741220203',
|
||||||
__typename: 'MarginLevels',
|
__typename: 'MarginLevels',
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
|
|
||||||
|
interface DealTicketEstimatesProps {
|
||||||
|
quoteName?: string;
|
||||||
|
price?: string;
|
||||||
|
estCloseOut?: string;
|
||||||
|
estMargin?: string;
|
||||||
|
fees?: string;
|
||||||
|
notionalSize?: string;
|
||||||
|
size?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DataTitleProps {
|
||||||
|
children: ReactNode;
|
||||||
|
quoteName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DataTitle = ({ children, quoteName = '' }: DataTitleProps) => (
|
||||||
|
<dt>
|
||||||
|
{children}
|
||||||
|
{quoteName && <small> ({quoteName})</small>}
|
||||||
|
</dt>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const DealTicketEstimates = ({
|
||||||
|
price,
|
||||||
|
quoteName,
|
||||||
|
estCloseOut,
|
||||||
|
estMargin,
|
||||||
|
fees,
|
||||||
|
notionalSize,
|
||||||
|
size,
|
||||||
|
}: DealTicketEstimatesProps) => (
|
||||||
|
<dl className="text-black dark:text-white">
|
||||||
|
{size && (
|
||||||
|
<div className="flex justify-between mb-8">
|
||||||
|
<DataTitle>{t('No. of Contracts')}</DataTitle>
|
||||||
|
<dd>{size}</dd>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{price && (
|
||||||
|
<div className="flex justify-between mb-8">
|
||||||
|
<DataTitle>{t('Est. Price')}</DataTitle>
|
||||||
|
<dd>{price}</dd>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{notionalSize && (
|
||||||
|
<div className="flex justify-between mb-8">
|
||||||
|
<DataTitle quoteName={quoteName}>{t('Est. Position Size')}</DataTitle>
|
||||||
|
<dd>{notionalSize}</dd>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{fees && (
|
||||||
|
<div className="flex justify-between mb-8">
|
||||||
|
<DataTitle quoteName={quoteName}>{t('Est. Fees')}</DataTitle>
|
||||||
|
<dd>{fees}</dd>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{estMargin && (
|
||||||
|
<div className="flex justify-between mb-8">
|
||||||
|
<DataTitle quoteName={quoteName}>{t('Est. Margin')}</DataTitle>
|
||||||
|
<dd>{estMargin}</dd>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{estCloseOut && (
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<dt>
|
||||||
|
<span>{t('Est. Close out')}</span>
|
||||||
|
|
||||||
|
<small>({quoteName})</small>
|
||||||
|
</dt>
|
||||||
|
<dd>{estCloseOut}</dd>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</dl>
|
||||||
|
);
|
@ -10,6 +10,7 @@ import {
|
|||||||
FormGroup,
|
FormGroup,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { BigNumber } from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
|
import { DealTicketEstimates } from './deal-ticket-estimates';
|
||||||
|
|
||||||
interface DealTicketSizeProps {
|
interface DealTicketSizeProps {
|
||||||
step: number;
|
step: number;
|
||||||
@ -22,7 +23,9 @@ interface DealTicketSizeProps {
|
|||||||
price: string;
|
price: string;
|
||||||
estCloseOut: string;
|
estCloseOut: string;
|
||||||
estMargin: string;
|
estMargin: string;
|
||||||
|
fees: string;
|
||||||
positionDecimalPlaces: number;
|
positionDecimalPlaces: number;
|
||||||
|
notionalSize: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSizeLabel = (value: number): string => {
|
const getSizeLabel = (value: number): string => {
|
||||||
@ -47,6 +50,8 @@ export const DealTicketSize = ({
|
|||||||
onValueChange,
|
onValueChange,
|
||||||
estCloseOut,
|
estCloseOut,
|
||||||
positionDecimalPlaces,
|
positionDecimalPlaces,
|
||||||
|
fees,
|
||||||
|
notionalSize,
|
||||||
}: DealTicketSizeProps) => {
|
}: DealTicketSizeProps) => {
|
||||||
const sizeRatios = [0, 25, 50, 75, 100];
|
const sizeRatios = [0, 25, 50, 75, 100];
|
||||||
const [inputValue, setInputValue] = useState(value);
|
const [inputValue, setInputValue] = useState(value);
|
||||||
@ -142,11 +147,7 @@ export const DealTicketSize = ({
|
|||||||
|
|
||||||
<dl className="text-black dark:text-white">
|
<dl className="text-black dark:text-white">
|
||||||
<div className="flex items-center justify-between mb-8">
|
<div className="flex items-center justify-between mb-8">
|
||||||
<dt>
|
<dt>{t('Contracts')}</dt>
|
||||||
<span>{t('Size')}</span>
|
|
||||||
|
|
||||||
<small>({quoteName})</small>
|
|
||||||
</dt>
|
|
||||||
<dd className="flex justify-end w-full">
|
<dd className="flex justify-end w-full">
|
||||||
<FormGroup
|
<FormGroup
|
||||||
className="mb-0 flex items-center"
|
className="mb-0 flex items-center"
|
||||||
@ -187,15 +188,14 @@ export const DealTicketSize = ({
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between mb-8">
|
|
||||||
<dt>{t('Est. price')}</dt>
|
|
||||||
<dd>{price}</dd>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<dt>{t('Est. close out')}</dt>
|
|
||||||
<dd>{estCloseOut}</dd>
|
|
||||||
</div>
|
|
||||||
</dl>
|
</dl>
|
||||||
|
<DealTicketEstimates
|
||||||
|
quoteName={quoteName}
|
||||||
|
fees={fees}
|
||||||
|
estCloseOut={estCloseOut}
|
||||||
|
price={price}
|
||||||
|
notionalSize={notionalSize}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -72,6 +72,14 @@ export const DealTicketSteps = ({
|
|||||||
market,
|
market,
|
||||||
partyId: keypair?.pub || '',
|
partyId: keypair?.pub || '',
|
||||||
});
|
});
|
||||||
|
const value = new BigNumber(orderSize).toNumber();
|
||||||
|
const price =
|
||||||
|
market.depth.lastTrade &&
|
||||||
|
addDecimal(market.depth.lastTrade.price, market.decimalPlaces);
|
||||||
|
const emptyString = ' - ';
|
||||||
|
|
||||||
|
const [notionalSize, setNotionalSize] = useState<string | null>(null);
|
||||||
|
const [fees, setFees] = useState<string | null>(null);
|
||||||
|
|
||||||
const maxTrade = useMaximumPositionSize({
|
const maxTrade = useMaximumPositionSize({
|
||||||
partyId: keypair?.pub || '',
|
partyId: keypair?.pub || '',
|
||||||
@ -112,6 +120,28 @@ export const DealTicketSteps = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (market?.depth?.lastTrade?.price) {
|
||||||
|
const size = new BigNumber(market.depth.lastTrade.price)
|
||||||
|
.multipliedBy(value)
|
||||||
|
.toNumber();
|
||||||
|
|
||||||
|
setNotionalSize(addDecimal(size, market.decimalPlaces));
|
||||||
|
}
|
||||||
|
}, [market, value]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (estMargin?.fees && notionalSize) {
|
||||||
|
const percentage = new BigNumber(estMargin?.fees)
|
||||||
|
.dividedBy(notionalSize)
|
||||||
|
.multipliedBy(100)
|
||||||
|
.decimalPlaces(2)
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
setFees(`${estMargin.fees} (${percentage}%)`);
|
||||||
|
}
|
||||||
|
}, [estMargin, notionalSize]);
|
||||||
|
|
||||||
const transactionStatus =
|
const transactionStatus =
|
||||||
transaction.status === VegaTxStatus.Requested ||
|
transaction.status === VegaTxStatus.Requested ||
|
||||||
transaction.status === VegaTxStatus.Pending
|
transaction.status === VegaTxStatus.Pending
|
||||||
@ -163,15 +193,16 @@ export const DealTicketSteps = ({
|
|||||||
onValueChange={onSizeChange}
|
onValueChange={onSizeChange}
|
||||||
value={new BigNumber(orderSize).toNumber()}
|
value={new BigNumber(orderSize).toNumber()}
|
||||||
name="size"
|
name="size"
|
||||||
price={
|
price={price || emptyString}
|
||||||
market.depth.lastTrade
|
|
||||||
? addDecimal(market.depth.lastTrade.price, market.decimalPlaces)
|
|
||||||
: ''
|
|
||||||
}
|
|
||||||
positionDecimalPlaces={market.positionDecimalPlaces}
|
positionDecimalPlaces={market.positionDecimalPlaces}
|
||||||
quoteName={market.tradableInstrument.instrument.product.quoteName}
|
quoteName={
|
||||||
|
market.tradableInstrument.instrument.product.settlementAsset
|
||||||
|
.symbol
|
||||||
|
}
|
||||||
|
notionalSize={notionalSize || emptyString}
|
||||||
estCloseOut={estCloseOut}
|
estCloseOut={estCloseOut}
|
||||||
estMargin={estMargin || ' - '}
|
fees={fees || emptyString}
|
||||||
|
estMargin={estMargin?.margin || emptyString}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
'loading...'
|
'loading...'
|
||||||
@ -193,7 +224,14 @@ export const DealTicketSteps = ({
|
|||||||
transactionStatus={transactionStatus}
|
transactionStatus={transactionStatus}
|
||||||
order={order}
|
order={order}
|
||||||
estCloseOut={estCloseOut}
|
estCloseOut={estCloseOut}
|
||||||
estMargin={estMargin || ' - '}
|
estMargin={estMargin?.margin || emptyString}
|
||||||
|
price={price || emptyString}
|
||||||
|
quoteName={
|
||||||
|
market.tradableInstrument.instrument.product.settlementAsset
|
||||||
|
.symbol
|
||||||
|
}
|
||||||
|
notionalSize={notionalSize || emptyString}
|
||||||
|
fees={fees || emptyString}
|
||||||
/>
|
/>
|
||||||
<TransactionDialog
|
<TransactionDialog
|
||||||
title={getOrderDialogTitle(finalizedOrder?.status)}
|
title={getOrderDialogTitle(finalizedOrder?.status)}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { addDecimal, formatNumber, t } from '@vegaprotocol/react-helpers';
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Icon,
|
|
||||||
KeyValueTable,
|
KeyValueTable,
|
||||||
KeyValueTableRow,
|
KeyValueTableRow,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
@ -17,7 +16,7 @@ import type {
|
|||||||
MarketTags,
|
MarketTags,
|
||||||
MarketTagsVariables,
|
MarketTagsVariables,
|
||||||
} from './__generated__/MarketTags';
|
} from './__generated__/MarketTags';
|
||||||
import { IconNames } from '@blueprintjs/icons';
|
import { DealTicketEstimates } from './deal-ticket-estimates';
|
||||||
|
|
||||||
export const MARKET_TAGS_QUERY = gql`
|
export const MARKET_TAGS_QUERY = gql`
|
||||||
query MarketTags($marketId: ID!) {
|
query MarketTags($marketId: ID!) {
|
||||||
@ -40,6 +39,10 @@ interface Props {
|
|||||||
order: Order;
|
order: Order;
|
||||||
estCloseOut: string;
|
estCloseOut: string;
|
||||||
estMargin: string;
|
estMargin: string;
|
||||||
|
quoteName: string;
|
||||||
|
price: string;
|
||||||
|
fees: string;
|
||||||
|
notionalSize: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
@ -48,7 +51,10 @@ export default ({
|
|||||||
order,
|
order,
|
||||||
transactionStatus,
|
transactionStatus,
|
||||||
estCloseOut,
|
estCloseOut,
|
||||||
estMargin,
|
quoteName,
|
||||||
|
fees,
|
||||||
|
price,
|
||||||
|
notionalSize,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { data: tagsData } = useQuery<MarketTags, MarketTagsVariables>(
|
const { data: tagsData } = useQuery<MarketTags, MarketTagsVariables>(
|
||||||
MARKET_TAGS_QUERY,
|
MARKET_TAGS_QUERY,
|
||||||
@ -88,41 +94,20 @@ export default ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-blue">
|
<div className="text-blue">
|
||||||
@{' '}
|
{`@ ${price} `}
|
||||||
{market.depth.lastTrade
|
|
||||||
? addDecimal(market.depth.lastTrade.price, market.decimalPlaces)
|
|
||||||
: ' - '}{' '}
|
|
||||||
<span className="text-ui-small inline">(EST)</span>
|
<span className="text-ui-small inline">(EST)</span>
|
||||||
</div>
|
</div>
|
||||||
</KeyValueTableRow>
|
</KeyValueTableRow>
|
||||||
<KeyValueTableRow noBorder>
|
|
||||||
<>{t('Est. margin')}</>
|
|
||||||
<div className="text-black dark:text-white flex gap-x-5 items-center">
|
|
||||||
{estMargin}
|
|
||||||
<Icon name={IconNames.ISSUE} className="rotate-180" />
|
|
||||||
</div>
|
|
||||||
</KeyValueTableRow>
|
|
||||||
<KeyValueTableRow noBorder>
|
|
||||||
<>
|
|
||||||
{t('Size')}{' '}
|
|
||||||
<div className="text-ui-small inline">
|
|
||||||
({market.tradableInstrument.instrument.product.quoteName})
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
<div className="text-black dark:text-white flex gap-x-5 items-center">
|
|
||||||
{formatNumber(order.size, market.decimalPlaces)}
|
|
||||||
<Icon name={IconNames.ISSUE} className="rotate-180" />
|
|
||||||
</div>
|
|
||||||
</KeyValueTableRow>
|
|
||||||
<KeyValueTableRow noBorder>
|
|
||||||
<>{t('Est. close out')}</>
|
|
||||||
<div className="text-black dark:text-white flex gap-x-5 items-center">
|
|
||||||
{estCloseOut}
|
|
||||||
<Icon name={IconNames.ISSUE} className="rotate-180" />
|
|
||||||
</div>
|
|
||||||
</KeyValueTableRow>
|
|
||||||
</KeyValueTable>
|
</KeyValueTable>
|
||||||
|
|
||||||
|
<DealTicketEstimates
|
||||||
|
size={order.size}
|
||||||
|
quoteName={quoteName}
|
||||||
|
fees={fees}
|
||||||
|
estCloseOut={estCloseOut}
|
||||||
|
notionalSize={notionalSize}
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className="w-full !py-8 mt-64 max-w-sm"
|
className="w-full !py-8 mt-64 max-w-sm"
|
||||||
boxShadow={false}
|
boxShadow={false}
|
||||||
|
@ -9,6 +9,22 @@ import { Side, OrderTimeInForce, OrderType } from "@vegaprotocol/types";
|
|||||||
// GraphQL query operation: EstimateOrder
|
// GraphQL query operation: EstimateOrder
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
|
||||||
|
export interface EstimateOrder_estimateOrder_fee {
|
||||||
|
__typename: "TradeFee";
|
||||||
|
/**
|
||||||
|
* The maker fee, aggressive party to the other party (the one who had an order in the book)
|
||||||
|
*/
|
||||||
|
makerFee: string;
|
||||||
|
/**
|
||||||
|
* The infrastructure fee, a fee paid to the node runner to maintain the vega network
|
||||||
|
*/
|
||||||
|
infrastructureFee: string;
|
||||||
|
/**
|
||||||
|
* The fee paid to the market makers to provide liquidity in the market
|
||||||
|
*/
|
||||||
|
liquidityFee: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface EstimateOrder_estimateOrder_marginLevels {
|
export interface EstimateOrder_estimateOrder_marginLevels {
|
||||||
__typename: "MarginLevels";
|
__typename: "MarginLevels";
|
||||||
/**
|
/**
|
||||||
@ -20,9 +36,9 @@ export interface EstimateOrder_estimateOrder_marginLevels {
|
|||||||
export interface EstimateOrder_estimateOrder {
|
export interface EstimateOrder_estimateOrder {
|
||||||
__typename: "OrderEstimate";
|
__typename: "OrderEstimate";
|
||||||
/**
|
/**
|
||||||
* The total estimated amount of fee if the order was to trade
|
* The estimated fee if the order was to trade
|
||||||
*/
|
*/
|
||||||
totalFeeAmount: string;
|
fee: EstimateOrder_estimateOrder_fee;
|
||||||
/**
|
/**
|
||||||
* The margin requirement for this order
|
* The margin requirement for this order
|
||||||
*/
|
*/
|
||||||
|
@ -8,6 +8,11 @@ import useOrderMargin from './use-order-margin';
|
|||||||
|
|
||||||
let mockEstimateData = {
|
let mockEstimateData = {
|
||||||
estimateOrder: {
|
estimateOrder: {
|
||||||
|
fee: {
|
||||||
|
makerFee: '100000.000',
|
||||||
|
infrastructureFee: '100000.000',
|
||||||
|
liquidityFee: '100000.000',
|
||||||
|
},
|
||||||
marginLevels: {
|
marginLevels: {
|
||||||
initialLevel: '200000',
|
initialLevel: '200000',
|
||||||
},
|
},
|
||||||
@ -53,7 +58,7 @@ describe('useOrderMargin Hook', () => {
|
|||||||
partyId,
|
partyId,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(result.current).toEqual('100000');
|
expect(result.current?.margin).toEqual('100000');
|
||||||
|
|
||||||
const calledSize = new BigNumber(mockMarketPositions?.openVolume || 0)
|
const calledSize = new BigNumber(mockMarketPositions?.openVolume || 0)
|
||||||
.plus(order.size)
|
.plus(order.size)
|
||||||
@ -63,6 +68,17 @@ describe('useOrderMargin Hook', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fees should be properly calculated', () => {
|
||||||
|
const { result } = renderHook(() =>
|
||||||
|
useOrderMargin({
|
||||||
|
order: order as Order,
|
||||||
|
market: market as DealTicketQuery_market,
|
||||||
|
partyId,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(result.current?.fees).toEqual('300000');
|
||||||
|
});
|
||||||
|
|
||||||
it('if there is no positions initialMargin should not be subtracted', () => {
|
it('if there is no positions initialMargin should not be subtracted', () => {
|
||||||
mockMarketPositions = null;
|
mockMarketPositions = null;
|
||||||
const { result } = renderHook(() =>
|
const { result } = renderHook(() =>
|
||||||
@ -72,7 +88,7 @@ describe('useOrderMargin Hook', () => {
|
|||||||
partyId,
|
partyId,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(result.current).toEqual('200000');
|
expect(result.current?.margin).toEqual('200000');
|
||||||
|
|
||||||
expect((useQuery as jest.Mock).mock.calls[1][1].variables.size).toEqual(
|
expect((useQuery as jest.Mock).mock.calls[1][1].variables.size).toEqual(
|
||||||
order.size
|
order.size
|
||||||
@ -82,6 +98,11 @@ describe('useOrderMargin Hook', () => {
|
|||||||
it('if api fails, should return empty value', () => {
|
it('if api fails, should return empty value', () => {
|
||||||
mockEstimateData = {
|
mockEstimateData = {
|
||||||
estimateOrder: {
|
estimateOrder: {
|
||||||
|
fee: {
|
||||||
|
makerFee: '100000.000',
|
||||||
|
infrastructureFee: '100000.000',
|
||||||
|
liquidityFee: '100000.000',
|
||||||
|
},
|
||||||
marginLevels: {
|
marginLevels: {
|
||||||
initialLevel: '',
|
initialLevel: '',
|
||||||
},
|
},
|
||||||
@ -94,7 +115,7 @@ describe('useOrderMargin Hook', () => {
|
|||||||
partyId,
|
partyId,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(result.current).toEqual(' - ');
|
expect(result.current).toEqual(null);
|
||||||
|
|
||||||
const calledSize = new BigNumber(mockMarketPositions?.openVolume || 0)
|
const calledSize = new BigNumber(mockMarketPositions?.openVolume || 0)
|
||||||
.plus(order.size)
|
.plus(order.size)
|
||||||
|
@ -4,6 +4,7 @@ import { gql, useQuery } from '@apollo/client';
|
|||||||
import type {
|
import type {
|
||||||
EstimateOrder,
|
EstimateOrder,
|
||||||
EstimateOrderVariables,
|
EstimateOrderVariables,
|
||||||
|
EstimateOrder_estimateOrder_fee,
|
||||||
} from './__generated__/estimateOrder';
|
} from './__generated__/estimateOrder';
|
||||||
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
||||||
import { OrderTimeInForce, OrderType, Side } from '@vegaprotocol/types';
|
import { OrderTimeInForce, OrderType, Side } from '@vegaprotocol/types';
|
||||||
@ -37,7 +38,11 @@ export const ESTIMATE_ORDER_QUERY = gql`
|
|||||||
expiration: $expiration
|
expiration: $expiration
|
||||||
type: $type
|
type: $type
|
||||||
) {
|
) {
|
||||||
totalFeeAmount
|
fee {
|
||||||
|
makerFee
|
||||||
|
infrastructureFee
|
||||||
|
liquidityFee
|
||||||
|
}
|
||||||
marginLevels {
|
marginLevels {
|
||||||
initialLevel
|
initialLevel
|
||||||
}
|
}
|
||||||
@ -65,7 +70,22 @@ const types: Record<VegaWalletOrderType, OrderType> = {
|
|||||||
[VegaWalletOrderType.Limit]: OrderType.Limit,
|
[VegaWalletOrderType.Limit]: OrderType.Limit,
|
||||||
};
|
};
|
||||||
|
|
||||||
const useOrderMargin = ({ order, market, partyId }: Props) => {
|
const addFees = (feeObj: EstimateOrder_estimateOrder_fee) => {
|
||||||
|
return new BigNumber(feeObj.makerFee)
|
||||||
|
.plus(feeObj.liquidityFee)
|
||||||
|
.plus(feeObj.infrastructureFee);
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface OrderMargin {
|
||||||
|
margin: string;
|
||||||
|
fees: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useOrderMargin = ({
|
||||||
|
order,
|
||||||
|
market,
|
||||||
|
partyId,
|
||||||
|
}: Props): OrderMargin | null => {
|
||||||
const marketPositions = useMarketPositions({ marketId: market.id, partyId });
|
const marketPositions = useMarketPositions({ marketId: market.id, partyId });
|
||||||
const markPriceData = useMarketData(market.id);
|
const markPriceData = useMarketData(market.id);
|
||||||
const { data } = useQuery<EstimateOrder, EstimateOrderVariables>(
|
const { data } = useQuery<EstimateOrder, EstimateOrderVariables>(
|
||||||
@ -97,17 +117,22 @@ const useOrderMargin = ({ order, market, partyId }: Props) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (data?.estimateOrder.marginLevels.initialLevel) {
|
if (data?.estimateOrder.marginLevels.initialLevel) {
|
||||||
return addDecimal(
|
const fees =
|
||||||
BigNumber.maximum(
|
data?.estimateOrder?.fee && addFees(data.estimateOrder.fee).toString();
|
||||||
0,
|
return {
|
||||||
new BigNumber(data.estimateOrder.marginLevels.initialLevel).minus(
|
margin: addDecimal(
|
||||||
marketPositions?.balance || 0
|
BigNumber.maximum(
|
||||||
)
|
0,
|
||||||
).toString(),
|
new BigNumber(data.estimateOrder.marginLevels.initialLevel).minus(
|
||||||
market.decimalPlaces
|
marketPositions?.balance || 0
|
||||||
);
|
)
|
||||||
|
).toString(),
|
||||||
|
market.decimalPlaces
|
||||||
|
),
|
||||||
|
fees: addDecimal(fees, market.decimalPlaces),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return ' - ';
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useOrderMargin;
|
export default useOrderMargin;
|
||||||
|
@ -122,14 +122,14 @@ export interface Positions_party_positions_market {
|
|||||||
/**
|
/**
|
||||||
* decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct
|
* decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct
|
||||||
* number denominated in the currency of the Market. (uint64)
|
* number denominated in the currency of the Market. (uint64)
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
* Currency Balance decimalPlaces Real Balance
|
* Currency Balance decimalPlaces Real Balance
|
||||||
* GBP 100 0 GBP 100
|
* GBP 100 0 GBP 100
|
||||||
* GBP 100 2 GBP 1.00
|
* GBP 100 2 GBP 1.00
|
||||||
* GBP 100 4 GBP 0.01
|
* GBP 100 4 GBP 0.01
|
||||||
* GBP 1 4 GBP 0.0001 ( 0.01p )
|
* GBP 1 4 GBP 0.0001 ( 0.01p )
|
||||||
*
|
*
|
||||||
* GBX (pence) 100 0 GBP 1.00 (100p )
|
* GBX (pence) 100 0 GBP 1.00 (100p )
|
||||||
* GBX (pence) 100 2 GBP 0.01 ( 1p )
|
* GBX (pence) 100 2 GBP 0.01 ( 1p )
|
||||||
* GBX (pence) 100 4 GBP 0.0001 ( 0.01p )
|
* GBX (pence) 100 4 GBP 0.0001 ( 0.01p )
|
||||||
|
Loading…
Reference in New Issue
Block a user