Feature/support assets in emergency fund (#1601)

* Support assets in emergency fund

* Update changelog
pull/1603/head
Thomas Kaul 1 year ago committed by GitHub
parent 0878941c4f
commit d147c2313f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added support for assets other than cash in emergency fund (affecting buying power)
- Added support for translated tags
### Changed

@ -1,5 +1,6 @@
import { AccountService } from '@ghostfolio/api/app/account/account.service';
import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface';
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
import { OrderService } from '@ghostfolio/api/app/order/order.service';
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
import { PortfolioOrder } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-order.interface';
@ -597,7 +598,12 @@ export class PortfolioService {
const summary = await this.getSummary({
impersonationId,
userCurrency,
userId
userId,
balanceInBaseCurrency: cashDetails.balanceInBaseCurrency,
emergencyFundPositionsValueInBaseCurrency:
this.getEmergencyFundPositionsValueInBaseCurrency({
activities: orders
})
});
return {
@ -1167,7 +1173,7 @@ export class PortfolioService {
new FeeRatioInitialInvestment(
this.exchangeRateDataService,
currentPositions.totalInvestment.toNumber(),
this.getFees({ orders, userCurrency }).toNumber()
this.getFees({ userCurrency, activities: orders }).toNumber()
)
],
<UserSettings>this.request.user.Settings.settings
@ -1254,26 +1260,27 @@ export class PortfolioService {
}
private getDividend({
activities,
date = new Date(0),
orders,
userCurrency
}: {
activities: OrderWithAccount[];
date?: Date;
orders: OrderWithAccount[];
userCurrency: string;
}) {
return orders
.filter((order) => {
// Filter out all orders before given date and type dividend
return activities
.filter((activity) => {
// Filter out all activities before given date and type dividend
return (
isBefore(date, new Date(order.date)) &&
order.type === TypeOfOrder.DIVIDEND
isBefore(date, new Date(activity.date)) &&
activity.type === TypeOfOrder.DIVIDEND
);
})
.map((order) => {
.map(({ quantity, SymbolProfile, unitPrice }) => {
return this.exchangeRateDataService.toCurrency(
new Big(order.quantity).mul(order.unitPrice).toNumber(),
order.SymbolProfile.currency,
new Big(quantity).mul(unitPrice).toNumber(),
SymbolProfile.currency,
userCurrency
);
})
@ -1345,24 +1352,56 @@ export class PortfolioService {
return dividendsByGroup;
}
private getEmergencyFundPositionsValueInBaseCurrency({
activities
}: {
activities: Activity[];
}) {
const emergencyFundOrders = activities.filter((activity) => {
return (
activity.tags?.some(({ name }) => {
return name === 'EMERGENCY_FUND';
}) ?? false
);
});
let valueInBaseCurrencyOfEmergencyFundPositions = new Big(0);
for (const order of emergencyFundOrders) {
if (order.type === 'BUY') {
valueInBaseCurrencyOfEmergencyFundPositions =
valueInBaseCurrencyOfEmergencyFundPositions.plus(
order.valueInBaseCurrency
);
} else if (order.type === 'SELL') {
valueInBaseCurrencyOfEmergencyFundPositions =
valueInBaseCurrencyOfEmergencyFundPositions.minus(
order.valueInBaseCurrency
);
}
}
return valueInBaseCurrencyOfEmergencyFundPositions.toNumber();
}
private getFees({
activities,
date = new Date(0),
orders,
userCurrency
}: {
activities: OrderWithAccount[];
date?: Date;
orders: OrderWithAccount[];
userCurrency: string;
}) {
return orders
.filter((order) => {
// Filter out all orders before given date
return isBefore(date, new Date(order.date));
return activities
.filter((activity) => {
// Filter out all activities before given date
return isBefore(date, new Date(activity.date));
})
.map((order) => {
.map(({ fee, SymbolProfile }) => {
return this.exchangeRateDataService.toCurrency(
order.fee,
order.SymbolProfile.currency,
fee,
SymbolProfile.currency,
userCurrency
);
})
@ -1445,10 +1484,14 @@ export class PortfolioService {
}
private async getSummary({
balanceInBaseCurrency,
emergencyFundPositionsValueInBaseCurrency,
impersonationId,
userCurrency,
userId
}: {
balanceInBaseCurrency: number;
emergencyFundPositionsValueInBaseCurrency: number;
impersonationId: string;
userCurrency: string;
userId: string;
@ -1461,11 +1504,7 @@ export class PortfolioService {
userId
});
const { balanceInBaseCurrency } = await this.accountService.getCashDetails({
userId,
currency: userCurrency
});
const orders = await this.orderService.getOrders({
const activities = await this.orderService.getOrders({
userCurrency,
userId
});
@ -1480,18 +1519,24 @@ export class PortfolioService {
return account?.isExcluded ?? false;
});
const dividend = this.getDividend({ orders, userCurrency }).toNumber();
const dividend = this.getDividend({
activities,
userCurrency
}).toNumber();
const emergencyFund = new Big(
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
);
const fees = this.getFees({ orders, userCurrency }).toNumber();
const firstOrderDate = orders[0]?.date;
const items = this.getItems(orders).toNumber();
const fees = this.getFees({ activities, userCurrency }).toNumber();
const firstOrderDate = activities[0]?.date;
const items = this.getItems(activities).toNumber();
const totalBuy = this.getTotalByType(orders, userCurrency, 'BUY');
const totalSell = this.getTotalByType(orders, userCurrency, 'SELL');
const totalBuy = this.getTotalByType(activities, userCurrency, 'BUY');
const totalSell = this.getTotalByType(activities, userCurrency, 'SELL');
const cash = new Big(balanceInBaseCurrency).minus(emergencyFund).toNumber();
const cash = new Big(balanceInBaseCurrency)
.minus(emergencyFund)
.plus(emergencyFundPositionsValueInBaseCurrency)
.toNumber();
const committedFunds = new Big(totalBuy).minus(totalSell);
const totalOfExcludedActivities = new Big(
this.getTotalByType(excludedActivities, userCurrency, 'BUY')
@ -1547,8 +1592,8 @@ export class PortfolioService {
totalSell,
committedFunds: committedFunds.toNumber(),
emergencyFund: emergencyFund.toNumber(),
ordersCount: orders.filter((order) => {
return order.type === 'BUY' || order.type === 'SELL';
ordersCount: activities.filter(({ type }) => {
return type === 'BUY' || type === 'SELL';
}).length
};
}
@ -1565,7 +1610,7 @@ export class PortfolioService {
withExcludedAccounts?: boolean;
}): Promise<{
transactionPoints: TransactionPoint[];
orders: OrderWithAccount[];
orders: Activity[];
portfolioOrders: PortfolioOrder[];
}> {
const userCurrency =

@ -288,6 +288,16 @@ async function main() {
skipDuplicates: true
});
await prisma.tag.createMany({
data: [
{
id: '4452656d-9fa4-4bd0-ba38-70492e31d180',
name: 'EMERGENCY_FUND'
}
],
skipDuplicates: true
});
console.log({
platformBitcoinSuisse,
platformBitpanda,

Loading…
Cancel
Save