Add more fiat currencies using fx rates from FreeCurrencyAPI
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import DB from '../database';
|
||||
import logger from '../logger';
|
||||
import config from '../config';
|
||||
import priceUpdater from '../tasks/price-updater';
|
||||
|
||||
export interface ApiPrice {
|
||||
@@ -11,17 +12,81 @@ export interface ApiPrice {
|
||||
CHF: number,
|
||||
AUD: number,
|
||||
JPY: number,
|
||||
BGN: number,
|
||||
BRL: number,
|
||||
CNY: number,
|
||||
CZK: number,
|
||||
DKK: number,
|
||||
HKD: number,
|
||||
HRK: number,
|
||||
HUF: number,
|
||||
IDR: number,
|
||||
ILS: number,
|
||||
INR: number,
|
||||
ISK: number,
|
||||
KRW: number,
|
||||
MXN: number,
|
||||
MYR: number,
|
||||
NOK: number,
|
||||
NZD: number,
|
||||
PHP: number,
|
||||
PLN: number,
|
||||
RON: number,
|
||||
RUB: number,
|
||||
SEK: number,
|
||||
SGD: number,
|
||||
THB: number,
|
||||
TRY: number,
|
||||
ZAR: number,
|
||||
}
|
||||
const ApiPriceFields = `
|
||||
UNIX_TIMESTAMP(time) as time,
|
||||
USD,
|
||||
EUR,
|
||||
GBP,
|
||||
CAD,
|
||||
CHF,
|
||||
AUD,
|
||||
JPY
|
||||
`;
|
||||
|
||||
const ApiPriceFields = config.MEMPOOL.CURRENCY_API_KEY ?
|
||||
`
|
||||
UNIX_TIMESTAMP(time) as time,
|
||||
USD,
|
||||
EUR,
|
||||
GBP,
|
||||
CAD,
|
||||
CHF,
|
||||
AUD,
|
||||
JPY,
|
||||
BGN,
|
||||
BRL,
|
||||
CNY,
|
||||
CZK,
|
||||
DKK,
|
||||
HKD,
|
||||
HRK,
|
||||
HUF,
|
||||
IDR,
|
||||
ILS,
|
||||
INR,
|
||||
ISK,
|
||||
KRW,
|
||||
MXN,
|
||||
MYR,
|
||||
NOK,
|
||||
NZD,
|
||||
PHP,
|
||||
PLN,
|
||||
RON,
|
||||
RUB,
|
||||
SEK,
|
||||
SGD,
|
||||
THB,
|
||||
TRY,
|
||||
ZAR
|
||||
`:
|
||||
`
|
||||
UNIX_TIMESTAMP(time) as time,
|
||||
USD,
|
||||
EUR,
|
||||
GBP,
|
||||
CAD,
|
||||
CHF,
|
||||
AUD,
|
||||
JPY
|
||||
`;
|
||||
|
||||
export interface ExchangeRates {
|
||||
USDEUR: number,
|
||||
@@ -30,6 +95,32 @@ export interface ExchangeRates {
|
||||
USDCHF: number,
|
||||
USDAUD: number,
|
||||
USDJPY: number,
|
||||
USDBGN?: number,
|
||||
USDBRL?: number,
|
||||
USDCNY?: number,
|
||||
USDCZK?: number,
|
||||
USDDKK?: number,
|
||||
USDHKD?: number,
|
||||
USDHRK?: number,
|
||||
USDHUF?: number,
|
||||
USDIDR?: number,
|
||||
USDILS?: number,
|
||||
USDINR?: number,
|
||||
USDISK?: number,
|
||||
USDKRW?: number,
|
||||
USDMXN?: number,
|
||||
USDMYR?: number,
|
||||
USDNOK?: number,
|
||||
USDNZD?: number,
|
||||
USDPHP?: number,
|
||||
USDPLN?: number,
|
||||
USDRON?: number,
|
||||
USDRUB?: number,
|
||||
USDSEK?: number,
|
||||
USDSGD?: number,
|
||||
USDTHB?: number,
|
||||
USDTRY?: number,
|
||||
USDZAR?: number,
|
||||
}
|
||||
|
||||
export interface Conversion {
|
||||
@@ -45,6 +136,32 @@ export const MAX_PRICES = {
|
||||
CHF: 100000000,
|
||||
AUD: 100000000,
|
||||
JPY: 10000000000,
|
||||
BGN: 1000000000,
|
||||
BRL: 1000000000,
|
||||
CNY: 1000000000,
|
||||
CZK: 10000000000,
|
||||
DKK: 1000000000,
|
||||
HKD: 1000000000,
|
||||
HRK: 1000000000,
|
||||
HUF: 10000000000,
|
||||
IDR: 100000000000,
|
||||
ILS: 1000000000,
|
||||
INR: 10000000000,
|
||||
ISK: 10000000000,
|
||||
KRW: 100000000000,
|
||||
MXN: 1000000000,
|
||||
MYR: 1000000000,
|
||||
NOK: 1000000000,
|
||||
NZD: 1000000000,
|
||||
PHP: 10000000000,
|
||||
PLN: 1000000000,
|
||||
RON: 1000000000,
|
||||
RUB: 10000000000,
|
||||
SEK: 1000000000,
|
||||
SGD: 100000000,
|
||||
THB: 10000000000,
|
||||
TRY: 10000000000,
|
||||
ZAR: 10000000000,
|
||||
};
|
||||
|
||||
class PricesRepository {
|
||||
@@ -64,17 +181,49 @@ class PricesRepository {
|
||||
}
|
||||
|
||||
try {
|
||||
await DB.query(`
|
||||
INSERT INTO prices(time, USD, EUR, GBP, CAD, CHF, AUD, JPY)
|
||||
VALUE (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ? )`,
|
||||
[time, prices.USD, prices.EUR, prices.GBP, prices.CAD, prices.CHF, prices.AUD, prices.JPY]
|
||||
);
|
||||
if (!config.MEMPOOL.CURRENCY_API_KEY) { // Store only the 7 main currencies
|
||||
await DB.query(`
|
||||
INSERT INTO prices(time, USD, EUR, GBP, CAD, CHF, AUD, JPY)
|
||||
VALUE (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ? )`,
|
||||
[time, prices.USD, prices.EUR, prices.GBP, prices.CAD, prices.CHF, prices.AUD, prices.JPY]
|
||||
);
|
||||
} else { // Store all 7 main currencies + all the currencies obtained with the external API
|
||||
await DB.query(`
|
||||
INSERT INTO prices(time, USD, EUR, GBP, CAD, CHF, AUD, JPY, BGN, BRL, CNY, CZK, DKK, HKD, HRK, HUF, IDR, ILS, INR, ISK, KRW, MXN, MYR, NOK, NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, TRY, ZAR)
|
||||
VALUE (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ? , ?, ?, ?, ?, ?, ?, ?, ? , ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? , ? )`,
|
||||
[time, prices.USD, prices.EUR, prices.GBP, prices.CAD, prices.CHF, prices.AUD, prices.JPY, prices.BGN, prices.BRL, prices.CNY, prices.CZK, prices.DKK,
|
||||
prices.HKD, prices.HRK, prices.HUF, prices.IDR, prices.ILS, prices.INR, prices.ISK, prices.KRW, prices.MXN, prices.MYR, prices.NOK, prices.NZD,
|
||||
prices.PHP, prices.PLN, prices.RON, prices.RUB, prices.SEK, prices.SGD, prices.THB, prices.TRY, prices.ZAR]
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.err(`Cannot save exchange rate into db. Reason: ` + (e instanceof Error ? e.message : e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public async $saveAdditionalCurrencyPrices(time: number, prices: ApiPrice, legacyCurrencies: string[]): Promise<void> {
|
||||
try {
|
||||
await DB.query(`
|
||||
UPDATE prices
|
||||
SET BGN = ?, BRL = ?, CNY = ?, CZK = ?, DKK = ?, HKD = ?, HRK = ?, HUF = ?, IDR = ?, ILS = ?, INR = ?, ISK = ?, KRW = ?, MXN = ?, MYR = ?, NOK = ?, NZD = ?, PHP = ?, PLN = ?, RON = ?, RUB = ?, SEK = ?, SGD = ?, THB = ?, TRY = ?, ZAR = ?
|
||||
WHERE UNIX_TIMESTAMP(time) = ?`,
|
||||
[prices.BGN, prices.BRL, prices.CNY, prices.CZK, prices.DKK, prices.HKD, prices.HRK, prices.HUF, prices.IDR, prices.ILS, prices.INR, prices.ISK, prices.KRW, prices.MXN, prices.MYR, prices.NOK, prices.NZD, prices.PHP, prices.PLN, prices.RON, prices.RUB, prices.SEK, prices.SGD, prices.THB, prices.TRY, prices.ZAR, time]
|
||||
);
|
||||
for (const currency of legacyCurrencies) {
|
||||
await DB.query(`
|
||||
UPDATE prices
|
||||
SET ${currency} = ?
|
||||
WHERE UNIX_TIMESTAMP(time) = ?`,
|
||||
[prices[currency], time]
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.err(`Cannot update exchange rate into db. Reason: ` + (e instanceof Error ? e.message : e));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public async $getOldestPriceTime(): Promise<number> {
|
||||
const [oldestRow] = await DB.query(`
|
||||
SELECT UNIX_TIMESTAMP(time) AS time
|
||||
@@ -118,6 +267,28 @@ class PricesRepository {
|
||||
return times.map(time => time.time);
|
||||
}
|
||||
|
||||
public async $getPricesTimesWithMissingFields(): Promise<{time: number, USD: number, eur_missing: boolean, gbp_missing: boolean, cad_missing: boolean, chf_missing: boolean, aud_missing: boolean, jpy_missing: boolean}[]> {
|
||||
const [times] = await DB.query(`
|
||||
SELECT UNIX_TIMESTAMP(time) AS time,
|
||||
USD,
|
||||
CASE WHEN EUR = -1 THEN TRUE ELSE FALSE END AS eur_missing,
|
||||
CASE WHEN GBP = -1 THEN TRUE ELSE FALSE END AS gbp_missing,
|
||||
CASE WHEN CAD = -1 THEN TRUE ELSE FALSE END AS cad_missing,
|
||||
CASE WHEN CHF = -1 THEN TRUE ELSE FALSE END AS chf_missing,
|
||||
CASE WHEN AUD = -1 THEN TRUE ELSE FALSE END AS aud_missing,
|
||||
CASE WHEN JPY = -1 THEN TRUE ELSE FALSE END AS jpy_missing
|
||||
FROM prices
|
||||
WHERE USD != -1
|
||||
AND -1 IN (EUR, GBP, CAD, CHF, AUD, JPY, BGN, BRL, CNY, CZK, DKK, HKD, HRK, HUF, IDR, ILS, INR, ISK, KRW,
|
||||
MXN, MYR, NOK, NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, TRY, ZAR)
|
||||
ORDER BY time
|
||||
`);
|
||||
if (!Array.isArray(times)) {
|
||||
return [];
|
||||
}
|
||||
return times as {time: number, USD: number, eur_missing: boolean, gbp_missing: boolean, cad_missing: boolean, chf_missing: boolean, aud_missing: boolean, jpy_missing: boolean}[];
|
||||
}
|
||||
|
||||
public async $getPricesTimesAndId(): Promise<{time: number, id: number, USD: number}[]> {
|
||||
const [times] = await DB.query(`
|
||||
SELECT
|
||||
@@ -167,14 +338,48 @@ class PricesRepository {
|
||||
const computeFx = (usd: number, other: number): number =>
|
||||
Math.round(Math.max(other, 0) / Math.max(usd, 1) * 100) / 100;
|
||||
|
||||
const exchangeRates: ExchangeRates = {
|
||||
USDEUR: computeFx(latestPrice.USD, latestPrice.EUR),
|
||||
USDGBP: computeFx(latestPrice.USD, latestPrice.GBP),
|
||||
USDCAD: computeFx(latestPrice.USD, latestPrice.CAD),
|
||||
USDCHF: computeFx(latestPrice.USD, latestPrice.CHF),
|
||||
USDAUD: computeFx(latestPrice.USD, latestPrice.AUD),
|
||||
USDJPY: computeFx(latestPrice.USD, latestPrice.JPY),
|
||||
};
|
||||
const exchangeRates: ExchangeRates = config.MEMPOOL.CURRENCY_API_KEY ?
|
||||
{
|
||||
USDEUR: computeFx(latestPrice.USD, latestPrice.EUR),
|
||||
USDGBP: computeFx(latestPrice.USD, latestPrice.GBP),
|
||||
USDCAD: computeFx(latestPrice.USD, latestPrice.CAD),
|
||||
USDCHF: computeFx(latestPrice.USD, latestPrice.CHF),
|
||||
USDAUD: computeFx(latestPrice.USD, latestPrice.AUD),
|
||||
USDJPY: computeFx(latestPrice.USD, latestPrice.JPY),
|
||||
USDBGN: computeFx(latestPrice.USD, latestPrice.BGN),
|
||||
USDBRL: computeFx(latestPrice.USD, latestPrice.BRL),
|
||||
USDCNY: computeFx(latestPrice.USD, latestPrice.CNY),
|
||||
USDCZK: computeFx(latestPrice.USD, latestPrice.CZK),
|
||||
USDDKK: computeFx(latestPrice.USD, latestPrice.DKK),
|
||||
USDHKD: computeFx(latestPrice.USD, latestPrice.HKD),
|
||||
USDHRK: computeFx(latestPrice.USD, latestPrice.HRK),
|
||||
USDHUF: computeFx(latestPrice.USD, latestPrice.HUF),
|
||||
USDIDR: computeFx(latestPrice.USD, latestPrice.IDR),
|
||||
USDILS: computeFx(latestPrice.USD, latestPrice.ILS),
|
||||
USDINR: computeFx(latestPrice.USD, latestPrice.INR),
|
||||
USDISK: computeFx(latestPrice.USD, latestPrice.ISK),
|
||||
USDKRW: computeFx(latestPrice.USD, latestPrice.KRW),
|
||||
USDMXN: computeFx(latestPrice.USD, latestPrice.MXN),
|
||||
USDMYR: computeFx(latestPrice.USD, latestPrice.MYR),
|
||||
USDNOK: computeFx(latestPrice.USD, latestPrice.NOK),
|
||||
USDNZD: computeFx(latestPrice.USD, latestPrice.NZD),
|
||||
USDPHP: computeFx(latestPrice.USD, latestPrice.PHP),
|
||||
USDPLN: computeFx(latestPrice.USD, latestPrice.PLN),
|
||||
USDRON: computeFx(latestPrice.USD, latestPrice.RON),
|
||||
USDRUB: computeFx(latestPrice.USD, latestPrice.RUB),
|
||||
USDSEK: computeFx(latestPrice.USD, latestPrice.SEK),
|
||||
USDSGD: computeFx(latestPrice.USD, latestPrice.SGD),
|
||||
USDTHB: computeFx(latestPrice.USD, latestPrice.THB),
|
||||
USDTRY: computeFx(latestPrice.USD, latestPrice.TRY),
|
||||
USDZAR: computeFx(latestPrice.USD, latestPrice.ZAR),
|
||||
} : {
|
||||
USDEUR: computeFx(latestPrice.USD, latestPrice.EUR),
|
||||
USDGBP: computeFx(latestPrice.USD, latestPrice.GBP),
|
||||
USDCAD: computeFx(latestPrice.USD, latestPrice.CAD),
|
||||
USDCHF: computeFx(latestPrice.USD, latestPrice.CHF),
|
||||
USDAUD: computeFx(latestPrice.USD, latestPrice.AUD),
|
||||
USDJPY: computeFx(latestPrice.USD, latestPrice.JPY),
|
||||
};
|
||||
|
||||
return {
|
||||
prices: rates as ApiPrice[],
|
||||
@@ -206,14 +411,48 @@ class PricesRepository {
|
||||
const computeFx = (usd: number, other: number): number =>
|
||||
Math.round(Math.max(other, 0) / Math.max(usd, 1) * 100) / 100;
|
||||
|
||||
const exchangeRates: ExchangeRates = {
|
||||
USDEUR: computeFx(latestPrice.USD, latestPrice.EUR),
|
||||
USDGBP: computeFx(latestPrice.USD, latestPrice.GBP),
|
||||
USDCAD: computeFx(latestPrice.USD, latestPrice.CAD),
|
||||
USDCHF: computeFx(latestPrice.USD, latestPrice.CHF),
|
||||
USDAUD: computeFx(latestPrice.USD, latestPrice.AUD),
|
||||
USDJPY: computeFx(latestPrice.USD, latestPrice.JPY),
|
||||
};
|
||||
const exchangeRates: ExchangeRates = config.MEMPOOL.CURRENCY_API_KEY ?
|
||||
{
|
||||
USDEUR: computeFx(latestPrice.USD, latestPrice.EUR),
|
||||
USDGBP: computeFx(latestPrice.USD, latestPrice.GBP),
|
||||
USDCAD: computeFx(latestPrice.USD, latestPrice.CAD),
|
||||
USDCHF: computeFx(latestPrice.USD, latestPrice.CHF),
|
||||
USDAUD: computeFx(latestPrice.USD, latestPrice.AUD),
|
||||
USDJPY: computeFx(latestPrice.USD, latestPrice.JPY),
|
||||
USDBGN: computeFx(latestPrice.USD, latestPrice.BGN),
|
||||
USDBRL: computeFx(latestPrice.USD, latestPrice.BRL),
|
||||
USDCNY: computeFx(latestPrice.USD, latestPrice.CNY),
|
||||
USDCZK: computeFx(latestPrice.USD, latestPrice.CZK),
|
||||
USDDKK: computeFx(latestPrice.USD, latestPrice.DKK),
|
||||
USDHKD: computeFx(latestPrice.USD, latestPrice.HKD),
|
||||
USDHRK: computeFx(latestPrice.USD, latestPrice.HRK),
|
||||
USDHUF: computeFx(latestPrice.USD, latestPrice.HUF),
|
||||
USDIDR: computeFx(latestPrice.USD, latestPrice.IDR),
|
||||
USDILS: computeFx(latestPrice.USD, latestPrice.ILS),
|
||||
USDINR: computeFx(latestPrice.USD, latestPrice.INR),
|
||||
USDISK: computeFx(latestPrice.USD, latestPrice.ISK),
|
||||
USDKRW: computeFx(latestPrice.USD, latestPrice.KRW),
|
||||
USDMXN: computeFx(latestPrice.USD, latestPrice.MXN),
|
||||
USDMYR: computeFx(latestPrice.USD, latestPrice.MYR),
|
||||
USDNOK: computeFx(latestPrice.USD, latestPrice.NOK),
|
||||
USDNZD: computeFx(latestPrice.USD, latestPrice.NZD),
|
||||
USDPHP: computeFx(latestPrice.USD, latestPrice.PHP),
|
||||
USDPLN: computeFx(latestPrice.USD, latestPrice.PLN),
|
||||
USDRON: computeFx(latestPrice.USD, latestPrice.RON),
|
||||
USDRUB: computeFx(latestPrice.USD, latestPrice.RUB),
|
||||
USDSEK: computeFx(latestPrice.USD, latestPrice.SEK),
|
||||
USDSGD: computeFx(latestPrice.USD, latestPrice.SGD),
|
||||
USDTHB: computeFx(latestPrice.USD, latestPrice.THB),
|
||||
USDTRY: computeFx(latestPrice.USD, latestPrice.TRY),
|
||||
USDZAR: computeFx(latestPrice.USD, latestPrice.ZAR),
|
||||
} : {
|
||||
USDEUR: computeFx(latestPrice.USD, latestPrice.EUR),
|
||||
USDGBP: computeFx(latestPrice.USD, latestPrice.GBP),
|
||||
USDCAD: computeFx(latestPrice.USD, latestPrice.CAD),
|
||||
USDCHF: computeFx(latestPrice.USD, latestPrice.CHF),
|
||||
USDAUD: computeFx(latestPrice.USD, latestPrice.AUD),
|
||||
USDJPY: computeFx(latestPrice.USD, latestPrice.JPY),
|
||||
};
|
||||
|
||||
return {
|
||||
prices: rates as ApiPrice[],
|
||||
|
||||
Reference in New Issue
Block a user