* /volumes API
* /ticker API
This commit is contained in:
		
							parent
							
								
									a3f8555087
								
							
						
					
					
						commit
						c172de2c34
					
				@ -15,9 +15,9 @@
 | 
				
			|||||||
  "TX_PER_SECOND_SPAN_SECONDS": 150,
 | 
					  "TX_PER_SECOND_SPAN_SECONDS": 150,
 | 
				
			||||||
  "ELECTRS_API_URL": "http://localhost:50001",
 | 
					  "ELECTRS_API_URL": "http://localhost:50001",
 | 
				
			||||||
  "BISQ_ENABLED": false,
 | 
					  "BISQ_ENABLED": false,
 | 
				
			||||||
 | 
					  "BISQ_BLOCKS_DATA_PATH": "/bisq/seednode-data/btc_mainnet/db/json",
 | 
				
			||||||
  "BISQ_MARKET_ENABLED": false,
 | 
					  "BISQ_MARKET_ENABLED": false,
 | 
				
			||||||
  "BSQ_BLOCKS_DATA_PATH": "/bisq/data",
 | 
					  "BISQ_MARKETS_DATA_PATH": "/bisq/seednode-data/btc_mainnet/db",
 | 
				
			||||||
  "BSQ_MARKETS_DATA_PATH": "/bisq-folder/Bisq",
 | 
					 | 
				
			||||||
  "SSL": false,
 | 
					  "SSL": false,
 | 
				
			||||||
  "SSL_CERT_FILE_PATH": "/etc/letsencrypt/live/mysite/fullchain.pem",
 | 
					  "SSL_CERT_FILE_PATH": "/etc/letsencrypt/live/mysite/fullchain.pem",
 | 
				
			||||||
  "SSL_KEY_FILE_PATH": "/etc/letsencrypt/live/mysite/privkey.pem"
 | 
					  "SSL_KEY_FILE_PATH": "/etc/letsencrypt/live/mysite/privkey.pem"
 | 
				
			||||||
 | 
				
			|||||||
