Feat/1491 insert accounts and positions (#1515)

* feat: inserts of new item in positions

* feat: inserts of new item in positions - move select-market to app dir

* feat: inserts of new item in positions - add delta to update

* feat: inserts of new item in positions - fix e2e mocks

* feat: inserts of new item in positions - fix e2e mocks

* feat: inserts of new item in positions - adjust e2e mocks

* feat: inserts of new item in positions - adjust e2e tests

* feat: inserts of new item in positions - adjust e2e tests

* feat: inserts of new item in positions - adjust e2e trading tests

* feat: inserts of new item in positions - adjust e2e account tests

* feat: inserts of new item in positions - adjust e2e account tests

* feat: inserts of new item in positions - adjust e2e account tests

* feat: inserts of new item in accounts - manage inserting new accounts

* feat: inserts of new item in accounts - adjust console-lite tests

* feat: inserts of new item in accounts - adjust console-v2 tests

* feat: inserts of new item in accounts - adjust console-v2 tests

* feat: inserts of new item in accounts - clean up after merge

* feat: inserts of new item in accounts - fixes after feedback

Co-authored-by: maciek <maciek@vegaprotocol.io>
This commit is contained in:
macqbat 2022-10-04 10:37:31 +02:00 committed by GitHub
parent 8156a3c1a9
commit 406b69566f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1357 additions and 931 deletions

View File

@ -21,6 +21,6 @@ NX_URL=$URL
NX_DEPLOY_URL=$DEPLOY_URL NX_DEPLOY_URL=$DEPLOY_URL
NX_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL NX_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql
NX_VEGA_ENV=TESTNET NX_VEGA_ENV=TESTNET
NX_VEGA_WALLET_URL=http://localhost:1789 NX_VEGA_WALLET_URL=http://localhost:1789

View File

@ -6,11 +6,19 @@ import { aliasQuery } from '@vegaprotocol/cypress';
import { import {
generatePositions, generatePositions,
emptyPositions, emptyPositions,
generateMargins,
} from '../support/mocks/generate-positions'; } from '../support/mocks/generate-positions';
import { generateAccounts } from '../support/mocks/generate-accounts'; import {
generateAccounts,
generateAssets,
} from '../support/mocks/generate-accounts';
import { generateOrders } from '../support/mocks/generate-orders'; import { generateOrders } from '../support/mocks/generate-orders';
import { generateFills } from '../support/mocks/generate-fills'; import { generateFills } from '../support/mocks/generate-fills';
import { generateFillsMarkets } from '../support/mocks/generate-markets'; import {
generateFillsMarkets,
generateMarketsData,
generatePositionsMarkets,
} from '../support/mocks/generate-markets';
describe('Portfolio page', { tags: '@smoke' }, () => { describe('Portfolio page', { tags: '@smoke' }, () => {
afterEach(() => { afterEach(() => {
@ -49,7 +57,11 @@ describe('Portfolio page', { tags: '@smoke' }, () => {
beforeEach(() => { beforeEach(() => {
cy.mockGQL((req) => { cy.mockGQL((req) => {
aliasQuery(req, 'Positions', generatePositions()); aliasQuery(req, 'Positions', generatePositions());
aliasQuery(req, 'Margins', generateMargins());
aliasQuery(req, 'Markets', generatePositionsMarkets());
aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'Accounts', generateAccounts()); aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'Assets', generateAssets());
}); });
cy.visit('/portfolio/assets'); cy.visit('/portfolio/assets');
connectVegaWallet(); connectVegaWallet();
@ -75,6 +87,10 @@ describe('Portfolio page', { tags: '@smoke' }, () => {
cy.mockGQL((req) => { cy.mockGQL((req) => {
aliasQuery(req, 'Positions', generatePositions()); aliasQuery(req, 'Positions', generatePositions());
aliasQuery(req, 'Accounts', generateAccounts()); aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'Margins', generateMargins());
aliasQuery(req, 'Markets', generatePositionsMarkets());
aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'Assets', generateAssets());
}); });
cy.visit('/portfolio/positions'); cy.visit('/portfolio/positions');
connectVegaWallet(); connectVegaWallet();
@ -126,6 +142,9 @@ describe('Portfolio page', { tags: '@smoke' }, () => {
aliasQuery(req, 'Markets', { aliasQuery(req, 'Markets', {
marketsConnection: { edges: [], __typename: 'MarketConnection' }, marketsConnection: { edges: [], __typename: 'MarketConnection' },
}); });
aliasQuery(req, 'Assets', {
assetsConnection: { edges: null, __typename: 'AssetsConnection' },
});
}); });
cy.visit('/portfolio'); cy.visit('/portfolio');
connectVegaWallet(); connectVegaWallet();
@ -133,22 +152,26 @@ describe('Portfolio page', { tags: '@smoke' }, () => {
it('"No data to display" should be always displayed', () => { it('"No data to display" should be always displayed', () => {
cy.getByTestId('assets').click(); cy.getByTestId('assets').click();
cy.get('div.flex.items-center.justify-center').contains( cy.get('div.flex.items-center.justify-center').should(
'contain.text',
'No data to display' 'No data to display'
); );
cy.getByTestId('positions').click(); cy.getByTestId('positions').click();
cy.get('div.flex.items-center.justify-center').contains( cy.get('div.flex.items-center.justify-center').should(
'contain.text',
'No data to display' 'No data to display'
); );
cy.getByTestId('orders').click(); cy.getByTestId('orders').click();
cy.get('div.flex.items-center.justify-center').contains( cy.get('div.flex.items-center.justify-center').should(
'contain.text',
'No data to display' 'No data to display'
); );
cy.getByTestId('fills').click(); cy.getByTestId('fills').click();
cy.get('div.flex.items-center.justify-center').contains( cy.get('div.flex.items-center.justify-center').should(
'contain.text',
'No data to display' 'No data to display'
); );
}); });

View File

@ -1,6 +1,6 @@
import merge from 'lodash/merge'; import merge from 'lodash/merge';
import type { AccountsQuery } from '@vegaprotocol/accounts'; import type { AccountsQuery, AssetsQuery } from '@vegaprotocol/accounts';
import { AccountType } from '@vegaprotocol/types'; import { AccountType, Schema as Types } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest'; import type { PartialDeep } from 'type-fest';
export const generateAccounts = ( export const generateAccounts = (
@ -19,8 +19,6 @@ export const generateAccounts = (
asset: { asset: {
__typename: 'Asset', __typename: 'Asset',
id: 'asset-id', id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
}, },
}, },
{ {
@ -29,20 +27,11 @@ export const generateAccounts = (
balance: '100000000', balance: '100000000',
market: { market: {
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13', id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'AAVEDAI Monthly (30 Jun 2022)',
},
},
__typename: 'Market', __typename: 'Market',
}, },
asset: { asset: {
__typename: 'Asset', __typename: 'Asset',
id: 'asset-id-2', id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
}, },
}, },
{ {
@ -51,20 +40,11 @@ export const generateAccounts = (
balance: '1000', balance: '1000',
market: { market: {
__typename: 'Market', __typename: 'Market',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: '',
},
},
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376', id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
}, },
asset: { asset: {
__typename: 'Asset', __typename: 'Asset',
id: 'asset-id', id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
}, },
}, },
{ {
@ -73,20 +53,11 @@ export const generateAccounts = (
balance: '1000', balance: '1000',
market: { market: {
__typename: 'Market', __typename: 'Market',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: '',
},
},
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d', id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
}, },
asset: { asset: {
__typename: 'Asset', __typename: 'Asset',
id: 'asset-id-2', id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
}, },
}, },
{ {
@ -97,8 +68,6 @@ export const generateAccounts = (
asset: { asset: {
__typename: 'Asset', __typename: 'Asset',
id: 'asset-0', id: 'asset-0',
symbol: 'AST0',
decimals: 5,
}, },
}, },
], ],
@ -106,3 +75,43 @@ export const generateAccounts = (
}; };
return merge(defaultAccounts, override); return merge(defaultAccounts, override);
}; };
export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
const defaultAssets: AssetsQuery = {
assetsConnection: {
edges: [
{
node: {
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
name: 'Euro',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
name: 'DAI',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
name: 'Asto',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
],
},
};
return merge(defaultAssets, override);
};

View File

@ -1,15 +1,20 @@
import merge from 'lodash/merge'; import merge from 'lodash/merge';
import { MarketState } from '@vegaprotocol/types'; import {
AuctionTrigger,
MarketState,
MarketTradingMode,
} from '@vegaprotocol/types';
import type { import type {
MarketsQuery, MarketsQuery,
Market, Market,
MarketsCandlesQuery, MarketsCandlesQuery,
Candle, Candle,
MarketsDataQuery, MarketsDataQuery,
MarketDataFieldsFragment,
} from '@vegaprotocol/market-list'; } from '@vegaprotocol/market-list';
import { protoMarket, protoCandles } from './commons'; import { protoMarket, protoCandles } from './commons';
import type { PartialDeep } from 'type-fest';
MarketState.STATE_SUSPENDED;
export const generateSimpleMarkets = (): MarketsQuery => { export const generateSimpleMarkets = (): MarketsQuery => {
const markets: Market[] = [ const markets: Market[] = [
{ ...protoMarket }, { ...protoMarket },
@ -1072,7 +1077,7 @@ export const generateMarketsCandles = (): MarketsCandlesQuery => {
}; };
}; };
export const generateMarketsData = (): MarketsDataQuery => { export const generateEmptyMarketsData = (): MarketsDataQuery => {
return { return {
marketsConnection: { marketsConnection: {
__typename: 'MarketConnection', __typename: 'MarketConnection',
@ -1136,3 +1141,239 @@ export const generateFillsMarkets = () => {
}, },
}; };
}; };
export const generateMarketsData = (
override?: PartialDeep<MarketsDataQuery>
): MarketsDataQuery => {
const markets = [
{
data: {
market: {
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
__typename: 'Market',
},
marketTradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',
bestStaticOfferPrice: '0',
indicativeVolume: '0',
bestBidPrice: '0',
bestOfferPrice: '0',
markPrice: '17588787',
trigger: AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
__typename: 'MarketData',
},
__typename: 'Market',
},
{
data: {
market: {
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
__typename: 'Market',
},
marketTradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
staticMidPrice: '0',
indicativePrice: '0',
bestStaticBidPrice: '0',
bestStaticOfferPrice: '0',
indicativeVolume: '0',
bestBidPrice: '0',
bestOfferPrice: '0',
markPrice: '84377569',
trigger: AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
__typename: 'MarketData',
},
__typename: 'Market',
},
];
const defaultResult: MarketsDataQuery = {
marketsConnection: {
__typename: 'MarketConnection',
edges: markets.map((node) => ({
__typename: 'MarketEdge',
node: node as {
__typename: 'Market';
data: MarketDataFieldsFragment;
},
})),
},
};
return merge(defaultResult, override);
};
export const generatePositionsMarkets = () => {
return {
marketsConnection: {
edges: [
{
node: {
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
decimalPlaces: 5,
positionDecimalPlaces: 0,
state: 'STATE_ACTIVE',
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
fees: {
factors: {
makerFee: '0.0002',
infrastructureFee: '0.0005',
liquidityFee: '0.001',
__typename: 'FeeFactors',
},
__typename: 'Fees',
},
tradableInstrument: {
instrument: {
id: '',
name: 'UNIDAI Monthly (30 Jun 2022)',
code: 'UNIDAI.MF21',
metadata: {
tags: [
'formerly:5A86B190C384997F',
'quote:EURO',
'ticker:TSLA',
'class:equities/single-stock-futures',
'sector:tech',
'listing_venue:NASDAQ',
'country:US',
],
__typename: 'InstrumentMetadata',
},
product: {
settlementAsset: {
symbol: 'tDAI',
decimals: 5,
__typename: 'Asset',
},
quoteName: 'DAI',
__typename: 'Future',
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
marketTimestamps: {
open: '2022-09-28T14:03:19.937087458Z',
close: null,
__typename: 'MarketTimestamps',
},
__typename: 'Market',
},
__typename: 'MarketEdge',
},
{
node: {
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
decimalPlaces: 5,
positionDecimalPlaces: 0,
state: 'STATE_ACTIVE',
tradingMode: 'TRADING_MODE_CONTINUOUS',
fees: {
factors: {
makerFee: '0.0002',
infrastructureFee: '0.0005',
liquidityFee: '0.001',
__typename: 'FeeFactors',
},
__typename: 'Fees',
},
tradableInstrument: {
instrument: {
id: '',
name: 'AAVEDAI Monthly (30 Jun 2022)',
code: 'AAVEDAI.MF21',
metadata: {
tags: [
'formerly:2839D9B2329C9E70',
'base:AAVE',
'quote:DAI',
'class:fx/crypto',
'monthly',
'sector:defi',
],
__typename: 'InstrumentMetadata',
},
product: {
settlementAsset: {
symbol: 'tDAI',
decimals: 5,
__typename: 'Asset',
},
quoteName: 'DAI',
__typename: 'Future',
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
marketTimestamps: {
open: '2022-09-28T14:03:19.937087458Z',
close: null,
__typename: 'MarketTimestamps',
},
__typename: 'Market',
},
__typename: 'MarketEdge',
},
{
node: {
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
decimalPlaces: 5,
positionDecimalPlaces: 0,
state: 'STATE_ACTIVE',
tradingMode: 'TRADING_MODE_CONTINUOUS',
fees: {
factors: {
makerFee: '0.0002',
infrastructureFee: '0.0005',
liquidityFee: '0.001',
__typename: 'FeeFactors',
},
__typename: 'Fees',
},
tradableInstrument: {
instrument: {
id: '',
name: 'Tesla Quarterly (30 Jun 2022)',
code: 'TSLA.QM21',
metadata: {
tags: [
'formerly:4899E01009F1A721',
'quote:USD',
'ticker:AAPL',
'class:equities/single-stock-futures',
'sector:tech',
'listing_venue:NASDAQ',
'country:US',
],
__typename: 'InstrumentMetadata',
},
product: {
settlementAsset: {
symbol: 'tEURO',
decimals: 5,
__typename: 'Asset',
},
quoteName: 'EURO',
__typename: 'Future',
},
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
marketTimestamps: {
open: '2022-09-28T14:03:19.937087458Z',
close: null,
__typename: 'MarketTimestamps',
},
__typename: 'Market',
},
__typename: 'MarketEdge',
},
],
__typename: 'MarketConnection',
},
};
};

View File

@ -4,7 +4,6 @@ import type {
Positions, Positions,
Positions_party_positionsConnection_edges_node, Positions_party_positionsConnection_edges_node,
} from '@vegaprotocol/positions'; } from '@vegaprotocol/positions';
import { MarketTradingMode } from '@vegaprotocol/types';
export const generatePositions = ( export const generatePositions = (
override?: PartialDeep<Positions> override?: PartialDeep<Positions>
@ -17,49 +16,8 @@ export const generatePositions = (
unrealisedPNL: '895000', unrealisedPNL: '895000',
averageEntryPrice: '1129935', averageEntryPrice: '1129935',
updatedAt: '2022-07-28T15:09:34.441143Z', updatedAt: '2022-07-28T15:09:34.441143Z',
marginsConnection: {
__typename: 'MarginConnection',
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
},
asset: {
__typename: 'Asset',
symbol: 'tDAI',
},
},
},
],
},
market: { market: {
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d', id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
data: {
markPrice: '17588787',
__typename: 'MarketData',
market: {
__typename: 'Market',
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
},
},
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'UNIDAI Monthly (30 Jun 2022)',
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market', __typename: 'Market',
}, },
}, },
@ -70,49 +28,8 @@ export const generatePositions = (
unrealisedPNL: '895000', unrealisedPNL: '895000',
averageEntryPrice: '8509338', averageEntryPrice: '8509338',
updatedAt: '2022-07-28T15:09:34.441143Z', updatedAt: '2022-07-28T15:09:34.441143Z',
marginsConnection: {
__typename: 'MarginConnection',
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
},
asset: {
__typename: 'Asset',
symbol: 'tDAI',
},
},
},
],
},
market: { market: {
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13', id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
data: {
markPrice: '8649338',
__typename: 'MarketData',
market: {
__typename: 'Market',
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
},
},
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'AAVEDAI Monthly (30 Jun 2022)',
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market', __typename: 'Market',
}, },
}, },
@ -122,49 +39,8 @@ export const generatePositions = (
unrealisedPNL: '-22519', unrealisedPNL: '-22519',
averageEntryPrice: '84400088', averageEntryPrice: '84400088',
updatedAt: '2022-07-28T14:53:54.725477Z', updatedAt: '2022-07-28T14:53:54.725477Z',
marginsConnection: {
__typename: 'MarginConnection',
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
},
asset: {
__typename: 'Asset',
symbol: 'tEURO',
},
},
},
],
},
market: { market: {
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376', id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
data: {
markPrice: '84377569',
__typename: 'MarketData',
market: {
__typename: 'Market',
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
},
},
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'Tesla Quarterly (30 Jun 2022)',
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market', __typename: 'Market',
}, },
__typename: 'Position', __typename: 'Position',
@ -199,3 +75,70 @@ export const emptyPositions = () => {
}, },
}; };
}; };
export const generateMargins = () => {
return {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
marginsConnection: {
edges: [
{
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
},
asset: {
__typename: 'Asset',
id: 'tDAI-id',
},
},
},
{
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
},
asset: {
__typename: 'Asset',
id: 'tDAI-id',
},
},
__typename: 'MarginEdge',
},
{
node: {
m_typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
},
asset: {
__typename: 'Asset',
id: 'tEURO-id',
},
},
__typename: 'MarginEdge',
},
],
__typename: 'MarginConnection',
},
__typename: 'Party',
},
};
};

