feat: expose broker position counts
This commit is contained in:
parent
da6d05e425
commit
8aea56cbbf
@ -42,10 +42,27 @@ export class BrokerPortfolioYieldsDto {
|
||||
dailyPercent!: number | null;
|
||||
}
|
||||
|
||||
export class BrokerPortfolioPositionCountsDto {
|
||||
@ApiProperty({ minimum: 0 })
|
||||
shares!: number;
|
||||
|
||||
@ApiProperty({ minimum: 0 })
|
||||
bonds!: number;
|
||||
|
||||
@ApiProperty({ minimum: 0 })
|
||||
etf!: number;
|
||||
|
||||
@ApiProperty({ minimum: 0 })
|
||||
other!: number;
|
||||
}
|
||||
|
||||
export class BrokerPortfolioResponseDto {
|
||||
@ApiProperty({ type: BrokerAccountResponseDto })
|
||||
account!: BrokerAccountResponseDto;
|
||||
|
||||
@ApiProperty({ type: BrokerPortfolioPositionCountsDto })
|
||||
positionCounts!: BrokerPortfolioPositionCountsDto;
|
||||
|
||||
@ApiProperty({ type: BrokerPortfolioTotalsDto })
|
||||
totals!: BrokerPortfolioTotalsDto;
|
||||
|
||||
|
||||
@ -30,6 +30,12 @@ describe('portfolio.mapper', () => {
|
||||
currentPrice: { currency: 'rub', units: '250', nano: 0 },
|
||||
averagePositionPrice: { currency: 'rub', units: '200', nano: 0 },
|
||||
},
|
||||
{ instrumentType: 'SHARE' },
|
||||
{ instrumentType: 'bond' },
|
||||
{ instrumentType: 'etf' },
|
||||
{ instrumentType: 'fund' },
|
||||
{ instrumentType: 'future' },
|
||||
{},
|
||||
],
|
||||
},
|
||||
positions: {
|
||||
@ -43,5 +49,6 @@ describe('portfolio.mapper', () => {
|
||||
expect(result.totals.shares?.value).toBe(1000);
|
||||
expect(result.cash[0].value).toBe(500);
|
||||
expect(result.blockedCash[0].value).toBe(10);
|
||||
expect(result.positionCounts).toEqual({ shares: 2, bonds: 1, etf: 2, other: 2 });
|
||||
});
|
||||
});
|
||||
|
||||
@ -74,8 +74,28 @@ export function mapBrokerPosition(input: {
|
||||
}
|
||||
|
||||
export function mapBrokerPortfolio(input: MapBrokerPortfolioInput): BrokerPortfolio {
|
||||
const positionCounts = { shares: 0, bonds: 0, etf: 0, other: 0 };
|
||||
|
||||
for (const position of input.portfolio.positions ?? []) {
|
||||
switch (position.instrumentType?.toLowerCase()) {
|
||||
case 'share':
|
||||
positionCounts.shares += 1;
|
||||
break;
|
||||
case 'bond':
|
||||
positionCounts.bonds += 1;
|
||||
break;
|
||||
case 'etf':
|
||||
case 'fund':
|
||||
positionCounts.etf += 1;
|
||||
break;
|
||||
default:
|
||||
positionCounts.other += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
account: input.account,
|
||||
positionCounts,
|
||||
totals: {
|
||||
shares: mapMoneyValue(input.portfolio.totalAmountShares),
|
||||
bonds: mapMoneyValue(input.portfolio.totalAmountBonds),
|
||||
|
||||
@ -46,7 +46,7 @@ describe('BrokerPortfolioService', () => {
|
||||
.mockResolvedValueOnce({
|
||||
accountId: 'acc-1',
|
||||
totalAmountPortfolio: { currency: 'rub', units: '1000', nano: 0 },
|
||||
positions: [],
|
||||
positions: [{ instrumentType: 'share' }, { instrumentType: 'bond' }],
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
accountId: 'acc-1',
|
||||
@ -60,7 +60,9 @@ describe('BrokerPortfolioService', () => {
|
||||
|
||||
expect(result.data.account.id).toBe('acc-1');
|
||||
expect(result.data.cash[0].value).toBe(1000);
|
||||
expect(result.data.positionCounts).toEqual({ shares: 1, bonds: 1, etf: 0, other: 0 });
|
||||
expect('positions' in result.data).toBe(false);
|
||||
expect(client.callUnary).toHaveBeenCalledTimes(2);
|
||||
expect(cache.getOrFetch).toHaveBeenCalledWith(
|
||||
'tbank:portfolio',
|
||||
['acc-1'],
|
||||
|
||||
@ -33,6 +33,12 @@ export type BrokerPosition = {
|
||||
|
||||
export type BrokerPortfolio = {
|
||||
account: BrokerAccount;
|
||||
positionCounts: {
|
||||
shares: number;
|
||||
bonds: number;
|
||||
etf: number;
|
||||
other: number;
|
||||
};
|
||||
totals: {
|
||||
shares: BrokerMoney | null;
|
||||
bonds: BrokerMoney | null;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user