diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index d8a5c8870..08dc44f6b 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -29,16 +29,18 @@ import { } from '@ghostfolio/common/types'; import { Inject, Injectable } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; -import { DataSource } from '@prisma/client'; +import { DataSource, Currency, Type as TypeOfOrder } from '@prisma/client'; import Big from 'big.js'; import { add, addMonths, + endOfToday, format, getDate, getMonth, getYear, isAfter, + isBefore, isSameDay, max, parse, @@ -204,30 +206,25 @@ export class PortfolioService { public async getOverview( aImpersonationId: string ): Promise { - const impersonationUserId = - await this.impersonationService.validateImpersonationId( - aImpersonationId, - this.request.user.id - ); - - const portfolio = await this.createPortfolio( - impersonationUserId || this.request.user.id - ); + const userId = await this.getUserId(aImpersonationId); + const currency = this.request.user.Settings.currency; const { balance } = await this.accountService.getCashDetails( - impersonationUserId || this.request.user.id, - this.request.user.Settings.currency + userId, + currency ); - const committedFunds = portfolio.getCommittedFunds(); - const fees = portfolio.getFees(); + const orders = await this.getOrders(userId); + const fees = this.getFees(orders); + const totalBuy = this.getTotalByType(orders, currency, TypeOfOrder.BUY); + const totalSell = this.getTotalByType(orders, currency, TypeOfOrder.SELL); return { - committedFunds, + committedFunds: totalBuy - totalSell, fees, cash: balance, - ordersCount: portfolio.getOrders().length, - totalBuy: portfolio.getTotalBuy(), - totalSell: portfolio.getTotalSell() + ordersCount: orders.length, + totalBuy: totalBuy, + totalSell: totalSell }; } @@ -586,6 +583,22 @@ export class PortfolioService { }; } + public getFees(orders: OrderWithAccount[], date = new Date(0)) { + return orders + .filter((order) => { + // Filter out all orders before given date + return isBefore(date, new Date(order.date)); + }) + .map((order) => { + return this.exchangeRateDataService.toCurrency( + order.fee, + order.currency, + this.request.user.Settings.currency + ); + }) + .reduce((previous, current) => previous + current, 0); + } + private getStartDate(aDateRange: DateRange, portfolioStart: Date) { switch (aDateRange) { case '1d': @@ -742,4 +755,23 @@ export class PortfolioService { return impersonationUserId || this.request.user.id; } + + private getTotalByType( + orders: OrderWithAccount[], + currency: Currency, + type: TypeOfOrder + ) { + return orders + .filter( + (order) => !isAfter(order.date, endOfToday()) && order.type === type + ) + .map((order) => { + return this.exchangeRateDataService.toCurrency( + order.quantity * order.unitPrice, + order.currency, + currency + ); + }) + .reduce((previous, current) => previous + current, 0); + } } diff --git a/apps/api/src/models/interfaces/portfolio.interface.ts b/apps/api/src/models/interfaces/portfolio.interface.ts index 9e958272c..b369202cd 100644 --- a/apps/api/src/models/interfaces/portfolio.interface.ts +++ b/apps/api/src/models/interfaces/portfolio.interface.ts @@ -5,13 +5,9 @@ import { Order } from '../order'; export interface PortfolioInterface { get(aDate?: Date): PortfolioItem[]; - getCommittedFunds(): number; - getFees(): number; - getPositions( - aDate: Date - ): { + getPositions(aDate: Date): { [symbol: string]: Position; }; diff --git a/apps/api/src/models/portfolio.spec.ts b/apps/api/src/models/portfolio.spec.ts index 5e3b34f7b..45d5932aa 100644 --- a/apps/api/src/models/portfolio.spec.ts +++ b/apps/api/src/models/portfolio.spec.ts @@ -232,14 +232,6 @@ describe('Portfolio', () => { } ]); - expect(portfolio.getCommittedFunds()).toEqual( - exchangeRateDataService.toCurrency( - 1 * 49631.24, - Currency.USD, - baseCurrency - ) - ); - const details = await portfolio.getDetails('1d'); expect(details).toMatchObject({ BTCUSD: { @@ -311,14 +303,6 @@ describe('Portfolio', () => { } ]); - expect(portfolio.getCommittedFunds()).toEqual( - exchangeRateDataService.toCurrency( - 0.2 * 991.49, - Currency.USD, - baseCurrency - ) - ); - expect(portfolio.getFees()).toEqual(0); expect(portfolio.getPositions(getYesterday())).toMatchObject({ @@ -378,19 +362,6 @@ describe('Portfolio', () => { } ]); - expect(portfolio.getCommittedFunds()).toEqual( - exchangeRateDataService.toCurrency( - 0.2 * 991.49, - Currency.USD, - baseCurrency - ) + - exchangeRateDataService.toCurrency( - 0.3 * 1050, - Currency.USD, - baseCurrency - ) - ); - expect(portfolio.getFees()).toEqual(0); expect(portfolio.getPositions(getYesterday())).toMatchObject({ @@ -456,19 +427,6 @@ describe('Portfolio', () => { } ]); - expect(portfolio.getCommittedFunds()).toEqual( - exchangeRateDataService.toCurrency( - 0.05614682 * 3562.089535970158, - Currency.EUR, - baseCurrency - ) + - exchangeRateDataService.toCurrency( - 0.2 * 991.49, - Currency.USD, - baseCurrency - ) - ); - expect(portfolio.getFees()).toEqual( exchangeRateDataService.toCurrency(2.99, Currency.EUR, baseCurrency) + exchangeRateDataService.toCurrency(2.99, Currency.USD, baseCurrency) @@ -564,24 +522,6 @@ describe('Portfolio', () => { } ]); - expect(portfolio.getCommittedFunds()).toEqual( - exchangeRateDataService.toCurrency( - 0.2 * 991.49, - Currency.USD, - baseCurrency - ) - - exchangeRateDataService.toCurrency( - 0.1 * 1050, - Currency.USD, - baseCurrency - ) + - exchangeRateDataService.toCurrency( - 0.2 * 1050, - Currency.USD, - baseCurrency - ) - ); - expect(portfolio.getFees()).toEqual( exchangeRateDataService.toCurrency(3, Currency.USD, baseCurrency) ); diff --git a/apps/api/src/models/portfolio.ts b/apps/api/src/models/portfolio.ts index b03a9b829..7b75622bc 100644 --- a/apps/api/src/models/portfolio.ts +++ b/apps/api/src/models/portfolio.ts @@ -225,10 +225,6 @@ export class Portfolio implements PortfolioInterface { return cloneDeep(this.portfolioItems); } - public getCommittedFunds() { - return this.getTotalBuy() - this.getTotalSell(); - } - public async getDetails( aDateRange: DateRange = 'max' ): Promise<{ [symbol: string]: PortfolioPosition }> {