Respect cash balance in allocations, do not hide cryptocurrency holdings (#280)

* Respect cash balance in allocations, do not hide cryptocurrency holdings

* Update changelog
pull/277/head
Thomas 3 years ago committed by GitHub
parent 4ad5590838
commit 0a85a56c67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -10,6 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Improved the data gathering handling on server restart
- Respected the cash balance on the allocations page
### Fixed
- Fixed hidden cryptocurrency holdings
## 1.35.0 - 08.08.2021

@ -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':

@ -7,7 +7,6 @@ import {
} from '@angular/core';
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
import { Position } from '@ghostfolio/common/interfaces';
import { AssetClass } from '@prisma/client';
@Component({
selector: 'gf-positions',
@ -26,8 +25,6 @@ export class PositionsComponent implements OnChanges, OnInit {
public positionsRest: Position[] = [];
public positionsWithPriority: Position[] = [];
private ignoreAssetClasses = [AssetClass.CASH.toString()];
public constructor() {}
public ngOnInit() {}
@ -44,10 +41,6 @@ export class PositionsComponent implements OnChanges, OnInit {
this.positionsWithPriority = [];
for (const portfolioPosition of this.positions) {
if (this.ignoreAssetClasses.includes(portfolioPosition.assetClass)) {
continue;
}
if (
portfolioPosition.marketState === MarketState.open ||
this.range !== '1d'

Loading…
Cancel
Save