From b6f87e46a73ecb2781a20648cda823c13c7c0b4d Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Fri, 18 Apr 2025 14:41:55 +0200
Subject: [PATCH] Bugfix/fix asset class parsing in Financial Modeling Prep
 service for exchange rates (#4559)

* Fix the asset class parsing

* Update changelog
---
 CHANGELOG.md                                  |  1 +
 .../alpha-vantage/alpha-vantage.service.ts    |  5 ++-
 .../financial-modeling-prep.service.ts        | 41 +++++++++++++------
 3 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2b3171dc..0597a2e4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Fixed
 
 - Fixed the functionality to open an asset profile of a custom currency in the admin control panel
+- Fixed the asset class parsing in the _Financial Modeling Prep_ service for exchange rates
 
 ## 2.152.1 - 2025-04-17
 
diff --git a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts
index 606e6b7f..f9593f0d 100644
--- a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts
+++ b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts
@@ -11,6 +11,7 @@ import {
   IDataProviderHistoricalResponse,
   IDataProviderResponse
 } from '@ghostfolio/api/services/interfaces/interfaces';
+import { DEFAULT_CURRENCY } from '@ghostfolio/common/config';
 import { DATE_FORMAT } from '@ghostfolio/common/helper';
 import {
   DataProviderInfo,
@@ -72,7 +73,9 @@ export class AlphaVantageService implements DataProviderInterface {
       const historicalData: {
         [symbol: string]: IAlphaVantageHistoricalResponse[];
       } = await this.alphaVantage.crypto.daily(
-        symbol.substring(0, symbol.length - 3).toLowerCase(),
+        symbol
+          .substring(0, symbol.length - DEFAULT_CURRENCY.length)
+          .toLowerCase(),
         'usd'
       );
 
diff --git a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts
index d6eaec07..32aff438 100644
--- a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts
+++ b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts
@@ -12,8 +12,11 @@ import {
   IDataProviderHistoricalResponse,
   IDataProviderResponse
 } from '@ghostfolio/api/services/interfaces/interfaces';
-import { REPLACE_NAME_PARTS } from '@ghostfolio/common/config';
-import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper';
+import {
+  DEFAULT_CURRENCY,
+  REPLACE_NAME_PARTS
+} from '@ghostfolio/common/config';
+import { DATE_FORMAT, isCurrency, parseDate } from '@ghostfolio/common/helper';
 import {
   DataProviderInfo,
   LookupItem,
@@ -67,7 +70,15 @@ export class FinancialModelingPrepService implements DataProviderInterface {
     };
 
     try {
-      if (this.cryptocurrencyService.isCryptocurrency(symbol)) {
+      if (
+        isCurrency(symbol.substring(0, symbol.length - DEFAULT_CURRENCY.length))
+      ) {
+        response.assetClass = AssetClass.LIQUIDITY;
+        response.assetSubClass = AssetSubClass.CASH;
+        response.currency = symbol.substring(
+          symbol.length - DEFAULT_CURRENCY.length
+        );
+      } else if (this.cryptocurrencyService.isCryptocurrency(symbol)) {
         const [quote] = await fetch(
           `${this.URL}/quote/${symbol}?apikey=${this.apiKey}`,
           {
@@ -77,7 +88,9 @@ export class FinancialModelingPrepService implements DataProviderInterface {
 
         response.assetClass = AssetClass.LIQUIDITY;
         response.assetSubClass = AssetSubClass.CRYPTOCURRENCY;
-        response.currency = symbol.substring(symbol.length - 3);
+        response.currency = symbol.substring(
+          symbol.length - DEFAULT_CURRENCY.length
+        );
         response.name = quote.name;
       } else {
         const [assetProfile] = await fetch(
@@ -472,15 +485,17 @@ export class FinancialModelingPrepService implements DataProviderInterface {
     let assetClass: AssetClass;
     let assetSubClass: AssetSubClass;
 
-    if (profile.isEtf) {
-      assetClass = AssetClass.EQUITY;
-      assetSubClass = AssetSubClass.ETF;
-    } else if (profile.isFund) {
-      assetClass = AssetClass.EQUITY;
-      assetSubClass = AssetSubClass.MUTUALFUND;
-    } else {
-      assetClass = AssetClass.EQUITY;
-      assetSubClass = AssetSubClass.STOCK;
+    if (profile) {
+      if (profile.isEtf) {
+        assetClass = AssetClass.EQUITY;
+        assetSubClass = AssetSubClass.ETF;
+      } else if (profile.isFund) {
+        assetClass = AssetClass.EQUITY;
+        assetSubClass = AssetSubClass.MUTUALFUND;
+      } else {
+        assetClass = AssetClass.EQUITY;
+        assetSubClass = AssetSubClass.STOCK;
+      }
     }
 
     return { assetClass, assetSubClass };