Merge branch 'main' of gitea.suda.codes:giteauser/ghostfolio-mirror

This commit is contained in:
ksyasuda 2024-08-25 12:51:55 -07:00
commit 633995c9c8
13 changed files with 88 additions and 100 deletions

View File

@ -5,12 +5,16 @@ 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).
## 2.106.0-alpha.1 - 2024-08-24
## 2.106.0-beta.1 - 2024-08-25
### Changed
- Reworked the portfolio calculator
### Fixed
- Fixed an issue in the view mode toggle of the holdings tab on the home page (experimental)
## 2.105.0 - 2024-08-21
### Added

View File

@ -519,6 +519,23 @@ export class OrderService {
return { activities, count };
}
public async getOrdersForPortfolioCalculator({
filters,
userCurrency,
userId
}: {
filters?: Filter[];
userCurrency: string;
userId: string;
}) {
return this.getOrders({
filters,
userCurrency,
userId,
withExcludedAccounts: false // TODO
});
}
public async getStatisticsByCurrency(
currency: EnhancedSymbolProfile['currency']
): Promise<{

View File

@ -713,10 +713,14 @@ export abstract class PortfolioCalculator {
netPerformanceWithCurrencyEffect:
netPerformanceWithCurrencyEffectSinceStartDate,
netPerformanceInPercentage:
netPerformanceSinceStartDate / timeWeightedInvestmentValue,
timeWeightedInvestmentValue === 0
? 0
: netPerformanceSinceStartDate / timeWeightedInvestmentValue,
netPerformanceInPercentageWithCurrencyEffect:
netPerformanceWithCurrencyEffectSinceStartDate /
timeWeightedInvestmentValue,
timeWeightedInvestmentValue === 0
? 0
: netPerformanceWithCurrencyEffectSinceStartDate /
timeWeightedInvestmentValue,
// TODO: Add net worth with valuables
// netWorth: totalCurrentValueWithCurrencyEffect
// .plus(totalAccountBalanceWithCurrencyEffect)

View File

@ -247,13 +247,12 @@ export class PortfolioService {
const { endDate, startDate } = getIntervalFromDateRange(dateRange);
const { activities } = await this.orderService.getOrders({
filters,
userId,
includeDrafts: true,
types: ['BUY', 'SELL'],
userCurrency: this.getUserCurrency()
});
const { activities } =
await this.orderService.getOrdersForPortfolioCalculator({
filters,
userId,
userCurrency: this.getUserCurrency()
});
if (activities.length === 0) {
return {
@ -332,12 +331,12 @@ export class PortfolioService {
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
);
const { activities } = await this.orderService.getOrders({
filters,
userCurrency,
userId,
withExcludedAccounts
});
const { activities } =
await this.orderService.getOrdersForPortfolioCalculator({
filters,
userCurrency,
userId
});
const portfolioCalculator = this.calculatorFactory.createCalculator({
activities,
@ -597,11 +596,11 @@ export class PortfolioService {
const user = await this.userService.user({ id: userId });
const userCurrency = this.getUserCurrency(user);
const { activities } = await this.orderService.getOrders({
userCurrency,
userId,
withExcludedAccounts: true
});
const { activities } =
await this.orderService.getOrdersForPortfolioCalculator({
userCurrency,
userId
});
const orders = activities.filter(({ SymbolProfile }) => {
return (
@ -906,14 +905,12 @@ export class PortfolioService {
const userId = await this.getUserId(impersonationId, this.request.user.id);
const user = await this.userService.user({ id: userId });
const { endDate } = getIntervalFromDateRange(dateRange);
const { activities } = await this.orderService.getOrders({
endDate,
filters,
userId,
userCurrency: this.getUserCurrency()
});
const { activities } =
await this.orderService.getOrdersForPortfolioCalculator({
filters,
userId,
userCurrency: this.getUserCurrency()
});
if (activities?.length <= 0) {
return {
@ -1085,15 +1082,12 @@ export class PortfolioService {
)
);
const { endDate, startDate } = getIntervalFromDateRange(dateRange);
const { activities } = await this.orderService.getOrders({
endDate,
filters,
userCurrency,
userId,
withExcludedAccounts
});
const { activities } =
await this.orderService.getOrdersForPortfolioCalculator({
filters,
userCurrency,
userId
});
if (accountBalanceItems?.length <= 0 && activities?.length <= 0) {
return {
@ -1126,6 +1120,8 @@ export class PortfolioService {
const { errors, hasErrors, historicalData } =
await portfolioCalculator.getSnapshot();
const { endDate, startDate } = getIntervalFromDateRange(dateRange);
const { chart } = await portfolioCalculator.getPerformance({
end: endDate,
start: startDate
@ -1175,10 +1171,11 @@ export class PortfolioService {
const user = await this.userService.user({ id: userId });
const userCurrency = this.getUserCurrency(user);
const { activities } = await this.orderService.getOrders({
userCurrency,
userId
});
const { activities } =
await this.orderService.getOrdersForPortfolioCalculator({
userCurrency,
userId
});
const portfolioCalculator = this.calculatorFactory.createCalculator({
activities,

View File

@ -161,10 +161,8 @@ export class HeaderComponent implements OnChanges {
.putUserSetting({ dateRange })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe();
});
@ -191,10 +189,8 @@ export class HeaderComponent implements OnChanges {
.putUserSetting(userSetting)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe();
});

View File

@ -18,7 +18,7 @@ import { FormControl } from '@angular/forms';
import { Router } from '@angular/router';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
import { skip, takeUntil } from 'rxjs/operators';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-home-holdings',
@ -87,20 +87,14 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
});
this.viewModeFormControl.valueChanges
.pipe(
// Skip inizialization: "new FormControl"
skip(1),
takeUntil(this.unsubscribeSubject)
)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((holdingsViewMode) => {
this.dataService
.putUserSetting({ holdingsViewMode })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;
@ -144,7 +138,7 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
}
private initialize() {
this.viewModeFormControl.disable();
this.viewModeFormControl.disable({ emitEvent: false });
if (
this.hasPermissionToAccessHoldingsChart &&

View File

@ -73,10 +73,8 @@ export class HomeSummaryComponent implements OnDestroy, OnInit {
.putUserSetting({ emergencyFund })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;

View File

@ -125,10 +125,8 @@ export class UserAccountSettingsComponent implements OnDestroy, OnInit {
.putUserSetting({ [aKey]: aValue })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;
@ -180,10 +178,8 @@ export class UserAccountSettingsComponent implements OnDestroy, OnInit {
.putUserSetting({ isExperimentalFeatures: aEvent.checked })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;
@ -218,10 +214,8 @@ export class UserAccountSettingsComponent implements OnDestroy, OnInit {
.putUserSetting({ isRestrictedView: aEvent.checked })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;
@ -259,10 +253,8 @@ export class UserAccountSettingsComponent implements OnDestroy, OnInit {
.putUserSetting({ viewMode: aEvent.checked === true ? 'ZEN' : 'DEFAULT' })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;

View File

@ -143,10 +143,8 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
.putUserSetting({ benchmark: symbolProfileId })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;

View File

@ -103,10 +103,8 @@ export class FirePageComponent implements OnDestroy, OnInit {
.putUserSetting({ annualInterestRate })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;
@ -124,10 +122,8 @@ export class FirePageComponent implements OnDestroy, OnInit {
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;
@ -153,10 +149,8 @@ export class FirePageComponent implements OnDestroy, OnInit {
.putUserSetting({ savingsRate })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;
@ -174,10 +168,8 @@ export class FirePageComponent implements OnDestroy, OnInit {
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;

View File

@ -466,11 +466,9 @@
[ngClass]="{
'cursor-pointer':
hasPermissionToOpenDetails &&
!row.isDraft &&
row.type !== 'FEE' &&
row.type !== 'INTEREST' &&
row.type !== 'ITEM' &&
row.type !== 'LIABILITY'
row.Account?.isExcluded !== true &&
row.isDraft === false &&
['BUY', 'DIVIDEND', 'SELL'].includes(row.type)
}"
(click)="onClickActivity(row)"
></tr>

View File

@ -199,11 +199,9 @@ export class GfActivitiesTableComponent
}
} else if (
this.hasPermissionToOpenDetails &&
!activity.isDraft &&
activity.type !== 'FEE' &&
activity.type !== 'INTEREST' &&
activity.type !== 'ITEM' &&
activity.type !== 'LIABILITY'
activity.Account?.isExcluded !== true &&
activity.isDraft === false &&
['BUY', 'DIVIDEND', 'SELL'].includes(activity.type)
) {
this.onOpenPositionDialog({
dataSource: activity.SymbolProfile.dataSource,

View File

@ -1,6 +1,6 @@
{
"name": "ghostfolio",
"version": "2.106.0-alpha.1",
"version": "2.106.0-beta.1",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio",