From 4d201acdbe8ce4b8b79c31ed065aad2937d475ae Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 19 Jan 2025 09:39:05 +0100 Subject: [PATCH] Feature/extend get dividends in financial modeling prep service (#4210) * Extend get dividends * Update changelog --- CHANGELOG.md | 3 +- .../financial-modeling-prep.service.ts | 71 +++++++++++++++++-- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d3a23dc4..9b9c31586 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Extended the asset profile data in the _Financial Modeling Prep_ service -- Extended the search by `isin` in the _Financial Modeling Prep_ service +- Extended the _Financial Modeling Prep_ service - Switched to _ESLint_’s flat config format - Upgraded `chart.js` from version `4.2.0` to `4.4.7` - Upgraded `chartjs-chart-treemap` from version `2.3.1` to `3.1.0` 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 af8a9e9a2..386bcc8d4 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 @@ -11,6 +11,7 @@ import { IDataProviderHistoricalResponse, IDataProviderResponse } from '@ghostfolio/api/services/interfaces/interfaces'; +import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper'; import { DataProviderInfo, @@ -27,7 +28,14 @@ import { } from '@prisma/client'; import { isISIN } from 'class-validator'; import { countries } from 'countries-list'; -import { format, isAfter, isBefore, isSameDay } from 'date-fns'; +import { + addDays, + format, + isAfter, + isBefore, + isSameDay, + parseISO +} from 'date-fns'; @Injectable() export class FinancialModelingPrepService implements DataProviderInterface { @@ -58,7 +66,10 @@ export class FinancialModelingPrepService implements DataProviderInterface { }; try { - if (this.cryptocurrencyService.isCryptocurrency(symbol)) { + if ( + symbol.endsWith(DEFAULT_CURRENCY) && + this.cryptocurrencyService.isCryptocurrency(symbol) + ) { const [quote] = await fetch( `${this.URL}/quote/${symbol}?apikey=${this.apiKey}`, { @@ -208,8 +219,54 @@ export class FinancialModelingPrepService implements DataProviderInterface { }; } - public async getDividends({}: GetDividendsParams) { - return {}; + public async getDividends({ + from, + requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'), + symbol, + to + }: GetDividendsParams) { + if (isSameDay(from, to)) { + to = addDays(to, 1); + } + + try { + const response: { + [date: string]: IDataProviderHistoricalResponse; + } = {}; + + const { historical } = await fetch( + `${this.URL}/historical-price-full/stock_dividend/${symbol}?apikey=${this.apiKey}`, + { + signal: AbortSignal.timeout(requestTimeout) + } + ).then((res) => res.json()); + + historical + .filter(({ date }) => { + return ( + (isSameDay(parseISO(date), from) || + isAfter(parseISO(date), from)) && + isBefore(parseISO(date), to) + ); + }) + .forEach(({ adjDividend, date }) => { + response[date] = { + marketPrice: adjDividend + }; + }); + + return response; + } catch (error) { + Logger.error( + `Could not get dividends for ${symbol} (${this.getName()}) from ${format( + from, + DATE_FORMAT + )} to ${format(to, DATE_FORMAT)}: [${error.name}] ${error.message}`, + 'FinancialModelingPrepService' + ); + + return {}; + } } public async getHistorical({ @@ -234,14 +291,14 @@ export class FinancialModelingPrepService implements DataProviderInterface { [symbol]: {} }; - for (const { close, date } of historical) { + for (const { adjClose, date } of historical) { if ( (isSameDay(parseDate(date), from) || isAfter(parseDate(date), from)) && isBefore(parseDate(date), to) ) { result[symbol][date] = { - marketPrice: close + marketPrice: adjClose }; } } @@ -375,7 +432,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { return `https://financialmodelingprep.com/api/v${version}`; } - public parseAssetClass(profile: any): { + private parseAssetClass(profile: any): { assetClass: AssetClass; assetSubClass: AssetSubClass; } {