Bisq Markets API. WIP
This commit is contained in:
291
backend/src/api/bisq/markets-api.ts
Normal file
291
backend/src/api/bisq/markets-api.ts
Normal file
@@ -0,0 +1,291 @@
|
||||
import { Currencies, OffsersData, TradesData, Depth, Currency, Interval, HighLowOpenClose,
|
||||
Markets, Offers, Offer, BisqTrade, MarketVolume, Tickers } from './interfaces';
|
||||
|
||||
class BisqMarketsApi {
|
||||
private cryptoCurrencyData: Currency[] = [];
|
||||
private fiatCurrencyData: Currency[] = [];
|
||||
private offersData: OffsersData[] = [];
|
||||
private tradesData: TradesData[] = [];
|
||||
|
||||
constructor() { }
|
||||
|
||||
public setData(cryptoCurrency: Currency[], fiatCurrency: Currency[], offers: OffsersData[], trades: TradesData[]) {
|
||||
this.cryptoCurrencyData = cryptoCurrency,
|
||||
this.fiatCurrencyData = fiatCurrency;
|
||||
this.offersData = offers;
|
||||
this.tradesData = trades;
|
||||
|
||||
this.fiatCurrencyData.forEach((currency) => currency.type = 'fiat');
|
||||
this.cryptoCurrencyData.forEach((currency) => currency.type = 'crypto');
|
||||
this.tradesData.forEach((trade) => {
|
||||
trade._market = trade.currencyPair.toLowerCase().replace('/', '_');
|
||||
});
|
||||
}
|
||||
|
||||
getCurrencies(
|
||||
type: 'crypto' | 'fiat' | 'all' = 'all',
|
||||
): Currencies {
|
||||
let currencies: Currency[];
|
||||
|
||||
switch (type) {
|
||||
case 'fiat':
|
||||
currencies = this.fiatCurrencyData;
|
||||
break;
|
||||
case 'crypto':
|
||||
currencies = this.cryptoCurrencyData;
|
||||
break;
|
||||
case 'all':
|
||||
default:
|
||||
currencies = this.cryptoCurrencyData.concat(this.fiatCurrencyData);
|
||||
}
|
||||
const result = {};
|
||||
currencies.forEach((currency) => {
|
||||
result[currency.code] = currency;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
getDepth(
|
||||
market: string,
|
||||
): Depth {
|
||||
const currencyPair = market.replace('_', '/').toUpperCase();
|
||||
|
||||
const buys = this.offersData
|
||||
.filter((offer) => offer.currencyPair === currencyPair && offer.direction === 'BUY')
|
||||
.map((offer) => offer.price)
|
||||
.sort((a, b) => b - a)
|
||||
.map((price) => this.intToBtc(price));
|
||||
|
||||
const sells = this.offersData
|
||||
.filter((offer) => offer.currencyPair === currencyPair && offer.direction === 'SELL')
|
||||
.map((offer) => offer.price)
|
||||
.sort((a, b) => a - b)
|
||||
.map((price) => this.intToBtc(price));
|
||||
|
||||
const result = {};
|
||||
result[market] = {
|
||||
'buys': buys,
|
||||
'sells': sells,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
getOffers(
|
||||
market: string,
|
||||
direction?: 'BUY' | 'SELL',
|
||||
): Offers {
|
||||
const currencyPair = market.replace('_', '/').toUpperCase();
|
||||
|
||||
let buys: Offer[] | null = null;
|
||||
let sells: Offer[] | null = null;
|
||||
|
||||
if (!direction || direction === 'BUY') {
|
||||
buys = this.offersData
|
||||
.filter((offer) => offer.currencyPair === currencyPair && offer.direction === 'BUY')
|
||||
.map((offer) => this.offerDataToOffer(offer));
|
||||
}
|
||||
|
||||
if (!direction || direction === 'SELL') {
|
||||
sells = this.offersData
|
||||
.filter((offer) => offer.currencyPair === currencyPair && offer.direction === 'SELL')
|
||||
.map((offer) => this.offerDataToOffer(offer));
|
||||
}
|
||||
|
||||
const result: Offers = {};
|
||||
result[market] = {
|
||||
'buys': buys,
|
||||
'sells': sells,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
getMarkets(): Markets {
|
||||
const allCurrencies = this.getCurrencies();
|
||||
const markets = {};
|
||||
|
||||
for (const currency of Object.keys(allCurrencies)) {
|
||||
if (allCurrencies[currency].code === 'BTC') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const isFiat = allCurrencies[currency].type === 'fiat';
|
||||
const pmarketname = allCurrencies['BTC']['name'];
|
||||
|
||||
const lsymbol = isFiat ? 'BTC' : currency;
|
||||
const rsymbol = isFiat ? currency : 'BTC';
|
||||
const lname = isFiat ? pmarketname : allCurrencies[currency].name;
|
||||
const rname = isFiat ? allCurrencies[currency].name : pmarketname;
|
||||
const ltype = isFiat ? 'crypto' : allCurrencies[currency].type;
|
||||
const rtype = isFiat ? 'fiat' : 'crypto';
|
||||
const lprecision = 8;
|
||||
const rprecision = isFiat ? 2 : 8;
|
||||
const pair = lsymbol.toLowerCase() + '_' + rsymbol.toLowerCase();
|
||||
|
||||
markets[pair] = {
|
||||
'pair': pair,
|
||||
'lname': lname,
|
||||
'rname': rname,
|
||||
'lsymbol': lsymbol,
|
||||
'rsymbol': rsymbol,
|
||||
'lprecision': lprecision,
|
||||
'rprecision': rprecision,
|
||||
'ltype': ltype,
|
||||
'rtype': rtype,
|
||||
'name': lname + '/' + rname,
|
||||
};
|
||||
}
|
||||
|
||||
return markets;
|
||||
}
|
||||
|
||||
getTrades(
|
||||
market: string,
|
||||
timestamp_from?: number,
|
||||
timestamp_to?: number,
|
||||
trade_id_from?: string,
|
||||
trade_id_to?: string,
|
||||
direction?: 'buy' | 'sell',
|
||||
limit: number = 100,
|
||||
sort: 'asc' | 'desc' = 'desc',
|
||||
): BisqTrade[] {
|
||||
limit = Math.min(limit, 2000);
|
||||
let trade_id_from_ts: number | null = null;
|
||||
let trade_id_to_ts: number | null = null;
|
||||
const _market = market === 'all' ? null : market;
|
||||
|
||||
if (!timestamp_from) {
|
||||
timestamp_from = new Date('2016-01-01').getTime();
|
||||
}
|
||||
if (!timestamp_to) {
|
||||
timestamp_to = new Date().getTime();
|
||||
}
|
||||
|
||||
const allCurrencies = this.getCurrencies();
|
||||
|
||||
// note: the offer_id_from/to depends on iterating over trades in
|
||||
// descending chronological order.
|
||||
const tradesDataSorted = this.tradesData.slice();
|
||||
if (sort === 'asc') {
|
||||
tradesDataSorted.reverse();
|
||||
}
|
||||
|
||||
let matches: TradesData[] = [];
|
||||
for (const trade of tradesDataSorted) {
|
||||
if (trade_id_from === trade.offerId) {
|
||||
trade_id_from_ts = trade.tradeDate;
|
||||
}
|
||||
if (trade_id_to === trade.offerId) {
|
||||
trade_id_to_ts = trade.tradeDate;
|
||||
}
|
||||
if (trade_id_to && trade_id_to_ts === null) {
|
||||
continue;
|
||||
}
|
||||
if (trade_id_from && trade_id_from_ts != null && trade_id_from_ts !== trade.tradeDate ) {
|
||||
continue;
|
||||
}
|
||||
if (_market && _market !== trade._market) {
|
||||
continue;
|
||||
}
|
||||
if (timestamp_from && timestamp_from > trade.tradeDate) {
|
||||
continue;
|
||||
}
|
||||
if (timestamp_to && timestamp_to < trade.tradeDate) {
|
||||
continue;
|
||||
}
|
||||
if (direction && direction !== trade.direction.toLowerCase() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter out bogus trades with BTC/BTC or XXX/XXX market.
|
||||
// See github issue: https://github.com/bitsquare/bitsquare/issues/883
|
||||
const currencyPairs = trade.currencyPair.split('/');
|
||||
if (currencyPairs[0] === currencyPairs[1]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const currencyLeft = allCurrencies[currencyPairs[0]];
|
||||
const currencyRight = allCurrencies[currencyPairs[1]];
|
||||
|
||||
trade.tradePrice = trade.primaryMarketTradePrice * Math.pow(10, 8 - currencyRight.precision);
|
||||
trade.tradeAmount = trade.primaryMarketTradeAmount * Math.pow(10, 8 - currencyLeft.precision);
|
||||
const tradeVolume = trade.primaryMarketTradeVolume * Math.pow(10, 8 - currencyRight.precision);
|
||||
|
||||
trade._tradePrice = this.intToBtc(trade.tradePrice);
|
||||
trade._tradeAmount = this.intToBtc(trade.tradeAmount);
|
||||
trade._tradeVolume = this.intToBtc(tradeVolume);
|
||||
trade._offerAmount = this.intToBtc(trade.offerAmount);
|
||||
|
||||
matches.push(trade);
|
||||
|
||||
if (matches.length >= limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((trade_id_from && !trade_id_from_ts) || (trade_id_to && !trade_id_to_ts) ) {
|
||||
matches = [];
|
||||
}
|
||||
|
||||
return matches.map((trade) => {
|
||||
return {
|
||||
direction: trade.direction,
|
||||
price: trade._tradePrice,
|
||||
amount: trade._tradeAmount,
|
||||
volume: trade._tradeVolume,
|
||||
payment_method: trade.paymentMethod,
|
||||
trade_id: trade.offerId,
|
||||
trade_date: trade.tradeDate,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getVolumes(
|
||||
timestamp_from: number,
|
||||
timestamp_to: number,
|
||||
interval: Interval,
|
||||
market?: string,
|
||||
): MarketVolume[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
getTicker(
|
||||
market?: string,
|
||||
): Tickers {
|
||||
return {};
|
||||
}
|
||||
|
||||
getHloc(
|
||||
market: string,
|
||||
interval: Interval = 'auto',
|
||||
timestamp_from?: number,
|
||||
timestamp_to?: number,
|
||||
): HighLowOpenClose[] {
|
||||
if (!timestamp_from) {
|
||||
timestamp_from = new Date('2016-01-01').getTime();
|
||||
}
|
||||
if (!timestamp_to) {
|
||||
timestamp_to = new Date().getTime();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
private offerDataToOffer(offer: OffsersData): Offer {
|
||||
return {
|
||||
offer_id: offer.id,
|
||||
offer_date: offer.date,
|
||||
direction: offer.direction,
|
||||
min_amount: this.intToBtc(offer.minAmount),
|
||||
amount: this.intToBtc(offer.amount),
|
||||
price: this.intToBtc(offer.price),
|
||||
volume: this.intToBtc(offer.primaryMarketVolume),
|
||||
payment_method: offer.paymentMethod,
|
||||
offer_fee_txid: null,
|
||||
};
|
||||
}
|
||||
|
||||
private intToBtc(val: number): string {
|
||||
return (val / 100000000).toFixed(8);
|
||||
}
|
||||
}
|
||||
|
||||
export default new BisqMarketsApi();
|
||||
Reference in New Issue
Block a user