From fb5716c8a799718d7ac380b804db4902e2ebe94b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 15 May 2026 10:58:54 +0300 Subject: [PATCH 1/5] Task/refactor deprecated currency to asset profile in public controller (#6775) Refactor deprecated currency to asset profile --- apps/api/src/app/endpoints/public/public.controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/api/src/app/endpoints/public/public.controller.ts b/apps/api/src/app/endpoints/public/public.controller.ts index 33c6052a6..1d6eb6b0b 100644 --- a/apps/api/src/app/endpoints/public/public.controller.ts +++ b/apps/api/src/app/endpoints/public/public.controller.ts @@ -151,11 +151,11 @@ export class PublicController { }; const totalValue = getSum( - Object.values(holdings).map(({ currency, marketPrice, quantity }) => { + Object.values(holdings).map(({ assetProfile, marketPrice, quantity }) => { return new Big( this.exchangeRateDataService.toCurrency( quantity * marketPrice, - currency, + assetProfile.currency, this.request.user?.settings?.settings.baseCurrency ?? DEFAULT_CURRENCY ) From 9ab28d3f56f909886e5bf713861abc4060ed2d76 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Fri, 15 May 2026 15:05:32 +0700 Subject: [PATCH 2/5] Task/improve type safety in investment chart component (#6859) * fix(client): resolve errors * feat(client): enforce encapsulation * feat(client): use viewChild signals * feat(client): enforce immutability --- .../investment-chart.component.ts | 240 +++++++++--------- 1 file changed, 124 insertions(+), 116 deletions(-) diff --git a/apps/client/src/app/components/investment-chart/investment-chart.component.ts b/apps/client/src/app/components/investment-chart/investment-chart.component.ts index 21a7ac85a..691133009 100644 --- a/apps/client/src/app/components/investment-chart/investment-chart.component.ts +++ b/apps/client/src/app/components/investment-chart/investment-chart.component.ts @@ -24,7 +24,7 @@ import { Input, OnChanges, OnDestroy, - ViewChild + viewChild } from '@angular/core'; import { BarController, @@ -55,20 +55,21 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; templateUrl: './investment-chart.component.html' }) export class GfInvestmentChartComponent implements OnChanges, OnDestroy { - @Input() benchmarkDataItems: InvestmentItem[] = []; - @Input() benchmarkDataLabel = ''; - @Input() colorScheme: ColorScheme; - @Input() currency: string; - @Input() groupBy: GroupBy; - @Input() historicalDataItems: LineChartItem[] = []; - @Input() isInPercentage = false; - @Input() isLoading = false; - @Input() locale = getLocale(); - @Input() savingsRate = 0; + @Input() public readonly benchmarkDataItems: InvestmentItem[] = []; + @Input() public readonly benchmarkDataLabel = ''; + @Input() public readonly colorScheme: ColorScheme; + @Input() public readonly currency: string; + @Input() public readonly groupBy: GroupBy; + @Input() public readonly historicalDataItems: LineChartItem[] = []; + @Input() public readonly isInPercentage = false; + @Input() public readonly isLoading = false; + @Input() public readonly locale = getLocale(); + @Input() public readonly savingsRate = 0; - @ViewChild('chartCanvas') chartCanvas: ElementRef; + private readonly chartCanvas = + viewChild.required>('chartCanvas'); - public chart: Chart<'bar' | 'line'>; + private chart: Chart<'bar' | 'line'>; private investments: InvestmentItem[]; private values: LineChartItem[]; @@ -118,7 +119,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { borderWidth: this.groupBy ? 0 : 1, data: this.investments.map(({ date, investment }) => { return { - x: parseDate(date).getTime(), + x: parseDate(date)?.getTime() ?? null, y: this.isInPercentage ? investment * 100 : investment }; }), @@ -138,7 +139,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { borderWidth: 2, data: this.values.map(({ date, value }) => { return { - x: parseDate(date).getTime(), + x: parseDate(date)?.getTime() ?? null, y: this.isInPercentage ? value * 100 : value }; }), @@ -165,123 +166,126 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { this.getTooltipPluginConfiguration(); const annotations = this.chart.options.plugins.annotation - .annotations as Record>; + ?.annotations as Record>; if (this.savingsRate && annotations.savingsRate) { annotations.savingsRate.value = this.savingsRate; } this.chart.update(); } else { - this.chart = new Chart(this.chartCanvas.nativeElement, { - data: chartData, - options: { - animation: false, - elements: { - line: { - tension: 0 + this.chart = new Chart<'bar' | 'line'>( + this.chartCanvas().nativeElement, + { + data: chartData, + options: { + animation: false, + elements: { + line: { + tension: 0 + }, + point: { + hoverBackgroundColor: getBackgroundColor(this.colorScheme), + hoverRadius: 2, + radius: 0 + } }, - point: { - hoverBackgroundColor: getBackgroundColor(this.colorScheme), - hoverRadius: 2, - radius: 0 - } - }, - interaction: { intersect: false, mode: 'index' }, - maintainAspectRatio: true, - plugins: { - annotation: { - annotations: { - savingsRate: this.savingsRate - ? { - borderColor: `rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.75)`, - borderWidth: 1, - label: { - backgroundColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`, - borderRadius: 2, - color: 'white', - content: $localize`Savings Rate`, - display: true, - font: { size: 10, weight: 'normal' }, - padding: { - x: 4, - y: 2 + interaction: { intersect: false, mode: 'index' }, + maintainAspectRatio: true, + plugins: { + annotation: { + annotations: { + savingsRate: this.savingsRate + ? { + borderColor: `rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.75)`, + borderWidth: 1, + label: { + backgroundColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`, + borderRadius: 2, + color: 'white', + content: $localize`Savings Rate`, + display: true, + font: { size: 10, weight: 'normal' }, + padding: { + x: 4, + y: 2 + }, + position: 'start' }, - position: 'start' - }, - scaleID: 'y', - type: 'line', - value: this.savingsRate - } - : undefined, - yAxis: { - borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, - borderWidth: 1, - scaleID: 'y', - type: 'line', - value: 0 + scaleID: 'y', + type: 'line', + value: this.savingsRate + } + : undefined, + yAxis: { + borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, + borderWidth: 1, + scaleID: 'y', + type: 'line', + value: 0 + } } - } - }, - legend: { - display: false - }, - tooltip: this.getTooltipPluginConfiguration(), - verticalHoverLine: { - color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` - } - }, - responsive: true, - scales: { - x: { - border: { - color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, - width: this.groupBy ? 0 : 1 }, - display: true, - grid: { + legend: { display: false }, - type: 'time', - time: { - tooltipFormat: getDateFormatString(this.locale), - unit: 'year' + tooltip: this.getTooltipPluginConfiguration(), + verticalHoverLine: { + color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` } }, - y: { - border: { - display: false - }, - display: !this.isInPercentage, - grid: { - color: ({ scale, tick }) => { - if ( - tick.value === 0 || - tick.value === scale.max || - tick.value === scale.min - ) { - return `rgba(${getTextColor(this.colorScheme)}, 0.1)`; - } - - return 'transparent'; + responsive: true, + scales: { + x: { + border: { + color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, + width: this.groupBy ? 0 : 1 + }, + display: true, + grid: { + display: false + }, + type: 'time', + time: { + tooltipFormat: getDateFormatString(this.locale), + unit: 'year' } }, - position: 'right', - ticks: { - callback: (value: number) => { - return transformTickToAbbreviation(value); + y: { + border: { + display: false }, - display: true, - mirror: true, - z: 1 + display: !this.isInPercentage, + grid: { + color: ({ scale, tick }) => { + if ( + tick.value === 0 || + tick.value === scale.max || + tick.value === scale.min + ) { + return `rgba(${getTextColor(this.colorScheme)}, 0.1)`; + } + + return 'transparent'; + } + }, + position: 'right', + ticks: { + callback: (value: number) => { + return transformTickToAbbreviation(value); + }, + display: true, + mirror: true, + z: 1 + } } } - } - }, - plugins: [ - getVerticalHoverLinePlugin(this.chartCanvas, this.colorScheme) - ], - type: this.groupBy ? 'bar' : 'line' - }); + }, + plugins: [ + getVerticalHoverLinePlugin(this.chartCanvas(), this.colorScheme) + ], + type: this.groupBy ? 'bar' : 'line' + } + ); } } } @@ -305,8 +309,12 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { } private isInFuture(aContext: ScriptableLineSegmentContext, aValue: T) { - return isAfter(new Date(aContext?.p1?.parsed?.x), new Date()) - ? aValue - : undefined; + const xValue = aContext?.p1?.parsed?.x; + + if (xValue == null) { + return undefined; + } + + return isAfter(new Date(xValue), new Date()) ? aValue : undefined; } } From 21ed03f5ba6ba3496f1833f5ec84d65db7921e46 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 15 May 2026 11:15:24 +0300 Subject: [PATCH 3/5] Task/refactor deprecated portfolio position attributes in X-ray rules (#6776) Refactor deprecated portfolio position attributes to asset profile --- apps/api/src/models/rule.ts | 8 ++++---- .../rules/asset-class-cluster-risk/equity.ts | 3 ++- .../rules/asset-class-cluster-risk/fixed-income.ts | 3 ++- .../base-currency-current-investment.ts | 2 +- .../currency-cluster-risk/current-investment.ts | 2 +- libs/common/src/lib/helper.ts | 14 -------------- 6 files changed, 10 insertions(+), 22 deletions(-) diff --git a/apps/api/src/models/rule.ts b/apps/api/src/models/rule.ts index 5603964c5..66cda1d78 100644 --- a/apps/api/src/models/rule.ts +++ b/apps/api/src/models/rule.ts @@ -1,6 +1,5 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config'; -import { groupBy } from '@ghostfolio/common/helper'; import { PortfolioPosition, PortfolioReportRule, @@ -9,6 +8,7 @@ import { } from '@ghostfolio/common/interfaces'; import { Big } from 'big.js'; +import { groupBy } from 'lodash'; import { EvaluationResult } from './interfaces/evaluation-result.interface'; import { RuleInterface } from './interfaces/rule.interface'; @@ -41,10 +41,10 @@ export abstract class Rule implements RuleInterface { public groupCurrentHoldingsByAttribute( holdings: PortfolioPosition[], - attribute: keyof PortfolioPosition, + attribute: `assetProfile.${Extract}`, baseCurrency: string ) { - return Array.from(groupBy(attribute, holdings).entries()).map( + return Object.entries(groupBy(holdings, attribute)).map( ([attributeValue, objs]) => ({ groupKey: attributeValue, investment: objs.reduce( @@ -59,7 +59,7 @@ export abstract class Rule implements RuleInterface { new Big(currentValue.quantity) .mul(currentValue.marketPrice ?? 0) .toNumber(), - currentValue.currency, + currentValue.assetProfile.currency, baseCurrency ), 0 diff --git a/apps/api/src/models/rules/asset-class-cluster-risk/equity.ts b/apps/api/src/models/rules/asset-class-cluster-risk/equity.ts index 372b0bb06..12303fd92 100644 --- a/apps/api/src/models/rules/asset-class-cluster-risk/equity.ts +++ b/apps/api/src/models/rules/asset-class-cluster-risk/equity.ts @@ -27,9 +27,10 @@ export class AssetClassClusterRiskEquity extends Rule { public evaluate(ruleSettings: Settings) { const holdingsGroupedByAssetClass = this.groupCurrentHoldingsByAttribute( this.holdings, - 'assetClass', + 'assetProfile.assetClass', ruleSettings.baseCurrency ); + let totalValue = 0; const equityValueInBaseCurrency = diff --git a/apps/api/src/models/rules/asset-class-cluster-risk/fixed-income.ts b/apps/api/src/models/rules/asset-class-cluster-risk/fixed-income.ts index 404b4cd32..fd7c00f11 100644 --- a/apps/api/src/models/rules/asset-class-cluster-risk/fixed-income.ts +++ b/apps/api/src/models/rules/asset-class-cluster-risk/fixed-income.ts @@ -27,9 +27,10 @@ export class AssetClassClusterRiskFixedIncome extends Rule { public evaluate(ruleSettings: Settings) { const holdingsGroupedByAssetClass = this.groupCurrentHoldingsByAttribute( this.holdings, - 'assetClass', + 'assetProfile.assetClass', ruleSettings.baseCurrency ); + let totalValue = 0; const fixedIncomeValueInBaseCurrency = diff --git a/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts b/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts index 83c72eeb8..6890fecd6 100644 --- a/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts +++ b/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts @@ -27,7 +27,7 @@ export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule { public evaluate(ruleSettings: Settings) { const holdingsGroupedByCurrency = this.groupCurrentHoldingsByAttribute( this.holdings, - 'currency', + 'assetProfile.currency', ruleSettings.baseCurrency ); diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 4db1fcf2d..2d8cd90e4 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -342,20 +342,6 @@ export function getYesterday() { return subDays(new Date(Date.UTC(year, month, day)), 1); } -export function groupBy( - key: K, - arr: T[] -): Map { - const map = new Map(); - arr.forEach((t) => { - if (!map.has(t[key])) { - map.set(t[key], []); - } - map.get(t[key])!.push(t); - }); - return map; -} - export function interpolate(template: string, context: any) { return template?.replace(/[$]{([^}]+)}/g, (_, objectPath) => { const properties = objectPath.split('.'); From 5fd9eff8a77448d10f75d96e60eb65ccccfa0f45 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 15 May 2026 11:16:45 +0300 Subject: [PATCH 4/5] Task/refactor deprecated portfolio position attributes in treemap chart component (#6779) Refactor deprecated portfolio position attributes to asset profile --- .../lib/treemap-chart/treemap-chart.component.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts index 7069cabb0..910914230 100644 --- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts +++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts @@ -280,8 +280,8 @@ export class GfTreemapChartComponent ); } - const name = raw._data.name; - const symbol = raw._data.symbol; + const name = raw._data.assetProfile.name; + const symbol = raw._data.assetProfile.symbol; return [ isUUID(symbol) ? (name ?? symbol) : symbol, @@ -322,8 +322,10 @@ export class GfTreemapChartComponent ['desc'] ) as PortfolioPosition[]; - const dataSource: DataSource = dataset[dataIndex].dataSource; - const symbol: string = dataset[dataIndex].symbol; + const dataSource: DataSource = + dataset[dataIndex].assetProfile.dataSource; + + const symbol: string = dataset[dataIndex].assetProfile.symbol; this.treemapChartClicked.emit({ dataSource, symbol }); } catch {} @@ -357,10 +359,12 @@ export class GfTreemapChartComponent callbacks: { label: ({ raw }: GfTreemapTooltipItem) => { const allocationInPercentage = `${(raw._data.allocationInPercentage * 100).toFixed(2)}%`; - const name = raw._data.name; + const name = raw._data.assetProfile.name; + const sign = raw._data.netPerformancePercentWithCurrencyEffect > 0 ? '+' : ''; - const symbol = raw._data.symbol; + + const symbol = raw._data.assetProfile.symbol; const netPerformanceInPercentageWithSign = `${sign}${(raw._data.netPerformancePercentWithCurrencyEffect * 100).toFixed(2)}%`; From f82fbcfc5885f9e4992d43a0dcb33cf3cac4aaa1 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 15 May 2026 11:22:35 +0300 Subject: [PATCH 5/5] Bugfix/exception in portfolio details endpoint for unmatched asset profile (#6861) * Resolve exception in portfolio details endpoint when an asset profile is unmatched * Use asset profile identifier for value uniqueness * Update changelog --- CHANGELOG.md | 6 ++++ .../src/app/portfolio/current-rate.service.ts | 21 +++++++++--- .../src/app/portfolio/portfolio.service.ts | 34 ++++++++++++++++--- .../data-provider/data-provider.service.ts | 4 +++ 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f23e1af95..be6630ae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 + +### Fixed + +- Resolved an exception in the portfolio details endpoint when an asset profile is unmatched + ## 3.3.0 - 2026-05-14 ### Added diff --git a/apps/api/src/app/portfolio/current-rate.service.ts b/apps/api/src/app/portfolio/current-rate.service.ts index b454b01cd..f0a451975 100644 --- a/apps/api/src/app/portfolio/current-rate.service.ts +++ b/apps/api/src/app/portfolio/current-rate.service.ts @@ -2,7 +2,10 @@ import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.ser import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; -import { resetHours } from '@ghostfolio/common/helper'; +import { + getAssetProfileIdentifier, + resetHours +} from '@ghostfolio/common/helper'; import { AssetProfileIdentifier, DataProviderInfo, @@ -114,8 +117,8 @@ export class CurrentRateService { errors: quoteErrors.map(({ dataSource, symbol }) => { return { dataSource, symbol }; }), - values: uniqBy(values, ({ date, symbol }) => { - return `${date}-${symbol}`; + values: uniqBy(values, ({ dataSource, date, symbol }) => { + return `${date}-${getAssetProfileIdentifier({ dataSource, symbol })}`; }) }; @@ -124,7 +127,11 @@ export class CurrentRateService { try { // If missing quote, fallback to the latest available historical market price let value: GetValueObject = response.values.find((currentValue) => { - return currentValue.symbol === symbol && isToday(currentValue.date); + return ( + currentValue.dataSource === dataSource && + currentValue.symbol === symbol && + isToday(currentValue.date) + ); }); if (!value) { @@ -147,7 +154,11 @@ export class CurrentRateService { const [latestValue] = response.values .filter((currentValue) => { - return currentValue.symbol === symbol && currentValue.marketPrice; + return ( + currentValue.dataSource === dataSource && + currentValue.marketPrice && + currentValue.symbol === symbol + ); }) .sort((a, b) => { if (a.date < b.date) { diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 60b413cf9..ade683d41 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -36,7 +36,12 @@ import { TAG_ID_EXCLUDE_FROM_ANALYSIS, UNKNOWN_KEY } from '@ghostfolio/common/config'; -import { DATE_FORMAT, getSum, parseDate } from '@ghostfolio/common/helper'; +import { + DATE_FORMAT, + getAssetProfileIdentifier, + getSum, + parseDate +} from '@ghostfolio/common/helper'; import { AccountsResponse, Activity, @@ -64,7 +69,7 @@ import { } from '@ghostfolio/common/types'; import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, Logger } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { Account, @@ -558,9 +563,17 @@ export class PortfolioService { const cashSymbolProfiles = this.getCashSymbolProfiles(cashDetails); symbolProfiles.push(...cashSymbolProfiles); - const symbolProfileMap: { [symbol: string]: EnhancedSymbolProfile } = {}; + const symbolProfileMap: { + [assetProfileIdentifier: string]: EnhancedSymbolProfile; + } = {}; + for (const symbolProfile of symbolProfiles) { - symbolProfileMap[symbolProfile.symbol] = symbolProfile; + symbolProfileMap[ + getAssetProfileIdentifier({ + dataSource: symbolProfile.dataSource, + symbol: symbolProfile.symbol + }) + ] = symbolProfile; } const portfolioItemsNow: { [symbol: string]: TimelinePosition } = {}; @@ -571,6 +584,7 @@ export class PortfolioService { for (const { activitiesCount, currency, + dataSource, dateOfFirstActivity, dividend, grossPerformance, @@ -600,7 +614,17 @@ export class PortfolioService { } } - const assetProfile = symbolProfileMap[symbol]; + const assetProfile = + symbolProfileMap[getAssetProfileIdentifier({ dataSource, symbol })]; + + if (!assetProfile) { + Logger.warn( + `Asset profile not found for ${symbol} (${dataSource})`, + 'PortfolioService' + ); + + continue; + } let markets: PortfolioPosition['markets']; let marketsAdvanced: PortfolioPosition['marketsAdvanced']; diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index e7c7e8a2e..5f0a6928a 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -82,6 +82,7 @@ export class DataProviderService implements OnModuleInit { return false; } + // TODO: Change symbol in response to assetProfileIdentifier public async getAssetProfiles(items: AssetProfileIdentifier[]): Promise<{ [symbol: string]: Partial; }> { @@ -330,6 +331,7 @@ export class DataProviderService implements OnModuleInit { }); } + // TODO: Change symbol in response to assetProfileIdentifier public async getHistorical( aItems: AssetProfileIdentifier[], aGranularity: Granularity = 'month', @@ -395,6 +397,7 @@ export class DataProviderService implements OnModuleInit { } } + // TODO: Change symbol in response to assetProfileIdentifier public async getHistoricalRaw({ assetProfileIdentifiers, from, @@ -508,6 +511,7 @@ export class DataProviderService implements OnModuleInit { return result; } + // TODO: Change symbol in response to assetProfileIdentifier public async getQuotes({ items, requestTimeout,