Handle missing price (show 0)
This commit is contained in:
parent
51d50292e6
commit
d483362a9b
@ -1,8 +1,8 @@
|
|||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
import * as WebSocket from 'ws';
|
import * as WebSocket from 'ws';
|
||||||
import {
|
import {
|
||||||
BlockExtended, TransactionExtended, WebsocketResponse, MempoolBlock, MempoolBlockDelta,
|
BlockExtended, TransactionExtended, WebsocketResponse,
|
||||||
OptimizedStatistic, ILoadingIndicators, IConversionRates
|
OptimizedStatistic, ILoadingIndicators
|
||||||
} from '../mempool.interfaces';
|
} from '../mempool.interfaces';
|
||||||
import blocks from './blocks';
|
import blocks from './blocks';
|
||||||
import memPool from './mempool';
|
import memPool from './mempool';
|
||||||
@ -20,6 +20,7 @@ import BlocksSummariesRepository from '../repositories/BlocksSummariesRepository
|
|||||||
import Audit from './audit';
|
import Audit from './audit';
|
||||||
import { deepClone } from '../utils/clone';
|
import { deepClone } from '../utils/clone';
|
||||||
import priceUpdater from '../tasks/price-updater';
|
import priceUpdater from '../tasks/price-updater';
|
||||||
|
import { ApiPrice } from '../repositories/PricesRepository';
|
||||||
|
|
||||||
class WebsocketHandler {
|
class WebsocketHandler {
|
||||||
private wss: WebSocket.Server | undefined;
|
private wss: WebSocket.Server | undefined;
|
||||||
@ -193,7 +194,7 @@ class WebsocketHandler {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNewConversionRates(conversionRates: IConversionRates) {
|
handleNewConversionRates(conversionRates: ApiPrice) {
|
||||||
if (!this.wss) {
|
if (!this.wss) {
|
||||||
throw new Error('WebSocket.Server is not set');
|
throw new Error('WebSocket.Server is not set');
|
||||||
}
|
}
|
||||||
@ -214,7 +215,7 @@ class WebsocketHandler {
|
|||||||
'mempoolInfo': memPool.getMempoolInfo(),
|
'mempoolInfo': memPool.getMempoolInfo(),
|
||||||
'vBytesPerSecond': memPool.getVBytesPerSecond(),
|
'vBytesPerSecond': memPool.getVBytesPerSecond(),
|
||||||
'blocks': _blocks,
|
'blocks': _blocks,
|
||||||
'conversions': priceUpdater.latestPrices,
|
'conversions': priceUpdater.getLatestPrices(),
|
||||||
'mempool-blocks': mempoolBlocks.getMempoolBlocks(),
|
'mempool-blocks': mempoolBlocks.getMempoolBlocks(),
|
||||||
'transactions': memPool.getLatestTransactions(),
|
'transactions': memPool.getLatestTransactions(),
|
||||||
'backendInfo': backendInfo.getBackendInfo(),
|
'backendInfo': backendInfo.getBackendInfo(),
|
||||||
|
@ -293,7 +293,6 @@ interface RequiredParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ILoadingIndicators { [name: string]: number; }
|
export interface ILoadingIndicators { [name: string]: number; }
|
||||||
export interface IConversionRates { [currency: string]: number; }
|
|
||||||
|
|
||||||
export interface IBackendInfo {
|
export interface IBackendInfo {
|
||||||
hostname: string;
|
hostname: string;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import DB from '../database';
|
import DB from '../database';
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
import { IConversionRates } from '../mempool.interfaces';
|
|
||||||
import priceUpdater from '../tasks/price-updater';
|
import priceUpdater from '../tasks/price-updater';
|
||||||
|
|
||||||
export interface ApiPrice {
|
export interface ApiPrice {
|
||||||
@ -13,6 +12,16 @@ export interface ApiPrice {
|
|||||||
AUD: number,
|
AUD: number,
|
||||||
JPY: number,
|
JPY: number,
|
||||||
}
|
}
|
||||||
|
const ApiPriceFields = `
|
||||||
|
UNIX_TIMESTAMP(time) as time,
|
||||||
|
USD,
|
||||||
|
EUR,
|
||||||
|
GBP,
|
||||||
|
CAD,
|
||||||
|
CHF,
|
||||||
|
AUD,
|
||||||
|
JPY
|
||||||
|
`;
|
||||||
|
|
||||||
export interface ExchangeRates {
|
export interface ExchangeRates {
|
||||||
USDEUR: number,
|
USDEUR: number,
|
||||||
@ -39,7 +48,7 @@ export const MAX_PRICES = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class PricesRepository {
|
class PricesRepository {
|
||||||
public async $savePrices(time: number, prices: IConversionRates): Promise<void> {
|
public async $savePrices(time: number, prices: ApiPrice): Promise<void> {
|
||||||
if (prices.USD === -1) {
|
if (prices.USD === -1) {
|
||||||
// Some historical price entries have no USD prices, so we just ignore them to avoid future UX issues
|
// Some historical price entries have no USD prices, so we just ignore them to avoid future UX issues
|
||||||
// As of today there are only 4 (on 2013-09-05, 2013-0909, 2013-09-12 and 2013-09-26) so that's fine
|
// As of today there are only 4 (on 2013-09-05, 2013-0909, 2013-09-12 and 2013-09-26) so that's fine
|
||||||
@ -60,77 +69,115 @@ class PricesRepository {
|
|||||||
VALUE (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ? )`,
|
VALUE (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ? )`,
|
||||||
[time, prices.USD, prices.EUR, prices.GBP, prices.CAD, prices.CHF, prices.AUD, prices.JPY]
|
[time, prices.USD, prices.EUR, prices.GBP, prices.CAD, prices.CHF, prices.AUD, prices.JPY]
|
||||||
);
|
);
|
||||||
} catch (e: any) {
|
} catch (e) {
|
||||||
logger.err(`Cannot save exchange rate into db. Reason: ` + (e instanceof Error ? e.message : e));
|
logger.err(`Cannot save exchange rate into db. Reason: ` + (e instanceof Error ? e.message : e));
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $getOldestPriceTime(): Promise<number> {
|
public async $getOldestPriceTime(): Promise<number> {
|
||||||
const [oldestRow] = await DB.query(`SELECT UNIX_TIMESTAMP(time) as time from prices WHERE USD != 0 ORDER BY time LIMIT 1`);
|
const [oldestRow] = await DB.query(`
|
||||||
|
SELECT UNIX_TIMESTAMP(time) AS time
|
||||||
|
FROM prices
|
||||||
|
ORDER BY time
|
||||||
|
LIMIT 1
|
||||||
|
`);
|
||||||
return oldestRow[0] ? oldestRow[0].time : 0;
|
return oldestRow[0] ? oldestRow[0].time : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $getLatestPriceId(): Promise<number | null> {
|
public async $getLatestPriceId(): Promise<number | null> {
|
||||||
const [oldestRow] = await DB.query(`SELECT id from prices WHERE USD != 0 ORDER BY time DESC LIMIT 1`);
|
const [oldestRow] = await DB.query(`
|
||||||
return oldestRow[0] ? oldestRow[0].id : null;
|
SELECT id
|
||||||
}
|
|
||||||
|
|
||||||
public async $getLatestPriceTime(): Promise<number> {
|
|
||||||
const [oldestRow] = await DB.query(`SELECT UNIX_TIMESTAMP(time) as time from prices WHERE USD != 0 ORDER BY time DESC LIMIT 1`);
|
|
||||||
return oldestRow[0] ? oldestRow[0].time : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async $getPricesTimes(): Promise<number[]> {
|
|
||||||
const [times]: any[] = await DB.query(`SELECT UNIX_TIMESTAMP(time) as time from prices WHERE USD != 0 ORDER BY time`);
|
|
||||||
return times.map(time => time.time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async $getPricesTimesAndId(): Promise<number[]> {
|
|
||||||
const [times]: any[] = await DB.query(`SELECT UNIX_TIMESTAMP(time) as time, id, USD from prices ORDER BY time`);
|
|
||||||
return times;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async $getLatestConversionRates(): Promise<any> {
|
|
||||||
const [rates]: any[] = await DB.query(`
|
|
||||||
SELECT USD, EUR, GBP, CAD, CHF, AUD, JPY
|
|
||||||
FROM prices
|
FROM prices
|
||||||
ORDER BY time DESC
|
ORDER BY time DESC
|
||||||
LIMIT 1`
|
LIMIT 1`
|
||||||
);
|
);
|
||||||
if (!rates || rates.length === 0) {
|
return oldestRow[0] ? oldestRow[0].id : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async $getLatestPriceTime(): Promise<number> {
|
||||||
|
const [oldestRow] = await DB.query(`
|
||||||
|
SELECT UNIX_TIMESTAMP(time) AS time
|
||||||
|
FROM prices
|
||||||
|
ORDER BY time DESC
|
||||||
|
LIMIT 1`
|
||||||
|
);
|
||||||
|
return oldestRow[0] ? oldestRow[0].time : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async $getPricesTimes(): Promise<number[]> {
|
||||||
|
const [times] = await DB.query(`
|
||||||
|
SELECT UNIX_TIMESTAMP(time) AS time
|
||||||
|
FROM prices
|
||||||
|
WHERE USD != -1
|
||||||
|
ORDER BY time
|
||||||
|
`);
|
||||||
|
if (!Array.isArray(times)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return times.map(time => time.time);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async $getPricesTimesAndId(): Promise<{time: number, id: number, USD: number}[]> {
|
||||||
|
const [times] = await DB.query(`
|
||||||
|
SELECT
|
||||||
|
UNIX_TIMESTAMP(time) AS time,
|
||||||
|
id,
|
||||||
|
USD
|
||||||
|
FROM prices
|
||||||
|
ORDER BY time
|
||||||
|
`);
|
||||||
|
return times as {time: number, id: number, USD: number}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async $getLatestConversionRates(): Promise<ApiPrice> {
|
||||||
|
const [rates] = await DB.query(`
|
||||||
|
SELECT ${ApiPriceFields}
|
||||||
|
FROM prices
|
||||||
|
ORDER BY time DESC
|
||||||
|
LIMIT 1`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!Array.isArray(rates) || rates.length === 0) {
|
||||||
return priceUpdater.getEmptyPricesObj();
|
return priceUpdater.getEmptyPricesObj();
|
||||||
}
|
}
|
||||||
return rates[0];
|
return rates[0] as ApiPrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $getNearestHistoricalPrice(timestamp: number | undefined): Promise<Conversion | null> {
|
public async $getNearestHistoricalPrice(timestamp: number | undefined): Promise<Conversion | null> {
|
||||||
try {
|
try {
|
||||||
const [rates]: any[] = await DB.query(`
|
const [rates] = await DB.query(`
|
||||||
SELECT *, UNIX_TIMESTAMP(time) AS time
|
SELECT ${ApiPriceFields}
|
||||||
FROM prices
|
FROM prices
|
||||||
WHERE UNIX_TIMESTAMP(time) < ?
|
WHERE UNIX_TIMESTAMP(time) < ?
|
||||||
ORDER BY time DESC
|
ORDER BY time DESC
|
||||||
LIMIT 1`,
|
LIMIT 1`,
|
||||||
[timestamp]
|
[timestamp]
|
||||||
);
|
);
|
||||||
if (!rates) {
|
if (!Array.isArray(rates)) {
|
||||||
throw Error(`Cannot get single historical price from the database`);
|
throw Error(`Cannot get single historical price from the database`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute fiat exchange rates
|
// Compute fiat exchange rates
|
||||||
const latestPrice = await this.$getLatestConversionRates();
|
let latestPrice = rates[0] as ApiPrice;
|
||||||
|
if (latestPrice.USD === -1) {
|
||||||
|
latestPrice = priceUpdater.getEmptyPricesObj();
|
||||||
|
}
|
||||||
|
|
||||||
|
const computeFx = (usd: number, other: number): number =>
|
||||||
|
Math.round(Math.max(other, 0) / Math.max(usd, 1) * 100) / 100;
|
||||||
|
|
||||||
const exchangeRates: ExchangeRates = {
|
const exchangeRates: ExchangeRates = {
|
||||||
USDEUR: Math.round(latestPrice.EUR / latestPrice.USD * 100) / 100,
|
USDEUR: computeFx(latestPrice.USD, latestPrice.EUR),
|
||||||
USDGBP: Math.round(latestPrice.GBP / latestPrice.USD * 100) / 100,
|
USDGBP: computeFx(latestPrice.USD, latestPrice.GBP),
|
||||||
USDCAD: Math.round(latestPrice.CAD / latestPrice.USD * 100) / 100,
|
USDCAD: computeFx(latestPrice.USD, latestPrice.CAD),
|
||||||
USDCHF: Math.round(latestPrice.CHF / latestPrice.USD * 100) / 100,
|
USDCHF: computeFx(latestPrice.USD, latestPrice.CHF),
|
||||||
USDAUD: Math.round(latestPrice.AUD / latestPrice.USD * 100) / 100,
|
USDAUD: computeFx(latestPrice.USD, latestPrice.AUD),
|
||||||
USDJPY: Math.round(latestPrice.JPY / latestPrice.USD * 100) / 100,
|
USDJPY: computeFx(latestPrice.USD, latestPrice.JPY),
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
prices: rates,
|
prices: rates as ApiPrice[],
|
||||||
exchangeRates: exchangeRates
|
exchangeRates: exchangeRates
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -141,28 +188,35 @@ class PricesRepository {
|
|||||||
|
|
||||||
public async $getHistoricalPrices(): Promise<Conversion | null> {
|
public async $getHistoricalPrices(): Promise<Conversion | null> {
|
||||||
try {
|
try {
|
||||||
const [rates]: any[] = await DB.query(`
|
const [rates] = await DB.query(`
|
||||||
SELECT *, UNIX_TIMESTAMP(time) AS time
|
SELECT ${ApiPriceFields}
|
||||||
FROM prices
|
FROM prices
|
||||||
ORDER BY time DESC
|
ORDER BY time DESC
|
||||||
`);
|
`);
|
||||||
if (!rates) {
|
if (!Array.isArray(rates)) {
|
||||||
throw Error(`Cannot get average historical price from the database`);
|
throw Error(`Cannot get average historical price from the database`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute fiat exchange rates
|
// Compute fiat exchange rates
|
||||||
const latestPrice: ApiPrice = rates[0];
|
let latestPrice = rates[0] as ApiPrice;
|
||||||
|
if (latestPrice.USD === -1) {
|
||||||
|
latestPrice = priceUpdater.getEmptyPricesObj();
|
||||||
|
}
|
||||||
|
|
||||||
|
const computeFx = (usd: number, other: number): number =>
|
||||||
|
Math.round(Math.max(other, 0) / Math.max(usd, 1) * 100) / 100;
|
||||||
|
|
||||||
const exchangeRates: ExchangeRates = {
|
const exchangeRates: ExchangeRates = {
|
||||||
USDEUR: Math.round(latestPrice.EUR / latestPrice.USD * 100) / 100,
|
USDEUR: computeFx(latestPrice.USD, latestPrice.EUR),
|
||||||
USDGBP: Math.round(latestPrice.GBP / latestPrice.USD * 100) / 100,
|
USDGBP: computeFx(latestPrice.USD, latestPrice.GBP),
|
||||||
USDCAD: Math.round(latestPrice.CAD / latestPrice.USD * 100) / 100,
|
USDCAD: computeFx(latestPrice.USD, latestPrice.CAD),
|
||||||
USDCHF: Math.round(latestPrice.CHF / latestPrice.USD * 100) / 100,
|
USDCHF: computeFx(latestPrice.USD, latestPrice.CHF),
|
||||||
USDAUD: Math.round(latestPrice.AUD / latestPrice.USD * 100) / 100,
|
USDAUD: computeFx(latestPrice.USD, latestPrice.AUD),
|
||||||
USDJPY: Math.round(latestPrice.JPY / latestPrice.USD * 100) / 100,
|
USDJPY: computeFx(latestPrice.USD, latestPrice.JPY),
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
prices: rates,
|
prices: rates as ApiPrice[],
|
||||||
exchangeRates: exchangeRates
|
exchangeRates: exchangeRates
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -8,9 +8,6 @@ class BitfinexApi implements PriceFeed {
|
|||||||
public url: string = 'https://api.bitfinex.com/v1/pubticker/BTC';
|
public url: string = 'https://api.bitfinex.com/v1/pubticker/BTC';
|
||||||
public urlHist: string = 'https://api-pub.bitfinex.com/v2/candles/trade:{GRANULARITY}:tBTC{CURRENCY}/hist';
|
public urlHist: string = 'https://api-pub.bitfinex.com/v2/candles/trade:{GRANULARITY}:tBTC{CURRENCY}/hist';
|
||||||
|
|
||||||
constructor() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public async $fetchPrice(currency): Promise<number> {
|
public async $fetchPrice(currency): Promise<number> {
|
||||||
const response = await query(this.url + currency);
|
const response = await query(this.url + currency);
|
||||||
if (response && response['last_price']) {
|
if (response && response['last_price']) {
|
||||||
|
@ -2,8 +2,7 @@ import * as fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
import { IConversionRates } from '../mempool.interfaces';
|
import PricesRepository, { ApiPrice, MAX_PRICES } from '../repositories/PricesRepository';
|
||||||
import PricesRepository, { MAX_PRICES } from '../repositories/PricesRepository';
|
|
||||||
import BitfinexApi from './price-feeds/bitfinex-api';
|
import BitfinexApi from './price-feeds/bitfinex-api';
|
||||||
import BitflyerApi from './price-feeds/bitflyer-api';
|
import BitflyerApi from './price-feeds/bitflyer-api';
|
||||||
import CoinbaseApi from './price-feeds/coinbase-api';
|
import CoinbaseApi from './price-feeds/coinbase-api';
|
||||||
@ -21,18 +20,18 @@ export interface PriceFeed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PriceHistory {
|
export interface PriceHistory {
|
||||||
[timestamp: number]: IConversionRates;
|
[timestamp: number]: ApiPrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
class PriceUpdater {
|
class PriceUpdater {
|
||||||
public historyInserted = false;
|
public historyInserted = false;
|
||||||
lastRun = 0;
|
private lastRun = 0;
|
||||||
lastHistoricalRun = 0;
|
private lastHistoricalRun = 0;
|
||||||
running = false;
|
private running = false;
|
||||||
feeds: PriceFeed[] = [];
|
private feeds: PriceFeed[] = [];
|
||||||
currencies: string[] = ['USD', 'EUR', 'GBP', 'CAD', 'CHF', 'AUD', 'JPY'];
|
private currencies: string[] = ['USD', 'EUR', 'GBP', 'CAD', 'CHF', 'AUD', 'JPY'];
|
||||||
latestPrices: IConversionRates;
|
private latestPrices: ApiPrice;
|
||||||
private ratesChangedCallback: ((rates: IConversionRates) => void) | undefined;
|
private ratesChangedCallback: ((rates: ApiPrice) => void) | undefined;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.latestPrices = this.getEmptyPricesObj();
|
this.latestPrices = this.getEmptyPricesObj();
|
||||||
@ -44,8 +43,13 @@ class PriceUpdater {
|
|||||||
this.feeds.push(new GeminiApi());
|
this.feeds.push(new GeminiApi());
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEmptyPricesObj(): IConversionRates {
|
public getLatestPrices(): ApiPrice {
|
||||||
|
return this.latestPrices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getEmptyPricesObj(): ApiPrice {
|
||||||
return {
|
return {
|
||||||
|
time: 0,
|
||||||
USD: -1,
|
USD: -1,
|
||||||
EUR: -1,
|
EUR: -1,
|
||||||
GBP: -1,
|
GBP: -1,
|
||||||
@ -56,7 +60,7 @@ class PriceUpdater {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public setRatesChangedCallback(fn: (rates: IConversionRates) => void) {
|
public setRatesChangedCallback(fn: (rates: ApiPrice) => void): void {
|
||||||
this.ratesChangedCallback = fn;
|
this.ratesChangedCallback = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +160,10 @@ class PriceUpdater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.lastRun = new Date().getTime() / 1000;
|
this.lastRun = new Date().getTime() / 1000;
|
||||||
|
|
||||||
|
if (this.latestPrices.USD === -1) {
|
||||||
|
this.latestPrices = await PricesRepository.$getLatestConversionRates();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,7 +232,7 @@ class PriceUpdater {
|
|||||||
|
|
||||||
// Group them by timestamp and currency, for example
|
// Group them by timestamp and currency, for example
|
||||||
// grouped[123456789]['USD'] = [1, 2, 3, 4];
|
// grouped[123456789]['USD'] = [1, 2, 3, 4];
|
||||||
const grouped: any = {};
|
const grouped = {};
|
||||||
for (const historicalEntry of historicalPrices) {
|
for (const historicalEntry of historicalPrices) {
|
||||||
for (const time in historicalEntry) {
|
for (const time in historicalEntry) {
|
||||||
if (existingPriceTimes.includes(parseInt(time, 10))) {
|
if (existingPriceTimes.includes(parseInt(time, 10))) {
|
||||||
@ -249,7 +257,7 @@ class PriceUpdater {
|
|||||||
// Average prices and insert everything into the db
|
// Average prices and insert everything into the db
|
||||||
let totalInserted = 0;
|
let totalInserted = 0;
|
||||||
for (const time in grouped) {
|
for (const time in grouped) {
|
||||||
const prices: IConversionRates = this.getEmptyPricesObj();
|
const prices: ApiPrice = this.getEmptyPricesObj();
|
||||||
for (const currency in grouped[time]) {
|
for (const currency in grouped[time]) {
|
||||||
if (grouped[time][currency].length === 0) {
|
if (grouped[time][currency].length === 0) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -3,13 +3,15 @@
|
|||||||
{{ addPlus && satoshis >= 0 ? '+' : '' }}
|
{{ addPlus && satoshis >= 0 ? '+' : '' }}
|
||||||
{{
|
{{
|
||||||
(
|
(
|
||||||
(blockConversion.price[currency] >= 0 ? blockConversion.price[currency] : null) ??
|
(blockConversion.price[currency] > -1 ? blockConversion.price[currency] : null) ??
|
||||||
(blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency]) ?? 0
|
(blockConversion.price['USD'] > -1 ? blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency] : null) ?? 0
|
||||||
) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency
|
) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
<ng-template #noblockconversion>
|
<ng-template #noblockconversion>
|
||||||
<span class="fiat">{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ (conversions ? conversions[currency] : 0) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency }}</span>
|
<span class="fiat">{{ addPlus && satoshis >= 0 ? '+' : '' }}
|
||||||
|
{{ (conversions[currency] > -1 ? conversions[currency] : 0) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency }}
|
||||||
|
</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
<span class="green-color" *ngIf="blockConversion; else noblockconversion">
|
<span class="green-color" *ngIf="blockConversion; else noblockconversion">
|
||||||
{{
|
{{
|
||||||
(
|
(
|
||||||
(blockConversion.price[currency] >= 0 ? blockConversion.price[currency] : null) ??
|
(blockConversion.price[currency] > -1 ? blockConversion.price[currency] : null) ??
|
||||||
(blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency]) ?? 0
|
(blockConversion.price['USD'] > -1 ? blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency] : null) ?? 0
|
||||||
) * value / 100000000 | fiatCurrency : digitsInfo : currency
|
) * value / 100000000 | fiatCurrency : digitsInfo : currency
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<ng-template #noblockconversion>
|
<ng-template #noblockconversion>
|
||||||
<span class="green-color" *ngIf="(conversions$ | async) as conversions">
|
<span class="green-color" *ngIf="(conversions$ | async) as conversions">
|
||||||
{{ (conversions[currency] ?? conversions['USD'] ?? 0) * value / 100000000 | fiatCurrency : digitsInfo : currency }}
|
{{ (conversions[currency] > -1 ? conversions[currency] : 0) * value / 100000000 | fiatCurrency : digitsInfo : currency }}
|
||||||
</span>
|
</span>
|
||||||
</ng-template>
|
</ng-template>
|
@ -89,7 +89,7 @@ export class PriceService {
|
|||||||
return this.singlePriceObservable$.pipe(
|
return this.singlePriceObservable$.pipe(
|
||||||
map((conversion) => {
|
map((conversion) => {
|
||||||
if (conversion.prices.length <= 0) {
|
if (conversion.prices.length <= 0) {
|
||||||
return this.getEmptyPrice();
|
return undefined;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
price: {
|
price: {
|
||||||
@ -113,7 +113,7 @@ export class PriceService {
|
|||||||
|
|
||||||
return this.priceObservable$.pipe(
|
return this.priceObservable$.pipe(
|
||||||
map((conversion) => {
|
map((conversion) => {
|
||||||
if (!blockTimestamp) {
|
if (!blockTimestamp || !conversion) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user