|
|
@ -1,4 +1,5 @@ |
|
|
|
import { AccountService } from '@ghostfolio/api/app/account/account.service'; |
|
|
|
import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface'; |
|
|
|
import { CurrentRateService } from '@ghostfolio/api/app/core/current-rate.service'; |
|
|
|
import { PortfolioOrder } from '@ghostfolio/api/app/core/interfaces/portfolio-order.interface'; |
|
|
|
import { TimelineSpecification } from '@ghostfolio/api/app/core/interfaces/timeline-specification.interface'; |
|
|
@ -17,10 +18,11 @@ import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee |
|
|
|
import { DataProviderService } from '@ghostfolio/api/services/data-provider.service'; |
|
|
|
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; |
|
|
|
import { ImpersonationService } from '@ghostfolio/api/services/impersonation.service'; |
|
|
|
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces'; |
|
|
|
import { EnhancedSymbolProfile } from '@ghostfolio/api/services/interfaces/symbol-profile.interface'; |
|
|
|
import { RulesService } from '@ghostfolio/api/services/rules.service'; |
|
|
|
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service'; |
|
|
|
import { UNKNOWN_KEY } from '@ghostfolio/common/config'; |
|
|
|
import { UNKNOWN_KEY, ghostfolioCashSymbol } from '@ghostfolio/common/config'; |
|
|
|
import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper'; |
|
|
|
import { |
|
|
|
PortfolioOverview, |
|
|
@ -38,7 +40,12 @@ import { |
|
|
|
} from '@ghostfolio/common/types'; |
|
|
|
import { Inject, Injectable } from '@nestjs/common'; |
|
|
|
import { REQUEST } from '@nestjs/core'; |
|
|
|
import { Currency, DataSource, Type as TypeOfOrder } from '@prisma/client'; |
|
|
|
import { |
|
|
|
AssetClass, |
|
|
|
Currency, |
|
|
|
DataSource, |
|
|
|
Type as TypeOfOrder |
|
|
|
} from '@prisma/client'; |
|
|
|
import Big from 'big.js'; |
|
|
|
import { |
|
|
|
endOfToday, |
|
|
@ -201,8 +208,16 @@ export class PortfolioService { |
|
|
|
throw new Error('Missing information'); |
|
|
|
} |
|
|
|
|
|
|
|
const cashDetails = await this.accountService.getCashDetails( |
|
|
|
userId, |
|
|
|
userCurrency |
|
|
|
); |
|
|
|
|
|
|
|
const result: { [symbol: string]: PortfolioPosition } = {}; |
|
|
|
const totalValue = currentPositions.currentValue; |
|
|
|
const totalInvestment = currentPositions.totalInvestment.plus( |
|
|
|
cashDetails.balance |
|
|
|
); |
|
|
|
const totalValue = currentPositions.currentValue.plus(cashDetails.balance); |
|
|
|
|
|
|
|
const symbols = currentPositions.positions.map( |
|
|
|
(position) => position.symbol |
|
|
@ -231,9 +246,7 @@ export class PortfolioService { |
|
|
|
result[item.symbol] = { |
|
|
|
accounts, |
|
|
|
allocationCurrent: value.div(totalValue).toNumber(), |
|
|
|
allocationInvestment: item.investment |
|
|
|
.div(currentPositions.totalInvestment) |
|
|
|
.toNumber(), |
|
|
|
allocationInvestment: item.investment.div(totalInvestment).toNumber(), |
|
|
|
assetClass: symbolProfile.assetClass, |
|
|
|
countries: symbolProfile.countries, |
|
|
|
currency: item.currency, |
|
|
@ -252,6 +265,13 @@ export class PortfolioService { |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: Add a cash position for each currency
|
|
|
|
result[ghostfolioCashSymbol] = await this.getCashPosition({ |
|
|
|
cashDetails, |
|
|
|
investment: totalInvestment, |
|
|
|
value: totalValue |
|
|
|
}); |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
@ -660,6 +680,46 @@ export class PortfolioService { |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
private async getCashPosition({ |
|
|
|
cashDetails, |
|
|
|
investment, |
|
|
|
value |
|
|
|
}: { |
|
|
|
cashDetails: CashDetails; |
|
|
|
investment: Big; |
|
|
|
value: Big; |
|
|
|
}) { |
|
|
|
const accounts = {}; |
|
|
|
const cashValue = new Big(cashDetails.balance); |
|
|
|
|
|
|
|
cashDetails.accounts.forEach((account) => { |
|
|
|
accounts[account.name] = { |
|
|
|
current: account.balance, |
|
|
|
original: account.balance |
|
|
|
}; |
|
|
|
}); |
|
|
|
|
|
|
|
return { |
|
|
|
accounts, |
|
|
|
allocationCurrent: cashValue.div(value).toNumber(), |
|
|
|
allocationInvestment: cashValue.div(investment).toNumber(), |
|
|
|
assetClass: AssetClass.CASH, |
|
|
|
countries: [], |
|
|
|
currency: Currency.CHF, |
|
|
|
grossPerformance: 0, |
|
|
|
grossPerformancePercent: 0, |
|
|
|
investment: cashValue.toNumber(), |
|
|
|
marketPrice: 0, |
|
|
|
marketState: MarketState.open, |
|
|
|
name: 'Cash', |
|
|
|
quantity: 0, |
|
|
|
sectors: [], |
|
|
|
symbol: ghostfolioCashSymbol, |
|
|
|
transactionCount: 0, |
|
|
|
value: cashValue.toNumber() |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
private getStartDate(aDateRange: DateRange, portfolioStart: Date) { |
|
|
|
switch (aDateRange) { |
|
|
|
case '1d': |
|
|
|