feat: [console-lite] - fixes in order close out calcs (#934)
* feat: [console-lite] - fixes in order close out calcs * feat: [console-lite] - fixes in order close out calcs - adjust int test * feat: [console-lite] - fixes in order close out calcs - adjust int test * feat: [console-lite] - fixes in order close out calcs - adjust int test * feat: [console-lite] - fixes in order close out calcs - add dash instead 0 * feat: [console-lite] - fixes in order close out calcs - add dash instead 0 Co-authored-by: maciek <maciek@vegaprotocol.io>
This commit is contained in:
parent
45d05b38f9
commit
f0e37e4a2f
@ -5,6 +5,8 @@ import { generateMarketTags } from '../support/mocks/generate-market-tags';
|
|||||||
import { generateMarketPositions } from '../support/mocks/generate-market-positions';
|
import { generateMarketPositions } from '../support/mocks/generate-market-positions';
|
||||||
import { generateEstimateOrder } from '../support/mocks/generate-estimate-order';
|
import { generateEstimateOrder } from '../support/mocks/generate-estimate-order';
|
||||||
import { generatePartyBalance } from '../support/mocks/generate-party-balance';
|
import { generatePartyBalance } from '../support/mocks/generate-party-balance';
|
||||||
|
import { generatePartyMarketData } from '../support/mocks/generate-party-market-data';
|
||||||
|
import { generateMarketMarkPrice } from '../support/mocks/generate-market-mark-price';
|
||||||
|
|
||||||
const connectVegaWallet = () => {
|
const connectVegaWallet = () => {
|
||||||
const form = 'rest-connector-form';
|
const form = 'rest-connector-form';
|
||||||
@ -28,6 +30,8 @@ describe('Market trade', () => {
|
|||||||
aliasQuery(req, 'MarketPositions', generateMarketPositions());
|
aliasQuery(req, 'MarketPositions', generateMarketPositions());
|
||||||
aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
|
aliasQuery(req, 'EstimateOrder', generateEstimateOrder());
|
||||||
aliasQuery(req, 'PartyBalanceQuery', generatePartyBalance());
|
aliasQuery(req, 'PartyBalanceQuery', generatePartyBalance());
|
||||||
|
aliasQuery(req, 'PartyMarketData', generatePartyMarketData());
|
||||||
|
aliasQuery(req, 'MarketMarkPrice', generateMarketMarkPrice());
|
||||||
});
|
});
|
||||||
cy.visit('/markets');
|
cy.visit('/markets');
|
||||||
cy.wait('@SimpleMarkets').then((response) => {
|
cy.wait('@SimpleMarkets').then((response) => {
|
||||||
@ -104,7 +108,7 @@ describe('Market trade', () => {
|
|||||||
.find('dl')
|
.find('dl')
|
||||||
.eq(3)
|
.eq(3)
|
||||||
.find('dd div')
|
.find('dd div')
|
||||||
.should('have.text', '-785.81045');
|
.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',
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
export const generateMarketMarkPrice = () => {
|
||||||
|
return {
|
||||||
|
market: {
|
||||||
|
decimalPlaces: 5,
|
||||||
|
data: { markPrice: '692748', __typename: 'MarketData' },
|
||||||
|
__typename: 'Market',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,19 @@
|
|||||||
|
export const generatePartyMarketData = () => {
|
||||||
|
return {
|
||||||
|
party: {
|
||||||
|
id: '2e1ef32e5804e14232406aebaad719087d326afa5c648b7824d0823d8a46c8d1',
|
||||||
|
accounts: [
|
||||||
|
{
|
||||||
|
type: 'General',
|
||||||
|
balance: '1200000',
|
||||||
|
asset: { id: 'fBTC', decimals: 5, __typename: 'Asset' },
|
||||||
|
market: null,
|
||||||
|
__typename: 'Account',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
marginsConnection: { edges: null, __typename: 'MarginConnection' },
|
||||||
|
positionsConnection: { edges: null, __typename: 'PositionConnection' },
|
||||||
|
__typename: 'Party',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import * as React from 'react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import {
|
import {
|
||||||
render,
|
render,
|
||||||
@ -60,6 +60,7 @@ describe('SimpleMarketList', () => {
|
|||||||
};
|
};
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(
|
render(
|
||||||
|
// @ts-ignore different versions of react types in apollo and app
|
||||||
<MockedProvider mocks={[mocks, filterMock]}>
|
<MockedProvider mocks={[mocks, filterMock]}>
|
||||||
<SimpleMarketList />
|
<SimpleMarketList />
|
||||||
</MockedProvider>,
|
</MockedProvider>,
|
||||||
@ -129,6 +130,7 @@ describe('SimpleMarketList', () => {
|
|||||||
};
|
};
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(
|
render(
|
||||||
|
// @ts-ignore different versions of react types in apollo and app
|
||||||
<MockedProvider mocks={[mocks, filterMock]}>
|
<MockedProvider mocks={[mocks, filterMock]}>
|
||||||
<SimpleMarketList />
|
<SimpleMarketList />
|
||||||
</MockedProvider>,
|
</MockedProvider>,
|
||||||
|
@ -59,6 +59,7 @@ describe('SimpleMarketToolbar', () => {
|
|||||||
|
|
||||||
it('should be properly rendered', async () => {
|
it('should be properly rendered', async () => {
|
||||||
render(
|
render(
|
||||||
|
// @ts-ignore different versions of react types in apollo and app
|
||||||
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
||||||
<WrappedCompForTest />
|
<WrappedCompForTest />
|
||||||
</MockedProvider>,
|
</MockedProvider>,
|
||||||
@ -83,6 +84,7 @@ describe('SimpleMarketToolbar', () => {
|
|||||||
|
|
||||||
it('navigation should work well', async () => {
|
it('navigation should work well', async () => {
|
||||||
render(
|
render(
|
||||||
|
// @ts-ignore different versions of react types in apollo and app
|
||||||
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
||||||
<WrappedCompForTest />
|
<WrappedCompForTest />
|
||||||
</MockedProvider>,
|
</MockedProvider>,
|
||||||
|
52
apps/simple-trading-app/src/app/hooks/__generated__/MarketMarkPrice.ts
generated
Normal file
52
apps/simple-trading-app/src/app/hooks/__generated__/MarketMarkPrice.ts
generated
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @generated
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL query operation: MarketMarkPrice
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface MarketMarkPrice_market_data {
|
||||||
|
__typename: "MarketData";
|
||||||
|
/**
|
||||||
|
* the mark price (actually an unsigned int)
|
||||||
|
*/
|
||||||
|
markPrice: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MarketMarkPrice_market {
|
||||||
|
__typename: "Market";
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* Currency Balance decimalPlaces Real Balance
|
||||||
|
* GBP 100 0 GBP 100
|
||||||
|
* GBP 100 2 GBP 1.00
|
||||||
|
* GBP 100 4 GBP 0.01
|
||||||
|
* GBP 1 4 GBP 0.0001 ( 0.01p )
|
||||||
|
*
|
||||||
|
* GBX (pence) 100 0 GBP 1.00 (100p )
|
||||||
|
* GBX (pence) 100 2 GBP 0.01 ( 1p )
|
||||||
|
* GBX (pence) 100 4 GBP 0.0001 ( 0.01p )
|
||||||
|
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
|
||||||
|
*/
|
||||||
|
decimalPlaces: number;
|
||||||
|
/**
|
||||||
|
* marketData for the given market
|
||||||
|
*/
|
||||||
|
data: MarketMarkPrice_market_data | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MarketMarkPrice {
|
||||||
|
/**
|
||||||
|
* An instrument that is trading on the VEGA network
|
||||||
|
*/
|
||||||
|
market: MarketMarkPrice_market | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MarketMarkPriceVariables {
|
||||||
|
marketId: string;
|
||||||
|
}
|
118
apps/simple-trading-app/src/app/hooks/__generated__/PartyMarketData.ts
generated
Normal file
118
apps/simple-trading-app/src/app/hooks/__generated__/PartyMarketData.ts
generated
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @generated
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
import { AccountType } from "@vegaprotocol/types";
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL query operation: PartyMarketData
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface PartyMarketData_party_accounts_asset {
|
||||||
|
__typename: "Asset";
|
||||||
|
/**
|
||||||
|
* The id of the asset
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* The precision of the asset
|
||||||
|
*/
|
||||||
|
decimals: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PartyMarketData_party_accounts_market {
|
||||||
|
__typename: "Market";
|
||||||
|
/**
|
||||||
|
* Market ID
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PartyMarketData_party_accounts {
|
||||||
|
__typename: "Account";
|
||||||
|
/**
|
||||||
|
* Account type (General, Margin, etc)
|
||||||
|
*/
|
||||||
|
type: AccountType;
|
||||||
|
/**
|
||||||
|
* Balance as string - current account balance (approx. as balances can be updated several times per second)
|
||||||
|
*/
|
||||||
|
balance: string;
|
||||||
|
/**
|
||||||
|
* Asset, the 'currency'
|
||||||
|
*/
|
||||||
|
asset: PartyMarketData_party_accounts_asset;
|
||||||
|
/**
|
||||||
|
* Market (only relevant to margin accounts)
|
||||||
|
*/
|
||||||
|
market: PartyMarketData_party_accounts_market | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PartyMarketData_party_marginsConnection_edges_node_market {
|
||||||
|
__typename: "Market";
|
||||||
|
/**
|
||||||
|
* Market ID
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PartyMarketData_party_marginsConnection_edges_node {
|
||||||
|
__typename: "MarginLevels";
|
||||||
|
/**
|
||||||
|
* market in which the margin is required for this party
|
||||||
|
*/
|
||||||
|
market: PartyMarketData_party_marginsConnection_edges_node_market;
|
||||||
|
/**
|
||||||
|
* this is the minimal margin required for a party to place a new order on the network (unsigned int actually)
|
||||||
|
*/
|
||||||
|
initialLevel: string;
|
||||||
|
/**
|
||||||
|
* minimal margin for the position to be maintained in the network (unsigned int actually)
|
||||||
|
*/
|
||||||
|
maintenanceLevel: string;
|
||||||
|
/**
|
||||||
|
* if the margin is between maintenance and search, the network will initiate a collateral search (unsigned int actually)
|
||||||
|
*/
|
||||||
|
searchLevel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PartyMarketData_party_marginsConnection_edges {
|
||||||
|
__typename: "MarginEdge";
|
||||||
|
node: PartyMarketData_party_marginsConnection_edges_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PartyMarketData_party_marginsConnection {
|
||||||
|
__typename: "MarginConnection";
|
||||||
|
/**
|
||||||
|
* The margin levels in this connection
|
||||||
|
*/
|
||||||
|
edges: PartyMarketData_party_marginsConnection_edges[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PartyMarketData_party {
|
||||||
|
__typename: "Party";
|
||||||
|
/**
|
||||||
|
* Party identifier
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
/**
|
||||||
|
* Collateral accounts relating to a party
|
||||||
|
*/
|
||||||
|
accounts: PartyMarketData_party_accounts[] | null;
|
||||||
|
/**
|
||||||
|
* Margin level for a market
|
||||||
|
*/
|
||||||
|
marginsConnection: PartyMarketData_party_marginsConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PartyMarketData {
|
||||||
|
/**
|
||||||
|
* An entity that is trading on the VEGA network
|
||||||
|
*/
|
||||||
|
party: PartyMarketData_party | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PartyMarketDataVariables {
|
||||||
|
partyId: string;
|
||||||
|
}
|
38
apps/simple-trading-app/src/app/hooks/use-market-data.ts
Normal file
38
apps/simple-trading-app/src/app/hooks/use-market-data.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { gql, useQuery } from '@apollo/client';
|
||||||
|
import { useMemo, useRef } from 'react';
|
||||||
|
import type {
|
||||||
|
MarketMarkPrice,
|
||||||
|
MarketMarkPriceVariables,
|
||||||
|
} from './__generated__/MarketMarkPrice';
|
||||||
|
|
||||||
|
const MARKET_MARK_PRICE = gql`
|
||||||
|
query MarketMarkPrice($marketId: ID!) {
|
||||||
|
market(id: $marketId) {
|
||||||
|
decimalPlaces
|
||||||
|
data {
|
||||||
|
markPrice
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default (marketId: string) => {
|
||||||
|
const memoRef = useRef<MarketMarkPrice | null>(null);
|
||||||
|
const { data } = useQuery<MarketMarkPrice, MarketMarkPriceVariables>(
|
||||||
|
MARKET_MARK_PRICE,
|
||||||
|
{
|
||||||
|
pollInterval: 5000,
|
||||||
|
variables: { marketId },
|
||||||
|
skip: !marketId,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return useMemo(() => {
|
||||||
|
if (
|
||||||
|
data &&
|
||||||
|
data.market?.data?.markPrice !== memoRef.current?.market?.data?.markPrice
|
||||||
|
) {
|
||||||
|
memoRef.current = data;
|
||||||
|
}
|
||||||
|
return memoRef.current;
|
||||||
|
}, [data, memoRef]);
|
||||||
|
};
|
@ -1,71 +0,0 @@
|
|||||||
import { renderHook } from '@testing-library/react-hooks';
|
|
||||||
import useOrderCloseOut from './use-order-closeout';
|
|
||||||
import type { Order } from '@vegaprotocol/orders';
|
|
||||||
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
|
||||||
import type { PartyBalanceQuery } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
|
||||||
|
|
||||||
describe('useOrderCloseOut Hook', () => {
|
|
||||||
const order = { size: '2', side: 'SIDE_BUY' };
|
|
||||||
const market = {
|
|
||||||
decimalPlaces: 5,
|
|
||||||
depth: {
|
|
||||||
lastTrade: {
|
|
||||||
price: '1000000',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tradableInstrument: {
|
|
||||||
instrument: {
|
|
||||||
product: {
|
|
||||||
settlementAsset: {
|
|
||||||
id: 'assetId',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const partyData = {
|
|
||||||
party: {
|
|
||||||
accounts: [
|
|
||||||
{
|
|
||||||
balance: '200000',
|
|
||||||
asset: {
|
|
||||||
id: 'assetId',
|
|
||||||
decimals: 5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
it('return proper buy value', () => {
|
|
||||||
const { result } = renderHook(() =>
|
|
||||||
useOrderCloseOut({
|
|
||||||
order: order as Order,
|
|
||||||
market: market as DealTicketQuery_market,
|
|
||||||
partyData: partyData as PartyBalanceQuery,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
expect(result.current).toEqual('9.00000');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('return proper sell value', () => {
|
|
||||||
const { result } = renderHook(() =>
|
|
||||||
useOrderCloseOut({
|
|
||||||
order: { ...order, side: 'SIDE_SELL' } as Order,
|
|
||||||
market: market as DealTicketQuery_market,
|
|
||||||
partyData: partyData as PartyBalanceQuery,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
expect(result.current).toEqual('11.00000');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('return proper empty value', () => {
|
|
||||||
const { result } = renderHook(() =>
|
|
||||||
useOrderCloseOut({
|
|
||||||
order: { ...order, side: 'SIDE_SELL' } as Order,
|
|
||||||
market: market as DealTicketQuery_market,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
expect(result.current).toEqual(' - ');
|
|
||||||
});
|
|
||||||
});
|
|
@ -0,0 +1,99 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { renderHook } from '@testing-library/react-hooks';
|
||||||
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
|
import useOrderCloseOut from './use-order-closeout';
|
||||||
|
import type { Order } from '@vegaprotocol/orders';
|
||||||
|
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
||||||
|
import type { PartyBalanceQuery } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
||||||
|
|
||||||
|
jest.mock('@vegaprotocol/wallet', () => ({
|
||||||
|
...jest.requireActual('@vegaprotocol/wallet'),
|
||||||
|
useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('useOrderCloseOut Hook', () => {
|
||||||
|
const order = { size: '2', side: 'SIDE_BUY' };
|
||||||
|
const market = {
|
||||||
|
decimalPlaces: 5,
|
||||||
|
depth: {
|
||||||
|
lastTrade: {
|
||||||
|
price: '1000000',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tradableInstrument: {
|
||||||
|
instrument: {
|
||||||
|
product: {
|
||||||
|
settlementAsset: {
|
||||||
|
id: 'assetId',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const partyData = {
|
||||||
|
party: {
|
||||||
|
accounts: [
|
||||||
|
{
|
||||||
|
balance: '200000',
|
||||||
|
asset: {
|
||||||
|
id: 'assetId',
|
||||||
|
decimals: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
it('return proper buy value', () => {
|
||||||
|
const { result } = renderHook(
|
||||||
|
() =>
|
||||||
|
useOrderCloseOut({
|
||||||
|
order: order as Order,
|
||||||
|
market: market as DealTicketQuery_market,
|
||||||
|
partyData: partyData as PartyBalanceQuery,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
wrapper: ({ children }: { children: React.ReactNode }) => (
|
||||||
|
// @ts-ignore different versions of react types in apollo and app
|
||||||
|
<MockedProvider mocks={[]}>{children}</MockedProvider>
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(result.current).toEqual(' - ');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('return proper sell value', () => {
|
||||||
|
const { result } = renderHook(
|
||||||
|
() =>
|
||||||
|
useOrderCloseOut({
|
||||||
|
order: { ...order, side: 'SIDE_SELL' } as Order,
|
||||||
|
market: market as DealTicketQuery_market,
|
||||||
|
partyData: partyData as PartyBalanceQuery,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
wrapper: ({ children }: { children: React.ReactNode }) => (
|
||||||
|
// @ts-ignore different versions of react types in apollo and app
|
||||||
|
<MockedProvider mocks={[]}>{children}</MockedProvider>
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(result.current).toEqual('1.00000');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('return proper empty value', () => {
|
||||||
|
const { result } = renderHook(
|
||||||
|
() =>
|
||||||
|
useOrderCloseOut({
|
||||||
|
order: { ...order, side: 'SIDE_SELL' } as Order,
|
||||||
|
market: market as DealTicketQuery_market,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
wrapper: ({ children }: { children: React.ReactNode }) => (
|
||||||
|
// @ts-ignore different versions of react types in apollo and app
|
||||||
|
<MockedProvider mocks={[]}>{children}</MockedProvider>
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(result.current).toEqual('0.00000');
|
||||||
|
});
|
||||||
|
});
|
@ -3,8 +3,46 @@ import type { Order } from '@vegaprotocol/orders';
|
|||||||
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
import type { DealTicketQuery_market } from '@vegaprotocol/deal-ticket';
|
||||||
import type { PartyBalanceQuery } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
import type { PartyBalanceQuery } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
||||||
import { useSettlementAccount } from './use-settlement-account';
|
import { useSettlementAccount } from './use-settlement-account';
|
||||||
import { VegaWalletOrderSide } from '@vegaprotocol/wallet';
|
import { useVegaWallet, VegaWalletOrderSide } from '@vegaprotocol/wallet';
|
||||||
import { addDecimal, formatNumber } from '@vegaprotocol/react-helpers';
|
import { addDecimal, formatNumber } from '@vegaprotocol/react-helpers';
|
||||||
|
import { gql, useQuery } from '@apollo/client';
|
||||||
|
import useMarketPositions from './use-market-positions';
|
||||||
|
import useMarketData from './use-market-data';
|
||||||
|
import type {
|
||||||
|
PartyMarketData,
|
||||||
|
PartyMarketDataVariables,
|
||||||
|
} from './__generated__/PartyMarketData';
|
||||||
|
|
||||||
|
const CLOSEOUT_PRICE_QUERY = gql`
|
||||||
|
query PartyMarketData($partyId: ID!) {
|
||||||
|
party(id: $partyId) {
|
||||||
|
id
|
||||||
|
accounts {
|
||||||
|
type
|
||||||
|
balance
|
||||||
|
asset {
|
||||||
|
id
|
||||||
|
decimals
|
||||||
|
}
|
||||||
|
market {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
marginsConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
market {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
initialLevel
|
||||||
|
maintenanceLevel
|
||||||
|
searchLevel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
order: Order;
|
order: Order;
|
||||||
@ -13,25 +51,65 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const useOrderCloseOut = ({ order, market, partyData }: Props): string => {
|
const useOrderCloseOut = ({ order, market, partyData }: Props): string => {
|
||||||
|
const { keypair } = useVegaWallet();
|
||||||
const account = useSettlementAccount(
|
const account = useSettlementAccount(
|
||||||
market.tradableInstrument.instrument.product.settlementAsset.id,
|
market.tradableInstrument.instrument.product.settlementAsset.id,
|
||||||
partyData?.party?.accounts || []
|
partyData?.party?.accounts || []
|
||||||
);
|
);
|
||||||
if (account?.balance && market.depth.lastTrade) {
|
const { data } = useQuery<PartyMarketData, PartyMarketDataVariables>(
|
||||||
const price = new BigNumber(
|
CLOSEOUT_PRICE_QUERY,
|
||||||
addDecimal(market.depth.lastTrade.price, market.decimalPlaces)
|
{
|
||||||
|
pollInterval: 5000,
|
||||||
|
variables: { partyId: keypair?.pub || '' },
|
||||||
|
skip: !keypair?.pub,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
const balance = new BigNumber(
|
|
||||||
addDecimal(account.balance, account.asset.decimals)
|
const markPriceData = useMarketData(market.id);
|
||||||
);
|
const marketPositions = useMarketPositions({
|
||||||
const { size, side } = order;
|
marketId: market.id,
|
||||||
const bigOne = new BigNumber(1);
|
partyId: keypair?.pub || '',
|
||||||
return formatNumber(
|
});
|
||||||
side === VegaWalletOrderSide.Buy
|
|
||||||
? bigOne.minus(balance.div(price.times(size))).times(price)
|
const marginMaintenanceLevel = new BigNumber(
|
||||||
: bigOne.plus(balance.div(price.times(size))).times(price),
|
addDecimal(
|
||||||
|
data?.party?.marginsConnection.edges?.find(
|
||||||
|
(nodes) => nodes.node.market.id === market.id
|
||||||
|
)?.node.maintenanceLevel || 0,
|
||||||
market.decimalPlaces
|
market.decimalPlaces
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
const positionAccount = data?.party?.accounts?.find(
|
||||||
|
(account) => account.market?.id === market.id
|
||||||
|
);
|
||||||
|
const positionAccountBalance = new BigNumber(
|
||||||
|
addDecimal(
|
||||||
|
positionAccount?.balance || 0,
|
||||||
|
positionAccount?.asset?.decimals || 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const generalAccountBalance = new BigNumber(
|
||||||
|
addDecimal(account?.balance || 0, account?.asset.decimals || 0)
|
||||||
|
);
|
||||||
|
const volume = new BigNumber(
|
||||||
|
addDecimal(
|
||||||
|
marketPositions?.openVolume.toNumber() || 0,
|
||||||
|
market.positionDecimalPlaces
|
||||||
|
)
|
||||||
|
)[order.side === VegaWalletOrderSide.Buy ? 'plus' : 'minus'](order.size);
|
||||||
|
const markPrice = new BigNumber(
|
||||||
|
addDecimal(
|
||||||
|
markPriceData?.market?.data?.markPrice || 0,
|
||||||
|
markPriceData?.market?.decimalPlaces || 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// regarding formula (marginMaintenanceLevel - positionAccountBalance - generalAccountBalance) / volume + markPrice
|
||||||
|
const marginDifference = marginMaintenanceLevel
|
||||||
|
.minus(positionAccountBalance)
|
||||||
|
.minus(generalAccountBalance);
|
||||||
|
const closeOut = marginDifference.div(volume).plus(markPrice);
|
||||||
|
if (closeOut.isPositive()) {
|
||||||
|
return formatNumber(closeOut, market.decimalPlaces);
|
||||||
}
|
}
|
||||||
return ' - ';
|
return ' - ';
|
||||||
};
|
};
|
||||||
|
@ -58,7 +58,7 @@ describe('useOrderMargin Hook', () => {
|
|||||||
const calledSize = new BigNumber(mockMarketPositions?.openVolume || 0)
|
const calledSize = new BigNumber(mockMarketPositions?.openVolume || 0)
|
||||||
.plus(order.size)
|
.plus(order.size)
|
||||||
.toString();
|
.toString();
|
||||||
expect((useQuery as jest.Mock).mock.calls[0][1].variables.size).toEqual(
|
expect((useQuery as jest.Mock).mock.calls[1][1].variables.size).toEqual(
|
||||||
calledSize
|
calledSize
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -74,7 +74,7 @@ describe('useOrderMargin Hook', () => {
|
|||||||
);
|
);
|
||||||
expect(result.current).toEqual('200000');
|
expect(result.current).toEqual('200000');
|
||||||
|
|
||||||
expect((useQuery as jest.Mock).mock.calls[0][1].variables.size).toEqual(
|
expect((useQuery as jest.Mock).mock.calls[1][1].variables.size).toEqual(
|
||||||
order.size
|
order.size
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -99,7 +99,7 @@ describe('useOrderMargin Hook', () => {
|
|||||||
const calledSize = new BigNumber(mockMarketPositions?.openVolume || 0)
|
const calledSize = new BigNumber(mockMarketPositions?.openVolume || 0)
|
||||||
.plus(order.size)
|
.plus(order.size)
|
||||||
.toString();
|
.toString();
|
||||||
expect((useQuery as jest.Mock).mock.calls[0][1].variables.size).toEqual(
|
expect((useQuery as jest.Mock).mock.calls[1][1].variables.size).toEqual(
|
||||||
calledSize
|
calledSize
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -12,8 +12,9 @@ import {
|
|||||||
VegaWalletOrderTimeInForce,
|
VegaWalletOrderTimeInForce,
|
||||||
VegaWalletOrderType,
|
VegaWalletOrderType,
|
||||||
} from '@vegaprotocol/wallet';
|
} from '@vegaprotocol/wallet';
|
||||||
import { addDecimal } from '@vegaprotocol/react-helpers';
|
import { addDecimal, removeDecimal } from '@vegaprotocol/react-helpers';
|
||||||
import useMarketPositions from './use-market-positions';
|
import useMarketPositions from './use-market-positions';
|
||||||
|
import useMarketData from './use-market-data';
|
||||||
|
|
||||||
export const ESTIMATE_ORDER_QUERY = gql`
|
export const ESTIMATE_ORDER_QUERY = gql`
|
||||||
query EstimateOrder(
|
query EstimateOrder(
|
||||||
@ -66,26 +67,35 @@ const types: Record<VegaWalletOrderType, OrderType> = {
|
|||||||
|
|
||||||
const useOrderMargin = ({ order, market, partyId }: Props) => {
|
const useOrderMargin = ({ order, market, partyId }: Props) => {
|
||||||
const marketPositions = useMarketPositions({ marketId: market.id, partyId });
|
const marketPositions = useMarketPositions({ marketId: market.id, partyId });
|
||||||
|
const markPriceData = useMarketData(market.id);
|
||||||
const { data } = useQuery<EstimateOrder, EstimateOrderVariables>(
|
const { data } = useQuery<EstimateOrder, EstimateOrderVariables>(
|
||||||
ESTIMATE_ORDER_QUERY,
|
ESTIMATE_ORDER_QUERY,
|
||||||
{
|
{
|
||||||
variables: {
|
variables: {
|
||||||
marketId: market.id,
|
marketId: market.id,
|
||||||
partyId,
|
partyId,
|
||||||
price: market.depth.lastTrade?.price,
|
price: markPriceData?.market?.data?.markPrice || '',
|
||||||
size: new BigNumber(marketPositions?.openVolume || 0)
|
size: removeDecimal(
|
||||||
[order.side === VegaWalletOrderSide.Buy ? 'plus' : 'minus'](
|
BigNumber.maximum(
|
||||||
order.size
|
0,
|
||||||
)
|
new BigNumber(marketPositions?.openVolume || 0)[
|
||||||
.toString(),
|
order.side === VegaWalletOrderSide.Buy ? 'plus' : 'minus'
|
||||||
|
](order.size)
|
||||||
|
).toString(),
|
||||||
|
market.positionDecimalPlaces
|
||||||
|
),
|
||||||
side: order.side === VegaWalletOrderSide.Buy ? Side.Buy : Side.Sell,
|
side: order.side === VegaWalletOrderSide.Buy ? Side.Buy : Side.Sell,
|
||||||
timeInForce: times[order.timeInForce],
|
timeInForce: times[order.timeInForce],
|
||||||
type: types[order.type],
|
type: types[order.type],
|
||||||
},
|
},
|
||||||
skip:
|
skip:
|
||||||
!partyId || !market.id || !order.size || !market.depth.lastTrade?.price,
|
!partyId ||
|
||||||
|
!market.id ||
|
||||||
|
!order.size ||
|
||||||
|
!markPriceData?.market?.data?.markPrice,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (data?.estimateOrder.marginLevels.initialLevel) {
|
if (data?.estimateOrder.marginLevels.initialLevel) {
|
||||||
return addDecimal(
|
return addDecimal(
|
||||||
BigNumber.maximum(
|
BigNumber.maximum(
|
||||||
|
@ -23,6 +23,9 @@ export function createClient(base?: string) {
|
|||||||
|
|
||||||
const cache = new InMemoryCache({
|
const cache = new InMemoryCache({
|
||||||
typePolicies: {
|
typePolicies: {
|
||||||
|
Party: {
|
||||||
|
keyFields: false,
|
||||||
|
},
|
||||||
Query: {},
|
Query: {},
|
||||||
Account: {
|
Account: {
|
||||||
keyFields: false,
|
keyFields: false,
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
"outDir": "../../dist/out-tsc",
|
"outDir": "../../dist/out-tsc",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"types": ["jest", "node", "@testing-library/jest-dom"],
|
"types": ["jest", "node", "@testing-library/jest-dom"],
|
||||||
"jsx": "react"
|
"jsx": "react",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"**/*.test.ts",
|
"**/*.test.ts",
|
||||||
|
Loading…
Reference in New Issue
Block a user