UNPKG

sfccxt

Version:

A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges

1,119 lines (1,100 loc) 84.5 kB
'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { TICK_SIZE } = require ('./base/functions/number'); const { ExchangeError, NotSupported, RequestTimeout, DDoSProtection, InvalidOrder, InvalidAddress, BadRequest, InsufficientFunds, OrderNotFound, AuthenticationError, ExchangeNotAvailable, ArgumentsRequired } = require ('./base/errors'); const Precise = require ('./base/Precise'); // --------------------------------------------------------------------------- module.exports = class btcex extends Exchange { describe () { return this.deepExtend (super.describe (), { 'id': 'btcex', 'name': 'BTCEX', 'countries': [ 'CA' ], // Canada 'version': 'v1', 'certified': false, 'pro': false, 'requiredCredentials': { 'apiKey': true, 'secret': true, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/173489620-d49807a4-55cd-4f4e-aca9-534921298bbf.jpg', 'www': 'https://www.btcex.com/', 'api': { 'rest': 'https://api.btcex.com', }, 'doc': 'https://docs.btcex.com/', 'fees': 'https://support.btcex.com/hc/en-us/articles/4415995130647', 'referral': { 'url': 'https://www.btcex.com/en-us/register?i=48biatg1', 'discount': 0.1, }, }, 'has': { 'CORS': undefined, 'spot': true, 'margin': true, 'swap': true, 'future': true, 'option': true, 'cancelAllOrders': true, 'cancelOrder': true, 'createOrder': true, 'editOrder': false, 'fetchBalance': true, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchClosedOrders': true, 'fetchCurrencies': false, 'fetchDepositAddress': false, 'fetchDeposits': true, 'fetchFundingHistory': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchPosition': true, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchPremiumIndexOHLCV': false, 'fetchTicker': true, 'fetchTickers': false, 'fetchTime': false, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': false, 'fetchTransactionFees': undefined, 'fetchWithdrawal': true, 'fetchWithdrawals': true, 'signIn': true, 'withdraw': false, }, 'timeframes': { '1m': '1', '3m': '3', '5m': '5', '15m': '15', '30m': '30', '1h': '60', '2h': '120', '3h': '180', '4h': '240', '6h': '360', '12h': '720', '1d': '1D', '3d': '3D', '1M': '30D', }, 'api': { 'public': { 'get': [ // Market data 'get_last_trades_by_currency', 'get_last_trades_by_instrument', 'get_order_book', 'tickers', 'get_instruments', 'get_tradingview_chart_data', // CMC 'cmc_spot_summary', 'cmc_spot_ticker', 'cmc_spot_orderbook', 'cmc_market_trades', 'cmc_contracts', 'cmc_contract_orderbook', // CoinGecko 'coin_gecko_spot_pairs', 'coin_gecko_spot_ticker', 'coin_gecko_spot_orderbook', 'coin_gecko_market_trades', 'coin_gecko_contracts', 'coin_gecko_contract_orderbook', ], 'post': [ 'auth', ], }, 'private': { 'get': [ // wallet 'get_deposit_record', 'get_withdraw_record', // trade 'get_position', 'get_positions', 'get_open_orders_by_currency', 'get_open_orders_by_instrument', 'get_order_history_by_currency', 'get_order_history_by_instrument', 'get_order_state', 'get_user_trades_by_currency', 'get_user_trades_by_instrument', 'get_user_trades_by_order', ], 'post': [ // auth 'logout', // wallet 'get_assets_info', 'add_withdraw_address', // trade 'buy', 'sell', 'cancel', 'cancel_all_by_currency', 'cancel_all_by_instrument', 'close_position', ], 'delete': [], }, }, 'fees': { 'trading': { 'tierBased': false, 'percentage': true, 'maker': this.parseNumber ('0.001'), 'taker': this.parseNumber ('0.001'), }, 'margin': { 'tierBased': false, 'percentage': true, 'maker': this.parseNumber ('0.001'), 'taker': this.parseNumber ('0.001'), }, 'perpetual': { 'tierBased': false, 'percentage': true, 'maker': this.parseNumber ('0.002'), 'taker': this.parseNumber ('0.002'), }, }, 'exceptions': { 'exact': { '9999': ExchangeError, // SYSTEM_INNER_ERROR System error, please try again later '9900': ExchangeNotAvailable, // SERVICE_BUSY Service is busy,please try again later '401': AuthenticationError, // UNAUTHENTICATION_ERROR UnAuthentication '403': AuthenticationError, // ACCESS_DENIED_ERROR Access denied '1000': ExchangeNotAvailable, // NO_SERVICE No service found '1001': BadRequest, // BAD_REQUEST Bad requested '2000': AuthenticationError, // NEED_LOGIN Login is required '2001': AuthenticationError, // ACCOUNT_NOT_MATCH Account information does not match '2002': AuthenticationError, // ACCOUNT_NEED_ENABLE Account needs to be activated '2003': AuthenticationError, // ACCOUNT_NOT_AVAILABLE Account not available '3000': AuthenticationError, // TEST user '3002': AuthenticationError, // NICKNAME_EXIST Nicknames exist '3003': AuthenticationError, // ACCOUNT_NOT_EXIST No account '3004': BadRequest, // PARAM_ERROR Parameter exception '3005': NotSupported, // LANGUAGE_NONSUPPORT Unsupported languages '3007': AuthenticationError, // ONLY_SUBACCOUNT_OPE Sub-account operations only '3008': AuthenticationError, // LOGIN_ENABLE Account not logged '3009': AuthenticationError, // TFA_EXPIRE_ERROR Google key failed '3011': AuthenticationError, // PASSWORD_ERROR Password error '3012': AuthenticationError, // TFA_UUID_ERROR One-time unlock code error '3013': RequestTimeout, // TIME_OUT time out '3015': AuthenticationError, // ID_IS_ERROR id_is_error '3016': AuthenticationError, // WRONG_SUBACCOUNT_NAME already taken '3018': BadRequest, // USER_NAME_AT_LEAST_5_BYTE The user name must have at least 5 digits '3019': BadRequest, // PASSWORD_AT_LEAST_8_BYTE 8-32 bits contain at least three of the numbers, capital, lowercase letters and special symbols! '3020': BadRequest, // TFA_ALREADY_SET GoogleCode Already Set '3021': BadRequest, // PWD_MATCH_ERROR pwd_match_error '3022': BadRequest, // ILLEGAL_OPERATION illegal operation '3023': BadRequest, // REMOVE_SUBACCOUNT_OVER_LIMIT remove subaccount over limit '3024': BadRequest, // GOOGLE_VERIFICATION_CODE_TURNED_ON Google verification code turned on '3025': BadRequest, // OPERATION_FAILURE The operation failure '3026': BadRequest, // ACCOUNT_ACTIVED Account has Actived '3027': BadRequest, // INVALID_EMAIL_ADDRESS Invalid email address! '3028': BadRequest, // PASSWORD_FORMAT_ERROR Password format err '3029': DDoSProtection, // ONE_MINUTE_LIMIT Only one operation per minute and the remaining ${times}s '3030': DDoSProtection, // ONE_HOUR_LIMIT Do this up to 5 times per hour '3031': BadRequest, // USER_NAME_UP_12_BYTE Up to 12 characters, only letters and numbers are supported '3032': BadRequest, // EMAIL_SETTED You need to set email address and password first '3033': BadRequest, // PASSWORD_SETTED You need to set password first '3034': AuthenticationError, // SUBACCOUNT_EMAIL_ACTIVATE You need to wait for email confirmation '3035': BadRequest, // API_NOT_EXIST No api message '3036': BadRequest, // UNAVAILABLE_IN_SUBACCOUNT Unavailable in subaccount '3037': BadRequest, // MAX_SUBACCOUNT_NUMBER Limit of subaccounts is reached '3038': BadRequest, // MAIN_SUBACCOUNT_EMAIL_SAME Provided email address is already used for your other subaccount '3039': BadRequest, // MAX_API_KEY_NUMBER You cannot have more than 8 API keys '3040': AuthenticationError, // ALPHA_TEST Non-invited users shall contact BTCEX Team to obtain the internal tests qualification '3041': BadRequest, // API_NAME_MAX_LENGTH Name of key maximum length - 16 characters '4000': BadRequest, // WALLET_ERROR Wallet error || RECHARGE_CLOSED Recharge closed '4001': InvalidAddress, // WRONG_WITHDRAWAL_ADDRESS Wrong withdrawal address '4002': InvalidAddress, // ADDRESS_DOES_NOT_EXIST Address does not exist '4003': BadRequest, // WITHDRAWAL_CLOSED Withdrawal closed || TOO_SMALL_WITHDRAWAL_AMOUNT Too small withdrawal amount '4004': NotSupported, // INTERNAL_TRANSFER_IS_NOT_SUPPORTED_TEMPORARILY Internal transfer is not supported temporarily '4005': ExchangeError, // WITHDRAW_FAIL Withdrawal failed '4006': InsufficientFunds, // INSUFFICIENT_ASSET ser asset not enough '4007': BadRequest, // TRANSFER_ACCOUNT_ERROR Transfer account error '4008': NotSupported, // AMOUNT_ERROR Amount error '4009': InvalidAddress, // NO_RECHARGE_ADDRESS No recharge address '4010': BadRequest, // GET_TRANSFER_SUBACCOUNT_ERROR Get transfer subaccount error '4011': BadRequest, // TRANSFER_SUBMIT_URL_ERROR Transfer submit url error '5001': InvalidOrder, // ORDER_PARAM_WRONG Order's param wrong. '5002': OrderNotFound, // ORDER_DOSE_NOT_EXIST Order does not exist. '5003': InvalidOrder, // CONTRACT_DOSE_NOT_EXIST Contract does not exist. '5004': InvalidOrder, // ORDER_STATUS_ERR Order status error. '5005': InvalidOrder, // ORDER_AMOUNT_MIN_TRANCSACTION_ERR Order amount min transaction error. '5006': InvalidOrder, // ORDER_PRICE_MIN_TRANCSACTION_ERR Order price min price error. '5007': InvalidOrder, // ORDER_PRICE_TICK_SIZE_ERR Order price tick size error. '5008': InvalidOrder, // ORDER_TYPE_ERR Order type error. '5009': InvalidOrder, // ORDER_OPTION_IS_EXPIRED Order option is expired. '5010': InvalidOrder, // ORDER_IS_NOT_ACTIVE Order is not active. '5011': InvalidOrder, // IV_ORDER_ARE_NOT_SUPPORTED Iv orders are not supported. '5012': InvalidOrder, // ORDER_NO_MARK_PRICE_ERROR No mark price error. '5013': InvalidOrder, // ORDER_PRICE_RANGE_IS_TOO_HIGH order price range is too high. '5014': InvalidOrder, // ORDER_PRICE_RANGE_IS_TOO_LOW Order price range is too low. '5109': InvalidOrder, // ORDER_PRICE_RANGE_IS_TOO_LOW Order price range is too low. '5135': InvalidOrder, // The quantity should be larger than: 0.01 '5901': InvalidOrder, // TRANSFER_RESULT transfer out success. '5902': InvalidOrder, // ORDER_SUCCESS place order success. '5903': InvalidOrder, // ORDER_FAIL place order fail. '5904': InvalidOrder, // PRICE_TRIGGER_LIQ price trigger liquidation '5905': InvalidOrder, // LIQ_CANCEL liquidation make order cancel. '5906': InvalidOrder, // LIQ_ORDER liquidation place a new order '5907': InsufficientFunds, // ASSET_NOT_ENOUTH asset not enough '8000': BadRequest, // PARAM_ERROR Request params not valid! '8001': BadRequest, // DATA_NOT_EXIST The data doesn't exist! '8100': BadRequest, // CODE_CHECK_FAIL Incorrect verification code '8101': RequestTimeout, // CODE_NOT_EXIST Verification code time out, please retry later '8102': DDoSProtection, // CODE_CHECK_FAIL_LIMIT Errors exceed the limit. Please try again after 24H. '8103': BadRequest, // SMS_CODE_CHECK_FAIL Incorrect SMS verification code '8104': BadRequest, // MAIL_CODE_CHECK_FAIL Incorrect mail verification code '8105': BadRequest, // GOOGLE_CODE_CHECK_FAIL 2FA Code error! '8106': DDoSProtection, // SMS_CODE_LIMIT Your message service is over limit today, please try tomorrow '8107': ExchangeError, // REQUEST_FAILED Request failed '11000': BadRequest, // CHANNEL_REGEX_ERROR channel regex not match }, 'broad': { }, }, 'precisionMode': TICK_SIZE, 'options': { 'accountsByType': { 'wallet': 'WALLET', 'spot': 'SPOT', 'perpetual': 'PERPETUAL', 'margin': 'MARGIN', 'swap': 'PERPETUAL', 'BTC': 'BTC', 'ETH': 'ETH', }, }, 'commonCurrencies': { }, }); } async fetchMarkets (params = {}) { const response = await this.publicGetGetInstruments (params); const markets = this.safeValue (response, 'result', []); // // { // "jsonrpc":"2.0", // "usIn":1647533492507, // "usOut":1647533492511, // "usDiff":4, // "result":[{ // "currency":"BTC", // "base_currency":"USDT", // "contract_size":"0.01", // "creation_timestamp":"1632384961348", // "expiration_timestamp":"1648195200000", // "instrument_name":"BTC-25MAR22", // "show_name":"BTC-25MAR22", // "is_active":true, // "kind":"future", // "leverage":0, // "maker_commission":"10", // "taker_commission":"17", // "min_trade_amount":"0.01", // "option_type":"init", // "quote_currency":"USDT", // "settlement_period":"week", // "strike":"0", // "tick_size":"0.1", // "instr_multiple":"0.01", // "order_price_low_rate":"0.8", // "order_price_high_rate":"1.2", // "order_price_limit_type":0, // "min_qty":"0.01", // "min_notional":"0", // "support_trace_trade":false // }] // } // const result = []; for (let i = 0; i < markets.length; i++) { const market = markets[i]; const id = this.safeString (market, 'instrument_name'); const type = this.safeString (market, 'kind'); let unifiedType = type; if (type === 'perpetual') { unifiedType = 'swap'; } let baseId = this.safeString (market, 'quote_currency'); const quoteId = this.safeString (market, 'base_currency'); const swap = (type === 'perpetual'); const spot = (type === 'spot'); const margin = (type === 'margin'); const option = (type === 'option'); const future = (type === 'future'); const contract = swap || future || option; let expiry = undefined; if (option || future) { baseId = this.safeString (market, 'currency'); expiry = this.safeInteger (market, 'expiration_timestamp'); } let contractSize = undefined; let settleId = undefined; let settle = undefined; if (contract) { settleId = quoteId; settle = this.safeCurrencyCode (settleId); } let optionType = undefined; let strike = undefined; if (option) { optionType = this.safeString (market, 'option_type'); strike = this.safeNumber (market, 'strike'); } const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); let symbol = undefined; if (margin) { symbol = id; } else { symbol = base + '/' + quote; } if (contract) { contractSize = this.safeNumber (market, 'contract_size'); symbol = symbol + ':' + settle; if (future || option) { symbol = symbol + '-' + this.yymmdd (expiry); if (option) { const letter = (optionType === 'call') ? 'C' : 'P'; symbol = symbol + ':' + this.numberToString (strike) + ':' + letter; } } } const minTradeAmount = this.safeNumber (market, 'min_trade_amount'); const tickSize = this.safeNumber (market, 'tick_size'); const maker = this.safeNumber (market, 'maker_commission'); const taker = this.safeNumber (market, 'taker_commission'); const percentage = !(option || future); result.push ({ 'id': id, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'settle': settle, 'type': unifiedType, 'maker': maker, 'taker': taker, 'percentage': percentage, 'spot': spot, 'margin': margin, 'swap': swap, 'future': future, 'option': option, 'active': this.safeValue (market, 'is_active'), 'contract': contract, 'linear': contract ? true : undefined, 'inverse': contract ? false : undefined, 'contractSize': contractSize, 'expiry': expiry, 'expiryDatetime': this.iso8601 (expiry), 'strike': strike, 'optionType': optionType, 'precision': { 'amount': minTradeAmount, 'price': tickSize, }, 'limits': { 'leverage': { 'min': undefined, 'max': this.safeString (market, 'leverage'), }, 'amount': { 'min': minTradeAmount, 'max': undefined, }, 'price': { 'min': tickSize, 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'info': market, }); } return result; } parseTicker (ticker, market = undefined) { // // { // "best_ask_amount":"0.20962", // "best_ask_price":"40491.7", // "best_bid_amount":"0.08855", // "best_bid_price":"40491.6", // "instrument_name":"BTC-USDT", // "last_price":"40493", // "mark_price":"40493.10644717", // "state":"open", // "stats":{ // "high":"41468.8", // "low":"40254.9", // "price_change":"-0.0159", // "volume":"3847.35240000000000005" // "turnover":"1109811189.67100102035328746" // }, // "timestamp":"1647569486224" // } // const marketId = this.safeString (ticker, 'instrument_name'); market = this.safeMarket (marketId, market); const symbol = this.safeSymbol (marketId, market); const timestamp = this.safeInteger (ticker, 'timestamp'); const stats = this.safeValue (ticker, 'stats'); return this.safeTicker ({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'high': this.safeString (stats, 'high'), 'low': this.safeString (stats, 'low'), 'bid': this.safeString (ticker, 'best_bid_price'), 'bidVolume': this.safeString (ticker, 'best_bid_amount'), 'ask': this.safeString (ticker, 'best_ask_price'), 'askVolume': this.safeString (ticker, 'best_ask_amount'), 'vwap': undefined, 'open': undefined, 'close': this.safeString (ticker, 'last_price'), 'last': this.safeString (ticker, 'last_price'), 'previousClose': undefined, 'change': undefined, 'percentage': this.safeString (stats, 'price_change'), 'average': undefined, 'baseVolume': this.safeString (stats, 'volume'), 'quoteVolume': this.safeString (stats, 'turnover'), 'info': ticker, }, market); } async fetchTicker (symbol, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'instrument_name': market['id'], }; const response = await this.publicGetTickers (this.extend (request, params)); const result = this.safeValue (response, 'result', {}); // // { // "jsonrpc":"2.0", // "usIn":1647569487238, // "usOut":1647569487240, // "usDiff":2, // "result":[{ // "best_ask_amount":"0.20962", // "best_ask_price":"40491.7", // "best_bid_amount":"0.08855", // "best_bid_price":"40491.6", // "instrument_name":"BTC-USDT", // "last_price":"40493", // "mark_price":"40493.10644717", // "state":"open", // "stats":{ // "high":"41468.8", // "low":"40254.9", // "price_change":"-0.0159", // "volume":"3847.35240000000000005" // }, // "timestamp":"1647569486224" // }] // } // const ticker = this.safeValue (result, 0); return this.parseTicker (ticker, market); } async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'instrument_name': market['id'], }; const response = await this.publicGetGetOrderBook (this.extend (request, params)); const result = this.safeValue (response, 'result', {}); // // { // "jsonrpc":"2.0", // "usIn":1647573916524, // "usOut":1647573916526, // "usDiff":2, // "result":{ // "asks":[["10155.00000","0.200","186.980","0.000"],["10663.00000","0.200","217.480","0.000"]], // "bids":[["7896.00000","0.200","1.000","0.000"],["7481.00000","0.200","1.000","0.000"]], // "timestamp":"1647573916525", // "instrument_name":"BTC-25MAR22-32000-C", // "version":1002541 // } // } // const timestamp = this.safeInteger (result, 'timestamp'); return this.parseOrderBook (result, market['symbol'], timestamp); } parseOHLCV (ohlcv, market = undefined) { // // { // "tick":1647547200, // "open":"40868.16800000", // "high":"40877.65600000", // "low":"40647.00000000", // "close":"40699.10000000", // "volume":"100.27789000", // "cost":"4083185.78337596" // } // return [ this.safeTimestamp (ohlcv, 'tick'), this.safeNumber (ohlcv, 'open'), this.safeNumber (ohlcv, 'high'), this.safeNumber (ohlcv, 'low'), this.safeNumber (ohlcv, 'close'), this.safeNumber (ohlcv, 'volume'), ]; } async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); if (limit === undefined) { limit = 10; } const request = { 'resolution': this.timeframes[timeframe], // 'start_timestamp': 0, // 'end_timestamp': 0, }; let marketId = market['id']; if (market['spot'] || market['margin']) { marketId = market['baseId'] + '-' + market['quoteId']; } request['instrument_name'] = marketId; if (since === undefined) { request['end_timestamp'] = this.milliseconds (); request['start_timestamp'] = 0; } else { const timeframeInSeconds = this.parseTimeframe (timeframe); const timeframeInMilliseconds = timeframeInSeconds * 1000; request['start_timestamp'] = since; request['end_timestamp'] = this.sum (request['start_timestamp'], limit * timeframeInMilliseconds); } const response = await this.publicGetGetTradingviewChartData (this.extend (request, params)); const result = this.safeValue (response, 'result', []); // // { // "jsonrpc":"2.0", // "usIn":1647578562427, // "usOut":1647578562428, // "usDiff":1, // "result":[{ // "tick":1647547200, // "open":"40868.16800000", // "high":"40877.65600000", // "low":"40647.00000000", // "close":"40699.10000000", // "volume":"100.27789000", // "cost":"4083185.78337596" // }] // } // return this.parseOHLCVs (result, market, timeframe, since, limit); } parseTrade (trade, market = undefined) { // // fetchTrades (public) // // { // "amount":"0.0003", // "direction":"sell", // "iv":"0", // "price":"40767.18", // "timestamp":"1647582687050", // "instrument_name":"BTC-USDT-SPOT", // "trade_id":57499240 // } // // fetchOrderTrades || fetchMyTrades // // { // "direction":"sell", // "amount":"0.03", // "price":"397.8", // "fee":"0.011934", // "timestamp":1647668570759, // "role":"taker", // "trade_id":"58319385", // "order_id":"250979478947823616", // "instrument_name":"BNB-USDT-SPOT", // "order_type":"market", // "fee_use_coupon":false, // "fee_coin_type":"USDT", // "index_price":"", // "self_trade":false // } // const id = this.safeString (trade, 'trade_id'); const marketId = this.safeString (trade, 'instrument_name'); const symbol = this.safeSymbol (marketId, market); const timestamp = this.safeInteger (trade, 'timestamp'); const side = this.safeString (trade, 'direction'); const priceString = this.safeString (trade, 'price'); const amountString = this.safeString (trade, 'amount'); const takerOrMaker = this.safeString (trade, 'role'); const feeCostString = this.safeString (trade, 'fee'); let fee = undefined; if (feeCostString !== undefined) { const feeCurrencyId = this.safeString (trade, 'fee_coin_type'); const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); fee = { 'cost': feeCostString, 'currency': feeCurrencyCode, }; } return this.safeTrade ({ 'info': trade, 'id': id, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'symbol': symbol, 'order': this.safeString (trade, 'order_id'), 'type': this.safeString (trade, 'order_type'), 'side': side, 'takerOrMaker': takerOrMaker, 'price': priceString, 'amount': amountString, 'cost': undefined, 'fee': fee, }, market); } async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'instrument_name': market['id'], // 'start_id' : 0, // 'end_id': 0, // 'sorting': 'asc', // asc | desc }; if (limit !== undefined) { request['count'] = limit; // default 10 } const response = await this.publicGetGetLastTradesByInstrument (this.extend (request, params)); const result = this.safeValue (response, 'result', {}); // // { // "jsonrpc":"2.0", // "usIn":1647582703220, // "usOut":1647582703253, // "usDiff":33, // "result":{ // "trades":[{ // "amount":"0.0003", // "direction":"sell", // "iv":"0", // "price":"40767.18", // "timestamp":"1647582687050", // "instrument_name":"BTC-USDT-SPOT", // "trade_id":57499240 // }], // "has_more":true // } // } // const trades = this.safeValue (result, 'trades', []); return this.parseTrades (trades, market, since, limit); } async signIn (params = {}) { let accessToken = this.safeString (this.options, 'accessToken'); if (accessToken !== undefined) { return accessToken; } this.checkRequiredCredentials (); const request = { 'grant_type': 'client_credentials', // client_signature || refresh_token 'client_id': this.apiKey, 'client_secret': this.secret, // 'refresh_token': '', // Required for grant type refresh_token // 'signature': '', // Required for grant type client_signature }; const response = await this.publicPostAuth (this.extend (request, params)); const result = this.safeValue (response, 'result'); // // { // jsonrpc: '2.0', // usIn: '1647601525586', // usOut: '1647601525597', // usDiff: '11', // result: { // access_token: '', // token_type: 'bearer', // refresh_token: '', // expires_in: '604799', // scope: 'account:read_write block_trade:read_write trade:read_write wallet:read_write' // } // } // accessToken = this.safeString (result, 'access_token'); this.options['accessToken'] = accessToken; return accessToken; } parseBalance (response) { // // { // "WALLET":{ // "total":"0", // "coupon":"0", // "details":[{ // "available":"0", // "freeze":"0", // "coin_type":"1INCH", // "current_mark_price":"1.657" // }] // }, // "MARGIN":{ // "total":"0", // "net":"0", // "available":"0", // "borrowed":"0", // "details":[], // "maintenance_margin":"0", // "interest_owed":"0" // }, // "SPOT":{ // "total":"3.965", // "available":"15.887066", // "details":[{ // "available":"0", // "freeze":"0", // "total":"0", // "coin_type":"1INCH", // "current_mark_price":"1.657" // }] // }, // "BTC":{ // "currency":"BTC", // "balance":"0", // "freeze":"0", // "equity":"0", // "base_currency":"USDT", // "available_funds":"0", // "available_withdrawal_funds":"0", // "initial_margin":"0", // "maintenance_margin":"0", // "margin_balance":"0", // "session_funding":"0", // "session_rpl":"0", // "session_upl":"0", // "futures_pl":"0", // "futures_session_rpl":"0", // "futures_session_upl":"0", // "options_value":"0", // "options_pl":"0", // "options_session_rpl":"0", // "options_session_upl":"0", // "total_pl":"0", // "options_delta":"0", // "options_gamma":"0", // "options_theta":"0", // "options_vega":"0", // "delta_total":"0" // }, // "ETH":{ // "currency":"ETH", // "balance":"0", // "freeze":"0", // "equity":"0", // "base_currency":"USDT", // "available_funds":"0", // "available_withdrawal_funds":"0", // "initial_margin":"0", // "maintenance_margin":"0", // "margin_balance":"0", // "session_funding":"0", // "session_rpl":"0", // "session_upl":"0", // "futures_pl":"0", // "futures_session_rpl":"0", // "futures_session_upl":"0", // "options_value":"0", // "options_pl":"0", // "options_session_rpl":"0", // "options_session_upl":"0", // "total_pl":"0", // "options_delta":"0", // "options_gamma":"0", // "options_theta":"0", // "options_vega":"0", // "delta_total":"0" // }, // "PERPETUAL":{ // "bonus":"0", // "global_state":0, // "available_funds":"0", // "wallet_balance":"0", // "available_withdraw_funds":"0", // "total_pl":"0", // "total_upl":"0", // "position_rpl":"0", // "total_upl_isolated":"0", // "total_upl_cross":"0", // "total_initial_margin_cross":"0", // "total_initial_margin_isolated":"0", // "total_margin_balance_isolated":"0", // "total_margin_balance":"0", // "total_margin_balance_cross":"0", // "total_maintenance_margin_cross":"0", // "total_wallet_balance_isolated":"0", // "order_frozen":"0", // "order_cross_frozen":"0", // "order_isolated_frozen":"0", // "risk_level":"0", // "bonus_max":"0" // } // } // const result = { 'info': response }; const assetTypes = Object.keys (response); for (let i = 0; i < assetTypes.length; i++) { const assetType = assetTypes[i]; const currency = this.safeValue (response, assetType); if ((assetType === 'WALLET') || (assetType === 'SPOT')) { const details = this.safeValue (currency, 'details'); if (details !== undefined) { for (let i = 0; i < details.length; i++) { const detail = details[i]; const coinType = this.safeString (detail, 'coin_type'); const code = this.safeCurrencyCode (coinType); const account = this.safeValue (result, code, this.account ()); account['free'] = this.safeString (detail, 'available'); account['used'] = this.safeString (detail, 'freeze'); account['total'] = this.safeString (detail, 'total'); result[code] = account; } } } else { // all other wallets are linear futures const code = 'USDT'; const account = this.account (); account['total'] = this.safeString (currency, 'wallet_balance'); account['free'] = this.safeString (currency, 'available_withdraw_funds'); result[code] = account; } } return this.safeBalance (result); } async fetchBalance (params = {}) { await this.signIn (); await this.loadMarkets (); const type = this.safeStringLower (params, 'type', 'spot'); const types = this.safeValue (this.options, 'accountsByType', {}); const assetType = this.safeString (types, type, type); params = this.omit (params, 'type'); const request = { 'asset_type': [ assetType ], }; const response = await this.privatePostGetAssetsInfo (this.extend (request, params)); const result = this.safeValue (response, 'result', []); // // { // "id":"1647675393", // "jsonrpc":"2.0", // "usIn":1647675394091, // "usOut":1647675394104, // "usDiff":13, // "result":{ // "WALLET":{ // "total":"0", // "coupon":"0", // "details":[{ // "available":"0", // "freeze":"0", // "coin_type":"1INCH", // "current_mark_price":"1.657" // }] // }, // "MARGIN":{ // "total":"0", // "net":"0", // "available":"0", // "borrowed":"0", // "details":[], // "maintenance_margin":"0", // "interest_owed":"0" // }, // "SPOT":{ // "total":"3.965", // "available":"15.887066", // "details":[{ // "available":"0", // "freeze":"0", // "total":"0", // "coin_type":"1INCH", // "current_mark_price":"1.657" // }] // }, // "BTC":{ // "currency":"BTC", // "balance":"0", // "freeze":"0", // "equity":"0", // "base_currency":"USDT", // "available_funds":"0", // "available_withdrawal_funds":"0", // "initial_margin":"0", // "maintenance_margin":"0", // "margin_balance":"0", // "session_funding":"0", // "session_rpl":"0", // "session_upl":"0", // "futures_pl":"0", // "futures_session_rpl":"0", // "futures_session_upl":"0", // "options_value":"0", // "options_pl":"0", // "options_session_rpl":"0", // "options_session_upl":"0", // "total_pl":"0", // "options_delta":"0", // "options_gamma":"0", // "options_theta":"0", // "options_vega":"0", // "delta_total":"0" // }, // "ETH":{ // "currency":"ETH", // "balance":"0", // "freeze":"0", // "equity":"0", // "base_currency":"USDT", // "available_funds":"0", // "available_withdrawal_funds":"0", // "initial_margin":"0", // "maintenance_margin":"0", // "margin_balance":"0", // "session_funding":"0", // "session_rpl":"0", // "session_upl":"0", // "futures_pl":"0", // "futures_session_rpl":"0", // "futures_session_upl":"0", // "options_value":"0", // "options_pl":"0", // "options_session_rpl":"0", // "options_session_upl":"0", // "total_pl":"0", // "options_delta":"0", // "options_gamma":"0", // "options_theta":"0", // "options_vega":"0", // "delta_total":"0" // }, // "PERPETUAL":{ // "bonus":"0", // "global_state":0, // "available_funds":"0", // "wallet_balance":"0", // "available_withdraw_funds":"0", // "total_pl":"0", // "total_upl":"0", // "position_rpl":"0", // "total_upl_isolated":"0", // "total_upl_cross":"0", // "total_initial_margin_cross":"0", // "total_initial_margin_isolated":"0", // "total_margin_balance_isolated":"0", // "total_margin_balance":"0", // "total_margin_balance_cross":"0", // "total_maintenance_margin_cross":"0", // "total_wallet_balance_isolated":"0", // "order_frozen":"0", // "order_cross_frozen":"0", // "order_isolated_frozen":"0", // "risk_level":"0", // "bonus_max":"0" // } // } // } // return this.parseBalance (result); } parseOrderStatus (status) { const statuses = { 'open': 'open', 'cancelled': 'canceled', 'filled': 'closed', 'rejected': 'rejected', }; return this.safeString (statuses, status, status); } parseTimeInForce (timeInForce) { if (timeInForce === '-') { return undefined; } const timeInForces = { 'good_til_cancelled': 'GTC', 'good_til_date': 'GTD', 'fill_or_kill': 'FOK', 'immediate_or_cancel': 'IOC', }; return this.safeString (timeInForces, timeInForce, timeInForce); } parseOrder (order, market = undefined) { // // fetchOrder || fetchOpenOrders || fetchClosedOrders // { // "kind":"spot", // "direction":"sell", // "amount":"0.02", // "price":"900", // "advanced":"usdt", // "source":"api", // "mmp":false, // "version":1, // "order_id":"250971492850401280", // "order_state":"open", // "instrument_name":"BNB-USDT-SPOT", // "filled_amount":"0", // "average_price":"0", // "order_type":"limit", // "time_in_force":"GTC", // "post_only":false, // "reduce_only":false, // "creation_timestamp":1647666666723, // "last_update_timestamp":1647666666725 // } // // createOrder // // { // "order_id":"251052889774161920", // "custom_order_id":"-" // } // // closeOrder // {