Feature/break down emergency fund by cash and assets (#2159)
* Break down emergency fund in cash and assets * Update changelog
This commit is contained in:
parent
455a2d2e92
commit
bdf72164b1
@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- Broken down the emergency fund by cash and assets
|
||||
|
||||
## 1.290.0 - 2023-07-16
|
||||
|
||||
### Added
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DataSource, Type as TypeOfOrder } from '@prisma/client';
|
||||
import { DataSource, Tag, Type as TypeOfOrder } from '@prisma/client';
|
||||
import Big from 'big.js';
|
||||
|
||||
export interface PortfolioOrder {
|
||||
@ -9,6 +9,7 @@ export interface PortfolioOrder {
|
||||
name: string;
|
||||
quantity: Big;
|
||||
symbol: string;
|
||||
tags?: Tag[];
|
||||
type: TypeOfOrder;
|
||||
unitPrice: Big;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DataSource } from '@prisma/client';
|
||||
import { DataSource, Tag } from '@prisma/client';
|
||||
import Big from 'big.js';
|
||||
|
||||
export interface TransactionPointSymbol {
|
||||
@ -9,5 +9,6 @@ export interface TransactionPointSymbol {
|
||||
investment: Big;
|
||||
quantity: Big;
|
||||
symbol: string;
|
||||
tags?: Tag[];
|
||||
transactionCount: number;
|
||||
}
|
||||
|
@ -114,6 +114,7 @@ export class PortfolioCalculator {
|
||||
firstBuyDate: oldAccumulatedSymbol.firstBuyDate,
|
||||
quantity: newQuantity,
|
||||
symbol: order.symbol,
|
||||
tags: order.tags,
|
||||
transactionCount: oldAccumulatedSymbol.transactionCount + 1
|
||||
};
|
||||
} else {
|
||||
@ -125,6 +126,7 @@ export class PortfolioCalculator {
|
||||
investment: unitPrice.mul(order.quantity).mul(factor),
|
||||
quantity: order.quantity.mul(factor),
|
||||
symbol: order.symbol,
|
||||
tags: order.tags,
|
||||
transactionCount: 1
|
||||
};
|
||||
}
|
||||
@ -492,6 +494,7 @@ export class PortfolioCalculator {
|
||||
: null,
|
||||
quantity: item.quantity,
|
||||
symbol: item.symbol,
|
||||
tags: item.tags,
|
||||
transactionCount: item.transactionCount
|
||||
});
|
||||
|
||||
|
@ -161,10 +161,12 @@ export class PortfolioController {
|
||||
'emergencyFund',
|
||||
'excludedAccountsAndActivities',
|
||||
'fees',
|
||||
'fireWealth',
|
||||
'items',
|
||||
'liabilities',
|
||||
'netWorth',
|
||||
'totalBuy',
|
||||
'totalInvestment',
|
||||
'totalSell'
|
||||
]);
|
||||
}
|
||||
|
@ -583,6 +583,7 @@ export class PortfolioService {
|
||||
quantity: item.quantity.toNumber(),
|
||||
sectors: symbolProfile.sectors,
|
||||
symbol: item.symbol,
|
||||
tags: item.tags,
|
||||
transactionCount: item.transactionCount,
|
||||
url: symbolProfile.url,
|
||||
valueInBaseCurrency: value.toNumber()
|
||||
@ -628,7 +629,7 @@ export class PortfolioService {
|
||||
const emergencyFundInCash = emergencyFund
|
||||
.minus(
|
||||
this.getEmergencyFundPositionsValueInBaseCurrency({
|
||||
activities: orders
|
||||
holdings
|
||||
})
|
||||
)
|
||||
.toNumber();
|
||||
@ -656,7 +657,7 @@ export class PortfolioService {
|
||||
balanceInBaseCurrency: cashDetails.balanceInBaseCurrency,
|
||||
emergencyFundPositionsValueInBaseCurrency:
|
||||
this.getEmergencyFundPositionsValueInBaseCurrency({
|
||||
activities: orders
|
||||
holdings
|
||||
})
|
||||
});
|
||||
|
||||
@ -742,6 +743,7 @@ export class PortfolioService {
|
||||
name: order.SymbolProfile?.name,
|
||||
quantity: new Big(order.quantity),
|
||||
symbol: order.SymbolProfile.symbol,
|
||||
tags: order.tags,
|
||||
type: order.type,
|
||||
unitPrice: new Big(order.unitPrice)
|
||||
}));
|
||||
@ -1392,13 +1394,13 @@ export class PortfolioService {
|
||||
}
|
||||
|
||||
private getEmergencyFundPositionsValueInBaseCurrency({
|
||||
activities
|
||||
holdings
|
||||
}: {
|
||||
activities: Activity[];
|
||||
holdings: PortfolioDetails['holdings'];
|
||||
}) {
|
||||
const emergencyFundOrders = activities.filter((activity) => {
|
||||
const emergencyFundHoldings = Object.values(holdings).filter(({ tags }) => {
|
||||
return (
|
||||
activity.tags?.some(({ id }) => {
|
||||
tags?.some(({ id }) => {
|
||||
return id === EMERGENCY_FUND_TAG_ID;
|
||||
}) ?? false
|
||||
);
|
||||
@ -1406,18 +1408,9 @@ export class PortfolioService {
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
for (const { value } of emergencyFundHoldings) {
|
||||
valueInBaseCurrencyOfEmergencyFundPositions =
|
||||
valueInBaseCurrencyOfEmergencyFundPositions.plus(value);
|
||||
}
|
||||
|
||||
return valueInBaseCurrencyOfEmergencyFundPositions.toNumber();
|
||||
@ -1476,6 +1469,7 @@ export class PortfolioService {
|
||||
quantity: 0,
|
||||
sectors: [],
|
||||
symbol: currency,
|
||||
tags: [],
|
||||
transactionCount: 0,
|
||||
valueInBaseCurrency: balance
|
||||
};
|
||||
@ -1687,7 +1681,16 @@ export class PortfolioService {
|
||||
totalBuy,
|
||||
totalSell,
|
||||
committedFunds: committedFunds.toNumber(),
|
||||
emergencyFund: emergencyFund.toNumber(),
|
||||
emergencyFund: {
|
||||
assets: emergencyFundPositionsValueInBaseCurrency,
|
||||
cash: emergencyFund
|
||||
.minus(emergencyFundPositionsValueInBaseCurrency)
|
||||
.toNumber(),
|
||||
total: emergencyFund.toNumber()
|
||||
},
|
||||
fireWealth: new Big(performanceInformation.performance.currentValue)
|
||||
.minus(emergencyFundPositionsValueInBaseCurrency)
|
||||
.toNumber(),
|
||||
ordersCount: activities.filter(({ type }) => {
|
||||
return type === 'BUY' || type === 'SELL';
|
||||
}).length
|
||||
@ -1739,6 +1742,7 @@ export class PortfolioService {
|
||||
name: order.SymbolProfile?.name,
|
||||
quantity: new Big(order.quantity),
|
||||
symbol: order.SymbolProfile.symbol,
|
||||
tags: order.tags,
|
||||
type: order.type,
|
||||
unitPrice: new Big(
|
||||
this.exchangeRateDataService.toCurrency(
|
||||
|
@ -163,7 +163,33 @@
|
||||
[isCurrency]="true"
|
||||
[locale]="locale"
|
||||
[unit]="baseCurrency"
|
||||
[value]="isLoading ? undefined : summary?.emergencyFund"
|
||||
[value]="isLoading ? undefined : summary?.emergencyFund?.total"
|
||||
></gf-value>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-nowrap px-3 py-1 row">
|
||||
<div class="flex-grow-1 ml-3 text-truncate" i18n>Cash</div>
|
||||
<div class="flex-column flex-wrap justify-content-end">
|
||||
<gf-value
|
||||
class="justify-content-end"
|
||||
position="end"
|
||||
[isCurrency]="true"
|
||||
[locale]="locale"
|
||||
[unit]="baseCurrency"
|
||||
[value]="isLoading ? undefined : summary?.emergencyFund?.cash"
|
||||
></gf-value>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-nowrap px-3 py-1 row">
|
||||
<div class="flex-grow-1 ml-3 text-truncate" i18n>Assets</div>
|
||||
<div class="flex-column flex-wrap justify-content-end">
|
||||
<gf-value
|
||||
class="justify-content-end"
|
||||
position="end"
|
||||
[isCurrency]="true"
|
||||
[locale]="locale"
|
||||
[unit]="baseCurrency"
|
||||
[value]="isLoading ? undefined : summary?.emergencyFund?.assets"
|
||||
></gf-value>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -51,7 +51,7 @@ export class FirePageComponent implements OnDestroy, OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
this.fireWealth = new Big(summary.currentValue);
|
||||
this.fireWealth = new Big(summary.fireWealth);
|
||||
this.withdrawalRatePerYear = this.fireWealth.mul(4).div(100);
|
||||
this.withdrawalRatePerMonth = this.withdrawalRatePerYear.div(12);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { AssetClass, AssetSubClass, DataSource } from '@prisma/client';
|
||||
import { AssetClass, AssetSubClass, DataSource, Tag } from '@prisma/client';
|
||||
|
||||
import { Market, MarketState } from '../types';
|
||||
import { Country } from './country.interface';
|
||||
@ -26,8 +26,9 @@ export interface PortfolioPosition {
|
||||
netPerformancePercent: number;
|
||||
quantity: number;
|
||||
sectors: Sector[];
|
||||
transactionCount: number;
|
||||
symbol: string;
|
||||
tags?: Tag[];
|
||||
transactionCount: number;
|
||||
type?: string;
|
||||
url?: string;
|
||||
valueInBaseCurrency?: number;
|
||||
|
@ -5,9 +5,14 @@ export interface PortfolioSummary extends PortfolioPerformance {
|
||||
cash: number;
|
||||
committedFunds: number;
|
||||
dividend: number;
|
||||
emergencyFund: number;
|
||||
emergencyFund: {
|
||||
assets: number;
|
||||
cash: number;
|
||||
total: number;
|
||||
};
|
||||
excludedAccountsAndActivities: number;
|
||||
fees: number;
|
||||
fireWealth: number;
|
||||
firstOrderDate: Date;
|
||||
items: number;
|
||||
liabilities: number;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DataSource } from '@prisma/client';
|
||||
import { DataSource, Tag } from '@prisma/client';
|
||||
import Big from 'big.js';
|
||||
|
||||
export interface TimelinePosition {
|
||||
@ -15,5 +15,6 @@ export interface TimelinePosition {
|
||||
netPerformancePercentage: Big;
|
||||
quantity: Big;
|
||||
symbol: string;
|
||||
tags?: Tag[];
|
||||
transactionCount: number;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user