@proton/ccxt
Version:
A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 130+ exchanges
1,128 lines (1,126 loc) • 135 kB
JavaScript
'use strict';
var bitmart$1 = require('./abstract/bitmart.js');
var errors = require('./base/errors.js');
var Precise = require('./base/Precise.js');
var number = require('./base/functions/number.js');
var sha256 = require('./static_dependencies/noble-hashes/sha256.js');
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
class bitmart extends bitmart$1 {
describe() {
return this.deepExtend(super.describe(), {
'id': 'bitmart',
'name': 'BitMart',
'countries': ['US', 'CN', 'HK', 'KR'],
// 150 per 5 seconds = 30 per second
// rateLimit = 1000ms / 30 ~= 33.334
'rateLimit': 33.34,
'version': 'v2',
'certified': true,
'pro': true,
'has': {
'CORS': undefined,
'spot': true,
'margin': true,
'swap': undefined,
'future': false,
'option': undefined,
'borrowMargin': true,
'cancelAllOrders': true,
'cancelOrder': true,
'cancelOrders': false,
'createOrder': true,
'createPostOnlyOrder': true,
'createStopLimitOrder': false,
'createStopMarketOrder': false,
'createStopOrder': false,
'fetchBalance': true,
'fetchBorrowInterest': true,
'fetchBorrowRate': true,
'fetchBorrowRateHistories': false,
'fetchBorrowRateHistory': false,
'fetchBorrowRates': true,
'fetchCanceledOrders': true,
'fetchClosedOrders': true,
'fetchCurrencies': true,
'fetchDeposit': true,
'fetchDepositAddress': true,
'fetchDepositAddresses': false,
'fetchDepositAddressesByNetwork': false,
'fetchDeposits': true,
'fetchDepositWithdrawFee': true,
'fetchDepositWithdrawFees': false,
'fetchFundingHistory': undefined,
'fetchMarginMode': false,
'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrders': false,
'fetchOrderTrades': true,
'fetchPositionMode': false,
'fetchStatus': true,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': true,
'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': false,
'fetchTransactionFee': true,
'fetchTransactionFees': false,
'fetchTransfer': false,
'fetchTransfers': false,
'fetchWithdrawAddressesByNetwork': false,
'fetchWithdrawal': true,
'fetchWithdrawals': true,
'reduceMargin': false,
'repayMargin': true,
'setLeverage': false,
'setMarginMode': false,
'transfer': true,
'withdraw': true,
},
'hostname': 'bitmart.com',
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/129991357-8f47464b-d0f4-41d6-8a82-34122f0d1398.jpg',
'api': {
'rest': 'https://api-cloud.{hostname}', // bitmart.info for Hong Kong users
},
'www': 'https://www.bitmart.com/',
'doc': 'https://developer-pro.bitmart.com/',
'referral': {
'url': 'http://www.bitmart.com/?r=rQCFLh',
'discount': 0.3,
},
'fees': 'https://www.bitmart.com/fee/en',
},
'requiredCredentials': {
'apiKey': true,
'secret': true,
'uid': true,
},
'api': {
'public': {
'get': {
'system/time': 3,
'system/service': 3,
// spot markets
'spot/v1/currencies': 7.5,
'spot/v1/symbols': 7.5,
'spot/v1/symbols/details': 5,
'spot/v1/ticker': 5,
'spot/v2/ticker': 5,
'spot/v1/steps': 30,
'spot/v1/symbols/kline': 5,
'spot/v1/symbols/book': 5,
'spot/v1/symbols/trades': 5,
// contract markets
'contract/v1/tickers': 15,
'contract/public/details': 5,
'contract/public/depth': 5,
'contract/public/open-interest': 30,
'contract/public/funding-rate': 30,
'contract/public/kline': 5,
'account/v1/currencies': 30,
},
},
'private': {
'get': {
// sub-account
'account/sub-account/v1/transfer-list': 7.5,
'account/sub-account/v1/transfer-history': 7.5,
'account/sub-account/main/v1/wallet': 5,
'account/sub-account/main/v1/subaccount-list': 7.5,
// account
'account/v1/wallet': 5,
'account/v1/currencies': 30,
'spot/v1/wallet': 5,
'account/v1/deposit/address': 30,
'account/v1/withdraw/charge': 32,
'account/v2/deposit-withdraw/history': 7.5,
'account/v1/deposit-withdraw/detail': 7.5,
// order
'spot/v1/order_detail': 1,
'spot/v2/orders': 5,
'spot/v1/trades': 5,
// newer order endpoint
'spot/v2/trades': 5,
'spot/v3/orders': 5,
'spot/v2/order_detail': 1,
// margin
'spot/v1/margin/isolated/borrow_record': 1,
'spot/v1/margin/isolated/repay_record': 1,
'spot/v1/margin/isolated/pairs': 1,
'spot/v1/margin/isolated/account': 6,
'spot/v1/trade_fee': 6,
'spot/v1/user_fee': 6,
// contract
'contract/private/assets-detail': 5,
'contract/private/order': 2,
'contract/private/order-history': 10,
'contract/private/position': 10,
},
'post': {
// sub-account endpoints
'account/sub-account/main/v1/sub-to-main': 30,
'account/sub-account/sub/v1/sub-to-main': 30,
'account/sub-account/main/v1/main-to-sub': 30,
'account/sub-account/sub/v1/sub-to-sub': 30,
'account/sub-account/main/v1/sub-to-sub': 30,
// account
'account/v1/withdraw/apply': 7.5,
// transaction and trading
'spot/v1/submit_order': 1,
'spot/v1/batch_orders': 1,
'spot/v2/cancel_order': 1,
'spot/v1/cancel_orders': 15,
// newer endpoint
'spot/v3/cancel_order': 1,
'spot/v2/batch_orders': 1,
'spot/v2/submit_order': 1,
// margin
'spot/v1/margin/submit_order': 1,
'spot/v1/margin/isolated/borrow': 6,
'spot/v1/margin/isolated/repay': 6,
'spot/v1/margin/isolated/transfer': 6,
// contract
'contract/private/trades': 10,
},
},
},
'timeframes': {
'1m': 1,
'3m': 3,
'5m': 5,
'15m': 15,
'30m': 30,
'45m': 45,
'1h': 60,
'2h': 120,
'3h': 180,
'4h': 240,
'1d': 1440,
'1w': 10080,
'1M': 43200,
},
'fees': {
'trading': {
'tierBased': true,
'percentage': true,
'taker': this.parseNumber('0.0025'),
'maker': this.parseNumber('0.0025'),
'tiers': {
'taker': [
[this.parseNumber('0'), this.parseNumber('0.0020')],
[this.parseNumber('10'), this.parseNumber('0.18')],
[this.parseNumber('50'), this.parseNumber('0.0016')],
[this.parseNumber('250'), this.parseNumber('0.0014')],
[this.parseNumber('1000'), this.parseNumber('0.0012')],
[this.parseNumber('5000'), this.parseNumber('0.0010')],
[this.parseNumber('25000'), this.parseNumber('0.0008')],
[this.parseNumber('50000'), this.parseNumber('0.0006')],
],
'maker': [
[this.parseNumber('0'), this.parseNumber('0.001')],
[this.parseNumber('10'), this.parseNumber('0.0009')],
[this.parseNumber('50'), this.parseNumber('0.0008')],
[this.parseNumber('250'), this.parseNumber('0.0007')],
[this.parseNumber('1000'), this.parseNumber('0.0006')],
[this.parseNumber('5000'), this.parseNumber('0.0005')],
[this.parseNumber('25000'), this.parseNumber('0.0004')],
[this.parseNumber('50000'), this.parseNumber('0.0003')],
],
},
},
},
'precisionMode': number.TICK_SIZE,
'exceptions': {
'exact': {
// general errors
'30000': errors.ExchangeError,
'30001': errors.AuthenticationError,
'30002': errors.AuthenticationError,
'30003': errors.AccountSuspended,
'30004': errors.AuthenticationError,
'30005': errors.AuthenticationError,
'30006': errors.AuthenticationError,
'30007': errors.AuthenticationError,
'30008': errors.AuthenticationError,
'30010': errors.PermissionDenied,
'30011': errors.AuthenticationError,
'30012': errors.AuthenticationError,
'30013': errors.RateLimitExceeded,
'30014': errors.ExchangeNotAvailable,
// funding account errors
'60000': errors.BadRequest,
'60001': errors.BadRequest,
'60002': errors.BadRequest,
'60003': errors.ExchangeError,
'60004': errors.ExchangeError,
'60005': errors.ExchangeError,
'60006': errors.ExchangeError,
'60007': errors.InvalidAddress,
'60008': errors.InsufficientFunds,
'60009': errors.ExchangeError,
'60010': errors.ExchangeError,
'60011': errors.InvalidAddress,
'60012': errors.ExchangeError,
'60020': errors.PermissionDenied,
'60021': errors.PermissionDenied,
'60022': errors.PermissionDenied,
'60030': errors.BadRequest,
'60031': errors.BadRequest,
'60050': errors.ExchangeError,
'60051': errors.ExchangeError,
'61001': errors.InsufficientFunds,
'61003': errors.BadRequest,
// spot errors
'50000': errors.BadRequest,
'50001': errors.BadSymbol,
'50002': errors.BadRequest,
'50003': errors.BadRequest,
'50004': errors.BadRequest,
'50005': errors.OrderNotFound,
'50006': errors.InvalidOrder,
'50007': errors.InvalidOrder,
'50008': errors.InvalidOrder,
'50009': errors.InvalidOrder,
'50010': errors.InvalidOrder,
'50011': errors.InvalidOrder,
'50012': errors.InvalidOrder,
'50013': errors.InvalidOrder,
'50014': errors.BadRequest,
'50015': errors.BadRequest,
'50016': errors.BadRequest,
'50017': errors.BadRequest,
'50018': errors.BadRequest,
'50019': errors.BadRequest,
'51004': errors.InsufficientFunds,
// '50019': ExchangeError, // 400, Invalid status. validate status is [1=Failed, 2=Success, 3=Frozen Failed, 4=Frozen Success, 5=Partially Filled, 6=Fully Fulled, 7=Canceling, 8=Canceled
'50020': errors.InsufficientFunds,
'50021': errors.BadRequest,
'50022': errors.ExchangeNotAvailable,
'50023': errors.BadSymbol,
'50029': errors.InvalidOrder,
'50030': errors.InvalidOrder,
'50032': errors.OrderNotFound,
// below Error codes used interchangeably for both failed postOnly and IOC orders depending on market price and order side
'50035': errors.InvalidOrder,
'50034': errors.InvalidOrder,
'51011': errors.InvalidOrder,
'53000': errors.AccountSuspended,
'53001': errors.AccountSuspended,
'57001': errors.BadRequest,
'58001': errors.BadRequest,
'59001': errors.ExchangeError,
'59002': errors.ExchangeError,
// contract errors
'40001': errors.ExchangeError,
'40002': errors.ExchangeError,
'40003': errors.ExchangeError,
'40004': errors.ExchangeError,
'40005': errors.ExchangeError,
'40006': errors.PermissionDenied,
'40007': errors.BadRequest,
'40008': errors.InvalidNonce,
'40009': errors.BadRequest,
'40010': errors.BadRequest,
'40011': errors.BadRequest,
'40012': errors.ExchangeError,
'40013': errors.ExchangeError,
'40014': errors.BadSymbol,
'40015': errors.BadSymbol,
'40016': errors.InvalidOrder,
'40017': errors.InvalidOrder,
'40018': errors.InvalidOrder,
'40019': errors.ExchangeError,
'40020': errors.InvalidOrder,
'40021': errors.ExchangeError,
'40022': errors.ExchangeError,
'40023': errors.ExchangeError,
'40024': errors.ExchangeError,
'40025': errors.ExchangeError,
'40026': errors.ExchangeError,
'40027': errors.InsufficientFunds,
'40028': errors.PermissionDenied,
'40029': errors.InvalidOrder,
'40030': errors.InvalidOrder,
'40031': errors.InvalidOrder,
'40032': errors.InvalidOrder,
'40033': errors.InvalidOrder,
'40034': errors.BadSymbol,
'53002': errors.PermissionDenied, // 403, Your account has not yet completed the kyc advanced certification, please complete first
},
'broad': {},
},
'commonCurrencies': {
'$GM': 'GOLDMINER',
'$HERO': 'Step Hero',
'$PAC': 'PAC',
'BP': 'BEYOND',
'GDT': 'Gorilla Diamond',
'GLD': 'Goldario',
'MVP': 'MVP Coin',
'TRU': 'Truebit', // conflict with TrueFi
},
'options': {
'networks': {
'TRX': 'TRC20',
'ETH': 'ERC20',
},
'defaultNetworks': {
'USDT': 'ERC20',
},
'defaultType': 'spot',
'fetchBalance': {
'type': 'spot', // 'spot', 'swap', 'account'
},
'accountsByType': {
'spot': 'spot',
},
'createMarketBuyOrderRequiresPrice': true,
},
});
}
async fetchTime(params = {}) {
/**
* @method
* @name bitmart#fetchTime
* @description fetches the current integer timestamp in milliseconds from the exchange server
* @param {object} params extra parameters specific to the bitmart api endpoint
* @returns {int} the current integer timestamp in milliseconds from the exchange server
*/
const response = await this.publicGetSystemTime(params);
//
// {
// "message":"OK",
// "code":1000,
// "trace":"c4e5e5b7-fe9f-4191-89f7-53f6c5bf9030",
// "data":{
// "server_time":1599843709578
// }
// }
//
const data = this.safeValue(response, 'data', {});
return this.safeInteger(data, 'server_time');
}
async fetchStatus(params = {}) {
/**
* @method
* @name bitmart#fetchStatus
* @description the latest known information on the availability of the exchange API
* @param {object} params extra parameters specific to the bitmart api endpoint
* @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
*/
const options = this.safeValue(this.options, 'fetchStatus', {});
const defaultType = this.safeString(this.options, 'defaultType');
let type = this.safeString(options, 'type', defaultType);
type = this.safeString(params, 'type', type);
params = this.omit(params, 'type');
const response = await this.publicGetSystemService(params);
//
// {
// "message": "OK",
// "code": 1000,
// "trace": "1d3f28b0-763e-4f78-90c4-5e3ad19dc595",
// "data": {
// "service": [
// {
// "title": "Spot API Stop",
// "service_type": "spot",
// "status": 2,
// "start_time": 1648639069125,
// "end_time": 1648639069125
// },
// {
// "title": "Contract API Stop",
// "service_type": "contract",
// "status": 2,
// "start_time": 1648639069125,
// "end_time": 1648639069125
// }
// ]
// }
// }
//
const data = this.safeValue(response, 'data', {});
const services = this.safeValue(data, 'service', []);
const servicesByType = this.indexBy(services, 'service_type');
if (type === 'swap') {
type = 'contract';
}
const service = this.safeValue(servicesByType, type);
let status = undefined;
let eta = undefined;
if (service !== undefined) {
const statusCode = this.safeInteger(service, 'status');
if (statusCode === 2) {
status = 'ok';
}
else {
status = 'maintenance';
eta = this.safeInteger(service, 'end_time');
}
}
return {
'status': status,
'updated': undefined,
'eta': eta,
'url': undefined,
'info': response,
};
}
async fetchSpotMarkets(params = {}) {
const response = await this.publicGetSpotV1SymbolsDetails(params);
//
// {
// "message":"OK",
// "code":1000,
// "trace":"a67c9146-086d-4d3f-9897-5636a9bb26e1",
// "data":{
// "symbols":[
// {
// "symbol": "BTC_USDT",
// "symbol_id": 53,
// "base_currency": "BTC",
// "quote_currency": "USDT",
// "base_min_size": "0.000010000000000000000000000000",
// "base_max_size": "100000000.000000000000000000000000000000",
// "price_min_precision": -1,
// "price_max_precision": 2,
// "quote_increment": "0.00001", // Api docs says "The minimum order quantity is also the minimum order quantity increment", however I think they mistakenly use the term 'order quantity'
// "expiration": "NA",
// "min_buy_amount": "5.000000000000000000000000000000",
// "min_sell_amount": "5.000000000000000000000000000000",
// "trade_status": "trading"
// },
// ]
// }
// }
//
const data = this.safeValue(response, 'data', {});
const symbols = this.safeValue(data, 'symbols', []);
const result = [];
for (let i = 0; i < symbols.length; i++) {
const market = symbols[i];
const id = this.safeString(market, 'symbol');
const numericId = this.safeInteger(market, 'symbol_id');
const baseId = this.safeString(market, 'base_currency');
const quoteId = this.safeString(market, 'quote_currency');
const base = this.safeCurrencyCode(baseId);
const quote = this.safeCurrencyCode(quoteId);
const symbol = base + '/' + quote;
const minBuyCost = this.safeString(market, 'min_buy_amount');
const minSellCost = this.safeString(market, 'min_sell_amount');
const minCost = Precise["default"].stringMax(minBuyCost, minSellCost);
const baseMinSize = this.safeNumber(market, 'base_min_size');
result.push({
'id': id,
'numericId': numericId,
'symbol': symbol,
'base': base,
'quote': quote,
'settle': undefined,
'baseId': baseId,
'quoteId': quoteId,
'settleId': undefined,
'type': 'spot',
'spot': true,
'margin': false,
'swap': false,
'future': false,
'option': false,
'active': true,
'contract': false,
'linear': undefined,
'inverse': undefined,
'contractSize': undefined,
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': baseMinSize,
'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'price_max_precision'))),
},
'limits': {
'leverage': {
'min': undefined,
'max': undefined,
},
'amount': {
'min': baseMinSize,
'max': this.safeNumber(market, 'base_max_size'),
},
'price': {
'min': undefined,
'max': undefined,
},
'cost': {
'min': this.parseNumber(minCost),
'max': undefined,
},
},
'info': market,
});
}
return result;
}
async fetchContractMarkets(params = {}) {
const response = await this.publicGetContractPublicDetails(params);
//
// {
// "code": 1000,
// "message": "Ok",
// "trace": "9b92a999-9463-4c96-91a4-93ad1cad0d72",
// "data": {
// "symbols": [{
// "symbol": "BTCUSDT",
// "product_type": 1,
// "open_timestamp": 1594080000,
// "expire_timestamp": 0,
// "settle_timestamp": 0,
// "base_currency": "BTC",
// "quote_currency": "USDT",
// "last_price": "23920",
// "volume_24h": "18969368",
// "turnover_24h": "458933659.7858",
// "index_price": "23945.25191635",
// "index_name": "BTCUSDT",
// "contract_size": "0.001",
// "min_leverage": "1",
// "max_leverage": "100",
// "price_precision": "0.1",
// "vol_precision": "1",
// "max_volume": "500000",
// "min_volume": "1"
// },
// ...
// ]
// }
// }
//
const data = this.safeValue(response, 'data', {});
const symbols = this.safeValue(data, 'symbols', []);
const result = [];
for (let i = 0; i < symbols.length; i++) {
const market = symbols[i];
const id = this.safeString(market, 'symbol');
const baseId = this.safeString(market, 'base_currency');
const quoteId = this.safeString(market, 'quote_currency');
const base = this.safeCurrencyCode(baseId);
const quote = this.safeCurrencyCode(quoteId);
const settleId = 'USDT'; // this is bitmart's ID for usdt
const settle = this.safeCurrencyCode(settleId);
const symbol = base + '/' + quote + ':' + settle;
const productType = this.safeInteger(market, 'product_type');
const isSwap = (productType === 1);
const isFutures = (productType === 2);
let expiry = this.safeInteger(market, 'expire_timestamp');
if (!isFutures && (expiry === 0)) {
expiry = undefined;
}
result.push({
'id': id,
'numericId': undefined,
'symbol': symbol,
'base': base,
'quote': quote,
'settle': settle,
'baseId': baseId,
'quoteId': quoteId,
'settleId': settleId,
'type': isSwap ? 'swap' : 'future',
'spot': false,
'margin': false,
'swap': isSwap,
'future': isFutures,
'option': false,
'active': true,
'contract': true,
'linear': true,
'inverse': false,
'contractSize': this.safeNumber(market, 'contract_size'),
'expiry': expiry,
'expiryDatetime': this.iso8601(expiry),
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': this.safeNumber(market, 'vol_precision'),
'price': this.safeNumber(market, 'price_precision'),
},
'limits': {
'leverage': {
'min': this.safeNumber(market, 'min_leverage'),
'max': this.safeNumber(market, 'max_leverage'),
},
'amount': {
'min': this.safeNumber(market, 'min_volume'),
'max': this.safeNumber(market, 'max_volume'),
},
'price': {
'min': undefined,
'max': undefined,
},
'cost': {
'min': undefined,
'max': undefined,
},
},
'info': market,
});
}
return result;
}
async fetchMarkets(params = {}) {
/**
* @method
* @name bitmart#fetchMarkets
* @description retrieves data on all markets for bitmart
* @param {object} params extra parameters specific to the exchange api endpoint
* @returns {[object]} an array of objects representing market data
*/
const spot = await this.fetchSpotMarkets(params);
const contract = await this.fetchContractMarkets(params);
return this.arrayConcat(spot, contract);
}
async fetchCurrencies(params = {}) {
/**
* @method
* @name bitmart#fetchCurrencies
* @description fetches all available currencies on an exchange
* @param {object} params extra parameters specific to the bitmart api endpoint
* @returns {object} an associative dictionary of currencies
*/
const response = await this.publicGetSpotV1Currencies(params);
//
// {
// "message":"OK",
// "code":1000,
// "trace":"8c768b3c-025f-413f-bec5-6d6411d46883",
// "data":{
// "currencies":[
// {"currency":"MATIC","name":"Matic Network","withdraw_enabled":true,"deposit_enabled":true},
// {"currency":"KTN","name":"Kasoutuuka News","withdraw_enabled":true,"deposit_enabled":false},
// {"currency":"BRT","name":"Berith","withdraw_enabled":true,"deposit_enabled":true},
// ]
// }
// }
//
const data = this.safeValue(response, 'data', {});
const currencies = this.safeValue(data, 'currencies', []);
const result = {};
for (let i = 0; i < currencies.length; i++) {
const currency = currencies[i];
const id = this.safeString(currency, 'id');
const code = this.safeCurrencyCode(id);
const name = this.safeString(currency, 'name');
const withdrawEnabled = this.safeValue(currency, 'withdraw_enabled');
const depositEnabled = this.safeValue(currency, 'deposit_enabled');
const active = withdrawEnabled && depositEnabled;
result[code] = {
'id': id,
'code': code,
'name': name,
'info': currency,
'active': active,
'deposit': depositEnabled,
'withdraw': withdrawEnabled,
'fee': undefined,
'precision': undefined,
'limits': {
'amount': { 'min': undefined, 'max': undefined },
'withdraw': { 'min': undefined, 'max': undefined },
},
};
}
return result;
}
async fetchTransactionFee(code, params = {}) {
/**
* @method
* @name bitmart#fetchTransactionFee
* @description *DEPRECATED* please use fetchDepositWithdrawFee instead
* @param {string} code unified currency code
* @param {object} params extra parameters specific to the bitmart api endpoint
* @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure}
*/
await this.loadMarkets();
const currency = this.currency(code);
const request = {
'currency': currency['id'],
};
const response = await this.privateGetAccountV1WithdrawCharge(this.extend(request, params));
//
// {
// message: 'OK',
// code: '1000',
// trace: '3ecc0adf-91bd-4de7-aca1-886c1122f54f',
// data: {
// today_available_withdraw_BTC: '100.0000',
// min_withdraw: '0.005',
// withdraw_precision: '8',
// withdraw_fee: '0.000500000000000000000000000000'
// }
// }
//
const data = response['data'];
const withdrawFees = {};
withdrawFees[code] = this.safeNumber(data, 'withdraw_fee');
return {
'info': response,
'withdraw': withdrawFees,
'deposit': {},
};
}
parseDepositWithdrawFee(fee, currency = undefined) {
//
// {
// today_available_withdraw_BTC: '100.0000',
// min_withdraw: '0.005',
// withdraw_precision: '8',
// withdraw_fee: '0.000500000000000000000000000000'
// }
//
return {
'info': fee,
'withdraw': {
'fee': this.safeNumber(fee, 'withdraw_fee'),
'percentage': undefined,
},
'deposit': {
'fee': undefined,
'percentage': undefined,
},
'networks': {},
};
}
async fetchDepositWithdrawFee(code, params = {}) {
/**
* @method
* @name bitmart#fetchDepositWithdrawFee
* @description fetch the fee for deposits and withdrawals
* @param {string} code unified currency code
* @param {object} params extra parameters specific to the bitmart api endpoint
* @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure}
*/
await this.loadMarkets();
const currency = this.currency(code);
const request = {
'currency': currency['id'],
};
const response = await this.privateGetAccountV1WithdrawCharge(this.extend(request, params));
//
// {
// message: 'OK',
// code: '1000',
// trace: '3ecc0adf-91bd-4de7-aca1-886c1122f54f',
// data: {
// today_available_withdraw_BTC: '100.0000',
// min_withdraw: '0.005',
// withdraw_precision: '8',
// withdraw_fee: '0.000500000000000000000000000000'
// }
// }
//
const data = response['data'];
return this.parseDepositWithdrawFee(data);
}
parseTicker(ticker, market = undefined) {
//
// spot
//
// {
// "symbol": "SOLAR_USDT",
// "last_price": "0.020342",
// "quote_volume_24h": "56817.811802",
// "base_volume_24h": "2172060",
// "high_24h": "0.256000",
// "low_24h": "0.016980",
// "open_24h": "0.022309",
// "close_24h": "0.020342",
// "best_ask": "0.020389",
// "best_ask_size": "339.000000000000000000000000000000",
// "best_bid": "0.020342",
// "best_bid_size": "3369.000000000000000000000000000000",
// "fluctuation": "-0.0882",
// "url": "https://www.bitmart.com/trade?symbol=SOLAR_USDT",
// "timestamp": 1667403439367
// }
//
// swap
//
// {
// "contract_symbol":"DOGEUSDT",
// "last_price":"0.130340",
// "index_price":"0.13048245",
// "last_funding_rate":"0.00002287",
// "price_change_percent_24h":"-2.074",
// "volume_24h":"113705028.59482228",
// "url":"https://futures.bitmart.com/en?symbol=DOGEUSDT",
// "high_price":"0.134520",
// "low_price":"0.128570",
// "legal_coin_price":"0.1302699"
// }
//
const timestamp = this.safeInteger(ticker, 'timestamp', this.milliseconds());
const marketId = this.safeString2(ticker, 'symbol', 'contract_symbol');
market = this.safeMarket(marketId, market);
const symbol = market['symbol'];
const last = this.safeString2(ticker, 'close_24h', 'last_price');
let percentage = this.safeString(ticker, 'price_change_percent_24h');
if (percentage === undefined) {
const percentageRaw = this.safeString(ticker, 'fluctuation');
if ((percentageRaw !== undefined) && (percentageRaw !== '0')) { // a few tickers show strictly '0' in fluctuation field
const direction = percentageRaw[0];
percentage = direction + Precise["default"].stringMul(percentageRaw.replace(direction, ''), '100');
}
else if (percentageRaw === '0') {
percentage = '0';
}
}
const baseVolume = this.safeString(ticker, 'base_volume_24h');
let quoteVolume = this.safeString(ticker, 'quote_volume_24h');
quoteVolume = this.safeString(ticker, 'volume_24h', quoteVolume);
const average = this.safeString2(ticker, 'avg_price', 'index_price');
const high = this.safeString2(ticker, 'high_24h', 'high_price');
const low = this.safeString2(ticker, 'low_24h', 'low_price');
return this.safeTicker({
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'high': high,
'low': low,
'bid': this.safeString(ticker, 'best_bid'),
'bidVolume': this.safeString(ticker, 'best_bid_size'),
'ask': this.safeString(ticker, 'best_ask'),
'askVolume': this.safeString(ticker, 'best_ask_size'),
'vwap': undefined,
'open': this.safeString(ticker, 'open_24h'),
'close': last,
'last': last,
'previousClose': undefined,
'change': undefined,
'percentage': percentage,
'average': average,
'baseVolume': baseVolume,
'quoteVolume': quoteVolume,
'info': ticker,
}, market);
}
async fetchTicker(symbol, params = {}) {
/**
* @method
* @name bitmart#fetchTicker
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @param {string} symbol unified symbol of the market to fetch the ticker for
* @param {object} params extra parameters specific to the bitmart api endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
*/
await this.loadMarkets();
const market = this.market(symbol);
const request = {};
let method = undefined;
if (market['swap']) {
method = 'publicGetContractV1Tickers';
request['contract_symbol'] = market['id'];
}
else if (market['spot']) {
method = 'publicGetSpotV1Ticker';
request['symbol'] = market['id'];
}
const response = await this[method](this.extend(request, params));
//
// spot
//
// {
// "message":"OK",
// "code":1000,
// "trace":"6aa5b923-2f57-46e3-876d-feca190e0b82",
// "data":{
// "tickers":[
// {
// "symbol":"ETH_BTC",
// "last_price":"0.036037",
// "quote_volume_24h":"4380.6660000000",
// "base_volume_24h":"159.3582006712",
// "high_24h":"0.036972",
// "low_24h":"0.035524",
// "open_24h":"0.036561",
// "close_24h":"0.036037",
// "best_ask":"0.036077",
// "best_ask_size":"9.9500",
// "best_bid":"0.035983",
// "best_bid_size":"4.2792",
// "fluctuation":"-0.0143",
// "url":"https://www.bitmart.com/trade?symbol=ETH_BTC"
// }
// ]
// }
// }
//
// swap
//
// {
// "message":"OK",
// "code":1000,
// "trace":"4a0ebceb-d3f7-45a3-8feb-f61e230e24cd",
// "data":{
// "tickers":[
// {
// "contract_symbol":"DOGEUSDT",
// "last_price":"0.130180",
// "index_price":"0.13028635",
// "last_funding_rate":"0.00002025",
// "price_change_percent_24h":"-2.326",
// "volume_24h":"116789313.01797258",
// "url":"https://futures.bitmart.com/en?symbol=DOGEUSDT",
// "high_price":"0.134520",
// "low_price":"0.128570",
// "legal_coin_price":"0.13017401"
// }
// ]
// }
// }
//
const data = this.safeValue(response, 'data', {});
const tickers = this.safeValue(data, 'tickers', []);
// fails in naming for contract tickers 'contract_symbol'
let tickersById = undefined;
if (market['spot']) {
tickersById = this.indexBy(tickers, 'symbol');
}
else if (market['swap']) {
tickersById = this.indexBy(tickers, 'contract_symbol');
}
const ticker = this.safeValue(tickersById, market['id']);
return this.parseTicker(ticker, market);
}
async fetchTickers(symbols = undefined, params = {}) {
/**
* @method
* @name bitmart#fetchTickers
* @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
* @see https://developer-pro.bitmart.com/en/spot/#get-ticker-of-all-pairs-v2
* @param {[string]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
* @param {object} params extra parameters specific to the bitmart api endpoint
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
*/
await this.loadMarkets();
symbols = this.marketSymbols(symbols);
let type = undefined;
let market = undefined;
if (symbols !== undefined) {
const symbol = this.safeValue(symbols, 0);
market = this.market(symbol);
}
[type, params] = this.handleMarketTypeAndParams('fetchTickers', market, params);
const method = this.getSupportedMapping(type, {
'spot': 'publicGetSpotV2Ticker',
'swap': 'publicGetContractV1Tickers',
});
const response = await this[method](params);
const data = this.safeValue(response, 'data', {});
const tickers = this.safeValue(data, 'tickers', []);
const result = {};
for (let i = 0; i < tickers.length; i++) {
const ticker = this.parseTicker(tickers[i]);
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
return this.filterByArray(result, 'symbol', symbols);
}
async fetchOrderBook(symbol, limit = undefined, params = {}) {
/**
* @method
* @name bitmart#fetchOrderBook
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @param {string} symbol unified symbol of the market to fetch the order book for
* @param {int|undefined} limit the maximum amount of order book entries to return
* @param {object} params extra parameters specific to the bitmart api endpoint
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
*/
await this.loadMarkets();
const market = this.market(symbol);
if (!market['spot']) {
throw new errors.NotSupported(this.id + ' fetchOrderBook() does not support ' + market['type'] + ' markets, only spot markets are accepted');
}
const request = {
'symbol': market['id'],
};
if (limit !== undefined) {
request['size'] = limit; // default 50, max 200
}
// request['precision'] = 4; // optional price precision / depth level whose range is defined in symbol details
const response = await this.publicGetSpotV1SymbolsBook(this.extend(request, params));
//
// spot
//
// {
// "message":"OK",
// "code":1000,
// "trace":"8254f8fc-431d-404f-ad9a-e716339f66c7",
// "data":{
// "buys":[
// {"amount":"4.7091","total":"4.71","price":"0.034047","count":"1"},
// {"amount":"5.7439","total":"10.45","price":"0.034039","count":"1"},
// {"amount":"2.5249","total":"12.98","price":"0.032937","count":"1"},
// ],
// "sells":[
// {"amount":"41.4365","total":"41.44","price":"0.034174","count":"1"},
// {"amount":"4.2317","total":"45.67","price":"0.034183","count":"1"},
// {"amount":"0.3000","total":"45.97","price":"0.034240","count":"1"},
// ]
// }
// }
//
const data = this.safeValue(response, 'data', {});
const timestamp = this.safeInteger(data, 'timestamp');
return this.parseOrderBook(data, symbol, timestamp, 'buys', 'sells', 'price', 'amount');
}
parseTrade(trade, market = undefined) {
//
// public fetchTrades spot ( amount = count * price )
//
// {
// "amount": "818.94",
// "order_time": "1637601839035", // ETH/USDT
// "price": "4221.99",
// "count": "0.19397",
// "type": "buy"
// }
//
// private fetchMyTrades spot
//
// {
// "detail_id":256348632,
// "order_id":2147484350,
// "symbol":"BTC_USDT",
// "create_time":1590462303000,
// "side":"buy",
// "fees":"0.00001350",
// "fee_coin_name":"BTC",
// "notional":"88.00000000",
// "price_avg":"8800.00",
// "size":"0.01000",
// "exec_type":"M"
// }
//
const id = this.safeString(trade, 'detail_id');
const timestamp = this.safeInteger2(trade, 'order_time', 'create_time');
const type = undefined;
const side = this.safeStringLower2(trade, 'type', 'side');
let takerOrMaker = undefined;
const execType = this.safeString(trade, 'exec_type');
if (execType !== undefined) {
takerOrMaker = (execType === 'M') ? 'maker' : 'taker';
}
let priceString = this.safeString(trade, 'price');
priceString = this.safeString(trade, 'price_avg', priceString);
let amountString = this.safeString(trade, 'count');
amountString = this.safeString(trade, 'size', amountString);
const costString = this.safeString2(trade, 'amount', 'notional');
const orderId = this.safeString(trade, 'order_id');
const marketId = this.safeString(trade, 'sy