View File

@ -44,10 +44,10 @@ describe('positions', { tags: '@smoke' }, () => {
}); });
cy.get('[col-id="averageEntryPrice"]') cy.get('[col-id="averageEntryPrice"]')
.should('contain.text', '11.29935') // entry price .should('contain.text', '85,093.38') // entry price
.should('contain.text', '9.21954'); // liquidation price .should('contain.text', '0.00'); // liquidation price
cy.get('[col-id="currentLeverage"]').should('contain.text', '1.1'); cy.get('[col-id="currentLeverage"]').should('contain.text', '0.8');
cy.get('[col-id="capitalUtilisation"]') // margin allocated cy.get('[col-id="capitalUtilisation"]') // margin allocated
.should('contain.text', '0.00%') .should('contain.text', '0.00%')
@ -57,12 +57,12 @@ describe('positions', { tags: '@smoke' }, () => {
cy.wrap($unrealisedPnl).invoke('text').should('not.be.empty'); cy.wrap($unrealisedPnl).invoke('text').should('not.be.empty');
}); });
cy.getByTestId('flash-cell').should('contain.text', '2,785.19482'); // Total tDAI position cy.getByTestId('flash-cell').should('contain.text', '276,761.40348'); // Total tDAI position
cy.getByTestId('flash-cell').should('contain.text', '0.00100'); // Total Realised PNL cy.getByTestId('flash-cell').should('contain.text', '0.00000'); // Total Realised PNL
cy.get('[col-id="unrealisedPNL"]').should('contain.text', '17.90000'); // Total Unrealised PNL cy.get('[col-id="unrealisedPNL"]').should('contain.text', '8.95000'); // Total Unrealised PNL
}); });
cy.getByTestId('balance').eq(0).should('have.text', '1,000.01000'); // Asset balance cy.getByTestId('balance').eq(1).should('have.text', '1,000.01000'); // Asset balance
cy.getByTestId('close-position').should('be.visible').and('have.length', 3); cy.getByTestId('close-position').should('be.visible').and('have.length', 3);
} }

View File

