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

This commit is contained in:
ksyasuda 2024-10-02 11:31:06 -07:00
commit 84457f4816
5 changed files with 33 additions and 29 deletions

View File

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Optimized the portfolio calculations with smarter date interval selection
- Improved the language localization for German (`de`)
## 2.111.0 - 2024-09-28

View File

@ -16,13 +16,14 @@ import {
addDays,
addMilliseconds,
differenceInDays,
eachDayOfInterval,
format,
isBefore
} from 'date-fns';
import { cloneDeep, first, last, sortBy } from 'lodash';
export class TWRPortfolioCalculator extends PortfolioCalculator {
private chartDatesDescending: string[];
protected calculateOverallPerformance(
positions: TimelinePosition[]
): PortfolioSnapshot {
@ -820,31 +821,35 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
startDate = start;
}
const endDateString = format(endDate, DATE_FORMAT);
const startDateString = format(startDate, DATE_FORMAT);
const currentValuesAtDateRangeStartWithCurrencyEffect =
currentValuesWithCurrencyEffect[format(startDate, DATE_FORMAT)] ??
new Big(0);
currentValuesWithCurrencyEffect[startDateString] ?? new Big(0);
const investmentValuesAccumulatedAtStartDateWithCurrencyEffect =
investmentValuesAccumulatedWithCurrencyEffect[
format(startDate, DATE_FORMAT)
] ?? new Big(0);
investmentValuesAccumulatedWithCurrencyEffect[startDateString] ??
new Big(0);
const grossPerformanceAtDateRangeStartWithCurrencyEffect =
currentValuesAtDateRangeStartWithCurrencyEffect.minus(
investmentValuesAccumulatedAtStartDateWithCurrencyEffect
);
const dates = eachDayOfInterval({
end: endDate,
start: startDate
}).map((date) => {
return format(date, DATE_FORMAT);
});
let average = new Big(0);
let dayCount = 0;
for (const date of dates) {
if (!this.chartDatesDescending) {
this.chartDatesDescending = Object.keys(chartDateMap).sort().reverse();
}
for (const date of this.chartDatesDescending) {
if (date > endDateString) {
continue;
} else if (date < startDateString) {
break;
}
if (
investmentValuesAccumulatedWithCurrencyEffect[date] instanceof Big &&
investmentValuesAccumulatedWithCurrencyEffect[date].gt(0)
@ -864,17 +869,14 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
}
netPerformanceWithCurrencyEffectMap[dateRange] =
netPerformanceValuesWithCurrencyEffect[
format(endDate, DATE_FORMAT)
]?.minus(
netPerformanceValuesWithCurrencyEffect[endDateString]?.minus(
// If the date range is 'max', take 0 as a start value. Otherwise,
// the value of the end of the day of the start date is taken which
// differs from the buying price.
dateRange === 'max'
? new Big(0)
: (netPerformanceValuesWithCurrencyEffect[
format(startDate, DATE_FORMAT)
] ?? new Big(0))
: (netPerformanceValuesWithCurrencyEffect[startDateString] ??
new Big(0))
) ?? new Big(0);
netPerformancePercentageWithCurrencyEffectMap[dateRange] = average.gt(0)

View File

@ -111,7 +111,7 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
this.initialize();
}
public onSymbolClicked({ dataSource, symbol }: AssetProfileIdentifier) {
public onHoldingClicked({ dataSource, symbol }: AssetProfileIdentifier) {
if (dataSource && symbol) {
this.router.navigate([], {
queryParams: { dataSource, symbol, holdingDetailDialog: true }

View File

@ -40,7 +40,7 @@
cursor="pointer"
[dateRange]="user?.settings?.dateRange"
[holdings]="holdings"
(treemapChartClicked)="onSymbolClicked($event)"
(treemapChartClicked)="onHoldingClicked($event)"
/>
}
<div [ngClass]="{ 'd-none': viewModeFormControl.value !== 'TABLE' }">
@ -50,6 +50,7 @@
[hasPermissionToCreateActivity]="hasPermissionToCreateOrder"
[holdings]="holdings"
[locale]="user?.settings?.locale"
(holdingClicked)="onHoldingClicked($event)"
/>
@if (hasPermissionToCreateOrder && holdings?.length > 0) {
<div class="text-center">

View File

@ -14,10 +14,12 @@ import {
CUSTOM_ELEMENTS_SCHEMA,
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
ViewChild
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
@ -25,7 +27,6 @@ import { MatDialogModule } from '@angular/material/dialog';
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
import { MatSort, MatSortModule } from '@angular/material/sort';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { Router, RouterModule } from '@angular/router';
import { AssetSubClass } from '@prisma/client';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { Subject, Subscription } from 'rxjs';
@ -44,8 +45,7 @@ import { Subject, Subscription } from 'rxjs';
MatPaginatorModule,
MatSortModule,
MatTableModule,
NgxSkeletonLoaderModule,
RouterModule
NgxSkeletonLoaderModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
selector: 'gf-holdings-table',
@ -63,6 +63,8 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy, OnInit {
@Input() locale = getLocale();
@Input() pageSize = Number.MAX_SAFE_INTEGER;
@Output() holdingClicked = new EventEmitter<AssetProfileIdentifier>();
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
@ -75,7 +77,7 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy, OnInit {
private unsubscribeSubject = new Subject<void>();
public constructor(private router: Router) {}
public constructor() {}
public ngOnInit() {}
@ -107,9 +109,7 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy, OnInit {
public onOpenHoldingDialog({ dataSource, symbol }: AssetProfileIdentifier) {
if (this.hasPermissionToOpenDetails) {
this.router.navigate([], {
queryParams: { dataSource, symbol, holdingDetailDialog: true }
});
this.holdingClicked.emit({ dataSource, symbol });
}
}