Browse Source

Set up Ghostfolio data provider

pull/4016/head
Thomas Kaul 9 months ago
parent
commit
e1b2c60add
  1. 8
      apps/api/src/app/endpoints/data-providers/ghostfolio/get-historical.dto.ts
  2. 1
      apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts
  3. 27
      apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts
  4. 52
      apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts

8
apps/api/src/app/endpoints/data-providers/ghostfolio/get-historical.dto.ts

@ -1,9 +1,15 @@
import { IsISO8601 } from 'class-validator'; import { Granularity } from '@ghostfolio/common/types';
import { IsIn, IsISO8601, IsOptional } from 'class-validator';
export class GetHistoricalDto { export class GetHistoricalDto {
@IsISO8601() @IsISO8601()
from: string; from: string;
@IsIn(['day', 'month'] as Granularity[])
@IsOptional()
granularity: Granularity;
@IsISO8601() @IsISO8601()
to: string; to: string;
} }

1
apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts

@ -56,6 +56,7 @@ export class GhostfolioController {
const historicalData = await this.ghostfolioService.getHistorical({ const historicalData = await this.ghostfolioService.getHistorical({
symbol, symbol,
from: parseDate(query.from), from: parseDate(query.from),
granularity: query.granularity,
to: parseDate(query.to) to: parseDate(query.to)
}); });

27
apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.service.ts

@ -1,5 +1,10 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import {
GetHistoricalParams,
GetQuotesParams,
GetSearchParams
} from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface';
import { IDataProviderHistoricalResponse } from '@ghostfolio/api/services/interfaces/interfaces'; import { IDataProviderHistoricalResponse } from '@ghostfolio/api/services/interfaces/interfaces';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service';
@ -31,15 +36,11 @@ export class GhostfolioService {
public async getHistorical({ public async getHistorical({
from, from,
granularity,
requestTimeout, requestTimeout,
to, to,
symbol symbol
}: { }: GetHistoricalParams) {
from: Date;
requestTimeout?: number;
symbol: string;
to: Date;
}) {
const result: HistoricalResponse = { historicalData: {} }; const result: HistoricalResponse = { historicalData: {} };
try { try {
@ -52,6 +53,7 @@ export class GhostfolioService {
dataProviderService dataProviderService
.getHistorical({ .getHistorical({
from, from,
granularity,
requestTimeout, requestTimeout,
symbol, symbol,
to to
@ -83,13 +85,7 @@ export class GhostfolioService {
); );
} }
public async getQuotes({ public async getQuotes({ requestTimeout, symbols }: GetQuotesParams) {
requestTimeout,
symbols
}: {
requestTimeout?: number;
symbols: string[];
}) {
const promises: Promise<any>[] = []; const promises: Promise<any>[] = [];
const results: QuotesResponse = { quotes: {} }; const results: QuotesResponse = { quotes: {} };
@ -180,10 +176,7 @@ export class GhostfolioService {
public async lookup({ public async lookup({
includeIndices = false, includeIndices = false,
query query
}: { }: GetSearchParams): Promise<LookupResponse> {
includeIndices?: boolean;
query: string;
}): Promise<LookupResponse> {
const results: LookupResponse = { items: [] }; const results: LookupResponse = { items: [] };
if (!query) { if (!query) {

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

@ -13,14 +13,17 @@ import {
} from '@ghostfolio/api/services/interfaces/interfaces'; } from '@ghostfolio/api/services/interfaces/interfaces';
import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { PROPERTY_API_KEY_GHOSTFOLIO } from '@ghostfolio/common/config'; import { PROPERTY_API_KEY_GHOSTFOLIO } from '@ghostfolio/common/config';
import { DATE_FORMAT } from '@ghostfolio/common/helper';
import { import {
DataProviderInfo, DataProviderInfo,
HistoricalResponse,
LookupResponse, LookupResponse,
QuotesResponse QuotesResponse
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import { DataSource, SymbolProfile } from '@prisma/client'; import { DataSource, SymbolProfile } from '@prisma/client';
import { format } from 'date-fns';
import got from 'got'; import got from 'got';
@Injectable() @Injectable()
@ -52,9 +55,16 @@ export class GhostfolioService implements DataProviderInterface {
}: { }: {
symbol: string; symbol: string;
}): Promise<Partial<SymbolProfile>> { }): Promise<Partial<SymbolProfile>> {
const { items } = await this.search({ query: symbol });
const searchResult = items?.[0];
return { return {
symbol, symbol,
dataSource: this.getName() assetClass: searchResult?.assetClass,
assetSubClass: searchResult?.assetSubClass,
currency: searchResult?.currency,
dataSource: this.getName(),
name: searchResult?.name
}; };
} }
@ -70,11 +80,45 @@ export class GhostfolioService implements DataProviderInterface {
return {}; return {};
} }
public async getHistorical({}: GetHistoricalParams): Promise<{ public async getHistorical({
from,
granularity = 'day',
requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'),
symbol,
to
}: GetHistoricalParams): Promise<{
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; [symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
}> { }> {
// TODO try {
return {}; const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const { historicalData } = await got(
`${this.URL}/v1/data-providers/ghostfolio/historical/${symbol}?from=${format(from, DATE_FORMAT)}&granularity=${granularity}&to=${format(
to,
DATE_FORMAT
)}`,
{
headers: this.getRequestHeaders(),
// @ts-ignore
signal: abortController.signal
}
).json<HistoricalResponse>();
return {
[symbol]: historicalData
};
} catch (error) {
throw new Error(
`Could not get historical market data for ${symbol} (${this.getName()}) from ${format(
from,
DATE_FORMAT
)} to ${format(to, DATE_FORMAT)}: [${error.name}] ${error.message}`
);
}
} }
public getMaxNumberOfSymbolsPerRequest() { public getMaxNumberOfSymbolsPerRequest() {

Loading…
Cancel
Save