Browse Source

Bugfix/handling of indices in FMP service (#7738)

* Improve handling of indices

* Update changelog
pull/7743/head
Thomas Kaul 1 day ago
committed by GitHub
parent
commit
21e78b3982
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      CHANGELOG.md
  2. 108
      apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts

4
CHANGELOG.md

@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Consolidated the duplicated translations of the asset classes and asset sub classes - Consolidated the duplicated translations of the asset classes and asset sub classes
### Fixed
- Improved the handling of indices in the _Financial Modeling Prep_ service
## 3.62.0 - 2026-08-27 ## 3.62.0 - 2026-08-27
### Added ### Added

108
apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts

@ -142,9 +142,18 @@ export class FinancialModelingPrepService
.then((res) => res.json()); .then((res) => res.json());
if (!assetProfile) { if (!assetProfile) {
throw new AssetProfileDelistedError( const indexProfile = await this.getIndexProfile({
`No data found, ${symbol} (${this.getName()}) may be delisted` requestTimeout,
); symbol
});
if (!indexProfile) {
throw new AssetProfileDelistedError(
`No data found, ${symbol} (${this.getName()}) may be delisted`
);
}
return { ...response, ...indexProfile };
} }
const { assetClass, assetSubClass } = const { assetClass, assetSubClass } =
@ -582,28 +591,17 @@ export class FinancialModelingPrepService
}; };
}); });
} else { } else {
const queryParams = new URLSearchParams({
query,
apikey: this.apiKey
});
const [nameResults, symbolResults] = await Promise.all([ const [nameResults, symbolResults] = await Promise.all([
this.fetchService this.getSearchResults({
.fetch( query,
`${this.getUrl({ version: 'stable' })}/search-name?${queryParams.toString()}`, requestTimeout,
{ endpoint: 'search-name'
signal: AbortSignal.timeout(requestTimeout) }),
} this.getSearchResults({
) query,
.then((res) => res.json()), requestTimeout,
this.fetchService endpoint: 'search-symbol'
.fetch( })
`${this.getUrl({ version: 'stable' })}/search-symbol?${queryParams.toString()}`,
{
signal: AbortSignal.timeout(requestTimeout)
}
)
.then((res) => res.json())
]); ]);
const result = uniqBy( const result = uniqBy(
@ -615,10 +613,9 @@ export class FinancialModelingPrepService
items = result items = result
.filter(({ exchange, symbol }) => { .filter(({ exchange, symbol }) => {
if ( const isIndex = exchange === 'INDEX' || symbol.startsWith('^');
exchange === 'FOREX' ||
(includeIndices === false && symbol.startsWith('^')) if (exchange === 'FOREX' || (includeIndices === false && isIndex)) {
) {
return false; return false;
} }
@ -663,6 +660,61 @@ export class FinancialModelingPrepService
return name; return name;
} }
/**
* Financial Modeling Prep has no profile for an index, thus the currency and
* the name are taken from the search endpoint.
*/
private async getIndexProfile({
requestTimeout,
symbol
}: {
requestTimeout: number;
symbol: string;
}): Promise<Pick<SymbolProfile, 'currency' | 'name'>> {
const results = await this.getSearchResults({
requestTimeout,
endpoint: 'search-symbol',
query: symbol
});
const index = results?.find(({ exchange, symbol: symbolOfResult }) => {
return exchange === 'INDEX' && symbolOfResult === symbol;
});
if (!index) {
return undefined;
}
return {
currency: index.currency,
name: this.formatName({ name: index.name })
};
}
private async getSearchResults({
endpoint,
query,
requestTimeout
}: {
endpoint: 'search-name' | 'search-symbol';
query: string;
requestTimeout: number;
}) {
const queryParams = new URLSearchParams({
query,
apikey: this.apiKey
});
return this.fetchService
.fetch(
`${this.getUrl({ version: 'stable' })}/${endpoint}?${queryParams.toString()}`,
{
signal: AbortSignal.timeout(requestTimeout)
}
)
.then((res) => res.json());
}
private getUrl({ version }: { version: number | 'stable' }) { private getUrl({ version }: { version: number | 'stable' }) {
const baseUrl = 'https://financialmodelingprep.com'; const baseUrl = 'https://financialmodelingprep.com';

Loading…
Cancel
Save