Respect cash balance in allocations, do not hide cryptocurrency holdings (#280)
* Respect cash balance in allocations, do not hide cryptocurrency holdings * Update changelog
This commit is contained in:
parent
4ad5590838
commit
0a85a56c67
@ -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…
x
Reference in New Issue
Block a user