From bf8856ad19adf3b6ab966cc8f088ed7a02bad7c7 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 6 Sep 2021 22:02:49 +0200 Subject: [PATCH] Bugfix/fix search for cryptocurrencies (#348) * Fix the search for cryptocurrency symbols * Update changelog --- CHANGELOG.md | 6 + .../data-provider/data-provider.service.ts | 8 +- .../yahoo-finance/yahoo-finance.service.ts | 109 ++++++++---------- 3 files changed, 63 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 407828358..60ae7b416 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed + +- Fixed the search functionality for cryptocurrency symbols + ## 1.46.0 - 05.09.2021 ### Added 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 81c8982cc..04331f05e 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -19,7 +19,10 @@ import { format } from 'date-fns'; import { AlphaVantageService } from './alpha-vantage/alpha-vantage.service'; import { GhostfolioScraperApiService } from './ghostfolio-scraper-api/ghostfolio-scraper-api.service'; import { RakutenRapidApiService } from './rakuten-rapid-api/rakuten-rapid-api.service'; -import { YahooFinanceService } from './yahoo-finance/yahoo-finance.service'; +import { + convertToYahooFinanceSymbol, + YahooFinanceService +} from './yahoo-finance/yahoo-finance.service'; @Injectable() export class DataProviderService { @@ -44,6 +47,9 @@ export class DataProviderService { return this.ghostfolioScraperApiService.get(aSymbols); } else if (isRakutenRapidApiSymbol(symbol)) { return this.rakutenRapidApiService.get(aSymbols); + } else { + const yahooFinanceSymbol = convertToYahooFinanceSymbol(symbol); + return this.yahooFinanceService.get([yahooFinanceSymbol]); } } 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 418687b17..5383d6c28 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 @@ -43,16 +43,12 @@ export class YahooFinanceService implements DataProviderInterface { } public async get( - aSymbols: string[] + aYahooFinanceSymbols: string[] ): Promise<{ [symbol: string]: IDataProviderResponse }> { - if (aSymbols.length <= 0) { + if (aYahooFinanceSymbols.length <= 0) { return {}; } - const yahooSymbols = aSymbols.map((symbol) => { - return this.convertToYahooSymbol(symbol); - }); - try { const response: { [symbol: string]: IDataProviderResponse } = {}; @@ -60,12 +56,12 @@ export class YahooFinanceService implements DataProviderInterface { [symbol: string]: IYahooFinanceQuoteResponse; } = await yahooFinance.quote({ modules: ['price', 'summaryProfile'], - symbols: yahooSymbols + symbols: aYahooFinanceSymbols }); - for (const [yahooSymbol, value] of Object.entries(data)) { + for (const [yahooFinanceSymbol, value] of Object.entries(data)) { // Convert symbols back - const symbol = convertFromYahooSymbol(yahooSymbol); + const symbol = convertFromYahooFinanceSymbol(yahooFinanceSymbol); const { assetClass, assetSubClass } = this.parseAssetClass(value.price); @@ -136,15 +132,15 @@ export class YahooFinanceService implements DataProviderInterface { return {}; } - const yahooSymbols = aSymbols.map((symbol) => { - return this.convertToYahooSymbol(symbol); + const yahooFinanceSymbols = aSymbols.map((symbol) => { + return convertToYahooFinanceSymbol(symbol); }); try { const historicalData: { [symbol: string]: IYahooFinanceHistoricalResponse[]; } = await yahooFinance.historical({ - symbols: yahooSymbols, + symbols: yahooFinanceSymbols, from: format(from, DATE_FORMAT), to: format(to, DATE_FORMAT) }); @@ -153,9 +149,11 @@ export class YahooFinanceService implements DataProviderInterface { [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; } = {}; - for (const [yahooSymbol, timeSeries] of Object.entries(historicalData)) { + for (const [yahooFinanceSymbol, timeSeries] of Object.entries( + historicalData + )) { // Convert symbols back - const symbol = convertFromYahooSymbol(yahooSymbol); + const symbol = convertFromYahooFinanceSymbol(yahooFinanceSymbol); response[symbol] = {}; timeSeries.forEach((timeSerie) => { @@ -175,7 +173,7 @@ export class YahooFinanceService implements DataProviderInterface { } public async search(aSymbol: string): Promise<{ items: LookupItem[] }> { - let items: LookupItem[] = []; + const items: LookupItem[] = []; try { const get = bent( @@ -192,19 +190,6 @@ export class YahooFinanceService implements DataProviderInterface { // filter out undefined symbols return quote.symbol; }) - .filter(({ quoteType }) => { - return quoteType === 'EQUITY' || quoteType === 'ETF'; - }) - .map(({ symbol }) => { - return symbol; - }); - - const marketData = await this.get(symbols); - - items = searchResult.quotes - .filter((quote) => { - return quote.isYahooFinance; - }) .filter(({ quoteType }) => { return ( quoteType === 'CRYPTOCURRENCY' || @@ -220,40 +205,23 @@ export class YahooFinanceService implements DataProviderInterface { return true; }) - .map(({ longname, shortname, symbol }) => { - return { - currency: marketData[symbol]?.currency, - dataSource: DataSource.YAHOO, - name: longname || shortname, - symbol: convertFromYahooSymbol(symbol) - }; + .map(({ symbol }) => { + return symbol; }); - } catch {} - return { items }; - } + const marketData = await this.get(symbols); - /** - * Converts a symbol to a Yahoo symbol - * - * Currency: USDCHF=X - * Cryptocurrency: BTC-USD - */ - private convertToYahooSymbol(aSymbol: string) { - if (isCurrency(aSymbol)) { - if (isCrypto(aSymbol)) { - // Add a dash before the last three characters - // BTCUSD -> BTC-USD - // DOGEUSD -> DOGE-USD - return `${aSymbol.substring(0, aSymbol.length - 3)}-${aSymbol.substring( - aSymbol.length - 3 - )}`; + for (const [symbol, value] of Object.entries(marketData)) { + items.push({ + symbol, + currency: value.currency, + dataSource: DataSource.YAHOO, + name: value.name + }); } + } catch {} - return `${aSymbol}=X`; - } - - return aSymbol; + return { items }; } private parseAssetClass(aPrice: IYahooFinancePrice): { @@ -290,7 +258,30 @@ export class YahooFinanceService implements DataProviderInterface { } } -export const convertFromYahooSymbol = (aSymbol: string) => { - const symbol = aSymbol.replace('-', ''); +export const convertFromYahooFinanceSymbol = (aYahooFinanceSymbol: string) => { + const symbol = aYahooFinanceSymbol.replace('-', ''); return symbol.replace('=X', ''); }; + +/** + * Converts a symbol to a Yahoo Finance symbol + * + * Currency: USDCHF=X + * Cryptocurrency: BTC-USD + */ +export const convertToYahooFinanceSymbol = (aSymbol: string) => { + if (isCurrency(aSymbol)) { + if (isCrypto(aSymbol)) { + // Add a dash before the last three characters + // BTCUSD -> BTC-USD + // DOGEUSD -> DOGE-USD + return `${aSymbol.substring(0, aSymbol.length - 3)}-${aSymbol.substring( + aSymbol.length - 3 + )}`; + } + + return `${aSymbol}=X`; + } + + return aSymbol; +};