@ -1,6 +1,6 @@
import merge from 'lodash/merge'; import merge from 'lodash/merge';
import type { AccountsQuery } from '@vegaprotocol/accounts'; import type { AccountsQuery, AssetsQuery } from '@vegaprotocol/accounts';
import { AccountType } from '@vegaprotocol/types'; import { AccountType, Schema as Types } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest'; import type { PartialDeep } from 'type-fest';
export const generateAccounts = ( export const generateAccounts = (
@ -19,8 +19,6 @@ export const generateAccounts = (
asset: { asset: {
__typename: 'Asset', __typename: 'Asset',
id: 'asset-id', id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
}, },
}, },
{ {
@ -28,21 +26,12 @@ export const generateAccounts = (
type: AccountType.ACCOUNT_TYPE_GENERAL, type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000', balance: '100000000',
market: { market: {
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13', id: 'market-1',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'AAVEDAI Monthly (30 Jun 2022)',
},
},
__typename: 'Market', __typename: 'Market',
}, },
asset: { asset: {
__typename: 'Asset', __typename: 'Asset',
id: 'asset-id-2', id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
}, },
}, },
{ {
@ -51,20 +40,11 @@ export const generateAccounts = (
balance: '1000', balance: '1000',
market: { market: {
__typename: 'Market', __typename: 'Market',
tradableInstrument: { id: 'market-2',
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: '',
},
},
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
}, },
asset: { asset: {
__typename: 'Asset', __typename: 'Asset',
id: 'asset-id', id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
}, },
}, },
{ {
@ -73,20 +53,11 @@ export const generateAccounts = (
balance: '1000', balance: '1000',
market: { market: {
__typename: 'Market', __typename: 'Market',
tradableInstrument: { id: 'market-0',
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: '',
},
},
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
}, },
asset: { asset: {
__typename: 'Asset', __typename: 'Asset',
id: 'asset-id-2', id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
}, },
}, },
{ {
@ -97,8 +68,6 @@ export const generateAccounts = (
asset: { asset: {
__typename: 'Asset', __typename: 'Asset',
id: 'asset-0', id: 'asset-0',
symbol: 'AST0',
decimals: 5,
}, },
}, },
], ],
@ -106,3 +75,43 @@ export const generateAccounts = (
}; };
return merge(defaultAccounts, override); return merge(defaultAccounts, override);
}; };
export const generateAssets = (override?: PartialDeep<AssetsQuery>) => {
const defaultAssets: AssetsQuery = {
assetsConnection: {
edges: [
{
node: {
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
name: 'Euro',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
name: 'DAI',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
{
node: {
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
name: 'Asto',
quantum: '',
status: Types.AssetStatus.STATUS_ENABLED,
},
},
],
},
};
return merge(defaultAssets, override);
};

View File

@ -3,8 +3,8 @@ import type { PartialDeep } from 'type-fest';
import type { import type {
Positions, Positions,
Positions_party_positionsConnection_edges_node, Positions_party_positionsConnection_edges_node,
Margins,
} from '@vegaprotocol/positions'; } from '@vegaprotocol/positions';
import { MarketTradingMode } from '@vegaprotocol/types';
export const generatePositions = ( export const generatePositions = (
override?: PartialDeep<Positions> override?: PartialDeep<Positions>
@ -17,49 +17,8 @@ export const generatePositions = (
unrealisedPNL: '895000', unrealisedPNL: '895000',
averageEntryPrice: '1129935', averageEntryPrice: '1129935',
updatedAt: '2022-07-28T15:09:34.441143Z', updatedAt: '2022-07-28T15:09:34.441143Z',
marginsConnection: {
__typename: 'MarginConnection',
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
},
asset: {
__typename: 'Asset',
symbol: 'tDAI',
},
},
},
],
},
market: { market: {
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d', id: 'market-0',
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
data: {
markPrice: '17588787',
__typename: 'MarketData',
market: {
__typename: 'Market',
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
},
},
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'UNIDAI Monthly (30 Jun 2022)',
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market', __typename: 'Market',
}, },
}, },
@ -70,49 +29,8 @@ export const generatePositions = (
unrealisedPNL: '895000', unrealisedPNL: '895000',
averageEntryPrice: '8509338', averageEntryPrice: '8509338',
updatedAt: '2022-07-28T15:09:34.441143Z', updatedAt: '2022-07-28T15:09:34.441143Z',
marginsConnection: {
__typename: 'MarginConnection',
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
},
asset: {
__typename: 'Asset',
symbol: 'tDAI',
},
},
},
],
},
market: { market: {
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13', id: 'market-1',
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
data: {
markPrice: '8649338',
__typename: 'MarketData',
market: {
__typename: 'Market',
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
},
},
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'AAVEDAI Monthly (30 Jun 2022)',
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market', __typename: 'Market',
}, },
}, },
@ -122,49 +40,8 @@ export const generatePositions = (
unrealisedPNL: '-22519', unrealisedPNL: '-22519',
averageEntryPrice: '84400088', averageEntryPrice: '84400088',
updatedAt: '2022-07-28T14:53:54.725477Z', updatedAt: '2022-07-28T14:53:54.725477Z',
marginsConnection: {
__typename: 'MarginConnection',
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
},
asset: {
__typename: 'Asset',
symbol: 'tEURO',
},
},
},
],
},
market: { market: {
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376', id: 'market-2',
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
data: {
markPrice: '84377569',
__typename: 'MarketData',
market: {
__typename: 'Market',
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
},
},
decimalPlaces: 5,
positionDecimalPlaces: 0,
tradableInstrument: {
instrument: {
name: 'Tesla Quarterly (30 Jun 2022)',
__typename: 'Instrument',
},
__typename: 'TradableInstrument',
},
__typename: 'Market', __typename: 'Market',
}, },
__typename: 'Position', __typename: 'Position',
@ -189,3 +66,71 @@ export const generatePositions = (
return merge(defaultResult, override); return merge(defaultResult, override);
}; };
export const generateMargins = (): Margins => {
return {
party: {
id: Cypress.env('VEGA_PUBLIC_KEY'),
marginsConnection: {
edges: [
{
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: 'market-0',
},
asset: {
__typename: 'Asset',
id: 'tDAI-id',
},
},
__typename: 'MarginEdge',
},
{
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: 'market-1',
},
asset: {
__typename: 'Asset',
id: 'tDAI-id',
},
},
__typename: 'MarginEdge',
},
{
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: 'market-2',
},
asset: {
__typename: 'Asset',
id: 'tEURO-id',
},
},
__typename: 'MarginEdge',
},
],
__typename: 'MarginConnection',
},
__typename: 'Party',
},
};
};

View File

