diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts index d8385d70e2..1da85101d9 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts @@ -9,6 +9,7 @@ import { } from '@ghostfolio/common/config'; import { CreateOrderDto } from '@ghostfolio/common/dtos'; import { + alignLineChartItemsToDates, DATE_FORMAT, downloadAsFile, getCountryName @@ -725,6 +726,13 @@ export class GfHoldingDetailDialogComponent implements OnInit { } ); + this.benchmarkDataItems = alignLineChartItemsToDates({ + dates: this.historicalDataItems.map(({ date }) => { + return date; + }), + items: this.benchmarkDataItems + }); + this.changeDetectorRef.markForCheck(); }); } diff --git a/libs/common/src/lib/helper.spec.ts b/libs/common/src/lib/helper.spec.ts index d1130f0d75..cbf2bd1e99 100644 --- a/libs/common/src/lib/helper.spec.ts +++ b/libs/common/src/lib/helper.spec.ts @@ -3,6 +3,7 @@ import { TAG_ID_EXCLUDE_FROM_ANALYSIS } from '@ghostfolio/common/config'; import { + alignLineChartItemsToDates, canApplyFiltersToAccess, extractNumberFromString, getCountryCodeFromCurrency, @@ -23,6 +24,66 @@ import { import { UserSettings } from '@ghostfolio/common/interfaces'; describe('Helper', () => { + describe('Align line chart items to dates', () => { + it('Dates before the first item', () => { + expect( + alignLineChartItemsToDates({ + dates: ['2025-01-02', '2025-01-03'], + items: [{ date: '2026-01-09', value: 100 }] + }) + ).toEqual([ + { date: '2025-01-02', value: null }, + { date: '2025-01-03', value: null } + ]); + }); + + it('Dates on and after the items', () => { + expect( + alignLineChartItemsToDates({ + dates: [ + '2026-01-08', + '2026-01-09', + '2026-01-10', + '2026-01-12', + '2026-01-13' + ], + items: [ + { date: '2026-01-09', value: 100 }, + { date: '2026-01-12', value: 110 } + ] + }) + ).toEqual([ + { date: '2026-01-08', value: null }, + { date: '2026-01-09', value: 100 }, + { date: '2026-01-10', value: 100 }, + { date: '2026-01-12', value: 110 }, + { date: '2026-01-13', value: 110 } + ]); + }); + + it('Null values', () => { + expect( + alignLineChartItemsToDates({ + dates: ['2026-01-09', '2026-01-10', '2026-01-11'], + items: [ + { date: '2026-01-09', value: 100 }, + { date: '2026-01-10', value: null } + ] + }) + ).toEqual([ + { date: '2026-01-09', value: 100 }, + { date: '2026-01-10', value: null }, + { date: '2026-01-11', value: null } + ]); + }); + + it('No items', () => { + expect( + alignLineChartItemsToDates({ dates: ['2026-01-09'], items: [] }) + ).toEqual([{ date: '2026-01-09', value: null }]); + }); + }); + describe('Can apply filters to access', () => { it('An access of the model context protocol', () => { expect(canApplyFiltersToAccess({ type: 'MCP' })).toEqual(false); diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 6e50911322..769d693572 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -57,6 +57,7 @@ import { AssetProfileIdentifier, AssetProfileItem, Benchmark, + NullableLineChartItem, PortfolioPosition, UserSettings } from './interfaces'; @@ -91,6 +92,27 @@ const USER_SETTINGS_KEYS_OF_AUTHENTICATED_USER: (keyof UserSettings)[] = [ const VALID_COUNTRY_CODES = new Set([...Object.keys(countries), 'EU']); +export function alignLineChartItemsToDates({ + dates, + items +}: { + dates: string[]; + items: NullableLineChartItem[]; +}): NullableLineChartItem[] { + let index = -1; + + return dates.map((date) => { + while ( + index + 1 < items.length && + !isAfter(parseISO(items[index + 1].date), parseISO(date)) + ) { + index++; + } + + return { date, value: items[index]?.value ?? null }; + }); +} + export function applyAssetProfileOverrides>( assetProfile: T, assetProfileOverrides: AssetProfileOverrides | null