diff --git a/CHANGELOG.md b/CHANGELOG.md index 039c54432..4ed0c80a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added support for commodities (via futures) + +### Changed + +- Upgraded `yahoo-finance2` from version `2.3.1` to `2.3.2` + ### Fixed - Fixed the import validation for numbers equal 0 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 b5d8e1ebd..3d07c833b 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 @@ -20,10 +20,7 @@ import Big from 'big.js'; import { countries } from 'countries-list'; import { addDays, format, isSameDay } from 'date-fns'; import yahooFinance from 'yahoo-finance2'; -import type { - Price, - QuoteSummaryResult -} from 'yahoo-finance2/dist/esm/src/modules/quoteSummary-iface'; +import type { Price } from 'yahoo-finance2/dist/esm/src/modules/quoteSummary-iface'; @Injectable() export class YahooFinanceService implements DataProviderInterface { @@ -92,7 +89,12 @@ export class YahooFinanceService implements DataProviderInterface { response.assetSubClass = assetSubClass; response.currency = assetProfile.price.currency; response.dataSource = this.getName(); - response.name = this.formatName(assetProfile); + response.name = this.formatName({ + longName: assetProfile.price.longName, + quoteType: assetProfile.price.quoteType, + shortName: assetProfile.price.shortName, + symbol: assetProfile.price.symbol + }); response.symbol = aSymbol; if ( @@ -247,7 +249,7 @@ export class YahooFinanceService implements DataProviderInterface { const quotes = searchResult.quotes .filter((quote) => { - // filter out undefined symbols + // Filter out undefined symbols return quote.symbol; }) .filter(({ quoteType, symbol }) => { @@ -256,7 +258,7 @@ export class YahooFinanceService implements DataProviderInterface { this.cryptocurrencyService.isCryptocurrency( symbol.replace(new RegExp(`-${baseCurrency}$`), baseCurrency) )) || - ['EQUITY', 'ETF', 'MUTUALFUND'].includes(quoteType) + ['EQUITY', 'ETF', 'FUTURE', 'MUTUALFUND'].includes(quoteType) ); }) .filter(({ quoteType, symbol }) => { @@ -264,6 +266,9 @@ export class YahooFinanceService implements DataProviderInterface { // 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(baseCurrency); + } else if (quoteType === 'FUTURE') { + // Allow GC=F, but not MGC=F + return symbol.length === 4; } return true; @@ -288,7 +293,12 @@ export class YahooFinanceService implements DataProviderInterface { symbol, currency: marketDataItem.currency, dataSource: this.getName(), - name: quote?.longname || quote?.shortname || symbol + name: this.formatName({ + longName: quote.longname, + quoteType: quote.quoteType, + shortName: quote.shortname, + symbol: quote.symbol + }) }); } } catch (error) { @@ -298,8 +308,18 @@ export class YahooFinanceService implements DataProviderInterface { return { items }; } - private formatName(aAssetProfile: QuoteSummaryResult) { - let name = aAssetProfile.price.longName; + private formatName({ + longName, + quoteType, + shortName, + symbol + }: { + longName: Price['longName']; + quoteType: Price['quoteType']; + shortName: Price['shortName']; + symbol: Price['symbol']; + }) { + let name = longName; if (name) { name = name.replace('iShares ETF (CH) - ', ''); @@ -314,7 +334,12 @@ export class YahooFinanceService implements DataProviderInterface { name = name.replace('Xtrackers (IE) Plc - ', ''); } - return name || aAssetProfile.price.shortName || aAssetProfile.price.symbol; + if (quoteType === 'FUTURE') { + // "Gold Jun 22" -> "Gold" + name = shortName?.slice(0, -6); + } + + return name || shortName || symbol; } private parseAssetClass(aPrice: Price): { @@ -337,6 +362,10 @@ export class YahooFinanceService implements DataProviderInterface { assetClass = AssetClass.EQUITY; assetSubClass = AssetSubClass.ETF; break; + case 'future': + assetClass = AssetClass.COMMODITY; + assetSubClass = AssetSubClass.COMMODITY; + break; case 'mutualfund': assetClass = AssetClass.EQUITY; assetSubClass = AssetSubClass.MUTUALFUND; diff --git a/package.json b/package.json index 9749f12d9..27b5210ac 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "tslib": "2.0.0", "twitter-api-v2": "1.10.3", "uuid": "8.3.2", - "yahoo-finance2": "2.3.1", + "yahoo-finance2": "2.3.2", "zone.js": "0.11.4" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 250fbd811..de5b59b06 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18836,10 +18836,10 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yahoo-finance2@2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/yahoo-finance2/-/yahoo-finance2-2.3.1.tgz#d2cffbef78f6974e4e6a40487cc08ab133dc9fc5" - integrity sha512-QTXiiWgfrpVbSylchBgLqESZz+8+SyyDSqntjfZHxMIHa6d14xq+biNNDIeYd5SylcZ9Vt4zLmZXHN7EdLM1pA== +yahoo-finance2@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/yahoo-finance2/-/yahoo-finance2-2.3.2.tgz#3643b5e14f752b1d5546427d760d515401ac2ac7" + integrity sha512-xOBaamD/mXN9ruc3TBOEhEIhP/N+efWo/wQf2PyYtB6N68iSGZVDt+4vdJN7ra+iCVq7FnSHTDH3K4Cvqy63lQ== dependencies: ajv "8.10.0" ajv-formats "2.1.1"