| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -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,15 @@ export class EodHistoricalDataService implements DataProviderInterface { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public async getAssetProfile( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    aSymbol: string | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ): Promise<Partial<SymbolProfile>> { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const { items } = await this.search(aSymbol); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const [searchResult] = await this.getSearchResult(aSymbol); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      currency: items[0]?.currency, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      assetClass: searchResult?.assetClass, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      assetSubClass: searchResult?.assetSubClass, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      currency: searchResult?.currency, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      dataSource: this.getName(), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      name: items[0]?.name | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      isin: searchResult?.isin, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      name: searchResult?.name | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -156,7 +164,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 +195,25 @@ 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: 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 +224,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 }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
					 | 
				
				 | 
				
					
  |