UNPKG

sfccxt

Version:

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

1,076 lines (1,051 loc) 74.6 kB
'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { ExchangeError, AuthenticationError, ArgumentsRequired, InvalidNonce, BadRequest, ExchangeNotAvailable, PermissionDenied, AccountSuspended, RateLimitExceeded, InsufficientFunds, BadSymbol, InvalidOrder } = require ('./base/errors'); const { TICK_SIZE } = require ('./base/functions/number'); // --------------------------------------------------------------------------- module.exports = class latoken extends Exchange { describe () { return this.deepExtend (super.describe (), { 'id': 'latoken', 'name': 'Latoken', 'countries': [ 'KY' ], // Cayman Islands 'version': 'v2', 'rateLimit': 1000, 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': undefined, // has but unimplemented 'future': undefined, 'option': false, 'cancelAllOrders': true, 'cancelOrder': true, 'createOrder': true, 'fetchBalance': true, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchBorrowRatesPerSymbol': false, 'fetchCurrencies': true, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMyTrades': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchPositionMode': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': true, 'fetchTradingFees': false, 'fetchTransactions': true, 'fetchTransfer': false, 'fetchTransfers': true, 'transfer': true, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/61511972-24c39f00-aa01-11e9-9f7c-471f1d6e5214.jpg', 'api': { 'rest': 'https://api.latoken.com', }, 'www': 'https://latoken.com', 'doc': [ 'https://api.latoken.com', ], 'fees': 'https://latoken.com/fees', 'referral': 'https://latoken.com/invite?r=mvgp2djk', }, 'api': { 'public': { 'get': { 'book/{currency}/{quote}': 1, 'chart/week': 1, 'chart/week/{currency}/{quote}': 1, 'currency': 1, 'currency/available': 1, 'currency/quotes': 1, 'currency/{currency}': 1, 'pair': 1, 'pair/available': 1, 'ticker': 1, 'ticker/{base}/{quote}': 1, 'time': 1, 'trade/history/{currency}/{quote}': 1, 'trade/fee/{currency}/{quote}': 1, 'trade/feeLevels': 1, 'transaction/bindings': 1, }, }, 'private': { 'get': { 'auth/account': 1, 'auth/account/currency/{currency}/{type}': 1, 'auth/order': 1, 'auth/order/getOrder/{id}': 1, 'auth/order/pair/{currency}/{quote}': 1, 'auth/order/pair/{currency}/{quote}/active': 1, 'auth/stopOrder': 1, 'auth/stopOrder/getOrder/{id}': 1, 'auth/stopOrder/pair/{currency}/{quote}': 1, 'auth/stopOrder/pair/{currency}/{quote}/active': 1, 'auth/trade': 1, 'auth/trade/pair/{currency}/{quote}': 1, 'auth/trade/fee/{currency}/{quote}': 1, 'auth/transaction': 1, 'auth/transaction/bindings': 1, 'auth/transaction/bindings/{currency}': 1, 'auth/transaction/{id}': 1, 'auth/transfer': 1, }, 'post': { 'auth/order/cancel': 1, 'auth/order/cancelAll': 1, 'auth/order/cancelAll/{currency}/{quote}': 1, 'auth/order/place': 1, 'auth/spot/deposit': 1, 'auth/spot/withdraw': 1, 'auth/stopOrder/cancel': 1, 'auth/stopOrder/cancelAll': 1, 'auth/stopOrder/cancelAll/{currency}/{quote}': 1, 'auth/stopOrder/place': 1, 'auth/transaction/depositAddress': 1, 'auth/transaction/withdraw': 1, 'auth/transaction/withdraw/cancel': 1, 'auth/transaction/withdraw/confirm': 1, 'auth/transaction/withdraw/resendCode': 1, 'auth/transfer/email': 1, 'auth/transfer/id': 1, 'auth/transfer/phone': 1, }, }, }, 'precisionMode': TICK_SIZE, 'fees': { 'trading': { 'feeSide': 'get', 'tierBased': false, 'percentage': true, 'maker': this.parseNumber ('0.0049'), 'taker': this.parseNumber ('0.0049'), }, }, 'commonCurrencies': { 'BUX': 'Buxcoin', 'CBT': 'Community Business Token', 'CTC': 'CyberTronchain', 'DMD': 'Diamond Coin', 'FREN': 'Frenchie', 'GDX': 'GoldenX', 'GEC': 'Geco One', 'GEM': 'NFTmall', 'GMT': 'GMT Token', 'IMC': 'IMCoin', 'MT': 'Monarch', 'TPAY': 'Tetra Pay', 'TRADE': 'Smart Trade Coin', 'TSL': 'Treasure SL', 'UNO': 'Unobtanium', 'WAR': 'Warrior Token', }, 'exceptions': { 'exact': { 'INTERNAL_ERROR': ExchangeError, // internal server error. You can contact our support to solve this problem. {"message":"Internal Server Error","error":"INTERNAL_ERROR","status":"FAILURE"} 'SERVICE_UNAVAILABLE': ExchangeNotAvailable, // requested information currently not available. You can contact our support to solve this problem or retry later. 'NOT_AUTHORIZED': AuthenticationError, // user's query not authorized. Check if you are logged in. 'FORBIDDEN': PermissionDenied, // you don't have enough access rights. 'BAD_REQUEST': BadRequest, // some bad request, for example bad fields values or something else. Read response message for more information. 'NOT_FOUND': ExchangeError, // entity not found. Read message for more information. 'ACCESS_DENIED': PermissionDenied, // access is denied. Probably you don't have enough access rights, you contact our support. 'REQUEST_REJECTED': ExchangeError, // user's request rejected for some reasons. Check error message. 'HTTP_MEDIA_TYPE_NOT_SUPPORTED': BadRequest, // http media type not supported. 'MEDIA_TYPE_NOT_ACCEPTABLE': BadRequest, // media type not acceptable 'METHOD_ARGUMENT_NOT_VALID': BadRequest, // one of method argument is invalid. Check argument types and error message for more information. 'VALIDATION_ERROR': BadRequest, // check errors field to get reasons. 'ACCOUNT_EXPIRED': AccountSuspended, // restore your account or create a new one. 'BAD_CREDENTIALS': AuthenticationError, // invalid username or password. 'COOKIE_THEFT': AuthenticationError, // cookie has been stolen. Let's try reset your cookies. 'CREDENTIALS_EXPIRED': AccountSuspended, // credentials expired. 'INSUFFICIENT_AUTHENTICATION': AuthenticationError, // for example, 2FA required. 'UNKNOWN_LOCATION': AuthenticationError, // user logged from unusual location, email confirmation required. 'TOO_MANY_REQUESTS': RateLimitExceeded, // too many requests at the time. A response header X-Rate-Limit-Remaining indicates the number of allowed request per a period. 'INSUFFICIENT_FUNDS': InsufficientFunds, // {"message":"not enough balance on the spot account for currency (USDT), need (20.000)","error":"INSUFFICIENT_FUNDS","status":"FAILURE"} 'ORDER_VALIDATION': InvalidOrder, // {"message":"Quantity (0) is not positive","error":"ORDER_VALIDATION","status":"FAILURE"} 'BAD_TICKS': InvalidOrder, // {"status":"FAILURE","message":"Quantity (1.4) does not match quantity tick (10)","error":"BAD_TICKS","errors":null,"result":false} }, 'broad': { 'invalid API key, signature or digest': AuthenticationError, // {"result":false,"message":"invalid API key, signature or digest","error":"BAD_REQUEST","status":"FAILURE"} 'The API key was revoked': AuthenticationError, // {"result":false,"message":"The API key was revoked","error":"BAD_REQUEST","status":"FAILURE"} 'request expired or bad': InvalidNonce, // {"result":false,"message":"request expired or bad <timeAlive>/<timestamp> format","error":"BAD_REQUEST","status":"FAILURE"} 'For input string': BadRequest, // {"result":false,"message":"Internal error","error":"For input string: \"NaN\"","status":"FAILURE"} 'Unable to resolve currency by tag': BadSymbol, // {"message":"Unable to resolve currency by tag (undefined)","error":"NOT_FOUND","status":"FAILURE"} "Can't find currency with tag": BadSymbol, // {"status":"FAILURE","message":"Can't find currency with tag = undefined","error":"NOT_FOUND","errors":null,"result":false} 'Unable to place order because pair is in inactive state': BadSymbol, // {"message":"Unable to place order because pair is in inactive state (PAIR_STATUS_INACTIVE)","error":"ORDER_VALIDATION","status":"FAILURE"} 'API keys are not available for FROZEN user': AccountSuspended, // {"result":false,"message":"API keys are not available for FROZEN user","error":"BAD_REQUEST","status":"FAILURE"} }, }, 'options': { 'defaultType': 'spot', 'types': { 'wallet': 'ACCOUNT_TYPE_WALLET', 'spot': 'ACCOUNT_TYPE_SPOT', }, 'accounts': { 'ACCOUNT_TYPE_WALLET': 'wallet', 'ACCOUNT_TYPE_SPOT': 'spot', }, 'fetchTradingFee': { 'method': 'fetchPrivateTradingFee', // or 'fetchPublicTradingFee' }, }, }); } nonce () { return this.milliseconds () - this.options['timeDifference']; } async fetchTime (params = {}) { /** * @method * @name latoken#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @param {object} params extra parameters specific to the latoken api endpoint * @returns {int} the current integer timestamp in milliseconds from the exchange server */ const response = await this.publicGetTime (params); // // { // "serverTime": 1570615577321 // } // return this.safeInteger (response, 'serverTime'); } async fetchMarkets (params = {}) { /** * @method * @name latoken#fetchMarkets * @description retrieves data on all markets for latoken * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ const currencies = await this.fetchCurrenciesFromCache (params); // // [ // { // "id":"1a075819-9e0b-48fc-8784-4dab1d186d6d", // "status":"CURRENCY_STATUS_ACTIVE", // "type":"CURRENCY_TYPE_ALTERNATIVE", // CURRENCY_TYPE_CRYPTO, CURRENCY_TYPE_IEO // "name":"MyCryptoBank", // "tag":"MCB", // "description":"", // "logo":"", // "decimals":18, // "created":1572912000000, // "tier":1, // "assetClass":"ASSET_CLASS_UNKNOWN", // "minTransferAmount":0 // }, // { // "id":"db02758e-2507-46a5-a805-7bc60355b3eb", // "status":"CURRENCY_STATUS_ACTIVE", // "type":"CURRENCY_TYPE_FUTURES_CONTRACT", // "name":"BTC USDT Futures Contract", // "tag":"BTCUSDT", // "description":"", // "logo":"", // "decimals":8, // "created":1589459984395, // "tier":1, // "assetClass":"ASSET_CLASS_UNKNOWN", // "minTransferAmount":0 // }, // ] // const response = await this.publicGetPair (params); // // [ // { // "id":"dba4289b-6b46-4d94-bf55-49eec9a163ad", // "status":"PAIR_STATUS_ACTIVE", // CURRENCY_STATUS_INACTIVE // "baseCurrency":"fb9b53d6-bbf6-472f-b6ba-73cc0d606c9b", // "quoteCurrency":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f", // "priceTick":"0.000000100000000000", // "priceDecimals":7, // "quantityTick":"0.010000000", // "quantityDecimals":2, // "costDisplayDecimals":7, // "created":1572957210501, // "minOrderQuantity":"0", // "maxOrderCostUsd":"999999999999999999", // "minOrderCostUsd":"0", // "externalSymbol":"" // } // ] // if (this.safeValue (this.options, 'adjustForTimeDifference', true)) { await this.loadTimeDifference (); } const currenciesById = this.indexBy (currencies, 'id'); const result = []; for (let i = 0; i < response.length; i++) { const market = response[i]; const id = this.safeString (market, 'id'); // the exchange shows them inverted const baseId = this.safeString (market, 'baseCurrency'); const quoteId = this.safeString (market, 'quoteCurrency'); const baseCurrency = this.safeValue (currenciesById, baseId); const quoteCurrency = this.safeValue (currenciesById, quoteId); if (baseCurrency !== undefined && quoteCurrency !== undefined) { const base = this.safeCurrencyCode (this.safeString (baseCurrency, 'tag')); const quote = this.safeCurrencyCode (this.safeString (quoteCurrency, 'tag')); const lowercaseQuote = quote.toLowerCase (); const capitalizedQuote = this.capitalize (lowercaseQuote); const status = this.safeString (market, 'status'); result.push ({ 'id': id, 'symbol': base + '/' + quote, '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': (status === 'PAIR_STATUS_ACTIVE'), // assuming true 'contract': false, 'linear': undefined, 'inverse': undefined, 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.safeNumber (market, 'quantityTick'), 'price': this.safeNumber (market, 'priceTick'), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber (market, 'minOrderQuantity'), 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': this.safeNumber (market, 'minOrderCost' + capitalizedQuote), 'max': this.safeNumber (market, 'maxOrderCost' + capitalizedQuote), }, }, 'info': market, }); } } return result; } async fetchCurrenciesFromCache (params = {}) { // this method is now redundant // currencies are now fetched before markets const options = this.safeValue (this.options, 'fetchCurrencies', {}); const timestamp = this.safeInteger (options, 'timestamp'); const expires = this.safeInteger (options, 'expires', 1000); const now = this.milliseconds (); if ((timestamp === undefined) || ((now - timestamp) > expires)) { const response = await this.publicGetCurrency (params); this.options['fetchCurrencies'] = this.extend (options, { 'response': response, 'timestamp': now, }); } return this.safeValue (this.options['fetchCurrencies'], 'response'); } async fetchCurrencies (params = {}) { /** * @method * @name latoken#fetchCurrencies * @description fetches all available currencies on an exchange * @param {object} params extra parameters specific to the latoken api endpoint * @returns {object} an associative dictionary of currencies */ const response = await this.fetchCurrenciesFromCache (params); // // [ // { // "id":"1a075819-9e0b-48fc-8784-4dab1d186d6d", // "status":"CURRENCY_STATUS_ACTIVE", // "type":"CURRENCY_TYPE_ALTERNATIVE", // CURRENCY_TYPE_CRYPTO, CURRENCY_TYPE_IEO // "name":"MyCryptoBank", // "tag":"MCB", // "description":"", // "logo":"", // "decimals":18, // "created":1572912000000, // "tier":1, // "assetClass":"ASSET_CLASS_UNKNOWN", // "minTransferAmount":0 // }, // { // "id":"db02758e-2507-46a5-a805-7bc60355b3eb", // "status":"CURRENCY_STATUS_ACTIVE", // "type":"CURRENCY_TYPE_FUTURES_CONTRACT", // "name":"BTC USDT Futures Contract", // "tag":"BTCUSDT", // "description":"", // "logo":"", // "decimals":8, // "created":1589459984395, // "tier":1, // "assetClass":"ASSET_CLASS_UNKNOWN", // "minTransferAmount":0 // }, // ] // const result = {}; for (let i = 0; i < response.length; i++) { const currency = response[i]; const id = this.safeString (currency, 'id'); const tag = this.safeString (currency, 'tag'); const code = this.safeCurrencyCode (tag); const fee = this.safeNumber (currency, 'fee'); const currencyType = this.safeString (currency, 'type'); const parts = currencyType.split ('_'); const numParts = parts.length; const lastPart = this.safeValue (parts, numParts - 1); const type = lastPart.toLowerCase (); const status = this.safeString (currency, 'status'); const active = (status === 'CURRENCY_STATUS_ACTIVE'); const name = this.safeString (currency, 'name'); result[code] = { 'id': id, 'code': code, 'info': currency, 'name': name, 'type': type, 'active': active, 'deposit': undefined, 'withdraw': undefined, 'fee': fee, 'precision': this.parseNumber (this.parsePrecision (this.safeString (currency, 'decimals'))), 'limits': { 'amount': { 'min': this.safeNumber (currency, 'minTransferAmount'), 'max': undefined, }, 'withdraw': { 'min': undefined, 'max': undefined, }, }, }; } return result; } async fetchBalance (params = {}) { /** * @method * @name latoken#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 latoken api endpoint * @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure} */ await this.loadMarkets (); const response = await this.privateGetAuthAccount (params); // // [ // { // id: "e5852e02-8711-431c-9749-a6f5503c6dbe", // status: "ACCOUNT_STATUS_ACTIVE", // type: "ACCOUNT_TYPE_WALLET", // timestamp: "1635920106506", // currency: "0c3a106d-bde3-4c13-a26e-3fd2394529e5", // available: "100.000000", // blocked: "0.000000" // }, // { // id: "369df204-acbc-467e-a25e-b16e3cc09cf6", // status: "ACCOUNT_STATUS_ACTIVE", // type: "ACCOUNT_TYPE_SPOT", // timestamp: "1635920106504", // currency: "0c3a106d-bde3-4c13-a26e-3fd2394529e5", // available: "100.000000", // blocked: "0.000000" // } // ] // const result = { 'info': response, 'timestamp': undefined, 'datetime': undefined, }; let maxTimestamp = undefined; const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType', 'spot'); const type = this.safeString (params, 'type', defaultType); const types = this.safeValue (this.options, 'types', {}); const accountType = this.safeString (types, type, type); const balancesByType = this.groupBy (response, 'type'); const balances = this.safeValue (balancesByType, accountType, []); for (let i = 0; i < balances.length; i++) { const balance = balances[i]; const currencyId = this.safeString (balance, 'currency'); const timestamp = this.safeInteger (balance, 'timestamp'); if (timestamp !== undefined) { if (maxTimestamp === undefined) { maxTimestamp = timestamp; } else { maxTimestamp = Math.max (maxTimestamp, timestamp); } } const code = this.safeCurrencyCode (currencyId); const account = this.account (); account['free'] = this.safeString (balance, 'available'); account['used'] = this.safeString (balance, 'blocked'); result[code] = account; } result['timestamp'] = maxTimestamp; result['datetime'] = this.iso8601 (maxTimestamp); return this.safeBalance (result); } async fetchOrderBook (symbol, limit = undefined, params = {}) { /** * @method * @name latoken#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 latoken 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); const request = { 'currency': market['baseId'], 'quote': market['quoteId'], }; if (limit !== undefined) { request['limit'] = limit; // max 1000 } const response = await this.publicGetBookCurrencyQuote (this.extend (request, params)); // // { // "ask":[ // {"price":"4428.76","quantity":"0.08136","cost":"360.3239136","accumulated":"360.3239136"}, // {"price":"4429.77","quantity":"1.11786","cost":"4951.8626922","accumulated":"5312.1866058"}, // {"price":"4430.94","quantity":"1.78418","cost":"7905.5945292","accumulated":"13217.781135"}, // ], // "bid":[ // {"price":"4428.43","quantity":"0.13675","cost":"605.5878025","accumulated":"605.5878025"}, // {"price":"4428.19","quantity":"0.03619","cost":"160.2561961","accumulated":"765.8439986"}, // {"price":"4428.15","quantity":"0.02926","cost":"129.567669","accumulated":"895.4116676"}, // ], // "totalAsk":"53.14814", // "totalBid":"112216.9029791" // } // return this.parseOrderBook (response, symbol, undefined, 'bid', 'ask', 'price', 'quantity'); } parseTicker (ticker, market = undefined) { // // { // "symbol":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f/0c3a106d-bde3-4c13-a26e-3fd2394529e5", // "baseCurrency":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f", // "quoteCurrency":"0c3a106d-bde3-4c13-a26e-3fd2394529e5", // "volume24h":"76411867.852585600000000000", // "volume7d":"637809926.759451100000000000", // "change24h":"2.5300", // "change7d":"5.1300", // "lastPrice":"4426.9" // } // const marketId = this.safeString (ticker, 'symbol'); const symbol = this.safeSymbol (marketId, market); const last = this.safeString (ticker, 'lastPrice'); const change = this.safeString (ticker, 'change24h'); const timestamp = this.nonce (); return this.safeTicker ({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'low': this.safeString (ticker, 'low'), 'high': this.safeString (ticker, 'high'), 'bid': undefined, 'bidVolume': undefined, 'ask': undefined, 'askVolume': undefined, 'vwap': undefined, 'open': undefined, 'close': last, 'last': last, 'previousClose': undefined, 'change': change, 'percentage': undefined, 'average': undefined, 'baseVolume': undefined, 'quoteVolume': this.safeString (ticker, 'volume24h'), 'info': ticker, }, market); } async fetchTicker (symbol, params = {}) { /** * @method * @name latoken#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 latoken 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 = { 'base': market['baseId'], 'quote': market['quoteId'], }; const response = await this.publicGetTickerBaseQuote (this.extend (request, params)); // // { // "symbol":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f/0c3a106d-bde3-4c13-a26e-3fd2394529e5", // "baseCurrency":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f", // "quoteCurrency":"0c3a106d-bde3-4c13-a26e-3fd2394529e5", // "volume24h":"76411867.852585600000000000", // "volume7d":"637809926.759451100000000000", // "change24h":"2.5300", // "change7d":"5.1300", // "lastPrice":"4426.9" // } // return this.parseTicker (response, market); } async fetchTickers (symbols = undefined, params = {}) { /** * @method * @name latoken#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 latoken api endpoint * @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ await this.loadMarkets (); const response = await this.publicGetTicker (params); // // [ // { // "symbol":"DASH/BTC", // "baseCurrency":"ed75c263-4ab9-494b-8426-031dab1c7cc1", // "quoteCurrency":"92151d82-df98-4d88-9a4d-284fa9eca49f", // "volume24h":"1.977753278000000000", // "volume7d":"18.964342670000000000", // "change24h":"-1.4800", // "change7d":"-5.5200", // "lastPrice":"0.003066" // }, // ] // return this.parseTickers (response, symbols); } parseTrade (trade, market = undefined) { // // fetchTrades (public) // // { // "id":"c152f814-8eeb-44f0-8f3f-e5c568f2ffcf", // "isMakerBuyer":false, // "baseCurrency":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f", // "quoteCurrency":"0c3a106d-bde3-4c13-a26e-3fd2394529e5", // "price":"4435.56", // "quantity":"0.32534", // "cost":"1443.0650904", // "timestamp":1635854642725, // "makerBuyer":false // } // // fetchMyTrades (private) // // { // "id":"02e02533-b4bf-4ba9-9271-24e2108dfbf7", // "isMakerBuyer":false, // "direction":"TRADE_DIRECTION_BUY", // "baseCurrency":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f", // "quoteCurrency":"0c3a106d-bde3-4c13-a26e-3fd2394529e5", // "price":"4564.32", // "quantity":"0.01000", // "cost":"45.6432", // "fee":"0.223651680000000000", // "order":"c9cac6a0-484c-4892-88e7-ad51b39f2ce1", // "timestamp":1635921580399, // "makerBuyer":false // } // const type = undefined; const timestamp = this.safeInteger (trade, 'timestamp'); const priceString = this.safeString (trade, 'price'); const amountString = this.safeString (trade, 'quantity'); const costString = this.safeString (trade, 'cost'); const makerBuyer = this.safeValue (trade, 'makerBuyer'); let side = this.safeString (trade, 'direction'); if (side === undefined) { side = makerBuyer ? 'sell' : 'buy'; } else { if (side === 'TRADE_DIRECTION_BUY') { side = 'buy'; } else if (side === 'TRADE_DIRECTION_SELL') { side = 'sell'; } } const isBuy = (side === 'buy'); const takerOrMaker = (makerBuyer && isBuy) ? 'maker' : 'taker'; const baseId = this.safeString (trade, 'baseCurrency'); const quoteId = this.safeString (trade, 'quoteCurrency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; if (symbol in this.markets) { market = this.market (symbol); } const id = this.safeString (trade, 'id'); const orderId = this.safeString (trade, 'order'); const feeCost = this.safeString (trade, 'fee'); let fee = undefined; if (feeCost !== undefined) { fee = { 'cost': feeCost, 'currency': quote, }; } return this.safeTrade ({ 'info': trade, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'symbol': symbol, 'id': id, 'order': orderId, 'type': type, 'takerOrMaker': takerOrMaker, 'side': side, 'price': priceString, 'amount': amountString, 'cost': costString, 'fee': fee, }, market); } async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name latoken#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 latoken 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 = { 'currency': market['baseId'], 'quote': market['quoteId'], // 'from': since.toString (), // milliseconds // 'limit': limit, // default 100, max 1000 }; if (limit !== undefined) { request['limit'] = limit; // default 100, max 1000 } const response = await this.publicGetTradeHistoryCurrencyQuote (this.extend (request, params)); // // [ // {"id":"c152f814-8eeb-44f0-8f3f-e5c568f2ffcf","isMakerBuyer":false,"baseCurrency":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f","quoteCurrency":"0c3a106d-bde3-4c13-a26e-3fd2394529e5","price":"4435.56","quantity":"0.32534","cost":"1443.0650904","timestamp":1635854642725,"makerBuyer":false}, // {"id":"cfecbefb-3d11-43d7-b9d4-fa16211aad8a","isMakerBuyer":false,"baseCurrency":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f","quoteCurrency":"0c3a106d-bde3-4c13-a26e-3fd2394529e5","price":"4435.13","quantity":"0.26540","cost":"1177.083502","timestamp":1635854641114,"makerBuyer":false}, // {"id":"f43d3ec8-db94-49f3-b534-91dbc2779296","isMakerBuyer":true,"baseCurrency":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f","quoteCurrency":"0c3a106d-bde3-4c13-a26e-3fd2394529e5","price":"4435.00","quantity":"0.41738","cost":"1851.0803","timestamp":1635854640323,"makerBuyer":true}, // ] // return this.parseTrades (response, market, since, limit); } async fetchTradingFee (symbol, params = {}) { /** * @method * @name latoken#fetchTradingFee * @description fetch the trading fees for a market * @param {string} symbol unified market symbol * @param {object} params extra parameters specific to the latoken api endpoint * @returns {object} a [fee structure]{@link https://docs.ccxt.com/en/latest/manual.html#fee-structure} */ let method = this.safeString (params, 'method'); params = this.omit (params, 'method'); if (method === undefined) { const options = this.safeValue (this.options, 'fetchTradingFee', {}); method = this.safeString (options, 'method', 'fetchPrivateTradingFee'); } return await this[method] (symbol, params); } async fetchPublicTradingFee (symbol, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'currency': market['baseId'], 'quote': market['quoteId'], }; const response = await this.publicGetTradeFeeCurrencyQuote (this.extend (request, params)); // // { // makerFee: '0.004900000000000000', // takerFee: '0.004900000000000000', // type: 'FEE_SCHEME_TYPE_PERCENT_QUOTE', // take: 'FEE_SCHEME_TAKE_PROPORTION' // } // return { 'info': response, 'symbol': market['symbol'], 'maker': this.safeNumber (response, 'makerFee'), 'taker': this.safeNumber (response, 'takerFee'), }; } async fetchPrivateTradingFee (symbol, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'currency': market['baseId'], 'quote': market['quoteId'], }; const response = await this.privateGetAuthTradeFeeCurrencyQuote (this.extend (request, params)); // // { // makerFee: '0.004900000000000000', // takerFee: '0.004900000000000000', // type: 'FEE_SCHEME_TYPE_PERCENT_QUOTE', // take: 'FEE_SCHEME_TAKE_PROPORTION' // } // return { 'info': response, 'symbol': market['symbol'], 'maker': this.safeNumber (response, 'makerFee'), 'taker': this.safeNumber (response, 'takerFee'), }; } async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name latoken#fetchMyTrades * @description fetch all trades made by the user * @param {string|undefined} symbol unified market symbol * @param {int|undefined} since the earliest time in ms to fetch trades for * @param {int|undefined} limit the maximum number of trades structures to retrieve * @param {object} params extra parameters specific to the latoken api endpoint * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html#trade-structure} */ await this.loadMarkets (); const request = { // 'currency': market['baseId'], // 'quote': market['quoteId'], // 'from': this.milliseconds (), // 'limit': limit, // default '100' }; let method = 'privateGetAuthTrade'; let market = undefined; if (symbol !== undefined) { market = this.market (symbol); request['currency'] = market['baseId']; request['quote'] = market['quoteId']; method = 'privateGetAuthTradePairCurrencyQuote'; } if (limit !== undefined) { request['limit'] = limit; // default 100 } const response = await this[method] (this.extend (request, params)); // // [ // { // "id":"02e02533-b4bf-4ba9-9271-24e2108dfbf7", // "isMakerBuyer":false, // "direction":"TRADE_DIRECTION_BUY", // "baseCurrency":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f", // "quoteCurrency":"0c3a106d-bde3-4c13-a26e-3fd2394529e5", // "price":"4564.32", // "quantity":"0.01000", // "cost":"45.6432", // "fee":"0.223651680000000000", // "order":"c9cac6a0-484c-4892-88e7-ad51b39f2ce1", // "timestamp":1635921580399, // "makerBuyer":false // } // ] // return this.parseTrades (response, market, since, limit); } parseOrderStatus (status) { const statuses = { 'ORDER_STATUS_PLACED': 'open', 'ORDER_STATUS_CLOSED': 'closed', 'ORDER_STATUS_CANCELLED': 'canceled', }; return this.safeString (statuses, status, status); } parseOrderType (status) { const statuses = { 'ORDER_TYPE_MARKET': 'market', 'ORDER_TYPE_LIMIT': 'limit', }; return this.safeString (statuses, status, status); } parseTimeInForce (timeInForce) { const timeInForces = { 'ORDER_CONDITION_GOOD_TILL_CANCELLED': 'GTC', 'ORDER_CONDITION_IMMEDIATE_OR_CANCEL': 'IOC', 'ORDER_CONDITION_FILL_OR_KILL': 'FOK', }; return this.safeString (timeInForces, timeInForce, timeInForce); } parseOrder (order, market = undefined) { // // createOrder // // { // "orderId":"1563460093.134037.704945@0370:2", // "cliOrdId":"", // "pairId":370, // "symbol":"ETHBTC", // "side":"sell", // "orderType":"limit", // "price":1.0, // "amount":1.0 // } // // fetchOrder, fetchOpenOrders, fetchOrders // // { // "id":"a76bd262-3560-4bfb-98ac-1cedd394f4fc", // "status":"ORDER_STATUS_PLACED", // "side":"ORDER_SIDE_BUY", // "condition":"ORDER_CONDITION_GOOD_TILL_CANCELLED", // "type":"ORDER_TYPE_LIMIT", // "baseCurrency":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f", // "quoteCurrency":"0c3a106d-bde3-4c13-a26e-3fd2394529e5", // "clientOrderId":"web-macos_chrome_1a6a6659-6f7c-4fac-be0b-d1d7ac06d", // "price":"4000.00", // "quantity":"0.01", // "cost":"40.000000000000000000", // "filled":"0", // "trader":"7244bb3a-b6b2-446a-ac78-fa4bce5b59a9", // "creator":"ORDER_CREATOR_USER", // "creatorId":"", // "timestamp":1635920767648 // } // // cancelOrder // // { // "message":"cancellation request successfully submitted", // "status":"SUCCESS", // "id":"a631426d-3543-45ba-941e-75f7825afb0f" // } // const id = this.safeString (order, 'id'); const timestamp = this.safeInteger (order, 'timestamp'); const baseId = this.safeString (order, 'baseCurrency'); const quoteId = this.safeString (order, 'quoteCurrency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); let symbol = undefined; if ((base !== undefined) && (quote !== undefined)) { symbol = base + '/' + quote; if (symbol in this.markets) { market = this.market (symbol); } } const orderSide = this.safeString (order, 'side'); let side = undefined; if (orderSide !== undefined) { const parts = orderSide.split ('_'); const partsLength = parts.length; side = this.safeStringLower (parts, partsLength - 1); } const type = this.parseOrderType (this.safeString (order, 'type')); const price = this.safeString (order, 'price'); const amount = this.safeString (order, 'quantity'); const filled = this.safeString (order, 'filled'); const cost = this.safeString (order, 'cost'); let status = this.parseOrderStatus (this.safeString (order, 'status')); const message = this.safeString (order, 'message'); if (message !== undefined) { if (message.indexOf ('cancel') >= 0) { status = 'canceled'; } else if (message.indexOf ('accept') >= 0) { status = 'open'; } } const clientOrderId = this.safeString (order, 'clientOrderId'); const timeInForce = this.parseTimeInForce (this.safeString (order, 'condition')); return this.safeOrder ({ 'id': id, 'clientOrderId': clientOrderId, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, 'status': status, 'symbol': symbol, 'type': type, 'timeInForce': timeInForce, 'postOnly': undefined, 'side': side, 'price': price, 'stopPrice': undefined, 'cost': cost, 'amount': amount, 'filled': filled, 'average': undefined, 'remaining': undefined, 'fee': undefined, 'trades': undefined, }, market); } async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name latoken#fetchOpenOrders * @description fetch all unfilled currently open orders * @param {string} symbol unified market symbol * @param {int|undefined} since the earliest time in ms to fetch open orders for * @param {int|undefined} limit the maximum number of open orders structures to retrieve * @param {object} params extra parameters specific to the latoken api endpoint * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure} */ if (symbol === undefined) { throw new ArgumentsRequired (this.id + ' fetchOpenOrders() requires a symbol argument'); } await this.loadMarkets (); const market = this.market (symbol); const request = { 'currency': market['baseId'], 'quote': market['quoteId'], }; const response = await this.privateGetAuthOrderPairCurrencyQuoteActive (this.extend (request, params)); // // [ // { // "id":"a76bd262-3560-4bfb-98ac-1cedd394f4fc", // "status":"ORDER_STATUS_PLACED", // "side":"ORDER_SIDE_BUY", // "condition":"ORDER_CONDITION_GOOD_TILL_CANCELLED", // "type":"ORDER_TYPE_LIMIT", // "baseCurrency":"620f2019-33c0-423b-8a9d-cde4d7f8ef7f", // "quoteCurrency":"0c3a106d-bde3-4c13-a26e-3fd2394529e5", // "clientOrderId":"web-macos_chrome_1a6a6659-6f7c-4fac-be0b-d1d7ac06d", // "price":"4000.00", // "quantity":"0.01000", // "cost":"40.00", // "filled":"0.00000", // "trader":"7244bb3a-b6b2-446a-ac78-fa4bce5b59a9", //