Browse Source

optimize fetching from multiple data sources (#123)

* optimize fetching from multiple data sources

* improve performance by executing data gathering promises in parallel

* removed unused imports

* rename hasHistoricalData to canHandle
pull/107/head
Valentin Zickner 4 years ago
committed by Thomas
parent
commit
97961a7853
  1. 80
      apps/api/src/services/data-provider.service.ts
  2. 4
      apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts
  3. 9
      apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts
  4. 13
      apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts
  5. 4
      apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts
  6. 2
      apps/api/src/services/interfaces/data-provider.interface.ts

80
apps/api/src/services/data-provider.service.ts

@ -1,6 +1,4 @@
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
import { import {
isCrypto,
isGhostfolioScraperApiSymbol, isGhostfolioScraperApiSymbol,
isRakutenRapidApiSymbol isRakutenRapidApiSymbol
} from '@ghostfolio/common/helper'; } from '@ghostfolio/common/helper';
@ -132,73 +130,45 @@ export class DataProviderService implements DataProviderInterface {
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; [symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
} = {}; } = {};
const promises: Promise<{
data: { [date: string]: IDataProviderHistoricalResponse };
symbol: string;
}>[] = [];
for (const { dataSource, symbol } of aDataGatheringItems) { for (const { dataSource, symbol } of aDataGatheringItems) {
switch (dataSource) { const dataProvider = this.getDataProvider(dataSource);
case DataSource.ALPHA_VANTAGE: { if (dataProvider.canHandle(symbol)) {
if (this.configurationService.get('ALPHA_VANTAGE_API_KEY')) { promises.push(
const data = await this.alphaVantageService.getHistorical( dataProvider
[symbol], .getHistorical([symbol], undefined, from, to)
undefined, .then((data) => ({ data: data?.[symbol], symbol }))
from, );
to
);
result[symbol] = data?.[symbol];
}
break;
}
case DataSource.GHOSTFOLIO: {
if (isGhostfolioScraperApiSymbol(symbol)) {
const data = await this.ghostfolioScraperApiService.getHistorical(
[symbol],
undefined,
from,
to
);
result[symbol] = data?.[symbol];
}
break;
}
case DataSource.RAKUTEN: {
if (
isRakutenRapidApiSymbol(symbol) &&
this.configurationService.get('RAKUTEN_RAPID_API_KEY')
) {
const data = await this.rakutenRapidApiService.getHistorical(
[symbol],
undefined,
from,
to
);
result[symbol] = data?.[symbol];
}
break;
}
case DataSource.YAHOO: {
const data = await this.yahooFinanceService.getHistorical(
[symbol],
undefined,
from,
to
);
result[symbol] = data?.[symbol];
break;
}
} }
} }
const allData = await Promise.all(promises);
for (const { data, symbol } of allData) {
result[symbol] = data;
}
return result; return result;
} }
public async search(aSymbol: string) { public async search(aSymbol: string) {
return this.getDataProvider().search(aSymbol); return this.getDataProvider(
this.configurationService.get('DATA_SOURCES')[0]
).search(aSymbol);
} }
private getDataProvider() { private getDataProvider(providerName: DataSource) {
switch (this.configurationService.get('DATA_SOURCES')[0]) { switch (providerName) {
case DataSource.ALPHA_VANTAGE: case DataSource.ALPHA_VANTAGE:
return this.alphaVantageService; return this.alphaVantageService;
case DataSource.YAHOO: case DataSource.YAHOO:
return this.yahooFinanceService; return this.yahooFinanceService;
case DataSource.RAKUTEN:
return this.rakutenRapidApiService;
case DataSource.GHOSTFOLIO:
return this.ghostfolioScraperApiService;
default: default:
throw new Error('No data provider has been found.'); throw new Error('No data provider has been found.');
} }

4
apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts

@ -24,6 +24,10 @@ export class AlphaVantageService implements DataProviderInterface {
}); });
} }
public canHandle(symbol: string) {
return this.configurationService.get('ALPHA_VANTAGE_API_KEY');
}
public async get( public async get(
aSymbols: string[] aSymbols: string[]
): Promise<{ [symbol: string]: IDataProviderResponse }> { ): Promise<{ [symbol: string]: IDataProviderResponse }> {

9
apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts

@ -1,4 +1,7 @@
import { getYesterday } from '@ghostfolio/common/helper'; import {
getYesterday,
isGhostfolioScraperApiSymbol
} from '@ghostfolio/common/helper';
import { Granularity } from '@ghostfolio/common/types'; import { Granularity } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DataSource } from '@prisma/client'; import { DataSource } from '@prisma/client';
@ -21,6 +24,10 @@ export class GhostfolioScraperApiService implements DataProviderInterface {
public constructor(private prisma: PrismaService) {} public constructor(private prisma: PrismaService) {}
public canHandle(symbol: string) {
return isGhostfolioScraperApiSymbol(symbol);
}
public async get( public async get(
aSymbols: string[] aSymbols: string[]
): Promise<{ [symbol: string]: IDataProviderResponse }> { ): Promise<{ [symbol: string]: IDataProviderResponse }> {

13
apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts

@ -1,4 +1,8 @@
import { getToday, getYesterday } from '@ghostfolio/common/helper'; import {
getToday,
getYesterday,
isRakutenRapidApiSymbol
} from '@ghostfolio/common/helper';
import { Granularity } from '@ghostfolio/common/types'; import { Granularity } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DataSource } from '@prisma/client'; import { DataSource } from '@prisma/client';
@ -24,6 +28,13 @@ export class RakutenRapidApiService implements DataProviderInterface {
private readonly configurationService: ConfigurationService private readonly configurationService: ConfigurationService
) {} ) {}
public canHandle(symbol: string) {
return (
isRakutenRapidApiSymbol(symbol) &&
this.configurationService.get('RAKUTEN_RAPID_API_KEY')
);
}
public async get( public async get(
aSymbols: string[] aSymbols: string[]
): Promise<{ [symbol: string]: IDataProviderResponse }> { ): Promise<{ [symbol: string]: IDataProviderResponse }> {

4
apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts

@ -28,6 +28,10 @@ export class YahooFinanceService implements DataProviderInterface {
public constructor() {} public constructor() {}
public canHandle(symbol: string) {
return true;
}
public async get( public async get(
aSymbols: string[] aSymbols: string[]
): Promise<{ [symbol: string]: IDataProviderResponse }> { ): Promise<{ [symbol: string]: IDataProviderResponse }> {

2
apps/api/src/services/interfaces/data-provider.interface.ts

@ -7,6 +7,8 @@ import {
} from './interfaces'; } from './interfaces';
export interface DataProviderInterface { export interface DataProviderInterface {
canHandle(symbol: string): boolean;
get(aSymbols: string[]): Promise<{ [symbol: string]: IDataProviderResponse }>; get(aSymbols: string[]): Promise<{ [symbol: string]: IDataProviderResponse }>;
getHistorical( getHistorical(

Loading…
Cancel
Save