parent
ffb11cd10e
commit
4c893c4dcc
@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed the public page
|
||||||
- Improved the loading indicator of the portfolio evolution chart
|
- Improved the loading indicator of the portfolio evolution chart
|
||||||
|
|
||||||
## 1.206.2 - 20.10.2022
|
## 1.206.2 - 20.10.2022
|
||||||
|
@ -10,7 +10,6 @@ import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interc
|
|||||||
import { ApiService } from '@ghostfolio/api/services/api/api.service';
|
import { ApiService } from '@ghostfolio/api/services/api/api.service';
|
||||||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
||||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
|
||||||
import { parseDate } from '@ghostfolio/common/helper';
|
|
||||||
import {
|
import {
|
||||||
PortfolioDetails,
|
PortfolioDetails,
|
||||||
PortfolioInvestments,
|
PortfolioInvestments,
|
||||||
@ -240,7 +239,8 @@ export class PortfolioController {
|
|||||||
): Promise<PortfolioPerformanceResponse> {
|
): Promise<PortfolioPerformanceResponse> {
|
||||||
const performanceInformation = await this.portfolioService.getPerformance({
|
const performanceInformation = await this.portfolioService.getPerformance({
|
||||||
dateRange,
|
dateRange,
|
||||||
impersonationId
|
impersonationId,
|
||||||
|
userId: this.request.user.id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -331,7 +331,7 @@ export class PortfolioController {
|
|||||||
dateRange: 'max',
|
dateRange: 'max',
|
||||||
filters: [{ id: 'EQUITY', type: 'ASSET_CLASS' }],
|
filters: [{ id: 'EQUITY', type: 'ASSET_CLASS' }],
|
||||||
impersonationId: access.userId,
|
impersonationId: access.userId,
|
||||||
userId: access.userId
|
userId: user.id
|
||||||
});
|
});
|
||||||
|
|
||||||
const portfolioPublicDetails: PortfolioPublicDetails = {
|
const portfolioPublicDetails: PortfolioPublicDetails = {
|
||||||
|
@ -3,7 +3,6 @@ import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details
|
|||||||
import { OrderService } from '@ghostfolio/api/app/order/order.service';
|
import { OrderService } from '@ghostfolio/api/app/order/order.service';
|
||||||
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
|
||||||
import { PortfolioOrder } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-order.interface';
|
import { PortfolioOrder } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-order.interface';
|
||||||
import { TimelineSpecification } from '@ghostfolio/api/app/portfolio/interfaces/timeline-specification.interface';
|
|
||||||
import { TransactionPoint } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point.interface';
|
import { TransactionPoint } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point.interface';
|
||||||
import { UserService } from '@ghostfolio/api/app/user/user.service';
|
import { UserService } from '@ghostfolio/api/app/user/user.service';
|
||||||
import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment';
|
import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment';
|
||||||
@ -36,7 +35,8 @@ import {
|
|||||||
PortfolioSummary,
|
PortfolioSummary,
|
||||||
Position,
|
Position,
|
||||||
TimelinePosition,
|
TimelinePosition,
|
||||||
UserSettings
|
UserSettings,
|
||||||
|
UserWithSettings
|
||||||
} from '@ghostfolio/common/interfaces';
|
} from '@ghostfolio/common/interfaces';
|
||||||
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
|
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
|
||||||
import type {
|
import type {
|
||||||
@ -67,11 +67,9 @@ import {
|
|||||||
isAfter,
|
isAfter,
|
||||||
isBefore,
|
isBefore,
|
||||||
max,
|
max,
|
||||||
parse,
|
|
||||||
parseISO,
|
parseISO,
|
||||||
set,
|
set,
|
||||||
setDayOfYear,
|
setDayOfYear,
|
||||||
startOfDay,
|
|
||||||
subDays,
|
subDays,
|
||||||
subYears
|
subYears
|
||||||
} from 'date-fns';
|
} from 'date-fns';
|
||||||
@ -130,9 +128,9 @@ export class PortfolioService {
|
|||||||
}),
|
}),
|
||||||
this.getDetails({
|
this.getDetails({
|
||||||
filters,
|
filters,
|
||||||
userId,
|
|
||||||
withExcludedAccounts,
|
withExcludedAccounts,
|
||||||
impersonationId: userId
|
impersonationId: userId,
|
||||||
|
userId: this.request.user.id
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -304,12 +302,16 @@ export class PortfolioService {
|
|||||||
|
|
||||||
public async getChart({
|
public async getChart({
|
||||||
dateRange = 'max',
|
dateRange = 'max',
|
||||||
impersonationId
|
impersonationId,
|
||||||
|
userCurrency,
|
||||||
|
userId
|
||||||
}: {
|
}: {
|
||||||
dateRange?: DateRange;
|
dateRange?: DateRange;
|
||||||
impersonationId: string;
|
impersonationId: string;
|
||||||
|
userCurrency: string;
|
||||||
|
userId: string;
|
||||||
}): Promise<HistoricalDataContainer> {
|
}): Promise<HistoricalDataContainer> {
|
||||||
const userId = await this.getUserId(impersonationId, this.request.user.id);
|
userId = await this.getUserId(impersonationId, userId);
|
||||||
|
|
||||||
const { portfolioOrders, transactionPoints } =
|
const { portfolioOrders, transactionPoints } =
|
||||||
await this.getTransactionPoints({
|
await this.getTransactionPoints({
|
||||||
@ -317,7 +319,7 @@ export class PortfolioService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const portfolioCalculator = new PortfolioCalculator({
|
const portfolioCalculator = new PortfolioCalculator({
|
||||||
currency: this.request.user.Settings.settings.baseCurrency,
|
currency: userCurrency,
|
||||||
currentRateService: this.currentRateService,
|
currentRateService: this.currentRateService,
|
||||||
orders: portfolioOrders
|
orders: portfolioOrders
|
||||||
});
|
});
|
||||||
@ -355,28 +357,24 @@ export class PortfolioService {
|
|||||||
|
|
||||||
public async getDetails({
|
public async getDetails({
|
||||||
impersonationId,
|
impersonationId,
|
||||||
userId,
|
|
||||||
dateRange = 'max',
|
dateRange = 'max',
|
||||||
filters,
|
filters,
|
||||||
|
userId,
|
||||||
withExcludedAccounts = false
|
withExcludedAccounts = false
|
||||||
}: {
|
}: {
|
||||||
impersonationId: string;
|
impersonationId: string;
|
||||||
userId: string;
|
|
||||||
dateRange?: DateRange;
|
dateRange?: DateRange;
|
||||||
filters?: Filter[];
|
filters?: Filter[];
|
||||||
|
userId: string;
|
||||||
withExcludedAccounts?: boolean;
|
withExcludedAccounts?: boolean;
|
||||||
}): Promise<PortfolioDetails & { hasErrors: boolean }> {
|
}): Promise<PortfolioDetails & { hasErrors: boolean }> {
|
||||||
// TODO
|
|
||||||
userId = await this.getUserId(impersonationId, userId);
|
userId = await this.getUserId(impersonationId, userId);
|
||||||
const user = await this.userService.user({ id: userId });
|
const user = await this.userService.user({ id: userId });
|
||||||
|
const userCurrency = this.getUserCurrency(user);
|
||||||
|
|
||||||
const emergencyFund = new Big(
|
const emergencyFund = new Big(
|
||||||
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
|
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
|
||||||
);
|
);
|
||||||
const userCurrency =
|
|
||||||
user.Settings?.settings.baseCurrency ??
|
|
||||||
this.request.user?.Settings?.settings.baseCurrency ??
|
|
||||||
this.baseCurrency;
|
|
||||||
|
|
||||||
const { orders, portfolioOrders, transactionPoints } =
|
const { orders, portfolioOrders, transactionPoints } =
|
||||||
await this.getTransactionPoints({
|
await this.getTransactionPoints({
|
||||||
@ -540,7 +538,11 @@ export class PortfolioService {
|
|||||||
withExcludedAccounts
|
withExcludedAccounts
|
||||||
});
|
});
|
||||||
|
|
||||||
const summary = await this.getSummary({ impersonationId });
|
const summary = await this.getSummary({
|
||||||
|
impersonationId,
|
||||||
|
userCurrency,
|
||||||
|
userId
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accounts,
|
accounts,
|
||||||
@ -560,8 +562,9 @@ export class PortfolioService {
|
|||||||
aImpersonationId: string,
|
aImpersonationId: string,
|
||||||
aSymbol: string
|
aSymbol: string
|
||||||
): Promise<PortfolioPositionDetail> {
|
): Promise<PortfolioPositionDetail> {
|
||||||
const userCurrency = this.request.user.Settings.settings.baseCurrency;
|
|
||||||
const userId = await this.getUserId(aImpersonationId, this.request.user.id);
|
const userId = await this.getUserId(aImpersonationId, this.request.user.id);
|
||||||
|
const user = await this.userService.user({ id: userId });
|
||||||
|
const userCurrency = this.getUserCurrency(user);
|
||||||
|
|
||||||
const orders = (
|
const orders = (
|
||||||
await this.orderService.getOrders({
|
await this.orderService.getOrders({
|
||||||
@ -883,12 +886,16 @@ export class PortfolioService {
|
|||||||
|
|
||||||
public async getPerformance({
|
public async getPerformance({
|
||||||
dateRange = 'max',
|
dateRange = 'max',
|
||||||
impersonationId
|
impersonationId,
|
||||||
|
userId
|
||||||
}: {
|
}: {
|
||||||
dateRange?: DateRange;
|
dateRange?: DateRange;
|
||||||
impersonationId: string;
|
impersonationId: string;
|
||||||
|
userId: string;
|
||||||
}): Promise<PortfolioPerformanceResponse> {
|
}): Promise<PortfolioPerformanceResponse> {
|
||||||
const userId = await this.getUserId(impersonationId, this.request.user.id);
|
userId = await this.getUserId(impersonationId, userId);
|
||||||
|
const user = await this.userService.user({ id: userId });
|
||||||
|
const userCurrency = this.getUserCurrency(user);
|
||||||
|
|
||||||
const { portfolioOrders, transactionPoints } =
|
const { portfolioOrders, transactionPoints } =
|
||||||
await this.getTransactionPoints({
|
await this.getTransactionPoints({
|
||||||
@ -896,7 +903,7 @@ export class PortfolioService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const portfolioCalculator = new PortfolioCalculator({
|
const portfolioCalculator = new PortfolioCalculator({
|
||||||
currency: this.request.user.Settings.settings.baseCurrency,
|
currency: userCurrency,
|
||||||
currentRateService: this.currentRateService,
|
currentRateService: this.currentRateService,
|
||||||
orders: portfolioOrders
|
orders: portfolioOrders
|
||||||
});
|
});
|
||||||
@ -947,7 +954,9 @@ export class PortfolioService {
|
|||||||
|
|
||||||
const historicalDataContainer = await this.getChart({
|
const historicalDataContainer = await this.getChart({
|
||||||
dateRange,
|
dateRange,
|
||||||
impersonationId
|
impersonationId,
|
||||||
|
userCurrency,
|
||||||
|
userId
|
||||||
});
|
});
|
||||||
|
|
||||||
const itemOfToday = historicalDataContainer.items.find((item) => {
|
const itemOfToday = historicalDataContainer.items.find((item) => {
|
||||||
@ -995,8 +1004,9 @@ export class PortfolioService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async getReport(impersonationId: string): Promise<PortfolioReport> {
|
public async getReport(impersonationId: string): Promise<PortfolioReport> {
|
||||||
const currency = this.request.user.Settings.settings.baseCurrency;
|
|
||||||
const userId = await this.getUserId(impersonationId, this.request.user.id);
|
const userId = await this.getUserId(impersonationId, this.request.user.id);
|
||||||
|
const user = await this.userService.user({ id: userId });
|
||||||
|
const userCurrency = this.getUserCurrency(user);
|
||||||
|
|
||||||
const { orders, portfolioOrders, transactionPoints } =
|
const { orders, portfolioOrders, transactionPoints } =
|
||||||
await this.getTransactionPoints({
|
await this.getTransactionPoints({
|
||||||
@ -1010,7 +1020,7 @@ export class PortfolioService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const portfolioCalculator = new PortfolioCalculator({
|
const portfolioCalculator = new PortfolioCalculator({
|
||||||
currency,
|
currency: userCurrency,
|
||||||
currentRateService: this.currentRateService,
|
currentRateService: this.currentRateService,
|
||||||
orders: portfolioOrders
|
orders: portfolioOrders
|
||||||
});
|
});
|
||||||
@ -1030,7 +1040,7 @@ export class PortfolioService {
|
|||||||
orders,
|
orders,
|
||||||
portfolioItemsNow,
|
portfolioItemsNow,
|
||||||
userId,
|
userId,
|
||||||
userCurrency: currency
|
userCurrency
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
rules: {
|
rules: {
|
||||||
@ -1077,7 +1087,7 @@ export class PortfolioService {
|
|||||||
new FeeRatioInitialInvestment(
|
new FeeRatioInitialInvestment(
|
||||||
this.exchangeRateDataService,
|
this.exchangeRateDataService,
|
||||||
currentPositions.totalInvestment.toNumber(),
|
currentPositions.totalInvestment.toNumber(),
|
||||||
this.getFees(orders).toNumber()
|
this.getFees({ orders, userCurrency }).toNumber()
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
<UserSettings>this.request.user.Settings.settings
|
<UserSettings>this.request.user.Settings.settings
|
||||||
@ -1180,7 +1190,15 @@ export class PortfolioService {
|
|||||||
return cashPositions;
|
return cashPositions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDividend(orders: OrderWithAccount[], date = new Date(0)) {
|
private getDividend({
|
||||||
|
date = new Date(0),
|
||||||
|
orders,
|
||||||
|
userCurrency
|
||||||
|
}: {
|
||||||
|
date?: Date;
|
||||||
|
orders: OrderWithAccount[];
|
||||||
|
userCurrency: string;
|
||||||
|
}) {
|
||||||
return orders
|
return orders
|
||||||
.filter((order) => {
|
.filter((order) => {
|
||||||
// Filter out all orders before given date and type dividend
|
// Filter out all orders before given date and type dividend
|
||||||
@ -1193,7 +1211,7 @@ export class PortfolioService {
|
|||||||
return this.exchangeRateDataService.toCurrency(
|
return this.exchangeRateDataService.toCurrency(
|
||||||
new Big(order.quantity).mul(order.unitPrice).toNumber(),
|
new Big(order.quantity).mul(order.unitPrice).toNumber(),
|
||||||
order.SymbolProfile.currency,
|
order.SymbolProfile.currency,
|
||||||
this.request.user.Settings.settings.baseCurrency
|
userCurrency
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.reduce(
|
.reduce(
|
||||||
@ -1202,7 +1220,15 @@ export class PortfolioService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFees(orders: OrderWithAccount[], date = new Date(0)) {
|
private getFees({
|
||||||
|
date = new Date(0),
|
||||||
|
orders,
|
||||||
|
userCurrency
|
||||||
|
}: {
|
||||||
|
date?: Date;
|
||||||
|
orders: OrderWithAccount[];
|
||||||
|
userCurrency: string;
|
||||||
|
}) {
|
||||||
return orders
|
return orders
|
||||||
.filter((order) => {
|
.filter((order) => {
|
||||||
// Filter out all orders before given date
|
// Filter out all orders before given date
|
||||||
@ -1212,7 +1238,7 @@ export class PortfolioService {
|
|||||||
return this.exchangeRateDataService.toCurrency(
|
return this.exchangeRateDataService.toCurrency(
|
||||||
order.fee,
|
order.fee,
|
||||||
order.SymbolProfile.currency,
|
order.SymbolProfile.currency,
|
||||||
this.request.user.Settings.settings.baseCurrency
|
userCurrency
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.reduce(
|
.reduce(
|
||||||
@ -1262,16 +1288,20 @@ export class PortfolioService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async getSummary({
|
private async getSummary({
|
||||||
impersonationId
|
impersonationId,
|
||||||
|
userCurrency,
|
||||||
|
userId
|
||||||
}: {
|
}: {
|
||||||
impersonationId: string;
|
impersonationId: string;
|
||||||
|
userCurrency: string;
|
||||||
|
userId: string;
|
||||||
}): Promise<PortfolioSummary> {
|
}): Promise<PortfolioSummary> {
|
||||||
const userCurrency = this.request.user.Settings.settings.baseCurrency;
|
userId = await this.getUserId(impersonationId, userId);
|
||||||
const userId = await this.getUserId(impersonationId, this.request.user.id);
|
|
||||||
const user = await this.userService.user({ id: userId });
|
const user = await this.userService.user({ id: userId });
|
||||||
|
|
||||||
const performanceInformation = await this.getPerformance({
|
const performanceInformation = await this.getPerformance({
|
||||||
impersonationId
|
impersonationId,
|
||||||
|
userId
|
||||||
});
|
});
|
||||||
|
|
||||||
const { balanceInBaseCurrency } = await this.accountService.getCashDetails({
|
const { balanceInBaseCurrency } = await this.accountService.getCashDetails({
|
||||||
@ -1293,11 +1323,11 @@ export class PortfolioService {
|
|||||||
return account?.isExcluded ?? false;
|
return account?.isExcluded ?? false;
|
||||||
});
|
});
|
||||||
|
|
||||||
const dividend = this.getDividend(orders).toNumber();
|
const dividend = this.getDividend({ orders, userCurrency }).toNumber();
|
||||||
const emergencyFund = new Big(
|
const emergencyFund = new Big(
|
||||||
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
|
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
|
||||||
);
|
);
|
||||||
const fees = this.getFees(orders).toNumber();
|
const fees = this.getFees({ orders, userCurrency }).toNumber();
|
||||||
const firstOrderDate = orders[0]?.date;
|
const firstOrderDate = orders[0]?.date;
|
||||||
const items = this.getItems(orders).toNumber();
|
const items = this.getItems(orders).toNumber();
|
||||||
|
|
||||||
@ -1565,4 +1595,12 @@ export class PortfolioService {
|
|||||||
})
|
})
|
||||||
.reduce((previous, current) => previous + current, 0);
|
.reduce((previous, current) => previous + current, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getUserCurrency(aUser: UserWithSettings) {
|
||||||
|
return (
|
||||||
|
aUser.Settings?.settings.baseCurrency ??
|
||||||
|
this.request.user?.Settings?.settings.baseCurrency ??
|
||||||
|
this.baseCurrency
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user