From bc33e5f147e624cc1e23ce84a09262243bb007a9 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 8 Sep 2023 20:43:23 +0200 Subject: [PATCH] Feature/remove deprecated environment variable base currency (#2255) * Remove the deprecated environment variable BASE_CURRENCY * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/admin/admin.service.ts | 17 +++---- apps/api/src/app/info/info.service.ts | 3 +- .../portfolio/current-rate.service.spec.ts | 1 - .../src/app/portfolio/portfolio.controller.ts | 14 +++--- .../src/app/portfolio/portfolio.service.ts | 13 ++--- apps/api/src/app/user/user.service.ts | 10 ++-- apps/api/src/main.ts | 10 ---- .../configuration/configuration.service.ts | 6 +-- .../coingecko/coingecko.service.ts | 21 +++----- .../yahoo-finance.service.spec.ts | 4 -- .../yahoo-finance/yahoo-finance.service.ts | 33 +++++-------- .../eod-historical-data.service.ts | 47 +++++++++--------- .../financial-modeling-prep.service.ts | 5 +- .../yahoo-finance/yahoo-finance.service.ts | 49 +++++++++---------- .../exchange-rate-data.service.ts | 34 ++++++------- .../interfaces/environment.interface.ts | 1 - 17 files changed, 109 insertions(+), 160 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6276d39bf..307c79272 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **Breaking Change**: Removed the deprecated environment variable `BASE_CURRENCY` - Improved the validation in the activities import - Deactivated _Internet Identity_ as a social login provider for the account registration - Improved the language localization for German (`de`) diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 7563909dd..b1b6b9418 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -6,7 +6,10 @@ import { MarketDataService } from '@ghostfolio/api/services/market-data/market-d import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; -import { PROPERTY_CURRENCIES } from '@ghostfolio/common/config'; +import { + DEFAULT_CURRENCY, + PROPERTY_CURRENCIES +} from '@ghostfolio/common/config'; import { AdminData, AdminMarketData, @@ -23,8 +26,6 @@ import { groupBy } from 'lodash'; @Injectable() export class AdminService { - private baseCurrency: string; - public constructor( private readonly configurationService: ConfigurationService, private readonly dataProviderService: DataProviderService, @@ -34,9 +35,7 @@ export class AdminService { private readonly propertyService: PropertyService, private readonly subscriptionService: SubscriptionService, private readonly symbolProfileService: SymbolProfileService - ) { - this.baseCurrency = this.configurationService.get('BASE_CURRENCY'); - } + ) {} public async addAssetProfile({ dataSource, @@ -80,15 +79,15 @@ export class AdminService { exchangeRates: this.exchangeRateDataService .getCurrencies() .filter((currency) => { - return currency !== this.baseCurrency; + return currency !== DEFAULT_CURRENCY; }) .map((currency) => { return { - label1: this.baseCurrency, + label1: DEFAULT_CURRENCY, label2: currency, value: this.exchangeRateDataService.toCurrency( 1, - this.baseCurrency, + DEFAULT_CURRENCY, currency ) }; diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index 59df59f0b..ec294bc25 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -7,6 +7,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate- import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { TagService } from '@ghostfolio/api/services/tag/tag.service'; import { + DEFAULT_CURRENCY, PROPERTY_BETTER_UPTIME_MONITOR_ID, PROPERTY_COUNTRIES_OF_SUBSCRIBERS, PROPERTY_DEMO_USER_ID, @@ -139,7 +140,7 @@ export class InfoService { subscriptions, systemMessage, tags, - baseCurrency: this.configurationService.get('BASE_CURRENCY'), + baseCurrency: DEFAULT_CURRENCY, currencies: this.exchangeRateDataService.getCurrencies() }; } diff --git a/apps/api/src/app/portfolio/current-rate.service.spec.ts b/apps/api/src/app/portfolio/current-rate.service.spec.ts index c9711aa7b..88790d2be 100644 --- a/apps/api/src/app/portfolio/current-rate.service.spec.ts +++ b/apps/api/src/app/portfolio/current-rate.service.spec.ts @@ -105,7 +105,6 @@ describe('CurrentRateService', () => { null, null, null, - null, null ); marketDataService = new MarketDataService(null); diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 93af43edb..ef6f3af99 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -10,7 +10,10 @@ import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interc import { ApiService } from '@ghostfolio/api/services/api/api.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; -import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config'; +import { + DEFAULT_CURRENCY, + HEADER_KEY_IMPERSONATION +} from '@ghostfolio/common/config'; import { PortfolioDetails, PortfolioDividends, @@ -47,8 +50,6 @@ import { PortfolioService } from './portfolio.service'; @Controller('portfolio') export class PortfolioController { - private baseCurrency: string; - public constructor( private readonly accessService: AccessService, private readonly apiService: ApiService, @@ -57,9 +58,7 @@ export class PortfolioController { private readonly portfolioService: PortfolioService, @Inject(REQUEST) private readonly request: RequestWithUser, private readonly userService: UserService - ) { - this.baseCurrency = this.configurationService.get('BASE_CURRENCY'); - } + ) {} @Get('details') @UseGuards(AuthGuard('jwt')) @@ -442,8 +441,7 @@ export class PortfolioController { return this.exchangeRateDataService.toCurrency( portfolioPosition.quantity * portfolioPosition.marketPrice, portfolioPosition.currency, - this.request.user?.Settings?.settings.baseCurrency ?? - this.baseCurrency + this.request.user?.Settings?.settings.baseCurrency ?? DEFAULT_CURRENCY ); }) .reduce((a, b) => a + b, 0); diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 466cec964..6deda49b7 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -11,12 +11,12 @@ import { AccountClusterRiskSingleAccount } from '@ghostfolio/api/models/rules/ac import { CurrencyClusterRiskBaseCurrencyCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/base-currency-current-investment'; import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/current-investment'; import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment'; -import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { + DEFAULT_CURRENCY, EMERGENCY_FUND_TAG_ID, MAX_CHART_ITEMS, UNKNOWN_KEY @@ -90,11 +90,8 @@ const europeMarkets = require('../../assets/countries/europe-markets.json'); @Injectable() export class PortfolioService { - private baseCurrency: string; - public constructor( private readonly accountService: AccountService, - private readonly configurationService: ConfigurationService, private readonly currentRateService: CurrentRateService, private readonly dataProviderService: DataProviderService, private readonly exchangeRateDataService: ExchangeRateDataService, @@ -104,9 +101,7 @@ export class PortfolioService { private readonly rulesService: RulesService, private readonly symbolProfileService: SymbolProfileService, private readonly userService: UserService - ) { - this.baseCurrency = this.configurationService.get('BASE_CURRENCY'); - } + ) {} public async getAccounts({ filters, @@ -1768,7 +1763,7 @@ export class PortfolioService { portfolioOrders: PortfolioOrder[]; }> { const userCurrency = - this.request.user?.Settings?.settings.baseCurrency ?? this.baseCurrency; + this.request.user?.Settings?.settings.baseCurrency ?? DEFAULT_CURRENCY; const orders = await this.orderService.getOrders({ filters, @@ -1990,7 +1985,7 @@ export class PortfolioService { return ( aUser.Settings?.settings.baseCurrency ?? this.request.user?.Settings?.settings.baseCurrency ?? - this.baseCurrency + DEFAULT_CURRENCY ); } diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 88f4bc0b1..c5cc3c8ce 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -25,17 +25,13 @@ const crypto = require('crypto'); @Injectable() export class UserService { - private baseCurrency: string; - public constructor( private readonly configurationService: ConfigurationService, private readonly prismaService: PrismaService, private readonly propertyService: PropertyService, private readonly subscriptionService: SubscriptionService, private readonly tagService: TagService - ) { - this.baseCurrency = this.configurationService.get('BASE_CURRENCY'); - } + ) {} public async count(args?: Prisma.UserCountArgs) { return this.prismaService.user.count(args); @@ -271,7 +267,7 @@ export class UserService { ...data, Account: { create: { - currency: this.baseCurrency, + currency: DEFAULT_CURRENCY, isDefault: true, name: 'Default Account' } @@ -279,7 +275,7 @@ export class UserService { Settings: { create: { settings: { - currency: this.baseCurrency + currency: DEFAULT_CURRENCY } } } diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index e0e7daf2f..016f82473 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -55,7 +55,6 @@ async function bootstrap() { app.use(HtmlTemplateMiddleware); - const BASE_CURRENCY = configService.get('BASE_CURRENCY'); const HOST = configService.get('HOST') || '0.0.0.0'; const PORT = configService.get('PORT') || 3333; @@ -63,15 +62,6 @@ async function bootstrap() { logLogo(); Logger.log(`Listening at http://${HOST}:${PORT}`); Logger.log(''); - - if (BASE_CURRENCY) { - Logger.warn( - `The environment variable "BASE_CURRENCY" is deprecated and will be removed in Ghostfolio 2.0.` - ); - Logger.warn( - 'Please use the currency converter in the activity dialog instead.' - ); - } }); } diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts index 54eedaa4d..40a04f5a0 100644 --- a/apps/api/src/services/configuration/configuration.service.ts +++ b/apps/api/src/services/configuration/configuration.service.ts @@ -1,5 +1,5 @@ import { Environment } from '@ghostfolio/api/services/interfaces/environment.interface'; -import { DEFAULT_CURRENCY, DEFAULT_ROOT_URL } from '@ghostfolio/common/config'; +import { DEFAULT_ROOT_URL } from '@ghostfolio/common/config'; import { Injectable } from '@nestjs/common'; import { DataSource } from '@prisma/client'; import { bool, cleanEnv, host, json, num, port, str } from 'envalid'; @@ -12,10 +12,6 @@ export class ConfigurationService { this.environmentConfiguration = cleanEnv(process.env, { ACCESS_TOKEN_SALT: str(), ALPHA_VANTAGE_API_KEY: str({ default: '' }), - BASE_CURRENCY: str({ - choices: ['AUD', 'CAD', 'CNY', 'EUR', 'GBP', 'JPY', 'RUB', 'USD'], - default: DEFAULT_CURRENCY - }), BETTER_UPTIME_API_KEY: str({ default: '' }), CACHE_QUOTES_TTL: num({ default: 1 }), CACHE_TTL: num({ default: 1 }), diff --git a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts index 492664393..56594ca40 100644 --- a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts +++ b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts @@ -1,10 +1,10 @@ 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 { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { DataProviderInfo } from '@ghostfolio/common/interfaces'; import { Granularity } from '@ghostfolio/common/types'; @@ -20,14 +20,9 @@ import got from 'got'; @Injectable() export class CoinGeckoService implements DataProviderInterface { - private baseCurrency: string; private readonly URL = 'https://api.coingecko.com/api/v3'; - public constructor( - private readonly configurationService: ConfigurationService - ) { - this.baseCurrency = this.configurationService.get('BASE_CURRENCY'); - } + public constructor() {} public canHandle(symbol: string) { return true; @@ -39,7 +34,7 @@ export class CoinGeckoService implements DataProviderInterface { const response: Partial = { assetClass: AssetClass.CASH, assetSubClass: AssetSubClass.CRYPTOCURRENCY, - currency: this.baseCurrency, + currency: DEFAULT_CURRENCY, dataSource: this.getName(), symbol: aSymbol }; @@ -81,7 +76,7 @@ export class CoinGeckoService implements DataProviderInterface { const { prices } = await got( `${ this.URL - }/coins/${aSymbol}/market_chart/range?vs_currency=${this.baseCurrency.toLowerCase()}&from=${getUnixTime( + }/coins/${aSymbol}/market_chart/range?vs_currency=${DEFAULT_CURRENCY.toLowerCase()}&from=${getUnixTime( from )}&to=${getUnixTime(to)}` ).json(); @@ -130,16 +125,16 @@ export class CoinGeckoService implements DataProviderInterface { const response = await got( `${this.URL}/simple/price?ids=${aSymbols.join( ',' - )}&vs_currencies=${this.baseCurrency.toLowerCase()}` + )}&vs_currencies=${DEFAULT_CURRENCY.toLowerCase()}` ).json(); for (const symbol in response) { if (Object.prototype.hasOwnProperty.call(response, symbol)) { results[symbol] = { - currency: this.baseCurrency, + currency: DEFAULT_CURRENCY, dataProviderInfo: this.getDataProviderInfo(), dataSource: DataSource.COINGECKO, - marketPrice: response[symbol][this.baseCurrency.toLowerCase()], + marketPrice: response[symbol][DEFAULT_CURRENCY.toLowerCase()], marketState: 'open' }; } @@ -175,7 +170,7 @@ export class CoinGeckoService implements DataProviderInterface { symbol, assetClass: AssetClass.CASH, assetSubClass: AssetSubClass.CRYPTOCURRENCY, - currency: this.baseCurrency, + currency: DEFAULT_CURRENCY, dataSource: this.getName() }; }); diff --git a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts index 951a623d0..8a8ab1f08 100644 --- a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts +++ b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts @@ -1,4 +1,3 @@ -import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { CryptocurrencyService } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service'; import { YahooFinanceDataEnhancerService } from './yahoo-finance.service'; @@ -26,16 +25,13 @@ jest.mock( ); describe('YahooFinanceDataEnhancerService', () => { - let configurationService: ConfigurationService; let cryptocurrencyService: CryptocurrencyService; let yahooFinanceDataEnhancerService: YahooFinanceDataEnhancerService; beforeAll(async () => { - configurationService = new ConfigurationService(); cryptocurrencyService = new CryptocurrencyService(); yahooFinanceDataEnhancerService = new YahooFinanceDataEnhancerService( - configurationService, cryptocurrencyService ); }); diff --git a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts index 725d85457..8731e709c 100644 --- a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts @@ -1,7 +1,6 @@ -import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { CryptocurrencyService } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service'; import { DataEnhancerInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-enhancer.interface'; -import { UNKNOWN_KEY } from '@ghostfolio/common/config'; +import { DEFAULT_CURRENCY, UNKNOWN_KEY } from '@ghostfolio/common/config'; import { isCurrency } from '@ghostfolio/common/helper'; import { Injectable, Logger } from '@nestjs/common'; import { @@ -17,23 +16,18 @@ import type { Price } from 'yahoo-finance2/dist/esm/src/modules/quoteSummary-ifa @Injectable() export class YahooFinanceDataEnhancerService implements DataEnhancerInterface { - private baseCurrency: string; - public constructor( - private readonly configurationService: ConfigurationService, private readonly cryptocurrencyService: CryptocurrencyService - ) { - this.baseCurrency = this.configurationService.get('BASE_CURRENCY'); - } + ) {} public convertFromYahooFinanceSymbol(aYahooFinanceSymbol: string) { let symbol = aYahooFinanceSymbol.replace( - new RegExp(`-${this.baseCurrency}$`), - this.baseCurrency + new RegExp(`-${DEFAULT_CURRENCY}$`), + DEFAULT_CURRENCY ); - if (symbol.includes('=X') && !symbol.includes(this.baseCurrency)) { - symbol = `${this.baseCurrency}${symbol}`; + if (symbol.includes('=X') && !symbol.includes(DEFAULT_CURRENCY)) { + symbol = `${DEFAULT_CURRENCY}${symbol}`; } return symbol.replace('=X', ''); @@ -48,21 +42,18 @@ export class YahooFinanceDataEnhancerService implements DataEnhancerInterface { */ public convertToYahooFinanceSymbol(aSymbol: string) { if ( - aSymbol.includes(this.baseCurrency) && - aSymbol.length > this.baseCurrency.length + aSymbol.includes(DEFAULT_CURRENCY) && + aSymbol.length > DEFAULT_CURRENCY.length ) { if ( isCurrency( - aSymbol.substring(0, aSymbol.length - this.baseCurrency.length) + aSymbol.substring(0, aSymbol.length - DEFAULT_CURRENCY.length) ) ) { return `${aSymbol}=X`; } else if ( this.cryptocurrencyService.isCryptocurrency( - aSymbol.replace( - new RegExp(`-${this.baseCurrency}$`), - this.baseCurrency - ) + aSymbol.replace(new RegExp(`-${DEFAULT_CURRENCY}$`), DEFAULT_CURRENCY) ) ) { // Add a dash before the last three characters @@ -70,8 +61,8 @@ export class YahooFinanceDataEnhancerService implements DataEnhancerInterface { // DOGEUSD -> DOGE-USD // SOL1USD -> SOL1-USD return aSymbol.replace( - new RegExp(`-?${this.baseCurrency}$`), - `-${this.baseCurrency}` + new RegExp(`-?${DEFAULT_CURRENCY}$`), + `-${DEFAULT_CURRENCY}` ); } } diff --git a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts index e0d77645e..fd8114ad6 100644 --- a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts +++ b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts @@ -5,7 +5,10 @@ import { IDataProviderHistoricalResponse, IDataProviderResponse } from '@ghostfolio/api/services/interfaces/interfaces'; -import { DEFAULT_REQUEST_TIMEOUT } from '@ghostfolio/common/config'; +import { + DEFAULT_CURRENCY, + DEFAULT_REQUEST_TIMEOUT +} from '@ghostfolio/common/config'; import { DATE_FORMAT, isCurrency } from '@ghostfolio/common/helper'; import { Granularity } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; @@ -22,14 +25,12 @@ import got from 'got'; @Injectable() export class EodHistoricalDataService implements DataProviderInterface { private apiKey: string; - private baseCurrency: string; private readonly URL = 'https://eodhistoricaldata.com/api'; public constructor( private readonly configurationService: ConfigurationService ) { this.apiKey = this.configurationService.get('EOD_HISTORICAL_DATA_API_KEY'); - this.baseCurrency = this.configurationService.get('BASE_CURRENCY'); } public canHandle(symbol: string) { @@ -175,7 +176,7 @@ export class EodHistoricalDataService implements DataProviderInterface { })?.currency; result[this.convertFromEodSymbol(code)] = { - currency: currency ?? this.baseCurrency, + currency: currency ?? DEFAULT_CURRENCY, dataSource: DataSource.EOD_HISTORICAL_DATA, marketPrice: close, marketState: isToday(new Date(timestamp * 1000)) ? 'open' : 'closed' @@ -186,24 +187,24 @@ export class EodHistoricalDataService implements DataProviderInterface { {} ); - if (response[`${this.baseCurrency}GBP`]) { - response[`${this.baseCurrency}GBp`] = { - ...response[`${this.baseCurrency}GBP`], - currency: `${this.baseCurrency}GBp`, + if (response[`${DEFAULT_CURRENCY}GBP`]) { + response[`${DEFAULT_CURRENCY}GBp`] = { + ...response[`${DEFAULT_CURRENCY}GBP`], + currency: `${DEFAULT_CURRENCY}GBp`, marketPrice: this.getConvertedValue({ - symbol: `${this.baseCurrency}GBp`, - value: response[`${this.baseCurrency}GBP`].marketPrice + symbol: `${DEFAULT_CURRENCY}GBp`, + value: response[`${DEFAULT_CURRENCY}GBP`].marketPrice }) }; } - if (response[`${this.baseCurrency}ILS`]) { - response[`${this.baseCurrency}ILA`] = { - ...response[`${this.baseCurrency}ILS`], - currency: `${this.baseCurrency}ILA`, + if (response[`${DEFAULT_CURRENCY}ILS`]) { + response[`${DEFAULT_CURRENCY}ILA`] = { + ...response[`${DEFAULT_CURRENCY}ILS`], + currency: `${DEFAULT_CURRENCY}ILA`, marketPrice: this.getConvertedValue({ - symbol: `${this.baseCurrency}ILA`, - value: response[`${this.baseCurrency}ILS`].marketPrice + symbol: `${DEFAULT_CURRENCY}ILA`, + value: response[`${DEFAULT_CURRENCY}ILS`].marketPrice }) }; } @@ -272,7 +273,7 @@ export class EodHistoricalDataService implements DataProviderInterface { if (symbol.endsWith('.FOREX')) { symbol = symbol.replace('GBX', 'GBp'); symbol = symbol.replace('.FOREX', ''); - symbol = `${this.baseCurrency}${symbol}`; + symbol = `${DEFAULT_CURRENCY}${symbol}`; } return symbol; @@ -285,17 +286,17 @@ export class EodHistoricalDataService implements DataProviderInterface { */ private convertToEodSymbol(aSymbol: string) { if ( - aSymbol.startsWith(this.baseCurrency) && - aSymbol.length > this.baseCurrency.length + aSymbol.startsWith(DEFAULT_CURRENCY) && + aSymbol.length > DEFAULT_CURRENCY.length ) { if ( isCurrency( - aSymbol.substring(0, aSymbol.length - this.baseCurrency.length) + aSymbol.substring(0, aSymbol.length - DEFAULT_CURRENCY.length) ) ) { return `${aSymbol .replace('GBp', 'GBX') - .replace(this.baseCurrency, '')}.FOREX`; + .replace(DEFAULT_CURRENCY, '')}.FOREX`; } } @@ -309,10 +310,10 @@ export class EodHistoricalDataService implements DataProviderInterface { symbol: string; value: number; }) { - if (symbol === `${this.baseCurrency}GBp`) { + if (symbol === `${DEFAULT_CURRENCY}GBp`) { // Convert GPB to GBp (pence) return new Big(value).mul(100).toNumber(); - } else if (symbol === `${this.baseCurrency}ILA`) { + } else if (symbol === `${DEFAULT_CURRENCY}ILA`) { // Convert ILS to ILA return new Big(value).mul(100).toNumber(); } 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 3d7ba65f4..c5d163456 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 @@ -5,6 +5,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 } from '@ghostfolio/common/interfaces'; import { Granularity } from '@ghostfolio/common/types'; @@ -16,7 +17,6 @@ import got from 'got'; @Injectable() export class FinancialModelingPrepService implements DataProviderInterface { private apiKey: string; - private baseCurrency: string; private readonly URL = 'https://financialmodelingprep.com/api/v3'; public constructor( @@ -25,7 +25,6 @@ export class FinancialModelingPrepService implements DataProviderInterface { this.apiKey = this.configurationService.get( 'FINANCIAL_MODELING_PREP_API_KEY' ); - this.baseCurrency = this.configurationService.get('BASE_CURRENCY'); } public canHandle(symbol: string) { @@ -117,7 +116,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { for (const { price, symbol } of response) { results[symbol] = { - currency: this.baseCurrency, + currency: DEFAULT_CURRENCY, dataProviderInfo: this.getDataProviderInfo(), dataSource: DataSource.FINANCIAL_MODELING_PREP, marketPrice: price, diff --git a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts index a525b4685..c7c0ebbc8 100644 --- a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts @@ -1,5 +1,4 @@ import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; -import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { CryptocurrencyService } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service'; import { YahooFinanceDataEnhancerService } from '@ghostfolio/api/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service'; import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; @@ -7,6 +6,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 { Granularity } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; @@ -18,15 +18,10 @@ import { Quote } from 'yahoo-finance2/dist/esm/src/modules/quote'; @Injectable() export class YahooFinanceService implements DataProviderInterface { - private baseCurrency: string; - public constructor( - private readonly configurationService: ConfigurationService, private readonly cryptocurrencyService: CryptocurrencyService, private readonly yahooFinanceDataEnhancerService: YahooFinanceDataEnhancerService - ) { - this.baseCurrency = this.configurationService.get('BASE_CURRENCY'); - } + ) {} public canHandle(symbol: string) { return true; @@ -212,50 +207,50 @@ export class YahooFinanceService implements DataProviderInterface { }; if ( - symbol === `${this.baseCurrency}GBP` && - yahooFinanceSymbols.includes(`${this.baseCurrency}GBp=X`) + symbol === `${DEFAULT_CURRENCY}GBP` && + yahooFinanceSymbols.includes(`${DEFAULT_CURRENCY}GBp=X`) ) { // Convert GPB to GBp (pence) - response[`${this.baseCurrency}GBp`] = { + response[`${DEFAULT_CURRENCY}GBp`] = { ...response[symbol], currency: 'GBp', marketPrice: this.getConvertedValue({ - symbol: `${this.baseCurrency}GBp`, + symbol: `${DEFAULT_CURRENCY}GBp`, value: response[symbol].marketPrice }) }; } else if ( - symbol === `${this.baseCurrency}ILS` && - yahooFinanceSymbols.includes(`${this.baseCurrency}ILA=X`) + symbol === `${DEFAULT_CURRENCY}ILS` && + yahooFinanceSymbols.includes(`${DEFAULT_CURRENCY}ILA=X`) ) { // Convert ILS to ILA - response[`${this.baseCurrency}ILA`] = { + response[`${DEFAULT_CURRENCY}ILA`] = { ...response[symbol], currency: 'ILA', marketPrice: this.getConvertedValue({ - symbol: `${this.baseCurrency}ILA`, + symbol: `${DEFAULT_CURRENCY}ILA`, value: response[symbol].marketPrice }) }; } else if ( - symbol === `${this.baseCurrency}ZAR` && - yahooFinanceSymbols.includes(`${this.baseCurrency}ZAc=X`) + symbol === `${DEFAULT_CURRENCY}ZAR` && + yahooFinanceSymbols.includes(`${DEFAULT_CURRENCY}ZAc=X`) ) { // Convert ZAR to ZAc (cents) - response[`${this.baseCurrency}ZAc`] = { + response[`${DEFAULT_CURRENCY}ZAc`] = { ...response[symbol], currency: 'ZAc', marketPrice: this.getConvertedValue({ - symbol: `${this.baseCurrency}ZAc`, + symbol: `${DEFAULT_CURRENCY}ZAc`, value: response[symbol].marketPrice }) }; } } - if (yahooFinanceSymbols.includes(`${this.baseCurrency}USX=X`)) { + if (yahooFinanceSymbols.includes(`${DEFAULT_CURRENCY}USX=X`)) { // Convert USD to USX (cent) - response[`${this.baseCurrency}USX`] = { + response[`${DEFAULT_CURRENCY}USX`] = { currency: 'USX', dataSource: this.getName(), marketPrice: new Big(1).mul(100).toNumber(), @@ -303,8 +298,8 @@ export class YahooFinanceService implements DataProviderInterface { (quoteType === 'CRYPTOCURRENCY' && this.cryptocurrencyService.isCryptocurrency( symbol.replace( - new RegExp(`-${this.baseCurrency}$`), - this.baseCurrency + new RegExp(`-${DEFAULT_CURRENCY}$`), + DEFAULT_CURRENCY ) )) || quoteTypes.includes(quoteType) @@ -314,7 +309,7 @@ export class YahooFinanceService implements DataProviderInterface { if (quoteType === 'CRYPTOCURRENCY') { // Only allow cryptocurrencies in base currency to avoid having redundancy in the database. // Transactions need to be converted manually to the base currency before - return symbol.includes(this.baseCurrency); + return symbol.includes(DEFAULT_CURRENCY); } else if (quoteType === 'FUTURE') { // Allow GC=F, but not MGC=F return symbol.length === 4; @@ -373,13 +368,13 @@ export class YahooFinanceService implements DataProviderInterface { symbol: string; value: number; }) { - if (symbol === `${this.baseCurrency}GBp`) { + if (symbol === `${DEFAULT_CURRENCY}GBp`) { // Convert GPB to GBp (pence) return new Big(value).mul(100).toNumber(); - } else if (symbol === `${this.baseCurrency}ILA`) { + } else if (symbol === `${DEFAULT_CURRENCY}ILA`) { // Convert ILS to ILA return new Big(value).mul(100).toNumber(); - } else if (symbol === `${this.baseCurrency}ZAc`) { + } else if (symbol === `${DEFAULT_CURRENCY}ZAc`) { // Convert ZAR to ZAc (cents) return new Big(value).mul(100).toNumber(); } diff --git a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts index 24b0ed5d0..376aa1a6a 100644 --- a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts +++ b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts @@ -1,10 +1,12 @@ -import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; -import { PROPERTY_CURRENCIES } from '@ghostfolio/common/config'; +import { + DEFAULT_CURRENCY, + PROPERTY_CURRENCIES +} from '@ghostfolio/common/config'; import { DATE_FORMAT, getYesterday } from '@ghostfolio/common/helper'; import { Injectable, Logger } from '@nestjs/common'; import { format, isToday } from 'date-fns'; @@ -12,13 +14,11 @@ import { isNumber, uniq } from 'lodash'; @Injectable() export class ExchangeRateDataService { - private baseCurrency: string; private currencies: string[] = []; private currencyPairs: IDataGatheringItem[] = []; private exchangeRates: { [currencyPair: string]: number } = {}; public constructor( - private readonly configurationService: ConfigurationService, private readonly dataProviderService: DataProviderService, private readonly marketDataService: MarketDataService, private readonly prismaService: PrismaService, @@ -26,7 +26,7 @@ export class ExchangeRateDataService { ) {} public getCurrencies() { - return this.currencies?.length > 0 ? this.currencies : [this.baseCurrency]; + return this.currencies?.length > 0 ? this.currencies : [DEFAULT_CURRENCY]; } public getCurrencyPairs() { @@ -43,7 +43,6 @@ export class ExchangeRateDataService { } public async initialize() { - this.baseCurrency = this.configurationService.get('BASE_CURRENCY'); this.currencies = await this.prepareCurrencies(); this.currencyPairs = []; this.exchangeRates = {}; @@ -113,9 +112,9 @@ export class ExchangeRateDataService { if (!this.exchangeRates[symbol]) { // Not found, calculate indirectly via base currency this.exchangeRates[symbol] = - resultExtended[`${currency1}${this.baseCurrency}`]?.[date] + resultExtended[`${currency1}${DEFAULT_CURRENCY}`]?.[date] ?.marketPrice * - resultExtended[`${this.baseCurrency}${currency2}`]?.[date] + resultExtended[`${DEFAULT_CURRENCY}${currency2}`]?.[date] ?.marketPrice; // Calculate the opposite direction @@ -144,9 +143,8 @@ export class ExchangeRateDataService { } else { // Calculate indirectly via base currency const factor1 = - this.exchangeRates[`${aFromCurrency}${this.baseCurrency}`]; - const factor2 = - this.exchangeRates[`${this.baseCurrency}${aToCurrency}`]; + this.exchangeRates[`${aFromCurrency}${DEFAULT_CURRENCY}`]; + const factor2 = this.exchangeRates[`${DEFAULT_CURRENCY}${aToCurrency}`]; factor = factor1 * factor2; @@ -204,28 +202,28 @@ export class ExchangeRateDataService { let marketPriceBaseCurrencyToCurrency: number; try { - if (this.baseCurrency === aFromCurrency) { + if (aFromCurrency === DEFAULT_CURRENCY) { marketPriceBaseCurrencyFromCurrency = 1; } else { marketPriceBaseCurrencyFromCurrency = ( await this.marketDataService.get({ dataSource, date: aDate, - symbol: `${this.baseCurrency}${aFromCurrency}` + symbol: `${DEFAULT_CURRENCY}${aFromCurrency}` }) )?.marketPrice; } } catch {} try { - if (this.baseCurrency === aToCurrency) { + if (aToCurrency === DEFAULT_CURRENCY) { marketPriceBaseCurrencyToCurrency = 1; } else { marketPriceBaseCurrencyToCurrency = ( await this.marketDataService.get({ dataSource, date: aDate, - symbol: `${this.baseCurrency}${aToCurrency}` + symbol: `${DEFAULT_CURRENCY}${aToCurrency}` }) )?.marketPrice; } @@ -295,14 +293,14 @@ export class ExchangeRateDataService { private prepareCurrencyPairs(aCurrencies: string[]) { return aCurrencies .filter((currency) => { - return currency !== this.baseCurrency; + return currency !== DEFAULT_CURRENCY; }) .map((currency) => { return { - currency1: this.baseCurrency, + currency1: DEFAULT_CURRENCY, currency2: currency, dataSource: this.dataProviderService.getDataSourceForExchangeRates(), - symbol: `${this.baseCurrency}${currency}` + symbol: `${DEFAULT_CURRENCY}${currency}` }; }); } diff --git a/apps/api/src/services/interfaces/environment.interface.ts b/apps/api/src/services/interfaces/environment.interface.ts index 88fa4c3f5..b437668ab 100644 --- a/apps/api/src/services/interfaces/environment.interface.ts +++ b/apps/api/src/services/interfaces/environment.interface.ts @@ -3,7 +3,6 @@ import { CleanedEnvAccessors } from 'envalid'; export interface Environment extends CleanedEnvAccessors { ACCESS_TOKEN_SALT: string; ALPHA_VANTAGE_API_KEY: string; - BASE_CURRENCY: string; BETTER_UPTIME_API_KEY: string; CACHE_QUOTES_TTL: number; CACHE_TTL: number;