@ -1,7 +1,7 @@
import { aliasQuery } from '@vegaprotocol/cypress'; import { aliasQuery } from '@vegaprotocol/cypress';
import type { MarketState } from '@vegaprotocol/types'; import type { MarketState } from '@vegaprotocol/types';
import type { CyHttpMessages } from 'cypress/types/net-stubbing'; import type { CyHttpMessages } from 'cypress/types/net-stubbing';
import { generateAccounts } from './mocks/generate-accounts'; import { generateAccounts, generateAssets } from './mocks/generate-accounts';
import { generateCandles } from './mocks/generate-candles'; import { generateCandles } from './mocks/generate-candles';
import { generateChart } from './mocks/generate-chart'; import { generateChart } from './mocks/generate-chart';
import { generateDealTicketQuery } from './mocks/generate-deal-ticket-query'; import { generateDealTicketQuery } from './mocks/generate-deal-ticket-query';
@ -14,7 +14,7 @@ import {
generateMarketsCandles, generateMarketsCandles,
} from './mocks/generate-markets'; } from './mocks/generate-markets';
import { generateOrders } from './mocks/generate-orders'; import { generateOrders } from './mocks/generate-orders';
import { generatePositions } from './mocks/generate-positions'; import { generateMargins, generatePositions } from './mocks/generate-positions';
import { generateTrades } from './mocks/generate-trades'; import { generateTrades } from './mocks/generate-trades';
export const mockTradingPage = ( export const mockTradingPage = (
@ -43,7 +43,10 @@ export const mockTradingPage = (
aliasQuery(req, 'Orders', generateOrders()); aliasQuery(req, 'Orders', generateOrders());
aliasQuery(req, 'Accounts', generateAccounts()); aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'Positions', generatePositions()); aliasQuery(req, 'Positions', generatePositions());
aliasQuery(req, 'Margins', generateMargins());
aliasQuery(req, 'DealTicket', generateDealTicketQuery({ market: { state } })); aliasQuery(req, 'DealTicket', generateDealTicketQuery({ market: { state } }));
aliasQuery(req, 'Assets', generateAssets());
aliasQuery( aliasQuery(
req, req,
'MarketInfoQuery', 'MarketInfoQuery',

View File

@ -0,0 +1,3 @@
export * from './select-market-columns';
export * from './select-market-table';
export * from './select-market';

View File

@ -15,11 +15,16 @@ import {
import { PriceCellChange, Sparkline, Tooltip } from '@vegaprotocol/ui-toolkit'; import { PriceCellChange, Sparkline, Tooltip } from '@vegaprotocol/ui-toolkit';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import Link from 'next/link'; import Link from 'next/link';
import {
import { calcCandleHigh, calcCandleLow, totalFees } from '../utils'; calcCandleHigh,
calcCandleLow,
totalFees,
} from '@vegaprotocol/market-list';
import type { CandleClose } from '@vegaprotocol/types'; import type { CandleClose } from '@vegaprotocol/types';
import type { MarketWithData, MarketWithCandles } from '../'; import type {
MarketWithData,
MarketWithCandles,
} from '@vegaprotocol/market-list';
import isNil from 'lodash/isNil'; import isNil from 'lodash/isNil';
type Market = MarketWithData & MarketWithCandles; type Market = MarketWithData & MarketWithCandles;

View File

@ -1,10 +1,11 @@
import { fireEvent, render, screen } from '@testing-library/react'; import { fireEvent, render, screen } from '@testing-library/react';
import { AuctionTrigger, MarketTradingMode } from '@vegaprotocol/types'; import { AuctionTrigger, MarketTradingMode } from '@vegaprotocol/types';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import type { MarketWithCandles, MarketWithData } from '../markets-provider'; import type {
import type { MarketData } from '../market-data-provider'; MarketWithCandles,
MarketWithData,
MarketData,
} from '@vegaprotocol/market-list';
import { import {
SelectAllMarketsTableBody, SelectAllMarketsTableBody,
SelectMarketLandingTable, SelectMarketLandingTable,

View File

@ -1,3 +1,5 @@
import type { ReactNode } from 'react';
import { useMemo, useState } from 'react';
import { t, useDataProvider } from '@vegaprotocol/react-helpers'; import { t, useDataProvider } from '@vegaprotocol/react-helpers';
import { import {
Dialog, Dialog,
@ -7,17 +9,11 @@ import {
Link, Link,
Popover, Popover,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { useMarketList } from '@vegaprotocol/market-list';
import type { ReactNode } from 'react'; import type {
import { useMemo, useState } from 'react'; MarketWithCandles,
import type { Column, OnCellClickHandler } from './select-market-columns'; MarketWithData,
import { } from '@vegaprotocol/market-list';
columnHeadersPositionMarkets,
columnsPositionMarkets,
} from './select-market-columns';
import { columnHeaders } from './select-market-columns';
import { columns } from './select-market-columns';
import type { MarketWithCandles, MarketWithData } from '../';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';
import type { Positions_party_positionsConnection_edges_node } from '@vegaprotocol/positions'; import type { Positions_party_positionsConnection_edges_node } from '@vegaprotocol/positions';
import { positionsDataProvider } from '@vegaprotocol/positions'; import { positionsDataProvider } from '@vegaprotocol/positions';
@ -25,7 +21,13 @@ import {
SelectMarketTableHeader, SelectMarketTableHeader,
SelectMarketTableRow, SelectMarketTableRow,
} from './select-market-table'; } from './select-market-table';
import { useMarketList } from '../markets-provider'; import type { Column, OnCellClickHandler } from './select-market-columns';
import {
columnHeadersPositionMarkets,
columnsPositionMarkets,
columnHeaders,
columns,
} from './select-market-columns';
type Market = MarketWithCandles & MarketWithData; type Market = MarketWithCandles & MarketWithData;

View File

@ -54,6 +54,12 @@ export function createClient(base?: string) {
ERC20: { ERC20: {
keyFields: ['contractAddress'], keyFields: ['contractAddress'],
}, },
PositionUpdate: {
keyFields: false,
},
AccountUpdate: {
keyFields: false,
},
}, },
}); });

View File

@ -1,6 +1,5 @@
import { gql, useQuery } from '@apollo/client'; import { gql, useQuery } from '@apollo/client';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import { ColumnKind, SelectMarketDialog } from '@vegaprotocol/market-list';
import { import {
addDecimalsFormatNumber, addDecimalsFormatNumber,
t, t,
@ -14,6 +13,7 @@ import React, { useEffect, useMemo, useState } from 'react';
import { useGlobalStore } from '../../stores'; import { useGlobalStore } from '../../stores';
import { TradeGrid, TradePanels } from './trade-grid'; import { TradeGrid, TradePanels } from './trade-grid';
import type { Market, MarketVariables } from './__generated__/Market'; import type { Market, MarketVariables } from './__generated__/Market';
import { ColumnKind, SelectMarketDialog } from '../../components/select-market';
// Top level page query // Top level page query
const MARKET_QUERY = gql` const MARKET_QUERY = gql`

View File

@ -5,8 +5,6 @@ import {
} from '@vegaprotocol/deal-ticket'; } from '@vegaprotocol/deal-ticket';
import { MarketInfoContainer } from '@vegaprotocol/market-info'; import { MarketInfoContainer } from '@vegaprotocol/market-info';
import { OrderbookContainer } from '@vegaprotocol/market-depth'; import { OrderbookContainer } from '@vegaprotocol/market-depth';
import { ColumnKind, SelectMarketPopover } from '@vegaprotocol/market-list';
import type { OnCellClickHandler } from '@vegaprotocol/market-list';
import { OrderListContainer } from '@vegaprotocol/orders'; import { OrderListContainer } from '@vegaprotocol/orders';
import { FillsContainer } from '@vegaprotocol/fills'; import { FillsContainer } from '@vegaprotocol/fills';
import { PositionsContainer } from '@vegaprotocol/positions'; import { PositionsContainer } from '@vegaprotocol/positions';
@ -44,6 +42,11 @@ import {
} from '@vegaprotocol/types'; } from '@vegaprotocol/types';
import { Header, HeaderStat } from '../../components/header'; import { Header, HeaderStat } from '../../components/header';
import { AccountsContainer } from '../portfolio/accounts-container'; import { AccountsContainer } from '../portfolio/accounts-container';
import {
ColumnKind,
SelectMarketPopover,
} from '../../components/select-market';
import type { OnCellClickHandler } from '../../components/select-market';
const TradingViews = { const TradingViews = {
Candles: CandlesChartContainer, Candles: CandlesChartContainer,

View File

@ -3,16 +3,9 @@ fragment AccountFields on Account {
balance balance
market { market {
id id
tradableInstrument {
instrument {
name
}
}
} }
asset { asset {
id id
symbol
decimals
} }
} }
@ -33,3 +26,22 @@ subscription AccountEvents($partyId: ID!) {
marketId marketId
} }
} }
fragment AssetsFields on Asset {
id
name
symbol
decimals
quantum
status
}
query Assets {
assetsConnection {
edges {
node {
...AssetsFields
}
}
}
}

View File

@ -3,14 +3,14 @@ import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client'; import * as Apollo from '@apollo/client';
const defaultOptions = {} as const; const defaultOptions = {} as const;
export type AccountFieldsFragment = { __typename?: 'Account', type: Types.AccountType, balance: string, market?: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } | null, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } }; export type AccountFieldsFragment = { __typename?: 'Account', type: Types.AccountType, balance: string, market?: { __typename?: 'Market', id: string } | null, asset: { __typename?: 'Asset', id: string } };
export type AccountsQueryVariables = Types.Exact<{ export type AccountsQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID']; partyId: Types.Scalars['ID'];
}>; }>;
export type AccountsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, market?: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } | null, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } }> | null } | null }; export type AccountsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, market?: { __typename?: 'Market', id: string } | null, asset: { __typename?: 'Asset', id: string } }> | null } | null };
export type AccountEventsSubscriptionVariables = Types.Exact<{ export type AccountEventsSubscriptionVariables = Types.Exact<{
partyId: Types.Scalars['ID']; partyId: Types.Scalars['ID'];
@ -19,25 +19,35 @@ export type AccountEventsSubscriptionVariables = Types.Exact<{
export type AccountEventsSubscription = { __typename?: 'Subscription', accounts: Array<{ __typename?: 'AccountUpdate', type: Types.AccountType, balance: string, assetId: string, marketId?: string | null }> }; export type AccountEventsSubscription = { __typename?: 'Subscription', accounts: Array<{ __typename?: 'AccountUpdate', type: Types.AccountType, balance: string, assetId: string, marketId?: string | null }> };
export type AssetsFieldsFragment = { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus };
export type AssetsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type AssetsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus } } | null> | null } | null };
export const AccountFieldsFragmentDoc = gql` export const AccountFieldsFragmentDoc = gql`
fragment AccountFields on Account { fragment AccountFields on Account {
type type
balance balance
market { market {
id id
tradableInstrument {
instrument {
name
}
}
} }
asset { asset {
id id
symbol
decimals
} }
} }
`; `;
export const AssetsFieldsFragmentDoc = gql`
fragment AssetsFields on Asset {
id
name
symbol
decimals
quantum
status
}
`;
export const AccountsDocument = gql` export const AccountsDocument = gql`
query Accounts($partyId: ID!) { query Accounts($partyId: ID!) {
party(id: $partyId) { party(id: $partyId) {
@ -109,3 +119,41 @@ export function useAccountEventsSubscription(baseOptions: Apollo.SubscriptionHoo
} }
export type AccountEventsSubscriptionHookResult = ReturnType<typeof useAccountEventsSubscription>; export type AccountEventsSubscriptionHookResult = ReturnType<typeof useAccountEventsSubscription>;
export type AccountEventsSubscriptionResult = Apollo.SubscriptionResult<AccountEventsSubscription>; export type AccountEventsSubscriptionResult = Apollo.SubscriptionResult<AccountEventsSubscription>;
export const AssetsDocument = gql`
query Assets {
assetsConnection {
edges {
node {
...AssetsFields
}
}
}
}
${AssetsFieldsFragmentDoc}`;
/**
* __useAssetsQuery__
*
* To run a query within a React component, call `useAssetsQuery` and pass it any options that fit your needs.
* When your component renders, `useAssetsQuery` 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 } = useAssetsQuery({
* variables: {
* },
* });
*/
export function useAssetsQuery(baseOptions?: Apollo.QueryHookOptions<AssetsQuery, AssetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<AssetsQuery, AssetsQueryVariables>(AssetsDocument, options);
}
export function useAssetsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AssetsQuery, AssetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<AssetsQuery, AssetsQueryVariables>(AssetsDocument, options);
}
export type AssetsQueryHookResult = ReturnType<typeof useAssetsQuery>;
export type AssetsLazyQueryHookResult = ReturnType<typeof useAssetsLazyQuery>;
export type AssetsQueryResult = Apollo.QueryResult<AssetsQuery, AssetsQueryVariables>;

View File

@ -3,14 +3,14 @@ import { Schema as Types } from '@vegaprotocol/types';
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client'; import * as Apollo from '@apollo/client';
const defaultOptions = {} as const; const defaultOptions = {} as const;
export type AccountFieldsFragment = { __typename?: 'Account', type: Types.AccountType, balance: string, market?: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } | null, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } }; export type AccountFieldsFragment = { __typename?: 'Account', type: Types.AccountType, balance: string, market?: { __typename?: 'Market', id: string } | null, asset: { __typename?: 'Asset', id: string } };
export type AccountsQueryVariables = Types.Exact<{ export type AccountsQueryVariables = Types.Exact<{
partyId: Types.Scalars['ID']; partyId: Types.Scalars['ID'];
}>; }>;
export type AccountsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, market?: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } | null, asset: { __typename?: 'Asset', id: string, symbol: string, decimals: number } }> | null } | null }; export type AccountsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', id: string, accounts?: Array<{ __typename?: 'Account', type: Types.AccountType, balance: string, market?: { __typename?: 'Market', id: string } | null, asset: { __typename?: 'Asset', id: string } }> | null } | null };
export type AccountEventsSubscriptionVariables = Types.Exact<{ export type AccountEventsSubscriptionVariables = Types.Exact<{
partyId: Types.Scalars['ID']; partyId: Types.Scalars['ID'];
@ -19,35 +19,45 @@ export type AccountEventsSubscriptionVariables = Types.Exact<{
export type AccountEventsSubscription = { __typename?: 'Subscription', accounts: Array<{ __typename?: 'AccountUpdate', type: Types.AccountType, balance: string, assetId: string, marketId?: string | null }> }; export type AccountEventsSubscription = { __typename?: 'Subscription', accounts: Array<{ __typename?: 'AccountUpdate', type: Types.AccountType, balance: string, assetId: string, marketId?: string | null }> };
export type AssetsFieldsFragment = { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus };
export type AssetsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type AssetsQuery = { __typename?: 'Query', assetsConnection?: { __typename?: 'AssetsConnection', edges?: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, status: Types.AssetStatus } } | null> | null } | null };
export const AccountFieldsFragmentDoc = gql` export const AccountFieldsFragmentDoc = gql`
fragment AccountFields on Account { fragment AccountFields on Account {
type type
balance balance
market { market {
id
}
asset {
id
}
}
`;
export const AssetsFieldsFragmentDoc = gql`
fragment AssetsFields on Asset {
id id
tradableInstrument { name
instrument { symbol
name decimals
quantum
status
}
`;
export const AccountsDocument = gql`
query Accounts($partyId: ID!) {
party(id: $partyId) {
id
accounts {
...AccountFields
} }
} }
} }
asset { ${AccountFieldsFragmentDoc}`;
id
symbol
decimals
}
}
`;
export const AccountsDocument = gql`
query Accounts($partyId: ID!) {
party(id: $partyId) {
id
accounts {
...AccountFields
}
}
}
${AccountFieldsFragmentDoc}`;
/** /**
* __useAccountsQuery__ * __useAccountsQuery__
@ -66,26 +76,26 @@ export const AccountsDocument = gql`
* }); * });
*/ */
export function useAccountsQuery(baseOptions: Apollo.QueryHookOptions<AccountsQuery, AccountsQueryVariables>) { export function useAccountsQuery(baseOptions: Apollo.QueryHookOptions<AccountsQuery, AccountsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions} const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<AccountsQuery, AccountsQueryVariables>(AccountsDocument, options); return Apollo.useQuery<AccountsQuery, AccountsQueryVariables>(AccountsDocument, options);
} }
export function useAccountsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AccountsQuery, AccountsQueryVariables>) { export function useAccountsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AccountsQuery, AccountsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions} const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<AccountsQuery, AccountsQueryVariables>(AccountsDocument, options); return Apollo.useLazyQuery<AccountsQuery, AccountsQueryVariables>(AccountsDocument, options);
} }
export type AccountsQueryHookResult = ReturnType<typeof useAccountsQuery>; export type AccountsQueryHookResult = ReturnType<typeof useAccountsQuery>;
export type AccountsLazyQueryHookResult = ReturnType<typeof useAccountsLazyQuery>; export type AccountsLazyQueryHookResult = ReturnType<typeof useAccountsLazyQuery>;
export type AccountsQueryResult = Apollo.QueryResult<AccountsQuery, AccountsQueryVariables>; export type AccountsQueryResult = Apollo.QueryResult<AccountsQuery, AccountsQueryVariables>;
export const AccountEventsDocument = gql` export const AccountEventsDocument = gql`
subscription AccountEvents($partyId: ID!) { subscription AccountEvents($partyId: ID!) {
accounts(partyId: $partyId) { accounts(partyId: $partyId) {
type type
balance balance
assetId assetId
marketId marketId
}
} }
} `;
`;
/** /**
* __useAccountEventsSubscription__ * __useAccountEventsSubscription__
@ -104,8 +114,46 @@ export const AccountEventsDocument = gql`
* }); * });
*/ */
export function useAccountEventsSubscription(baseOptions: Apollo.SubscriptionHookOptions<AccountEventsSubscription, AccountEventsSubscriptionVariables>) { export function useAccountEventsSubscription(baseOptions: Apollo.SubscriptionHookOptions<AccountEventsSubscription, AccountEventsSubscriptionVariables>) {
const options = {...defaultOptions, ...baseOptions} const options = {...defaultOptions, ...baseOptions}
return Apollo.useSubscription<AccountEventsSubscription, AccountEventsSubscriptionVariables>(AccountEventsDocument, options); return Apollo.useSubscription<AccountEventsSubscription, AccountEventsSubscriptionVariables>(AccountEventsDocument, options);
} }
export type AccountEventsSubscriptionHookResult = ReturnType<typeof useAccountEventsSubscription>; export type AccountEventsSubscriptionHookResult = ReturnType<typeof useAccountEventsSubscription>;
export type AccountEventsSubscriptionResult = Apollo.SubscriptionResult<AccountEventsSubscription>; export type AccountEventsSubscriptionResult = Apollo.SubscriptionResult<AccountEventsSubscription>;
export const AssetsDocument = gql`
query Assets {
assetsConnection {
edges {
node {
...AssetsFields
}
}
}
}
${AssetsFieldsFragmentDoc}`;
/**
* __useAssetsQuery__
*
* To run a query within a React component, call `useAssetsQuery` and pass it any options that fit your needs.
* When your component renders, `useAssetsQuery` 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 } = useAssetsQuery({
* variables: {
* },
* });
*/
export function useAssetsQuery(baseOptions?: Apollo.QueryHookOptions<AssetsQuery, AssetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<AssetsQuery, AssetsQueryVariables>(AssetsDocument, options);
}
export function useAssetsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AssetsQuery, AssetsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<AssetsQuery, AssetsQueryVariables>(AssetsDocument, options);
}
export type AssetsQueryHookResult = ReturnType<typeof useAssetsQuery>;
export type AssetsLazyQueryHookResult = ReturnType<typeof useAssetsLazyQuery>;
export type AssetsQueryResult = Apollo.QueryResult<AssetsQuery, AssetsQueryVariables>;

