feat(trading): calculate required margin base on open volume, active … (#2957)
Co-authored-by: mattrussell36 <mattrussell36@users.noreply.github.com>
This commit is contained in:
parent
9d3fc04597
commit
6705eb4398
@ -4,9 +4,8 @@ import {
|
||||
getMarketExpiryDateFormatted,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type { MarketInfoNoCandlesQuery } from '@vegaprotocol/market-info';
|
||||
import type { MarketInfoWithData } from '@vegaprotocol/market-info';
|
||||
import { MarketInfoTable } from '@vegaprotocol/market-info';
|
||||
import pick from 'lodash/pick';
|
||||
import {
|
||||
MarketStateMapping,
|
||||
MarketTradingModeMapping,
|
||||
@ -17,11 +16,7 @@ import BigNumber from 'bignumber.js';
|
||||
import { useMemo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export const MarketDetails = ({
|
||||
market,
|
||||
}: {
|
||||
market: MarketInfoNoCandlesQuery['market'];
|
||||
}) => {
|
||||
export const MarketDetails = ({ market }: { market: MarketInfoWithData }) => {
|
||||
const quoteUnit = market?.tradableInstrument.instrument.product.quoteName;
|
||||
const assetId = useMemo(
|
||||
() => market?.tradableInstrument.instrument.product?.settlementAsset.id,
|
||||
@ -32,7 +27,9 @@ export const MarketDetails = ({
|
||||
if (!market) return null;
|
||||
|
||||
const keyDetails = {
|
||||
...pick(market, 'decimalPlaces', 'positionDecimalPlaces', 'tradingMode'),
|
||||
decimalPlaces: market.decimalPlaces,
|
||||
positionDecimalPlaces: market.positionDecimalPlaces,
|
||||
tradingMode: market.tradingMode,
|
||||
state: MarketStateMapping[market.state],
|
||||
};
|
||||
const assetDecimals =
|
||||
|
@ -12,6 +12,7 @@ export const Proposals = () => {
|
||||
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: proposalsDataProvider,
|
||||
variables: {},
|
||||
});
|
||||
|
||||
useDocumentTitle([t('Governance Proposals')]);
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { AsyncRenderer, Button } from '@vegaprotocol/ui-toolkit';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { MarketDetails } from '../../components/markets/market-details';
|
||||
import { useScrollToLocation } from '../../hooks/scroll-to-location';
|
||||
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||
import compact from 'lodash/compact';
|
||||
import { JsonViewerDialog } from '../../components/dialogs/json-viewer-dialog';
|
||||
import { marketInfoNoCandlesDataProvider } from '@vegaprotocol/market-info';
|
||||
import { marketInfoProvider } from '@vegaprotocol/market-info';
|
||||
import { PageTitle } from '../../components/page-helpers/page-title';
|
||||
|
||||
export const MarketPage = () => {
|
||||
@ -16,24 +16,17 @@ export const MarketPage = () => {
|
||||
|
||||
const { marketId } = useParams<{ marketId: string }>();
|
||||
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
marketId,
|
||||
}),
|
||||
[marketId]
|
||||
);
|
||||
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: marketInfoNoCandlesDataProvider,
|
||||
dataProvider: marketInfoProvider,
|
||||
skipUpdates: true,
|
||||
variables,
|
||||
variables: {
|
||||
marketId: marketId || '',
|
||||
skip: !marketId,
|
||||
},
|
||||
});
|
||||
|
||||
useDocumentTitle(
|
||||
compact([
|
||||
'Market details',
|
||||
data?.market?.tradableInstrument.instrument.name,
|
||||
])
|
||||
compact(['Market details', data?.tradableInstrument.instrument.name])
|
||||
);
|
||||
|
||||
const [dialogOpen, setDialogOpen] = useState<boolean>(false);
|
||||
@ -43,10 +36,10 @@ export const MarketPage = () => {
|
||||
<section className="relative">
|
||||
<PageTitle
|
||||
data-testid="markets-heading"
|
||||
title={data?.market?.tradableInstrument.instrument.name || ''}
|
||||
title={data?.tradableInstrument.instrument.name || ''}
|
||||
actions={
|
||||
<Button
|
||||
disabled={!data?.market}
|
||||
disabled={!data}
|
||||
size="xs"
|
||||
onClick={() => setDialogOpen(true)}
|
||||
>
|
||||
@ -60,14 +53,14 @@ export const MarketPage = () => {
|
||||
loading={loading}
|
||||
error={error}
|
||||
>
|
||||
<MarketDetails market={data?.market} />
|
||||
{data && <MarketDetails market={data} />}
|
||||
</AsyncRenderer>
|
||||
</section>
|
||||
<JsonViewerDialog
|
||||
open={dialogOpen}
|
||||
onChange={(isOpen) => setDialogOpen(isOpen)}
|
||||
title={data?.market?.tradableInstrument.instrument.name || ''}
|
||||
content={data?.market}
|
||||
title={data?.tradableInstrument.instrument.name || ''}
|
||||
content={data}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
@ -13,6 +13,7 @@ export const MarketsPage = () => {
|
||||
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: marketsProvider,
|
||||
variables: undefined,
|
||||
skipUpdates: true,
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useMemo } from 'react';
|
||||
import { makeDerivedDataProvider } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
@ -43,7 +42,7 @@ const useMarketDetails = (marketId: string | undefined) => {
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: lpDataProvider,
|
||||
skipUpdates: true,
|
||||
variables: useMemo(() => ({ marketId }), [marketId]),
|
||||
variables: { marketId: marketId || '' },
|
||||
});
|
||||
|
||||
const liquidityProviders = data?.liquidityProviders || [];
|
||||
|
@ -39,14 +39,11 @@ export const Last24hVolume = ({
|
||||
[marketId, yTimestamp]
|
||||
);
|
||||
|
||||
const variables24hAgo = useMemo(
|
||||
() => ({
|
||||
marketId: marketId,
|
||||
interval: Schema.Interval.INTERVAL_I1D,
|
||||
since: yTimestamp,
|
||||
}),
|
||||
[marketId, yTimestamp]
|
||||
);
|
||||
const variables24hAgo = {
|
||||
marketId: marketId,
|
||||
interval: Schema.Interval.INTERVAL_I1D,
|
||||
since: yTimestamp,
|
||||
};
|
||||
|
||||
const throttledSetCandles = useRef(
|
||||
throttle((data: Candle[]) => {
|
||||
@ -64,7 +61,7 @@ export const Last24hVolume = ({
|
||||
[throttledSetCandles]
|
||||
);
|
||||
|
||||
const { data, error } = useDataProvider<Candle[], Candle>({
|
||||
const { data, error } = useDataProvider({
|
||||
dataProvider: marketCandlesProvider,
|
||||
variables: variables,
|
||||
update,
|
||||
@ -88,7 +85,7 @@ export const Last24hVolume = ({
|
||||
[throttledSetVolumeChange]
|
||||
);
|
||||
|
||||
useDataProvider<Candle[], Candle>({
|
||||
useDataProvider({
|
||||
dataProvider: marketCandlesProvider,
|
||||
update: updateCandle24hAgo,
|
||||
variables: variables24hAgo,
|
||||
|
@ -26,20 +26,20 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
|
||||
it('market price', () => {
|
||||
cy.getByTestId(marketTitle).contains('Market price').click();
|
||||
validateMarketDataRow(0, 'Mark Price', '0.05749');
|
||||
validateMarketDataRow(1, 'Best Bid Price', '6.81765 ');
|
||||
validateMarketDataRow(2, 'Best Offer Price', '6.81769 ');
|
||||
validateMarketDataRow(0, 'Mark Price', '46,126.90058');
|
||||
validateMarketDataRow(1, 'Best Bid Price', '44,126.90058 ');
|
||||
validateMarketDataRow(2, 'Best Offer Price', '48,126.90058 ');
|
||||
validateMarketDataRow(3, 'Quote Unit', 'BTC');
|
||||
});
|
||||
|
||||
it('market volume displayed', () => {
|
||||
cy.getByTestId(marketTitle).contains('Market volume').click();
|
||||
validateMarketDataRow(0, '24 Hour Volume', '-');
|
||||
validateMarketDataRow(0, '24 Hour Volume', '1');
|
||||
validateMarketDataRow(1, 'Open Interest', '0');
|
||||
validateMarketDataRow(2, 'Best Bid Volume', '5');
|
||||
validateMarketDataRow(3, 'Best Offer Volume', '1');
|
||||
validateMarketDataRow(4, 'Best Static Bid Volume', '5');
|
||||
validateMarketDataRow(5, 'Best Static Offer Volume', '1');
|
||||
validateMarketDataRow(2, 'Best Bid Volume', '1');
|
||||
validateMarketDataRow(3, 'Best Offer Volume', '3');
|
||||
validateMarketDataRow(4, 'Best Static Bid Volume', '2');
|
||||
validateMarketDataRow(5, 'Best Static Offer Volume', '4');
|
||||
});
|
||||
|
||||
it('insurance pool displayed', () => {
|
||||
@ -149,9 +149,9 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
.contains(/Liquidity(?! m)/)
|
||||
.click();
|
||||
|
||||
validateMarketDataRow(0, 'Target Stake', '0.56789 tBTC');
|
||||
validateMarketDataRow(1, 'Supplied Stake', '0.56767 tBTC');
|
||||
validateMarketDataRow(2, 'Market Value Proxy', '6.77678 tBTC');
|
||||
validateMarketDataRow(0, 'Target Stake', '10.00 tBTC');
|
||||
validateMarketDataRow(1, 'Supplied Stake', '0.01 tBTC');
|
||||
validateMarketDataRow(2, 'Market Value Proxy', '20.00 tBTC');
|
||||
|
||||
cy.getByTestId('view-liquidity-link').should(
|
||||
'have.text',
|
||||
@ -163,8 +163,8 @@ describe('market info is displayed', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId(marketTitle).contains('Liquidity price range').click();
|
||||
|
||||
validateMarketDataRow(0, 'Liquidity Price Range', '2.00% of mid price');
|
||||
validateMarketDataRow(1, 'Lowest Price', '0.05634 BTC');
|
||||
validateMarketDataRow(2, 'Highest Price', '0.05864 BTC');
|
||||
validateMarketDataRow(1, 'Lowest Price', '45,204.362 BTC');
|
||||
validateMarketDataRow(2, 'Highest Price', '47,049.438 BTC');
|
||||
});
|
||||
|
||||
it('oracle displayed', () => {
|
||||
|
@ -38,7 +38,7 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId('tab-accounts')
|
||||
.get(tradingAccountRowId)
|
||||
.find('[col-id="deposited"]')
|
||||
.should('have.text', '1,001.00');
|
||||
.should('have.text', '100,001.01');
|
||||
});
|
||||
describe('sorting by ag-grid columns should work well', () => {
|
||||
it('sorting by asset', () => {
|
||||
@ -58,24 +58,24 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId('Collateral').click();
|
||||
const marketsSortedDefault = [
|
||||
'1,000.00002',
|
||||
'1,001.00',
|
||||
'1,000.01',
|
||||
'100,001.01',
|
||||
'1,000.01',
|
||||
'1,000.00',
|
||||
'1,000.00001',
|
||||
];
|
||||
const marketsSortedAsc = [
|
||||
'1,000.00',
|
||||
'1,000.00001',
|
||||
'1,000.00002',
|
||||
'1,000.01',
|
||||
'1,000.01',
|
||||
'1,001.00',
|
||||
'100,001.01',
|
||||
];
|
||||
const marketsSortedDesc = [
|
||||
'1,001.00',
|
||||
'1,000.01',
|
||||
'100,001.01',
|
||||
'1,000.01',
|
||||
'1,000.00002',
|
||||
'1,000.00001',
|
||||
'1,000.00',
|
||||
];
|
||||
checkSorting(
|
||||
'deposited',
|
||||
@ -87,9 +87,9 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
|
||||
it('sorting by used', () => {
|
||||
cy.getByTestId('Collateral').click();
|
||||
const marketsSortedDefault = ['0.00', '1.00', '0.01', '0.01', '0.00'];
|
||||
const marketsSortedAsc = ['0.00', '0.00', '0.01', '0.01', '1.00'];
|
||||
const marketsSortedDesc = ['1.00', '0.01', '0.01', '0.00', '0.00'];
|
||||
const marketsSortedDefault = ['0.00', '1.01', '0.01', '0.00', '0.00'];
|
||||
const marketsSortedAsc = ['0.00', '0.00', '0.00', '0.01', '1.01'];
|
||||
const marketsSortedDesc = ['1.01', '0.01', '0.00', '0.00', '0.00'];
|
||||
checkSorting(
|
||||
'used',
|
||||
marketsSortedDefault,
|
||||
@ -102,24 +102,24 @@ describe('accounts', { tags: '@smoke' }, () => {
|
||||
cy.getByTestId('Collateral').click();
|
||||
const marketsSortedDefault = [
|
||||
'1,000.00002',
|
||||
'1,000.00',
|
||||
'100,000.00',
|
||||
'1,000.00',
|
||||
'1,000.00',
|
||||
'1,000.00001',
|
||||
];
|
||||
const marketsSortedAsc = [
|
||||
'1,000.00',
|
||||
'1,000.00',
|
||||
'1,000.00',
|
||||
'1,000.00001',
|
||||
'1,000.00002',
|
||||
'100,000.00',
|
||||
];
|
||||
const marketsSortedDesc = [
|
||||
'100,000.00',
|
||||
'1,000.00002',
|
||||
'1,000.00001',
|
||||
'1,000.00',
|
||||
'1,000.00',
|
||||
'1,000.00',
|
||||
];
|
||||
|
||||
checkSorting(
|
||||
|
@ -2,7 +2,11 @@ import * as Schema from '@vegaprotocol/types';
|
||||
import { aliasGQLQuery, mockConnectWallet } from '@vegaprotocol/cypress';
|
||||
import { testOrderSubmission } from '../support/order-validation';
|
||||
import type { OrderSubmission } from '@vegaprotocol/wallet';
|
||||
import { accountsQuery, estimateOrderQuery } from '@vegaprotocol/mock';
|
||||
import {
|
||||
accountsQuery,
|
||||
estimateOrderQuery,
|
||||
amendGeneralAccountBalance,
|
||||
} from '@vegaprotocol/mock';
|
||||
import { createOrder } from '../support/create-order';
|
||||
|
||||
const orderSizeField = 'order-size';
|
||||
@ -583,6 +587,10 @@ describe('suspended market validation', { tags: '@regression' }, () => {
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
|
||||
);
|
||||
const accounts = accountsQuery();
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.wait('@Markets');
|
||||
@ -632,30 +640,10 @@ describe('account validation', { tags: '@regression' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
const accounts = accountsQuery();
|
||||
amendGeneralAccountBalance(accounts, 'market-0', '0');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(
|
||||
req,
|
||||
'Accounts',
|
||||
accountsQuery({
|
||||
party: {
|
||||
accountsConnection: {
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
balance: '0',
|
||||
market: null,
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-0',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
@ -679,19 +667,13 @@ describe('account validation', { tags: '@regression' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.setVegaWallet();
|
||||
cy.mockTradingPage();
|
||||
const accounts = accountsQuery();
|
||||
amendGeneralAccountBalance(accounts, 'market-0', '100000000');
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(
|
||||
req,
|
||||
'EstimateOrder',
|
||||
estimateOrderQuery({
|
||||
estimateOrder: {
|
||||
marginLevels: {
|
||||
__typename: 'MarginLevels',
|
||||
initialLevel: '1000000000',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
aliasGQLQuery(req, 'Accounts', accounts);
|
||||
});
|
||||
cy.mockGQL((req) => {
|
||||
aliasGQLQuery(req, 'EstimateOrder', estimateOrderQuery());
|
||||
});
|
||||
cy.mockSubscription();
|
||||
cy.visit('/#/markets/market-0');
|
||||
@ -707,7 +689,7 @@ describe('account validation', { tags: '@regression' }, () => {
|
||||
);
|
||||
cy.getByTestId('dealticket-warning-margin').should(
|
||||
'contain.text',
|
||||
'9,999.99 tDAI is currently required. You have only 1,000.00 tDAI available.Deposit tDAI'
|
||||
'You may not have enough margin available to open this position. 2,354.72283 tDAI is currently required. You have only 1,000.01 tDAI available.'
|
||||
);
|
||||
cy.getByTestId('deal-ticket-deposit-dialog-button').click();
|
||||
cy.getByTestId('dialog-content')
|
||||
|
@ -31,7 +31,7 @@ describe('orders list', { tags: '@smoke' }, () => {
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId('Orders').click();
|
||||
cy.wait('@Orders').then(() => {
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledTwice;
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledThrice;
|
||||
});
|
||||
cy.wait('@Markets');
|
||||
});
|
||||
@ -136,7 +136,7 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId('Orders').click();
|
||||
cy.wait('@Orders').then(() => {
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledTwice;
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledThrice;
|
||||
});
|
||||
});
|
||||
const orderId = '1234567890';
|
||||
@ -354,7 +354,7 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
|
||||
cy.visit('/#/markets/market-0');
|
||||
cy.getByTestId('Orders').click();
|
||||
cy.wait('@Orders').then(() => {
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledTwice;
|
||||
expect(subscriptionMocks.OrdersUpdate).to.be.calledThrice;
|
||||
});
|
||||
cy.mockVegaWalletTransaction();
|
||||
});
|
||||
|
@ -164,10 +164,10 @@ describe('positions', { tags: '@smoke' }, () => {
|
||||
|
||||
cy.get('[col-id="liquidationPrice"]').should('contain.text', '0'); // liquidation price
|
||||
|
||||
cy.get('[col-id="currentLeverage"]').should('contain.text', '138.446.1');
|
||||
cy.get('[col-id="currentLeverage"]').should('contain.text', '2.846.1');
|
||||
|
||||
cy.get('[col-id="marginAccountBalance"]') // margin allocated
|
||||
.should('contain.text', '1,000');
|
||||
.should('contain.text', '0.01');
|
||||
|
||||
cy.get('[col-id="unrealisedPNL"]').each(($unrealisedPnl) => {
|
||||
cy.wrap($unrealisedPnl).invoke('text').should('not.be.empty');
|
||||
|
@ -7,13 +7,13 @@ import type { onMessage } from '@vegaprotocol/cypress';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import { orderUpdateSubscription } from '@vegaprotocol/mock';
|
||||
|
||||
let sendOrderUpdate: (data: OrdersUpdateSubscription) => void;
|
||||
const sendOrderUpdate: ((data: OrdersUpdateSubscription) => void)[] = [];
|
||||
const getOnOrderUpdate = () => {
|
||||
const onOrderUpdate: onMessage<
|
||||
OrdersUpdateSubscription,
|
||||
OrdersUpdateSubscriptionVariables
|
||||
> = (send) => {
|
||||
sendOrderUpdate = send;
|
||||
sendOrderUpdate.push(send);
|
||||
};
|
||||
return onOrderUpdate;
|
||||
};
|
||||
@ -31,5 +31,5 @@ export function updateOrder(
|
||||
if (!sendOrderUpdate) {
|
||||
throw new Error('OrderSub not called');
|
||||
}
|
||||
sendOrderUpdate(update);
|
||||
sendOrderUpdate.forEach((send) => send(update));
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ import {
|
||||
} from '@vegaprotocol/mock';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
import type { MarketDataQuery, MarketsQuery } from '@vegaprotocol/market-list';
|
||||
import type { MarketInfoQuery } from '@vegaprotocol/market-info';
|
||||
|
||||
type MarketPageMockData = {
|
||||
state: Schema.MarketState;
|
||||
@ -69,18 +68,6 @@ const marketsDataOverride = (
|
||||
},
|
||||
});
|
||||
|
||||
const marketInfoOverride = (
|
||||
data: MarketPageMockData
|
||||
): PartialDeep<MarketInfoQuery> => ({
|
||||
market: {
|
||||
state: data.state,
|
||||
tradingMode: data.tradingMode,
|
||||
data: {
|
||||
trigger: data.trigger,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const mockTradingPage = (
|
||||
req: CyHttpMessages.IncomingHttpRequest,
|
||||
state: Schema.MarketState = Schema.MarketState.STATE_ACTIVE,
|
||||
@ -109,11 +96,7 @@ const mockTradingPage = (
|
||||
aliasGQLQuery(req, 'Margins', marginsQuery());
|
||||
aliasGQLQuery(req, 'Assets', assetsQuery());
|
||||
aliasGQLQuery(req, 'Asset', assetQuery());
|
||||
aliasGQLQuery(
|
||||
req,
|
||||
'MarketInfo',
|
||||
marketInfoQuery(marketInfoOverride({ state, tradingMode, trigger }))
|
||||
);
|
||||
aliasGQLQuery(req, 'MarketInfo', marketInfoQuery());
|
||||
aliasGQLQuery(req, 'Trades', tradesQuery());
|
||||
aliasGQLQuery(req, 'Chart', chartQuery());
|
||||
aliasGQLQuery(req, 'Candles', candlesQuery());
|
||||
|
@ -12,6 +12,7 @@ export const Home = () => {
|
||||
// should be the oldest market that is currently trading in us mode(i.e. not in auction).
|
||||
const { data, error, loading } = useDataProvider({
|
||||
dataProvider: marketsWithDataProvider,
|
||||
variables: undefined,
|
||||
});
|
||||
const update = useGlobalStore((store) => store.update);
|
||||
const marketId = useGlobalStore((store) => store.marketId);
|
||||
|
@ -47,7 +47,8 @@ export const Liquidity = () => {
|
||||
const useReloadLiquidityData = (marketId: string | undefined) => {
|
||||
const { reload } = useDataProvider({
|
||||
dataProvider: liquidityProvisionsDataProvider,
|
||||
variables: useMemo(() => ({ marketId }), [marketId]),
|
||||
variables: { marketId: marketId || '' },
|
||||
skip: !marketId,
|
||||
});
|
||||
useEffect(() => {
|
||||
const interval = setInterval(reload, 10000);
|
||||
@ -77,7 +78,8 @@ export const LiquidityContainer = ({
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: lpAggregatedDataProvider,
|
||||
update,
|
||||
variables: useMemo(() => ({ marketId }), [marketId]),
|
||||
variables: { marketId: marketId || '' },
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
const assetDecimalPlaces =
|
||||
@ -161,7 +163,8 @@ export const LiquidityViewContainer = ({
|
||||
} = useDataProvider({
|
||||
dataProvider: lpAggregatedDataProvider,
|
||||
update,
|
||||
variables: useMemo(() => ({ marketId }), [marketId]),
|
||||
variables: { marketId: marketId || '' },
|
||||
skip: !marketId,
|
||||
});
|
||||
|
||||
const targetStake = marketData?.targetStake;
|
||||
|
@ -7,10 +7,6 @@ import {
|
||||
useThrottledDataProvider,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { AsyncRenderer, ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import type {
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
} from '@vegaprotocol/market-list';
|
||||
|
||||
import { marketProvider, marketDataProvider } from '@vegaprotocol/market-list';
|
||||
import { useGlobalStore, usePageTitleStore } from '../../stores';
|
||||
@ -35,13 +31,10 @@ const TitleUpdater = ({
|
||||
}) => {
|
||||
const pageTitle = usePageTitleStore((store) => store.pageTitle);
|
||||
const updateTitle = usePageTitleStore((store) => store.updateTitle);
|
||||
const { data: marketData } = useThrottledDataProvider<
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment
|
||||
>(
|
||||
const { data: marketData } = useThrottledDataProvider(
|
||||
{
|
||||
dataProvider: marketDataProvider,
|
||||
variables: useMemo(() => ({ marketId }), [marketId]),
|
||||
variables: { marketId: marketId || '' },
|
||||
skip: !marketId,
|
||||
},
|
||||
1000
|
||||
|
@ -1,5 +1,4 @@
|
||||
import type { RefObject } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import { isNumeric } from '@vegaprotocol/utils';
|
||||
import {
|
||||
@ -9,7 +8,6 @@ import {
|
||||
import { PriceChangeCell } from '@vegaprotocol/datagrid';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { CandleClose } from '@vegaprotocol/types';
|
||||
import type { Candle } from '@vegaprotocol/market-list';
|
||||
import { marketCandlesProvider } from '@vegaprotocol/market-list';
|
||||
import { THROTTLE_UPDATE_TIME } from '../constants';
|
||||
|
||||
@ -30,19 +28,14 @@ export const Last24hPriceChange = ({
|
||||
}: Props) => {
|
||||
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
||||
const yesterday = useYesterday();
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
marketId: marketId,
|
||||
interval: Schema.Interval.INTERVAL_I1H,
|
||||
since: new Date(yesterday).toISOString(),
|
||||
}),
|
||||
[marketId, yesterday]
|
||||
);
|
||||
|
||||
const { data, error } = useThrottledDataProvider<Candle[], Candle>(
|
||||
const { data, error } = useThrottledDataProvider(
|
||||
{
|
||||
dataProvider: marketCandlesProvider,
|
||||
variables,
|
||||
variables: {
|
||||
marketId: marketId || '',
|
||||
interval: Schema.Interval.INTERVAL_I1H,
|
||||
since: new Date(yesterday).toISOString(),
|
||||
},
|
||||
skip: !marketId || !inView,
|
||||
},
|
||||
THROTTLE_UPDATE_TIME
|
||||
|
@ -10,8 +10,6 @@ import {
|
||||
useYesterday,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { useMemo } from 'react';
|
||||
import type { Candle } from '@vegaprotocol/market-list';
|
||||
import { THROTTLE_UPDATE_TIME } from '../constants';
|
||||
|
||||
interface Props {
|
||||
@ -32,19 +30,14 @@ export const Last24hVolume = ({
|
||||
const yesterday = useYesterday();
|
||||
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
||||
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
marketId: marketId,
|
||||
interval: Schema.Interval.INTERVAL_I1H,
|
||||
since: new Date(yesterday).toISOString(),
|
||||
}),
|
||||
[marketId, yesterday]
|
||||
);
|
||||
|
||||
const { data } = useThrottledDataProvider<Candle[], Candle>(
|
||||
const { data } = useThrottledDataProvider(
|
||||
{
|
||||
dataProvider: marketCandlesProvider,
|
||||
variables,
|
||||
variables: {
|
||||
marketId: marketId || '',
|
||||
interval: Schema.Interval.INTERVAL_I1H,
|
||||
since: new Date(yesterday).toISOString(),
|
||||
},
|
||||
skip: !(inView && marketId),
|
||||
},
|
||||
THROTTLE_UPDATE_TIME
|
||||
|
@ -4,10 +4,7 @@ import {
|
||||
useDataProvider,
|
||||
useNetworkParams,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import type { MarketData } from '@vegaprotocol/market-list';
|
||||
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
|
||||
import { HeaderStat } from '../header';
|
||||
import {
|
||||
@ -70,7 +67,7 @@ export const MarketLiquiditySupplied = ({
|
||||
[noUpdate]
|
||||
);
|
||||
|
||||
useDataProvider<MarketData, MarketDataUpdateFieldsFragment>({
|
||||
useDataProvider({
|
||||
dataProvider: marketDataProvider,
|
||||
update,
|
||||
variables,
|
||||
|
@ -1,13 +1,8 @@
|
||||
import type { RefObject } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import { addDecimalsFormatNumber, isNumeric } from '@vegaprotocol/utils';
|
||||
import { useThrottledDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { PriceCell } from '@vegaprotocol/datagrid';
|
||||
import type {
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { marketDataProvider } from '@vegaprotocol/market-list';
|
||||
import { THROTTLE_UPDATE_TIME } from '../constants';
|
||||
|
||||
@ -27,15 +22,10 @@ export const MarketMarkPrice = ({
|
||||
asPriceCell,
|
||||
}: Props) => {
|
||||
const [ref, inView] = useInView({ root: inViewRoot?.current });
|
||||
const variables = useMemo(() => ({ marketId }), [marketId]);
|
||||
|
||||
const { data } = useThrottledDataProvider<
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment
|
||||
>(
|
||||
const { data } = useThrottledDataProvider(
|
||||
{
|
||||
dataProvider: marketDataProvider,
|
||||
variables,
|
||||
variables: { marketId: marketId || '' },
|
||||
skip: !inView,
|
||||
},
|
||||
THROTTLE_UPDATE_TIME
|
||||
|
@ -1,15 +1,11 @@
|
||||
import throttle from 'lodash/throttle';
|
||||
import type {
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
Market,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import type { MarketData, Market } from '@vegaprotocol/market-list';
|
||||
import { marketDataProvider } from '@vegaprotocol/market-list';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { HeaderStat } from '../header';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import * as constants from '../constants';
|
||||
|
||||
export const MarketState = ({ market }: { market: Market | null }) => {
|
||||
@ -33,14 +29,10 @@ export const MarketState = ({ market }: { market: Market | null }) => {
|
||||
[throttledSetMarketState]
|
||||
);
|
||||
|
||||
const variables = useMemo(
|
||||
() => ({ marketId: market?.id || '' }),
|
||||
[market?.id]
|
||||
);
|
||||
useDataProvider<MarketData, MarketDataUpdateFieldsFragment>({
|
||||
useDataProvider({
|
||||
dataProvider: marketDataProvider,
|
||||
update,
|
||||
variables,
|
||||
variables: { marketId: market?.id || '' },
|
||||
skip: !market?.id,
|
||||
});
|
||||
|
||||
|
@ -1,24 +1,16 @@
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import throttle from 'lodash/throttle';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
MarketData,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import type { MarketData } from '@vegaprotocol/market-list';
|
||||
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
|
||||
import { HeaderStat } from '../header';
|
||||
import * as constants from '../constants';
|
||||
|
||||
export const MarketVolume = ({ marketId }: { marketId: string }) => {
|
||||
const [marketVolume, setMarketVolume] = useState<string>('-');
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
marketId: marketId,
|
||||
}),
|
||||
[marketId]
|
||||
);
|
||||
const variables = { marketId };
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: marketProvider,
|
||||
variables,
|
||||
@ -46,7 +38,7 @@ export const MarketVolume = ({ marketId }: { marketId: string }) => {
|
||||
[data?.positionDecimalPlaces, throttledSetMarketVolume]
|
||||
);
|
||||
|
||||
useDataProvider<MarketData, MarketDataUpdateFieldsFragment>({
|
||||
useDataProvider({
|
||||
dataProvider: marketDataProvider,
|
||||
update,
|
||||
variables,
|
||||
|
@ -106,14 +106,13 @@ export const SelectMarketPopover = ({
|
||||
loading: marketsLoading,
|
||||
reload: marketListReload,
|
||||
} = useMarketList();
|
||||
const variables = useMemo(() => ({ partyId: pubKey }), [pubKey]);
|
||||
const {
|
||||
data: positions,
|
||||
loading: positionsLoading,
|
||||
reload,
|
||||
} = useDataProvider({
|
||||
dataProvider: positionsDataProvider,
|
||||
variables,
|
||||
variables: { partyId: pubKey || '' },
|
||||
skip: !pubKey,
|
||||
});
|
||||
const onSelectMarket = useCallback(
|
||||
|
@ -20,6 +20,7 @@ export const WelcomeDialog = () => {
|
||||
const [riskAccepted] = useLocalStorage(constants.RISK_ACCEPTED_KEY);
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: activeMarketsProvider,
|
||||
variables: undefined,
|
||||
});
|
||||
|
||||
const { update, shouldDisplayWelcomeDialog } = useGlobalStore((store) => ({
|
||||
|
@ -18,6 +18,7 @@ import type {
|
||||
AccountFieldsFragment,
|
||||
AccountsQuery,
|
||||
AccountEventsSubscription,
|
||||
AccountsQueryVariables,
|
||||
} from './__generated__/Accounts';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
import type { Asset } from '@vegaprotocol/assets';
|
||||
@ -85,7 +86,8 @@ export const accountsOnlyDataProvider = makeDataProvider<
|
||||
AccountsQuery,
|
||||
AccountFieldsFragment[],
|
||||
AccountEventsSubscription,
|
||||
AccountEventsSubscription['accounts']
|
||||
AccountEventsSubscription['accounts'],
|
||||
AccountsQueryVariables
|
||||
>({
|
||||
query: AccountsDocument,
|
||||
subscriptionQuery: AccountEventsDocument,
|
||||
@ -159,8 +161,16 @@ const getAssetAccountAggregation = (
|
||||
return { ...balanceAccount, breakdown };
|
||||
};
|
||||
|
||||
export const accountsDataProvider = makeDerivedDataProvider<Account[], never>(
|
||||
[accountsOnlyDataProvider, marketsProvider, assetsProvider],
|
||||
export const accountsDataProvider = makeDerivedDataProvider<
|
||||
Account[],
|
||||
never,
|
||||
AccountsQueryVariables
|
||||
>(
|
||||
[
|
||||
accountsOnlyDataProvider,
|
||||
(callback, client) => marketsProvider(callback, client, undefined),
|
||||
(callback, client) => assetsProvider(callback, client, undefined),
|
||||
],
|
||||
([accounts, markets, assets]): Account[] | null => {
|
||||
return accounts
|
||||
? accounts
|
||||
@ -194,7 +204,8 @@ export const accountsDataProvider = makeDerivedDataProvider<Account[], never>(
|
||||
|
||||
export const aggregatedAccountsDataProvider = makeDerivedDataProvider<
|
||||
AccountFields[],
|
||||
never
|
||||
never,
|
||||
AccountsQueryVariables
|
||||
>(
|
||||
[accountsDataProvider],
|
||||
(parts) => parts[0] && getAccountData(parts[0] as Account[])
|
||||
|
@ -31,10 +31,7 @@ export const AccountManager = ({
|
||||
}: AccountManagerProps) => {
|
||||
const gridRef = useRef<AgGridReact | null>(null);
|
||||
const variables = useMemo(() => ({ partyId }), [partyId]);
|
||||
const { data, loading, error, reload } = useDataProvider<
|
||||
AccountFields[],
|
||||
never
|
||||
>({
|
||||
const { data, loading, error, reload } = useDataProvider({
|
||||
dataProvider: aggregatedAccountsDataProvider,
|
||||
variables,
|
||||
});
|
||||
|
@ -1,9 +1,14 @@
|
||||
import { forwardRef, useMemo, useState } from 'react';
|
||||
import { addDecimalsFormatNumber, isNumeric } from '@vegaprotocol/utils';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
isNumeric,
|
||||
toBigNum,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import type {
|
||||
VegaICellRendererParams,
|
||||
VegaValueFormatterParams,
|
||||
VegaValueGetterParams,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import { Button, ButtonLink, Dialog } from '@vegaprotocol/ui-toolkit';
|
||||
import { TooltipCellComponent } from '@vegaprotocol/ui-toolkit';
|
||||
@ -117,17 +122,23 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
|
||||
headerTooltip={t(
|
||||
'This is the total amount of collateral used plus the amount available in your general account.'
|
||||
)}
|
||||
valueGetter={({
|
||||
data,
|
||||
}: VegaValueGetterParams<AccountFields, 'deposited'>) => {
|
||||
return !data?.deposited
|
||||
? undefined
|
||||
: toBigNum(data.deposited, data.asset.decimals).toNumber();
|
||||
}}
|
||||
maxWidth={300}
|
||||
cellRenderer={({
|
||||
data,
|
||||
value,
|
||||
node,
|
||||
}: VegaICellRendererParams<AccountFields, 'deposited'>) => {
|
||||
const valueFormatted =
|
||||
data &&
|
||||
data.asset &&
|
||||
isNumeric(value) &&
|
||||
addDecimalsFormatNumber(value, data.asset.decimals);
|
||||
isNumeric(data.deposited) &&
|
||||
addDecimalsFormatNumber(data.deposited, data.asset.decimals);
|
||||
return node.rowPinned ? (
|
||||
<CenteredGridCellWrapper className="h-[30px] justify-end">
|
||||
{valueFormatted}
|
||||
@ -144,17 +155,23 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
|
||||
headerTooltip={t(
|
||||
'This is the amount of collateral used from your general account.'
|
||||
)}
|
||||
valueGetter={({
|
||||
data,
|
||||
}: VegaValueGetterParams<AccountFields, 'used'>) => {
|
||||
return !data?.used
|
||||
? undefined
|
||||
: toBigNum(data.used, data.asset.decimals).toNumber();
|
||||
}}
|
||||
maxWidth={300}
|
||||
cellRenderer={({
|
||||
data,
|
||||
value,
|
||||
node,
|
||||
}: VegaICellRendererParams<AccountFields, 'used'>) => {
|
||||
const valueFormatted =
|
||||
data &&
|
||||
data.asset &&
|
||||
isNumeric(value) &&
|
||||
addDecimalsFormatNumber(value, data.asset.decimals);
|
||||
isNumeric(data.used) &&
|
||||
addDecimalsFormatNumber(data.used, data.asset.decimals);
|
||||
return node.rowPinned ? (
|
||||
<CenteredGridCellWrapper className="h-[30px] justify-end">
|
||||
{valueFormatted}
|
||||
@ -171,26 +188,31 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
|
||||
headerTooltip={t(
|
||||
'This is the amount of collateral available in your general account.'
|
||||
)}
|
||||
valueGetter={({
|
||||
data,
|
||||
}: VegaValueGetterParams<AccountFields, 'available'>) => {
|
||||
return !data?.available
|
||||
? undefined
|
||||
: toBigNum(data.available, data.asset.decimals).toNumber();
|
||||
}}
|
||||
valueFormatter={({
|
||||
value,
|
||||
data,
|
||||
}: VegaValueFormatterParams<AccountFields, 'available'>) =>
|
||||
data &&
|
||||
data.asset &&
|
||||
isNumeric(value) &&
|
||||
addDecimalsFormatNumber(value, data.asset.decimals)
|
||||
isNumeric(data.available) &&
|
||||
addDecimalsFormatNumber(data.available, data.asset.decimals)
|
||||
}
|
||||
maxWidth={300}
|
||||
cellRenderer={({
|
||||
data,
|
||||
value,
|
||||
node,
|
||||
}: VegaICellRendererParams<AccountFields, 'available'>) => {
|
||||
const valueFormatted =
|
||||
data &&
|
||||
data.asset &&
|
||||
isNumeric(value) &&
|
||||
addDecimalsFormatNumber(value, data.asset.decimals);
|
||||
isNumeric(data.available) &&
|
||||
addDecimalsFormatNumber(data.available, data.asset.decimals);
|
||||
return node.rowPinned ? (
|
||||
<CenteredGridCellWrapper className="h-[30px] justify-end">
|
||||
{valueFormatted}
|
||||
|
@ -43,10 +43,6 @@ export const accountFields: AccountFieldsFragment[] = [
|
||||
__typename: 'AccountBalance',
|
||||
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
balance: '100000000',
|
||||
market: {
|
||||
id: 'market-0',
|
||||
__typename: 'Market',
|
||||
},
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-id-2',
|
||||
@ -75,7 +71,7 @@ export const accountFields: AccountFieldsFragment[] = [
|
||||
},
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
id: 'asset-id-2',
|
||||
id: 'asset-0',
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -94,7 +90,7 @@ export const accountFields: AccountFieldsFragment[] = [
|
||||
{
|
||||
__typename: 'AccountBalance',
|
||||
type: Schema.AccountType.ACCOUNT_TYPE_GENERAL,
|
||||
balance: '100000000',
|
||||
balance: '10000000000',
|
||||
market: null,
|
||||
asset: {
|
||||
__typename: 'Asset',
|
||||
@ -141,3 +137,25 @@ export const accountEventsSubscription = (
|
||||
};
|
||||
return merge(defaultResult, override);
|
||||
};
|
||||
|
||||
export const amendGeneralAccountBalance = (
|
||||
accounts: AccountsQuery,
|
||||
marketId: string,
|
||||
balance: string
|
||||
) => {
|
||||
if (accounts.party?.accountsConnection?.edges) {
|
||||
const marginAccount = accounts.party.accountsConnection.edges.find(
|
||||
(edge) => edge?.node.market?.id === marketId
|
||||
);
|
||||
if (marginAccount) {
|
||||
const generalAccount = accounts.party.accountsConnection.edges.find(
|
||||
(edge) =>
|
||||
edge?.node.asset.id === marginAccount.node.asset.id &&
|
||||
!edge?.node.market
|
||||
);
|
||||
if (generalAccount) {
|
||||
generalAccount.node.balance = balance;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -20,7 +20,7 @@ export const TransferContainer = () => {
|
||||
const { param } = useNetworkParam(NetworkParams.transfer_fee_factor);
|
||||
const { data } = useDataProvider({
|
||||
dataProvider: accountsDataProvider,
|
||||
variables: { partyId: pubKey },
|
||||
variables: { partyId: pubKey || '' },
|
||||
skip: !pubKey,
|
||||
});
|
||||
const create = useVegaTransactionStore((store) => store.create);
|
||||
|
@ -1,8 +1,11 @@
|
||||
import { makeDataProvider } from '@vegaprotocol/utils';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import type { AssetQuery, AssetFieldsFragment } from './__generated__/Asset';
|
||||
import type {
|
||||
AssetQuery,
|
||||
AssetFieldsFragment,
|
||||
AssetQueryVariables,
|
||||
} from './__generated__/Asset';
|
||||
import { AssetDocument } from './__generated__/Asset';
|
||||
|
||||
export type Asset = AssetFieldsFragment;
|
||||
@ -15,21 +18,21 @@ export const getData = (responseData: AssetQuery | null | undefined) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
export const assetProvider = makeDataProvider<AssetQuery, Asset, never, never>({
|
||||
export const assetProvider = makeDataProvider<
|
||||
AssetQuery,
|
||||
Asset,
|
||||
never,
|
||||
never,
|
||||
AssetQueryVariables
|
||||
>({
|
||||
query: AssetDocument,
|
||||
getData,
|
||||
});
|
||||
|
||||
export const useAssetDataProvider = (assetId: string) => {
|
||||
const variables = useMemo(
|
||||
() => ({
|
||||
assetId,
|
||||
}),
|
||||
[assetId]
|
||||
);
|
||||
return useDataProvider({
|
||||
dataProvider: assetProvider,
|
||||
variables,
|
||||
variables: { assetId: assetId || '' },
|
||||
skip: !assetId,
|
||||
});
|
||||
};
|
||||
|
@ -40,4 +40,5 @@ export const enabledAssetsProvider = makeDerivedDataProvider<
|
||||
export const useAssetsDataProvider = () =>
|
||||
useDataProvider({
|
||||
dataProvider: assetsProvider,
|
||||
variables: undefined,
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { formatNumber } from '@vegaprotocol/utils';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { Notification, Intent } from '@vegaprotocol/ui-toolkit';
|
||||
import { useDepositDialog } from '@vegaprotocol/deposits';
|
||||
@ -19,14 +19,14 @@ export const MarginWarning = ({ margin, balance, asset }: Props) => {
|
||||
<Notification
|
||||
intent={Intent.Warning}
|
||||
testId="dealticket-warning-margin"
|
||||
message={`You may not have enough margin available to open this position. ${formatNumber(
|
||||
message={`You may not have enough margin available to open this position. ${addDecimalsFormatNumber(
|
||||
margin,
|
||||
asset.decimals
|
||||
)} ${asset.symbol} ${t(
|
||||
'is currently required. You have only'
|
||||
)} ${formatNumber(balance, asset.decimals)} ${asset.symbol} ${t(
|
||||
'available.'
|
||||
)}`}
|
||||
)} ${addDecimalsFormatNumber(balance, asset.decimals)} ${
|
||||
asset.symbol
|
||||
} ${t('available.')}`}
|
||||
buttonProps={{
|
||||
text: t(`Deposit ${asset.symbol}`),
|
||||
action: () => openDepositDialog(asset.id),
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { useMemo } from 'react';
|
||||
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { useThrottledDataProvider } from '@vegaprotocol/react-helpers';
|
||||
@ -29,7 +28,7 @@ export const DealTicketContainer = ({
|
||||
} = useThrottledDataProvider(
|
||||
{
|
||||
dataProvider: marketDataProvider,
|
||||
variables: useMemo(() => ({ marketId }), [marketId]),
|
||||
variables: { marketId },
|
||||
},
|
||||
1000
|
||||
);
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
@ -12,22 +11,51 @@ interface DealTicketFeeDetailsProps {
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
margin: string;
|
||||
totalMargin: string;
|
||||
balance: string;
|
||||
}
|
||||
|
||||
export interface DealTicketFeeDetails {
|
||||
export interface DealTicketFeeDetailProps {
|
||||
label: string;
|
||||
value?: string | number | null;
|
||||
labelDescription?: string | ReactNode;
|
||||
symbol?: string;
|
||||
}
|
||||
|
||||
export const DealTicketFeeDetail = ({
|
||||
label,
|
||||
value,
|
||||
labelDescription,
|
||||
symbol,
|
||||
}: DealTicketFeeDetailProps) => (
|
||||
<div className="text-xs mt-2 flex justify-between items-center gap-4 flex-wrap">
|
||||
<div>
|
||||
<Tooltip description={labelDescription}>
|
||||
<div>{label}</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="text-neutral-500 dark:text-neutral-300">{`${value ?? '-'} ${
|
||||
symbol || ''
|
||||
}`}</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const DealTicketFeeDetails = ({
|
||||
order,
|
||||
market,
|
||||
marketData,
|
||||
margin,
|
||||
totalMargin,
|
||||
balance,
|
||||
}: DealTicketFeeDetailsProps) => {
|
||||
const feeDetails = useFeeDealTicketDetails(order, market, marketData);
|
||||
const details = useMemo(() => getFeeDetailsValues(feeDetails), [feeDetails]);
|
||||
const details = getFeeDetailsValues({
|
||||
...feeDetails,
|
||||
margin,
|
||||
totalMargin,
|
||||
balance,
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
{details.map(({ label, value, labelDescription, symbol }) => (
|
||||
|
@ -21,8 +21,7 @@ import {
|
||||
Intent,
|
||||
Notification,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import { useOrderMarginValidation } from '../../hooks/use-order-margin-validation';
|
||||
import { MarginWarning } from '../deal-ticket-validation/margin-warning';
|
||||
|
||||
import {
|
||||
validateExpiration,
|
||||
validateMarketState,
|
||||
@ -32,11 +31,16 @@ import {
|
||||
} from '../../utils';
|
||||
import { ZeroBalanceError } from '../deal-ticket-validation/zero-balance-error';
|
||||
import { SummaryValidationType } from '../../constants';
|
||||
import { useHasNoBalance } from '../../hooks/use-has-no-balance';
|
||||
import { useInitialMargin } from '../../hooks/use-initial-margin';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import { MarginWarning } from '../deal-ticket-validation/margin-warning';
|
||||
import {
|
||||
useMarketAccountBalance,
|
||||
useAccountBalance,
|
||||
} from '@vegaprotocol/accounts';
|
||||
|
||||
import { OrderTimeInForce, OrderType } from '@vegaprotocol/types';
|
||||
import { useOrderForm } from '../../hooks/use-order-form';
|
||||
import type { OrderObj } from '@vegaprotocol/orders';
|
||||
|
||||
export interface DealTicketProps {
|
||||
market: Market;
|
||||
@ -67,17 +71,41 @@ export const DealTicket = ({
|
||||
update,
|
||||
handleSubmit,
|
||||
} = useOrderForm(market.id);
|
||||
const marketStateError = validateMarketState(marketData.marketState);
|
||||
const hasNoBalance = useHasNoBalance(
|
||||
market.tradableInstrument.instrument.product.settlementAsset.id
|
||||
const asset = market.tradableInstrument.instrument.product.settlementAsset;
|
||||
const { accountBalance: marginAccountBalance } = useMarketAccountBalance(
|
||||
market.id
|
||||
);
|
||||
const { accountBalance: generalAccountBalance } = useAccountBalance(asset.id);
|
||||
const balance = (
|
||||
BigInt(marginAccountBalance) + BigInt(generalAccountBalance)
|
||||
).toString();
|
||||
|
||||
const marketStateError = validateMarketState(marketData.marketState);
|
||||
const hasNoBalance = generalAccountBalance === '0';
|
||||
const marketTradingModeError = validateMarketTradingMode(
|
||||
marketData.marketTradingMode
|
||||
);
|
||||
|
||||
const normalizedOrder =
|
||||
order &&
|
||||
normalizeOrderSubmission(
|
||||
order,
|
||||
market.decimalPlaces,
|
||||
market.positionDecimalPlaces
|
||||
);
|
||||
|
||||
const { margin, totalMargin } = useInitialMargin(
|
||||
market.id,
|
||||
normalizedOrder?.size,
|
||||
order?.side
|
||||
);
|
||||
|
||||
const checkForErrors = useCallback(() => {
|
||||
if (!pubKey) {
|
||||
setError('summary', { message: t('No public key selected') });
|
||||
setError('summary', {
|
||||
message: t('No public key selected'),
|
||||
type: SummaryValidationType.NoPubKey,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -114,6 +142,7 @@ export const DealTicket = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
(pubKey && errors.summary?.type === SummaryValidationType.NoPubKey) ||
|
||||
(!hasNoBalance &&
|
||||
errors.summary?.type === SummaryValidationType.NoCollateral) ||
|
||||
(marketStateError === true &&
|
||||
@ -125,6 +154,7 @@ export const DealTicket = ({
|
||||
}
|
||||
checkForErrors();
|
||||
}, [
|
||||
pubKey,
|
||||
hasNoBalance,
|
||||
marketStateError,
|
||||
marketTradingModeError,
|
||||
@ -254,9 +284,10 @@ export const DealTicket = ({
|
||||
)}
|
||||
<SummaryMessage
|
||||
errorMessage={errors.summary?.message}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
order={order}
|
||||
asset={asset}
|
||||
marketTradingMode={marketData.marketTradingMode}
|
||||
balance={balance}
|
||||
margin={totalMargin}
|
||||
isReadOnly={isReadOnly}
|
||||
pubKey={pubKey}
|
||||
onClickCollateral={onClickCollateral}
|
||||
@ -266,9 +297,16 @@ export const DealTicket = ({
|
||||
variant={order.side === Schema.Side.SIDE_BUY ? 'ternary' : 'secondary'}
|
||||
/>
|
||||
<DealTicketFeeDetails
|
||||
order={order}
|
||||
order={normalizeOrderSubmission(
|
||||
order,
|
||||
market.decimalPlaces,
|
||||
market.positionDecimalPlaces
|
||||
)}
|
||||
market={market}
|
||||
marketData={marketData}
|
||||
margin={margin}
|
||||
totalMargin={totalMargin}
|
||||
balance={marginAccountBalance}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
@ -280,9 +318,10 @@ export const DealTicket = ({
|
||||
*/
|
||||
interface SummaryMessageProps {
|
||||
errorMessage?: string;
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
order: OrderObj;
|
||||
asset: { id: string; symbol: string; name: string; decimals: number };
|
||||
marketTradingMode: MarketData['marketTradingMode'];
|
||||
balance: string;
|
||||
margin: string;
|
||||
isReadOnly: boolean;
|
||||
pubKey: string | null;
|
||||
onClickCollateral?: () => void;
|
||||
@ -290,22 +329,17 @@ interface SummaryMessageProps {
|
||||
const SummaryMessage = memo(
|
||||
({
|
||||
errorMessage,
|
||||
market,
|
||||
marketData,
|
||||
order,
|
||||
asset,
|
||||
marketTradingMode,
|
||||
balance,
|
||||
margin,
|
||||
isReadOnly,
|
||||
pubKey,
|
||||
onClickCollateral,
|
||||
}: SummaryMessageProps) => {
|
||||
// Specific error UI for if balance is so we can
|
||||
// render a deposit dialog
|
||||
const asset = market.tradableInstrument.instrument.product.settlementAsset;
|
||||
const assetSymbol = asset.symbol;
|
||||
const { balanceError, balance, margin } = useOrderMarginValidation({
|
||||
market,
|
||||
marketData,
|
||||
order,
|
||||
});
|
||||
const openVegaWalletDialog = useVegaWalletDialogStore(
|
||||
(store) => store.openVegaWalletDialog
|
||||
);
|
||||
@ -349,7 +383,7 @@ const SummaryMessage = memo(
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<ZeroBalanceError
|
||||
asset={market.tradableInstrument.instrument.product.settlementAsset}
|
||||
asset={asset}
|
||||
onClickCollateral={onClickCollateral}
|
||||
/>
|
||||
</div>
|
||||
@ -370,21 +404,16 @@ const SummaryMessage = memo(
|
||||
|
||||
// If there is no blocking error but user doesn't have enough
|
||||
// balance render the margin warning, but still allow submission
|
||||
if (balanceError) {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<MarginWarning balance={balance} margin={margin} asset={asset} />
|
||||
</div>
|
||||
);
|
||||
if (BigInt(balance) < BigInt(margin)) {
|
||||
return <MarginWarning balance={balance} margin={margin} asset={asset} />;
|
||||
}
|
||||
|
||||
// Show auction mode warning
|
||||
if (
|
||||
[
|
||||
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
|
||||
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||
].includes(marketData.marketTradingMode)
|
||||
].includes(marketTradingMode)
|
||||
) {
|
||||
return (
|
||||
<div className="mb-2">
|
||||
|
@ -55,6 +55,7 @@ export const MarketSelector = ({ market, setMarket, ItemRenderer }: Props) => {
|
||||
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: marketsProvider,
|
||||
variables: undefined,
|
||||
skipUpdates: true,
|
||||
});
|
||||
|
||||
|
@ -7,6 +7,15 @@ export const EST_MARGIN_TOOLTIP_TEXT = (settlementAsset: string) =>
|
||||
For example, for a notional size of $500, if the margin requirement is 10%, then the estimated margin would be approximately $50.`,
|
||||
[settlementAsset]
|
||||
);
|
||||
export const EST_TOTAL_MARGIN_TOOLTIP_TEXT = t(
|
||||
'Estimated total margin that will cover open position, active orders and this order.'
|
||||
);
|
||||
export const MARGIN_ACCOUNT_TOOLTIP_TEXT = t('Margin account balance');
|
||||
export const MARGIN_DIFF_TOOLTIP_TEXT = (settlementAsset: string) =>
|
||||
t(
|
||||
"The additional margin required for your new position (taking into account volume and open orders), compared to your current margin. Measured in the market's settlement asset ($s).",
|
||||
[settlementAsset]
|
||||
);
|
||||
export const CONTRACTS_MARGIN_TOOLTIP_TEXT = t(
|
||||
'The number of contracts determines how many units of the futures contract to buy or sell. For example, this is similar to buying one share of a listed company. The value of 1 contract is equivalent to the price of the contract. For example, if the current price is $50, then one contract is worth $50.'
|
||||
);
|
||||
@ -41,6 +50,7 @@ export enum MarketModeValidationType {
|
||||
}
|
||||
|
||||
export enum SummaryValidationType {
|
||||
NoPubKey = 'NoPubKey',
|
||||
NoCollateral = 'NoCollateral',
|
||||
TradingMode = 'MarketTradingMode',
|
||||
MarketState = 'MarketState',
|
||||
|
@ -4,5 +4,3 @@ export * from './use-fee-deal-ticket-details';
|
||||
export * from './use-market-positions';
|
||||
export * from './use-maximum-position-size';
|
||||
export * from './use-order-closeout';
|
||||
export * from './use-order-margin';
|
||||
export * from './use-order-margin-validation';
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { useMemo } from 'react';
|
||||
import { marketDepthProvider } from '@vegaprotocol/market-depth';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
@ -13,11 +12,10 @@ interface Props {
|
||||
}
|
||||
|
||||
export const useCalculateSlippage = ({ market, order }: Props) => {
|
||||
const variables = useMemo(() => ({ marketId: market.id }), [market.id]);
|
||||
const { data } = useThrottledDataProvider(
|
||||
{
|
||||
dataProvider: marketDepthProvider,
|
||||
variables,
|
||||
variables: { marketId: market.id },
|
||||
},
|
||||
1000
|
||||
);
|
||||
|
@ -3,24 +3,26 @@ import {
|
||||
addDecimal,
|
||||
addDecimalsFormatNumber,
|
||||
formatNumber,
|
||||
toBigNum,
|
||||
} from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { useMemo } from 'react';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import {
|
||||
EST_CLOSEOUT_TOOLTIP_TEXT,
|
||||
EST_MARGIN_TOOLTIP_TEXT,
|
||||
// EST_MARGIN_TOOLTIP_TEXT,
|
||||
EST_TOTAL_MARGIN_TOOLTIP_TEXT,
|
||||
NOTIONAL_SIZE_TOOLTIP_TEXT,
|
||||
MARGIN_ACCOUNT_TOOLTIP_TEXT,
|
||||
MARGIN_DIFF_TOOLTIP_TEXT,
|
||||
} from '../constants';
|
||||
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 { useMarketAccountBalance } from '@vegaprotocol/accounts';
|
||||
import { getDerivedPrice } from '../utils/get-price';
|
||||
import { useEstimateOrderQuery } from './__generated__/EstimateOrder';
|
||||
import type { EstimateOrderQuery } from './__generated__/EstimateOrder';
|
||||
|
||||
export const useFeeDealTicketDetails = (
|
||||
order: OrderSubmissionBody['orderSubmission'],
|
||||
@ -28,33 +30,23 @@ export const useFeeDealTicketDetails = (
|
||||
marketData: MarketData
|
||||
) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const slippage = useCalculateSlippage({ market, order });
|
||||
const { accountBalance } = useMarketAccountBalance(market.id);
|
||||
|
||||
const derivedPrice = useMemo(() => {
|
||||
return getDerivedPrice(order, market, marketData);
|
||||
}, [order, market, marketData]);
|
||||
const price = useMemo(() => {
|
||||
return getDerivedPrice(order, marketData);
|
||||
}, [order, marketData]);
|
||||
|
||||
// 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(derivedPrice).multipliedBy(multiplier).toNumber();
|
||||
}
|
||||
return derivedPrice;
|
||||
}
|
||||
return null;
|
||||
}, [derivedPrice, order.side, slippage]);
|
||||
|
||||
const estMargin = useOrderMargin({
|
||||
order,
|
||||
market,
|
||||
marketData,
|
||||
partyId: pubKey || '',
|
||||
derivedPrice,
|
||||
const { data: estMargin } = useEstimateOrderQuery({
|
||||
variables: {
|
||||
marketId: market.id,
|
||||
partyId: pubKey || '',
|
||||
price,
|
||||
size: order.size,
|
||||
side: order.side,
|
||||
timeInForce: order.timeInForce,
|
||||
type: order.type,
|
||||
},
|
||||
skip: !pubKey || !market || !order.size || !price,
|
||||
});
|
||||
|
||||
const estCloseOut = useOrderCloseOut({
|
||||
@ -64,13 +56,13 @@ export const useFeeDealTicketDetails = (
|
||||
});
|
||||
|
||||
const notionalSize = useMemo(() => {
|
||||
if (derivedPrice && order.size) {
|
||||
return new BigNumber(order.size)
|
||||
.multipliedBy(addDecimal(derivedPrice, market.decimalPlaces))
|
||||
if (price && order.size) {
|
||||
return toBigNum(order.size, market.positionDecimalPlaces)
|
||||
.multipliedBy(addDecimal(price, market.decimalPlaces))
|
||||
.toString();
|
||||
}
|
||||
return null;
|
||||
}, [derivedPrice, order.size, market.decimalPlaces]);
|
||||
}, [price, order.size, market.decimalPlaces, market.positionDecimalPlaces]);
|
||||
|
||||
const assetSymbol =
|
||||
market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
||||
@ -80,37 +72,40 @@ export const useFeeDealTicketDetails = (
|
||||
market,
|
||||
assetSymbol,
|
||||
notionalSize,
|
||||
estMargin,
|
||||
accountBalance,
|
||||
estimateOrder: estMargin?.estimateOrder,
|
||||
estCloseOut,
|
||||
slippage,
|
||||
slippageAdjustedPrice,
|
||||
};
|
||||
}, [
|
||||
market,
|
||||
assetSymbol,
|
||||
notionalSize,
|
||||
accountBalance,
|
||||
estMargin,
|
||||
estCloseOut,
|
||||
slippage,
|
||||
slippageAdjustedPrice,
|
||||
]);
|
||||
};
|
||||
|
||||
export interface FeeDetails {
|
||||
balance: string;
|
||||
market: Market;
|
||||
assetSymbol: string;
|
||||
notionalSize: string | null;
|
||||
estMargin: OrderMargin | null;
|
||||
estCloseOut: string | null;
|
||||
slippage: string | null;
|
||||
estimateOrder: EstimateOrderQuery['estimateOrder'] | undefined;
|
||||
margin: string;
|
||||
totalMargin: string;
|
||||
}
|
||||
|
||||
export const getFeeDetailsValues = ({
|
||||
balance,
|
||||
assetSymbol,
|
||||
notionalSize,
|
||||
estMargin,
|
||||
estCloseOut,
|
||||
estimateOrder,
|
||||
margin,
|
||||
market,
|
||||
notionalSize,
|
||||
totalMargin,
|
||||
}: FeeDetails) => {
|
||||
const assetDecimals =
|
||||
market.tradableInstrument.instrument.product.settlementAsset.decimals;
|
||||
@ -129,7 +124,12 @@ export const getFeeDetailsValues = ({
|
||||
? addDecimalsFormatNumber(value, assetDecimals)
|
||||
: '-';
|
||||
};
|
||||
return [
|
||||
const details: {
|
||||
label: string;
|
||||
value?: string | null;
|
||||
symbol: string;
|
||||
labelDescription: React.ReactNode;
|
||||
}[] = [
|
||||
{
|
||||
label: t('Notional'),
|
||||
value: formatValueWithMarketDp(notionalSize),
|
||||
@ -139,8 +139,8 @@ export const getFeeDetailsValues = ({
|
||||
{
|
||||
label: t('Fees'),
|
||||
value:
|
||||
estMargin?.totalFees &&
|
||||
`~${formatValueWithAssetDp(estMargin?.totalFees)}`,
|
||||
estimateOrder?.totalFeeAmount &&
|
||||
`~${formatValueWithAssetDp(estimateOrder?.totalFeeAmount)}`,
|
||||
labelDescription: (
|
||||
<>
|
||||
<span>
|
||||
@ -149,7 +149,7 @@ export const getFeeDetailsValues = ({
|
||||
)}
|
||||
</span>
|
||||
<FeesBreakdown
|
||||
fees={estMargin?.fees}
|
||||
fees={estimateOrder?.fee}
|
||||
feeFactors={market.fees.factors}
|
||||
symbol={assetSymbol}
|
||||
decimals={assetDecimals}
|
||||
@ -158,18 +158,46 @@ export const getFeeDetailsValues = ({
|
||||
),
|
||||
symbol: assetSymbol,
|
||||
},
|
||||
/*
|
||||
{
|
||||
label: t('Margin'),
|
||||
value:
|
||||
estMargin?.margin && `~${formatValueWithAssetDp(estMargin?.margin)}`,
|
||||
label: t('Initial margin'),
|
||||
value: margin && `~${formatValueWithAssetDp(margin)}`,
|
||||
symbol: assetSymbol,
|
||||
labelDescription: EST_MARGIN_TOOLTIP_TEXT(assetSymbol),
|
||||
},
|
||||
*/
|
||||
{
|
||||
label: t('Liquidation'),
|
||||
value: estCloseOut && `~${formatValueWithMarketDp(estCloseOut)}`,
|
||||
symbol: market.tradableInstrument.instrument.product.quoteName,
|
||||
labelDescription: EST_CLOSEOUT_TOOLTIP_TEXT(quoteName),
|
||||
label: t('Margin required'),
|
||||
value: `~${formatValueWithAssetDp(
|
||||
balance
|
||||
? (BigInt(totalMargin) - BigInt(balance)).toString()
|
||||
: totalMargin
|
||||
)}`,
|
||||
symbol: assetSymbol,
|
||||
labelDescription: MARGIN_DIFF_TOOLTIP_TEXT(assetSymbol),
|
||||
},
|
||||
];
|
||||
if (balance) {
|
||||
details.push({
|
||||
label: t('Projected margin'),
|
||||
value: `~${formatValueWithAssetDp(totalMargin)}`,
|
||||
symbol: assetSymbol,
|
||||
labelDescription: EST_TOTAL_MARGIN_TOOLTIP_TEXT,
|
||||
});
|
||||
}
|
||||
details.push({
|
||||
label: t('Current margin allocation'),
|
||||
value: balance
|
||||
? `~${formatValueWithAssetDp(balance)}`
|
||||
: `${formatValueWithAssetDp(balance)}`,
|
||||
symbol: assetSymbol,
|
||||
labelDescription: MARGIN_ACCOUNT_TOOLTIP_TEXT,
|
||||
});
|
||||
details.push({
|
||||
label: t('Liquidation'),
|
||||
value: estCloseOut && `~${formatValueWithMarketDp(estCloseOut)}`,
|
||||
symbol: market.tradableInstrument.instrument.product.quoteName,
|
||||
labelDescription: EST_CLOSEOUT_TOOLTIP_TEXT(quoteName),
|
||||
});
|
||||
return details;
|
||||
};
|
||||
|
@ -1,11 +0,0 @@
|
||||
import { useAccountBalance } from '@vegaprotocol/accounts';
|
||||
import { toBigNum } from '@vegaprotocol/utils';
|
||||
|
||||
export const useHasNoBalance = (assetId: string) => {
|
||||
const { accountBalance, accountDecimals } = useAccountBalance(assetId);
|
||||
const balance =
|
||||
accountBalance && accountDecimals !== null
|
||||
? toBigNum(accountBalance, accountDecimals)
|
||||
: toBigNum('0', 0);
|
||||
return balance.isZero();
|
||||
};
|
70
libs/deal-ticket/src/hooks/use-initial-margin.ts
Normal file
70
libs/deal-ticket/src/hooks/use-initial-margin.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { marketDataProvider } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
calculateMargins,
|
||||
// getDerivedPrice,
|
||||
volumeAndMarginProvider,
|
||||
} from '@vegaprotocol/positions';
|
||||
import { Side } from '@vegaprotocol/types';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { marketInfoProvider } from '@vegaprotocol/market-info';
|
||||
|
||||
export const useInitialMargin = (
|
||||
marketId: OrderSubmissionBody['orderSubmission']['marketId'],
|
||||
size?: OrderSubmissionBody['orderSubmission']['size'],
|
||||
side?: OrderSubmissionBody['orderSubmission']['side']
|
||||
) => {
|
||||
const { pubKey: partyId } = useVegaWallet();
|
||||
const commonVariables = { marketId, partyId: partyId || '' };
|
||||
const { data: marketData } = useDataProvider({
|
||||
dataProvider: marketDataProvider,
|
||||
variables: { marketId },
|
||||
});
|
||||
const { data: activeVolumeAndMargin } = useDataProvider({
|
||||
dataProvider: volumeAndMarginProvider,
|
||||
variables: commonVariables,
|
||||
skip: !partyId,
|
||||
});
|
||||
const { data: marketInfo } = useDataProvider({
|
||||
dataProvider: marketInfoProvider,
|
||||
variables: commonVariables,
|
||||
});
|
||||
let totalMargin = '0';
|
||||
let margin = '0';
|
||||
if (marketInfo?.riskFactors && marketData && size && side) {
|
||||
const {
|
||||
positionDecimalPlaces,
|
||||
decimalPlaces,
|
||||
tradableInstrument,
|
||||
riskFactors,
|
||||
} = marketInfo;
|
||||
const { marginCalculator, instrument } = tradableInstrument;
|
||||
const { decimals } = instrument.product.settlementAsset;
|
||||
margin = totalMargin = calculateMargins({
|
||||
side,
|
||||
size,
|
||||
price: marketData.markPrice, // getDerivedPrice(order, marketData), same in positions-data-providers
|
||||
positionDecimalPlaces,
|
||||
decimalPlaces,
|
||||
decimals,
|
||||
scalingFactors: marginCalculator?.scalingFactors,
|
||||
riskFactors,
|
||||
}).initialMargin;
|
||||
}
|
||||
|
||||
if (activeVolumeAndMargin) {
|
||||
let sellMargin = BigInt(activeVolumeAndMargin.sellInitialMargin);
|
||||
let buyMargin = BigInt(activeVolumeAndMargin.buyInitialMargin);
|
||||
if (side === Side.SIDE_SELL) {
|
||||
sellMargin += BigInt(totalMargin);
|
||||
} else {
|
||||
buyMargin += BigInt(totalMargin);
|
||||
}
|
||||
totalMargin =
|
||||
sellMargin > buyMargin ? sellMargin.toString() : buyMargin.toString();
|
||||
}
|
||||
|
||||
return useMemo(() => ({ totalMargin, margin }), [totalMargin, margin]);
|
||||
};
|
@ -1,48 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { toBigNum } from '@vegaprotocol/utils';
|
||||
import { useAccountBalance } from '@vegaprotocol/accounts';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { useOrderMargin } from './use-order-margin';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
|
||||
interface Props {
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
}
|
||||
|
||||
export const useOrderMarginValidation = ({
|
||||
market,
|
||||
marketData,
|
||||
order,
|
||||
}: Props) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const estMargin = useOrderMargin({
|
||||
order,
|
||||
market,
|
||||
marketData,
|
||||
partyId: pubKey || '',
|
||||
});
|
||||
const { id: assetId, decimals: assetDecimals } =
|
||||
market.tradableInstrument.instrument.product.settlementAsset;
|
||||
|
||||
const { accountBalance, accountDecimals } = useAccountBalance(assetId);
|
||||
const balance =
|
||||
accountBalance && accountDecimals !== null
|
||||
? toBigNum(accountBalance, accountDecimals)
|
||||
: toBigNum('0', assetDecimals);
|
||||
const margin = toBigNum(estMargin?.margin || 0, assetDecimals);
|
||||
|
||||
// return only simple types (bool, string) for make memo sensible
|
||||
const balanceError = balance.isGreaterThan(0) && balance.isLessThan(margin);
|
||||
const balanceAsString = balance.toString();
|
||||
const marginAsString = margin.toString();
|
||||
return useMemo(() => {
|
||||
return {
|
||||
balance: balanceAsString,
|
||||
margin: marginAsString,
|
||||
balanceError,
|
||||
};
|
||||
}, [balanceAsString, marginAsString, balanceError]);
|
||||
};
|
@ -1,116 +0,0 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import type { PositionMargin } from './use-market-positions';
|
||||
import type { Props } from './use-order-margin';
|
||||
import { useOrderMargin } from './use-order-margin';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
|
||||
let mockEstimateData = {
|
||||
estimateOrder: {
|
||||
fee: {
|
||||
makerFee: '100000.000',
|
||||
infrastructureFee: '100000.000',
|
||||
liquidityFee: '100000.000',
|
||||
},
|
||||
marginLevels: {
|
||||
initialLevel: '200000',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock('@apollo/client', () => ({
|
||||
...jest.requireActual('@apollo/client'),
|
||||
useQuery: jest.fn(() => ({ data: mockEstimateData })),
|
||||
}));
|
||||
|
||||
let mockMarketPositions: PositionMargin = {
|
||||
openVolume: '1',
|
||||
balance: '100000',
|
||||
};
|
||||
|
||||
jest.mock('./use-market-positions', () => ({
|
||||
useMarketPositions: ({
|
||||
marketId,
|
||||
partyId,
|
||||
}: {
|
||||
marketId: string;
|
||||
partyId: string;
|
||||
}) => mockMarketPositions,
|
||||
}));
|
||||
|
||||
describe('useOrderMargin', () => {
|
||||
const marketId = 'marketId';
|
||||
const args: Props = {
|
||||
order: {
|
||||
marketId,
|
||||
size: '2',
|
||||
side: Schema.Side.SIDE_BUY,
|
||||
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
|
||||
type: Schema.OrderType.TYPE_MARKET,
|
||||
},
|
||||
market: {
|
||||
id: marketId,
|
||||
decimalPlaces: 2,
|
||||
positionDecimalPlaces: 0,
|
||||
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
} as unknown as Market,
|
||||
marketData: {
|
||||
indicativePrice: '100',
|
||||
markPrice: '200',
|
||||
} as unknown as MarketData,
|
||||
partyId: 'partyId',
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should calculate margin correctly', () => {
|
||||
const { result } = renderHook(() => useOrderMargin(args));
|
||||
expect(result.current?.margin).toEqual('100000');
|
||||
expect((useQuery as jest.Mock).mock.calls[0][1].variables.size).toEqual(
|
||||
args.order.size
|
||||
);
|
||||
});
|
||||
|
||||
it('should calculate fees correctly', () => {
|
||||
const { result } = renderHook(() => useOrderMargin(args));
|
||||
expect(result.current?.totalFees).toEqual('300000');
|
||||
});
|
||||
|
||||
it('should not subtract initialMargin if there is no position', () => {
|
||||
mockMarketPositions = null;
|
||||
const { result } = renderHook(() => useOrderMargin(args));
|
||||
expect(result.current?.margin).toEqual('200000');
|
||||
|
||||
expect((useQuery as jest.Mock).mock.calls[0][1].variables.size).toEqual(
|
||||
args.order.size
|
||||
);
|
||||
});
|
||||
|
||||
it('should return empty value if API fails', () => {
|
||||
mockEstimateData = {
|
||||
estimateOrder: {
|
||||
fee: {
|
||||
makerFee: '100000.000',
|
||||
infrastructureFee: '100000.000',
|
||||
liquidityFee: '100000.000',
|
||||
},
|
||||
marginLevels: {
|
||||
initialLevel: '',
|
||||
},
|
||||
},
|
||||
};
|
||||
const { result } = renderHook(() => useOrderMargin(args));
|
||||
expect(result.current).toEqual(null);
|
||||
|
||||
const calledSize = new BigNumber(mockMarketPositions?.openVolume || 0)
|
||||
.plus(args.order.size)
|
||||
.toString();
|
||||
expect((useQuery as jest.Mock).mock.calls[0][1].variables.size).toEqual(
|
||||
calledSize
|
||||
);
|
||||
});
|
||||
});
|
@ -1,76 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
|
||||
import { removeDecimal } from '@vegaprotocol/utils';
|
||||
import { useMarketPositions } from './use-market-positions';
|
||||
import { useEstimateOrderQuery } from './__generated__/EstimateOrder';
|
||||
import type { Market, MarketData } from '@vegaprotocol/market-list';
|
||||
import { getDerivedPrice } from '../utils/get-price';
|
||||
|
||||
export interface Props {
|
||||
order: OrderSubmissionBody['orderSubmission'];
|
||||
market: Market;
|
||||
marketData: MarketData;
|
||||
partyId: string;
|
||||
derivedPrice?: string;
|
||||
}
|
||||
|
||||
export interface OrderMargin {
|
||||
margin: string;
|
||||
totalFees: string | null;
|
||||
fees: {
|
||||
makerFee: string;
|
||||
liquidityFee: string;
|
||||
infrastructureFee: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const useOrderMargin = ({
|
||||
order,
|
||||
market,
|
||||
marketData,
|
||||
partyId,
|
||||
derivedPrice,
|
||||
}: Props): OrderMargin | null => {
|
||||
const { balance } = useMarketPositions({ marketId: market.id }) || {};
|
||||
const priceForEstimate =
|
||||
derivedPrice || getDerivedPrice(order, market, marketData);
|
||||
|
||||
const { data } = useEstimateOrderQuery({
|
||||
variables: {
|
||||
marketId: market.id,
|
||||
partyId,
|
||||
price: priceForEstimate,
|
||||
size: removeDecimal(order.size, market.positionDecimalPlaces),
|
||||
side: order.side,
|
||||
timeInForce: order.timeInForce,
|
||||
type: order.type,
|
||||
},
|
||||
skip: !partyId || !market.id || !order.size || !priceForEstimate,
|
||||
});
|
||||
const { makerFee, liquidityFee, infrastructureFee } = data?.estimateOrder
|
||||
.fee || { makerFee: '', liquidityFee: '', infrastructureFee: '' };
|
||||
const { initialLevel } = data?.estimateOrder.marginLevels ?? {};
|
||||
return useMemo(() => {
|
||||
if (initialLevel) {
|
||||
const margin = BigNumber.maximum(
|
||||
0,
|
||||
new BigNumber(initialLevel).minus(balance || 0)
|
||||
).toString();
|
||||
const fees = new BigNumber(makerFee)
|
||||
.plus(liquidityFee)
|
||||
.plus(infrastructureFee)
|
||||
.toString();
|
||||
return {
|
||||
margin,
|
||||
totalFees: fees,
|
||||
fees: {
|
||||
makerFee,
|
||||
liquidityFee,
|
||||
infrastructureFee,
|
||||
},
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}, [initialLevel, makerFee, liquidityFee, infrastructureFee, balance]);
|
||||
};
|
@ -64,20 +64,27 @@ export function generateMarketData(
|
||||
id: 'market-id',
|
||||
__typename: 'Market',
|
||||
},
|
||||
auctionStart: '2022-06-21T17:18:43.484055236Z',
|
||||
auctionEnd: '2022-06-21T17:18:43.484055236Z',
|
||||
targetStake: '1000000',
|
||||
suppliedStake: '1000',
|
||||
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
marketState: Schema.MarketState.STATE_ACTIVE,
|
||||
staticMidPrice: '0',
|
||||
indicativePrice: '100',
|
||||
bestStaticBidPrice: '0',
|
||||
bestStaticOfferPrice: '0',
|
||||
indicativeVolume: '10',
|
||||
auctionStart: '2022-06-21T17:18:43.484055236Z',
|
||||
bestBidPrice: '0',
|
||||
bestBidVolume: '0',
|
||||
bestOfferPrice: '0',
|
||||
bestOfferVolume: '0',
|
||||
bestStaticBidPrice: '0',
|
||||
bestStaticBidVolume: '0',
|
||||
bestStaticOfferPrice: '0',
|
||||
bestStaticOfferVolume: '0',
|
||||
indicativePrice: '100',
|
||||
indicativeVolume: '10',
|
||||
marketState: Schema.MarketState.STATE_ACTIVE,
|
||||
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
marketValueProxy: '',
|
||||
markPrice: '200',
|
||||
midPrice: '0',
|
||||
openInterest: '',
|
||||
staticMidPrice: '0',
|
||||
suppliedStake: '1000',
|
||||
targetStake: '1000000',
|
||||
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_BATCH,
|
||||
};
|
||||
return merge(defaultMarketData, override);
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { removeDecimal } from '@vegaprotocol/utils';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import { isMarketInAuction } from './is-market-in-auction';
|
||||
import type { MarketData, Market } from '@vegaprotocol/market-list';
|
||||
import type { MarketData } from '@vegaprotocol/market-list';
|
||||
|
||||
/**
|
||||
* Get the market price based on market mode (auction or not auction)
|
||||
@ -34,7 +33,6 @@ export const getDerivedPrice = (
|
||||
type: Schema.OrderType;
|
||||
price?: string | undefined;
|
||||
},
|
||||
market: Market,
|
||||
marketData: MarketData
|
||||
) => {
|
||||
// If order type is market we should use either the mark price
|
||||
@ -44,7 +42,7 @@ export const getDerivedPrice = (
|
||||
// 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);
|
||||
price = order.price;
|
||||
} else {
|
||||
price = getMarketPrice(marketData);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ export const DepositContainer = ({ assetId }: { assetId?: string }) => {
|
||||
const { VEGA_ENV } = useEnvironment();
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: enabledAssetsProvider,
|
||||
variables: undefined,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -13,6 +13,7 @@ import type { PageInfo, Edge } from '@vegaprotocol/utils';
|
||||
import { FillsDocument, FillsEventDocument } from './__generated__/Fills';
|
||||
import type {
|
||||
FillsQuery,
|
||||
FillsQueryVariables,
|
||||
FillFieldsFragment,
|
||||
FillEdgeFragment,
|
||||
FillsEventSubscription,
|
||||
@ -62,13 +63,19 @@ export type TradeEdge = Edge<Trade>;
|
||||
const getData = (responseData: FillsQuery | null): FillEdgeFragment[] =>
|
||||
responseData?.party?.tradesConnection?.edges || [];
|
||||
|
||||
const getPageInfo = (responseData: FillsQuery): PageInfo | null =>
|
||||
responseData.party?.tradesConnection?.pageInfo || null;
|
||||
const getPageInfo = (responseData: FillsQuery | null): PageInfo | null =>
|
||||
responseData?.party?.tradesConnection?.pageInfo || null;
|
||||
|
||||
const getDelta = (subscriptionData: FillsEventSubscription) =>
|
||||
subscriptionData.trades || [];
|
||||
|
||||
export const fillsProvider = makeDataProvider({
|
||||
export const fillsProvider = makeDataProvider<
|
||||
Parameters<typeof getData>['0'],
|
||||
ReturnType<typeof getData>,
|
||||
Parameters<typeof getDelta>['0'],
|
||||
ReturnType<typeof getDelta>,
|
||||
FillsQueryVariables
|
||||
>({
|
||||
query: FillsDocument,
|
||||
subscriptionQuery: FillsEventDocument,
|
||||
update,
|
||||
@ -83,9 +90,13 @@ export const fillsProvider = makeDataProvider({
|
||||
|
||||
export const fillsWithMarketProvider = makeDerivedDataProvider<
|
||||
(TradeEdge | null)[],
|
||||
Trade[]
|
||||
Trade[],
|
||||
FillsQueryVariables
|
||||
>(
|
||||
[fillsProvider, marketsProvider],
|
||||
[
|
||||
fillsProvider,
|
||||
(callback, client) => marketsProvider(callback, client, undefined),
|
||||
],
|
||||
(partsData): (TradeEdge | null)[] =>
|
||||
(partsData[0] as ReturnType<typeof getData>)?.map(
|
||||
(edge) =>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { RefObject } from 'react';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { useCallback, useMemo, useRef } from 'react';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { makeInfiniteScrollGetRows } from '@vegaprotocol/utils';
|
||||
import { useDataProvider, updateGridData } from '@vegaprotocol/react-helpers';
|
||||
import type { Trade, TradeEdge } from './fills-data-provider';
|
||||
@ -73,16 +73,11 @@ export const useFillsList = ({
|
||||
[gridRef]
|
||||
);
|
||||
|
||||
const variables = useMemo(() => ({ partyId, marketId }), [partyId, marketId]);
|
||||
|
||||
const { data, error, loading, load, totalCount, reload } = useDataProvider<
|
||||
(TradeEdge | null)[],
|
||||
Trade[]
|
||||
>({
|
||||
const { data, error, loading, load, totalCount, reload } = useDataProvider({
|
||||
dataProvider: fillsWithMarketProvider,
|
||||
update,
|
||||
insert,
|
||||
variables,
|
||||
variables: { partyId, marketId: marketId || '' },
|
||||
});
|
||||
totalCountRef.current = totalCount;
|
||||
|
||||
|
@ -42,7 +42,7 @@ export const update = (
|
||||
data: ReturnType<typeof getData> | null,
|
||||
delta: ReturnType<typeof getData>,
|
||||
reload: () => void,
|
||||
variables?: LedgerEntriesQueryVariables
|
||||
variables: LedgerEntriesQueryVariables
|
||||
) => {
|
||||
if (!data) {
|
||||
return data;
|
||||
@ -110,8 +110,8 @@ export const ledgerEntriesProvider = makeDerivedDataProvider<
|
||||
>(
|
||||
[
|
||||
ledgerEntriesOnlyProvider,
|
||||
(callback, client) => assetsProvider(callback, client),
|
||||
marketsProvider,
|
||||
(callback, client) => assetsProvider(callback, client, undefined),
|
||||
(callback, client) => marketsProvider(callback, client, undefined),
|
||||
],
|
||||
([entries, assets, markets]) => {
|
||||
return entries.map((edge: AggregatedLedgerEntriesEdge) => {
|
||||
|
@ -14,11 +14,14 @@ import {
|
||||
|
||||
import type {
|
||||
MarketLpQuery,
|
||||
MarketLpQueryVariables,
|
||||
LiquidityProviderFeeShareFieldsFragment,
|
||||
LiquidityProviderFeeShareQuery,
|
||||
LiquidityProviderFeeShareQueryVariables,
|
||||
LiquidityProviderFeeShareUpdateSubscription,
|
||||
LiquidityProvisionFieldsFragment,
|
||||
LiquidityProvisionsQuery,
|
||||
LiquidityProvisionsQueryVariables,
|
||||
LiquidityProvisionsUpdateSubscription,
|
||||
} from './__generated__/MarketLiquidity';
|
||||
import type { IterableElement } from 'type-fest';
|
||||
@ -27,7 +30,8 @@ export const liquidityProvisionsDataProvider = makeDataProvider<
|
||||
LiquidityProvisionsQuery,
|
||||
LiquidityProvisionFieldsFragment[],
|
||||
LiquidityProvisionsUpdateSubscription,
|
||||
LiquidityProvisionsUpdateSubscription['liquidityProvisions']
|
||||
LiquidityProvisionsUpdateSubscription['liquidityProvisions'],
|
||||
LiquidityProvisionsQueryVariables
|
||||
>({
|
||||
query: LiquidityProvisionsDocument,
|
||||
subscriptionQuery: LiquidityProvisionsUpdateDocument,
|
||||
@ -99,7 +103,8 @@ export const marketLiquidityDataProvider = makeDataProvider<
|
||||
MarketLpQuery,
|
||||
MarketLpQuery,
|
||||
never,
|
||||
never
|
||||
never,
|
||||
MarketLpQueryVariables
|
||||
>({
|
||||
query: MarketLpDocument,
|
||||
getData: (responseData: MarketLpQuery | null) => {
|
||||
@ -111,7 +116,8 @@ export const liquidityFeeShareDataProvider = makeDataProvider<
|
||||
LiquidityProviderFeeShareQuery,
|
||||
LiquidityProviderFeeShareFieldsFragment[],
|
||||
LiquidityProviderFeeShareUpdateSubscription,
|
||||
LiquidityProviderFeeShareUpdateSubscription['marketsData'][0]['liquidityProviderFeeShare']
|
||||
LiquidityProviderFeeShareUpdateSubscription['marketsData'][0]['liquidityProviderFeeShare'],
|
||||
LiquidityProviderFeeShareQueryVariables
|
||||
>({
|
||||
query: LiquidityProviderFeeShareDocument,
|
||||
subscriptionQuery: LiquidityProviderFeeShareUpdateDocument,
|
||||
@ -147,7 +153,11 @@ export const liquidityFeeShareDataProvider = makeDataProvider<
|
||||
},
|
||||
});
|
||||
|
||||
export const lpAggregatedDataProvider = makeDerivedDataProvider(
|
||||
export const lpAggregatedDataProvider = makeDerivedDataProvider<
|
||||
ReturnType<typeof getLiquidityProvision>,
|
||||
never,
|
||||
MarketLpQueryVariables
|
||||
>(
|
||||
[
|
||||
liquidityProvisionsDataProvider,
|
||||
marketLiquidityDataProvider,
|
||||
|
@ -5,12 +5,10 @@ import { useDataProvider, useYesterday } from '@vegaprotocol/react-helpers';
|
||||
import type {
|
||||
MarketCandles,
|
||||
MarketMaybeWithDataAndCandles,
|
||||
MarketsCandlesQueryVariables,
|
||||
} from '@vegaprotocol/market-list';
|
||||
|
||||
import {
|
||||
marketsCandlesProvider,
|
||||
marketListProvider,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { marketListProvider } from '@vegaprotocol/market-list';
|
||||
|
||||
import type { LiquidityProvisionMarketsQuery } from './__generated__/MarketsLiquidity';
|
||||
import { LiquidityProvisionMarketsDocument } from './__generated__/MarketsLiquidity';
|
||||
@ -97,15 +95,18 @@ export const liquidityMarketsProvider = makeDataProvider<
|
||||
getData,
|
||||
});
|
||||
|
||||
const liquidityProvisionProvider = makeDerivedDataProvider<Market[], never>(
|
||||
const liquidityProvisionProvider = makeDerivedDataProvider<
|
||||
Market[],
|
||||
never,
|
||||
Exclude<MarketsCandlesQueryVariables, 'interval'>
|
||||
>(
|
||||
[
|
||||
marketListProvider,
|
||||
(callback, client, variables) =>
|
||||
marketsCandlesProvider(callback, client, {
|
||||
...variables,
|
||||
marketListProvider(callback, client, {
|
||||
since: variables.since,
|
||||
interval: Schema.Interval.INTERVAL_I1D,
|
||||
}),
|
||||
liquidityMarketsProvider,
|
||||
(callback, client) => liquidityMarketsProvider(callback, client, undefined),
|
||||
],
|
||||
(parts) => {
|
||||
return addData(
|
||||
|
@ -31,7 +31,7 @@ describe('market depth provider update', () => {
|
||||
sequenceNumber: '',
|
||||
previousSequenceNumber: '',
|
||||
};
|
||||
const updatedData = update(data, [delta], reload);
|
||||
const updatedData = update(data, [delta], reload, { marketId: '1' });
|
||||
expect(updatedData).toBe(data);
|
||||
});
|
||||
|
||||
@ -54,8 +54,12 @@ describe('market depth provider update', () => {
|
||||
previousSequenceNumber: '',
|
||||
},
|
||||
];
|
||||
expect(update(data, delta.slice(0, 1), reload)).toBe(data);
|
||||
expect(update(data, delta.slice(1, 2), reload)).toBe(data);
|
||||
expect(update(data, delta.slice(0, 1), reload, { marketId: '1' })).toBe(
|
||||
data
|
||||
);
|
||||
expect(update(data, delta.slice(1, 2), reload, { marketId: '1' })).toBe(
|
||||
data
|
||||
);
|
||||
});
|
||||
|
||||
it('restarts and captureException when there is gap in updates', () => {
|
||||
@ -72,7 +76,7 @@ describe('market depth provider update', () => {
|
||||
previousSequenceNumber: '12',
|
||||
},
|
||||
];
|
||||
const updatedData = update(data, delta, reload);
|
||||
const updatedData = update(data, delta, reload, { marketId: '1' });
|
||||
expect(updatedData).toBe(data);
|
||||
expect(reload).toBeCalled();
|
||||
expect(mockCaptureException).toBeCalled();
|
||||
|
@ -9,12 +9,14 @@ import {
|
||||
} from './__generated__/MarketDepth';
|
||||
import type {
|
||||
MarketDepthQuery,
|
||||
MarketDepthQueryVariables,
|
||||
MarketDepthUpdateSubscription,
|
||||
} from './__generated__/MarketDepth';
|
||||
|
||||
export const update: Update<
|
||||
ReturnType<typeof getData>,
|
||||
ReturnType<typeof getDelta>
|
||||
ReturnType<typeof getDelta>,
|
||||
MarketDepthQueryVariables
|
||||
> = (data, deltas, reload) => {
|
||||
if (!data) {
|
||||
return data;
|
||||
@ -61,12 +63,19 @@ export const update: Update<
|
||||
return data;
|
||||
};
|
||||
|
||||
const getData = (responseData: MarketDepthQuery | null) => responseData?.market;
|
||||
const getData = (responseData: MarketDepthQuery | null) =>
|
||||
responseData?.market || null;
|
||||
|
||||
const getDelta = (subscriptionData: MarketDepthUpdateSubscription) =>
|
||||
subscriptionData.marketsDepthUpdate;
|
||||
|
||||
export const marketDepthProvider = makeDataProvider({
|
||||
export const marketDepthProvider = makeDataProvider<
|
||||
MarketDepthQuery,
|
||||
ReturnType<typeof getData>,
|
||||
MarketDepthUpdateSubscription,
|
||||
ReturnType<typeof getDelta>,
|
||||
MarketDepthQueryVariables
|
||||
>({
|
||||
query: MarketDepthDocument,
|
||||
subscriptionQuery: MarketDepthUpdateDocument,
|
||||
update,
|
||||
|
@ -7,12 +7,13 @@ import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { marketDepthProvider } from './market-depth-provider';
|
||||
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
|
||||
import type { MarketData } from '@vegaprotocol/market-list';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import type {
|
||||
MarketDepthUpdateSubscription,
|
||||
MarketDepthQuery,
|
||||
PriceLevelFieldsFragment,
|
||||
MarketDepthQueryVariables,
|
||||
} from './__generated__/MarketDepth';
|
||||
import type { PriceLevelFieldsFragment } from './__generated__/MarketDepth';
|
||||
import {
|
||||
compactRows,
|
||||
updateCompactedRows,
|
||||
@ -28,7 +29,7 @@ interface OrderbookManagerProps {
|
||||
|
||||
export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
|
||||
const [resolution, setResolution] = useState(1);
|
||||
const variables = useMemo(() => ({ marketId }), [marketId]);
|
||||
const variables = { marketId };
|
||||
const resolutionRef = useRef(resolution);
|
||||
const [orderbookData, setOrderbookData] = useState<OrderbookData>({
|
||||
rows: null,
|
||||
@ -79,8 +80,8 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
|
||||
delta: deltas,
|
||||
data: rawData,
|
||||
}: {
|
||||
delta?: MarketDepthUpdateSubscription['marketsDepthUpdate'];
|
||||
data?: MarketDepthQuery['market'];
|
||||
delta?: MarketDepthUpdateSubscription['marketsDepthUpdate'] | null;
|
||||
data: NonNullable<MarketDepthQuery['market']> | null | undefined;
|
||||
}) => {
|
||||
if (!dataRef.current.rows) {
|
||||
return false;
|
||||
@ -103,7 +104,11 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
|
||||
[marketId, updateOrderbookData]
|
||||
);
|
||||
|
||||
const { data, error, loading, flush, reload } = useDataProvider({
|
||||
const { data, error, loading, flush, reload } = useDataProvider<
|
||||
MarketDepthQuery['market'] | undefined,
|
||||
MarketDepthUpdateSubscription['marketsDepthUpdate'] | null,
|
||||
MarketDepthQueryVariables
|
||||
>({
|
||||
dataProvider: marketDepthProvider,
|
||||
update,
|
||||
variables,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { totalFeesPercentage } from '@vegaprotocol/market-list';
|
||||
import type { TradeFee, FeeFactors } from '@vegaprotocol/types';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumberPercentage,
|
||||
@ -7,12 +8,7 @@ import { t } from '@vegaprotocol/i18n';
|
||||
import { Tooltip } from '@vegaprotocol/ui-toolkit';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
import type { Market } from '@vegaprotocol/market-list';
|
||||
export const FeesCell = ({
|
||||
feeFactors,
|
||||
}: {
|
||||
feeFactors: Market['fees']['factors'];
|
||||
}) => (
|
||||
export const FeesCell = ({ feeFactors }: { feeFactors: FeeFactors }) => (
|
||||
<Tooltip description={<FeesBreakdownPercentage feeFactors={feeFactors} />}>
|
||||
<span>{totalFeesPercentage(feeFactors) ?? '-'}</span>
|
||||
</Tooltip>
|
||||
@ -21,7 +17,7 @@ export const FeesCell = ({
|
||||
export const FeesBreakdownPercentage = ({
|
||||
feeFactors,
|
||||
}: {
|
||||
feeFactors?: Market['fees']['factors'];
|
||||
feeFactors?: FeeFactors;
|
||||
}) => {
|
||||
if (!feeFactors) return null;
|
||||
return (
|
||||
@ -54,12 +50,8 @@ export const FeesBreakdown = ({
|
||||
symbol,
|
||||
decimals,
|
||||
}: {
|
||||
fees?: {
|
||||
infrastructureFee: string;
|
||||
liquidityFee: string;
|
||||
makerFee: string;
|
||||
};
|
||||
feeFactors?: Market['fees']['factors'];
|
||||
fees?: TradeFee;
|
||||
feeFactors?: FeeFactors;
|
||||
symbol?: string;
|
||||
decimals: number;
|
||||
}) => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
query MarketInfo($marketId: ID!, $interval: Interval!, $since: String!) {
|
||||
query MarketInfo($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
id
|
||||
decimalPlaces
|
||||
@ -32,7 +32,6 @@ query MarketInfo($marketId: ID!, $interval: Interval!, $since: String!) {
|
||||
}
|
||||
}
|
||||
}
|
||||
tradingMode
|
||||
fees {
|
||||
factors {
|
||||
makerFee
|
||||
@ -54,35 +53,6 @@ query MarketInfo($marketId: ID!, $interval: Interval!, $since: String!) {
|
||||
short
|
||||
long
|
||||
}
|
||||
data {
|
||||
market {
|
||||
id
|
||||
}
|
||||
markPrice
|
||||
midPrice
|
||||
bestBidVolume
|
||||
bestOfferVolume
|
||||
bestStaticBidVolume
|
||||
bestStaticOfferVolume
|
||||
bestBidPrice
|
||||
bestOfferPrice
|
||||
trigger
|
||||
openInterest
|
||||
suppliedStake
|
||||
openInterest
|
||||
targetStake
|
||||
marketValueProxy
|
||||
priceMonitoringBounds {
|
||||
minValidPrice
|
||||
maxValidPrice
|
||||
trigger {
|
||||
horizonSecs
|
||||
probability
|
||||
auctionExtensionSecs
|
||||
}
|
||||
referencePrice
|
||||
}
|
||||
}
|
||||
liquidityMonitoringParameters {
|
||||
triggeringRatio
|
||||
targetStakeParameters {
|
||||
@ -90,13 +60,6 @@ query MarketInfo($marketId: ID!, $interval: Interval!, $since: String!) {
|
||||
scalingFactor
|
||||
}
|
||||
}
|
||||
candlesConnection(interval: $interval, since: $since) {
|
||||
edges {
|
||||
node {
|
||||
volume
|
||||
}
|
||||
}
|
||||
}
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
id
|
||||
@ -144,10 +107,12 @@ query MarketInfo($marketId: ID!, $interval: Interval!, $since: String!) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
depth {
|
||||
lastTrade {
|
||||
price
|
||||
marginCalculator {
|
||||
scalingFactors {
|
||||
searchLevel
|
||||
initialMargin
|
||||
collateralRelease
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,147 +0,0 @@
|
||||
query MarketInfoNoCandles($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
id
|
||||
decimalPlaces
|
||||
positionDecimalPlaces
|
||||
state
|
||||
tradingMode
|
||||
lpPriceRange
|
||||
proposal {
|
||||
id
|
||||
rationale {
|
||||
title
|
||||
description
|
||||
}
|
||||
}
|
||||
marketTimestamps {
|
||||
open
|
||||
close
|
||||
}
|
||||
openingAuction {
|
||||
durationSecs
|
||||
volume
|
||||
}
|
||||
accountsConnection {
|
||||
edges {
|
||||
node {
|
||||
type
|
||||
asset {
|
||||
id
|
||||
}
|
||||
balance
|
||||
}
|
||||
}
|
||||
}
|
||||
tradingMode
|
||||
fees {
|
||||
factors {
|
||||
makerFee
|
||||
infrastructureFee
|
||||
liquidityFee
|
||||
}
|
||||
}
|
||||
priceMonitoringSettings {
|
||||
parameters {
|
||||
triggers {
|
||||
horizonSecs
|
||||
probability
|
||||
auctionExtensionSecs
|
||||
}
|
||||
}
|
||||
}
|
||||
riskFactors {
|
||||
market
|
||||
short
|
||||
long
|
||||
}
|
||||
data {
|
||||
market {
|
||||
id
|
||||
}
|
||||
markPrice
|
||||
midPrice
|
||||
bestBidVolume
|
||||
bestOfferVolume
|
||||
bestStaticBidVolume
|
||||
bestStaticOfferVolume
|
||||
bestBidPrice
|
||||
bestOfferPrice
|
||||
trigger
|
||||
openInterest
|
||||
suppliedStake
|
||||
openInterest
|
||||
targetStake
|
||||
marketValueProxy
|
||||
priceMonitoringBounds {
|
||||
minValidPrice
|
||||
maxValidPrice
|
||||
trigger {
|
||||
horizonSecs
|
||||
probability
|
||||
auctionExtensionSecs
|
||||
}
|
||||
referencePrice
|
||||
}
|
||||
}
|
||||
liquidityMonitoringParameters {
|
||||
triggeringRatio
|
||||
targetStakeParameters {
|
||||
timeWindow
|
||||
scalingFactor
|
||||
}
|
||||
}
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
id
|
||||
name
|
||||
code
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
product {
|
||||
... on Future {
|
||||
quoteName
|
||||
settlementAsset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
decimals
|
||||
}
|
||||
dataSourceSpecForSettlementData {
|
||||
id
|
||||
}
|
||||
dataSourceSpecForTradingTermination {
|
||||
id
|
||||
}
|
||||
dataSourceSpecBinding {
|
||||
settlementDataProperty
|
||||
tradingTerminationProperty
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
riskModel {
|
||||
... on LogNormalRiskModel {
|
||||
tau
|
||||
riskAversionParameter
|
||||
params {
|
||||
r
|
||||
sigma
|
||||
mu
|
||||
}
|
||||
}
|
||||
... on SimpleRiskModel {
|
||||
params {
|
||||
factorLong
|
||||
factorShort
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
depth {
|
||||
lastTrade {
|
||||
price
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,16 +5,14 @@ import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type MarketInfoQueryVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
interval: Types.Interval;
|
||||
since: Types.Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarketInfoQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, lpPriceRange: string, proposal?: { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any }, openingAuction: { __typename?: 'AuctionDuration', durationSecs: number, volume: number }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string } } } | null> | null } | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, priceMonitoringSettings: { __typename?: 'PriceMonitoringSettings', parameters?: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null } | null }, riskFactors?: { __typename?: 'RiskFactor', market: string, short: string, long: string } | null, data?: { __typename?: 'MarketData', markPrice: string, midPrice: string, bestBidVolume: string, bestOfferVolume: string, bestStaticBidVolume: string, bestStaticOfferVolume: string, bestBidPrice: string, bestOfferPrice: string, trigger: Types.AuctionTrigger, openInterest: string, suppliedStake?: string | null, targetStake?: string | null, marketValueProxy: string, market: { __typename?: 'Market', id: string }, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null } | null, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, candlesConnection?: { __typename?: 'CandleDataConnection', edges?: Array<{ __typename?: 'CandleEdge', node: { __typename?: 'Candle', volume: string } } | null> | null } | null, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, riskModel: { __typename?: 'LogNormalRiskModel', tau: number, riskAversionParameter: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } } }, depth: { __typename?: 'MarketDepth', lastTrade?: { __typename?: 'Trade', price: string } | null } } | null };
|
||||
export type MarketInfoQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, lpPriceRange: string, proposal?: { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any }, openingAuction: { __typename?: 'AuctionDuration', durationSecs: number, volume: number }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string } } } | null> | null } | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, priceMonitoringSettings: { __typename?: 'PriceMonitoringSettings', parameters?: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null } | null }, riskFactors?: { __typename?: 'RiskFactor', market: string, short: string, long: string } | null, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, riskModel: { __typename?: 'LogNormalRiskModel', tau: number, riskAversionParameter: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, marginCalculator?: { __typename?: 'MarginCalculator', scalingFactors: { __typename?: 'ScalingFactors', searchLevel: number, initialMargin: number, collateralRelease: number } } | null } } | null };
|
||||
|
||||
|
||||
export const MarketInfoDocument = gql`
|
||||
query MarketInfo($marketId: ID!, $interval: Interval!, $since: String!) {
|
||||
query MarketInfo($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
id
|
||||
decimalPlaces
|
||||
@ -48,7 +46,6 @@ export const MarketInfoDocument = gql`
|
||||
}
|
||||
}
|
||||
}
|
||||
tradingMode
|
||||
fees {
|
||||
factors {
|
||||
makerFee
|
||||
@ -70,35 +67,6 @@ export const MarketInfoDocument = gql`
|
||||
short
|
||||
long
|
||||
}
|
||||
data {
|
||||
market {
|
||||
id
|
||||
}
|
||||
markPrice
|
||||
midPrice
|
||||
bestBidVolume
|
||||
bestOfferVolume
|
||||
bestStaticBidVolume
|
||||
bestStaticOfferVolume
|
||||
bestBidPrice
|
||||
bestOfferPrice
|
||||
trigger
|
||||
openInterest
|
||||
suppliedStake
|
||||
openInterest
|
||||
targetStake
|
||||
marketValueProxy
|
||||
priceMonitoringBounds {
|
||||
minValidPrice
|
||||
maxValidPrice
|
||||
trigger {
|
||||
horizonSecs
|
||||
probability
|
||||
auctionExtensionSecs
|
||||
}
|
||||
referencePrice
|
||||
}
|
||||
}
|
||||
liquidityMonitoringParameters {
|
||||
triggeringRatio
|
||||
targetStakeParameters {
|
||||
@ -106,13 +74,6 @@ export const MarketInfoDocument = gql`
|
||||
scalingFactor
|
||||
}
|
||||
}
|
||||
candlesConnection(interval: $interval, since: $since) {
|
||||
edges {
|
||||
node {
|
||||
volume
|
||||
}
|
||||
}
|
||||
}
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
id
|
||||
@ -160,10 +121,12 @@ export const MarketInfoDocument = gql`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
depth {
|
||||
lastTrade {
|
||||
price
|
||||
marginCalculator {
|
||||
scalingFactors {
|
||||
searchLevel
|
||||
initialMargin
|
||||
collateralRelease
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -183,8 +146,6 @@ export const MarketInfoDocument = gql`
|
||||
* const { data, loading, error } = useMarketInfoQuery({
|
||||
* variables: {
|
||||
* marketId: // value for 'marketId'
|
||||
* interval: // value for 'interval'
|
||||
* since: // value for 'since'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
|
@ -1,190 +0,0 @@
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type MarketInfoNoCandlesQueryVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarketInfoNoCandlesQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, lpPriceRange: string, proposal?: { __typename?: 'Proposal', id?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string } } | null, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any }, openingAuction: { __typename?: 'AuctionDuration', durationSecs: number, volume: number }, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', type: Types.AccountType, balance: string, asset: { __typename?: 'Asset', id: string } } } | null> | null } | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, priceMonitoringSettings: { __typename?: 'PriceMonitoringSettings', parameters?: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null } | null }, riskFactors?: { __typename?: 'RiskFactor', market: string, short: string, long: string } | null, data?: { __typename?: 'MarketData', markPrice: string, midPrice: string, bestBidVolume: string, bestOfferVolume: string, bestStaticBidVolume: string, bestStaticOfferVolume: string, bestBidPrice: string, bestOfferPrice: string, trigger: Types.AuctionTrigger, openInterest: string, suppliedStake?: string | null, targetStake?: string | null, marketValueProxy: string, market: { __typename?: 'Market', id: string }, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null } | null, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, riskModel: { __typename?: 'LogNormalRiskModel', tau: number, riskAversionParameter: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } } }, depth: { __typename?: 'MarketDepth', lastTrade?: { __typename?: 'Trade', price: string } | null } } | null };
|
||||
|
||||
|
||||
export const MarketInfoNoCandlesDocument = gql`
|
||||
query MarketInfoNoCandles($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
id
|
||||
decimalPlaces
|
||||
positionDecimalPlaces
|
||||
state
|
||||
tradingMode
|
||||
lpPriceRange
|
||||
proposal {
|
||||
id
|
||||
rationale {
|
||||
title
|
||||
description
|
||||
}
|
||||
}
|
||||
marketTimestamps {
|
||||
open
|
||||
close
|
||||
}
|
||||
openingAuction {
|
||||
durationSecs
|
||||
volume
|
||||
}
|
||||
accountsConnection {
|
||||
edges {
|
||||
node {
|
||||
type
|
||||
asset {
|
||||
id
|
||||
}
|
||||
balance
|
||||
}
|
||||
}
|
||||
}
|
||||
tradingMode
|
||||
fees {
|
||||
factors {
|
||||
makerFee
|
||||
infrastructureFee
|
||||
liquidityFee
|
||||
}
|
||||
}
|
||||
priceMonitoringSettings {
|
||||
parameters {
|
||||
triggers {
|
||||
horizonSecs
|
||||
probability
|
||||
auctionExtensionSecs
|
||||
}
|
||||
}
|
||||
}
|
||||
riskFactors {
|
||||
market
|
||||
short
|
||||
long
|
||||
}
|
||||
data {
|
||||
market {
|
||||
id
|
||||
}
|
||||
markPrice
|
||||
midPrice
|
||||
bestBidVolume
|
||||
bestOfferVolume
|
||||
bestStaticBidVolume
|
||||
bestStaticOfferVolume
|
||||
bestBidPrice
|
||||
bestOfferPrice
|
||||
trigger
|
||||
openInterest
|
||||
suppliedStake
|
||||
openInterest
|
||||
targetStake
|
||||
marketValueProxy
|
||||
priceMonitoringBounds {
|
||||
minValidPrice
|
||||
maxValidPrice
|
||||
trigger {
|
||||
horizonSecs
|
||||
probability
|
||||
auctionExtensionSecs
|
||||
}
|
||||
referencePrice
|
||||
}
|
||||
}
|
||||
liquidityMonitoringParameters {
|
||||
triggeringRatio
|
||||
targetStakeParameters {
|
||||
timeWindow
|
||||
scalingFactor
|
||||
}
|
||||
}
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
id
|
||||
name
|
||||
code
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
product {
|
||||
... on Future {
|
||||
quoteName
|
||||
settlementAsset {
|
||||
id
|
||||
symbol
|
||||
name
|
||||
decimals
|
||||
}
|
||||
dataSourceSpecForSettlementData {
|
||||
id
|
||||
}
|
||||
dataSourceSpecForTradingTermination {
|
||||
id
|
||||
}
|
||||
dataSourceSpecBinding {
|
||||
settlementDataProperty
|
||||
tradingTerminationProperty
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
riskModel {
|
||||
... on LogNormalRiskModel {
|
||||
tau
|
||||
riskAversionParameter
|
||||
params {
|
||||
r
|
||||
sigma
|
||||
mu
|
||||
}
|
||||
}
|
||||
... on SimpleRiskModel {
|
||||
params {
|
||||
factorLong
|
||||
factorShort
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
depth {
|
||||
lastTrade {
|
||||
price
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useMarketInfoNoCandlesQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useMarketInfoNoCandlesQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useMarketInfoNoCandlesQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useMarketInfoNoCandlesQuery({
|
||||
* variables: {
|
||||
* marketId: // value for 'marketId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useMarketInfoNoCandlesQuery(baseOptions: Apollo.QueryHookOptions<MarketInfoNoCandlesQuery, MarketInfoNoCandlesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<MarketInfoNoCandlesQuery, MarketInfoNoCandlesQueryVariables>(MarketInfoNoCandlesDocument, options);
|
||||
}
|
||||
export function useMarketInfoNoCandlesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MarketInfoNoCandlesQuery, MarketInfoNoCandlesQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<MarketInfoNoCandlesQuery, MarketInfoNoCandlesQueryVariables>(MarketInfoNoCandlesDocument, options);
|
||||
}
|
||||
export type MarketInfoNoCandlesQueryHookResult = ReturnType<typeof useMarketInfoNoCandlesQuery>;
|
||||
export type MarketInfoNoCandlesLazyQueryHookResult = ReturnType<typeof useMarketInfoNoCandlesLazyQuery>;
|
||||
export type MarketInfoNoCandlesQueryResult = Apollo.QueryResult<MarketInfoNoCandlesQuery, MarketInfoNoCandlesQueryVariables>;
|
@ -2,5 +2,4 @@ export * from './info-key-value-table';
|
||||
export * from './info-market';
|
||||
export * from './tooltip-mapping';
|
||||
export * from './__generated__/MarketInfo';
|
||||
export * from './__generated__/MarketInfoNoCandles';
|
||||
export * from './market-info-data-provider';
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
|
||||
import { useEnvironment } from '@vegaprotocol/environment';
|
||||
import { totalFeesPercentage } from '@vegaprotocol/market-list';
|
||||
import {
|
||||
totalFeesPercentage,
|
||||
calcCandleVolume,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumber,
|
||||
@ -20,31 +23,20 @@ import {
|
||||
Splash,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import pick from 'lodash/pick';
|
||||
import { useMemo } from 'react';
|
||||
import { generatePath, Link } from 'react-router-dom';
|
||||
|
||||
import { MarketInfoTable } from './info-key-value-table';
|
||||
import { marketInfoDataProvider } from './market-info-data-provider';
|
||||
import { marketInfoWithDataAndCandlesProvider } from './market-info-data-provider';
|
||||
|
||||
import type { MarketInfoQuery } from './__generated__/MarketInfo';
|
||||
import type { MarketInfoWithDataAndCandles } from './market-info-data-provider';
|
||||
import { MarketProposalNotification } from '@vegaprotocol/proposals';
|
||||
|
||||
export interface InfoProps {
|
||||
market: MarketInfoQuery['market'];
|
||||
market: MarketInfoWithDataAndCandles;
|
||||
onSelect: (id: string) => void;
|
||||
}
|
||||
|
||||
export const calcCandleVolume = (
|
||||
m: MarketInfoQuery['market']
|
||||
): string | undefined => {
|
||||
return m?.candlesConnection?.edges
|
||||
?.reduce((acc: BigNumber, c) => {
|
||||
return acc.plus(new BigNumber(c?.node?.volume ?? 0));
|
||||
}, new BigNumber(m?.candlesConnection?.edges[0]?.node.volume ?? 0))
|
||||
?.toString();
|
||||
};
|
||||
|
||||
export interface MarketInfoContainerProps {
|
||||
marketId: string;
|
||||
onSelect?: (id: string) => void;
|
||||
@ -67,15 +59,15 @@ export const MarketInfoContainer = ({
|
||||
);
|
||||
|
||||
const { data, loading, error, reload } = useDataProvider({
|
||||
dataProvider: marketInfoDataProvider,
|
||||
dataProvider: marketInfoWithDataAndCandlesProvider,
|
||||
skipUpdates: true,
|
||||
variables,
|
||||
});
|
||||
|
||||
return (
|
||||
<AsyncRenderer data={data} loading={loading} error={error} reload={reload}>
|
||||
{data && data.market ? (
|
||||
<Info market={data.market} onSelect={(id) => onSelect?.(id)} />
|
||||
{data ? (
|
||||
<Info market={data} onSelect={(id) => onSelect?.(id)} />
|
||||
) : (
|
||||
<Splash>
|
||||
<p>{t('Could not load market')}</p>
|
||||
@ -88,7 +80,6 @@ export const MarketInfoContainer = ({
|
||||
export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
const { VEGA_TOKEN_URL, VEGA_EXPLORER_URL } = useEnvironment();
|
||||
const headerClassName = 'uppercase text-lg';
|
||||
const dayVolume = calcCandleVolume(market);
|
||||
const assetSymbol =
|
||||
market?.tradableInstrument.instrument.product?.settlementAsset.symbol || '';
|
||||
const quoteUnit =
|
||||
@ -105,6 +96,8 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
market.accountsConnection?.edges
|
||||
);
|
||||
|
||||
const last24hourVolume = market.candles && calcCandleVolume(market.candles);
|
||||
|
||||
const marketDataPanels = [
|
||||
{
|
||||
title: t('Current fees'),
|
||||
@ -131,13 +124,9 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
<>
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
...pick(
|
||||
market.data,
|
||||
'name',
|
||||
'markPrice',
|
||||
'bestBidPrice',
|
||||
'bestOfferPrice'
|
||||
),
|
||||
markPrice: market.data?.markPrice,
|
||||
bestBidPrice: market.data?.bestBidPrice,
|
||||
bestOfferPrice: market.data?.bestOfferPrice,
|
||||
quoteUnit: market.tradableInstrument.instrument.product.quoteName,
|
||||
}}
|
||||
decimalPlaces={market.decimalPlaces}
|
||||
@ -157,16 +146,17 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
<MarketInfoTable
|
||||
data={{
|
||||
'24hourVolume':
|
||||
dayVolume && dayVolume !== '0' ? formatNumber(dayVolume) : '-',
|
||||
...pick(
|
||||
market.data,
|
||||
'openInterest',
|
||||
'name',
|
||||
'bestBidVolume',
|
||||
'bestOfferVolume',
|
||||
'bestStaticBidVolume',
|
||||
'bestStaticOfferVolume'
|
||||
),
|
||||
last24hourVolume && last24hourVolume !== '0'
|
||||
? addDecimalsFormatNumber(
|
||||
last24hourVolume,
|
||||
market.positionDecimalPlaces
|
||||
)
|
||||
: '-',
|
||||
openInterest: market.data?.openInterest,
|
||||
bestBidVolume: market.data?.bestBidVolume,
|
||||
bestOfferVolume: market.data?.bestOfferVolume,
|
||||
bestStaticBidVolume: market.data?.bestStaticBidVolume,
|
||||
bestStaticOfferVolume: market.data?.bestStaticOfferVolume,
|
||||
}}
|
||||
decimalPlaces={market.positionDecimalPlaces}
|
||||
/>
|
||||
@ -192,7 +182,9 @@ export const Info = ({ market, onSelect }: InfoProps) => {
|
||||
];
|
||||
|
||||
const keyDetails = {
|
||||
...pick(market, 'decimalPlaces', 'positionDecimalPlaces', 'tradingMode'),
|
||||
decimalPlaces: market.decimalPlaces,
|
||||
positionDecimalPlaces: market.positionDecimalPlaces,
|
||||
tradingMode: market.tradingMode,
|
||||
state: Schema.MarketStateMapping[market.state],
|
||||
};
|
||||
|
||||
|
@ -1,25 +1,68 @@
|
||||
import { makeDataProvider } from '@vegaprotocol/utils';
|
||||
import type { MarketInfoQuery } from './__generated__/MarketInfo';
|
||||
import { makeDataProvider, makeDerivedDataProvider } from '@vegaprotocol/utils';
|
||||
import type {
|
||||
MarketInfoQuery,
|
||||
MarketInfoQueryVariables,
|
||||
} from './__generated__/MarketInfo';
|
||||
import {
|
||||
marketDataProvider,
|
||||
marketCandlesProvider,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import type {
|
||||
MarketData,
|
||||
Candle,
|
||||
MarketCandlesQueryVariables,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { MarketInfoDocument } from './__generated__/MarketInfo';
|
||||
import type { MarketInfoNoCandlesQuery } from './__generated__/MarketInfoNoCandles';
|
||||
import { MarketInfoNoCandlesDocument } from './__generated__/MarketInfoNoCandles';
|
||||
|
||||
export const marketInfoDataProvider = makeDataProvider<
|
||||
MarketInfoQuery,
|
||||
export type MarketInfo = NonNullable<MarketInfoQuery['market']>;
|
||||
export type MarketInfoWithData = MarketInfo & { data?: MarketData };
|
||||
|
||||
export type MarketInfoWithDataAndCandles = MarketInfoWithData & {
|
||||
candles?: Candle[];
|
||||
};
|
||||
|
||||
const getData = (responseData: MarketInfoQuery | null) =>
|
||||
responseData?.market || null;
|
||||
|
||||
export const marketInfoProvider = makeDataProvider<
|
||||
MarketInfoQuery,
|
||||
MarketInfoQuery['market'],
|
||||
never,
|
||||
never
|
||||
never,
|
||||
MarketInfoQueryVariables
|
||||
>({
|
||||
query: MarketInfoDocument,
|
||||
getData: (responseData: MarketInfoQuery | null) => responseData,
|
||||
getData,
|
||||
});
|
||||
|
||||
export const marketInfoNoCandlesDataProvider = makeDataProvider<
|
||||
MarketInfoNoCandlesQuery,
|
||||
MarketInfoNoCandlesQuery,
|
||||
export const marketInfoWithDataProvider = makeDerivedDataProvider<
|
||||
MarketInfoWithData,
|
||||
never,
|
||||
never
|
||||
>({
|
||||
query: MarketInfoNoCandlesDocument,
|
||||
getData: (responseData: MarketInfoNoCandlesQuery | null) => responseData,
|
||||
MarketInfoQueryVariables
|
||||
>([marketInfoProvider, marketDataProvider], (parts) => {
|
||||
const market: MarketInfo | null = parts[0];
|
||||
const marketData: MarketData | null = parts[1];
|
||||
return (
|
||||
market && {
|
||||
...market,
|
||||
data: marketData || undefined,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
export const marketInfoWithDataAndCandlesProvider = makeDerivedDataProvider<
|
||||
MarketInfoWithDataAndCandles,
|
||||
never,
|
||||
MarketCandlesQueryVariables
|
||||
>([marketInfoProvider, marketDataProvider, marketCandlesProvider], (parts) => {
|
||||
const market: MarketInfo | null = parts[0];
|
||||
const marketData: MarketData | null = parts[1];
|
||||
const candles: Candle[] | null = parts[2];
|
||||
return (
|
||||
market && {
|
||||
...market,
|
||||
data: marketData || undefined,
|
||||
candles: candles || undefined,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -93,40 +93,6 @@ export const marketInfoQuery = (
|
||||
long: '0.008508132993273576',
|
||||
},
|
||||
lpPriceRange: '0.02',
|
||||
data: {
|
||||
__typename: 'MarketData',
|
||||
market: {
|
||||
__typename: 'Market',
|
||||
id: '54b78c1b877e106842ae156332ccec740ad98d6bad43143ac6a029501dd7c6e0',
|
||||
},
|
||||
midPrice: '5749',
|
||||
markPrice: '5749',
|
||||
suppliedStake: '56767',
|
||||
marketValueProxy: '677678',
|
||||
targetStake: '56789',
|
||||
bestBidVolume: '5',
|
||||
bestOfferVolume: '1',
|
||||
bestStaticBidVolume: '5',
|
||||
bestStaticOfferVolume: '1',
|
||||
openInterest: '0',
|
||||
bestBidPrice: '681765',
|
||||
bestOfferPrice: '681769',
|
||||
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
|
||||
priceMonitoringBounds: [
|
||||
{
|
||||
minValidPrice: '654701',
|
||||
maxValidPrice: '797323',
|
||||
trigger: {
|
||||
horizonSecs: 43200,
|
||||
probability: 0.9999999,
|
||||
auctionExtensionSecs: 600,
|
||||
__typename: 'PriceMonitoringTrigger',
|
||||
},
|
||||
referencePrice: '722625',
|
||||
__typename: 'PriceMonitoringBounds',
|
||||
},
|
||||
],
|
||||
},
|
||||
liquidityMonitoringParameters: {
|
||||
triggeringRatio: '0',
|
||||
targetStakeParameters: {
|
||||
@ -136,7 +102,6 @@ export const marketInfoQuery = (
|
||||
},
|
||||
__typename: 'LiquidityMonitoringParameters',
|
||||
},
|
||||
candlesConnection: null,
|
||||
tradableInstrument: {
|
||||
__typename: 'TradableInstrument',
|
||||
instrument: {
|
||||
@ -192,13 +157,6 @@ export const marketInfoQuery = (
|
||||
},
|
||||
},
|
||||
},
|
||||
depth: {
|
||||
__typename: 'MarketDepth',
|
||||
lastTrade: {
|
||||
__typename: 'Trade',
|
||||
price: '100',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -3,40 +3,59 @@ import * as Types from '@vegaprotocol/types';
|
||||
import { gql } from '@apollo/client';
|
||||
import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type MarketDataUpdateFieldsFragment = { __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null };
|
||||
export type MarketDataUpdateFieldsFragment = { __typename?: 'ObservableMarketData', marketId: string, auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null };
|
||||
|
||||
export type MarketDataUpdateSubscriptionVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarketDataUpdateSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', marketId: string, bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null }> };
|
||||
export type MarketDataUpdateSubscription = { __typename?: 'Subscription', marketsData: Array<{ __typename?: 'ObservableMarketData', marketId: string, auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null }> };
|
||||
|
||||
export type MarketDataFieldsFragment = { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } };
|
||||
export type MarketDataFieldsFragment = { __typename?: 'MarketData', auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, market: { __typename?: 'Market', id: string }, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null };
|
||||
|
||||
export type MarketDataQueryVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarketDataQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', data?: { __typename?: 'MarketData', bestBidPrice: string, bestOfferPrice: string, markPrice: string, trigger: Types.AuctionTrigger, staticMidPrice: string, marketTradingMode: Types.MarketTradingMode, marketState: Types.MarketState, indicativeVolume: string, indicativePrice: string, bestStaticBidPrice: string, bestStaticOfferPrice: string, targetStake?: string | null, suppliedStake?: string | null, auctionStart?: string | null, auctionEnd?: string | null, market: { __typename?: 'Market', id: string } } | null } }> } | null };
|
||||
export type MarketDataQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', data?: { __typename?: 'MarketData', auctionEnd?: string | null, auctionStart?: string | null, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, indicativePrice: string, indicativeVolume: string, marketState: Types.MarketState, marketTradingMode: Types.MarketTradingMode, marketValueProxy: string, markPrice: string, midPrice: string, openInterest: string, staticMidPrice: string, suppliedStake?: string | null, targetStake?: string | null, trigger: Types.AuctionTrigger, market: { __typename?: 'Market', id: string }, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number } }> | null } | null } }> } | null };
|
||||
|
||||
export const MarketDataUpdateFieldsFragmentDoc = gql`
|
||||
fragment MarketDataUpdateFields on ObservableMarketData {
|
||||
marketId
|
||||
auctionEnd
|
||||
auctionStart
|
||||
bestBidPrice
|
||||
bestBidVolume
|
||||
bestOfferPrice
|
||||
markPrice
|
||||
trigger
|
||||
staticMidPrice
|
||||
marketTradingMode
|
||||
marketState
|
||||
indicativeVolume
|
||||
indicativePrice
|
||||
bestOfferVolume
|
||||
bestStaticBidPrice
|
||||
bestStaticBidVolume
|
||||
bestStaticOfferPrice
|
||||
targetStake
|
||||
bestStaticOfferVolume
|
||||
indicativePrice
|
||||
indicativeVolume
|
||||
marketState
|
||||
marketTradingMode
|
||||
marketValueProxy
|
||||
markPrice
|
||||
midPrice
|
||||
openInterest
|
||||
priceMonitoringBounds {
|
||||
minValidPrice
|
||||
maxValidPrice
|
||||
trigger {
|
||||
horizonSecs
|
||||
probability
|
||||
auctionExtensionSecs
|
||||
}
|
||||
referencePrice
|
||||
}
|
||||
staticMidPrice
|
||||
suppliedStake
|
||||
targetStake
|
||||
trigger
|
||||
}
|
||||
`;
|
||||
export const MarketDataFieldsFragmentDoc = gql`
|
||||
@ -44,21 +63,38 @@ export const MarketDataFieldsFragmentDoc = gql`
|
||||
market {
|
||||
id
|
||||
}
|
||||
bestBidPrice
|
||||
bestOfferPrice
|
||||
markPrice
|
||||
trigger
|
||||
staticMidPrice
|
||||
marketTradingMode
|
||||
marketState
|
||||
indicativeVolume
|
||||
indicativePrice
|
||||
bestStaticBidPrice
|
||||
bestStaticOfferPrice
|
||||
targetStake
|
||||
suppliedStake
|
||||
auctionStart
|
||||
auctionEnd
|
||||
auctionStart
|
||||
bestBidPrice
|
||||
bestBidVolume
|
||||
bestOfferPrice
|
||||
bestOfferVolume
|
||||
bestStaticBidPrice
|
||||
bestStaticBidVolume
|
||||
bestStaticOfferPrice
|
||||
bestStaticOfferVolume
|
||||
indicativePrice
|
||||
indicativeVolume
|
||||
marketState
|
||||
marketTradingMode
|
||||
marketValueProxy
|
||||
markPrice
|
||||
midPrice
|
||||
openInterest
|
||||
priceMonitoringBounds {
|
||||
minValidPrice
|
||||
maxValidPrice
|
||||
trigger {
|
||||
horizonSecs
|
||||
probability
|
||||
auctionExtensionSecs
|
||||
}
|
||||
referencePrice
|
||||
}
|
||||
staticMidPrice
|
||||
suppliedStake
|
||||
targetStake
|
||||
trigger
|
||||
}
|
||||
`;
|
||||
export const MarketDataUpdateDocument = gql`
|
||||
|
@ -13,13 +13,14 @@ export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
|
||||
const { data, error, loading, reload } = useDataProvider({
|
||||
dataProvider,
|
||||
skipUpdates: true,
|
||||
variables: undefined,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="h-full relative">
|
||||
<MarketListTable
|
||||
rowData={error ? [] : data}
|
||||
noRowsOverlayComponent={() => null}
|
||||
suppressLoadingOverlay
|
||||
suppressNoRowsOverlay
|
||||
onRowClicked={(rowEvent: RowClickedEvent) => {
|
||||
const { data, event } = rowEvent;
|
||||
// filters out clicks on the symbol column because it should display asset details
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { makeDataProvider } from '@vegaprotocol/utils';
|
||||
import type {
|
||||
MarketCandlesQuery,
|
||||
MarketCandlesQueryVariables,
|
||||
MarketCandlesUpdateSubscription,
|
||||
MarketCandlesFieldsFragment,
|
||||
} from './__generated__/market-candles';
|
||||
@ -36,7 +37,8 @@ export const marketCandlesProvider = makeDataProvider<
|
||||
MarketCandlesQuery,
|
||||
Candle[],
|
||||
MarketCandlesUpdateSubscription,
|
||||
Candle
|
||||
Candle,
|
||||
MarketCandlesQueryVariables
|
||||
>({
|
||||
query: MarketCandlesDocument,
|
||||
subscriptionQuery: MarketCandlesUpdateDocument,
|
||||
|
@ -1,5 +1,4 @@
|
||||
import produce from 'immer';
|
||||
import { useMemo } from 'react';
|
||||
import { makeDataProvider, makeDerivedDataProvider } from '@vegaprotocol/utils';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
@ -11,6 +10,7 @@ import type {
|
||||
MarketDataFieldsFragment,
|
||||
MarketDataUpdateSubscription,
|
||||
MarketDataUpdateFieldsFragment,
|
||||
MarketDataQueryVariables,
|
||||
} from './__generated__/market-data';
|
||||
|
||||
export type MarketData = MarketDataFieldsFragment;
|
||||
@ -29,7 +29,7 @@ const update = (
|
||||
};
|
||||
|
||||
const getData = (responseData: MarketDataQuery | null): MarketData | null =>
|
||||
responseData?.marketsConnection?.edges[0].node.data || null;
|
||||
responseData?.marketsConnection?.edges[0]?.node?.data || null;
|
||||
|
||||
const getDelta = (
|
||||
subscriptionData: MarketDataUpdateSubscription
|
||||
@ -39,7 +39,8 @@ export const marketDataProvider = makeDataProvider<
|
||||
MarketDataQuery,
|
||||
MarketData,
|
||||
MarketDataUpdateSubscription,
|
||||
MarketDataUpdateFieldsFragment
|
||||
MarketDataUpdateFieldsFragment,
|
||||
MarketDataQueryVariables
|
||||
>({
|
||||
query: MarketDataDocument,
|
||||
subscriptionQuery: MarketDataUpdateDocument,
|
||||
@ -48,6 +49,12 @@ export const marketDataProvider = makeDataProvider<
|
||||
getDelta,
|
||||
});
|
||||
|
||||
export const markPriceProvider = makeDerivedDataProvider<
|
||||
string,
|
||||
never,
|
||||
MarketDataQueryVariables
|
||||
>([marketDataProvider], ([marketData]) => (marketData as MarketData).markPrice);
|
||||
|
||||
export type StaticMarketData = Pick<
|
||||
MarketData,
|
||||
| 'marketTradingMode'
|
||||
@ -63,7 +70,8 @@ export type StaticMarketData = Pick<
|
||||
|
||||
export const staticMarketDataProvider = makeDerivedDataProvider<
|
||||
StaticMarketData,
|
||||
never
|
||||
never,
|
||||
MarketDataQueryVariables
|
||||
>([marketDataProvider], (parts, variables, prevData) => {
|
||||
const marketData = parts[0] as ReturnType<typeof getData>;
|
||||
if (!marketData) {
|
||||
@ -89,10 +97,9 @@ export const staticMarketDataProvider = makeDerivedDataProvider<
|
||||
});
|
||||
|
||||
export const useStaticMarketData = (marketId?: string, skip?: boolean) => {
|
||||
const variables = useMemo(() => ({ marketId }), [marketId]);
|
||||
return useDataProvider({
|
||||
dataProvider: staticMarketDataProvider,
|
||||
variables,
|
||||
variables: { marketId: marketId || '' },
|
||||
skip: skip || !marketId,
|
||||
});
|
||||
};
|
||||
|
@ -1,18 +1,37 @@
|
||||
fragment MarketDataUpdateFields on ObservableMarketData {
|
||||
marketId
|
||||
auctionEnd
|
||||
auctionStart
|
||||
bestBidPrice
|
||||
bestBidVolume
|
||||
bestOfferPrice
|
||||
markPrice
|
||||
trigger
|
||||
staticMidPrice
|
||||
marketTradingMode
|
||||
marketState
|
||||
indicativeVolume
|
||||
indicativePrice
|
||||
bestOfferVolume
|
||||
bestStaticBidPrice
|
||||
bestStaticBidVolume
|
||||
bestStaticOfferPrice
|
||||
targetStake
|
||||
bestStaticOfferVolume
|
||||
indicativePrice
|
||||
indicativeVolume
|
||||
marketState
|
||||
marketTradingMode
|
||||
marketValueProxy
|
||||
markPrice
|
||||
midPrice
|
||||
openInterest
|
||||
priceMonitoringBounds {
|
||||
minValidPrice
|
||||
maxValidPrice
|
||||
trigger {
|
||||
horizonSecs
|
||||
probability
|
||||
auctionExtensionSecs
|
||||
}
|
||||
referencePrice
|
||||
}
|
||||
staticMidPrice
|
||||
suppliedStake
|
||||
targetStake
|
||||
trigger
|
||||
}
|
||||
|
||||
subscription MarketDataUpdate($marketId: ID!) {
|
||||
@ -25,21 +44,38 @@ fragment MarketDataFields on MarketData {
|
||||
market {
|
||||
id
|
||||
}
|
||||
bestBidPrice
|
||||
bestOfferPrice
|
||||
markPrice
|
||||
trigger
|
||||
staticMidPrice
|
||||
marketTradingMode
|
||||
marketState
|
||||
indicativeVolume
|
||||
indicativePrice
|
||||
bestStaticBidPrice
|
||||
bestStaticOfferPrice
|
||||
targetStake
|
||||
suppliedStake
|
||||
auctionStart
|
||||
auctionEnd
|
||||
auctionStart
|
||||
bestBidPrice
|
||||
bestBidVolume
|
||||
bestOfferPrice
|
||||
bestOfferVolume
|
||||
bestStaticBidPrice
|
||||
bestStaticBidVolume
|
||||
bestStaticOfferPrice
|
||||
bestStaticOfferVolume
|
||||
indicativePrice
|
||||
indicativeVolume
|
||||
marketState
|
||||
marketTradingMode
|
||||
marketValueProxy
|
||||
markPrice
|
||||
midPrice
|
||||
openInterest
|
||||
priceMonitoringBounds {
|
||||
minValidPrice
|
||||
maxValidPrice
|
||||
trigger {
|
||||
horizonSecs
|
||||
probability
|
||||
auctionExtensionSecs
|
||||
}
|
||||
referencePrice
|
||||
}
|
||||
staticMidPrice
|
||||
suppliedStake
|
||||
targetStake
|
||||
trigger
|
||||
}
|
||||
|
||||
query MarketData($marketId: ID!) {
|
||||
|
@ -44,34 +44,62 @@ const marketDataFields: MarketDataFieldsFragment = {
|
||||
id: 'market-0',
|
||||
__typename: 'Market',
|
||||
},
|
||||
auctionStart: '2022-06-21T17:18:43.484055236Z',
|
||||
auctionEnd: '2022-06-21T17:18:43.484055236Z',
|
||||
targetStake: '1000000',
|
||||
suppliedStake: '1000',
|
||||
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
marketState: Schema.MarketState.STATE_ACTIVE,
|
||||
staticMidPrice: '0',
|
||||
auctionStart: '2022-06-21T17:18:43.484055236Z',
|
||||
bestBidPrice: '4412690058',
|
||||
bestBidVolume: '1',
|
||||
bestOfferPrice: '4812690058',
|
||||
bestOfferVolume: '3',
|
||||
bestStaticBidPrice: '4512690058',
|
||||
bestStaticBidVolume: '2',
|
||||
bestStaticOfferPrice: '4712690058',
|
||||
bestStaticOfferVolume: '4',
|
||||
indicativePrice: '0',
|
||||
bestStaticBidPrice: '0',
|
||||
bestStaticOfferPrice: '0',
|
||||
indicativeVolume: '0',
|
||||
bestBidPrice: '0',
|
||||
bestOfferPrice: '0',
|
||||
marketState: Schema.MarketState.STATE_ACTIVE,
|
||||
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
marketValueProxy: '2000000',
|
||||
markPrice: '4612690058',
|
||||
midPrice: '4612690000',
|
||||
openInterest: '0',
|
||||
priceMonitoringBounds: [
|
||||
{
|
||||
minValidPrice: '654701',
|
||||
maxValidPrice: '797323',
|
||||
trigger: {
|
||||
horizonSecs: 43200,
|
||||
probability: 0.9999999,
|
||||
auctionExtensionSecs: 600,
|
||||
__typename: 'PriceMonitoringTrigger',
|
||||
},
|
||||
referencePrice: '722625',
|
||||
__typename: 'PriceMonitoringBounds',
|
||||
},
|
||||
],
|
||||
staticMidPrice: '4612690001',
|
||||
suppliedStake: '1000',
|
||||
targetStake: '1000000',
|
||||
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
|
||||
};
|
||||
|
||||
const marketDataUpdateFields: MarketDataUpdateFieldsFragment = {
|
||||
marketId: 'market-0',
|
||||
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
marketState: Schema.MarketState.STATE_ACTIVE,
|
||||
staticMidPrice: '0',
|
||||
indicativePrice: '0',
|
||||
bestStaticBidPrice: '0',
|
||||
bestStaticOfferPrice: '0',
|
||||
indicativeVolume: '0',
|
||||
bestBidPrice: '0',
|
||||
bestBidVolume: '0',
|
||||
bestOfferPrice: '0',
|
||||
bestOfferVolume: '0',
|
||||
bestStaticBidPrice: '0',
|
||||
bestStaticBidVolume: '0',
|
||||
bestStaticOfferPrice: '0',
|
||||
bestStaticOfferVolume: '0',
|
||||
indicativePrice: '0',
|
||||
indicativeVolume: '0',
|
||||
marketId: 'market-0',
|
||||
marketState: Schema.MarketState.STATE_ACTIVE,
|
||||
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
|
||||
marketValueProxy: '',
|
||||
markPrice: '4612690058',
|
||||
midPrice: '0',
|
||||
openInterest: '0',
|
||||
staticMidPrice: '0',
|
||||
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
|
||||
};
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { makeDataProvider } from '@vegaprotocol/utils';
|
||||
import { MarketsCandlesDocument } from './__generated__/markets-candles';
|
||||
import type { MarketsCandlesQuery } from './__generated__/markets-candles';
|
||||
import type {
|
||||
MarketsCandlesQuery,
|
||||
MarketsCandlesQueryVariables,
|
||||
} from './__generated__/markets-candles';
|
||||
import type { Candle } from './market-candles-provider';
|
||||
|
||||
export interface MarketCandles {
|
||||
@ -22,7 +25,8 @@ export const marketsCandlesProvider = makeDataProvider<
|
||||
MarketsCandlesQuery,
|
||||
MarketCandles[],
|
||||
never,
|
||||
never
|
||||
never,
|
||||
MarketsCandlesQueryVariables
|
||||
>({
|
||||
query: MarketsCandlesDocument,
|
||||
getData,
|
||||
|
@ -4,6 +4,8 @@ import type {
|
||||
MarketsQuery,
|
||||
MarketFieldsFragment,
|
||||
} from './__generated__/markets';
|
||||
import type { MarketsCandlesQueryVariables } from './__generated__/markets-candles';
|
||||
|
||||
import { marketsDataProvider } from './markets-data-provider';
|
||||
import { marketDataProvider } from './market-data-provider';
|
||||
import { marketsCandlesProvider } from './markets-candles-provider';
|
||||
@ -37,7 +39,7 @@ export const marketProvider = makeDerivedDataProvider<
|
||||
never,
|
||||
{ marketId: string }
|
||||
>(
|
||||
[marketsProvider],
|
||||
[(callback, client) => marketsProvider(callback, client, undefined)],
|
||||
([markets], variables) =>
|
||||
((markets as ReturnType<typeof getData>) || []).find(
|
||||
(market) => market.id === variables?.marketId
|
||||
@ -84,10 +86,11 @@ const addCandles = <T extends Market>(
|
||||
|
||||
export const marketsWithCandlesProvider = makeDerivedDataProvider<
|
||||
MarketMaybeWithCandles[],
|
||||
never
|
||||
never,
|
||||
MarketsCandlesQueryVariables
|
||||
>(
|
||||
[
|
||||
(callback, client) => activeMarketsProvider(callback, client),
|
||||
(callback, client) => activeMarketsProvider(callback, client, undefined),
|
||||
marketsCandlesProvider,
|
||||
],
|
||||
(parts) => addCandles(parts[0] as Market[], parts[1] as MarketCandles[])
|
||||
@ -113,10 +116,11 @@ export type MarketMaybeWithDataAndCandles = MarketMaybeWithData &
|
||||
|
||||
export const marketListProvider = makeDerivedDataProvider<
|
||||
MarketMaybeWithDataAndCandles[],
|
||||
never
|
||||
never,
|
||||
MarketsCandlesQueryVariables
|
||||
>(
|
||||
[
|
||||
(callback, client) => marketsWithDataProvider(callback, client),
|
||||
(callback, client) => marketsWithDataProvider(callback, client, undefined),
|
||||
marketsCandlesProvider,
|
||||
],
|
||||
(parts) =>
|
||||
|
@ -76,7 +76,9 @@ const orderMatchFilters = (
|
||||
return true;
|
||||
};
|
||||
|
||||
const getData = (responseData: OrdersQuery | null) =>
|
||||
const getData = (
|
||||
responseData: OrdersQuery | null
|
||||
): Edge<OrderFieldsFragment>[] =>
|
||||
responseData?.party?.ordersConnection?.edges || [];
|
||||
|
||||
const getDelta = (subscriptionData: OrdersUpdateSubscription) =>
|
||||
@ -142,14 +144,19 @@ export const update = (
|
||||
__typename: 'Order',
|
||||
},
|
||||
cursor: '',
|
||||
__typename: 'OrderEdge',
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const ordersProvider = makeDataProvider({
|
||||
export const ordersProvider = makeDataProvider<
|
||||
OrdersQuery,
|
||||
ReturnType<typeof getData>,
|
||||
OrdersUpdateSubscription,
|
||||
ReturnType<typeof getDelta>,
|
||||
OrdersQueryVariables
|
||||
>({
|
||||
query: OrdersDocument,
|
||||
subscriptionQuery: OrdersUpdateDocument,
|
||||
update,
|
||||
@ -168,7 +175,10 @@ export const ordersWithMarketProvider = makeDerivedDataProvider<
|
||||
Order[],
|
||||
OrdersQueryVariables
|
||||
>(
|
||||
[ordersProvider, marketsProvider],
|
||||
[
|
||||
ordersProvider,
|
||||
(callback, client) => marketsProvider(callback, client, undefined),
|
||||
],
|
||||
(partsData): OrderEdge[] =>
|
||||
((partsData[0] as ReturnType<typeof getData>) || []).map((edge) => ({
|
||||
cursor: edge.cursor,
|
||||
@ -183,7 +193,13 @@ export const ordersWithMarketProvider = makeDerivedDataProvider<
|
||||
combineInsertionData<Order>
|
||||
);
|
||||
|
||||
const hasActiveOrderProviderInternal = makeDataProvider({
|
||||
const hasActiveOrderProviderInternal = makeDataProvider<
|
||||
OrdersQuery,
|
||||
boolean,
|
||||
OrdersUpdateSubscription,
|
||||
ReturnType<typeof getDelta>,
|
||||
OrdersQueryVariables
|
||||
>({
|
||||
query: OrdersDocument,
|
||||
subscriptionQuery: OrdersUpdateDocument,
|
||||
update: (
|
||||
|
@ -9,6 +9,8 @@ import type {
|
||||
} from 'ag-grid-community';
|
||||
import { Button } from '@vegaprotocol/ui-toolkit';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { GridReadyEvent } from 'ag-grid-community';
|
||||
|
||||
import { OrderListTable } from '../order-list/order-list';
|
||||
import { useOrderListData } from './use-order-list-data';
|
||||
import { useHasActiveOrder } from '../../order-hooks/use-has-active-order';
|
||||
@ -156,6 +158,16 @@ export const OrderListManager = ({
|
||||
},
|
||||
[create]
|
||||
);
|
||||
|
||||
const onGridReady = useCallback(
|
||||
(event: GridReadyEvent) => {
|
||||
event.api.setDatasource({
|
||||
getRows,
|
||||
});
|
||||
},
|
||||
[getRows]
|
||||
);
|
||||
|
||||
const cancelAll = useCallback(
|
||||
(marketId?: string) => {
|
||||
create({
|
||||
@ -177,7 +189,7 @@ export const OrderListManager = ({
|
||||
<OrderListTable
|
||||
ref={gridRef}
|
||||
rowModelType="infinite"
|
||||
datasource={{ getRows }}
|
||||
onGridReady={onGridReady}
|
||||
onBodyScrollEnd={onBodyScrollEnd}
|
||||
onBodyScroll={onBodyScroll}
|
||||
onFilterChanged={onFilterChanged}
|
||||
|
@ -139,18 +139,15 @@ export const useOrderListData = ({
|
||||
});
|
||||
totalCountRef.current = totalCount;
|
||||
|
||||
const getRows = makeInfiniteScrollGetRows<OrderEdge>(
|
||||
dataRef,
|
||||
totalCountRef,
|
||||
load,
|
||||
newRows
|
||||
const getRows = useRef(
|
||||
makeInfiniteScrollGetRows<OrderEdge>(dataRef, totalCountRef, load, newRows)
|
||||
);
|
||||
return {
|
||||
loading,
|
||||
error,
|
||||
data,
|
||||
addNewRows,
|
||||
getRows,
|
||||
getRows: getRows.current,
|
||||
reload,
|
||||
makeBottomPlaceholders,
|
||||
};
|
||||
|
@ -1,7 +1,8 @@
|
||||
export * from './__generated__/OrdersSubscription';
|
||||
export * from './use-has-active-order';
|
||||
export * from './use-order-cancel';
|
||||
export * from './use-order-submit';
|
||||
export * from './use-order-edit';
|
||||
export * from './use-order-submit';
|
||||
export * from './use-order-update';
|
||||
export * from './use-pending-orders-volume';
|
||||
export * from './use-order-store';
|
||||
|
74
libs/orders/src/lib/order-hooks/use-pending-orders-volume.ts
Normal file
74
libs/orders/src/lib/order-hooks/use-pending-orders-volume.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { OrderStatus, Side } from '@vegaprotocol/types';
|
||||
import { ordersProvider } from '../components/order-data-provider/order-data-provider';
|
||||
import type { OrderFieldsFragment } from '../components/order-data-provider/__generated__/Orders';
|
||||
import type { Edge } from '@vegaprotocol/utils';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
|
||||
const sumVolume = (orders: (Edge<OrderFieldsFragment> | null)[], side: Side) =>
|
||||
orders
|
||||
.reduce(
|
||||
(sum, order) =>
|
||||
order?.node.side === side
|
||||
? sum +
|
||||
BigInt(
|
||||
order?.node.status === OrderStatus.STATUS_PARTIALLY_FILLED
|
||||
? order?.node.remaining
|
||||
: order?.node.size
|
||||
)
|
||||
: sum,
|
||||
BigInt(0)
|
||||
)
|
||||
.toString();
|
||||
|
||||
export const useActiveOrdersVolumeAndMargin = (
|
||||
partyId: string | null | undefined,
|
||||
marketId: string
|
||||
) => {
|
||||
const [buyVolume, setBuyVolume] = useState<string | undefined>();
|
||||
const [sellVolume, setSellVolume] = useState<string | undefined>();
|
||||
const [buyInitialMargin, setBuyInitialMargin] = useState<
|
||||
string | undefined
|
||||
>();
|
||||
const [sellInitialMargin, setSellInitialMargin] = useState<
|
||||
string | undefined
|
||||
>();
|
||||
const update = useCallback(
|
||||
({ data }: { data: (Edge<OrderFieldsFragment> | null)[] | null }) => {
|
||||
if (!data) {
|
||||
setBuyVolume(undefined);
|
||||
setSellVolume(undefined);
|
||||
setBuyInitialMargin(undefined);
|
||||
setSellInitialMargin(undefined);
|
||||
} else {
|
||||
setBuyVolume(sumVolume(data, Side.SIDE_BUY));
|
||||
setSellVolume(sumVolume(data, Side.SIDE_SELL));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
[]
|
||||
);
|
||||
useDataProvider({
|
||||
dataProvider: ordersProvider,
|
||||
update,
|
||||
variables: {
|
||||
partyId: partyId || '',
|
||||
marketId,
|
||||
filter: {
|
||||
status: [
|
||||
OrderStatus.STATUS_ACTIVE,
|
||||
OrderStatus.STATUS_PARTIALLY_FILLED,
|
||||
],
|
||||
},
|
||||
},
|
||||
skip: !partyId,
|
||||
});
|
||||
return buyVolume || sellVolume
|
||||
? {
|
||||
buyVolume,
|
||||
sellVolume,
|
||||
buyInitialMargin,
|
||||
sellInitialMargin,
|
||||
}
|
||||
: undefined;
|
||||
};
|
@ -1,8 +1,11 @@
|
||||
export * from './lib/__generated__/Positions';
|
||||
export * from './lib/positions-container';
|
||||
export * from './lib/positions-data-providers';
|
||||
export * from './lib/margin-data-provider';
|
||||
export * from './lib/margin-calculator';
|
||||
export * from './lib/positions-table';
|
||||
export * from './lib/use-close-position';
|
||||
export * from './lib/use-positions-data';
|
||||
export * from './lib/use-market-position-open-volume';
|
||||
export * from './lib/use-market-margin';
|
||||
export * from './lib/use-market-position-open-volume';
|
||||
export * from './lib/use-open-volume';
|
||||
export * from './lib/use-positions-data';
|
||||
|
@ -5,9 +5,9 @@ import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type PositionFieldsFragment = { __typename?: 'Position', realisedPNL: string, openVolume: string, unrealisedPNL: string, averageEntryPrice: string, updatedAt?: any | null, positionStatus: Types.PositionStatus, lossSocializationAmount: string, market: { __typename?: 'Market', id: string } };
|
||||
|
||||
export type PositionsQueryVariables = Types.Exact<{
|
||||
export type PositionsQueryVariables = {
|
||||
partyId: Types.Scalars['ID'];
|
||||
}>;
|
||||
};
|
||||
|
||||
|
||||
export type PositionsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, positionsConnection?: { __typename?: 'PositionConnection', edges?: Array<{ __typename?: 'PositionEdge', node: { __typename?: 'Position', realisedPNL: string, openVolume: string, unrealisedPNL: string, averageEntryPrice: string, updatedAt?: any | null, positionStatus: Types.PositionStatus, lossSocializationAmount: string, market: { __typename?: 'Market', id: string } } }> | null } | null } | null };
|
||||
|
95
libs/positions/src/lib/margin-calculator.ts
Normal file
95
libs/positions/src/lib/margin-calculator.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import { toBigNum } from '@vegaprotocol/utils';
|
||||
import { Side, MarketTradingMode, OrderType } from '@vegaprotocol/types';
|
||||
import type { ScalingFactors, RiskFactor } from '@vegaprotocol/types';
|
||||
import type { MarketData } from '@vegaprotocol/market-list';
|
||||
|
||||
export const isMarketInAuction = (marketTradingMode: MarketTradingMode) => {
|
||||
return [
|
||||
MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
|
||||
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
|
||||
MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
|
||||
].includes(marketTradingMode);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the market price based on market mode (auction or not auction)
|
||||
*/
|
||||
export const getMarketPrice = ({
|
||||
marketTradingMode,
|
||||
indicativePrice,
|
||||
markPrice,
|
||||
}: Pick<MarketData, 'marketTradingMode' | 'indicativePrice' | 'markPrice'>) => {
|
||||
if (isMarketInAuction(marketTradingMode)) {
|
||||
// 0 can never be a valid uncrossing price
|
||||
// as it would require there being orders on the book at that price.
|
||||
if (
|
||||
indicativePrice &&
|
||||
indicativePrice !== '0' &&
|
||||
BigInt(indicativePrice) !== BigInt(0)
|
||||
) {
|
||||
return indicativePrice;
|
||||
}
|
||||
}
|
||||
return markPrice;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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?: OrderType | null;
|
||||
price?: string;
|
||||
},
|
||||
marketData: Pick<
|
||||
MarketData,
|
||||
'marketTradingMode' | 'indicativePrice' | 'markPrice'
|
||||
>
|
||||
) => {
|
||||
// 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
|
||||
if (order.type === OrderType.TYPE_LIMIT && order.price) {
|
||||
return order.price;
|
||||
}
|
||||
return getMarketPrice(marketData);
|
||||
};
|
||||
|
||||
export const calculateMargins = ({
|
||||
size,
|
||||
side,
|
||||
price,
|
||||
decimals,
|
||||
positionDecimalPlaces,
|
||||
decimalPlaces,
|
||||
scalingFactors,
|
||||
riskFactors,
|
||||
}: {
|
||||
size: string;
|
||||
side: Side;
|
||||
positionDecimalPlaces: number;
|
||||
decimalPlaces: number;
|
||||
decimals: number;
|
||||
price: string;
|
||||
scalingFactors?: ScalingFactors;
|
||||
riskFactors: RiskFactor;
|
||||
}) => {
|
||||
const maintenanceMargin = toBigNum(size, positionDecimalPlaces)
|
||||
.multipliedBy(
|
||||
side === Side.SIDE_SELL ? riskFactors.short : riskFactors.long
|
||||
)
|
||||
.multipliedBy(toBigNum(price, decimalPlaces));
|
||||
return {
|
||||
maintenanceMargin: maintenanceMargin
|
||||
.multipliedBy(Math.pow(10, decimals))
|
||||
.toFixed(0),
|
||||
initialMargin: maintenanceMargin
|
||||
.multipliedBy(scalingFactors?.initialMargin ?? 1)
|
||||
.multipliedBy(Math.pow(10, decimals))
|
||||
.toFixed(0),
|
||||
};
|
||||
};
|
@ -1,5 +1,9 @@
|
||||
import produce from 'immer';
|
||||
import { makeDataProvider, removePaginationWrapper } from '@vegaprotocol/utils';
|
||||
import {
|
||||
makeDataProvider,
|
||||
makeDerivedDataProvider,
|
||||
removePaginationWrapper,
|
||||
} from '@vegaprotocol/utils';
|
||||
import {
|
||||
MarginsSubscriptionDocument,
|
||||
MarginsDocument,
|
||||
@ -8,6 +12,7 @@ import type {
|
||||
MarginsQuery,
|
||||
MarginFieldsFragment,
|
||||
MarginsSubscriptionSubscription,
|
||||
MarginsQueryVariables,
|
||||
} from './__generated__/Positions';
|
||||
|
||||
const update = (
|
||||
@ -56,7 +61,8 @@ export const marginsDataProvider = makeDataProvider<
|
||||
MarginsQuery,
|
||||
MarginFieldsFragment[],
|
||||
MarginsSubscriptionSubscription,
|
||||
MarginsSubscriptionSubscription['margins']
|
||||
MarginsSubscriptionSubscription['margins'],
|
||||
MarginsQueryVariables
|
||||
>({
|
||||
query: MarginsDocument,
|
||||
subscriptionQuery: MarginsSubscriptionDocument,
|
||||
@ -64,3 +70,15 @@ export const marginsDataProvider = makeDataProvider<
|
||||
getData,
|
||||
getDelta,
|
||||
});
|
||||
|
||||
export const marketMarginDataProvider = makeDerivedDataProvider<
|
||||
MarginFieldsFragment,
|
||||
never,
|
||||
MarginsQueryVariables & { marketId: string }
|
||||
>(
|
||||
[marginsDataProvider],
|
||||
(data, { marketId }) =>
|
||||
(data[0] as MarginFieldsFragment[]).find(
|
||||
(margin) => margin.market.id === marketId
|
||||
) || null
|
||||
);
|
||||
|
@ -11,19 +11,32 @@ import {
|
||||
removePaginationWrapper,
|
||||
} from '@vegaprotocol/utils';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
import type { MarketMaybeWithData } from '@vegaprotocol/market-list';
|
||||
import type {
|
||||
MarketMaybeWithData,
|
||||
MarketDataQueryVariables,
|
||||
} from '@vegaprotocol/market-list';
|
||||
import { marketsWithDataProvider } from '@vegaprotocol/market-list';
|
||||
import type {
|
||||
PositionsQuery,
|
||||
PositionFieldsFragment,
|
||||
PositionsSubscriptionSubscription,
|
||||
MarginFieldsFragment,
|
||||
PositionsQueryVariables,
|
||||
} from './__generated__/Positions';
|
||||
import {
|
||||
PositionsDocument,
|
||||
PositionsSubscriptionDocument,
|
||||
} from './__generated__/Positions';
|
||||
import { marginsDataProvider } from './margin-data-provider';
|
||||
import { calculateMargins } from './margin-calculator';
|
||||
import type { Edge } from '@vegaprotocol/utils';
|
||||
import { OrderStatus, Side } from '@vegaprotocol/types';
|
||||
import { marketInfoProvider } from '@vegaprotocol/market-info';
|
||||
import type { MarketInfoQuery } from '@vegaprotocol/market-info';
|
||||
import { marketDataProvider } from '@vegaprotocol/market-list';
|
||||
import type { MarketData } from '@vegaprotocol/market-list';
|
||||
import { ordersProvider } from '@vegaprotocol/orders';
|
||||
import type { OrderFieldsFragment } from '@vegaprotocol/orders';
|
||||
import type { PositionStatus } from '@vegaprotocol/types';
|
||||
|
||||
type PositionMarginLevel = Pick<
|
||||
@ -229,7 +242,8 @@ export const positionsDataProvider = makeDataProvider<
|
||||
PositionsQuery,
|
||||
PositionFieldsFragment[],
|
||||
PositionsSubscriptionSubscription,
|
||||
PositionsSubscriptionSubscription['positions']
|
||||
PositionsSubscriptionSubscription['positions'],
|
||||
PositionsQueryVariables
|
||||
>({
|
||||
query: PositionsDocument,
|
||||
subscriptionQuery: PositionsSubscriptionDocument,
|
||||
@ -260,6 +274,32 @@ const upgradeMarginsConnection = (
|
||||
return null;
|
||||
};
|
||||
|
||||
export const positionDataProvider = makeDerivedDataProvider<
|
||||
PositionFieldsFragment,
|
||||
never,
|
||||
PositionsQueryVariables & MarketDataQueryVariables
|
||||
>(
|
||||
[
|
||||
(callback, client, variables) =>
|
||||
positionsDataProvider(callback, client, {
|
||||
partyId: variables?.partyId || '',
|
||||
}),
|
||||
],
|
||||
(data, variables) =>
|
||||
(data[0] as PositionFieldsFragment[] | null)?.find(
|
||||
(p) => p.market.id === variables?.marketId
|
||||
) || null
|
||||
);
|
||||
|
||||
export const openVolumeDataProvider = makeDerivedDataProvider<
|
||||
string,
|
||||
never,
|
||||
PositionsQueryVariables & MarketDataQueryVariables
|
||||
>(
|
||||
[positionDataProvider],
|
||||
(data) => (data[0] as PositionFieldsFragment | null)?.openVolume || null
|
||||
);
|
||||
|
||||
export const rejoinPositionData = (
|
||||
positions: PositionFieldsFragment[] | null,
|
||||
marketsData: MarketMaybeWithData[] | null,
|
||||
@ -284,19 +324,15 @@ export const rejoinPositionData = (
|
||||
return null;
|
||||
};
|
||||
|
||||
export interface PositionsMetricsProviderVariables {
|
||||
partyId: string;
|
||||
}
|
||||
|
||||
export const positionsMetricsProvider = makeDerivedDataProvider<
|
||||
Position[],
|
||||
Position[],
|
||||
PositionsMetricsProviderVariables
|
||||
PositionsQueryVariables
|
||||
>(
|
||||
[
|
||||
positionsDataProvider,
|
||||
accountsDataProvider,
|
||||
marketsWithDataProvider,
|
||||
(callback, client) => marketsWithDataProvider(callback, client, undefined),
|
||||
marginsDataProvider,
|
||||
],
|
||||
([positions, accounts, marketsData, margins], variables) => {
|
||||
@ -317,3 +353,103 @@ export const positionsMetricsProvider = makeDerivedDataProvider<
|
||||
return !(previousRow && isEqual(previousRow, row));
|
||||
})
|
||||
);
|
||||
|
||||
export const volumeAndMarginProvider = makeDerivedDataProvider<
|
||||
{
|
||||
buyVolume: string;
|
||||
sellVolume: string;
|
||||
buyInitialMargin: string;
|
||||
sellInitialMargin: string;
|
||||
},
|
||||
never,
|
||||
PositionsQueryVariables & MarketDataQueryVariables
|
||||
>(
|
||||
[
|
||||
(callback, client, variables) =>
|
||||
ordersProvider(callback, client, {
|
||||
...variables,
|
||||
filter: {
|
||||
status: [
|
||||
OrderStatus.STATUS_ACTIVE,
|
||||
OrderStatus.STATUS_PARTIALLY_FILLED,
|
||||
],
|
||||
},
|
||||
}),
|
||||
(callback, client, variables) =>
|
||||
marketDataProvider(callback, client, { marketId: variables.marketId }),
|
||||
(callback, client, variables) =>
|
||||
marketInfoProvider(callback, client, { marketId: variables.marketId }),
|
||||
openVolumeDataProvider,
|
||||
],
|
||||
(data) => {
|
||||
const orders = data[0] as (Edge<OrderFieldsFragment> | null)[] | null;
|
||||
const marketData = data[1] as MarketData | null;
|
||||
const marketInfo = data[2] as MarketInfoQuery['market'];
|
||||
let openVolume = (data[3] as string | null) || '0';
|
||||
const shortPosition = openVolume?.startsWith('-');
|
||||
if (shortPosition) {
|
||||
openVolume = openVolume.substring(1);
|
||||
}
|
||||
let buyVolume = BigInt(shortPosition ? 0 : openVolume);
|
||||
let sellVolume = BigInt(shortPosition ? openVolume : 0);
|
||||
let buyInitialMargin = BigInt(0);
|
||||
let sellInitialMargin = BigInt(0);
|
||||
if (marketInfo?.riskFactors && marketData) {
|
||||
const {
|
||||
positionDecimalPlaces,
|
||||
decimalPlaces,
|
||||
tradableInstrument,
|
||||
riskFactors,
|
||||
} = marketInfo;
|
||||
const { marginCalculator, instrument } = tradableInstrument;
|
||||
const { decimals } = instrument.product.settlementAsset;
|
||||
const calculatorParams = {
|
||||
positionDecimalPlaces,
|
||||
decimalPlaces,
|
||||
decimals,
|
||||
scalingFactors: marginCalculator?.scalingFactors,
|
||||
riskFactors,
|
||||
};
|
||||
if (openVolume !== '0') {
|
||||
const { initialMargin } = calculateMargins({
|
||||
side: shortPosition ? Side.SIDE_SELL : Side.SIDE_BUY,
|
||||
size: openVolume,
|
||||
price: marketData.markPrice,
|
||||
...calculatorParams,
|
||||
});
|
||||
if (shortPosition) {
|
||||
sellInitialMargin += BigInt(initialMargin);
|
||||
} else {
|
||||
buyInitialMargin += BigInt(initialMargin);
|
||||
}
|
||||
}
|
||||
orders?.forEach((order) => {
|
||||
if (!order) {
|
||||
return;
|
||||
}
|
||||
const { side, remaining: size } = order.node;
|
||||
const initialMargin = BigInt(
|
||||
calculateMargins({
|
||||
side,
|
||||
size,
|
||||
price: marketData.markPrice, //getDerivedPrice(order.node, marketData), same use-initial-margin
|
||||
...calculatorParams,
|
||||
}).initialMargin
|
||||
);
|
||||
if (order.node.side === Side.SIDE_BUY) {
|
||||
buyVolume += BigInt(size);
|
||||
buyInitialMargin += initialMargin;
|
||||
} else {
|
||||
sellVolume += BigInt(size);
|
||||
sellInitialMargin += initialMargin;
|
||||
}
|
||||
});
|
||||
}
|
||||
return {
|
||||
buyVolume: buyVolume.toString(),
|
||||
sellVolume: sellVolume.toString(),
|
||||
buyInitialMargin: buyInitialMargin.toString(),
|
||||
sellInitialMargin: sellInitialMargin.toString(),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
21
libs/positions/src/lib/use-open-volume.ts
Normal file
21
libs/positions/src/lib/use-open-volume.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { openVolumeDataProvider } from './positions-data-providers';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const useOpenVolume = (
|
||||
partyId: string | null | undefined,
|
||||
marketId: string
|
||||
) => {
|
||||
const [openVolume, setOpenVolume] = useState<string | undefined>(undefined);
|
||||
const update = useCallback(({ data }: { data: string | null }) => {
|
||||
setOpenVolume(data ?? undefined);
|
||||
return true;
|
||||
}, []);
|
||||
useDataProvider({
|
||||
dataProvider: openVolumeDataProvider,
|
||||
update,
|
||||
variables: { partyId: partyId || '', marketId },
|
||||
skip: !partyId,
|
||||
});
|
||||
return openVolume;
|
||||
};
|
@ -3,7 +3,7 @@ import type { RefObject } from 'react';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import type { Position } from './positions-data-providers';
|
||||
import { positionsMetricsProvider } from './positions-data-providers';
|
||||
import type { PositionsMetricsProviderVariables } from './positions-data-providers';
|
||||
import type { PositionsQueryVariables } from './__generated__/Positions';
|
||||
import { useDataProvider, updateGridData } from '@vegaprotocol/react-helpers';
|
||||
import type { GetRowsParams } from '@vegaprotocol/datagrid';
|
||||
|
||||
@ -14,7 +14,7 @@ export const usePositionsData = (
|
||||
gridRef: RefObject<AgGridReact>,
|
||||
clientSideModel?: boolean
|
||||
) => {
|
||||
const variables = useMemo<PositionsMetricsProviderVariables>(
|
||||
const variables = useMemo<PositionsQueryVariables>(
|
||||
() => ({ partyId }),
|
||||
[partyId]
|
||||
);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { makeDataProvider } from '@vegaprotocol/utils';
|
||||
import type {
|
||||
ProposalsListQuery,
|
||||
ProposalsListQueryVariables,
|
||||
ProposalListFieldsFragment,
|
||||
} from './__generated__/Proposals';
|
||||
import { ProposalsListDocument } from './__generated__/Proposals';
|
||||
@ -14,5 +15,6 @@ export const proposalsDataProvider = makeDataProvider<
|
||||
ProposalsListQuery,
|
||||
ProposalListFieldsFragment[],
|
||||
never,
|
||||
never
|
||||
never,
|
||||
ProposalsListQueryVariables
|
||||
>({ query: ProposalsListDocument, getData });
|
||||
|
@ -3,7 +3,7 @@ import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import * as Types from '@vegaprotocol/types';
|
||||
import { proposalsDataProvider } from '../proposals-data-provider';
|
||||
import { useCallback, useMemo, useRef } from 'react';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { useColumnDefs } from './use-column-defs';
|
||||
import type { ProposalListFieldsFragment } from '../proposals-data-provider/__generated__/Proposals';
|
||||
@ -22,14 +22,11 @@ export const ProposalsList = () => {
|
||||
const handleOnGridReady = useCallback(() => {
|
||||
gridRef.current?.api?.sizeColumnsToFit();
|
||||
}, [gridRef]);
|
||||
const variables = useMemo(() => {
|
||||
return {
|
||||
proposalType: Types.ProposalType.TYPE_NEW_MARKET,
|
||||
};
|
||||
}, []);
|
||||
const { data, loading, error, reload } = useDataProvider({
|
||||
dataProvider: proposalsDataProvider,
|
||||
variables,
|
||||
variables: {
|
||||
proposalType: Types.ProposalType.TYPE_NEW_MARKET,
|
||||
},
|
||||
});
|
||||
const filteredData = getNewMarketProposals(data || []);
|
||||
const { columnDefs, defaultColDef } = useColumnDefs();
|
||||
|
@ -6,6 +6,7 @@ import { MockedProvider } from '@apollo/client/testing';
|
||||
|
||||
type Data = number;
|
||||
type Delta = number;
|
||||
type Variables = { partyId: string };
|
||||
|
||||
const unsubscribe = jest.fn();
|
||||
const reload = jest.fn();
|
||||
@ -23,8 +24,8 @@ const updateCallbackPayload: Parameters<UpdateCallback<Data, Delta>>['0'] = {
|
||||
};
|
||||
|
||||
const dataProvider = jest.fn<
|
||||
ReturnType<Subscribe<Data, Delta>>,
|
||||
Parameters<Subscribe<Data, Delta>>
|
||||
ReturnType<Subscribe<Data, Delta, Variables>>,
|
||||
Parameters<Subscribe<Data, Delta, Variables>>
|
||||
>();
|
||||
|
||||
dataProvider.mockReturnValue({
|
||||
@ -37,10 +38,12 @@ dataProvider.mockReturnValue({
|
||||
jest.useFakeTimers();
|
||||
|
||||
describe('useDataProvider hook', () => {
|
||||
const render = (initialProps?: useDataProviderParams<Data, Delta>) =>
|
||||
const render = (
|
||||
initialProps?: useDataProviderParams<Data, Delta, Variables>
|
||||
) =>
|
||||
renderHook<
|
||||
ReturnType<typeof useDataProvider>,
|
||||
useDataProviderParams<Data, Delta>
|
||||
useDataProviderParams<Data, Delta, Variables>
|
||||
>((props) => useDataProvider(props), {
|
||||
wrapper: MockedProvider,
|
||||
initialProps,
|
||||
@ -224,6 +227,7 @@ describe('useThrottledDataProvider hook', () => {
|
||||
useThrottledDataProvider(
|
||||
{
|
||||
dataProvider,
|
||||
variables,
|
||||
},
|
||||
wait
|
||||
),
|
||||
|
@ -9,7 +9,7 @@ import type { Subscribe, Load, UpdateCallback } from '@vegaprotocol/utils';
|
||||
export interface useDataProviderParams<
|
||||
Data,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
> {
|
||||
dataProvider: Subscribe<Data, Delta, Variables>;
|
||||
update?: ({
|
||||
@ -30,7 +30,7 @@ export interface useDataProviderParams<
|
||||
data: Data | null;
|
||||
totalCount?: number;
|
||||
}) => boolean;
|
||||
variables?: Variables;
|
||||
variables: Variables;
|
||||
skipUpdates?: boolean;
|
||||
skip?: boolean;
|
||||
}
|
||||
@ -45,7 +45,7 @@ export interface useDataProviderParams<
|
||||
export const useDataProvider = <
|
||||
Data,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
>({
|
||||
dataProvider,
|
||||
update,
|
||||
@ -163,8 +163,12 @@ export const useDataProvider = <
|
||||
};
|
||||
};
|
||||
|
||||
export const useThrottledDataProvider = <Data, Delta>(
|
||||
params: Omit<useDataProviderParams<Data, Delta>, 'update'>,
|
||||
export const useThrottledDataProvider = <
|
||||
Data,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
>(
|
||||
params: Omit<useDataProviderParams<Data, Delta, Variables>, 'update'>,
|
||||
wait?: number
|
||||
) => {
|
||||
const [data, setData] = useState<Data | null>(null);
|
||||
|
@ -2,12 +2,11 @@ import { makeInfiniteScrollGetRows } from '@vegaprotocol/utils';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||
import type { AgGridReact } from 'ag-grid-react';
|
||||
import { useCallback, useMemo, useRef } from 'react';
|
||||
import { useCallback, useRef } from 'react';
|
||||
import type { BodyScrollEvent, BodyScrollEndEvent } from 'ag-grid-community';
|
||||
import { MAX_TRADES, tradesWithMarketProvider } from './trades-data-provider';
|
||||
import { tradesWithMarketProvider } from './trades-data-provider';
|
||||
import { TradesTable } from './trades-table';
|
||||
import type { Trade, TradeEdge } from './trades-data-provider';
|
||||
import type { TradesQueryVariables } from './__generated__/Trades';
|
||||
import { useOrderStore } from '@vegaprotocol/orders';
|
||||
|
||||
interface TradesContainerProps {
|
||||
@ -22,11 +21,6 @@ export const TradesContainer = ({ marketId }: TradesContainerProps) => {
|
||||
const scrolledToTop = useRef(true);
|
||||
const updateOrder = useOrderStore((store) => store.update);
|
||||
|
||||
const variables = useMemo<TradesQueryVariables>(
|
||||
() => ({ marketId, maxTrades: MAX_TRADES }),
|
||||
[marketId]
|
||||
);
|
||||
|
||||
const addNewRows = useCallback(() => {
|
||||
if (newRows.current === 0) {
|
||||
return;
|
||||
@ -84,7 +78,7 @@ export const TradesContainer = ({ marketId }: TradesContainerProps) => {
|
||||
dataProvider: tradesWithMarketProvider,
|
||||
update,
|
||||
insert,
|
||||
variables,
|
||||
variables: { marketId },
|
||||
});
|
||||
totalCountRef.current = totalCount;
|
||||
const getRows = makeInfiniteScrollGetRows<TradeEdge>(
|
||||
|
@ -10,6 +10,7 @@ import type { Market } from '@vegaprotocol/market-list';
|
||||
import { marketsProvider } from '@vegaprotocol/market-list';
|
||||
import type {
|
||||
TradesQuery,
|
||||
TradesQueryVariables,
|
||||
TradeFieldsFragment,
|
||||
TradesUpdateSubscription,
|
||||
} from './__generated__/Trades';
|
||||
@ -67,10 +68,16 @@ const update = (
|
||||
export type Trade = Omit<TradeFieldsFragment, 'market'> & { market?: Market };
|
||||
export type TradeEdge = Edge<Trade>;
|
||||
|
||||
const getPageInfo = (responseData: TradesQuery): PageInfo | null =>
|
||||
responseData.market?.tradesConnection?.pageInfo || null;
|
||||
const getPageInfo = (responseData: TradesQuery | null): PageInfo | null =>
|
||||
responseData?.market?.tradesConnection?.pageInfo || null;
|
||||
|
||||
export const tradesProvider = makeDataProvider({
|
||||
export const tradesProvider = makeDataProvider<
|
||||
Parameters<typeof getData>['0'],
|
||||
ReturnType<typeof getData>,
|
||||
Parameters<typeof getDelta>['0'],
|
||||
ReturnType<typeof getDelta>,
|
||||
TradesQueryVariables
|
||||
>({
|
||||
query: TradesDocument,
|
||||
subscriptionQuery: TradesUpdateDocument,
|
||||
update,
|
||||
@ -85,9 +92,13 @@ export const tradesProvider = makeDataProvider({
|
||||
|
||||
export const tradesWithMarketProvider = makeDerivedDataProvider<
|
||||
(TradeEdge | null)[],
|
||||
Trade[]
|
||||
Trade[],
|
||||
TradesQueryVariables
|
||||
>(
|
||||
[tradesProvider, marketsProvider],
|
||||
[
|
||||
tradesProvider,
|
||||
(callback, client) => marketsProvider(callback, client, undefined),
|
||||
],
|
||||
(partsData): (TradeEdge | null)[] | null => {
|
||||
const edges = partsData[0] as ReturnType<typeof getData>;
|
||||
return edges.map((edge) => {
|
||||
|
@ -45,10 +45,11 @@ type CombinedData = {
|
||||
|
||||
type SubscriptionData = QueryData;
|
||||
type Delta = Data;
|
||||
type Variables = { var: string };
|
||||
|
||||
const update = jest.fn<
|
||||
ReturnType<Update<Data, Delta>>,
|
||||
Parameters<Update<Data, Delta>>
|
||||
ReturnType<Update<Data, Delta, Variables>>,
|
||||
Parameters<Update<Data, Delta, Variables>>
|
||||
>();
|
||||
|
||||
const callback = jest.fn<
|
||||
@ -66,7 +67,13 @@ const getData = jest.fn((r: QueryData | null) => r?.data || null);
|
||||
|
||||
const getDelta = jest.fn((r: SubscriptionData) => r.data);
|
||||
|
||||
const subscribe = makeDataProvider<QueryData, Data, SubscriptionData, Delta>({
|
||||
const subscribe = makeDataProvider<
|
||||
QueryData,
|
||||
Data,
|
||||
SubscriptionData,
|
||||
Delta,
|
||||
Variables
|
||||
>({
|
||||
query,
|
||||
subscriptionQuery,
|
||||
update,
|
||||
@ -75,18 +82,18 @@ const subscribe = makeDataProvider<QueryData, Data, SubscriptionData, Delta>({
|
||||
});
|
||||
|
||||
const combineData = jest.fn<
|
||||
ReturnType<CombineDerivedData<CombinedData>>,
|
||||
Parameters<CombineDerivedData<CombinedData>>
|
||||
ReturnType<CombineDerivedData<CombinedData, Variables>>,
|
||||
Parameters<CombineDerivedData<CombinedData, Variables>>
|
||||
>();
|
||||
|
||||
const combineDelta = jest.fn<
|
||||
ReturnType<CombineDerivedDelta<CombinedData, CombinedData>>,
|
||||
Parameters<CombineDerivedDelta<CombinedData, CombinedData>>
|
||||
ReturnType<CombineDerivedDelta<CombinedData, CombinedData, Variables>>,
|
||||
Parameters<CombineDerivedDelta<CombinedData, CombinedData, Variables>>
|
||||
>();
|
||||
|
||||
const combineInsertionData = jest.fn<
|
||||
ReturnType<CombineInsertionData<CombinedData>>,
|
||||
Parameters<CombineInsertionData<CombinedData>>
|
||||
ReturnType<CombineInsertionData<CombinedData, Variables>>,
|
||||
Parameters<CombineInsertionData<CombinedData, Variables>>
|
||||
>();
|
||||
|
||||
const first = 100;
|
||||
@ -94,7 +101,8 @@ const paginatedSubscribe = makeDataProvider<
|
||||
QueryData,
|
||||
Data,
|
||||
SubscriptionData,
|
||||
Delta
|
||||
Delta,
|
||||
Variables
|
||||
>({
|
||||
query,
|
||||
subscriptionQuery,
|
||||
@ -116,7 +124,8 @@ const errorGuardedSubscribe = makeDataProvider<
|
||||
QueryData,
|
||||
Data,
|
||||
SubscriptionData,
|
||||
Delta
|
||||
Delta,
|
||||
Variables
|
||||
>({
|
||||
query,
|
||||
subscriptionQuery,
|
||||
@ -210,6 +219,8 @@ const clearPendingQueries = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const variables = { var: 'val' };
|
||||
|
||||
describe('data provider', () => {
|
||||
beforeEach(() => {
|
||||
clearPendingQueries();
|
||||
@ -220,7 +231,6 @@ describe('data provider', () => {
|
||||
clientSubscribeSubscribe.mockClear();
|
||||
});
|
||||
it('memoize instance and unsubscribe if no subscribers', () => {
|
||||
const variables = { var: 'val' };
|
||||
const subscription1 = subscribe(jest.fn(), client, variables);
|
||||
const subscription2 = subscribe(jest.fn(), client, { ...variables });
|
||||
// const subscription1 = subscribe(jest.fn(), client);
|
||||
@ -234,7 +244,7 @@ describe('data provider', () => {
|
||||
|
||||
it('calls callback before and after initial fetch', async () => {
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
const subscription = subscribe(callback, client, variables);
|
||||
expect(callback.mock.calls.length).toBe(1);
|
||||
expect(callback.mock.calls[0][0].data).toBe(null);
|
||||
expect(callback.mock.calls[0][0].loading).toBe(true);
|
||||
@ -246,7 +256,7 @@ describe('data provider', () => {
|
||||
});
|
||||
|
||||
it('calls callback on error', async () => {
|
||||
const subscription = subscribe(callback, client);
|
||||
const subscription = subscribe(callback, client, variables);
|
||||
expect(callback.mock.calls.length).toBe(1);
|
||||
expect(callback.mock.calls[0][0].data).toBe(null);
|
||||
expect(callback.mock.calls[0][0].loading).toBe(true);
|
||||
@ -260,7 +270,7 @@ describe('data provider', () => {
|
||||
});
|
||||
|
||||
it('calls successful callback on NotFound error on party path', async () => {
|
||||
const subscription = subscribe(callback, client);
|
||||
const subscription = subscribe(callback, client, variables);
|
||||
expect(callback.mock.calls.length).toBe(1);
|
||||
expect(callback.mock.calls[0][0].data).toBe(null);
|
||||
expect(callback.mock.calls[0][0].loading).toBe(true);
|
||||
@ -280,7 +290,7 @@ describe('data provider', () => {
|
||||
const data: Data = [];
|
||||
getData.mockReturnValueOnce(data);
|
||||
await rejectQuery(error);
|
||||
expect(getData).toHaveBeenCalledWith(null, undefined);
|
||||
expect(getData).toHaveBeenCalledWith(null, variables);
|
||||
expect(callback.mock.calls.length).toBe(2);
|
||||
expect(callback.mock.calls[1][0].data).toEqual(data);
|
||||
expect(callback.mock.calls[1][0].error).toEqual(undefined);
|
||||
@ -290,7 +300,7 @@ describe('data provider', () => {
|
||||
|
||||
it('calls update and callback on each update', async () => {
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
const subscription = subscribe(callback, client, variables);
|
||||
await resolveQuery({ data });
|
||||
const delta: Item[] = [];
|
||||
update.mockImplementationOnce((data, delta) => [...(data || []), ...delta]);
|
||||
@ -308,7 +318,7 @@ describe('data provider', () => {
|
||||
|
||||
it("don't calls callback on update if data doesn't change", async () => {
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
const subscription = subscribe(callback, client, variables);
|
||||
await resolveQuery({ data });
|
||||
const delta: Item[] = [];
|
||||
update.mockImplementationOnce((data) => data || []);
|
||||
@ -325,7 +335,7 @@ describe('data provider', () => {
|
||||
|
||||
it('refetch data on reload', async () => {
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
const subscription = subscribe(callback, client, variables);
|
||||
await resolveQuery({ data });
|
||||
subscription.reload();
|
||||
await resolveQuery({ data });
|
||||
@ -337,7 +347,7 @@ describe('data provider', () => {
|
||||
|
||||
it('refetch data and restart subscription on reload with force', async () => {
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
const subscription = subscribe(callback, client, variables);
|
||||
await resolveQuery({ data });
|
||||
subscription.reload(true);
|
||||
await resolveQuery({ data });
|
||||
@ -349,7 +359,7 @@ describe('data provider', () => {
|
||||
|
||||
it('calls callback on flush', async () => {
|
||||
const data: Item[] = [];
|
||||
const subscription = subscribe(callback, client);
|
||||
const subscription = subscribe(callback, client, variables);
|
||||
await resolveQuery({ data });
|
||||
const callbackCallsLength = callback.mock.calls.length;
|
||||
subscription.flush();
|
||||
@ -365,7 +375,7 @@ describe('data provider', () => {
|
||||
id: i.toString(),
|
||||
},
|
||||
}));
|
||||
const subscription = paginatedSubscribe(callback, client);
|
||||
const subscription = paginatedSubscribe(callback, client, variables);
|
||||
await resolveQuery({
|
||||
data,
|
||||
totalCount,
|
||||
@ -379,7 +389,7 @@ describe('data provider', () => {
|
||||
|
||||
it('loads requested data blocks and inserts data with total count', async () => {
|
||||
const totalCount = 1000;
|
||||
const subscription = paginatedSubscribe(callback, client);
|
||||
const subscription = paginatedSubscribe(callback, client, variables);
|
||||
await resolveQuery({
|
||||
data: generateData(),
|
||||
totalCount,
|
||||
@ -503,7 +513,7 @@ describe('data provider', () => {
|
||||
|
||||
it('loads requested data blocks and inserts data without totalCount', async () => {
|
||||
const totalCount = undefined;
|
||||
const subscription = paginatedSubscribe(callback, client);
|
||||
const subscription = paginatedSubscribe(callback, client, variables);
|
||||
await resolveQuery({
|
||||
data: generateData(),
|
||||
totalCount,
|
||||
@ -542,7 +552,7 @@ describe('data provider', () => {
|
||||
});
|
||||
|
||||
it('sets total count when first page has no next page', async () => {
|
||||
const subscription = paginatedSubscribe(callback, client);
|
||||
const subscription = paginatedSubscribe(callback, client, variables);
|
||||
await resolveQuery({
|
||||
data: generateData(),
|
||||
pageInfo: {
|
||||
@ -556,8 +566,8 @@ describe('data provider', () => {
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
|
||||
it('errorPolicyGuard should work properly', async () => {
|
||||
const subscription = errorGuardedSubscribe(callback, client);
|
||||
it('should retry with ignore error policy if errorPolicyGuard returns true', async () => {
|
||||
const subscription = errorGuardedSubscribe(callback, client, variables);
|
||||
const graphQLError = new GraphQLError(
|
||||
'',
|
||||
undefined,
|
||||
@ -579,7 +589,7 @@ describe('data provider', () => {
|
||||
});
|
||||
expect(mockErrorPolicyGuard).toHaveBeenNthCalledWith(1, graphQLErrors);
|
||||
await waitFor(() =>
|
||||
expect(getData).toHaveBeenCalledWith({ data }, undefined)
|
||||
expect(getData).toHaveBeenCalledWith({ data }, variables)
|
||||
);
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
@ -589,7 +599,6 @@ describe('derived data provider', () => {
|
||||
it('memoize instance and unsubscribe if no subscribers', () => {
|
||||
clientSubscribeSubscribe.mockClear();
|
||||
clientSubscribeUnsubscribe.mockClear();
|
||||
const variables = {};
|
||||
const subscription1 = derivedSubscribe(jest.fn(), client, variables);
|
||||
const subscription2 = derivedSubscribe(jest.fn(), client, variables);
|
||||
expect(clientSubscribeSubscribe.mock.calls.length).toEqual(2);
|
||||
@ -615,7 +624,7 @@ describe('derived data provider', () => {
|
||||
ReturnType<UpdateCallback<CombinedData, CombinedData>>,
|
||||
Parameters<UpdateCallback<CombinedData, CombinedData>>
|
||||
>();
|
||||
const subscription = derivedSubscribe(callback, client);
|
||||
const subscription = derivedSubscribe(callback, client, variables);
|
||||
const data = { totalCount: 0 };
|
||||
combineData.mockReturnValueOnce(data);
|
||||
expect(callback.mock.calls.length).toBe(0);
|
||||
@ -642,7 +651,7 @@ describe('derived data provider', () => {
|
||||
Parameters<UpdateCallback<CombinedData, CombinedData>>
|
||||
>();
|
||||
expect(callback.mock.calls.length).toBe(0);
|
||||
const subscription = derivedSubscribe(callback, client);
|
||||
const subscription = derivedSubscribe(callback, client, variables);
|
||||
const data = { totalCount: 0 };
|
||||
combineData.mockReturnValueOnce(data);
|
||||
expect(callback.mock.calls.length).toBe(0);
|
||||
@ -677,7 +686,7 @@ describe('derived data provider', () => {
|
||||
ReturnType<UpdateCallback<CombinedData, CombinedData>>,
|
||||
Parameters<UpdateCallback<CombinedData, CombinedData>>
|
||||
>();
|
||||
const subscription = derivedSubscribe(callback, client);
|
||||
const subscription = derivedSubscribe(callback, client, variables);
|
||||
const data = { totalCount: 0 };
|
||||
combineData.mockReturnValueOnce(data);
|
||||
await resolveQuery({ data: part1 });
|
||||
@ -709,7 +718,7 @@ describe('derived data provider', () => {
|
||||
ReturnType<UpdateCallback<CombinedData, CombinedData>>,
|
||||
Parameters<UpdateCallback<CombinedData, CombinedData>>
|
||||
>();
|
||||
const subscription = derivedSubscribe(callback, client);
|
||||
const subscription = derivedSubscribe(callback, client, variables);
|
||||
const data = { totalCount: 0 };
|
||||
combineData.mockReturnValueOnce(data);
|
||||
await resolveQuery({
|
||||
|
@ -53,12 +53,12 @@ export interface PageInfo {
|
||||
export interface Subscribe<
|
||||
Data,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
> {
|
||||
(
|
||||
callback: UpdateCallback<Data, Delta>,
|
||||
client: ApolloClient<object>,
|
||||
variables?: Variables
|
||||
variables: Variables
|
||||
): {
|
||||
unsubscribe: () => void;
|
||||
reload: Reload;
|
||||
@ -73,14 +73,9 @@ export type Query<Result> = DocumentNode | TypedDocumentNode<Result, any>;
|
||||
export interface Update<
|
||||
Data,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
> {
|
||||
(
|
||||
data: Data | null,
|
||||
delta: Delta,
|
||||
reload: Reload,
|
||||
variables?: Variables
|
||||
): Data;
|
||||
(data: Data | null, delta: Delta, reload: Reload, variables: Variables): Data;
|
||||
}
|
||||
|
||||
export interface Append<Data> {
|
||||
@ -165,7 +160,7 @@ interface DataProviderParams<
|
||||
Data,
|
||||
SubscriptionData,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
> {
|
||||
query: Query<QueryData>;
|
||||
subscriptionQuery?: Query<SubscriptionData>;
|
||||
@ -200,7 +195,7 @@ function makeDataProviderInternal<
|
||||
Data,
|
||||
SubscriptionData,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
>({
|
||||
query,
|
||||
subscriptionQuery,
|
||||
@ -225,7 +220,7 @@ function makeDataProviderInternal<
|
||||
const updateQueue: Delta[] = [];
|
||||
|
||||
let resetTimer: ReturnType<typeof setTimeout>;
|
||||
let variables: Variables | undefined;
|
||||
let variables: Variables;
|
||||
let data: Data | null = null;
|
||||
let error: Error | undefined;
|
||||
let loading = true;
|
||||
@ -492,7 +487,9 @@ function makeDataProviderInternal<
|
||||
callbacks.push(callback);
|
||||
if (callbacks.length === 1) {
|
||||
client = c;
|
||||
variables = v;
|
||||
if (v) {
|
||||
variables = v;
|
||||
}
|
||||
initialize();
|
||||
} else {
|
||||
notify(callback);
|
||||
@ -515,7 +512,7 @@ function makeDataProviderInternal<
|
||||
const memoize = <
|
||||
Data,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
>(
|
||||
fn: () => Subscribe<Data, Delta, Variables>
|
||||
) => {
|
||||
@ -563,7 +560,7 @@ export function makeDataProvider<
|
||||
Data,
|
||||
SubscriptionData,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
>(
|
||||
params: DataProviderParams<
|
||||
QueryData,
|
||||
@ -585,27 +582,27 @@ export function makeDataProvider<
|
||||
* This effects in parts in combine function has any[] type
|
||||
*/
|
||||
type DependencySubscribe<
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
> = Subscribe<any, any, Variables>; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
type DependencyUpdateCallback<
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
> = Parameters<DependencySubscribe<Variables>>['0'];
|
||||
export type DerivedPart<
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
> = Parameters<DependencyUpdateCallback<Variables>>['0'];
|
||||
export type CombineDerivedData<
|
||||
Data,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
> = (
|
||||
data: DerivedPart<Variables>['data'][],
|
||||
variables: Variables | undefined,
|
||||
variables: Variables,
|
||||
prevData: Data | null
|
||||
) => Data | null;
|
||||
|
||||
export type CombineDerivedDelta<
|
||||
Data,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
> = (
|
||||
data: Data,
|
||||
parts: DerivedPart<Variables>[],
|
||||
@ -615,7 +612,7 @@ export type CombineDerivedDelta<
|
||||
|
||||
export type CombineInsertionData<
|
||||
Data,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
> = (
|
||||
data: Data,
|
||||
parts: DerivedPart<Variables>[],
|
||||
@ -625,7 +622,7 @@ export type CombineInsertionData<
|
||||
function makeDerivedDataProviderInternal<
|
||||
Data,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
>(
|
||||
dependencies: DependencySubscribe<Variables>[],
|
||||
combineData: CombineDerivedData<Data, Variables>,
|
||||
@ -635,7 +632,7 @@ function makeDerivedDataProviderInternal<
|
||||
let subscriptions: ReturnType<DependencySubscribe>[] | undefined;
|
||||
let client: ApolloClient<object>;
|
||||
const callbacks: UpdateCallback<Data, Delta>[] = [];
|
||||
let variables: Variables | undefined;
|
||||
let variables: Variables;
|
||||
const parts: DerivedPart<Variables>[] = [];
|
||||
let data: Data | null = null;
|
||||
let error: Error | undefined;
|
||||
@ -756,7 +753,9 @@ function makeDerivedDataProviderInternal<
|
||||
callbacks.push(callback);
|
||||
if (callbacks.length === 1) {
|
||||
client = c;
|
||||
variables = v;
|
||||
if (v) {
|
||||
variables = v;
|
||||
}
|
||||
initialize();
|
||||
} else {
|
||||
notify(callback);
|
||||
@ -777,7 +776,7 @@ function makeDerivedDataProviderInternal<
|
||||
export function makeDerivedDataProvider<
|
||||
Data,
|
||||
Delta,
|
||||
Variables extends OperationVariables = OperationVariables
|
||||
Variables extends OperationVariables | undefined = undefined
|
||||
>(
|
||||
dependencies: DependencySubscribe<Variables>[],
|
||||
combineData: CombineDerivedData<Data, Variables>,
|
||||
|
@ -29,12 +29,16 @@ export const encodeTransaction = (tx: Transaction): string => {
|
||||
);
|
||||
};
|
||||
|
||||
export const normalizeOrderSubmission = <T extends Exact<OrderSubmission, T>>(
|
||||
order: T,
|
||||
export const normalizeOrderSubmission = (
|
||||
order: OrderSubmission,
|
||||
decimalPlaces: number,
|
||||
positionDecimalPlaces: number
|
||||
): OrderSubmission => ({
|
||||
...order,
|
||||
marketId: order.marketId,
|
||||
reference: order.reference,
|
||||
type: order.type,
|
||||
side: order.side,
|
||||
timeInForce: order.timeInForce,
|
||||
price:
|
||||
order.type === OrderType.TYPE_LIMIT && order.price
|
||||
? removeDecimal(order.price, decimalPlaces)
|
||||
|
@ -19,10 +19,9 @@ export const WithdrawFormContainer = ({
|
||||
partyId,
|
||||
submit,
|
||||
}: WithdrawFormContainerProps) => {
|
||||
const variables = useMemo(() => ({ partyId }), [partyId]);
|
||||
const { data, loading, error } = useDataProvider({
|
||||
dataProvider: accountsDataProvider,
|
||||
variables,
|
||||
variables: { partyId: partyId || '' },
|
||||
});
|
||||
|
||||
const filteredAsset = useMemo(
|
||||
|
Loading…
Reference in New Issue
Block a user