@jmparsons/ccxt
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 100+ exchanges
216 lines (205 loc) • 7.92 kB
JavaScript
'use strict';
// ---------------------------------------------------------------------------
const liqui = require ('./liqui.js');
const { ExchangeError, InsufficientFunds, DDoSProtection } = require ('./base/errors');
// ---------------------------------------------------------------------------
module.exports = class yobit extends liqui {
describe () {
return this.deepExtend (super.describe (), {
'id': 'yobit',
'name': 'YoBit',
'countries': 'RU',
'rateLimit': 3000, // responses are cached every 2 seconds
'version': '3',
'has': {
'createDepositAddress': true,
'fetchDepositAddress': true,
'CORS': false,
'withdraw': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27766910-cdcbfdae-5eea-11e7-9859-03fea873272d.jpg',
'api': {
'public': 'https://yobit.net/api',
'private': 'https://yobit.net/tapi',
},
'www': 'https://www.yobit.net',
'doc': 'https://www.yobit.net/en/api/',
'fees': 'https://www.yobit.net/en/fees/',
},
'api': {
'public': {
'get': [
'depth/{pair}',
'info',
'ticker/{pair}',
'trades/{pair}',
],
},
'private': {
'post': [
'ActiveOrders',
'CancelOrder',
'GetDepositAddress',
'getInfo',
'OrderInfo',
'Trade',
'TradeHistory',
'WithdrawCoinsToAddress',
],
},
},
'fees': {
'trading': {
'maker': 0.002,
'taker': 0.002,
},
'funding': {
'withdraw': {},
},
},
'commonCurrencies': {
'AIR': 'AirCoin',
'ANI': 'ANICoin',
'ANT': 'AntsCoin',
'AST': 'Astral',
'ATM': 'Autumncoin',
'BCC': 'BCH',
'BCS': 'BitcoinStake',
'BLN': 'Bulleon',
'BTS': 'Bitshares2',
'CAT': 'BitClave',
'COV': 'Coven Coin',
'CPC': 'Capricoin',
'CS': 'CryptoSpots',
'DCT': 'Discount',
'DGD': 'DarkGoldCoin',
'DROP': 'FaucetCoin',
'ERT': 'Eristica Token',
'ICN': 'iCoin',
'KNC': 'KingN Coin',
'LIZI': 'LiZi',
'LOC': 'LocoCoin',
'LOCX': 'LOC',
'LUN': 'LunarCoin',
'MDT': 'Midnight',
'NAV': 'NavajoCoin',
'OMG': 'OMGame',
'STK': 'StakeCoin',
'PAY': 'EPAY',
'PLC': 'Platin Coin',
'REP': 'Republicoin',
'RUR': 'RUB',
'XIN': 'XINCoin',
},
'options': {
'fetchOrdersRequiresSymbol': true,
},
});
}
parseOrderStatus (status) {
let statuses = {
'0': 'open',
'1': 'closed',
'2': 'canceled',
'3': 'open', // or partially-filled and closed? https://github.com/ccxt/ccxt/issues/1594
};
if (status in statuses)
return statuses[status];
return status;
}
async fetchBalance (params = {}) {
await this.loadMarkets ();
let response = await this.privatePostGetInfo ();
let balances = response['return'];
let result = { 'info': balances };
let sides = { 'free': 'funds', 'total': 'funds_incl_orders' };
let keys = Object.keys (sides);
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
let side = sides[key];
if (side in balances) {
let currencies = Object.keys (balances[side]);
for (let j = 0; j < currencies.length; j++) {
let lowercase = currencies[j];
let uppercase = lowercase.toUpperCase ();
let currency = this.commonCurrencyCode (uppercase);
let account = undefined;
if (currency in result) {
account = result[currency];
} else {
account = this.account ();
}
account[key] = balances[side][lowercase];
if ((typeof account['total'] !== 'undefined') && (typeof account['free'] !== 'undefined'))
account['used'] = account['total'] - account['free'];
result[currency] = account;
}
}
}
return this.parseBalance (result);
}
async createDepositAddress (code, params = {}) {
let response = await this.fetchDepositAddress (code, this.extend ({
'need_new': 1,
}, params));
let address = this.safeString (response, 'address');
this.checkAddress (address);
return {
'currency': code,
'address': address,
'status': 'ok',
'info': response['info'],
};
}
async fetchDepositAddress (code, params = {}) {
await this.loadMarkets ();
let currency = this.currency (code);
let request = {
'coinName': currency['id'],
'need_new': 0,
};
let response = await this.privatePostGetDepositAddress (this.extend (request, params));
let address = this.safeString (response['return'], 'address');
this.checkAddress (address);
return {
'currency': code,
'address': address,
'status': 'ok',
'info': response,
};
}
async withdraw (code, amount, address, tag = undefined, params = {}) {
this.checkAddress (address);
await this.loadMarkets ();
let currency = this.currency (code);
let response = await this.privatePostWithdrawCoinsToAddress (this.extend ({
'coinName': currency['id'],
'amount': amount,
'address': address,
}, params));
return {
'info': response,
'id': undefined,
};
}
handleErrors (code, reason, url, method, headers, body) {
if (body[0] === '{') {
let response = JSON.parse (body);
if ('success' in response) {
if (!response['success']) {
if ('error_log' in response) {
if (response['error_log'].indexOf ('Insufficient funds') >= 0) { // not enougTh is a typo inside Liqui's own API...
throw new InsufficientFunds (this.id + ' ' + this.json (response));
} else if (response['error_log'] === 'Requests too often') {
throw new DDoSProtection (this.id + ' ' + this.json (response));
} else if ((response['error_log'] === 'not available') || (response['error_log'] === 'external service unavailable')) {
throw new DDoSProtection (this.id + ' ' + this.json (response));
}
}
throw new ExchangeError (this.id + ' ' + this.json (response));
}
}
}
}
};