Feature/Add Coingecko api keys support (#2827)
* Add CoinGecko API keys support * Update changelog
This commit is contained in:
parent
af71274ea9
commit
d91f947ab0
@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added support to set a _CoinGecko_ Demo API key via environment variable (`API_KEY_COINGECKO_DEMO`)
|
||||||
|
- Added support to set a _CoinGecko_ Pro API key via environment variable (`API_KEY_COINGECKO_PRO`)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Removed the `AccountType` enum
|
- Removed the `AccountType` enum
|
||||||
|
30
README.md
30
README.md
@ -87,20 +87,22 @@ We provide official container images hosted on [Docker Hub](https://hub.docker.c
|
|||||||
|
|
||||||
### Supported Environment Variables
|
### Supported Environment Variables
|
||||||
|
|
||||||
| Name | Default Value | Description |
|
| Name | Default Value | Description |
|
||||||
| ------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `ACCESS_TOKEN_SALT` | | A random string used as salt for access tokens |
|
| `ACCESS_TOKEN_SALT` | | A random string used as salt for access tokens |
|
||||||
| `DATABASE_URL` | | The database connection URL, e.g. `postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=prefer` |
|
| `API_KEY_COINGECKO_DEMO` | | The _CoinGecko_ Demo API key |
|
||||||
| `HOST` | `0.0.0.0` | The host where the Ghostfolio application will run on |
|
| `API_KEY_COINGECKO_PRO` | | The _CoinGecko_ Pro API |
|
||||||
| `JWT_SECRET_KEY` | | A random string used for _JSON Web Tokens_ (JWT) |
|
| `DATABASE_URL` | | The database connection URL, e.g. `postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=prefer` |
|
||||||
| `PORT` | `3333` | The port where the Ghostfolio application will run on |
|
| `HOST` | `0.0.0.0` | The host where the Ghostfolio application will run on |
|
||||||
| `POSTGRES_DB` | | The name of the _PostgreSQL_ database |
|
| `JWT_SECRET_KEY` | | A random string used for _JSON Web Tokens_ (JWT) |
|
||||||
| `POSTGRES_PASSWORD` | | The password of the _PostgreSQL_ database |
|
| `PORT` | `3333` | The port where the Ghostfolio application will run on |
|
||||||
| `POSTGRES_USER` | | The user of the _PostgreSQL_ database |
|
| `POSTGRES_DB` | | The name of the _PostgreSQL_ database |
|
||||||
| `REDIS_HOST` | | The host where _Redis_ is running |
|
| `POSTGRES_PASSWORD` | | The password of the _PostgreSQL_ database |
|
||||||
| `REDIS_PASSWORD` | | The password of _Redis_ |
|
| `POSTGRES_USER` | | The user of the _PostgreSQL_ database |
|
||||||
| `REDIS_PORT` | | The port where _Redis_ is running |
|
| `REDIS_HOST` | | The host where _Redis_ is running |
|
||||||
| `REQUEST_TIMEOUT` | `2000` | The timeout of network requests to data providers in milliseconds |
|
| `REDIS_PASSWORD` | | The password of _Redis_ |
|
||||||
|
| `REDIS_PORT` | | The port where _Redis_ is running |
|
||||||
|
| `REQUEST_TIMEOUT` | `2000` | The timeout of network requests to data providers in milliseconds |
|
||||||
|
|
||||||
### Run with Docker Compose
|
### Run with Docker Compose
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ export class ConfigurationService {
|
|||||||
this.environmentConfiguration = cleanEnv(process.env, {
|
this.environmentConfiguration = cleanEnv(process.env, {
|
||||||
ACCESS_TOKEN_SALT: str(),
|
ACCESS_TOKEN_SALT: str(),
|
||||||
ALPHA_VANTAGE_API_KEY: str({ default: '' }),
|
ALPHA_VANTAGE_API_KEY: str({ default: '' }),
|
||||||
|
API_KEY_COINGECKO_DEMO: str({ default: '' }),
|
||||||
|
API_KEY_COINGECKO_PRO: str({ default: '' }),
|
||||||
BETTER_UPTIME_API_KEY: str({ default: '' }),
|
BETTER_UPTIME_API_KEY: str({ default: '' }),
|
||||||
CACHE_QUOTES_TTL: num({ default: 1 }),
|
CACHE_QUOTES_TTL: num({ default: 1 }),
|
||||||
CACHE_TTL: num({ default: 1 }),
|
CACHE_TTL: num({ default: 1 }),
|
||||||
|
@ -17,15 +17,30 @@ import {
|
|||||||
SymbolProfile
|
SymbolProfile
|
||||||
} from '@prisma/client';
|
} from '@prisma/client';
|
||||||
import { format, fromUnixTime, getUnixTime } from 'date-fns';
|
import { format, fromUnixTime, getUnixTime } from 'date-fns';
|
||||||
import got from 'got';
|
import got, { Headers } from 'got';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CoinGeckoService implements DataProviderInterface {
|
export class CoinGeckoService implements DataProviderInterface {
|
||||||
private readonly URL = 'https://api.coingecko.com/api/v3';
|
private readonly apiUrl: string;
|
||||||
|
private readonly headers: Headers = {};
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private readonly configurationService: ConfigurationService
|
private readonly configurationService: ConfigurationService
|
||||||
) {}
|
) {
|
||||||
|
const apiKeyDemo = this.configurationService.get('API_KEY_COINGECKO_DEMO');
|
||||||
|
const apiKeyPro = this.configurationService.get('API_KEY_COINGECKO_PRO');
|
||||||
|
|
||||||
|
this.apiUrl = 'https://api.coingecko.com/api/v3';
|
||||||
|
|
||||||
|
if (apiKeyDemo) {
|
||||||
|
this.headers['x-cg-demo-api-key'] = apiKeyDemo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiKeyPro) {
|
||||||
|
this.apiUrl = 'https://pro-api.coingecko.com/api/v3';
|
||||||
|
this.headers['x-cg-pro-api-key'] = apiKeyPro;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public canHandle(symbol: string) {
|
public canHandle(symbol: string) {
|
||||||
return true;
|
return true;
|
||||||
@ -49,7 +64,8 @@ export class CoinGeckoService implements DataProviderInterface {
|
|||||||
abortController.abort();
|
abortController.abort();
|
||||||
}, this.configurationService.get('REQUEST_TIMEOUT'));
|
}, this.configurationService.get('REQUEST_TIMEOUT'));
|
||||||
|
|
||||||
const { name } = await got(`${this.URL}/coins/${aSymbol}`, {
|
const { name } = await got(`${this.apiUrl}/coins/${aSymbol}`, {
|
||||||
|
headers: this.headers,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
signal: abortController.signal
|
signal: abortController.signal
|
||||||
}).json<any>();
|
}).json<any>();
|
||||||
@ -101,11 +117,12 @@ export class CoinGeckoService implements DataProviderInterface {
|
|||||||
|
|
||||||
const { prices } = await got(
|
const { prices } = await got(
|
||||||
`${
|
`${
|
||||||
this.URL
|
this.apiUrl
|
||||||
}/coins/${aSymbol}/market_chart/range?vs_currency=${DEFAULT_CURRENCY.toLowerCase()}&from=${getUnixTime(
|
}/coins/${aSymbol}/market_chart/range?vs_currency=${DEFAULT_CURRENCY.toLowerCase()}&from=${getUnixTime(
|
||||||
from
|
from
|
||||||
)}&to=${getUnixTime(to)}`,
|
)}&to=${getUnixTime(to)}`,
|
||||||
{
|
{
|
||||||
|
headers: this.headers,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
signal: abortController.signal
|
signal: abortController.signal
|
||||||
}
|
}
|
||||||
@ -163,10 +180,11 @@ export class CoinGeckoService implements DataProviderInterface {
|
|||||||
}, requestTimeout);
|
}, requestTimeout);
|
||||||
|
|
||||||
const quotes = await got(
|
const quotes = await got(
|
||||||
`${this.URL}/simple/price?ids=${symbols.join(
|
`${this.apiUrl}/simple/price?ids=${symbols.join(
|
||||||
','
|
','
|
||||||
)}&vs_currencies=${DEFAULT_CURRENCY.toLowerCase()}`,
|
)}&vs_currencies=${DEFAULT_CURRENCY.toLowerCase()}`,
|
||||||
{
|
{
|
||||||
|
headers: this.headers,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
signal: abortController.signal
|
signal: abortController.signal
|
||||||
}
|
}
|
||||||
@ -216,7 +234,8 @@ export class CoinGeckoService implements DataProviderInterface {
|
|||||||
abortController.abort();
|
abortController.abort();
|
||||||
}, this.configurationService.get('REQUEST_TIMEOUT'));
|
}, this.configurationService.get('REQUEST_TIMEOUT'));
|
||||||
|
|
||||||
const { coins } = await got(`${this.URL}/search?query=${query}`, {
|
const { coins } = await got(`${this.apiUrl}/search?query=${query}`, {
|
||||||
|
headers: this.headers,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
signal: abortController.signal
|
signal: abortController.signal
|
||||||
}).json<any>();
|
}).json<any>();
|
||||||
|
@ -3,6 +3,8 @@ import { CleanedEnvAccessors } from 'envalid';
|
|||||||
export interface Environment extends CleanedEnvAccessors {
|
export interface Environment extends CleanedEnvAccessors {
|
||||||
ACCESS_TOKEN_SALT: string;
|
ACCESS_TOKEN_SALT: string;
|
||||||
ALPHA_VANTAGE_API_KEY: string;
|
ALPHA_VANTAGE_API_KEY: string;
|
||||||
|
API_KEY_COINGECKO_DEMO: string;
|
||||||
|
API_KEY_COINGECKO_PRO: string;
|
||||||
BETTER_UPTIME_API_KEY: string;
|
BETTER_UPTIME_API_KEY: string;
|
||||||
CACHE_QUOTES_TTL: number;
|
CACHE_QUOTES_TTL: number;
|
||||||
CACHE_TTL: number;
|
CACHE_TTL: number;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user