View File

@ -1,7 +1,6 @@
import { AccountType } from '@vegaprotocol/types'; import { AccountType } from '@vegaprotocol/types';
import type { AccountFields } from './accounts-data-provider'; import type { AccountFields, Account } from './accounts-data-provider';
import { getAccountData } from './accounts-data-provider'; import { getAccountData } from './accounts-data-provider';
import type { AccountFieldsFragment } from './__generated___/Accounts';
describe('getAccountData', () => { describe('getAccountData', () => {
it('should return the correct aggregated data', () => { it('should return the correct aggregated data', () => {
@ -10,7 +9,7 @@ describe('getAccountData', () => {
}); });
}); });
const accounts: AccountFieldsFragment[] = [ const accounts = [
{ {
__typename: 'Account', __typename: 'Account',
type: AccountType.ACCOUNT_TYPE_MARGIN, type: AccountType.ACCOUNT_TYPE_MARGIN,
@ -115,9 +114,9 @@ const accounts: AccountFieldsFragment[] = [
decimals: 5, decimals: 5,
}, },
}, },
]; ] as Account[];
const accountResult: AccountFields[] = [ const accountResult = [
{ {
asset: { asset: {
__typename: 'Asset', __typename: 'Asset',
@ -240,4 +239,4 @@ const accountResult: AccountFields[] = [
type: AccountType.ACCOUNT_TYPE_GENERAL, type: AccountType.ACCOUNT_TYPE_GENERAL,
used: '0', used: '0',
}, },
]; ] as AccountFields[];

View File

@ -8,12 +8,16 @@ import type {
AccountFieldsFragment, AccountFieldsFragment,
AccountsQuery, AccountsQuery,
AccountEventsSubscription, AccountEventsSubscription,
AssetsFieldsFragment,
} from './__generated___/Accounts'; } from './__generated___/Accounts';
import { import {
makeDataProvider, makeDataProvider,
makeDerivedDataProvider, makeDerivedDataProvider,
} from '@vegaprotocol/react-helpers'; } from '@vegaprotocol/react-helpers';
import { AccountType } from '@vegaprotocol/types'; import { AccountType } from '@vegaprotocol/types';
import type { Market } from '@vegaprotocol/market-list';
import { marketsProvider } from '@vegaprotocol/market-list';
import { assetProvider } from './asset-data-provider';
function isAccount( function isAccount(
account: account:
@ -35,6 +39,11 @@ export const getId = (
? `${account.type}-${account.asset.id}-${account.market?.id ?? 'null'}` ? `${account.type}-${account.asset.id}-${account.market?.id ?? 'null'}`
: `${account.type}-${account.assetId}-${account.marketId}`; : `${account.type}-${account.assetId}-${account.marketId}`;
export type Account = Omit<AccountFieldsFragment, 'market' | 'asset'> & {
market?: Market | null;
asset: AssetsFieldsFragment;
};
const update = ( const update = (
data: AccountFieldsFragment[], data: AccountFieldsFragment[],
deltas: AccountEventsSubscription['accounts'] deltas: AccountEventsSubscription['accounts']
@ -46,7 +55,13 @@ const update = (
if (index !== -1) { if (index !== -1) {
draft[index].balance = delta.balance; draft[index].balance = delta.balance;
} else { } else {
// #TODO handle new account draft.unshift({
__typename: 'Account',
type: delta.type,
balance: delta.balance,
market: delta.marketId ? { id: delta.marketId } : null,
asset: { id: delta.assetId },
});
} }
}); });
}); });
@ -62,7 +77,7 @@ const getDelta = (
subscriptionData: AccountEventsSubscription subscriptionData: AccountEventsSubscription
): AccountEventsSubscription['accounts'] => subscriptionData.accounts; ): AccountEventsSubscription['accounts'] => subscriptionData.accounts;
export const accountsDataProvider = makeDataProvider< export const accountsBasedDataProvider = makeDataProvider<
AccountsQuery, AccountsQuery,
AccountFieldsFragment[], AccountFieldsFragment[],
AccountEventsSubscription, AccountEventsSubscription,
@ -75,7 +90,7 @@ export const accountsDataProvider = makeDataProvider<
getDelta, getDelta,
}); });
export interface AccountFields extends AccountFieldsFragment { export interface AccountFields extends Account {
available: string; available: string;
used: string; used: string;
deposited: string; deposited: string;
@ -92,15 +107,13 @@ const USE_ACCOUNT_TYPES = [
AccountType.ACCOUNT_TYPE_PENDING_TRANSFERS, AccountType.ACCOUNT_TYPE_PENDING_TRANSFERS,
]; ];
const getAssetIds = (data: AccountFieldsFragment[]) => const getAssetIds = (data: Account[]) =>
Array.from(new Set(data.map((a) => a.asset.id))).sort(); Array.from(new Set(data.map((a) => a.asset.id))).sort();
const getTotalBalance = (accounts: AccountFieldsFragment[]) => const getTotalBalance = (accounts: AccountFieldsFragment[]) =>
accounts.reduce((acc, a) => acc + BigInt(a.balance), BigInt(0)); accounts.reduce((acc, a) => acc + BigInt(a.balance), BigInt(0));
export const getAccountData = ( export const getAccountData = (data: Account[]): AccountFields[] => {
data: AccountFieldsFragment[]
): AccountFields[] => {
return getAssetIds(data).map((assetId) => { return getAssetIds(data).map((assetId) => {
const accounts = data.filter((a) => a.asset.id === assetId); const accounts = data.filter((a) => a.asset.id === assetId);
return accounts && getAssetAccountAggregation(accounts, assetId); return accounts && getAssetAccountAggregation(accounts, assetId);
@ -108,7 +121,7 @@ export const getAccountData = (
}; };
const getAssetAccountAggregation = ( const getAssetAccountAggregation = (
accountList: AccountFieldsFragment[], accountList: Account[],
assetId: string assetId: string
): AccountFields => { ): AccountFields => {
const accounts = accountList.filter((a) => a.asset.id === assetId); const accounts = accountList.filter((a) => a.asset.id === assetId);
@ -141,10 +154,42 @@ const getAssetAccountAggregation = (
return { ...balanceAccount, breakdown }; return { ...balanceAccount, breakdown };
}; };
export const accountsDataProvider = makeDerivedDataProvider<Account[], never>(
[accountsBasedDataProvider, marketsProvider, assetProvider],
([accounts, markets, assets]): Account[] | null => {
return accounts
? accounts
.map((account: AccountFieldsFragment) => {
const market = markets.find(
(market: Market) => market.id === account.market?.id
);
const asset = assets.find(
(asset: AssetsFieldsFragment) => asset.id === account.asset?.id
);
if (asset) {
return {
...account,
asset: {
...asset,
},
market: market
? {
...market,
}
: null,
};
}
return null;
})
.filter((account: Account | null) => Boolean(account))
: null;
}
);
export const aggregatedAccountsDataProvider = makeDerivedDataProvider< export const aggregatedAccountsDataProvider = makeDerivedDataProvider<
AccountFields[], AccountFields[],
never never
>( >(
[accountsDataProvider], [accountsDataProvider],
(parts) => parts[0] && getAccountData(parts[0] as AccountFieldsFragment[]) (parts) => parts[0] && getAccountData(parts[0] as Account[])
); );

View File

@ -4,7 +4,7 @@ import type { AccountFields } from './accounts-data-provider';
import { getAccountData } from './accounts-data-provider'; import { getAccountData } from './accounts-data-provider';
import { AccountTable } from './accounts-table'; import { AccountTable } from './accounts-table';
const singleRow: AccountFields = { const singleRow = {
__typename: 'Account', __typename: 'Account',
type: Types.AccountType.ACCOUNT_TYPE_MARGIN, type: Types.AccountType.ACCOUNT_TYPE_MARGIN,
balance: '125600000', balance: '125600000',
@ -28,7 +28,7 @@ const singleRow: AccountFields = {
available: '125600000', available: '125600000',
used: '125600000', used: '125600000',
deposited: '125600000', deposited: '125600000',
}; } as AccountFields;
const singleRowData = [singleRow]; const singleRowData = [singleRow];
describe('AccountsTable', () => { describe('AccountsTable', () => {

View File

@ -0,0 +1,21 @@
import { makeDataProvider } from '@vegaprotocol/react-helpers';
import { AssetsDocument } from './__generated__/Accounts';
import type {
AssetsQuery,
AssetsFieldsFragment,
} from './__generated__/Accounts';
const getData = (responseData: AssetsQuery) =>
responseData.assetsConnection?.edges
?.filter((e) => Boolean(e?.node))
.map((e) => e?.node as AssetsFieldsFragment) ?? null;
export const assetProvider = makeDataProvider<
AssetsQuery,
AssetsFieldsFragment[] | null,
never,
never
>({
query: AssetsDocument,
getData,
});

View File

@ -4,7 +4,7 @@ import { Schema as Types } from '@vegaprotocol/types';
import type { AccountFields } from './accounts-data-provider'; import type { AccountFields } from './accounts-data-provider';
import { getAccountData } from './accounts-data-provider'; import { getAccountData } from './accounts-data-provider';
const singleRow: AccountFields = { const singleRow = {
__typename: 'Account', __typename: 'Account',
type: Types.AccountType.ACCOUNT_TYPE_MARGIN, type: Types.AccountType.ACCOUNT_TYPE_MARGIN,
balance: '125600000', balance: '125600000',
@ -28,7 +28,7 @@ const singleRow: AccountFields = {
available: '125600000', available: '125600000',
used: '125600000', used: '125600000',
deposited: '125600000', deposited: '125600000',
}; } as AccountFields;
const singleRowData = [singleRow]; const singleRowData = [singleRow];
describe('BreakdownTable', () => { describe('BreakdownTable', () => {

View File

@ -1,4 +1 @@
export * from './markets-container'; export * from './markets-container';
export * from './select-market-columns';
export * from './select-market-table';
export * from './select-market';

View File

@ -1,5 +1,7 @@
export * from './lib/__generated__/Positions'; export * from './lib/__generated__/Positions';
export * from './lib/__generated__/Margins';
export * from './lib/__generated__/PositionsSubscription'; export * from './lib/__generated__/PositionsSubscription';
export * from './lib/__generated__/MarginsSubscription';
export * from './lib/positions-container'; export * from './lib/positions-container';
export * from './lib/positions-data-providers'; export * from './lib/positions-data-providers';
export * from './lib/positions-table'; export * from './lib/positions-table';

View File

@ -0,0 +1,89 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL query operation: Margins
// ====================================================
export interface Margins_party_marginsConnection_edges_node_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
}
export interface Margins_party_marginsConnection_edges_node_asset {
__typename: "Asset";
/**
* The ID of the asset
*/
id: string;
}
export interface Margins_party_marginsConnection_edges_node {
__typename: "MarginLevels";
/**
* Market in which the margin is required for this party
*/
market: Margins_party_marginsConnection_edges_node_market;
/**
* Minimal margin for the position to be maintained in the network (unsigned integer)
*/
maintenanceLevel: string;
/**
* If the margin is between maintenance and search, the network will initiate a collateral search (unsigned integer)
*/
searchLevel: string;
/**
* This is the minimum margin required for a party to place a new order on the network (unsigned integer)
*/
initialLevel: string;
/**
* If the margin of the party is greater than this level, then collateral will be released from the margin account into
* the general account of the party for the given asset.
*/
collateralReleaseLevel: string;
/**
* Asset for the current margins
*/
asset: Margins_party_marginsConnection_edges_node_asset;
}
export interface Margins_party_marginsConnection_edges {
__typename: "MarginEdge";
node: Margins_party_marginsConnection_edges_node;
}
export interface Margins_party_marginsConnection {
__typename: "MarginConnection";
/**
* The margin levels in this connection
*/
edges: Margins_party_marginsConnection_edges[] | null;
}
export interface Margins_party {
__typename: "Party";
/**
* Party identifier
*/
id: string;
/**
* Margin levels for a market
*/
marginsConnection: Margins_party_marginsConnection | null;
}
export interface Margins {
/**
* An entity that is trading on the Vega network
*/
party: Margins_party | null;
}
export interface MarginsVariables {
partyId: string;
}

View File

@ -0,0 +1,56 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL subscription operation: MarginsSubscription
// ====================================================
export interface MarginsSubscription_margins {
__typename: "MarginLevelsUpdate";
/**
* Market in which the margin is required for this party
*/
marketId: string;
/**
* Asset for the current margins
*/
asset: string;
/**
* The party for this margin
*/
partyId: string;
/**
* Minimal margin for the position to be maintained in the network (unsigned integer)
*/
maintenanceLevel: string;
/**
* If the margin is between maintenance and search, the network will initiate a collateral search (unsigned integer)
*/
searchLevel: string;
/**
* This is the minimum margin required for a party to place a new order on the network (unsigned integer)
*/
initialLevel: string;
/**
* If the margin of the party is greater than this level, then collateral will be released from the margin account into
* the general account of the party for the given asset.
*/
collateralReleaseLevel: string;
/**
* RFC3339Nano time from at which this margin level was relevant
*/
timestamp: string;
}
export interface MarginsSubscription {
/**
* Subscribe to the margin changes
*/
margins: MarginsSubscription_margins;
}
export interface MarginsSubscriptionVariables {
partyId: string;
}

View File

@ -3,148 +3,16 @@
// @generated // @generated
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { MarketTradingMode } from "@vegaprotocol/types";
// ==================================================== // ====================================================
// GraphQL fragment: PositionFields // GraphQL fragment: PositionFields
// ==================================================== // ====================================================
export interface PositionFields_marginsConnection_edges_node_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
}
export interface PositionFields_marginsConnection_edges_node_asset {
__typename: "Asset";
/**
* The symbol of the asset (e.g: GBP)
*/
symbol: string;
}
export interface PositionFields_marginsConnection_edges_node {
__typename: "MarginLevels";
/**
* Market in which the margin is required for this party
*/
market: PositionFields_marginsConnection_edges_node_market;
/**
* Minimal margin for the position to be maintained in the network (unsigned integer)
*/
maintenanceLevel: string;
/**
* If the margin is between maintenance and search, the network will initiate a collateral search (unsigned integer)
*/
searchLevel: string;
/**
* This is the minimum margin required for a party to place a new order on the network (unsigned integer)
*/
initialLevel: string;
/**
* If the margin of the party is greater than this level, then collateral will be released from the margin account into
* the general account of the party for the given asset.
*/
collateralReleaseLevel: string;
/**
* Asset for the current margins
*/
asset: PositionFields_marginsConnection_edges_node_asset;
}
export interface PositionFields_marginsConnection_edges {
__typename: "MarginEdge";
node: PositionFields_marginsConnection_edges_node;
}
export interface PositionFields_marginsConnection {
__typename: "MarginConnection";
/**
* The margin levels in this connection
*/
edges: PositionFields_marginsConnection_edges[] | null;
}
export interface PositionFields_market_tradableInstrument_instrument {
__typename: "Instrument";
/**
* Full and fairly descriptive name for the instrument
*/
name: string;
}
export interface PositionFields_market_tradableInstrument {
__typename: "TradableInstrument";
/**
* An instance of, or reference to, a fully specified instrument.
*/
instrument: PositionFields_market_tradableInstrument_instrument;
}
export interface PositionFields_market_data_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
}
export interface PositionFields_market_data {
__typename: "MarketData";
/**
* The mark price (an unsigned integer)
*/
markPrice: string;
/**
* Market of the associated mark price
*/
market: PositionFields_market_data_market;
}
export interface PositionFields_market { export interface PositionFields_market {
__typename: "Market"; __typename: "Market";
/** /**
* Market ID * Market ID
*/ */
id: string; id: string;
/**
* The number of decimal places that an integer must be shifted by in order to get a correct
* number denominated in the currency of the market. (uint64)
*
* Examples:
* Currency Balance decimalPlaces Real Balance
* GBP 100 0 GBP 100
* GBP 100 2 GBP 1.00
* GBP 100 4 GBP 0.01
* GBP 1 4 GBP 0.0001 ( 0.01p )
*
* GBX (pence) 100 0 GBP 1.00 (100p )
* GBX (pence) 100 2 GBP 0.01 ( 1p )
* GBX (pence) 100 4 GBP 0.0001 ( 0.01p )
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
/**
* The number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
* This sets how big the smallest order / position on the market can be.
*/
positionDecimalPlaces: number;
/**
* Current mode of execution of the market
*/
tradingMode: MarketTradingMode;
/**
* An instance of, or reference to, a tradable instrument.
*/
tradableInstrument: PositionFields_market_tradableInstrument;
/**
* marketData for the given market
*/
data: PositionFields_market_data | null;
} }
export interface PositionFields { export interface PositionFields {
@ -169,10 +37,6 @@ export interface PositionFields {
* RFC3339Nano time the position was updated * RFC3339Nano time the position was updated
*/ */
updatedAt: string | null; updatedAt: string | null;
/**
* Margins of the party for the given position
*/
marginsConnection: PositionFields_marginsConnection | null;
/** /**
* Market relating to this position * Market relating to this position
*/ */

View File

@ -3,148 +3,16 @@
// @generated // @generated
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { MarketTradingMode } from "@vegaprotocol/types";
// ==================================================== // ====================================================
// GraphQL query operation: Positions // GraphQL query operation: Positions
// ==================================================== // ====================================================
export interface Positions_party_positionsConnection_edges_node_marginsConnection_edges_node_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
}
export interface Positions_party_positionsConnection_edges_node_marginsConnection_edges_node_asset {
__typename: "Asset";
/**
* The symbol of the asset (e.g: GBP)
*/
symbol: string;
}
export interface Positions_party_positionsConnection_edges_node_marginsConnection_edges_node {
__typename: "MarginLevels";
/**
* Market in which the margin is required for this party
*/
market: Positions_party_positionsConnection_edges_node_marginsConnection_edges_node_market;
/**
* Minimal margin for the position to be maintained in the network (unsigned integer)
*/
maintenanceLevel: string;
/**
* If the margin is between maintenance and search, the network will initiate a collateral search (unsigned integer)
*/
searchLevel: string;
/**
* This is the minimum margin required for a party to place a new order on the network (unsigned integer)
*/
initialLevel: string;
/**
* If the margin of the party is greater than this level, then collateral will be released from the margin account into
* the general account of the party for the given asset.
*/
collateralReleaseLevel: string;
/**
* Asset for the current margins
*/
asset: Positions_party_positionsConnection_edges_node_marginsConnection_edges_node_asset;
}
export interface Positions_party_positionsConnection_edges_node_marginsConnection_edges {
__typename: "MarginEdge";
node: Positions_party_positionsConnection_edges_node_marginsConnection_edges_node;
}
export interface Positions_party_positionsConnection_edges_node_marginsConnection {
__typename: "MarginConnection";
/**
* The margin levels in this connection
*/
edges: Positions_party_positionsConnection_edges_node_marginsConnection_edges[] | null;
}
export interface Positions_party_positionsConnection_edges_node_market_tradableInstrument_instrument {
__typename: "Instrument";
/**
* Full and fairly descriptive name for the instrument
*/
name: string;
}
export interface Positions_party_positionsConnection_edges_node_market_tradableInstrument {
__typename: "TradableInstrument";
/**
* An instance of, or reference to, a fully specified instrument.
*/
instrument: Positions_party_positionsConnection_edges_node_market_tradableInstrument_instrument;
}
export interface Positions_party_positionsConnection_edges_node_market_data_market {
__typename: "Market";
/**
* Market ID
*/
id: string;
}
export interface Positions_party_positionsConnection_edges_node_market_data {
__typename: "MarketData";
/**
* The mark price (an unsigned integer)
*/
markPrice: string;
/**
* Market of the associated mark price
*/
market: Positions_party_positionsConnection_edges_node_market_data_market;
}
export interface Positions_party_positionsConnection_edges_node_market { export interface Positions_party_positionsConnection_edges_node_market {
__typename: "Market"; __typename: "Market";
/** /**
* Market ID * Market ID
*/ */
id: string; id: string;
/**
* The number of decimal places that an integer must be shifted by in order to get a correct
* number denominated in the currency of the market. (uint64)
*
* Examples:
* Currency Balance decimalPlaces Real Balance
* GBP 100 0 GBP 100
* GBP 100 2 GBP 1.00
* GBP 100 4 GBP 0.01
* GBP 1 4 GBP 0.0001 ( 0.01p )
*
* GBX (pence) 100 0 GBP 1.00 (100p )
* GBX (pence) 100 2 GBP 0.01 ( 1p )
* GBX (pence) 100 4 GBP 0.0001 ( 0.01p )
* GBX (pence) 1 4 GBP 0.000001 ( 0.0001p)
*/
decimalPlaces: number;
/**
* The number of decimal places that an integer must be shifted in order to get a correct size (uint64).
* i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes.
* 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market.
* This sets how big the smallest order / position on the market can be.
*/
positionDecimalPlaces: number;
/**
* Current mode of execution of the market
*/
tradingMode: MarketTradingMode;
/**
* An instance of, or reference to, a tradable instrument.
*/
tradableInstrument: Positions_party_positionsConnection_edges_node_market_tradableInstrument;
/**
* marketData for the given market
*/
data: Positions_party_positionsConnection_edges_node_market_data | null;
} }
export interface Positions_party_positionsConnection_edges_node { export interface Positions_party_positionsConnection_edges_node {
@ -169,10 +37,6 @@ export interface Positions_party_positionsConnection_edges_node {
* RFC3339Nano time the position was updated * RFC3339Nano time the position was updated
*/ */
updatedAt: string | null; updatedAt: string | null;
/**
* Margins of the party for the given position
*/
marginsConnection: Positions_party_positionsConnection_edges_node_marginsConnection | null;
/** /**
* Market relating to this position * Market relating to this position
*/ */

View File

@ -0,0 +1,104 @@
import { gql } from '@apollo/client';
import produce from 'immer';
import { makeDataProvider } from '@vegaprotocol/react-helpers';
import type {
MarginsSubscription,
MarginsSubscription_margins,
} from './__generated__/MarginsSubscription';
import type { Margins, Margins_party } from './__generated__/Margins';
export const MARGINS_QUERY = gql`
query Margins($partyId: ID!) {
party(id: $partyId) {
id
marginsConnection {
edges {
node {
market {
id
}
maintenanceLevel
searchLevel
initialLevel
collateralReleaseLevel
asset {
id
}
}
}
}
}
}
`;
export const MARGINS_SUBSCRIPTION = gql`
subscription MarginsSubscription($partyId: ID!) {
margins(partyId: $partyId) {
marketId
asset
partyId
maintenanceLevel
searchLevel
initialLevel
collateralReleaseLevel
timestamp
}
}
`;
const update = (data: Margins_party, delta: MarginsSubscription_margins) => {
return produce(data, (draft) => {
const { marketId } = delta;
if (marketId && draft.marginsConnection?.edges) {
const index = draft.marginsConnection.edges.findIndex(
(edge) => edge.node.market.id === marketId
);
if (index !== -1) {
const currNode = draft.marginsConnection.edges[index].node;
draft.marginsConnection.edges[index].node = {
...currNode,
maintenanceLevel: delta.maintenanceLevel,
searchLevel: delta.searchLevel,
initialLevel: delta.initialLevel,
collateralReleaseLevel: delta.collateralReleaseLevel,
};
} else {
draft.marginsConnection.edges.unshift({
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
market: {
__typename: 'Market',
id: delta.marketId,
},
maintenanceLevel: delta.maintenanceLevel,
searchLevel: delta.searchLevel,
initialLevel: delta.initialLevel,
collateralReleaseLevel: delta.collateralReleaseLevel,
asset: {
__typename: 'Asset',
id: delta.asset,
},
},
});
}
}
});
};
const getData = (responseData: Margins) => responseData.party;
const getDelta = (subscriptionData: MarginsSubscription) =>
subscriptionData.margins;
export const marginsDataProvider = makeDataProvider<
Margins,
Margins_party,
MarginsSubscription,
MarginsSubscription_margins
>({
query: MARGINS_QUERY,
subscriptionQuery: MARGINS_SUBSCRIPTION,
update,
getData,
getDelta,
});

View File

@ -1,74 +1,70 @@
import { AccountType, MarketTradingMode } from '@vegaprotocol/types'; import { AccountType, MarketTradingMode } from '@vegaprotocol/types';
import type { AccountsQuery } from '@vegaprotocol/accounts'; import type { Account } from '@vegaprotocol/accounts';
import type { Positions } from './__generated__/Positions'; import type { Positions } from './__generated__/Positions';
import { getMetrics } from './positions-data-providers'; import { getMetrics, rejoinPositionData } from './positions-data-providers';
import type { MarketWithData } from '@vegaprotocol/market-list';
import type { Margins } from './__generated__/Margins';
const accounts: AccountsQuery = { const accounts = [
party: { {
__typename: 'Party', __typename: 'Account',
id: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65', type: AccountType.ACCOUNT_TYPE_GENERAL,
accounts: [ asset: {
{ __typename: 'Asset',
__typename: 'Account', symbol: 'tDAI',
type: AccountType.ACCOUNT_TYPE_GENERAL, id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
asset: { decimals: 5,
__typename: 'Asset', },
symbol: 'tDAI', balance: '892824769',
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61', market: null,
decimals: 5,
},
balance: '892824769',
market: null,
},
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_MARGIN,
asset: {
__typename: 'Asset',
symbol: 'tDAI',
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
decimals: 5,
},
balance: '33353727',
market: {
__typename: 'Market',
id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'AAVEDAI Monthly (30 Jun 2022)',
},
},
},
},
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_MARGIN,
asset: {
__typename: 'Asset',
symbol: 'tDAI',
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
decimals: 5,
},
balance: '3274050',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'UNIDAI Monthly (30 Jun 2022)',
},
},
},
},
],
}, },
}; {
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_MARGIN,
asset: {
__typename: 'Asset',
symbol: 'tDAI',
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
decimals: 5,
},
balance: '33353727',
market: {
__typename: 'Market',
id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'AAVEDAI Monthly (30 Jun 2022)',
},
},
},
},
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_MARGIN,
asset: {
__typename: 'Asset',
symbol: 'tDAI',
id: '6d9d35f657589e40ddfb448b7ad4a7463b66efb307527fedd2aa7df1bbd5ea61',
decimals: 5,
},
balance: '3274050',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'UNIDAI Monthly (30 Jun 2022)',
},
},
},
},
] as Account[];
const data: Positions = { const positions: Positions = {
party: { party: {
__typename: 'Party', __typename: 'Party',
id: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65', id: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65',
@ -84,50 +80,9 @@ const data: Positions = {
updatedAt: '2022-07-28T14:53:54.725477Z', updatedAt: '2022-07-28T14:53:54.725477Z',
realisedPNL: '0', realisedPNL: '0',
unrealisedPNL: '43804770', unrealisedPNL: '43804770',
marginsConnection: {
__typename: 'MarginConnection',
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
},
asset: {
__typename: 'Asset',
symbol: 'tDAI',
},
},
},
],
},
market: { market: {
__typename: 'Market', __typename: 'Market',
id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8', id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
decimalPlaces: 5,
tradingMode: MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
positionDecimalPlaces: 0,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'AAVEDAI Monthly (30 Jun 2022)',
},
},
data: {
__typename: 'MarketData',
markPrice: '9431775',
market: {
__typename: 'Market',
id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
},
},
}, },
}, },
}, },
@ -140,50 +95,9 @@ const data: Positions = {
unrealisedPNL: '-9112700', unrealisedPNL: '-9112700',
averageEntryPrice: '840158', averageEntryPrice: '840158',
updatedAt: '2022-07-28T15:09:34.441143Z', updatedAt: '2022-07-28T15:09:34.441143Z',
marginsConnection: {
__typename: 'MarginConnection',
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
},
asset: {
__typename: 'Asset',
symbol: 'tDAI',
},
},
},
],
},
market: { market: {
__typename: 'Market', __typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e', id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
decimalPlaces: 5,
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
positionDecimalPlaces: 0,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'UNIDAI Monthly (30 Jun 2022)',
},
},
data: {
__typename: 'MarketData',
markPrice: '869762',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
},
},
}, },
}, },
}, },
@ -192,14 +106,129 @@ const data: Positions = {
}, },
}; };
describe('getMetrics', () => { const marketsData = [
{
__typename: 'Market',
id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
decimalPlaces: 5,
tradingMode: MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
positionDecimalPlaces: 0,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'AAVEDAI Monthly (30 Jun 2022)',
product: {
settlementAsset: {
symbol: 'tDAI',
},
},
},
},
data: {
__typename: 'MarketData',
markPrice: '9431775',
market: {
__typename: 'Market',
id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
},
},
},
{
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
decimalPlaces: 5,
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
positionDecimalPlaces: 0,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'UNIDAI Monthly (30 Jun 2022)',
product: {
settlementAsset: {
symbol: 'tDAI',
},
},
},
},
data: {
__typename: 'MarketData',
markPrice: '869762',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
},
},
},
] as MarketWithData[];
const margins: Margins = {
party: {
id: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65',
marginsConnection: {
edges: [
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
},
asset: {
__typename: 'Asset',
id: 'tDAI-id',
},
},
},
{
__typename: 'MarginEdge',
node: {
__typename: 'MarginLevels',
maintenanceLevel: '0',
searchLevel: '0',
initialLevel: '0',
collateralReleaseLevel: '0',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
},
asset: {
__typename: 'Asset',
id: 'tDAI-id',
},
},
},
],
__typename: 'MarginConnection',
},
__typename: 'Party',
},
};
describe('getMetrics && rejoinPositionData', () => {
it('returns positions metrics', () => { it('returns positions metrics', () => {
const metrics = getMetrics(data.party, accounts.party?.accounts ?? null); const positionsRejoined = rejoinPositionData(
positions.party,
marketsData,
margins.party
);
const metrics = getMetrics(positionsRejoined, accounts || null);
expect(metrics.length).toEqual(2); expect(metrics.length).toEqual(2);
}); });
it('calculates metrics', () => { it('calculates metrics', () => {
const metrics = getMetrics(data.party, accounts.party?.accounts ?? null); const positionsRejoined = rejoinPositionData(
positions.party,
marketsData,
margins.party
);
const metrics = getMetrics(positionsRejoined, accounts || null);
expect(metrics[0].assetSymbol).toEqual('tDAI'); expect(metrics[0].assetSymbol).toEqual('tDAI');
expect(metrics[0].averageEntryPrice).toEqual('8993727'); expect(metrics[0].averageEntryPrice).toEqual('8993727');

View File

@ -2,10 +2,14 @@ import { gql } from '@apollo/client';
import produce from 'immer'; import produce from 'immer';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import sortBy from 'lodash/sortBy'; import sortBy from 'lodash/sortBy';
import type { AccountFieldsFragment } from '@vegaprotocol/accounts'; import type { Account } from '@vegaprotocol/accounts';
import { accountsDataProvider } from '@vegaprotocol/accounts'; import { accountsDataProvider } from '@vegaprotocol/accounts';
import { toBigNum } from '@vegaprotocol/react-helpers'; import { toBigNum } from '@vegaprotocol/react-helpers';
import type { Positions, Positions_party } from './__generated__/Positions'; import type {
Positions,
Positions_party,
Positions_party_positionsConnection_edges,
} from './__generated__/Positions';
import { import {
makeDataProvider, makeDataProvider,
makeDerivedDataProvider, makeDerivedDataProvider,
@ -18,6 +22,28 @@ import type {
import { AccountType } from '@vegaprotocol/types'; import { AccountType } from '@vegaprotocol/types';
import type { MarketTradingMode } from '@vegaprotocol/types'; import type { MarketTradingMode } from '@vegaprotocol/types';
import type { MarketWithData } from '@vegaprotocol/market-list';
import { marketsWithDataProvider } from '@vegaprotocol/market-list';
import { marginsDataProvider } from './margin-data-provider';
import type {
Margins_party,
Margins_party_marginsConnection_edges_node,
} from './__generated__/Margins';
type PositionMarginLevel = Pick<
Margins_party_marginsConnection_edges_node,
'maintenanceLevel' | 'searchLevel' | 'initialLevel'
>;
interface PositionRejoined {
realisedPNL: string;
openVolume: string;
unrealisedPNL: string;
averageEntryPrice: string;
updatedAt: string | null;
market: MarketWithData | null;
margins: PositionMarginLevel | null;
}
export interface Position { export interface Position {
marketName: string; marketName: string;
@ -54,38 +80,8 @@ const POSITION_FIELDS = gql`
unrealisedPNL unrealisedPNL
averageEntryPrice averageEntryPrice
updatedAt updatedAt
marginsConnection {
edges {
node {
market {
id
}
maintenanceLevel
searchLevel
initialLevel
collateralReleaseLevel
asset {
symbol
}
}
}
}
market { market {
id id
decimalPlaces
positionDecimalPlaces
tradingMode
tradableInstrument {
instrument {
name
}
}
data {
markPrice
market {
id
}
}
} }
} }
`; `;
@ -120,27 +116,26 @@ export const POSITIONS_SUBSCRIPTION = gql`
`; `;
export const getMetrics = ( export const getMetrics = (
data: Positions_party | null, data: PositionRejoined[] | null,
accounts: AccountFieldsFragment[] | null accounts: Account[] | null
): Position[] => { ): Position[] => {
if (!data || !data?.positionsConnection?.edges) { if (!data || !data?.length) {
return []; return [];
} }
const metrics: Position[] = []; const metrics: Position[] = [];
data?.positionsConnection.edges.forEach((position) => { data.forEach((position) => {
const market = position.node.market; const market = position.market;
const marketData = market.data; const marketData = market?.data;
const marginLevel = position.node.marginsConnection?.edges?.find( const marginLevel = position.margins;
(margin) => margin.node.market.id === market.id
)?.node;
const marginAccount = accounts?.find((account) => { const marginAccount = accounts?.find((account) => {
return account.market?.id === market.id; return account.market?.id === market?.id;
}); });
if ( if (
!marginAccount || !marginAccount ||
!marginLevel || !marginLevel ||
!market ||
!marketData || !marketData ||
position.node.openVolume === '0' position.openVolume === '0'
) { ) {
return; return;
} }
@ -152,10 +147,7 @@ export const getMetrics = (
const decimals = marginAccount.asset.decimals; const decimals = marginAccount.asset.decimals;
const { positionDecimalPlaces, decimalPlaces: marketDecimalPlaces } = const { positionDecimalPlaces, decimalPlaces: marketDecimalPlaces } =
market; market;
const openVolume = toBigNum( const openVolume = toBigNum(position.openVolume, positionDecimalPlaces);
position.node.openVolume,
positionDecimalPlaces
);
const marginAccountBalance = toBigNum(marginAccount.balance ?? 0, decimals); const marginAccountBalance = toBigNum(marginAccount.balance ?? 0, decimals);
const generalAccountBalance = toBigNum( const generalAccountBalance = toBigNum(
@ -206,29 +198,30 @@ export const getMetrics = (
metrics.push({ metrics.push({
marketName: market.tradableInstrument.instrument.name, marketName: market.tradableInstrument.instrument.name,
averageEntryPrice: position.node.averageEntryPrice, averageEntryPrice: position.averageEntryPrice,
capitalUtilisation: Math.round(capitalUtilisation.toNumber()), capitalUtilisation: Math.round(capitalUtilisation.toNumber()),
currentLeverage: currentLeverage.toNumber(), currentLeverage: currentLeverage.toNumber(),
marketDecimalPlaces, marketDecimalPlaces,
positionDecimalPlaces, positionDecimalPlaces,
decimals, decimals,
assetSymbol: marginLevel.asset.symbol, assetSymbol:
market.tradableInstrument.instrument.product.settlementAsset.symbol,
totalBalance: totalBalance.multipliedBy(10 ** decimals).toFixed(), totalBalance: totalBalance.multipliedBy(10 ** decimals).toFixed(),
lowMarginLevel, lowMarginLevel,
liquidationPrice: liquidationPrice liquidationPrice: liquidationPrice
.multipliedBy(10 ** marketDecimalPlaces) .multipliedBy(10 ** marketDecimalPlaces)
.toFixed(0), .toFixed(0),
marketId: position.node.market.id, marketId: market.id,
marketTradingMode: position.node.market.tradingMode, marketTradingMode: market.tradingMode,
markPrice: marketData.markPrice, markPrice: marketData.markPrice,
notional: notional.multipliedBy(10 ** marketDecimalPlaces).toFixed(0), notional: notional.multipliedBy(10 ** marketDecimalPlaces).toFixed(0),
openVolume: position.node.openVolume, openVolume: position.openVolume,
realisedPNL: position.node.realisedPNL, realisedPNL: position.realisedPNL,
unrealisedPNL: position.node.unrealisedPNL, unrealisedPNL: position.unrealisedPNL,
searchPrice: searchPrice searchPrice: searchPrice
.multipliedBy(10 ** marketDecimalPlaces) .multipliedBy(10 ** marketDecimalPlaces)
.toFixed(0), .toFixed(0),
updatedAt: position.node.updatedAt, updatedAt: position.updatedAt,
}); });
}); });
return metrics; return metrics;
@ -257,7 +250,17 @@ export const update = (
updatedAt: delta.updatedAt, updatedAt: delta.updatedAt,
}; };
} else { } else {
// TODO: Handle new position insertion, we don't have full market details on PositionUpdate draft.positionsConnection.edges.unshift({
__typename: 'PositionEdge',
node: {
...delta,
__typename: 'Position',
market: {
__typename: 'Market',
id: delta.marketId,
},
},
});
} }
}); });
}); });
@ -277,15 +280,67 @@ export const positionsDataProvider = makeDataProvider<
subscriptionData.positions, subscriptionData.positions,
}); });
const upgradeMarginsConection = (
marketId: string,
margins: Margins_party | null
) => {
if (marketId && margins?.marginsConnection?.edges) {
const index =
margins.marginsConnection.edges.findIndex(
(edge) => edge.node.market.id === marketId
) ?? -1;
if (index >= 0) {
const marginLevel = margins.marginsConnection.edges[index].node;
return {
maintenanceLevel: marginLevel.maintenanceLevel,
searchLevel: marginLevel.searchLevel,
initialLevel: marginLevel.initialLevel,
};
}
}
return null;
};
export const rejoinPositionData = (
positions: Positions_party | null,
marketsData: MarketWithData[] | null,
margins: Margins_party | null
): PositionRejoined[] | null => {
if (positions?.positionsConnection?.edges && marketsData && margins) {
return positions.positionsConnection.edges.map(
(nodes: Positions_party_positionsConnection_edges) => {
return {
realisedPNL: nodes.node.realisedPNL,
openVolume: nodes.node.openVolume,
unrealisedPNL: nodes.node.unrealisedPNL,
averageEntryPrice: nodes.node.averageEntryPrice,
updatedAt: nodes.node.updatedAt,
market:
marketsData?.find((market) => market.id === nodes.node.market.id) ||
null,
margins: upgradeMarginsConection(nodes.node.market.id, margins),
};
}
);
}
return null;
};
export const positionsMetricsDataProvider = makeDerivedDataProvider< export const positionsMetricsDataProvider = makeDerivedDataProvider<
Position[], Position[],
never never
>([positionsDataProvider, accountsDataProvider], ([positions, accounts]) => { >(
return sortBy( [
getMetrics( positionsDataProvider,
positions as Positions_party | null, accountsDataProvider,
accounts as AccountFieldsFragment[] | null marketsWithDataProvider,
), marginsDataProvider,
'updatedAt' ],
).reverse(); ([positions, accounts, marketsData, margins]) => {
}); const positionsData = rejoinPositionData(positions, marketsData, margins);
return sortBy(
getMetrics(positionsData, accounts as Account[] | null),
'updatedAt'
).reverse();
}
);