Refactor custom cryptocurrencies (#433)

This commit is contained in:
Thomas Kaul 2021-10-21 22:11:12 +02:00 committed by GitHub
parent e24e5e1c44
commit 19e2d54791
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 65 additions and 31 deletions

View File

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
### Added
- Added support for more cryptocurrency symbols like _Avalanche_, _Polygon_, _SHIBA INU_ etc.
### Changed ### Changed
- Changed the data provider service to handle a dynamic list of services - Changed the data provider service to handle a dynamic list of services

View File

@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { CryptocurrencyService } from './cryptocurrency.service';
@Module({
providers: [CryptocurrencyService],
exports: [CryptocurrencyService]
})
export class CryptocurrencyModule {}

View File

@ -0,0 +1,28 @@
import { Injectable } from '@nestjs/common';
const cryptocurrencies = require('cryptocurrencies');
const customCryptocurrencies = require('./custom-cryptocurrencies.json');
@Injectable()
export class CryptocurrencyService {
private combinedCryptocurrencies: string[];
public constructor() {}
public isCrypto(aSymbol = '') {
const cryptocurrencySymbol = aSymbol.substring(0, aSymbol.length - 3);
return this.getCryptocurrencies().includes(cryptocurrencySymbol);
}
private getCryptocurrencies() {
if (!this.combinedCryptocurrencies) {
this.combinedCryptocurrencies = [
...cryptocurrencies.symbols(),
...Object.keys(customCryptocurrencies)
];
}
return this.combinedCryptocurrencies;
}
}

View File

@ -0,0 +1,6 @@
{
"1INCH": "1inch",
"AVAX": "Avalanche",
"MATIC": "Polygon",
"SHIB": "Shiba Inu"
}

View File

@ -1,4 +1,5 @@
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
import { CryptocurrencyModule } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.module';
import { TrackinsightDataEnhancerService } from '@ghostfolio/api/services/data-provider/data-enhancer/trackinsight/trackinsight.service'; import { TrackinsightDataEnhancerService } from '@ghostfolio/api/services/data-provider/data-enhancer/trackinsight/trackinsight.service';
import { GhostfolioScraperApiService } from '@ghostfolio/api/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service'; import { GhostfolioScraperApiService } from '@ghostfolio/api/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service';
import { RakutenRapidApiService } from '@ghostfolio/api/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service'; import { RakutenRapidApiService } from '@ghostfolio/api/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service';
@ -10,7 +11,7 @@ import { AlphaVantageService } from './alpha-vantage/alpha-vantage.service';
import { DataProviderService } from './data-provider.service'; import { DataProviderService } from './data-provider.service';
@Module({ @Module({
imports: [ConfigurationModule, PrismaModule], imports: [ConfigurationModule, CryptocurrencyModule, PrismaModule],
providers: [ providers: [
AlphaVantageService, AlphaVantageService,
DataProviderService, DataProviderService,

View File

@ -1,6 +1,7 @@
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { DataEnhancerInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-enhancer.interface'; import { DataEnhancerInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-enhancer.interface';
import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface';
import { import {
IDataGatheringItem, IDataGatheringItem,
IDataProviderHistoricalResponse, IDataProviderHistoricalResponse,
@ -13,7 +14,6 @@ import { Inject, Injectable } from '@nestjs/common';
import { DataSource, MarketData } from '@prisma/client'; import { DataSource, MarketData } from '@prisma/client';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface';
@Injectable() @Injectable()
export class DataProviderService { export class DataProviderService {

View File

@ -1,11 +1,11 @@
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
import { Granularity } from '@ghostfolio/common/types'; import { Granularity } from '@ghostfolio/common/types';
import { DataSource } from '@prisma/client';
import { import {
IDataProviderHistoricalResponse, IDataProviderHistoricalResponse,
IDataProviderResponse IDataProviderResponse
} from '../../interfaces/interfaces'; } from '../../interfaces/interfaces';
import { DataSource } from '@prisma/client';
export interface DataProviderInterface { export interface DataProviderInterface {
canHandle(symbol: string): boolean; canHandle(symbol: string): boolean;

View File

@ -1,6 +1,7 @@
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
import { CryptocurrencyService } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service';
import { UNKNOWN_KEY } from '@ghostfolio/common/config'; import { UNKNOWN_KEY } from '@ghostfolio/common/config';
import { DATE_FORMAT, isCrypto, isCurrency } from '@ghostfolio/common/helper'; import { DATE_FORMAT, isCurrency } 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 { AssetClass, AssetSubClass, DataSource } from '@prisma/client'; import { AssetClass, AssetSubClass, DataSource } from '@prisma/client';
@ -26,7 +27,9 @@ import {
export class YahooFinanceService implements DataProviderInterface { export class YahooFinanceService implements DataProviderInterface {
private yahooFinanceHostname = 'https://query1.finance.yahoo.com'; private yahooFinanceHostname = 'https://query1.finance.yahoo.com';
public constructor() {} public constructor(
private readonly cryptocurrencyService: CryptocurrencyService
) {}
public canHandle(symbol: string) { public canHandle(symbol: string) {
return true; return true;
@ -65,7 +68,8 @@ export class YahooFinanceService implements DataProviderInterface {
dataSource: DataSource.YAHOO, dataSource: DataSource.YAHOO,
exchange: this.parseExchange(value.price?.exchangeName), exchange: this.parseExchange(value.price?.exchangeName),
marketState: marketState:
value.price?.marketState === 'REGULAR' || isCrypto(symbol) value.price?.marketState === 'REGULAR' ||
this.cryptocurrencyService.isCrypto(symbol)
? MarketState.open ? MarketState.open
: MarketState.closed, : MarketState.closed,
marketPrice: value.price?.regularMarketPrice || 0, marketPrice: value.price?.regularMarketPrice || 0,
@ -249,7 +253,10 @@ export class YahooFinanceService implements DataProviderInterface {
) { ) {
if (isCurrency(aSymbol.substring(0, aSymbol.length - 3))) { if (isCurrency(aSymbol.substring(0, aSymbol.length - 3))) {
return `${aSymbol}=X`; return `${aSymbol}=X`;
} else if (isCrypto(aSymbol) || isCrypto(aSymbol.replace('1', ''))) { } else if (
this.cryptocurrencyService.isCrypto(aSymbol) ||
this.cryptocurrencyService.isCrypto(aSymbol.replace('1', ''))
) {
// Add a dash before the last three characters // Add a dash before the last three characters
// BTCUSD -> BTC-USD // BTCUSD -> BTC-USD
// DOGEUSD -> DOGE-USD // DOGEUSD -> DOGE-USD

View File

@ -1,11 +0,0 @@
{
"SHIB": "SHIBA INU USD",
"SOL1": "Solana",
"DOT1": "Polkadot",
"LUNA1": "Terra",
"AVAX": "Avalanche",
"MATIC": "MaticNetwork",
"ATOM1": "Cosmos",
"FTT1": "FTXToken",
"1INCH": "1inch"
}

View File

@ -3,11 +3,6 @@ import { getDate, getMonth, getYear, parse, subDays } from 'date-fns';
import { ghostfolioScraperApiSymbolPrefix } from './config'; import { ghostfolioScraperApiSymbolPrefix } from './config';
const cryptocurrencies = require('cryptocurrencies');
const customSymbolList = require('./customCryptocurrencies.json')
customSymbolList.symbols = () => Object.keys(customSymbolList);
export const DEMO_USER_ID = '9b112b4d-3b7d-4bad-9bdd-3b0f7b4dac2f'; export const DEMO_USER_ID = '9b112b4d-3b7d-4bad-9bdd-3b0f7b4dac2f';
export function capitalize(aString: string) { export function capitalize(aString: string) {
@ -53,9 +48,9 @@ export function getUtc(aDateString: string) {
return new Date( return new Date(
Date.UTC( Date.UTC(
parseInt(yearString), parseInt(yearString, 10),
parseInt(monthString) - 1, parseInt(monthString, 10) - 1,
parseInt(dayString) parseInt(dayString, 10)
) )
); );
} }
@ -82,11 +77,6 @@ export function groupBy<T, K extends keyof T>(
return map; return map;
} }
export function isCrypto(aSymbol = '') {
const cryptocurrencySymbol = aSymbol.substring(0, aSymbol.length - 3);
return cryptocurrencies.symbols().includes(cryptocurrencySymbol) || customSymbolList.symbols().includes(cryptocurrencySymbol);
}
export function isCurrency(aSymbol = '') { export function isCurrency(aSymbol = '') {
return currencies[aSymbol]; return currencies[aSymbol];
} }