@madnai/ccxt
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges
686 lines (660 loc) • 39 kB
JavaScript
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError, ArgumentsRequired, AuthenticationError, InsufficientFunds, InvalidOrder, OrderNotFound } = require ('./base/errors');
// ---------------------------------------------------------------------------
module.exports = class bcex extends Exchange {
describe () {
return this.deepExtend (super.describe (), {
'id': 'bcex',
'name': 'BCEX',
'countries': [ 'CN', 'HK' ],
'version': '1',
'has': {
'cancelOrder': true,
'createOrder': true,
'fetchBalance': true,
'fetchClosedOrders': 'emulated',
'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrders': true,
'fetchOrderBook': true,
'fetchTicker': true,
'fetchTickers': false,
'fetchTrades': true,
'fetchTradingLimits': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/51840849/77231516-851c6900-6bac-11ea-8fd6-ee5c23eddbd4.jpg',
'api': 'https://www.bcex.top',
'www': 'https://www.bcex.top',
'doc': 'https://github.com/BCEX-TECHNOLOGY-LIMITED/API_Docs/wiki/Interface',
'fees': 'https://bcex.udesk.cn/hc/articles/57085',
'referral': 'https://www.bcex.top/register?invite_code=758978&lang=en',
},
'status': {
'status': 'error',
'updated': undefined,
'eta': undefined,
'url': undefined,
},
'api': {
'public': {
'get': [
'Api_Market/getPriceList', // tickers
'Api_Order/ticker', // last ohlcv candle (ticker)
'Api_Order/depth', // orderbook
'Api_Market/getCoinTrade', // ticker
'Api_Order/marketOrder', // trades...
],
'post': [
'Api_Market/getPriceList', // tickers
'Api_Order/ticker', // last ohlcv candle (ticker)
'Api_Order/depth', // orderbook
'Api_Market/getCoinTrade', // ticker
'Api_Order/marketOrder', // trades...
],
},
'private': {
'post': [
'Api_Order/cancel',
'Api_Order/coinTrust', // limit order
'Api_Order/orderList', // open / all orders (my trades?)
'Api_Order/orderInfo',
'Api_Order/tradeList', // open / all orders
'Api_Order/trustList', // ?
'Api_User/userBalance',
],
},
},
'fees': {
'trading': {
'tierBased': false,
'percentage': true,
'maker': 0.1 / 100,
'taker': 0.2 / 100,
},
'funding': {
'tierBased': false,
'percentage': false,
'withdraw': {
'ckusd': 0.0,
'other': 0.05 / 100,
},
'deposit': {},
},
},
'exceptions': {
'该币不存在,非法操作': ExchangeError, // { code: 1, msg: "该币不存在,非法操作" } - returned when a required symbol parameter is missing in the request (also, maybe on other types of errors as well)
'公钥不合法': AuthenticationError, // { code: 1, msg: '公钥不合法' } - wrong public key
'您的可用余额不足': InsufficientFunds, // { code: 1, msg: '您的可用余额不足' } - your available balance is insufficient
'您的btc不足': InsufficientFunds, // { code: 1, msg: '您的btc不足' } - your btc is insufficient
'参数非法': InvalidOrder, // {'code': 1, 'msg': '参数非法'} - 'Parameter illegal'
'订单信息不存在': OrderNotFound, // {'code': 1, 'msg': '订单信息不存在'} - 'Order information does not exist'
},
'commonCurrencies': {
'UNI': 'UNI COIN',
'PNT': 'Penta',
},
'options': {
'limits': {
// hardcoding is deprecated, using these predefined values is not recommended, use loadTradingLimits instead
'AFC/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 6, 'max': 120000 }}},
'AFC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 6, 'max': 120000 }}},
'AFT/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 15, 'max': 300000 }}},
'AICC/CNET': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 5, 'max': 50000 }}},
'AIDOC/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 5, 'max': 100000 }}},
'AISI/ETH': { 'precision': { 'amount': 4, 'price': 2 }, 'limits': { 'amount': { 'min': 0.001, 'max': 500 }}},
'AIT/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 20, 'max': 400000 }}},
'ANS/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 0.1, 'max': 500 }}},
'ANS/CKUSD': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 0.1, 'max': 1000 }}},
'ARC/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 60, 'max': 600000 }}},
'AXF/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 100, 'max': 1000000 }}},
'BASH/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 250, 'max': 3000000 }}},
'BATT/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 60, 'max': 1500000 }}},
'BCD/BTC': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 0.3, 'max': 7000 }}},
'BHPC/BTC': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 2, 'max': 70000 }}},
'BHPC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 2, 'max': 60000 }}},
'BOPO/BTC': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 100, 'max': 2000000 }}},
'BOPO/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 100, 'max': 10000000 }}},
'BTC/CKUSD': { 'precision': { 'amount': 4, 'price': 2 }, 'limits': { 'amount': { 'min': 0.001, 'max': 10 }}},
'BTC/CNET': { 'precision': { 'amount': 4, 'price': 2 }, 'limits': { 'amount': { 'min': 0.0005, 'max': 5 }}},
'BTC/USDT': { 'precision': { 'amount': 4, 'price': 2 }, 'limits': { 'amount': { 'min': 0.0002, 'max': 4 }}},
'BTE/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 25, 'max': 250000 }}},
'BU/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 20, 'max': 400000 }}},
'CIC/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 3000, 'max': 30000000 }}},
'CIT/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 4, 'max': 40000 }}},
'CIT/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 4, 'max': 40000 }}},
'CMT/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 5, 'max': 2500000 }}},
'CNET/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 12, 'max': 120000 }}},
'CNMC/BTC': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 4, 'max': 50000 }}},
'CTC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 5, 'max': 550000 }}},
'CZR/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 12, 'max': 500000 }}},
'DCON/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 8, 'max': 300000 }}},
'DCT/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 2, 'max': 40000 }}},
'DCT/CKUSD': { 'precision': { 'amount': 2, 'price': 3 }, 'limits': { 'amount': { 'min': 2, 'max': 2000 }}},
'DOGE/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 3000, 'max': 14000000 }}},
'DOGE/CKUSD': { 'precision': { 'amount': 2, 'price': 6 }, 'limits': { 'amount': { 'min': 500, 'max': 2000000 }}},
'DRCT/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 16, 'max': 190000 }}},
'ELA/BTC': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 0.02, 'max': 500 }}},
'ELF/BTC': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 0.1, 'max': 100000 }}},
'ELF/CKUSD': { 'precision': { 'amount': 2, 'price': 3 }, 'limits': { 'amount': { 'min': 0.01, 'max': 100000 }}},
'EOS/CKUSD': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 0.5, 'max': 5000 }}},
'EOS/CNET': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 2.5, 'max': 30000 }}},
'EOS/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 0.18, 'max': 1800 }}},
'ETC/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 0.2, 'max': 2500 }}},
'ETC/CKUSD': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 0.2, 'max': 2500 }}},
'ETF/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 7, 'max': 150000 }}},
'ETH/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 0.015, 'max': 100 }}},
'ETH/CKUSD': { 'precision': { 'amount': 4, 'price': 4 }, 'limits': { 'amount': { 'min': 0.005, 'max': 100 }}},
'ETH/USDT': { 'precision': { 'amount': 4, 'price': 2 }, 'limits': { 'amount': { 'min': 0.005, 'max': 100 }}},
'FCT/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 0.24, 'max': 1000 }}},
'FCT/CKUSD': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 0.24, 'max': 1000 }}},
'GAME/CNET': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 1, 'max': 10000 }}},
'GOOC/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 200, 'max': 2000000 }}},
'GP/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 600, 'max': 6000000 }}},
'HSC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 1000, 'max': 20000000 }}},
'IFISH/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 300, 'max': 8000000 }}},
'IIC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 50, 'max': 4000000 }}},
'IMOS/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 15, 'max': 300000 }}},
'JC/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 300, 'max': 3000000 }}},
'LBTC/BTC': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 0.1, 'max': 3000 }}},
'LEC/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 500, 'max': 5000000 }}},
'LKY/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 10, 'max': 70000 }}},
'LKY/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 10, 'max': 100000 }}},
'LMC/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 25, 'max': 250000 }}},
'LSK/CNET': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 0.3, 'max': 3000 }}},
'LTC/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': 500 }}},
'LTC/CKUSD': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 0.01, 'max': 500 }}},
'LTC/USDT': { 'precision': { 'amount': 4, 'price': 2 }, 'limits': { 'amount': { 'min': 0.02, 'max': 450 }}},
'MC/CNET': { 'precision': { 'amount': 2, 'price': 6 }, 'limits': { 'amount': { 'min': 10000, 'max': 100000000 }}},
'MCC/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 30, 'max': 350000 }}},
'MOC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 25, 'max': 600000 }}},
'MRYC/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 300, 'max': 3000000 }}},
'MT/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 200, 'max': 6000000 }}},
'MXI/CNET': { 'precision': { 'amount': 2, 'price': 6 }, 'limits': { 'amount': { 'min': 5000, 'max': 60000000 }}},
'NAI/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 10, 'max': 100000 }}},
'NAS/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 0.2, 'max': 15000 }}},
'NAS/CKUSD': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 0.5, 'max': 5000 }}},
'NEWOS/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 65, 'max': 700000 }}},
'NKN/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 3, 'max': 350000 }}},
'NTK/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 2, 'max': 30000 }}},
'ONT/CKUSD': { 'precision': { 'amount': 2, 'price': 3 }, 'limits': { 'amount': { 'min': 0.2, 'max': 2000 }}},
'ONT/ETH': { 'precision': { 'amount': 3, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': 1000 }}},
'PNT/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 80, 'max': 800000 }}},
'PST/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 5, 'max': 100000 }}},
'PTT/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 450, 'max': 10000000 }}},
'QTUM/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 0.4, 'max': 2800 }}},
'QTUM/CKUSD': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 0.1, 'max': 1000 }}},
'RATING/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 500, 'max': 10000000 }}},
'RHC/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 1000, 'max': 10000000 }}},
'SDA/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 20, 'max': 500000 }}},
'SDD/CKUSD': { 'precision': { 'amount': 2, 'price': 3 }, 'limits': { 'amount': { 'min': 10, 'max': 100000 }}},
'SHC/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 250, 'max': 2500000 }}},
'SHE/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 100, 'max': 5000000 }}},
'SMC/CNET': { 'precision': { 'amount': 2, 'price': 6 }, 'limits': { 'amount': { 'min': 1000, 'max': 10000000 }}},
'SOP/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 50, 'max': 1000000 }}},
'TAC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 35, 'max': 800000 }}},
'TIP/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 7, 'max': 200000 }}},
'TKT/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 40, 'max': 400000 }}},
'TLC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 500, 'max': 10000000 }}},
'TNC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 10, 'max': 110000 }}},
'TUB/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 200, 'max': 8000000 }}},
'UC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 100, 'max': 3000000 }}},
'UDB/CNET': { 'precision': { 'amount': 2, 'price': 6 }, 'limits': { 'amount': { 'min': 2000, 'max': 40000000 }}},
'UIC/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 5, 'max': 150000 }}},
'VAAC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 10, 'max': 250000 }}},
'VPN/CNET': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 200, 'max': 2000000 }}},
'VSC/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 30, 'max': 650000 }}},
'WAVES/CKUSD': { 'precision': { 'amount': 2, 'price': 3 }, 'limits': { 'amount': { 'min': 0.15, 'max': 1500 }}},
'WDNA/ETH': { 'precision': { 'amount': 2, 'price': 8 }, 'limits': { 'amount': { 'min': 100, 'max': 250000 }}},
'WIC/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 3, 'max': 30000 }}},
'XAS/CNET': { 'precision': { 'amount': 2, 'price': 2 }, 'limits': { 'amount': { 'min': 2.5, 'max': 25000 }}},
'XLM/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 10, 'max': 300000 }}},
'XLM/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 1, 'max': 300000 }}},
'XLM/USDT': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 5, 'max': 150000 }}},
'XRP/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 24, 'max': 100000 }}},
'XRP/CKUSD': { 'precision': { 'amount': 2, 'price': 3 }, 'limits': { 'amount': { 'min': 5, 'max': 50000 }}},
'YBCT/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 15, 'max': 200000 }}},
'YBCT/CKUSD': { 'precision': { 'amount': 2, 'price': 4 }, 'limits': { 'amount': { 'min': 10, 'max': 200000 }}},
'YBY/CNET': { 'precision': { 'amount': 2, 'price': 6 }, 'limits': { 'amount': { 'min': 25000, 'max': 250000000 }}},
'ZEC/BTC': { 'precision': { 'amount': 4, 'price': 8 }, 'limits': { 'amount': { 'min': 0.02, 'max': 100 }}},
'ZEC/CKUSD': { 'precision': { 'amount': 4, 'price': 2 }, 'limits': { 'amount': { 'min': 0.02, 'max': 100 }}},
},
},
});
}
async fetchTradingLimits (symbols = undefined, params = {}) {
// this method should not be called directly, use loadTradingLimits () instead
// by default it will try load withdrawal fees of all currencies (with separate requests, sequentially)
// however if you define symbols = [ 'ETH/BTC', 'LTC/BTC' ] in args it will only load those
await this.loadMarkets ();
if (symbols === undefined) {
symbols = this.symbols;
}
const result = {};
for (let i = 0; i < symbols.length; i++) {
const symbol = symbols[i];
result[symbol] = await this.fetchTradingLimitsById (this.marketId (symbol), params);
}
return result;
}
async fetchTradingLimitsById (id, params = {}) {
const request = {
'symbol': id,
};
const response = await this.publicPostApiOrderTicker (this.extend (request, params));
//
// { code: 0,
// msg: "获取牌价信息成功",
// data: { high: 0.03721392,
// low: 0.03335362,
// buy: "0.03525757",
// sell: "0.03531160",
// last: 0.0352634,
// vol: "184742.4176",
// min_trade: "0.01500000",
// max_trade: "100.00000000",
// number_float: "4",
// price_float: "8" } } }
//
return this.parseTradingLimits (this.safeValue (response, 'data', {}));
}
parseTradingLimits (limits, symbol = undefined, params = {}) {
//
// { high: 0.03721392,
// low: 0.03335362,
// buy: "0.03525757",
// sell: "0.03531160",
// last: 0.0352634,
// vol: "184742.4176",
// min_trade: "0.01500000",
// max_trade: "100.00000000",
// number_float: "4",
// price_float: "8" }
//
return {
'info': limits,
'precision': {
'amount': this.safeInteger (limits, 'number_float'),
'price': this.safeInteger (limits, 'price_float'),
},
'limits': {
'amount': {
'min': this.safeFloat (limits, 'min_trade'),
'max': this.safeFloat (limits, 'max_trade'),
},
},
};
}
async fetchMarkets (params = {}) {
const response = await this.publicGetApiMarketGetPriceList (params);
const result = [];
const keys = Object.keys (response);
for (let i = 0; i < keys.length; i++) {
const currentMarketId = keys[i];
const currentMarkets = response[currentMarketId];
for (let j = 0; j < currentMarkets.length; j++) {
const market = currentMarkets[j];
const baseId = this.safeString (market, 'coin_from');
const quoteId = this.safeString (market, 'coin_to');
let base = baseId.toUpperCase ();
let quote = quoteId.toUpperCase ();
base = this.safeCurrencyCode (base);
quote = this.safeCurrencyCode (quote);
const id = baseId + '2' + quoteId;
const symbol = base + '/' + quote;
const active = true;
const defaults = this.safeValue (this.options['limits'], symbol, {});
result.push (this.extend ({
'id': id,
'symbol': symbol,
'base': base,
'quote': quote,
'baseId': baseId,
'quoteId': quoteId,
'active': active,
// overrided by defaults from this.options['limits']
'precision': {
'amount': undefined,
'price': undefined,
},
// overrided by defaults from this.options['limits']
'limits': {
'amount': { 'min': undefined, 'max': undefined },
'price': { 'min': undefined, 'max': undefined },
'cost': { 'min': undefined, 'max': undefined },
},
'info': market,
}, defaults));
}
}
return result;
}
parseTrade (trade, market = undefined) {
let symbol = undefined;
if (market !== undefined) {
symbol = market['symbol'];
}
const timestamp = this.safeTimestamp2 (trade, 'date', 'created');
const id = this.safeString (trade, 'tid');
const orderId = this.safeString (trade, 'order_id');
const amount = this.safeFloat2 (trade, 'number', 'amount');
const price = this.safeFloat (trade, 'price');
let cost = undefined;
if (price !== undefined) {
if (amount !== undefined) {
cost = amount * price;
}
}
let side = this.safeString (trade, 'side');
if (side === 'sale') {
side = 'sell';
}
return {
'info': trade,
'id': id,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'symbol': symbol,
'type': undefined,
'side': side,
'price': price,
'amount': amount,
'cost': cost,
'order': orderId,
'fee': undefined,
'takerOrMaker': undefined,
};
}
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {
'symbol': this.marketId (symbol),
};
if (limit !== undefined) {
request['limit'] = limit;
}
const market = this.market (symbol);
const response = await this.publicPostApiOrderMarketOrder (this.extend (request, params));
return this.parseTrades (response['data'], market, since, limit);
}
async fetchBalance (params = {}) {
await this.loadMarkets ();
const response = await this.privatePostApiUserUserBalance (params);
const data = this.safeValue (response, 'data');
let keys = Object.keys (data);
const result = { };
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const amount = this.safeFloat (data, key);
const parts = key.split ('_');
const currencyId = parts[0];
const lockOrOver = parts[1];
const code = this.safeCurrencyCode (currencyId);
if (!(code in result)) {
result[code] = this.account ();
}
if (lockOrOver === 'lock') {
result[code]['used'] = parseFloat (amount);
} else {
result[code]['free'] = parseFloat (amount);
}
}
keys = Object.keys (result);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const total = this.sum (result[key]['used'], result[key]['free']);
result[key]['total'] = total;
}
result['info'] = data;
return this.parseBalance (result);
}
async fetchTicker (symbol, params = {}) {
await this.loadMarkets ();
const market = this.markets[symbol];
const request = {
'part': market['quoteId'],
'coin': market['baseId'],
};
const response = await this.publicPostApiMarketGetCoinTrade (this.extend (request, params));
const timestamp = this.milliseconds ();
return {
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'high': this.safeFloat (response, 'max'),
'low': this.safeFloat (response, 'min'),
'bid': this.safeFloat (response, 'buy'),
'bidVolume': undefined,
'ask': this.safeFloat (response, 'sale'),
'askVolume': undefined,
'vwap': undefined,
'open': undefined,
'close': this.safeFloat (response, 'price'),
'last': this.safeFloat (response, 'price'),
'previousClose': undefined,
'change': undefined,
'percentage': this.safeFloat (response, 'change_24h'),
'average': undefined,
'baseVolume': this.safeFloat (response, 'volume_24h'),
'quoteVolume': undefined,
'info': response,
};
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const marketId = this.marketId (symbol);
const request = {
'symbol': marketId,
};
const response = await this.publicPostApiOrderDepth (this.extend (request, params));
const data = this.safeValue (response, 'data');
const timestamp = this.safeTimestamp (data, 'date');
return this.parseOrderBook (data, timestamp);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
const response = await this.privatePostApiOrderOrderList (this.extend (request, params));
return this.parseTrades (response['data'], market, since, limit);
}
parseOrderStatus (status) {
const statuses = {
'0': 'open',
'1': 'open', // partially filled
'2': 'closed',
'3': 'canceled',
};
return this.safeString (statuses, status, status);
}
async fetchOrder (id, symbol = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' fetchOrder requires a `symbol` argument');
}
await this.loadMarkets ();
const request = {
'symbol': this.marketId (symbol),
'trust_id': id,
};
const response = await this.privatePostApiOrderOrderInfo (this.extend (request, params));
const order = this.safeValue (response, 'data');
const timestamp = this.safeTimestamp (order, 'created');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
let side = this.safeString (order, 'flag');
if (side === 'sale') {
side = 'sell';
}
// Can't use parseOrder because the data format is different btw endpoint for fetchOrder and fetchOrders
return {
'info': order,
'id': id,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': undefined,
'side': side,
'price': this.safeFloat (order, 'price'),
'cost': undefined,
'average': this.safeFloat (order, 'avg_price'),
'amount': this.safeFloat (order, 'number'),
'filled': this.safeFloat (order, 'numberdeal'),
'remaining': this.safeFloat (order, 'numberover'),
'status': status,
'fee': undefined,
'clientOrderId': undefined,
'trades': undefined,
};
}
parseOrder (order, market = undefined) {
const id = this.safeString (order, 'id');
const timestamp = this.safeTimestamp (order, 'datetime');
let symbol = undefined;
if (market !== undefined) {
symbol = market['symbol'];
}
const type = undefined;
let side = this.safeString (order, 'type');
if (side === 'sale') {
side = 'sell';
}
const price = this.safeFloat (order, 'price');
const average = this.safeFloat (order, 'avg_price');
const amount = this.safeFloat (order, 'amount');
const remaining = this.safeFloat (order, 'amount_outstanding');
const filled = amount - remaining;
const status = this.parseOrderStatus (this.safeString (order, 'status'));
const cost = filled * price;
const fee = undefined;
const result = {
'info': order,
'id': id,
'clientOrderId': undefined,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
'side': side,
'price': price,
'cost': cost,
'average': average,
'amount': amount,
'filled': filled,
'remaining': remaining,
'status': status,
'fee': fee,
'trades': undefined,
};
return result;
}
async fetchOrdersByType (type, symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {
'type': type,
};
let market = undefined;
if (symbol !== undefined) {
market = this.market (symbol);
request['symbol'] = market['id'];
}
const response = await this.privatePostApiOrderTradeList (this.extend (request, params));
if ('data' in response) {
return this.parseOrders (response['data'], market, since, limit);
}
return [];
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
return this.fetchOrdersByType ('open', symbol, since, limit, params);
}
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
const orders = await this.fetchOrders (symbol, since, limit, params);
return this.filterBy (orders, 'status', 'closed');
}
async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
return this.fetchOrdersByType ('all', symbol, since, limit, params);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const request = {
'symbol': this.marketId (symbol),
'type': side,
'price': this.priceToPrecision (symbol, price),
'number': this.amountToPrecision (symbol, amount),
};
const response = await this.privatePostApiOrderCoinTrust (this.extend (request, params));
const data = this.safeValue (response, 'data', {});
const id = this.safeString (data, 'order_id');
return {
'info': response,
'id': id,
};
}
async cancelOrder (id, symbol = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' cancelOrder requires a `symbol` argument');
}
await this.loadMarkets ();
const request = {};
if (symbol !== undefined) {
request['symbol'] = this.marketId (symbol);
}
if (id !== undefined) {
request['order_id'] = id;
}
return await this.privatePostApiOrderCancel (this.extend (request, params));
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
let url = this.urls['api'] + '/' + this.implodeParams (path, params);
const query = this.omit (params, this.extractParams (path));
if (api === 'public') {
if (Object.keys (query).length) {
url += '?' + this.urlencode (query);
}
} else {
this.checkRequiredCredentials ();
let payload = this.urlencode ({ 'api_key': this.apiKey });
if (Object.keys (query).length) {
payload += '&' + this.urlencode (this.keysort (query));
}
const auth = payload + '&secret_key=' + this.secret;
const signature = this.hash (this.encode (auth));
body = payload + '&sign=' + signature;
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
};
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
if (response === undefined) {
return; // fallback to default error handler
}
const errorCode = this.safeValue (response, 'code');
if (errorCode !== undefined) {
if (errorCode !== 0) {
//
// { code: 1, msg: "该币不存在,非法操作" } - returned when a required symbol parameter is missing in the request (also, maybe on other types of errors as well)
// { code: 1, msg: '公钥不合法' } - wrong public key
// { code: 1, msg: '价格输入有误,请检查你的数值精度' } - 'The price input is incorrect, please check your numerical accuracy'
// { code: 1, msg: '单笔最小交易数量不能小于0.00100000,请您重新挂单'} -
// 'The minimum number of single transactions cannot be less than 0.00100000. Please re-post the order'
//
const message = this.safeString (response, 'msg');
const feedback = this.id + ' ' + message;
this.throwExactlyMatchedException (this.exceptions, message, feedback);
if (message.indexOf ('请您重新挂单') >= 0) { // minimum limit
throw new InvalidOrder (feedback);
} else {
throw new ExchangeError (feedback);
}
}
}
}
};