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_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_WALLET_URL=http://localhost:1789

View File

@ -6,11 +6,19 @@ import { aliasQuery } from '@vegaprotocol/cypress';
import {
generatePositions,
emptyPositions,
generateMargins,
} 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 { 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' }, () => {
afterEach(() => {
@ -49,7 +57,11 @@ describe('Portfolio page', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasQuery(req, 'Positions', generatePositions());
aliasQuery(req, 'Margins', generateMargins());
aliasQuery(req, 'Markets', generatePositionsMarkets());
aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'Assets', generateAssets());
});
cy.visit('/portfolio/assets');
connectVegaWallet();
@ -75,6 +87,10 @@ describe('Portfolio page', { tags: '@smoke' }, () => {
cy.mockGQL((req) => {
aliasQuery(req, 'Positions', generatePositions());
aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'Margins', generateMargins());
aliasQuery(req, 'Markets', generatePositionsMarkets());
aliasQuery(req, 'MarketsData', generateMarketsData());
aliasQuery(req, 'Assets', generateAssets());
});
cy.visit('/portfolio/positions');
connectVegaWallet();
@ -126,6 +142,9 @@ describe('Portfolio page', { tags: '@smoke' }, () => {
aliasQuery(req, 'Markets', {
marketsConnection: { edges: [], __typename: 'MarketConnection' },
});
aliasQuery(req, 'Assets', {
assetsConnection: { edges: null, __typename: 'AssetsConnection' },
});
});
cy.visit('/portfolio');
connectVegaWallet();
@ -133,22 +152,26 @@ describe('Portfolio page', { tags: '@smoke' }, () => {
it('"No data to display" should be always displayed', () => {
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'
);
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'
);
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'
);
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'
);
});

View File

