diff --git a/CHANGELOG.md b/CHANGELOG.md index fed801e1d..ec3023c2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added `FINANCIAL_MODELING_PREP` as a new data source type + ### Changed - Improved the market price on the first buy date in the chart of the position detail dialog diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts index eed51d1a8..fa1255fc2 100644 --- a/apps/api/src/services/configuration/configuration.service.ts +++ b/apps/api/src/services/configuration/configuration.service.ts @@ -29,6 +29,7 @@ export class ConfigurationService { ENABLE_FEATURE_SUBSCRIPTION: bool({ default: false }), ENABLE_FEATURE_SYSTEM_MESSAGE: bool({ default: false }), EOD_HISTORICAL_DATA_API_KEY: str({ default: '' }), + FINANCIAL_MODELING_PREP_API_KEY: str({ default: '' }), GOOGLE_CLIENT_ID: str({ default: 'dummyClientId' }), GOOGLE_SECRET: str({ default: 'dummySecret' }), GOOGLE_SHEETS_ACCOUNT: str({ default: '' }), diff --git a/apps/api/src/services/data-provider/data-provider.module.ts b/apps/api/src/services/data-provider/data-provider.module.ts index 9164b0c0b..3ba678631 100644 --- a/apps/api/src/services/data-provider/data-provider.module.ts +++ b/apps/api/src/services/data-provider/data-provider.module.ts @@ -3,6 +3,7 @@ import { CryptocurrencyModule } from '@ghostfolio/api/services/cryptocurrency/cr import { AlphaVantageService } from '@ghostfolio/api/services/data-provider/alpha-vantage/alpha-vantage.service'; import { CoinGeckoService } from '@ghostfolio/api/services/data-provider/coingecko/coingecko.service'; import { EodHistoricalDataService } from '@ghostfolio/api/services/data-provider/eod-historical-data/eod-historical-data.service'; +import { FinancialModelingPrepService } from '@ghostfolio/api/services/data-provider/financial-modeling-prep/financial-modeling-prep.service'; import { GoogleSheetsService } from '@ghostfolio/api/services/data-provider/google-sheets/google-sheets.service'; import { ManualService } from '@ghostfolio/api/services/data-provider/manual/manual.service'; import { RapidApiService } from '@ghostfolio/api/services/data-provider/rapid-api/rapid-api.service'; @@ -32,6 +33,7 @@ import { DataProviderService } from './data-provider.service'; CoinGeckoService, DataProviderService, EodHistoricalDataService, + FinancialModelingPrepService, GoogleSheetsService, ManualService, RapidApiService, @@ -41,6 +43,7 @@ import { DataProviderService } from './data-provider.service'; AlphaVantageService, CoinGeckoService, EodHistoricalDataService, + FinancialModelingPrepService, GoogleSheetsService, ManualService, RapidApiService, @@ -51,6 +54,7 @@ import { DataProviderService } from './data-provider.service'; alphaVantageService, coinGeckoService, eodHistoricalDataService, + financialModelingPrepService, googleSheetsService, manualService, rapidApiService, @@ -59,6 +63,7 @@ import { DataProviderService } from './data-provider.service'; alphaVantageService, coinGeckoService, eodHistoricalDataService, + financialModelingPrepService, googleSheetsService, manualService, rapidApiService, 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 472001db5..387c71be2 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -399,7 +399,10 @@ export class DataProviderService { } private isPremiumDataSource(aDataSource: DataSource) { - const premiumDataSources: DataSource[] = [DataSource.EOD_HISTORICAL_DATA]; + const premiumDataSources: DataSource[] = [ + DataSource.EOD_HISTORICAL_DATA, + DataSource.FINANCIAL_MODELING_PREP + ]; return premiumDataSources.includes(aDataSource); } } 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 new file mode 100644 index 000000000..d4fe3325b --- /dev/null +++ b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts @@ -0,0 +1,121 @@ +import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; +import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; +import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; +import { + IDataProviderHistoricalResponse, + IDataProviderResponse +} from '@ghostfolio/api/services/interfaces/interfaces'; +import { DataProviderInfo } from '@ghostfolio/common/interfaces'; +import { Granularity } from '@ghostfolio/common/types'; +import { Injectable, Logger } from '@nestjs/common'; +import { DataSource, SymbolProfile } from '@prisma/client'; +import bent from 'bent'; + +@Injectable() +export class FinancialModelingPrepService implements DataProviderInterface { + private apiKey: string; + private baseCurrency: string; + private readonly URL = 'https://financialmodelingprep.com/api/v3'; + + public constructor( + private readonly configurationService: ConfigurationService + ) { + this.apiKey = this.configurationService.get( + 'FINANCIAL_MODELING_PREP_API_KEY' + ); + this.baseCurrency = this.configurationService.get('BASE_CURRENCY'); + } + + public canHandle(symbol: string) { + return true; + } + + public async getAssetProfile( + aSymbol: string + ): Promise> { + return { + dataSource: this.getName(), + symbol: aSymbol + }; + } + + public async getDividends({ + from, + granularity = 'day', + symbol, + to + }: { + from: Date; + granularity: Granularity; + symbol: string; + to: Date; + }) { + return {}; + } + + public async getHistorical( + aSymbol: string, + aGranularity: Granularity = 'day', + from: Date, + to: Date + ): Promise<{ + [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; + }> { + return { + [aSymbol]: {} + }; + } + + public getName(): DataSource { + return DataSource.FINANCIAL_MODELING_PREP; + } + + public async getQuotes( + aSymbols: string[] + ): Promise<{ [symbol: string]: IDataProviderResponse }> { + const results: { [symbol: string]: IDataProviderResponse } = {}; + + if (aSymbols.length <= 0) { + return {}; + } + + try { + const get = bent( + `${this.URL}/quote/${aSymbols.join(',')}?apikey=${this.apiKey}`, + 'GET', + 'json', + 200 + ); + const response = await get(); + + for (const { price, symbol } of response) { + results[symbol] = { + currency: this.baseCurrency, + dataProviderInfo: this.getDataProviderInfo(), + dataSource: DataSource.FINANCIAL_MODELING_PREP, + marketPrice: price, + marketState: 'delayed' + }; + } + } catch (error) { + Logger.error(error, 'FinancialModelingPrepService'); + } + + return results; + } + + public getTestSymbol() { + return 'AAPL'; + } + + public async search(aQuery: string): Promise<{ items: LookupItem[] }> { + return { items: [] }; + } + + private getDataProviderInfo(): DataProviderInfo { + return { + name: 'Financial Modeling Prep', + url: 'https://financialmodelingprep.com/developer/docs' + }; + } +} diff --git a/apps/api/src/services/interfaces/environment.interface.ts b/apps/api/src/services/interfaces/environment.interface.ts index 586f19997..841309566 100644 --- a/apps/api/src/services/interfaces/environment.interface.ts +++ b/apps/api/src/services/interfaces/environment.interface.ts @@ -16,6 +16,7 @@ export interface Environment extends CleanedEnvAccessors { ENABLE_FEATURE_SUBSCRIPTION: boolean; ENABLE_FEATURE_SYSTEM_MESSAGE: boolean; EOD_HISTORICAL_DATA_API_KEY: string; + FINANCIAL_MODELING_PREP_API_KEY: string; GOOGLE_CLIENT_ID: string; GOOGLE_SECRET: string; GOOGLE_SHEETS_ACCOUNT: string; diff --git a/prisma/migrations/20230511070258_added_financial_modeling_prep_to_data_source/migration.sql b/prisma/migrations/20230511070258_added_financial_modeling_prep_to_data_source/migration.sql new file mode 100644 index 000000000..1005e6730 --- /dev/null +++ b/prisma/migrations/20230511070258_added_financial_modeling_prep_to_data_source/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "DataSource" ADD VALUE 'FINANCIAL_MODELING_PREP'; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d74a7ae54..cb6749929 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -209,6 +209,7 @@ enum DataSource { ALPHA_VANTAGE COINGECKO EOD_HISTORICAL_DATA + FINANCIAL_MODELING_PREP GOOGLE_SHEETS MANUAL RAPID_API