Refactor custom cryptocurrencies (#433)
This commit is contained in:
parent
e24e5e1c44
commit
19e2d54791
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for more cryptocurrency symbols like _Avalanche_, _Polygon_, _SHIBA INU_ etc.
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed the data provider service to handle a dynamic list of services
|
||||
|
@ -0,0 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { CryptocurrencyService } from './cryptocurrency.service';
|
||||
|
||||
@Module({
|
||||
providers: [CryptocurrencyService],
|
||||
exports: [CryptocurrencyService]
|
||||
})
|
||||
export class CryptocurrencyModule {}
|
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"1INCH": "1inch",
|
||||
"AVAX": "Avalanche",
|
||||
"MATIC": "Polygon",
|
||||
"SHIB": "Shiba Inu"
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
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 { 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';
|
||||
@ -10,7 +11,7 @@ import { AlphaVantageService } from './alpha-vantage/alpha-vantage.service';
|
||||
import { DataProviderService } from './data-provider.service';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigurationModule, PrismaModule],
|
||||
imports: [ConfigurationModule, CryptocurrencyModule, PrismaModule],
|
||||
providers: [
|
||||
AlphaVantageService,
|
||||
DataProviderService,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
|
||||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
||||
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 {
|
||||
IDataGatheringItem,
|
||||
IDataProviderHistoricalResponse,
|
||||
@ -13,7 +14,6 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { DataSource, MarketData } from '@prisma/client';
|
||||
import { format } from 'date-fns';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface';
|
||||
|
||||
@Injectable()
|
||||
export class DataProviderService {
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
|
||||
import { Granularity } from '@ghostfolio/common/types';
|
||||
import { DataSource } from '@prisma/client';
|
||||
|
||||
import {
|
||||
IDataProviderHistoricalResponse,
|
||||
IDataProviderResponse
|
||||
} from '../../interfaces/interfaces';
|
||||
import { DataSource } from '@prisma/client';
|
||||
|
||||
export interface DataProviderInterface {
|
||||
canHandle(symbol: string): boolean;
|
||||
|
@ -1,6 +1,7 @@
|
||||
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 { DATE_FORMAT, isCrypto, isCurrency } from '@ghostfolio/common/helper';
|
||||
import { DATE_FORMAT, isCurrency } from '@ghostfolio/common/helper';
|
||||
import { Granularity } from '@ghostfolio/common/types';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AssetClass, AssetSubClass, DataSource } from '@prisma/client';
|
||||
@ -26,7 +27,9 @@ import {
|
||||
export class YahooFinanceService implements DataProviderInterface {
|
||||
private yahooFinanceHostname = 'https://query1.finance.yahoo.com';
|
||||
|
||||
public constructor() {}
|
||||
public constructor(
|
||||
private readonly cryptocurrencyService: CryptocurrencyService
|
||||
) {}
|
||||
|
||||
public canHandle(symbol: string) {
|
||||
return true;
|
||||
@ -65,7 +68,8 @@ export class YahooFinanceService implements DataProviderInterface {
|
||||
dataSource: DataSource.YAHOO,
|
||||
exchange: this.parseExchange(value.price?.exchangeName),
|
||||
marketState:
|
||||
value.price?.marketState === 'REGULAR' || isCrypto(symbol)
|
||||
value.price?.marketState === 'REGULAR' ||
|
||||
this.cryptocurrencyService.isCrypto(symbol)
|
||||
? MarketState.open
|
||||
: MarketState.closed,
|
||||
marketPrice: value.price?.regularMarketPrice || 0,
|
||||
@ -249,7 +253,10 @@ export class YahooFinanceService implements DataProviderInterface {
|
||||
) {
|
||||
if (isCurrency(aSymbol.substring(0, aSymbol.length - 3))) {
|
||||
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
|
||||
// BTCUSD -> BTC-USD
|
||||
// DOGEUSD -> DOGE-USD
|
||||
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"SHIB": "SHIBA INU USD",
|
||||
"SOL1": "Solana",
|
||||
"DOT1": "Polkadot",
|
||||
"LUNA1": "Terra",
|
||||
"AVAX": "Avalanche",
|
||||
"MATIC": "MaticNetwork",
|
||||
"ATOM1": "Cosmos",
|
||||
"FTT1": "FTXToken",
|
||||
"1INCH": "1inch"
|
||||
}
|
@ -3,11 +3,6 @@ import { getDate, getMonth, getYear, parse, subDays } from 'date-fns';
|
||||
|
||||
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 function capitalize(aString: string) {
|
||||
@ -53,9 +48,9 @@ export function getUtc(aDateString: string) {
|
||||
|
||||
return new Date(
|
||||
Date.UTC(
|
||||
parseInt(yearString),
|
||||
parseInt(monthString) - 1,
|
||||
parseInt(dayString)
|
||||
parseInt(yearString, 10),
|
||||
parseInt(monthString, 10) - 1,
|
||||
parseInt(dayString, 10)
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -82,11 +77,6 @@ export function groupBy<T, K extends keyof T>(
|
||||
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 = '') {
|
||||
return currencies[aSymbol];
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user