@ -1,6 +1,6 @@
import merge from 'lodash/merge';
import type { AccountsQuery } from '@vegaprotocol/accounts';
import { AccountType } from '@vegaprotocol/types';
import type { AccountsQuery, AssetsQuery } from '@vegaprotocol/accounts';
import { AccountType, Schema as Types } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
export const generateAccounts = (
@ -19,8 +19,6 @@ export const generateAccounts = (
asset: {
__typename: 'Asset',
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
},
},
{
@ -29,20 +27,11 @@ export const generateAccounts = (
balance: '100000000',
market: {
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'AAVEDAI Monthly (30 Jun 2022)',
},
},
__typename: 'Market',
},
asset: {
__typename: 'Asset',
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
},
},
{
@ -51,20 +40,11 @@ export const generateAccounts = (
balance: '1000',
market: {
__typename: 'Market',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: '',
},
},
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
},
asset: {
__typename: 'Asset',
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
},
},
{
@ -73,20 +53,11 @@ export const generateAccounts = (
balance: '1000',
market: {
__typename: 'Market',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: '',
},
},
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
},
asset: {
__typename: 'Asset',
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
},
},
{
@ -97,8 +68,6 @@ export const generateAccounts = (
asset: {
__typename: 'Asset',
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
},
},
],
@ -106,3 +75,43 @@ export const generateAccounts = (
};
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 { MarketState } from '@vegaprotocol/types';
import {
AuctionTrigger,
MarketState,
MarketTradingMode,
} from '@vegaprotocol/types';
import type {
MarketsQuery,
Market,
MarketsCandlesQuery,
Candle,
MarketsDataQuery,
MarketDataFieldsFragment,
} from '@vegaprotocol/market-list';
import { protoMarket, protoCandles } from './commons';
import type { PartialDeep } from 'type-fest';
MarketState.STATE_SUSPENDED;
export const generateSimpleMarkets = (): MarketsQuery => {
const markets: Market[] = [
{ ...protoMarket },
@ -1072,7 +1077,7 @@ export const generateMarketsCandles = (): MarketsCandlesQuery => {
};
};
export const generateMarketsData = (): MarketsDataQuery => {
export const generateEmptyMarketsData = (): MarketsDataQuery => {
return {
marketsConnection: {
__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_party_positionsConnection_edges_node,
} from '@vegaprotocol/positions';
import { MarketTradingMode } from '@vegaprotocol/types';
export const generatePositions = (
override?: PartialDeep<Positions>
@ -17,49 +16,8 @@ export const generatePositions = (
unrealisedPNL: '895000',
averageEntryPrice: '1129935',
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: {
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',
},
},
@ -70,49 +28,8 @@ export const generatePositions = (
unrealisedPNL: '895000',
averageEntryPrice: '8509338',
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: {
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',
},
},
@ -122,49 +39,8 @@ export const generatePositions = (
unrealisedPNL: '-22519',
averageEntryPrice: '84400088',
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: {
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: '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"]')
.should('contain.text', '11.29935') // entry price
.should('contain.text', '9.21954'); // liquidation price
.should('contain.text', '85,093.38') // entry 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
.should('contain.text', '0.00%')
@ -57,12 +57,12 @@ describe('positions', { tags: '@smoke' }, () => {
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', '0.00100'); // Total Realised PNL
cy.get('[col-id="unrealisedPNL"]').should('contain.text', '17.90000'); // Total Unrealised PNL
cy.getByTestId('flash-cell').should('contain.text', '276,761.40348'); // Total tDAI position
cy.getByTestId('flash-cell').should('contain.text', '0.00000'); // Total Realised 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);
}

View File

@ -1,6 +1,6 @@
import merge from 'lodash/merge';
import type { AccountsQuery } from '@vegaprotocol/accounts';
import { AccountType } from '@vegaprotocol/types';
import type { AccountsQuery, AssetsQuery } from '@vegaprotocol/accounts';
import { AccountType, Schema as Types } from '@vegaprotocol/types';
import type { PartialDeep } from 'type-fest';
export const generateAccounts = (
@ -19,8 +19,6 @@ export const generateAccounts = (
asset: {
__typename: 'Asset',
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
},
},
{
@ -28,21 +26,12 @@ export const generateAccounts = (
type: AccountType.ACCOUNT_TYPE_GENERAL,
balance: '100000000',
market: {
id: '0604e8c918655474525e1a95367902266ade70d318c2c908f0cca6e3d11dcb13',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'AAVEDAI Monthly (30 Jun 2022)',
},
},
id: 'market-1',
__typename: 'Market',
},
asset: {
__typename: 'Asset',
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
},
},
{
@ -51,20 +40,11 @@ export const generateAccounts = (
balance: '1000',
market: {
__typename: 'Market',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: '',
},
},
id: '5a4b0b9e9c0629f0315ec56fcb7bd444b0c6e4da5ec7677719d502626658a376',
id: 'market-2',
},
asset: {
__typename: 'Asset',
id: 'asset-id',
symbol: 'tEURO',
decimals: 5,
},
},
{
@ -73,20 +53,11 @@ export const generateAccounts = (
balance: '1000',
market: {
__typename: 'Market',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: '',
},
},
id: 'c9f5acd348796011c075077e4d58d9b7f1689b7c1c8e030a5e886b83aa96923d',
id: 'market-0',
},
asset: {
__typename: 'Asset',
id: 'asset-id-2',
symbol: 'tDAI',
decimals: 5,
},
},
{
@ -97,8 +68,6 @@ export const generateAccounts = (
asset: {
__typename: 'Asset',
id: 'asset-0',
symbol: 'AST0',
decimals: 5,
},
},
],
@ -106,3 +75,43 @@ export const generateAccounts = (
};
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 {
Positions,
Positions_party_positionsConnection_edges_node,
Margins,
} from '@vegaprotocol/positions';
import { MarketTradingMode } from '@vegaprotocol/types';
export const generatePositions = (
override?: PartialDeep<Positions>
@ -17,49 +17,8 @@ export const generatePositions = (
unrealisedPNL: '895000',
averageEntryPrice: '1129935',
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: {
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',
},
id: 'market-0',
__typename: 'Market',
},
},
@ -70,49 +29,8 @@ export const generatePositions = (
unrealisedPNL: '895000',
averageEntryPrice: '8509338',
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: {
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',
},
id: 'market-1',
__typename: 'Market',
},
},
@ -122,49 +40,8 @@ export const generatePositions = (
unrealisedPNL: '-22519',
averageEntryPrice: '84400088',
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: {
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',
},
id: 'market-2',
__typename: 'Market',
},
__typename: 'Position',
@ -189,3 +66,71 @@ export const generatePositions = (
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 type { MarketState } from '@vegaprotocol/types';
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 { generateChart } from './mocks/generate-chart';
import { generateDealTicketQuery } from './mocks/generate-deal-ticket-query';
@ -14,7 +14,7 @@ import {
generateMarketsCandles,
} from './mocks/generate-markets';
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';
export const mockTradingPage = (
@ -43,7 +43,10 @@ export const mockTradingPage = (
aliasQuery(req, 'Orders', generateOrders());
aliasQuery(req, 'Accounts', generateAccounts());
aliasQuery(req, 'Positions', generatePositions());
aliasQuery(req, 'Margins', generateMargins());
aliasQuery(req, 'DealTicket', generateDealTicketQuery({ market: { state } }));
aliasQuery(req, 'Assets', generateAssets());
aliasQuery(
req,
'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 BigNumber from 'bignumber.js';
import Link from 'next/link';
import { calcCandleHigh, calcCandleLow, totalFees } from '../utils';
import {
calcCandleHigh,
calcCandleLow,
totalFees,
} from '@vegaprotocol/market-list';
import type { CandleClose } from '@vegaprotocol/types';
import type { MarketWithData, MarketWithCandles } from '../';
import type {
MarketWithData,
MarketWithCandles,
} from '@vegaprotocol/market-list';
import isNil from 'lodash/isNil';
type Market = MarketWithData & MarketWithCandles;

View File

@ -1,10 +1,11 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { AuctionTrigger, MarketTradingMode } from '@vegaprotocol/types';
import type { ReactNode } from 'react';
import type { MarketWithCandles, MarketWithData } from '../markets-provider';
import type { MarketData } from '../market-data-provider';
import type {
MarketWithCandles,
MarketWithData,
MarketData,
} from '@vegaprotocol/market-list';
import {
SelectAllMarketsTableBody,
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 {
Dialog,
@ -7,17 +9,11 @@ import {
Link,
Popover,
} from '@vegaprotocol/ui-toolkit';
import type { ReactNode } from 'react';
import { useMemo, useState } from 'react';
import type { Column, OnCellClickHandler } from './select-market-columns';
import {
columnHeadersPositionMarkets,
columnsPositionMarkets,
} from './select-market-columns';
import { columnHeaders } from './select-market-columns';
import { columns } from './select-market-columns';
import type { MarketWithCandles, MarketWithData } from '../';
import { useMarketList } from '@vegaprotocol/market-list';
import type {
MarketWithCandles,
MarketWithData,
} from '@vegaprotocol/market-list';
import { useVegaWallet } from '@vegaprotocol/wallet';
import type { Positions_party_positionsConnection_edges_node } from '@vegaprotocol/positions';
import { positionsDataProvider } from '@vegaprotocol/positions';
@ -25,7 +21,13 @@ import {
SelectMarketTableHeader,
SelectMarketTableRow,
} 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;

View File

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

View File

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

View File

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

View File

@ -3,16 +3,9 @@ fragment AccountFields on Account {
balance
market {
id
tradableInstrument {
instrument {
name
}
}
}
asset {
id
symbol
decimals
}
}
@ -33,3 +26,22 @@ subscription AccountEvents($partyId: ID!) {
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 * as Apollo from '@apollo/client';
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<{
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<{
partyId: Types.Scalars['ID'];
@ -19,23 +19,33 @@ 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 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`
fragment AccountFields on Account {
type
balance
market {
id
tradableInstrument {
instrument {
name
}
}
}
asset {
id
}
}
`;
export const AssetsFieldsFragmentDoc = gql`
fragment AssetsFields on Asset {
id
name
symbol
decimals
}
quantum
status
}
`;
export const AccountsDocument = gql`
@ -109,3 +119,41 @@ export function useAccountEventsSubscription(baseOptions: Apollo.SubscriptionHoo
}
export type AccountEventsSubscriptionHookResult = ReturnType<typeof useAccountEventsSubscription>;
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 * as Apollo from '@apollo/client';
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<{
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<{
partyId: Types.Scalars['ID'];
@ -19,23 +19,33 @@ 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 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`
fragment AccountFields on Account {
type
balance
market {
id
tradableInstrument {
instrument {
name
}
}
}
asset {
id
}
}
`;
export const AssetsFieldsFragmentDoc = gql`
fragment AssetsFields on Asset {
id
name
symbol
decimals
}
quantum
status
}
`;
export const AccountsDocument = gql`
@ -109,3 +119,41 @@ export function useAccountEventsSubscription(baseOptions: Apollo.SubscriptionHoo
}
export type AccountEventsSubscriptionHookResult = ReturnType<typeof useAccountEventsSubscription>;
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 type { AccountFields } from './accounts-data-provider';
import type { AccountFields, Account } from './accounts-data-provider';
import { getAccountData } from './accounts-data-provider';
import type { AccountFieldsFragment } from './__generated___/Accounts';
describe('getAccountData', () => {
it('should return the correct aggregated data', () => {
@ -10,7 +9,7 @@ describe('getAccountData', () => {
});
});
const accounts: AccountFieldsFragment[] = [
const accounts = [
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_MARGIN,
@ -115,9 +114,9 @@ const accounts: AccountFieldsFragment[] = [
decimals: 5,
},
},
];
] as Account[];
const accountResult: AccountFields[] = [
const accountResult = [
{
asset: {
__typename: 'Asset',
@ -240,4 +239,4 @@ const accountResult: AccountFields[] = [
type: AccountType.ACCOUNT_TYPE_GENERAL,
used: '0',
},
];
] as AccountFields[];

View File

@ -8,12 +8,16 @@ import type {
AccountFieldsFragment,
AccountsQuery,
AccountEventsSubscription,
AssetsFieldsFragment,
} from './__generated___/Accounts';
import {
makeDataProvider,
makeDerivedDataProvider,
} from '@vegaprotocol/react-helpers';
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(
account:
@ -35,6 +39,11 @@ export const getId = (
? `${account.type}-${account.asset.id}-${account.market?.id ?? 'null'}`
: `${account.type}-${account.assetId}-${account.marketId}`;
export type Account = Omit<AccountFieldsFragment, 'market' | 'asset'> & {
market?: Market | null;
asset: AssetsFieldsFragment;
};
const update = (
data: AccountFieldsFragment[],
deltas: AccountEventsSubscription['accounts']
@ -46,7 +55,13 @@ const update = (
if (index !== -1) {
draft[index].balance = delta.balance;
} 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
): AccountEventsSubscription['accounts'] => subscriptionData.accounts;
export const accountsDataProvider = makeDataProvider<
export const accountsBasedDataProvider = makeDataProvider<
AccountsQuery,
AccountFieldsFragment[],
AccountEventsSubscription,
@ -75,7 +90,7 @@ export const accountsDataProvider = makeDataProvider<
getDelta,
});
export interface AccountFields extends AccountFieldsFragment {
export interface AccountFields extends Account {
available: string;
used: string;
deposited: string;
@ -92,15 +107,13 @@ const USE_ACCOUNT_TYPES = [
AccountType.ACCOUNT_TYPE_PENDING_TRANSFERS,
];
const getAssetIds = (data: AccountFieldsFragment[]) =>
const getAssetIds = (data: Account[]) =>
Array.from(new Set(data.map((a) => a.asset.id))).sort();
const getTotalBalance = (accounts: AccountFieldsFragment[]) =>
accounts.reduce((acc, a) => acc + BigInt(a.balance), BigInt(0));
export const getAccountData = (
data: AccountFieldsFragment[]
): AccountFields[] => {
export const getAccountData = (data: Account[]): AccountFields[] => {
return getAssetIds(data).map((assetId) => {
const accounts = data.filter((a) => a.asset.id === assetId);
return accounts && getAssetAccountAggregation(accounts, assetId);
@ -108,7 +121,7 @@ export const getAccountData = (
};
const getAssetAccountAggregation = (
accountList: AccountFieldsFragment[],
accountList: Account[],
assetId: string
): AccountFields => {
const accounts = accountList.filter((a) => a.asset.id === assetId);
@ -141,10 +154,42 @@ const getAssetAccountAggregation = (
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<
AccountFields[],
never
>(
[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 { AccountTable } from './accounts-table';
const singleRow: AccountFields = {
const singleRow = {
__typename: 'Account',
type: Types.AccountType.ACCOUNT_TYPE_MARGIN,
balance: '125600000',
@ -28,7 +28,7 @@ const singleRow: AccountFields = {
available: '125600000',
used: '125600000',
deposited: '125600000',
};
} as AccountFields;
const singleRowData = [singleRow];
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 { getAccountData } from './accounts-data-provider';
const singleRow: AccountFields = {
const singleRow = {
__typename: 'Account',
type: Types.AccountType.ACCOUNT_TYPE_MARGIN,
balance: '125600000',
@ -28,7 +28,7 @@ const singleRow: AccountFields = {
available: '125600000',
used: '125600000',
deposited: '125600000',
};
} as AccountFields;
const singleRowData = [singleRow];
describe('BreakdownTable', () => {

View File

@ -1,4 +1 @@
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__/Margins';
export * from './lib/__generated__/PositionsSubscription';
export * from './lib/__generated__/MarginsSubscription';
export * from './lib/positions-container';
export * from './lib/positions-data-providers';
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
// This file was automatically generated and should not be edited.
import { MarketTradingMode } from "@vegaprotocol/types";
// ====================================================
// 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 {
__typename: "Market";
/**
* Market ID
*/
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 {
@ -169,10 +37,6 @@ export interface PositionFields {
* RFC3339Nano time the position was updated
*/
updatedAt: string | null;
/**
* Margins of the party for the given position
*/
marginsConnection: PositionFields_marginsConnection | null;
/**
* Market relating to this position
*/

View File

@ -3,148 +3,16 @@
// @generated
// This file was automatically generated and should not be edited.
import { MarketTradingMode } from "@vegaprotocol/types";
// ====================================================
// 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 {
__typename: "Market";
/**
* Market ID
*/
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 {
@ -169,10 +37,6 @@ export interface Positions_party_positionsConnection_edges_node {
* RFC3339Nano time the position was updated
*/
updatedAt: string | null;
/**
* Margins of the party for the given position
*/
marginsConnection: Positions_party_positionsConnection_edges_node_marginsConnection | null;
/**
* 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,13 +1,11 @@
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 { 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 = {
party: {
__typename: 'Party',
id: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65',
accounts: [
const accounts = [
{
__typename: 'Account',
type: AccountType.ACCOUNT_TYPE_GENERAL,
@ -64,11 +62,9 @@ const accounts: AccountsQuery = {
},
},
},
],
},
};
] as Account[];
const data: Positions = {
const positions: Positions = {
party: {
__typename: 'Party',
id: '02eceaba4df2bef76ea10caf728d8a099a2aa846cced25737cccaa9812342f65',
@ -84,51 +80,10 @@ const data: Positions = {
updatedAt: '2022-07-28T14:53:54.725477Z',
realisedPNL: '0',
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: {
__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)',
},
},
data: {
__typename: 'MarketData',
markPrice: '9431775',
market: {
__typename: 'Market',
id: '5e6035fe6a6df78c9ec44b333c231e63d357acef0a0620d2c243f5865d1dc0d8',
},
},
},
},
},
{
@ -140,9 +95,97 @@ const data: Positions = {
unrealisedPNL: '-9112700',
averageEntryPrice: '840158',
updatedAt: '2022-07-28T15:09:34.441143Z',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
},
},
},
],
},
},
};
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: {
__typename: 'MarginConnection',
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: {
@ -157,49 +200,35 @@ const data: Positions = {
},
asset: {
__typename: 'Asset',
symbol: 'tDAI',
},
},
},
],
},
market: {
__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)',
},
},
data: {
__typename: 'MarketData',
markPrice: '869762',
market: {
__typename: 'Market',
id: '10c4b1114d2f6fda239b73d018bca55888b6018f0ac70029972a17fea0a6a56e',
},
},
id: 'tDAI-id',
},
},
},
],
__typename: 'MarginConnection',
},
__typename: 'Party',
},
};
describe('getMetrics', () => {
describe('getMetrics && rejoinPositionData', () => {
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);
});
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].averageEntryPrice).toEqual('8993727');

View File

@ -2,10 +2,14 @@ import { gql } from '@apollo/client';
import produce from 'immer';
import BigNumber from 'bignumber.js';
import sortBy from 'lodash/sortBy';
import type { AccountFieldsFragment } from '@vegaprotocol/accounts';
import type { Account } from '@vegaprotocol/accounts';
import { accountsDataProvider } from '@vegaprotocol/accounts';
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 {
makeDataProvider,
makeDerivedDataProvider,
@ -18,6 +22,28 @@ import type {
import { AccountType } 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 {
marketName: string;
@ -54,39 +80,9 @@ const POSITION_FIELDS = gql`
unrealisedPNL
averageEntryPrice
updatedAt
marginsConnection {
edges {
node {
market {
id
}
maintenanceLevel
searchLevel
initialLevel
collateralReleaseLevel
asset {
symbol
}
}
}
}
market {
id
decimalPlaces
positionDecimalPlaces
tradingMode
tradableInstrument {
instrument {
name
}
}
data {
markPrice
market {
id
}
}
}
}
`;
@ -120,27 +116,26 @@ export const POSITIONS_SUBSCRIPTION = gql`
`;
export const getMetrics = (
data: Positions_party | null,
accounts: AccountFieldsFragment[] | null
data: PositionRejoined[] | null,
accounts: Account[] | null
): Position[] => {
if (!data || !data?.positionsConnection?.edges) {
if (!data || !data?.length) {
return [];
}
const metrics: Position[] = [];
data?.positionsConnection.edges.forEach((position) => {
const market = position.node.market;
const marketData = market.data;
const marginLevel = position.node.marginsConnection?.edges?.find(
(margin) => margin.node.market.id === market.id
)?.node;
data.forEach((position) => {
const market = position.market;
const marketData = market?.data;
const marginLevel = position.margins;
const marginAccount = accounts?.find((account) => {
return account.market?.id === market.id;
return account.market?.id === market?.id;
});
if (
!marginAccount ||
!marginLevel ||
!market ||
!marketData ||
position.node.openVolume === '0'
position.openVolume === '0'
) {
return;
}
@ -152,10 +147,7 @@ export const getMetrics = (
const decimals = marginAccount.asset.decimals;
const { positionDecimalPlaces, decimalPlaces: marketDecimalPlaces } =
market;
const openVolume = toBigNum(
position.node.openVolume,
positionDecimalPlaces
);
const openVolume = toBigNum(position.openVolume, positionDecimalPlaces);
const marginAccountBalance = toBigNum(marginAccount.balance ?? 0, decimals);
const generalAccountBalance = toBigNum(
@ -206,29 +198,30 @@ export const getMetrics = (
metrics.push({
marketName: market.tradableInstrument.instrument.name,
averageEntryPrice: position.node.averageEntryPrice,
averageEntryPrice: position.averageEntryPrice,
capitalUtilisation: Math.round(capitalUtilisation.toNumber()),
currentLeverage: currentLeverage.toNumber(),
marketDecimalPlaces,
positionDecimalPlaces,
decimals,
assetSymbol: marginLevel.asset.symbol,
assetSymbol:
market.tradableInstrument.instrument.product.settlementAsset.symbol,
totalBalance: totalBalance.multipliedBy(10 ** decimals).toFixed(),
lowMarginLevel,
liquidationPrice: liquidationPrice
.multipliedBy(10 ** marketDecimalPlaces)
.toFixed(0),
marketId: position.node.market.id,
marketTradingMode: position.node.market.tradingMode,
marketId: market.id,
marketTradingMode: market.tradingMode,
markPrice: marketData.markPrice,
notional: notional.multipliedBy(10 ** marketDecimalPlaces).toFixed(0),
openVolume: position.node.openVolume,
realisedPNL: position.node.realisedPNL,
unrealisedPNL: position.node.unrealisedPNL,
openVolume: position.openVolume,
realisedPNL: position.realisedPNL,
unrealisedPNL: position.unrealisedPNL,
searchPrice: searchPrice
.multipliedBy(10 ** marketDecimalPlaces)
.toFixed(0),
updatedAt: position.node.updatedAt,
updatedAt: position.updatedAt,
});
});
return metrics;
@ -257,7 +250,17 @@ export const update = (
updatedAt: delta.updatedAt,
};
} 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,
});
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<
Position[],
never
>([positionsDataProvider, accountsDataProvider], ([positions, accounts]) => {
>(
[
positionsDataProvider,
accountsDataProvider,
marketsWithDataProvider,
marginsDataProvider,
],
([positions, accounts, marketsData, margins]) => {
const positionsData = rejoinPositionData(positions, marketsData, margins);
return sortBy(
getMetrics(
positions as Positions_party | null,
accounts as AccountFieldsFragment[] | null
),
getMetrics(positionsData, accounts as Account[] | null),
'updatedAt'
).reverse();
});
}
);