| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -5,11 +5,13 @@ import { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  IDataProviderHistoricalResponse, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  IDataProviderResponse | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} from '@ghostfolio/api/services/interfaces/interfaces'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { DataProviderInfo } from '@ghostfolio/common/interfaces'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { Granularity } from '@ghostfolio/common/types'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { Injectable, Logger } from '@nestjs/common'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { DataSource, SymbolProfile } from '@prisma/client'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import bent from 'bent'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					import { format, isAfter, isBefore, isSameDay } from 'date-fns'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					@Injectable() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					export class FinancialModelingPrepService implements DataProviderInterface { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -61,9 +63,42 @@ export class FinancialModelingPrepService implements DataProviderInterface { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  ): Promise<{ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  }> { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      [aSymbol]: {} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    try { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      const get = bent( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        `${this.URL}/historical-price-full/${aSymbol}?apikey=${this.apiKey}`, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        'GET', | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        'json', | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        200 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      const { historical } = await get(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      const result: { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        [symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      } = { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        [aSymbol]: {} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      for (const { close, date } of historical) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        if ( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          (isSameDay(parseDate(date), from) || | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            isAfter(parseDate(date), from)) && | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          isBefore(parseDate(date), to) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        ) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          result[aSymbol][date] = { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            marketPrice: close | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      return result; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } catch (error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      throw new Error( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        `Could not get historical market data for ${aSymbol} (${this.getName()}) from ${format( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          from, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          DATE_FORMAT | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        )} to ${format(to, DATE_FORMAT)}: [${error.name}] ${error.message}` | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public getName(): DataSource { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -109,7 +144,32 @@ export class FinancialModelingPrepService implements DataProviderInterface { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  public async search(aQuery: string): Promise<{ items: LookupItem[] }> { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return { items: [] }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    let items: LookupItem[] = []; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    try { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      const get = bent( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        `${this.URL}/search?query=${aQuery}&apikey=${this.apiKey}`, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        'GET', | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        'json', | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        200 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      ); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      const result = await get(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      items = result.map(({ currency, name, symbol }) => { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        return { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          // TODO: Add assetClass
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          // TODO: Add assetSubClass
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          currency, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          name, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          symbol, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					          dataSource: this.getName() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      }); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } catch (error) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					      Logger.error(error, 'FinancialModelingPrepService'); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return { items }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					  private getDataProviderInfo(): DataProviderInfo { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
  |