@ -72,8 +72,8 @@ class Bisq {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private checkForBisqDataFolder() {
 | 
					  private checkForBisqDataFolder() {
 | 
				
			||||||
    if (!fs.existsSync(config.BSQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH)) {
 | 
					    if (!fs.existsSync(config.BISQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH)) {
 | 
				
			||||||
      console.log(config.BSQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH + ` doesn't exist. Make sure Bisq is running and the config is correct before starting the server.`);
 | 
					      console.log(config.BISQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH + ` doesn't exist. Make sure Bisq is running and the config is correct before starting the server.`);
 | 
				
			||||||
      return process.exit(1);
 | 
					      return process.exit(1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -83,7 +83,7 @@ class Bisq {
 | 
				
			|||||||
      this.topDirectoryWatcher.close();
 | 
					      this.topDirectoryWatcher.close();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let fsWait: NodeJS.Timeout | null = null;
 | 
					    let fsWait: NodeJS.Timeout | null = null;
 | 
				
			||||||
    this.topDirectoryWatcher = fs.watch(config.BSQ_BLOCKS_DATA_PATH, () => {
 | 
					    this.topDirectoryWatcher = fs.watch(config.BISQ_BLOCKS_DATA_PATH, () => {
 | 
				
			||||||
      if (fsWait) {
 | 
					      if (fsWait) {
 | 
				
			||||||
        clearTimeout(fsWait);
 | 
					        clearTimeout(fsWait);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -105,13 +105,13 @@ class Bisq {
 | 
				
			|||||||
    if (this.subdirectoryWatcher) {
 | 
					    if (this.subdirectoryWatcher) {
 | 
				
			||||||
      this.subdirectoryWatcher.close();
 | 
					      this.subdirectoryWatcher.close();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!fs.existsSync(config.BSQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH)) {
 | 
					    if (!fs.existsSync(config.BISQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH)) {
 | 
				
			||||||
      console.log(config.BSQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH + ` doesn't exist. Trying to restart sub directory watcher again in 3 minutes.`);
 | 
					      console.log(config.BISQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH + ` doesn't exist. Trying to restart sub directory watcher again in 3 minutes.`);
 | 
				
			||||||
      setTimeout(() => this.startSubDirectoryWatcher(), 180000);
 | 
					      setTimeout(() => this.startSubDirectoryWatcher(), 180000);
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let fsWait: NodeJS.Timeout | null = null;
 | 
					    let fsWait: NodeJS.Timeout | null = null;
 | 
				
			||||||
    this.subdirectoryWatcher = fs.watch(config.BSQ_BLOCKS_DATA_PATH + '/all', () => {
 | 
					    this.subdirectoryWatcher = fs.watch(config.BISQ_BLOCKS_DATA_PATH + '/all', () => {
 | 
				
			||||||
      if (fsWait) {
 | 
					      if (fsWait) {
 | 
				
			||||||
        clearTimeout(fsWait);
 | 
					        clearTimeout(fsWait);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -243,10 +243,10 @@ class Bisq {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private loadData(): Promise<string> {
 | 
					  private loadData(): Promise<string> {
 | 
				
			||||||
    return new Promise((resolve, reject) => {
 | 
					    return new Promise((resolve, reject) => {
 | 
				
			||||||
      if (!fs.existsSync(config.BSQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH)) {
 | 
					      if (!fs.existsSync(config.BISQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH)) {
 | 
				
			||||||
        return reject(Bisq.BLOCKS_JSON_FILE_PATH + ` doesn't exist`);
 | 
					        return reject(Bisq.BLOCKS_JSON_FILE_PATH + ` doesn't exist`);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      fs.readFile(config.BSQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH, 'utf8', (err, data) => {
 | 
					      fs.readFile(config.BISQ_BLOCKS_DATA_PATH + Bisq.BLOCKS_JSON_FILE_PATH, 'utf8', (err, data) => {
 | 
				
			||||||
        if (err) {
 | 
					        if (err) {
 | 
				
			||||||
          reject(err);
 | 
					          reject(err);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -234,8 +234,8 @@ export interface TradesData {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export interface MarketVolume {
 | 
					export interface MarketVolume {
 | 
				
			||||||
  period_start: number;
 | 
					  period_start: number;
 | 
				
			||||||
  volume: string;
 | 
					 | 
				
			||||||
  num_trades: number;
 | 
					  num_trades: number;
 | 
				
			||||||
 | 
					  volume: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface MarketsApiError {
 | 
					export interface MarketsApiError {
 | 
				
			||||||
@ -244,3 +244,15 @@ export interface MarketsApiError {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type Interval = 'minute' | 'half_hour' | 'hour' | 'half_day' | 'day' | 'week' | 'month' | 'year' | 'auto';
 | 
					export type Interval = 'minute' | 'half_hour' | 'hour' | 'half_day' | 'day' | 'week' | 'month' | 'year' | 'auto';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface SummarizedIntervals { [market: string]: SummarizedInterval; }
 | 
				
			||||||
 | 
					export interface SummarizedInterval {
 | 
				
			||||||
 | 
					  'period_start': number;
 | 
				
			||||||
 | 
					  'open': number;
 | 
				
			||||||
 | 
					  'close': number;
 | 
				
			||||||
 | 
					  'high': number;
 | 
				
			||||||
 | 
					  'low': number;
 | 
				
			||||||
 | 
					  'avg': number;
 | 
				
			||||||
 | 
					  'volume_right': number;
 | 
				
			||||||
 | 
					  'volume_left': number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
import { Currencies, OffsersData, TradesData, Depth, Currency, Interval, HighLowOpenClose,
 | 
					import { Currencies, OffsersData, TradesData, Depth, Currency, Interval, HighLowOpenClose,
 | 
				
			||||||
  Markets, Offers, Offer, BisqTrade, MarketVolume, Tickers } from './interfaces';
 | 
					  Markets, Offers, Offer, BisqTrade, MarketVolume, Tickers, Ticker, SummarizedIntervals, SummarizedInterval } from './interfaces';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import * as datetime from 'locutus/php/datetime';
 | 
					import * as datetime from 'locutus/php/datetime';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -8,6 +8,8 @@ class BisqMarketsApi {
 | 
				
			|||||||
  private fiatCurrencyData: Currency[] = [];
 | 
					  private fiatCurrencyData: Currency[] = [];
 | 
				
			||||||
  private offersData: OffsersData[] = [];
 | 
					  private offersData: OffsersData[] = [];
 | 
				
			||||||
  private tradesData: TradesData[] = [];
 | 
					  private tradesData: TradesData[] = [];
 | 
				
			||||||
 | 
					  private fiatCurrenciesIndexed: { [code: string]: true } = {};
 | 
				
			||||||
 | 
					  private tradeDataByMarket: { [market: string]: TradesData[] } = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor() { }
 | 
					  constructor() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -17,10 +19,18 @@ class BisqMarketsApi {
 | 
				
			|||||||
    this.offersData = offers;
 | 
					    this.offersData = offers;
 | 
				
			||||||
    this.tradesData = trades;
 | 
					    this.tradesData = trades;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.fiatCurrencyData.forEach((currency) => currency._type = 'fiat');
 | 
					    // Handle data for smarter memory caching
 | 
				
			||||||
 | 
					    this.fiatCurrencyData.forEach((currency) => {
 | 
				
			||||||
 | 
					      currency._type = 'fiat';
 | 
				
			||||||
 | 
					      this.fiatCurrenciesIndexed[currency.code] = true;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    this.cryptoCurrencyData.forEach((currency) => currency._type = 'crypto');
 | 
					    this.cryptoCurrencyData.forEach((currency) => currency._type = 'crypto');
 | 
				
			||||||
    this.tradesData.forEach((trade) => {
 | 
					    this.tradesData.forEach((trade) => {
 | 
				
			||||||
      trade._market = trade.currencyPair.toLowerCase().replace('/', '_');
 | 
					      trade._market = trade.currencyPair.toLowerCase().replace('/', '_');
 | 
				
			||||||
 | 
					      if (!this.tradeDataByMarket[trade._market]) {
 | 
				
			||||||
 | 
					        this.tradeDataByMarket[trade._market] = [];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.tradeDataByMarket[trade._market].push(trade);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -153,7 +163,7 @@ class BisqMarketsApi {
 | 
				
			|||||||
    sort: 'asc' | 'desc' = 'desc',
 | 
					    sort: 'asc' | 'desc' = 'desc',
 | 
				
			||||||
  ): BisqTrade[] {
 | 
					  ): BisqTrade[] {
 | 
				
			||||||
      limit = Math.min(limit, 2000);
 | 
					      limit = Math.min(limit, 2000);
 | 
				
			||||||
      const _market = market === 'all' ? null : market;
 | 
					      const _market = market === 'all' ? undefined : market;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!timestamp_from) {
 | 
					      if (!timestamp_from) {
 | 
				
			||||||
        timestamp_from = new Date('2016-01-01').getTime() / 1000;
 | 
					        timestamp_from = new Date('2016-01-01').getTime() / 1000;
 | 
				
			||||||
@ -188,18 +198,149 @@ class BisqMarketsApi {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getVolumes(
 | 
					  getVolumes(
 | 
				
			||||||
    timestamp_from: number,
 | 
					 | 
				
			||||||
    timestamp_to: number,
 | 
					 | 
				
			||||||
    interval: Interval,
 | 
					 | 
				
			||||||
    market?: string,
 | 
					    market?: string,
 | 
				
			||||||
    ): MarketVolume[] {
 | 
					    timestamp_from?: number,
 | 
				
			||||||
    return [];
 | 
					    timestamp_to?: number,
 | 
				
			||||||
 | 
					    interval: Interval = 'auto',
 | 
				
			||||||
 | 
					    milliseconds?: boolean,
 | 
				
			||||||
 | 
					  ): MarketVolume[] {
 | 
				
			||||||
 | 
					    if (milliseconds) {
 | 
				
			||||||
 | 
					      timestamp_from = timestamp_from ? timestamp_from / 1000 : timestamp_from;
 | 
				
			||||||
 | 
					      timestamp_to = timestamp_to ? timestamp_to / 1000 : timestamp_to;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!timestamp_from) {
 | 
				
			||||||
 | 
					      timestamp_from = new Date('2016-01-01').getTime() / 1000;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!timestamp_to) {
 | 
				
			||||||
 | 
					      timestamp_to = new Date().getTime() / 1000;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const trades = this.getTradesByCriteria(market, timestamp_to, timestamp_from,
 | 
				
			||||||
 | 
					      undefined, undefined, undefined, 'asc', Number.MAX_SAFE_INTEGER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (interval === 'auto') {
 | 
				
			||||||
 | 
					      const range = timestamp_to - timestamp_from;
 | 
				
			||||||
 | 
					      interval = this.getIntervalFromRange(range);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const intervals: any = {};
 | 
				
			||||||
 | 
					    const marketVolumes: MarketVolume[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const trade of trades) {
 | 
				
			||||||
 | 
					      const traded_at = trade['tradeDate'] / 1000;
 | 
				
			||||||
 | 
					      const interval_start = this.intervalStart(traded_at, interval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!intervals[interval_start]) {
 | 
				
			||||||
 | 
					        intervals[interval_start] = {
 | 
				
			||||||
 | 
					          'volume': 0,
 | 
				
			||||||
 | 
					          'num_trades': 0,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const period = intervals[interval_start];
 | 
				
			||||||
 | 
					      period['period_start'] = interval_start;
 | 
				
			||||||
 | 
					      period['volume'] += this.fiatCurrenciesIndexed[trade.currency] ? trade._tradeAmount : trade._tradeVolume;
 | 
				
			||||||
 | 
					      period['num_trades']++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const p in intervals) {
 | 
				
			||||||
 | 
					      if (intervals.hasOwnProperty(p)) {
 | 
				
			||||||
 | 
					        const period = intervals[p];
 | 
				
			||||||
 | 
					        marketVolumes.push({
 | 
				
			||||||
 | 
					          period_start: period['period_start'],
 | 
				
			||||||
 | 
					          num_trades: period['num_trades'],
 | 
				
			||||||
 | 
					          volume: this.intToBtc(period['volume']),
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return intervals;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getTicker(
 | 
					  getTicker(
 | 
				
			||||||
    market?: string,
 | 
					    market?: string,
 | 
				
			||||||
  ): Tickers {
 | 
					  ): Tickers | Ticker | null {
 | 
				
			||||||
    return {};
 | 
					    if (market) {
 | 
				
			||||||
 | 
					      return this.getTickerFromMarket(market);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const allMarkets = this.getMarkets();
 | 
				
			||||||
 | 
					    const tickers = {};
 | 
				
			||||||
 | 
					    for (const m in allMarkets) {
 | 
				
			||||||
 | 
					      if (allMarkets.hasOwnProperty(m)) {
 | 
				
			||||||
 | 
					        tickers[allMarkets[m].pair] = this.getTickerFromMarket(allMarkets[m].pair);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return tickers;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getTickerFromMarket(market: string): Ticker | null {
 | 
				
			||||||
 | 
					    let ticker: Ticker;
 | 
				
			||||||
 | 
					    const timestamp_from = datetime.strtotime('-24 hour');
 | 
				
			||||||
 | 
					    const timestamp_to = new Date().getTime() / 1000;
 | 
				
			||||||
 | 
					    const trades = this.getTradesByCriteria(market, timestamp_to, timestamp_from,
 | 
				
			||||||
 | 
					      undefined, undefined, undefined, 'asc', Number.MAX_SAFE_INTEGER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const periods: SummarizedInterval[] = Object.values(this.getTradesSummarized(trades, timestamp_from));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const allCurrencies = this.getCurrencies();
 | 
				
			||||||
 | 
					    const currencyRight = allCurrencies[market.split('_')[1].toUpperCase()];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (periods[0]) {
 | 
				
			||||||
 | 
					      ticker = {
 | 
				
			||||||
 | 
					        'last': this.intToBtc(periods[0].close),
 | 
				
			||||||
 | 
					        'high': this.intToBtc(periods[0].high),
 | 
				
			||||||
 | 
					        'low': this.intToBtc(periods[0].low),
 | 
				
			||||||
 | 
					        'volume_left': this.intToBtc(periods[0].volume_left),
 | 
				
			||||||
 | 
					        'volume_right': this.intToBtc(periods[0].volume_right),
 | 
				
			||||||
 | 
					        'buy': null,
 | 
				
			||||||
 | 
					        'sell': null,
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      const lastTrade = this.tradeDataByMarket[market];
 | 
				
			||||||
 | 
					      if (!lastTrade) {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const tradePrice = lastTrade[0].primaryMarketTradePrice * Math.pow(10, 8 - currencyRight.precision);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const lastTradePrice = this.intToBtc(tradePrice);
 | 
				
			||||||
 | 
					      ticker = {
 | 
				
			||||||
 | 
					        'last': lastTradePrice,
 | 
				
			||||||
 | 
					        'high': lastTradePrice,
 | 
				
			||||||
 | 
					        'low': lastTradePrice,
 | 
				
			||||||
 | 
					        'volume_left': '0',
 | 
				
			||||||
 | 
					        'volume_right': '0',
 | 
				
			||||||
 | 
					        'buy': null,
 | 
				
			||||||
 | 
					        'sell': null,
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const timestampFromMilli = timestamp_from * 1000;
 | 
				
			||||||
 | 
					    const timestampToMilli = timestamp_to * 1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const currencyPair = market.replace('_', '/').toUpperCase();
 | 
				
			||||||
 | 
					    const offersData = this.offersData.slice().sort((a, b) => a.price - b.price);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const buy = offersData.find((offer) => offer.currencyPair === currencyPair
 | 
				
			||||||
 | 
					                                          && offer.primaryMarketDirection === 'BUY'
 | 
				
			||||||
 | 
					                                          && offer.date >= timestampFromMilli
 | 
				
			||||||
 | 
					                                          && offer.date <= timestampToMilli
 | 
				
			||||||
 | 
					                                        );
 | 
				
			||||||
 | 
					    const sell = offersData.find((offer) => offer.currencyPair === currencyPair
 | 
				
			||||||
 | 
					                                            && offer.primaryMarketDirection === 'SELL'
 | 
				
			||||||
 | 
					                                            && offer.date >= timestampFromMilli
 | 
				
			||||||
 | 
					                                            && offer.date <= timestampToMilli
 | 
				
			||||||
 | 
					                                          );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (buy) {
 | 
				
			||||||
 | 
					      ticker.buy = this.intToBtc(buy.primaryMarketPrice * Math.pow(10, 8 - currencyRight.precision));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (sell) {
 | 
				
			||||||
 | 
					      ticker.sell = this.intToBtc(sell.primaryMarketPrice * Math.pow(10, 8 - currencyRight.precision));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ticker;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getHloc(
 | 
					  getHloc(
 | 
				
			||||||
@ -220,53 +361,73 @@ class BisqMarketsApi {
 | 
				
			|||||||
      timestamp_to = new Date().getTime() / 1000;
 | 
					      timestamp_to = new Date().getTime() / 1000;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const range = timestamp_to - timestamp_from;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const trades = this.getTradesByCriteria(market, timestamp_to, timestamp_from,
 | 
					    const trades = this.getTradesByCriteria(market, timestamp_to, timestamp_from,
 | 
				
			||||||
      undefined, undefined, undefined, 'asc', Number.MAX_SAFE_INTEGER);
 | 
					      undefined, undefined, undefined, 'asc', Number.MAX_SAFE_INTEGER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (interval === 'auto') {
 | 
					    if (interval === 'auto') {
 | 
				
			||||||
        // two days range loads minute data
 | 
					      const range = timestamp_to - timestamp_from;
 | 
				
			||||||
        if (range <= 3600) {
 | 
					      interval = this.getIntervalFromRange(range);
 | 
				
			||||||
          // up to one hour range loads minutely data
 | 
					 | 
				
			||||||
          interval = 'minute';
 | 
					 | 
				
			||||||
        } else if (range <= 1 * 24 * 3600) {
 | 
					 | 
				
			||||||
          // up to one day range loads half-hourly data
 | 
					 | 
				
			||||||
          interval = 'half_hour';
 | 
					 | 
				
			||||||
        } else if (range <= 3 * 24 * 3600) {
 | 
					 | 
				
			||||||
          // up to 3 day range loads hourly data
 | 
					 | 
				
			||||||
          interval = 'hour';
 | 
					 | 
				
			||||||
        } else if (range <= 7 * 24 * 3600) {
 | 
					 | 
				
			||||||
          // up to 7 day range loads half-daily data
 | 
					 | 
				
			||||||
          interval = 'half_day';
 | 
					 | 
				
			||||||
        } else if (range <= 60 * 24 * 3600) {
 | 
					 | 
				
			||||||
          // up to 2 month range loads daily data
 | 
					 | 
				
			||||||
          interval = 'day';
 | 
					 | 
				
			||||||
        } else if (range <= 12 * 31 * 24 * 3600) {
 | 
					 | 
				
			||||||
          // up to one year range loads weekly data
 | 
					 | 
				
			||||||
          interval = 'week';
 | 
					 | 
				
			||||||
        } else if (range <= 12 * 31 * 24 * 3600) {
 | 
					 | 
				
			||||||
          // up to 5 year range loads monthly data
 | 
					 | 
				
			||||||
          interval = 'month';
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          // greater range loads yearly data
 | 
					 | 
				
			||||||
          interval = 'year';
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const hlocs = this.getTradesSummarized(trades, timestamp_from, interval);
 | 
					    const intervals = this.getTradesSummarized(trades, timestamp_from, interval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return hlocs;
 | 
					    const hloc: HighLowOpenClose[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const p in intervals) {
 | 
				
			||||||
 | 
					      if (intervals.hasOwnProperty(p)) {
 | 
				
			||||||
 | 
					        const period = intervals[p];
 | 
				
			||||||
 | 
					        hloc.push({
 | 
				
			||||||
 | 
					          period_start: period['period_start'],
 | 
				
			||||||
 | 
					          open: this.intToBtc(period['open']),
 | 
				
			||||||
 | 
					          close: this.intToBtc(period['close']),
 | 
				
			||||||
 | 
					          high: this.intToBtc(period['high']),
 | 
				
			||||||
 | 
					          low: this.intToBtc(period['low']),
 | 
				
			||||||
 | 
					          avg: this.intToBtc(period['avg']),
 | 
				
			||||||
 | 
					          volume_right: this.intToBtc(period['volume_right']),
 | 
				
			||||||
 | 
					          volume_left: this.intToBtc(period['volume_left']),
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return hloc;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private getTradesSummarized(trades: TradesData[], timestamp_from, interval: string): HighLowOpenClose[] {
 | 
					  private getIntervalFromRange(range: number): Interval {
 | 
				
			||||||
 | 
					    // two days range loads minute data
 | 
				
			||||||
 | 
					    if (range <= 3600) {
 | 
				
			||||||
 | 
					      // up to one hour range loads minutely data
 | 
				
			||||||
 | 
					      return 'minute';
 | 
				
			||||||
 | 
					    } else if (range <= 1 * 24 * 3600) {
 | 
				
			||||||
 | 
					      // up to one day range loads half-hourly data
 | 
				
			||||||
 | 
					      return 'half_hour';
 | 
				
			||||||
 | 
					    } else if (range <= 3 * 24 * 3600) {
 | 
				
			||||||
 | 
					      // up to 3 day range loads hourly data
 | 
				
			||||||
 | 
					      return 'hour';
 | 
				
			||||||
 | 
					    } else if (range <= 7 * 24 * 3600) {
 | 
				
			||||||
 | 
					      // up to 7 day range loads half-daily data
 | 
				
			||||||
 | 
					      return 'half_day';
 | 
				
			||||||
 | 
					    } else if (range <= 60 * 24 * 3600) {
 | 
				
			||||||
 | 
					      // up to 2 month range loads daily data
 | 
				
			||||||
 | 
					      return 'day';
 | 
				
			||||||
 | 
					    } else if (range <= 12 * 31 * 24 * 3600) {
 | 
				
			||||||
 | 
					      // up to one year range loads weekly data
 | 
				
			||||||
 | 
					      return 'week';
 | 
				
			||||||
 | 
					    } else if (range <= 12 * 31 * 24 * 3600) {
 | 
				
			||||||
 | 
					      // up to 5 year range loads monthly data
 | 
				
			||||||
 | 
					      return 'month';
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // greater range loads yearly data
 | 
				
			||||||
 | 
					      return 'year';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private getTradesSummarized(trades: TradesData[], timestamp_from: number, interval?: string): SummarizedIntervals {
 | 
				
			||||||
    const intervals: any = {};
 | 
					    const intervals: any = {};
 | 
				
			||||||
    const intervals_prices: any = {};
 | 
					    const intervals_prices: any = {};
 | 
				
			||||||
    const one_period = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (const trade of trades) {
 | 
					    for (const trade of trades) {
 | 
				
			||||||
      const traded_at = trade.tradeDate / 1000;
 | 
					      const traded_at = trade.tradeDate / 1000;
 | 
				
			||||||
      const interval_start = one_period ? timestamp_from : this.intervalStart(traded_at, interval);
 | 
					      const interval_start = !interval ? timestamp_from : this.intervalStart(traded_at, interval);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!intervals[interval_start]) {
 | 
					      if (!intervals[interval_start]) {
 | 
				
			||||||
          intervals[interval_start] = {
 | 
					          intervals[interval_start] = {
 | 
				
			||||||
@ -306,30 +467,11 @@ class BisqMarketsApi {
 | 
				
			|||||||
          period['volume_right'] += trade._tradeVolume;
 | 
					          period['volume_right'] += trade._tradeVolume;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return intervals;
 | 
				
			||||||
    const hloc: HighLowOpenClose[] = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (const p in intervals) {
 | 
					 | 
				
			||||||
      if (intervals.hasOwnProperty(p)) {
 | 
					 | 
				
			||||||
        const period = intervals[p];
 | 
					 | 
				
			||||||
        hloc.push({
 | 
					 | 
				
			||||||
          period_start: period['period_start'],
 | 
					 | 
				
			||||||
          open: this.intToBtc(period['open']),
 | 
					 | 
				
			||||||
          close: this.intToBtc(period['close']),
 | 
					 | 
				
			||||||
          high: this.intToBtc(period['high']),
 | 
					 | 
				
			||||||
          low: this.intToBtc(period['low']),
 | 
					 | 
				
			||||||
          avg: this.intToBtc(period['avg']),
 | 
					 | 
				
			||||||
          volume_right: this.intToBtc(period['volume_right']),
 | 
					 | 
				
			||||||
          volume_left: this.intToBtc(period['volume_left']),
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return hloc;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private getTradesByCriteria(
 | 
					  private getTradesByCriteria(
 | 
				
			||||||
    market: string | null,
 | 
					    market: string | undefined,
 | 
				
			||||||
    timestamp_to: number,
 | 
					    timestamp_to: number,
 | 
				
			||||||
    timestamp_from: number,
 | 
					    timestamp_from: number,
 | 
				
			||||||
    trade_id_to: string | undefined,
 | 
					    trade_id_to: string | undefined,
 | 
				
			||||||
@ -422,7 +564,7 @@ class BisqMarketsApi {
 | 
				
			|||||||
    return matches;
 | 
					    return matches;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private intervalStart(ts: number, interval: string) {
 | 
					  private intervalStart(ts: number, interval: string): number {
 | 
				
			||||||
    switch (interval) {
 | 
					    switch (interval) {
 | 
				
			||||||
        case 'minute':
 | 
					        case 'minute':
 | 
				
			||||||
            return (ts - (ts % 60));
 | 
					            return (ts - (ts % 60));
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ import { OffsersData, TradesData, Currency } from './interfaces';
 | 
				
			|||||||
import bisqMarket from './markets-api';
 | 
					import bisqMarket from './markets-api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Bisq {
 | 
					class Bisq {
 | 
				
			||||||
  private static MARKET_JSON_PATH = config.BSQ_MARKETS_DATA_PATH + '/btc_mainnet/db';
 | 
					  private static MARKET_JSON_PATH = config.BISQ_MARKETS_DATA_PATH + '/btc_mainnet/db';
 | 
				
			||||||
  private static MARKET_JSON_FILE_PATHS = {
 | 
					  private static MARKET_JSON_FILE_PATHS = {
 | 
				
			||||||
    cryptoCurrency: '/crypto_currency_list.json',
 | 
					    cryptoCurrency: '/crypto_currency_list.json',
 | 
				
			||||||
    fiatCurrency: '/fiat_currency_list.json',
 | 
					    fiatCurrency: '/fiat_currency_list.json',
 | 
				
			||||||
 | 
				
			|||||||
@ -175,7 +175,7 @@ class Routes {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const p = this.parseRequestParameters(req, constraints);
 | 
					    const p = this.parseRequestParameters(req, constraints);
 | 
				
			||||||
    if (p.error) {
 | 
					    if (p.error) {
 | 
				
			||||||
      res.status(501).json(this.getBisqMarketErrorResponse(p.error));
 | 
					      res.status(400).json(this.getBisqMarketErrorResponse(p.error));
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -197,7 +197,7 @@ class Routes {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const p = this.parseRequestParameters(req, constraints);
 | 
					    const p = this.parseRequestParameters(req, constraints);
 | 
				
			||||||
    if (p.error) {
 | 
					    if (p.error) {
 | 
				
			||||||
      res.status(501).json(this.getBisqMarketErrorResponse(p.error));
 | 
					      res.status(400).json(this.getBisqMarketErrorResponse(p.error));
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -256,7 +256,7 @@ class Routes {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const p = this.parseRequestParameters(req, constraints);
 | 
					    const p = this.parseRequestParameters(req, constraints);
 | 
				
			||||||
    if (p.error) {
 | 
					    if (p.error) {
 | 
				
			||||||
      res.status(501).json(this.getBisqMarketErrorResponse(p.error));
 | 
					      res.status(400).json(this.getBisqMarketErrorResponse(p.error));
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -283,7 +283,7 @@ class Routes {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const p = this.parseRequestParameters(req, constraints);
 | 
					    const p = this.parseRequestParameters(req, constraints);
 | 
				
			||||||
    if (p.error) {
 | 
					    if (p.error) {
 | 
				
			||||||
      res.status(501).json(this.getBisqMarketErrorResponse(p.error));
 | 
					      res.status(400).json(this.getBisqMarketErrorResponse(p.error));
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -298,7 +298,7 @@ class Routes {
 | 
				
			|||||||
  public getBisqMarketVolumes(req: Request, res: Response) {
 | 
					  public getBisqMarketVolumes(req: Request, res: Response) {
 | 
				
			||||||
    const constraints: RequiredSpec = {
 | 
					    const constraints: RequiredSpec = {
 | 
				
			||||||
      'market': {
 | 
					      'market': {
 | 
				
			||||||
        required: true,
 | 
					        required: false,
 | 
				
			||||||
        types: ['@string']
 | 
					        types: ['@string']
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      'interval': {
 | 
					      'interval': {
 | 
				
			||||||
@ -313,15 +313,19 @@ class Routes {
 | 
				
			|||||||
        required: false,
 | 
					        required: false,
 | 
				
			||||||
        types: ['@number']
 | 
					        types: ['@number']
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      'milliseconds': {
 | 
				
			||||||
 | 
					        required: false,
 | 
				
			||||||
 | 
					        types: ['@boolean']
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const p = this.parseRequestParameters(req, constraints);
 | 
					    const p = this.parseRequestParameters(req, constraints);
 | 
				
			||||||
    if (p.error) {
 | 
					    if (p.error) {
 | 
				
			||||||
      res.status(501).json(this.getBisqMarketErrorResponse(p.error));
 | 
					      res.status(400).json(this.getBisqMarketErrorResponse(p.error));
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const result = bisqMarket.getVolumes(p.timestamp_from, p.timestamp_to, p.interval, p.market);
 | 
					    const result = bisqMarket.getVolumes(p.market, p.timestamp_from, p.timestamp_to, p.interval, p.milliseconds);
 | 
				
			||||||
    if (result) {
 | 
					    if (result) {
 | 
				
			||||||
      res.json(result);
 | 
					      res.json(result);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@ -355,7 +359,7 @@ class Routes {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const p = this.parseRequestParameters(req, constraints);
 | 
					    const p = this.parseRequestParameters(req, constraints);
 | 
				
			||||||
    if (p.error) {
 | 
					    if (p.error) {
 | 
				
			||||||
      res.status(501).json(this.getBisqMarketErrorResponse(p.error));
 | 
					      res.status(400).json(this.getBisqMarketErrorResponse(p.error));
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -377,11 +381,11 @@ class Routes {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const p = this.parseRequestParameters(req, constraints);
 | 
					    const p = this.parseRequestParameters(req, constraints);
 | 
				
			||||||
    if (p.error) {
 | 
					    if (p.error) {
 | 
				
			||||||
      res.status(501).json(this.getBisqMarketErrorResponse(p.error));
 | 
					      res.status(400).json(this.getBisqMarketErrorResponse(p.error));
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const result = bisqMarket.getCurrencies(p.market);
 | 
					    const result = bisqMarket.getTicker(p.market);
 | 
				
			||||||
    if (result) {
 | 
					    if (result) {
 | 
				
			||||||
      res.json(result);
 | 
					      res.json(result);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@
 | 
				
			|||||||
  "TX_PER_SECOND_SPAN_SECONDS": 150,
 | 
					  "TX_PER_SECOND_SPAN_SECONDS": 150,
 | 
				
			||||||
  "ELECTRS_API_URL": "http://[::1]:3000",
 | 
					  "ELECTRS_API_URL": "http://[::1]:3000",
 | 
				
			||||||
  "BISQ_ENABLED": true,
 | 
					  "BISQ_ENABLED": true,
 | 
				
			||||||
  "BSQ_BLOCKS_DATA_PATH": "/bisq/data",
 | 
					  "BISQ_BLOCKS_DATA_PATH": "/bisq/data",
 | 
				
			||||||
  "SSL": false,
 | 
					  "SSL": false,
 | 
				
			||||||
  "SSL_CERT_FILE_PATH": "/etc/letsencrypt/live/mysite/fullchain.pem",
 | 
					  "SSL_CERT_FILE_PATH": "/etc/letsencrypt/live/mysite/fullchain.pem",
 | 
				
			||||||
  "SSL_KEY_FILE_PATH": "/etc/letsencrypt/live/mysite/privkey.pem"
 | 
					  "SSL_KEY_FILE_PATH": "/etc/letsencrypt/live/mysite/privkey.pem"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user