UNPKG

sfccxt

Version:

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

1,218 lines (1,195 loc) 105 kB
'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { ExchangeError, InvalidAddress, DuplicateOrderId, ArgumentsRequired, InsufficientFunds, InvalidOrder, InvalidNonce, AuthenticationError, RateLimitExceeded, PermissionDenied, BadRequest, BadSymbol } = require ('./base/errors'); const { TICK_SIZE } = require ('./base/functions/number'); const Precise = require ('./base/Precise'); // --------------------------------------------------------------------------- module.exports = class lbank2 extends Exchange { describe () { return this.deepExtend (super.describe (), { 'id': 'lbank2', 'name': 'LBank', 'countries': [ 'CN' ], 'version': 'v2', // 50 per second for making and cancelling orders 1000ms / 50 = 20 // 20 per second for all other requests, cost = 50 / 20 = 2.5 'rateLimit': 20, 'has': { 'CORS': false, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'addMargin': false, 'cancelAllOrders': true, 'cancelOrder': true, 'createOrder': true, 'createReduceOnlyOrder': false, 'createStopLimitOrder': false, 'createStopMarketOrder': false, 'createStopOrder': false, 'fetchBalance': true, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchBorrowRatesPerSymbol': false, 'fetchClosedOrders': false, 'fetchDepositWithdrawFee': 'emulated', 'fetchDepositWithdrawFees': true, 'fetchFundingHistory': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchIsolatedPositions': false, 'fetchLeverage': false, 'fetchLeverageTiers': false, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchPosition': false, 'fetchPositionMode': false, 'fetchPositions': false, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTrades': true, 'fetchTradingFees': true, 'fetchTransactionFees': true, 'reduceMargin': false, 'setLeverage': false, 'setMarginMode': false, 'setPositionMode': false, 'withdraw': false, }, 'timeframes': { '1m': 'minute1', '5m': 'minute5', '15m': 'minute15', '30m': 'minute30', '1h': 'hour1', '2h': 'hour2', '4h': 'hour4', '6h': 'hour6', '8h': 'hour8', '12h': 'hour12', '1d': 'day1', '1w': 'week1', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/38063602-9605e28a-3302-11e8-81be-64b1e53c4cfb.jpg', 'api': { 'rest': 'https://api.lbank.info', }, 'api2': 'https://api.lbkex.com', 'www': 'https://www.lbank.info', 'doc': 'https://www.lbank.info/en-US/docs/index.html', 'fees': 'https://lbankinfo.zendesk.com/hc/en-gb/articles/360012072873-Trading-Fees', 'referral': 'https://www.lbank.info/invitevip?icode=7QCY', }, 'api': { 'public': { 'get': { 'currencyPairs': 2.5, 'accuracy': 2.5, 'usdToCny': 2.5, 'withdrawConfigs': 2.5, 'timestamp': 2.5, 'ticker/24hr': 2.5, 'ticker': 2.5, 'depth': 2.5, 'incrDepth': 2.5, 'trades': 2.5, 'kline': 2.5, // new quote endpoints 'supplement/system_ping': 2.5, 'supplement/incrDepth': 2.5, 'supplement/trades': 2.5, 'supplement/ticker/price': 2.5, 'supplement/ticker/bookTicker': 2.5, }, 'post': { 'supplement/system_status': 2.5, }, }, 'private': { 'post': { // account 'user_info': 2.5, 'subscribe/get_key': 2.5, 'subscribe/refresh_key': 2.5, 'subscribe/destroy_key': 2.5, 'get_deposit_address': 2.5, 'deposit_history': 2.5, // order 'create_order': 1, 'batch_create_order': 1, 'cancel_order': 1, 'cancel_clientOrders': 1, 'orders_info': 2.5, 'orders_info_history': 2.5, 'order_transaction_detail': 2.5, 'transaction_history': 2.5, 'orders_info_no_deal': 2.5, // withdraw 'withdraw': 2.5, 'withdrawCancel': 2.5, 'withdraws': 2.5, 'supplement/user_info': 2.5, 'supplement/withdraw': 2.5, 'supplement/deposit_history': 2.5, 'supplement/withdraws': 2.5, 'supplement/get_deposit_address': 2.5, 'supplement/asset_detail': 2.5, 'supplement/customer_trade_fee': 2.5, 'supplement/api_Restrictions': 2.5, // new quote endpoints 'supplement/system_ping': 2.5, // new order endpoints 'supplement/create_order_test': 1, 'supplement/create_order': 1, 'supplement/cancel_order': 1, 'supplement/cancel_order_by_symbol': 1, 'supplement/orders_info': 2.5, 'supplement/orders_info_no_deal': 2.5, 'supplement/orders_info_history': 2.5, 'supplement/user_info_account': 2.5, 'supplement/transaction_history': 2.5, }, }, }, 'fees': { 'trading': { 'maker': this.parseNumber ('0.001'), 'taker': this.parseNumber ('0.001'), }, 'funding': { 'withdraw': {}, }, }, 'commonCurrencies': { 'VET_ERC20': 'VEN', 'PNT': 'Penta', }, 'precisionMode': TICK_SIZE, 'options': { 'cacheSecretAsPem': true, 'createMarketBuyOrderRequiresPrice': true, 'fetchTrades': { 'method': 'publicGetTrades', // or 'publicGetTradesSupplement' }, 'fetchTransactionFees': { // DEPRECATED, please use fetchDepositWithdrawFees 'method': 'fetchPrivateTransactionFees', // or 'fetchPublicTransactionFees' }, 'fetchDepositWithdrawFees': { 'method': 'fetchPrivateDepositWithdrawFees', // or 'fetchPublicDepositWithdrawFees' }, 'fetchDepositAddress': { 'method': 'fetchDepositAddressDefault', // or fetchDepositAddressSupplement }, 'createOrder': { 'method': 'privatePostSupplementCreateOrder', // or privatePostCreateOrder }, 'fetchOrder': { 'method': 'fetchOrderSupplement', // or fetchOrderDefault }, 'fetchBalance': { 'method': 'privatePostSupplementUserInfo', // or privatePostSupplementUserInfoAccount or privatePostUserInfo }, 'networks': { 'ERC20': 'erc20', 'ETH': 'erc20', 'TRC20': 'trc20', 'TRX': 'trc20', 'OMNI': 'omni', 'ASA': 'asa', 'BEP20': 'bep20(bsc)', 'BSC': 'bep20(bsc)', 'HT': 'heco', 'BNB': 'bep2', 'BTC': 'btc', 'DOGE': 'dogecoin', 'MATIC': 'matic', 'POLYGON': 'matic', 'OEC': 'oec', 'BTCTRON': 'btctron', 'XRP': 'xrp', // other unusual chains with number of listed currencies supported // 'avax c-chain': 1, // klay: 12, // bta: 1, // fantom: 1, // celo: 1, // sol: 2, // zenith: 1, // ftm: 5, // bep20: 1, (single token with mis-named chain) SSS // bitci: 1, // sgb: 1, // moonbeam: 1, // ekta: 1, // etl: 1, // arbitrum: 1, // tpc: 1, // ptx: 1 // } }, 'inverse-networks': { 'erc20': 'ERC20', 'trc20': 'TRC20', 'omni': 'OMNI', 'asa': 'ASA', 'bep20(bsc)': 'BSC', 'bep20': 'BSC', 'heco': 'HT', 'bep2': 'BNB', 'btc': 'BTC', 'dogecoin': 'DOGE', 'matic': 'MATIC', 'oec': 'OEC', 'btctron': 'BTCTRON', 'xrp': 'XRP', }, 'defaultNetworks': { 'USDT': 'TRC20', }, }, }); } async fetchMarkets (params = {}) { /** * @method * @name lbank2#fetchMarkets * @description retrieves data on all markets for lbank2 * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ // needs to return a list of unified market structures const response = await this.publicGetAccuracy (); const data = this.safeValue (response, 'data'); // [ // { // symbol: 'snx3s_usdt', // quantityAccuracy: '2', // minTranQua: '0.01', // priceAccuracy: '6' // } // ] const result = []; for (let i = 0; i < data.length; i++) { const market = data[i]; const marketId = this.safeString (market, 'symbol'); const parts = marketId.split ('_'); const baseId = parts[0]; const quoteId = parts[1]; const base = baseId.toUpperCase (); const quote = quoteId.toUpperCase (); let symbol = base + '/' + quote; const productTypes = { '3l': true, '5l': true, '3s': true, '5s': true, }; const ending = baseId.slice (-2); const isLeveragedProduct = this.safeValue (productTypes, ending, false); if (isLeveragedProduct) { symbol += ':' + quote; } let linear = undefined; if (isLeveragedProduct === true) { linear = true; } result.push ({ 'id': marketId, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': undefined, 'baseId': baseId, 'quoteId': quoteId, 'settleId': undefined, 'type': 'spot', 'spot': true, 'margin': false, 'swap': isLeveragedProduct, 'future': false, 'option': false, 'active': true, 'contract': isLeveragedProduct, 'linear': linear, // all leveraged ETF products are in USDT 'inverse': undefined, 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber (this.parsePrecision (this.safeString (market, 'quantityAccuracy'))), 'price': this.parseNumber (this.parsePrecision (this.safeString (market, 'priceAccuracy'))), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber (market, 'minTranQua'), 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'info': market, }); } return result; } parseTicker (ticker, market = undefined) { // // { // "symbol":"btc_usdt", // "ticker": { // "high":40200.88, // "vol":7508.3096, // "low":38239.38, // "change":0.75, // "turnover":292962771.34, // "latest":39577.95 // }, // "timestamp":1647005189792 // } // const marketId = this.safeString (ticker, 'symbol'); const symbol = this.safeSymbol (marketId, market); const timestamp = this.safeInteger (ticker, 'timestamp'); const tickerData = this.safeValue (ticker, 'ticker'); return this.safeTicker ({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'high': this.safeString (tickerData, 'high'), 'low': this.safeString (tickerData, 'low'), 'bid': undefined, 'bidVolume': undefined, 'ask': undefined, 'askVolume': undefined, 'vwap': undefined, 'open': undefined, 'close': undefined, 'last': this.safeString (tickerData, 'latest'), 'previousClose': undefined, 'change': undefined, 'percentage': this.safeString (tickerData, 'change'), 'average': undefined, 'baseVolume': this.safeString (tickerData, 'vol'), 'quoteVolume': this.safeString (tickerData, 'turnover'), 'info': ticker, }, market); } async fetchTicker (symbol, params = {}) { /** * @method * @name lbank2#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 lbank2 api endpoint * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ await this.loadMarkets (); const market = this.market (symbol); const request = { 'symbol': market['id'], }; const response = await this.publicGetTicker24hr (this.extend (request, params)); // // { // "result":"true", // "data": [ // { // "symbol":"btc_usdt", // "ticker":{ // "high":40200.88, // "vol":7508.3096, // "low":38239.38, // "change":0.75, // "turnover":292962771.34, // "latest":39577.95 // }, // "timestamp":1647005189792 // } // ], // "error_code":0,"ts":1647005190755 // } // const data = this.safeValue (response, 'data', []); const first = this.safeValue (data, 0, {}); return this.parseTicker (first, market); } async fetchTickers (symbols = undefined, params = {}) { /** * @method * @name lbank2#fetchTickers * @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market * @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 lbank api endpoint * @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ await this.loadMarkets (); const request = { 'symbol': 'all', }; const response = await this.publicGetTicker24hr (this.extend (request, params)); const data = this.safeValue (response, 'data', []); return this.parseTickers (data, symbols); } async fetchOrderBook (symbol, limit = undefined, params = {}) { /** * @method * @name lbank2#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 lbank2 api endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-book-structure} indexed by market symbols */ await this.loadMarkets (); const market = this.market (symbol); if (limit === undefined) { limit = 60; } const request = { 'symbol': market['id'], 'size': limit, }; const response = await this.publicGetDepth (this.extend (request, params)); const orderbook = response['data']; const timestamp = this.milliseconds (); return this.parseOrderBook (orderbook, market['symbol'], timestamp); } parseTrade (trade, market = undefined) { // // fetchTrades (old) publicGetTrades // // { // "date_ms":1647021989789, // "amount":0.0028, // "price":38804.2, // "type":"buy", // "tid":"52d5616ee35c43019edddebe59b3e094" // } // // // fetchTrades (new) publicGetTradesSupplement // // { // "quoteQty":1675.048485, // "price":0.127545, // "qty":13133, // "id":"3589541dc22e4357b227283650f714e2", // "time":1648058297110, // "isBuyerMaker":false // } // // fetchMyTrades (private) // // { // "orderUuid":"38b4e7a4-14f6-45fd-aba1-1a37024124a0", // "tradeFeeRate":0.0010000000, // "dealTime":1648500944496, // "dealQuantity":30.00000000000000000000, // "tradeFee":0.00453300000000000000, // "txUuid":"11f3850cc6214ea3b495adad3a032794", // "dealPrice":0.15111300000000000000, // "dealVolumePrice":4.53339000000000000000, // "tradeType":"sell_market" // } // let timestamp = this.safeInteger2 (trade, 'date_ms', 'time'); if (timestamp === undefined) { timestamp = this.safeInteger (trade, 'dealTime'); } let amountString = this.safeString2 (trade, 'amount', 'qty'); if (amountString === undefined) { amountString = this.safeString (trade, 'dealQuantity'); } let priceString = this.safeString (trade, 'price'); if (priceString === undefined) { priceString = this.safeString (trade, 'dealPrice'); } let costString = this.safeString (trade, 'quoteQty'); if (costString === undefined) { costString = this.safeString (trade, 'dealVolumePrice'); } let side = this.safeString2 (trade, 'tradeType', 'type'); let type = undefined; let takerOrMaker = undefined; if (side !== undefined) { const parts = side.split ('_'); side = this.safeString (parts, 0); const typePart = this.safeString (parts, 1); type = 'limit'; takerOrMaker = 'taker'; if (typePart !== undefined) { if (typePart === 'market') { type = 'market'; } else if (typePart === 'maker') { takerOrMaker = 'maker'; } } } let id = this.safeString2 (trade, 'tid', 'id'); if (id === undefined) { id = this.safeString (trade, 'txUuid'); } const order = this.safeString (trade, 'orderUuid'); const symbol = this.safeSymbol (undefined, market); let fee = undefined; const feeCost = this.safeString (trade, 'tradeFee'); if (feeCost !== undefined) { fee = { 'cost': feeCost, 'currency': undefined, 'rate': this.safeString (trade, 'tradeFeeRate'), }; } return this.safeTrade ({ 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'symbol': symbol, 'id': id, 'order': order, 'type': type, 'takerOrMaker': takerOrMaker, 'side': side, 'price': priceString, 'amount': amountString, 'cost': costString, 'fee': fee, 'info': trade, }, market); } async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name lbank2#fetchTrades * @description get the list of most recent trades for a particular symbol * @param {string} symbol unified symbol of the market to fetch trades for * @param {int|undefined} since timestamp in ms of the earliest trade to fetch * @param {int|undefined} limit the maximum amount of trades to fetch * @param {object} params extra parameters specific to the lbank2 api endpoint * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades} */ await this.loadMarkets (); const market = this.market (symbol); const request = { 'symbol': market['id'], }; if (since !== undefined) { request['time'] = since; } if (limit !== undefined) { request['size'] = limit; } else { request['size'] = 600; // max } let method = this.safeString (params, 'method'); params = this.omit (params, 'method'); if (method === undefined) { const options = this.safeValue (this.options, 'fetchTrades', {}); method = this.safeString (options, 'method', 'publicGetTrades'); } const response = await this[method] (this.extend (request, params)); // // { // "result":"true", // "data": [ // { // "date_ms":1647021989789, // "amount":0.0028, // "price":38804.2, // "type":"buy", // "tid":"52d5616ee35c43019edddebe59b3e094" // } // ], // "error_code":0, // "ts":1647021999308 // } const trades = this.safeValue (response, 'data', []); return this.parseTrades (trades, market, since, limit); } parseOHLCV (ohlcv, market = undefined) { // // [ // 1482311500, // timestamp // 5423.23, // open // 5472.80, // high // 5516.09, // low // 5462, // close // 234.3250 // volume // ], // return [ this.safeTimestamp (ohlcv, 0), // timestamp this.safeNumber (ohlcv, 1), // open this.safeNumber (ohlcv, 2), // high this.safeNumber (ohlcv, 3), // low this.safeNumber (ohlcv, 4), // close this.safeNumber (ohlcv, 5), // volume ]; } async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { /** * @method * @name lbank2#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @param {string} symbol unified symbol of the market to fetch OHLCV data for * @param {string} timeframe the length of time each candle represents * @param {int|undefined} since timestamp in ms of the earliest candle to fetch * @param {int|undefined} limit the maximum amount of candles to fetch * @param {object} params extra parameters specific to the lbank2 api endpoint * @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume */ // endpoint doesnt work await this.loadMarkets (); const market = this.market (symbol); if (limit === undefined) { limit = 100; } if (since === undefined) { const duration = this.parseTimeframe (timeframe); since = this.milliseconds () - duration * 1000 * limit; } const request = { 'symbol': market['id'], 'type': this.timeframes[timeframe], 'time': parseInt (since / 1000), 'size': limit, // max 2000 }; const response = await this.publicGetKline (this.extend (request, params)); const ohlcvs = this.safeValue (response, 'data', []); // // // [ // [ // 1482311500, // 5423.23, // 5472.80, // 5516.09, // 5462, // 234.3250 // ], // [ // 1482311400, // 5432.52, // 5459.87, // 5414.30, // 5428.23, // 213.7329 // ] // ] // return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit); } parseBalance (response) { // // privatePostUserInfo // // { // "toBtc": { // "egc:": "0", // "iog": "0", // "ksm": "0", // }, // "freeze": { // "egc": "0", // "iog": "0", // "ksm": "0" , // }, // "asset": { // "egc": "0", // "iog": "0", // "ksm": "0", // }, // "free": { // "egc": "0", // "iog": "0", // "ksm": "0", // } // } // // privatePostSupplementUserInfoAccount // // { // "balances":[ // { // "asset":"lbk", // "free":"0", // "locked":"0" // }, ... // ] // } // // privatePostSupplementUserInfo // // [ // { // "usableAmt":"31.45130723", // "assetAmt":"31.45130723", // "networkList":[ // { // "isDefault":true, // "withdrawFeeRate":"", // "name":"bep20(bsc)", // "withdrawMin":30, // "minLimit":0.0001, // "minDeposit":0.0001, // "feeAssetCode":"doge", // "withdrawFee":"30", // "type":1, // "coin":"doge", // "network":"bsc" // }, // { // "isDefault":false, // "withdrawFeeRate":"", // "name":"dogecoin", // "withdrawMin":10, // "minLimit":0.0001, // "minDeposit":10, // "feeAssetCode":"doge", // "withdrawFee":"10", // "type":1, // "coin":"doge", // "network":"dogecoin" // } // ], // "freezeAmt":"0", // "coin":"doge" // }, ... // ] // const timestamp = this.safeInteger (response, 'ts'); const result = { 'info': response, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), }; const data = this.safeValue (response, 'data'); // from privatePostUserInfo const toBtc = this.safeValue (data, 'toBtc'); if (toBtc !== undefined) { const used = this.safeValue (data, 'freeze', {}); const free = this.safeValue (data, 'free', {}); const currencies = Object.keys (free); for (let i = 0; i < currencies.length; i++) { const currencyId = currencies[i]; const code = this.safeCurrencyCode (currencyId); const account = this.account (); account['used'] = this.safeString (used, currencyId); account['free'] = this.safeString (free, currencyId); result[code] = account; } return this.safeBalance (result); } // from privatePostSupplementUserInfoAccount const balances = this.safeValue (data, 'balances'); if (balances !== undefined) { for (let i = 0; i < balances.length; i++) { const item = balances[i]; const currencyId = this.safeString (item, 'asset'); const code = this.safeCurrencyCode (currencyId); const account = this.account (); account['free'] = this.safeString (item, 'free'); account['used'] = this.safeString (item, 'locked'); result[code] = account; } return this.safeBalance (result); } // from privatePostSupplementUserInfo const isArray = Array.isArray (data); if (isArray === true) { for (let i = 0; i < data.length; i++) { const item = data[i]; const currencyId = this.safeString (item, 'coin'); const code = this.safeCurrencyCode (currencyId); const account = this.account (); account['free'] = this.safeString (item, 'usableAmt'); account['used'] = this.safeString (item, 'freezeAmt'); result[code] = account; } return this.safeBalance (result); } } async fetchBalance (params = {}) { /** * @method * @name lbank2#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @param {object} params extra parameters specific to the lbank2 api endpoint * @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure} */ await this.loadMarkets (); let method = this.safeString (params, 'method'); if (method === undefined) { const options = this.safeValue (this.options, 'fetchBalance', {}); method = this.safeString (options, 'method', 'privatePostSupplementUserInfo'); } const response = await this[method] (); // // { // "result": "true", // "data": [ // { // "usableAmt": "14.36", // "assetAmt": "14.36", // "networkList": [ // { // "isDefault": false, // "withdrawFeeRate": "", // "name": "erc20", // "withdrawMin": 30, // "minLimit": 0.0001, // "minDeposit": 20, // "feeAssetCode": "usdt", // "withdrawFee": "30", // "type": 1, // "coin": "usdt", // "network": "eth" // }, // ... // ], // "freezeAmt": "0", // "coin": "ada" // } // ], // "code": 0 // } // return this.parseBalance (response); } parseTradingFee (fee, market = undefined) { // // { // "symbol":"skt_usdt", // "makerCommission":"0.10", // "takerCommission":"0.10" // } // const marketId = this.safeString (fee, 'symbol'); const symbol = this.safeSymbol (marketId); return { 'info': fee, 'symbol': symbol, 'maker': this.safeNumber (fee, 'makerCommission'), 'taker': this.safeNumber (fee, 'takerCommission'), }; } async fetchTradingFee (symbol, params = {}) { /** * @method * @name lbank2#fetchTradingFee * @description fetch the trading fees for a market * @param {string} symbol unified market symbol * @param {object} params extra parameters specific to the lbank2 api endpoint * @returns {object} a [fee structure]{@link https://docs.ccxt.com/en/latest/manual.html#fee-structure} */ const market = this.market (symbol); const result = await this.fetchTradingFees (this.extend (params, { 'category': market['id'] })); return result; } async fetchTradingFees (params = {}) { /** * @method * @name lbank2#fetchTradingFees * @description fetch the trading fees for multiple markets * @param {object} params extra parameters specific to the lbank2 api endpoint * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/en/latest/manual.html#fee-structure} indexed by market symbols */ await this.loadMarkets (); const request = {}; const response = await this.privatePostSupplementCustomerTradeFee (this.extend (request, params)); const fees = this.safeValue (response, 'data', []); const result = {}; for (let i = 0; i < fees.length; i++) { const fee = this.parseTradingFee (fees[i]); const symbol = fee['symbol']; result[symbol] = fee; } return result; } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { /** * @method * @name lbank2#createOrder * @description create a trade order * @param {string} symbol unified symbol of the market to create an order in * @param {string} type 'market' or 'limit' * @param {string} side 'buy' or 'sell' * @param {float} amount how much of currency you want to trade in units of base currency * @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders * @param {object} params extra parameters specific to the lbank2 api endpoint * @returns {object} an [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure} */ await this.loadMarkets (); const market = this.market (symbol); const clientOrderId = this.safeString2 (params, 'custom_id', 'clientOrderId'); const postOnly = this.safeValue (params, 'postOnly', false); const timeInForce = this.safeStringUpper (params, 'timeInForce'); params = this.omit (params, [ 'custom_id', 'clientOrderId', 'timeInForce', 'postOnly' ]); const request = { 'symbol': market['id'], }; const ioc = (timeInForce === 'IOC'); const fok = (timeInForce === 'FOK'); const maker = (postOnly || (timeInForce === 'PO')); if ((type === 'market') && (ioc || fok || maker)) { throw new InvalidOrder (this.id + ' createOrder () does not allow market FOK, IOC, or postOnly orders. Only limit IOC, FOK, and postOnly orders are allowed'); } if (type === 'limit') { request['type'] = side; request['price'] = this.priceToPrecision (symbol, price); request['amount'] = this.amountToPrecision (symbol, amount); if (ioc) { request['type'] = side + '_' + 'ioc'; } else if (fok) { request['type'] = side + '_' + 'fok'; } else if (maker) { request['type'] = side + '_' + 'maker'; } } else if (type === 'market') { if (side === 'sell') { request['type'] = side + '_' + 'market'; request['amount'] = this.amountToPrecision (symbol, amount); } else if (side === 'buy') { request['type'] = side + '_' + 'market'; if (this.options['createMarketBuyOrderRequiresPrice']) { if (price === undefined) { throw new InvalidOrder (this.id + " createOrder () requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply the price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false to supply the cost in the amount argument (the exchange-specific behaviour)"); } else { const amountString = this.numberToString (amount); const priceString = this.numberToString (price); const quoteAmount = Precise.stringMul (amountString, priceString); const cost = this.parseNumber (quoteAmount); request['price'] = this.priceToPrecision (symbol, cost); } } else { request['price'] = amount; } } } if (clientOrderId !== undefined) { request['custom_id'] = clientOrderId; } let method = undefined; method = this.safeString (params, 'method'); params = this.omit (params, 'method'); if (method === undefined) { const options = this.safeValue (this.options, 'createOrder', {}); method = this.safeString (options, 'method', 'privatePostSupplementCreateOrder'); } const response = await this[method] (this.extend (request, params)); // // { // "result":true, // "data":{ // "symbol":"doge_usdt", // "order_id":"0cf8a3de-4597-4296-af45-be7abaa06b07" // }, // "error_code":0, // "ts":1648162321043 // } // const result = this.safeValue (response, 'data', {}); return { 'id': this.safeString (result, 'order_id'), 'info': result, }; } parseOrderStatus (status) { const statuses = { '-1': 'canceled', // canceled '0': 'open', // not traded '1': 'open', // partial deal '2': 'closed', // complete deal '3': 'canceled', // filled partially and cancelled '4': 'closed', // disposal processing }; return this.safeString (statuses, status, status); } parseOrder (order, market = undefined) { // // fetchOrderSupplement (private) // // { // "cummulativeQuoteQty":0, // "symbol":"doge_usdt", // "executedQty":0, // "orderId":"53d2d53e-70fb-4398-b722-f48571a5f61e", // "origQty":1E+2, // "price":0.05, // "clientOrderId":null, // "origQuoteOrderQty":5, // "updateTime":1648163406000, // "time":1648163139387, // "type":"buy_maker", // "status":-1 // } // // // fetchOrderDefault (private) // // { // "symbol":"shib_usdt", // "amount":1, // "create_time":1649367863356, // "price":0.0000246103, // "avg_price":0.00002466180000000104, // "type":"buy_market", // "order_id":"abe8b92d-86d9-4d6d-b71e-d14f5fb53ddf", // "custom_id": "007", // field only present if user creates it at order time // "deal_amount":40548.54065802, // "status":2 // } // // fetchOpenOrders (private) // // { // "cummulativeQuoteQty":0, // "symbol":"doge_usdt", // "executedQty":0, // "orderId":"73878edf-008d-4e4c-8041-df1f1b2cd8bb", // "origQty":100, // "price":0.05, // "origQuoteOrderQty":5, // "updateTime":1648501762000, // "time":1648501762353, // "type":"buy", // "status":0 // } // // fetchOrders (private) // // { // "cummulativeQuoteQty":0, // "symbol":"doge_usdt", // "executedQty":0, // "orderId":"2cadc7cc-b5f6-486b-a5b4-d6ac49a9c186", // "origQty":100, // "price":0.05, // "origQuoteOrderQty":5, // "updateTime":1648501384000, // "time":1648501363889, // "type":"buy", // "status":-1 // } // const id = this.safeString2 (order, 'orderId', 'order_id'); const clientOrderId = this.safeString2 (order, 'clientOrderId', 'custom_id'); const timestamp = this.safeInteger2 (order, 'time', 'create_time'); const rawStatus = this.safeString (order, 'status'); const marketId = this.safeString (order, 'symbol'); market = this.safeMarket (marketId, market); let timeInForce = undefined; let postOnly = false; let type = 'limit'; const rawType = this.safeString (order, 'type'); // buy, sell, buy_market, sell_market, buy_maker,sell_maker,buy_ioc,sell_ioc, buy_fok, sell_fok const parts = rawType.split ('_'); const side = this.safeString (parts, 0); const typePart = this.safeString (parts, 1); // market, maker, ioc, fok or undefined (limit) if (typePart === 'market') { type = 'market'; } if (typePart === 'maker') { postOnly = true; timeInForce = 'PO'; } if (typePart === 'ioc') { timeInForce = 'IOC'; } if (typePart === 'fok') { timeInForce = 'FOK'; } const price = this.safeString (order, 'price'); const costString = this.safeString (order, 'cummulativeQuoteQty'); let amountString = undefined; if (rawType !== 'buy_market') { amountString = this.safeString2 (order, 'origQty', 'amount'); } const filledString = this.safeString2 (order, 'executedQty', 'deal_amount'); return this.safeOrder ({ 'id': id, 'clientOrderId': clientOrderId, 'datetime': this.iso8601 (timestamp), 'timestamp': timestamp, 'lastTradeTimestamp': undefined, 'status': this.parseOrderStatus (rawStatus), 'symbol': market['symbol'], 'type': type, 'timeInForce': timeInForce, 'postOnly': postOnly, 'side': side, 'price': price, 'stopPrice': undefined, 'cost': costString, 'amount': amountString, 'filled': filledString, 'remaining': undefined, 'trades': undefined, 'fee': undefined, 'info': order, 'average': undefined, }, market); } async fetchOrder (id, symbol = undefined, params = {}) { /** * @method * @name lbank2#fetchOrder * @description fetches information on an order made by the user * @param {string|undefined} symbol unified symbol of the market the order was made in * @param {object} params extra parameters specific to the lbank2 api endpoint * @returns {object} An [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure} */ await this.loadMarkets (); let method = this.safeString (params, 'method'); if (method === undefined) { const options = this.safeValue (this.options, 'fetchOrder', {}); method = this.safeString (options, 'method', 'fetchOrderSupplement'); } const result = await this[method] (id, symbol, params); return result; } async fetchOrderSupplement (id, symbol = undefined, params = {}) { await this.loadMarkets (); if (symbol === undefined) { throw new ArgumentsRequired (this.id + ' fetchOrder () requires a symbol argument'); } const market = this.market (symbol); const request = { 'symbol': market['id'], 'orderId': id, }; const response = await this.privatePostSupplementOrdersInfo (this.extend (request, params)); // // { // "result":true, // "data":{ // "cummulativeQuoteQty":0, // "symbol":"doge_usdt", //