From 650d51f4a79a460d1c0b3d5c0837f5ba05f23fdd Mon Sep 17 00:00:00 2001 From: Thomas <4159106+dtslvr@users.noreply.github.com> Date: Wed, 15 Mar 2023 21:09:52 +0100 Subject: [PATCH] Extend EodHistoricalDataService * asset and asset sub class * symbol mapping (ISIN) --- .../src/services/data-gathering.service.ts | 12 ++- .../eod-historical-data.service.ts | 93 +++++++++++++++++-- 2 files changed, 93 insertions(+), 12 deletions(-) diff --git a/apps/api/src/services/data-gathering.service.ts b/apps/api/src/services/data-gathering.service.ts index d3843456d..7eb84a20a 100644 --- a/apps/api/src/services/data-gathering.service.ts +++ b/apps/api/src/services/data-gathering.service.ts @@ -127,9 +127,11 @@ export class DataGatheringService { ); for (const [symbol, assetProfile] of Object.entries(assetProfiles)) { - const symbolMapping = symbolProfiles.find((symbolProfile) => { - return symbolProfile.symbol === symbol; - })?.symbolMapping; + const symbolMapping = + assetProfile.symbolMapping ?? + symbolProfiles.find((symbolProfile) => { + return symbolProfile.symbol === symbol; + })?.symbolMapping; for (const dataEnhancer of this.dataEnhancers) { try { @@ -155,7 +157,7 @@ export class DataGatheringService { name, sectors, url - } = assetProfiles[symbol]; + } = assetProfile; try { await this.prismaService.symbolProfile.upsert({ @@ -168,6 +170,7 @@ export class DataGatheringService { name, sectors, symbol, + symbolMapping, url }, update: { @@ -177,6 +180,7 @@ export class DataGatheringService { currency, name, sectors, + symbolMapping, url }, where: { 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 a39100d1f..a7b0d45bd 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 @@ -8,7 +8,12 @@ import { import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { Granularity } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; -import { DataSource, SymbolProfile } from '@prisma/client'; +import { + AssetClass, + AssetSubClass, + DataSource, + SymbolProfile +} from '@prisma/client'; import bent from 'bent'; import { format, isToday } from 'date-fns'; @@ -30,12 +35,21 @@ export class EodHistoricalDataService implements DataProviderInterface { public async getAssetProfile( aSymbol: string ): Promise> { - const { items } = await this.search(aSymbol); + const [searchResult] = await this.getSearchResult(aSymbol); + + const symbolMapping = searchResult?.ISIN + ? { + ISIN: searchResult.ISIN + } + : undefined; return { - currency: items[0]?.currency, + symbolMapping, + assetClass: searchResult?.assetClass, + assetSubClass: searchResult?.assetSubClass, + currency: searchResult?.currency, dataSource: this.getName(), - name: items[0]?.name + name: searchResult?.name }; } @@ -156,7 +170,27 @@ export class EodHistoricalDataService implements DataProviderInterface { } public async search(aQuery: string): Promise<{ items: LookupItem[] }> { - let items: LookupItem[] = []; + const searchResult = await this.getSearchResult(aQuery); + + return { + items: searchResult + .filter(({ symbol }) => { + return !symbol.toLowerCase().endsWith('forex'); + }) + .map(({ currency, dataSource, name, symbol }) => { + return { currency, dataSource, name, symbol }; + }) + }; + } + + private async getSearchResult(aQuery: string): Promise< + (LookupItem & { + assetClass: AssetClass; + assetSubClass: AssetSubClass; + ISIN: string; + })[] + > { + let searchResult = []; try { const get = bent( @@ -167,10 +201,18 @@ export class EodHistoricalDataService implements DataProviderInterface { ); const response = await get(); - items = response.map( - ({ Code, Currency: currency, Exchange, Name: name }) => { + searchResult = response.map( + ({ Code, Currency: currency, Exchange, ISIN, Name: name, Type }) => { + const { assetClass, assetSubClass } = this.parseAssetClass({ + Exchange, + Type + }); + return { + assetClass, + assetSubClass, currency, + ISIN, name, dataSource: this.getName(), symbol: `${Code}.${Exchange}` @@ -181,6 +223,41 @@ export class EodHistoricalDataService implements DataProviderInterface { Logger.error(error, 'EodHistoricalDataService'); } - return { items }; + return searchResult; + } + + private parseAssetClass({ + Exchange, + Type + }: { + Exchange: string; + Type: string; + }): { + assetClass: AssetClass; + assetSubClass: AssetSubClass; + } { + let assetClass: AssetClass; + let assetSubClass: AssetSubClass; + + switch (Type?.toLowerCase()) { + case 'common stock': + assetClass = AssetClass.EQUITY; + assetSubClass = AssetSubClass.STOCK; + break; + case 'currency': + assetClass = AssetClass.CASH; + + if (Exchange?.toLowerCase() === 'cc') { + assetSubClass = AssetSubClass.CRYPTOCURRENCY; + } + + break; + case 'etf': + assetClass = AssetClass.EQUITY; + assetSubClass = AssetSubClass.ETF; + break; + } + + return { assetClass, assetSubClass }; } }