UNPKG

consequunturatque

Version:

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

1,195 lines (1,161 loc) 55.6 kB
'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { ExchangeError, OrderNotFound, InvalidOrder, BadRequest, AuthenticationError, RateLimitExceeded, RequestTimeout, BadSymbol, AddressPending, PermissionDenied, InsufficientFunds } = require ('./base/errors'); const { ROUND } = require ('./base/functions/number'); const Precise = require ('./base/Precise'); // --------------------------------------------------------------------------- module.exports = class vcc extends Exchange { describe () { return this.deepExtend (super.describe (), { 'id': 'vcc', 'name': 'VCC Exchange', 'countries': [ 'VN' ], // Vietnam 'rateLimit': 1000, 'version': 'v3', 'has': { 'cancelAllOrders': true, 'cancelOrder': true, 'createOrder': true, 'editOrder': false, 'fetchBalance': true, 'fetchClosedOrders': true, 'fetchCurrencies': true, 'fetchDepositAddress': true, 'fetchDeposits': true, 'fetchMarkets': true, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': false, 'fetchTicker': 'emulated', 'fetchTickers': true, 'fetchTrades': true, 'fetchTradingFees': false, 'fetchTransactions': true, 'fetchWithdrawals': true, }, 'timeframes': { '1m': '60000', '5m': '300000', '15m': '900000', '30m': '1800000', '1h': '3600000', '2h': '7200000', '4h': '14400000', '6h': '21600000', '12h': '43200000', '1d': '86400000', '1w': '604800000', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/100545356-8427f500-326c-11eb-9539-7d338242d61b.jpg', 'api': { 'public': 'https://api.vcc.exchange', 'private': 'https://api.vcc.exchange', }, 'www': 'https://vcc.exchange', 'doc': [ 'https://vcc.exchange/api', ], 'fees': 'https://support.vcc.exchange/hc/en-us/articles/360016401754', 'referral': 'https://vcc.exchange?ref=l4xhrH', }, 'api': { 'public': { 'get': [ 'summary', 'exchange_info', 'assets', // Available Currencies 'ticker', // Ticker list for all symbols 'trades/{market_pair}', // Recent trades 'orderbook/{market_pair}', // Orderbook 'chart/bars', // Candles 'tick_sizes', ], }, 'private': { 'get': [ 'user', 'balance', // Get trading balance 'orders/{order_id}', // Get a single order by order_id 'orders/open', // Get open orders 'orders', // Get closed orders 'orders/trades', // Get trades history 'deposit-address', // Generate or get deposit address 'transactions', // Get deposit/withdrawal history ], 'post': [ 'orders', // Create new order ], 'put': [ 'orders/{order_id}/cancel', // Cancel order 'orders/cancel-by-type', 'orders/cancel-all', ], }, }, 'fees': { 'trading': { 'tierBased': false, 'percentage': true, 'maker': 0.2 / 100, 'taker': 0.2 / 100, }, }, 'exceptions': { 'exact': {}, 'broad': { 'limit may not be greater than': BadRequest, // {"message":"The given data was invalid.","errors":{"limit":["The limit may not be greater than 1000."]}} 'Insufficient balance': InsufficientFunds, // {"message":"Insufficient balance."} 'Unauthenticated': AuthenticationError, // {"message":"Unauthenticated."} // wrong api key 'signature is invalid': AuthenticationError, // {"message":"The given data was invalid.","errors":{"signature":["HMAC signature is invalid"]}} 'Timeout': RequestTimeout, // {"code":504,"message":"Gateway Timeout","description":""} 'Too many requests': RateLimitExceeded, // {"code":429,"message":"Too many requests","description":"Too many requests"} 'quantity field is required': InvalidOrder, // {"message":"The given data was invalid.","errors":{"quantity":["The quantity field is required when type is market."]}} 'price field is required': InvalidOrder, // {"message":"The given data was invalid.","errors":{"price":["The price field is required when type is limit."]}} 'error_security_level': PermissionDenied, // {"message":"error_security_level"} 'pair is invalid': BadSymbol, // {"message":"The given data was invalid.","errors":{"coin":["Trading pair is invalid","Trading pair is offline"]}} // {"message":"The given data was invalid.","errors":{"type":["The selected type is invalid."]}} // {"message":"The given data was invalid.","errors":{"trade_type":["The selected trade type is invalid."]}} 'type is invalid': InvalidOrder, 'Data not found': OrderNotFound, // {"message":"Data not found"} }, }, }); } async fetchMarkets (params = {}) { const response = await this.publicGetExchangeInfo (params); // // { // "message":null, // "dataVersion":"4677e56a42f0c29872f3a6e75f5d39d2f07c748c", // "data":{ // "timezone":"UTC", // "serverTime":1605821914333, // "symbols":[ // { // "id":"btcvnd", // "symbol":"BTC\/VND", // "coin":"btc", // "currency":"vnd", // "baseId":1, // "quoteId":0, // "active":true, // "base_precision":"0.0000010000", // "quote_precision":"1.0000000000", // "minimum_quantity":"0.0000010000", // "minimum_amount":"250000.0000000000", // "precision":{"price":0,"amount":6,"cost":6}, // "limits":{ // "amount":{"min":"0.0000010000"}, // "price":{"min":"1.0000000000"}, // "cost":{"min":"250000.0000000000"}, // }, // }, // ], // }, // } // const data = this.safeValue (response, 'data'); const markets = this.safeValue (data, 'symbols'); const result = []; for (let i = 0; i < markets.length; i++) { const market = this.safeValue (markets, i); const symbol = this.safeString (market, 'symbol'); const id = symbol.replace ('/', '_'); const baseId = this.safeString (market, 'coin'); const quoteId = this.safeString (market, 'currency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const active = this.safeValue (market, 'active'); const precision = this.safeValue (market, 'precision', {}); const limits = this.safeValue (market, 'limits', {}); const amountLimits = this.safeValue (limits, 'amount', {}); const priceLimits = this.safeValue (limits, 'price', {}); const costLimits = this.safeValue (limits, 'cost', {}); const entry = { 'info': market, 'id': id, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'active': active, 'precision': { 'price': this.safeInteger (precision, 'price'), 'amount': this.safeInteger (precision, 'amount'), 'cost': this.safeInteger (precision, 'cost'), }, 'limits': { 'amount': { 'min': this.safeNumber (amountLimits, 'min'), 'max': undefined, }, 'price': { 'min': this.safeNumber (priceLimits, 'min'), 'max': undefined, }, 'cost': { 'min': this.safeNumber (costLimits, 'min'), 'max': undefined, }, }, }; result.push (entry); } return result; } async fetchCurrencies (params = {}) { const response = await this.publicGetAssets (params); // // { // "message":null, // "dataVersion":"2514c8012d94ea375018fc13e0b5d4d896e435df", // "data":{ // "BTC":{ // "name":"Bitcoin", // "unified_cryptoasset_id":1, // "can_withdraw":1, // "can_deposit":1, // "min_withdraw":"0.0011250000", // "max_withdraw":"100.0000000000", // "maker_fee":"0.002", // "taker_fee":"0.002", // "decimal":8, // "withdrawal_fee":"0.0006250000", // }, // }, // } // const result = {}; const data = this.safeValue (response, 'data'); const ids = Object.keys (data); for (let i = 0; i < ids.length; i++) { const id = this.safeStringLower (ids, i); const currency = this.safeValue (data, ids[i]); const code = this.safeCurrencyCode (id); const canDeposit = this.safeValue (currency, 'can_deposit'); const canWithdraw = this.safeValue (currency, 'can_withdraw'); const active = (canDeposit && canWithdraw); result[code] = { 'id': id, 'code': code, 'name': this.safeString (currency, 'name'), 'active': active, 'fee': this.safeNumber (currency, 'withdrawal_fee'), 'precision': this.safeInteger (currency, 'decimal'), 'limits': { 'withdraw': { 'min': this.safeNumber (currency, 'min_withdraw'), 'max': this.safeNumber (currency, 'max_withdraw'), }, }, }; } return result; } async fetchTradingFee (symbol, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = this.extend ({ 'symbol': market['id'], }, this.omit (params, 'symbol')); const response = await this.privateGetTradingFeeSymbol (request); // // { // takeLiquidityRate: '0.001', // provideLiquidityRate: '-0.0001' // } // return { 'info': response, 'maker': this.safeNumber (response, 'provideLiquidityRate'), 'taker': this.safeNumber (response, 'takeLiquidityRate'), }; } async fetchBalance (params = {}) { await this.loadMarkets (); const response = await this.privateGetBalance (params); // // { // "message":null, // "dataVersion":"7168e6c99e90f60673070944d987988eef7d91fa", // "data":{ // "vnd":{"balance":0,"available_balance":0}, // "btc":{"balance":0,"available_balance":0}, // "eth":{"balance":0,"available_balance":0}, // }, // } // const data = this.safeValue (response, 'data'); const result = { 'info': response, 'timestamp': undefined, 'datetime': undefined, }; const currencyIds = Object.keys (data); for (let i = 0; i < currencyIds.length; i++) { const currencyId = currencyIds[i]; const code = this.safeCurrencyCode (currencyId); const balance = this.safeValue (data, currencyId); const account = this.account (); account['free'] = this.safeString (balance, 'available_balance'); account['total'] = this.safeString (balance, 'balance'); result[code] = account; } return this.parseBalance (result, false); } parseOHLCV (ohlcv, market = undefined) { // // { // "low":"415805323.0000000000", // "high":"415805323.0000000000", // "open":"415805323.0000000000", // "close":"415805323.0000000000", // "time":"1605845940000", // "volume":"0.0065930000", // "opening_time":1605845963263, // "closing_time":1605845963263 // } // return [ this.safeInteger (ohlcv, 'time'), 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); const request = { 'coin': market['baseId'], 'currency': market['quoteId'], 'resolution': this.timeframes[timeframe], }; limit = (limit === undefined) ? 100 : limit; limit = Math.min (100, limit); const duration = this.parseTimeframe (timeframe); if (since === undefined) { const end = this.seconds (); request['to'] = end; request['from'] = end - limit * duration; } else { const start = parseInt (since / 1000); request['from'] = start; request['to'] = this.sum (start, limit * duration); } const response = await this.publicGetChartBars (this.extend (request, params)); // // [ // {"low":"415805323.0000000000","high":"415805323.0000000000","open":"415805323.0000000000","close":"415805323.0000000000","time":"1605845940000","volume":"0.0065930000","opening_time":1605845963263,"closing_time":1605845963263}, // {"low":"416344148.0000000000","high":"416344148.0000000000","open":"415805323.0000000000","close":"416344148.0000000000","time":"1605846000000","volume":"0.0052810000","opening_time":1605846011490,"closing_time":1605846011490}, // {"low":"416299269.0000000000","high":"417278376.0000000000","open":"416344148.0000000000","close":"417278376.0000000000","time":"1605846060000","volume":"0.0136750000","opening_time":1605846070727,"closing_time":1605846102282}, // ] // return this.parseOHLCVs (response, market, timeframe, since, limit); } async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'market_pair': market['id'], // 'depth': 0, // 0 = full orderbook, 5, 10, 20, 50, 100, 500 'level': 2, // 1 = best bidask, 2 = aggregated by price, 3 = no aggregation }; if (limit !== undefined) { if ((limit !== 0) && (limit !== 5) && (limit !== 10) && (limit !== 20) && (limit !== 50) && (limit !== 100) && (limit !== 500)) { throw new BadRequest (this.id + ' fetchOrderBook limit must be 0, 5, 10, 20, 50, 100, 500 if specified'); } request['depth'] = limit; } const response = await this.publicGetOrderbookMarketPair (this.extend (request, params)); // // { // "message":null, // "dataVersion":"376cee43af26deabcd3762ab11a876b6e7a71e82", // "data":{ // "bids":[ // ["413342637.0000000000","0.165089"], // ["413274576.0000000000","0.03"], // ["413274574.0000000000","0.03"], // ], // "asks":[ // ["416979125.0000000000","0.122835"], // ["417248934.0000000000","0.030006"], // ["417458879.0000000000","0.1517"], // ], // "timestamp":"1605841619147" // } // } // const data = this.safeValue (response, 'data'); const timestamp = this.safeValue (data, 'timestamp'); return this.parseOrderBook (data, symbol, timestamp, 'bids', 'asks', 0, 1); } parseTicker (ticker, market = undefined) { // // { // "base_id":1, // "quote_id":0, // "last_price":"411119457", // "max_price":"419893173.0000000000", // "min_price":"401292577.0000000000", // "open_price":null, // "base_volume":"10.5915050000", // "quote_volume":"4367495977.4484430060", // "isFrozen":0 // } // const timestamp = this.milliseconds (); const baseVolume = this.safeNumber (ticker, 'base_volume'); const quoteVolume = this.safeNumber (ticker, 'quote_volume'); const open = this.safeNumber (ticker, 'open_price'); const last = this.safeNumber (ticker, 'last_price'); let change = undefined; let percentage = undefined; let average = undefined; if (last !== undefined && open !== undefined) { change = last - open; average = this.sum (last, open) / 2; if (open > 0) { percentage = change / open * 100; } } const vwap = this.vwap (baseVolume, quoteVolume); const symbol = (market === undefined) ? undefined : market['symbol']; return { 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'high': this.safeNumber (ticker, 'max_price'), 'low': this.safeNumber (ticker, 'min_price'), 'bid': this.safeNumber (ticker, 'bid'), 'bidVolume': undefined, 'ask': this.safeNumber (ticker, 'ask'), 'askVolume': undefined, 'vwap': vwap, 'open': open, 'close': last, 'last': last, 'previousClose': undefined, 'change': change, 'percentage': percentage, 'average': average, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'info': ticker, }; } async fetchTicker (symbol, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const response = await this.publicGetTicker (params); // // { // "message":null, // "dataVersion":"fc521161aebe506178b8588cd2adb598eaf1018e", // "data":{ // "BTC_VND":{ // "base_id":1, // "quote_id":0, // "last_price":"411119457", // "max_price":"419893173.0000000000", // "min_price":"401292577.0000000000", // "open_price":null, // "base_volume":"10.5915050000", // "quote_volume":"4367495977.4484430060", // "isFrozen":0 // }, // } // } // const data = this.safeValue (response, 'data'); const ticker = this.safeValue (data, market['id']); return this.parseTicker (ticker, market); } async fetchTickers (symbols = undefined, params = {}) { await this.loadMarkets (); const response = await this.publicGetTicker (params); // // { // "message":null, // "dataVersion":"fc521161aebe506178b8588cd2adb598eaf1018e", // "data":{ // "BTC_VND":{ // "base_id":1, // "quote_id":0, // "last_price":"411119457", // "max_price":"419893173.0000000000", // "min_price":"401292577.0000000000", // "open_price":null, // "base_volume":"10.5915050000", // "quote_volume":"4367495977.4484430060", // "isFrozen":0 // }, // } // } // const result = {}; const data = this.safeValue (response, 'data'); const marketIds = Object.keys (data); for (let i = 0; i < marketIds.length; i++) { const marketId = marketIds[i]; const market = this.safeMarket (marketId, undefined, '_'); const symbol = market['symbol']; result[symbol] = this.parseTicker (data[marketId], market); } return this.filterByArray (result, 'symbol', symbols); } parseTrade (trade, market = undefined) { // // public fetchTrades // // { // "trade_id":181509285, // "price":"415933022.0000000000", // "base_volume":"0.0022080000", // "quote_volume":"918380.1125760000", // "trade_timestamp":1605842150357, // "type":"buy", // } // // private fetchMyTrades // // { // "trade_type":"sell", // "fee":"0.0610578086", // "id":1483372, // "created_at":1606581578368, // "currency":"usdt", // "coin":"btc", // "price":"17667.1900000000", // "quantity":"0.0017280000", // "amount":"30.5289043200", // } // const timestamp = this.safeInteger2 (trade, 'trade_timestamp', 'created_at'); const baseId = this.safeStringUpper (trade, 'coin'); const quoteId = this.safeStringUpper (trade, 'currency'); let marketId = undefined; if ((baseId !== undefined) && (quoteId !== undefined)) { marketId = baseId + '_' + quoteId; } market = this.safeMarket (marketId, market, '_'); const symbol = market['symbol']; const priceString = this.safeString (trade, 'price'); const amountString = this.safeString2 (trade, 'base_volume', 'quantity'); const price = this.parseNumber (priceString); const amount = this.parseNumber (amountString); let cost = this.safeNumber2 (trade, 'quote_volume', 'amount'); if (cost === undefined) { cost = this.parseNumber (Precise.stringMul (priceString, amountString)); } const side = this.safeString2 (trade, 'type', 'trade_type'); const id = this.safeString2 (trade, 'trade_id', 'id'); const feeCost = this.safeNumber (trade, 'fee'); let fee = undefined; if (feeCost !== undefined) { fee = { 'cost': feeCost, 'currency': market['quote'], }; } return { 'info': trade, 'id': id, 'order': undefined, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'symbol': symbol, 'type': undefined, 'side': side, 'takerOrMaker': undefined, 'price': price, 'amount': amount, 'cost': cost, 'fee': fee, }; } async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'market_pair': market['id'], // 'type': 'buy', // 'sell' // 'count': limit, // default 500, max 1000 }; if (limit !== undefined) { request['count'] = Math.min (1000, limit); } const response = await this.publicGetTradesMarketPair (this.extend (request, params)); // // { // "message":null, // "dataVersion":"1f811b533143f739008a3e4ecaaab2ec82ea50d4", // "data":[ // { // "trade_id":181509285, // "price":"415933022.0000000000", // "base_volume":"0.0022080000", // "quote_volume":"918380.1125760000", // "trade_timestamp":1605842150357, // "type":"buy", // }, // ], // } // const data = this.safeValue (response, 'data'); return this.parseTrades (data, market, since, limit); } async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const request = { // 'type': type, // 'deposit', 'withdraw' // 'start': parseInt (since / 1000), // 'end': this.seconds (), }; let currency = undefined; if (code !== undefined) { currency = this.currency (code); request['currency'] = currency['id']; } if (limit !== undefined) { request['limit'] = Math.min (1000, limit); } if (since !== undefined) { request['start'] = since; } const response = await this.privateGetTransactions (this.extend (request, params)); // // { // "message":null, // "dataVersion":"1fdfb0ec85b666871d62fe59d098d01839b05e97", // "data":{ // "current_page":1, // "data":[ // { // "id":85391, // "user_id":253063, // "transaction_id":"0x885719cee5910ca509a223d208797510e80eb27a2f1d51a71bb4ccb82d538131", // "internal_transaction_id":null, // "temp_transaction_id":"2367", // "currency":"usdt", // "amount":"30.0000000000", // "btc_amount":"0.0000000000", // "usdt_amount":"0.0000000000", // "fee":"0.0000000000", // "tx_cost":"0.0000000000", // "confirmation":0, // "deposit_code":null, // "status":"success", // "bank_name":null, // "foreign_bank_account":null, // "foreign_bank_account_holder":null, // "blockchain_address":"0xd54b84AD27E4c4a8C9E0b2b53701DeFc728f6E44", // "destination_tag":null, // "error_detail":null, // "refunded":"0.0000000000", // "transaction_date":"2020-11-28", // "transaction_timestamp":"1606563143.959", // "created_at":1606563143959, // "updated_at":1606563143959, // "transaction_email_timestamp":0, // "network":null, // "collect_tx_id":null, // "collect_id":null // } // ], // "first_page_url":"http:\/\/api.vcc.exchange\/v3\/transactions?page=1", // "from":1, // "last_page":1, // "last_page_url":"http:\/\/api.vcc.exchange\/v3\/transactions?page=1", // "next_page_url":null, // "path":"http:\/\/api.vcc.exchange\/v3\/transactions", // "per_page":10, // "prev_page_url":null, // "to":1, // "total":1 // } // } // let data = this.safeValue (response, 'data', {}); data = this.safeValue (data, 'data', []); return this.parseTransactions (data, currency, since, limit); } async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { const request = { 'type': 'deposit' }; return await this.fetchTransactions (code, since, limit, this.extend (request, params)); } async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { const request = { 'type': 'withdraw' }; return await this.fetchTransactions (code, since, limit, this.extend (request, params)); } parseTransaction (transaction, currency = undefined) { // // fetchTransactions, fetchDeposits, fetchWithdrawals // // { // "id":85391, // "user_id":253063, // "transaction_id":"0x885719cee5910ca509a223d208797510e80eb27a2f1d51a71bb4ccb82d538131", // "internal_transaction_id":null, // "temp_transaction_id":"2367", // "currency":"usdt", // "amount":"30.0000000000", // "btc_amount":"0.0000000000", // "usdt_amount":"0.0000000000", // "fee":"0.0000000000", // "tx_cost":"0.0000000000", // "confirmation":0, // "deposit_code":null, // "status":"success", // "bank_name":null, // "foreign_bank_account":null, // "foreign_bank_account_holder":null, // "blockchain_address":"0xd54b84AD27E4c4a8C9E0b2b53701DeFc728f6E44", // "destination_tag":null, // "error_detail":null, // "refunded":"0.0000000000", // "transaction_date":"2020-11-28", // "transaction_timestamp":"1606563143.959", // "created_at":1606563143959, // "updated_at":1606563143959, // "transaction_email_timestamp":0, // "network":null, // "collect_tx_id":null, // "collect_id":null // } // const id = this.safeString (transaction, 'id'); const timestamp = this.safeInteger (transaction, 'created_at'); const updated = this.safeInteger (transaction, 'updated_at'); const currencyId = this.safeString (transaction, 'currency'); const code = this.safeCurrencyCode (currencyId, currency); const status = this.parseTransactionStatus (this.safeString (transaction, 'status')); let amount = this.safeNumber (transaction, 'amount'); if (amount !== undefined) { amount = Math.abs (amount); } const address = this.safeString (transaction, 'blockchain_address'); const txid = this.safeString (transaction, 'transaction_id'); const tag = this.safeString (transaction, 'destination_tag'); let fee = undefined; const feeCost = this.safeNumber (transaction, 'fee'); if (feeCost !== undefined) { fee = { 'cost': feeCost, 'currency': code, }; } const type = amount > 0 ? 'deposit' : 'withdrawal'; return { 'info': transaction, 'id': id, 'txid': txid, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'address': address, 'addressTo': address, 'addressFrom': undefined, 'tag': tag, 'tagTo': tag, 'tagFrom': undefined, 'type': type, 'amount': amount, 'currency': code, 'status': status, 'updated': updated, 'fee': fee, }; } parseTransactionStatus (status) { const statuses = { 'pending': 'pending', 'error': 'failed', 'success': 'ok', 'cancel': 'canceled', }; return this.safeString (statuses, status, status); } parseTransactionType (type) { const types = { 'deposit': 'deposit', 'withdraw': 'withdrawal', }; return this.safeString (types, type, type); } costToPrecision (symbol, cost) { return this.decimalToPrecision (cost, ROUND, this.markets[symbol]['precision']['cost'], this.precisionMode, this.paddingMode); } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'coin': market['baseId'], 'currency': market['quoteId'], 'trade_type': side, 'type': type, }; if (type === 'ceiling_market') { const ceiling = this.safeValue (params, 'ceiling'); if (ceiling !== undefined) { request['ceiling'] = this.costToPrecision (symbol, ceiling); } else if (price !== undefined) { request['ceiling'] = this.costToPrecision (symbol, amount * price); } else { throw new InvalidOrder (this.id + ' createOrder() requires a price argument or a ceiling parameter for ' + type + ' orders'); } } else { request['quantity'] = this.amountToPrecision (symbol, amount); } if (type === 'limit') { request['price'] = this.priceToPrecision (symbol, price); } const stopPrice = this.safeValue2 (params, 'stop_price', 'stopPrice'); if (stopPrice !== undefined) { request['is_stop'] = 1; request['stop_condition'] = (side === 'buy') ? 'le' : 'ge'; // ge = greater than or equal, le = less than or equal request['stop_price'] = this.priceToPrecision (symbol, price); } params = this.omit (params, [ 'stop_price', 'stopPrice' ]); const response = await this.privatePostOrders (this.extend (request, params)); // // ceiling_market order // // { // "message":null, // "dataVersion":"213fc0d433f38307f736cae1cbda4cc310469b7a", // "data":{ // "coin":"btc", // "currency":"usdt", // "trade_type":"buy", // "type":"ceiling_market", // "ceiling":"30", // "user_id":253063, // "email":"igor.kroitor@gmail.com", // "side":"buy", // "quantity":"0.00172800", // "status":"pending", // "fee":0, // "created_at":1606571333035, // "updated_at":1606571333035, // "instrument_symbol":"BTCUSDT", // "remaining":"0.00172800", // "fee_rate":"0.002", // "id":88214435 // } // } // // limit order // // { // "message":null, // "dataVersion":"d9b1159d2bcefa2388be156e32ddc7cc324400ee", // "data":{ // "id":41230, // "trade_type":"sell", // "type":"limit", // "quantity":"1", // "price":"14.99", // "currency":"usdt", // "coin":"neo", // "status":"pending", // "is_stop": "1", // "stop_price": "13", // "stop_condition": "ge", // "fee":0, // "created_at":1560244052168, // "updated_at":1560244052168 // } // } // const data = this.safeValue (response, 'data'); return this.parseOrder (data, market); } async cancelOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); const request = { 'order_id': id, }; const response = await this.privatePutOrdersOrderIdCancel (this.extend (request, params)); return this.parseOrder (response); } async cancelAllOrders (symbol = undefined, params = {}) { const type = this.safeString (params, 'type'); const method = (type === undefined) ? 'privatePutOrdersCancelAll' : 'privatePutOrdersCancelByType'; const request = {}; if (type !== undefined) { request['type'] = type; } await this.loadMarkets (); const response = await this[method] (this.extend (request, params)); // // { // "dataVersion":"6d72fb82a9c613c8166581a887e1723ce5a937ff", // "data":{ // "data":[ // { // "id":410, // "trade_type":"sell", // "currency":"usdt", // "coin":"neo", // "type":"limit", // "quantity":"1.0000000000", // "price":"14.9900000000", // "executed_quantity":"0.0000000000", // "executed_price":"0.0000000000", // "fee":"0.0000000000", // "status":"canceled", // "created_at":1560244052168, // "updated_at":1560244052168, // }, // ], // }, // } // let data = this.safeValue (response, 'data', {}); data = this.safeValue (response, 'data', []); return this.parseOrders (data); } parseOrderStatus (status) { const statuses = { 'pending': 'open', 'stopping': 'open', 'executing': 'open', 'executed': 'closed', 'canceled': 'canceled', }; return this.safeString (statuses, status, status); } parseOrder (order, market = undefined) { // // ceiling_market // // { // "coin":"btc", // "currency":"usdt", // "trade_type":"buy", // "type":"ceiling_market", // "ceiling":"30", // "user_id":253063, // "email":"igor.kroitor@gmail.com", // "side":"buy", // "quantity":"0.00172800", // "status":"pending", // "fee":0, // "created_at":1606571333035, // "updated_at":1606571333035, // "instrument_symbol":"BTCUSDT", // "remaining":"0.00172800", // "fee_rate":"0.002", // "id":88214435 // } // // limit order // // { // "id":41230, // "trade_type":"sell", // "type":"limit", // "quantity":"1", // "price":"14.99", // "currency":"usdt", // "coin":"neo", // "status":"pending", // "is_stop": "1", // "stop_price": "13", // "stop_condition": "ge", // "fee":0, // "created_at":1560244052168, // "updated_at":1560244052168 // } // const created = this.safeValue (order, 'created_at'); const updated = this.safeValue (order, 'updated_at'); const baseId = this.safeStringUpper (order, 'coin'); const quoteId = this.safeStringUpper (order, 'currency'); const marketId = baseId + '_' + quoteId; market = this.safeMarket (marketId, market, '_'); const symbol = market['symbol']; const amount = this.safeNumber (order, 'quantity'); const filled = this.safeNumber (order, 'executed_quantity'); const status = this.parseOrderStatus (this.safeString (order, 'status')); const cost = this.safeNumber (order, 'ceiling'); const id = this.safeString (order, 'id'); const price = this.safeNumber (order, 'price'); const average = this.safeNumber (order, 'executed_price'); const remaining = this.safeNumber (order, 'remaining'); const type = this.safeString (order, 'type'); const side = this.safeString (order, 'trade_type'); const fee = { 'currency': market['quote'], 'cost': this.safeNumber (order, 'fee'), 'rate': this.safeNumber (order, 'fee_rate'), }; let lastTradeTimestamp = undefined; if (updated !== created) { lastTradeTimestamp = updated; } const stopPrice = this.safeNumber (order, 'stopPrice'); return this.safeOrder ({ 'id': id, 'clientOrderId': id, 'timestamp': created, 'datetime': this.iso8601 (created), 'lastTradeTimestamp': lastTradeTimestamp, 'status': status, 'symbol': symbol, 'type': type, 'timeInForce': undefined, 'postOnly': undefined, 'side': side, 'price': price, 'stopPrice': stopPrice, 'average': average, 'amount': amount, 'cost': cost, 'filled': filled, 'remaining': remaining, 'fee': fee, 'trades': undefined, 'info': order, }); } async fetchOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); const request = { 'order_id': id, }; const response = await this.privateGetOrdersOrderId (this.extend (request, params)); // // { // "message":null, // "dataVersion":"57448aa1fb8f227254e8e2e925b3ade8e1e5bbef", // "data":{ // "id":88265741, // "user_id":253063, // "email":"igor.kroitor@gmail.com", // "updated_at":1606581578141, // "created_at":1606581578141, // "coin":"btc", // "currency":"usdt", // "type":"market", // "trade_type":"sell", // "executed_price":"17667.1900000000", // "price":null, // "executed_quantity":"0.0017280000", // "quantity":"0.0017280000", // "fee":"0.0610578086", // "status":"executed", // "is_stop":0, // "stop_condition":null, // "stop_price":null, // "ceiling":null // } // } // const data = this.safeValue (response, 'data'); return this.parseOrder (data); } async fetchOrdersWithMethod (method, symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const request = { // 'page': 1, // 'limit': limit, // max 1000 // 'start_date': since, // 'end_date': this.milliseconds (), // 'currency': market['quoteId'], // 'coin': market['baseId'], // 'trade_type': 'buy', // or 'sell' // 'hide_canceled': 0, // 1 to exclude canceled orders }; let market = undefined; if (symbol !== undefined) { market = this.market (symbol); request['coin'] = market['baseId']; request['currency'] = market['quoteId']; } if (since !== undefined) { request['start_date'] = since; } if (limit !== undefined) { request['limit'] = Math.min (1000, limit); // max 1000 } const response = await this[method] (this.extend (request, params)); // // { // "message":null, // "dataVersion":"89aa11497f23fdd34cf9de9c55acfad863c78780", // "data":{ // "current_page":1, // "data":[ // { // "id":88489678, // "email":"igor.kroitor@gmail.com", // "updated_at":1606628593567, // "created_at":1606628593567, // "coin":"btc", // "currency":"usdt", // "type":"limit", // "trade_type":"buy", // "executed_price":"0.0000000000", // "price":"10000.0000000000", // "executed_quantity":"0.0000000000", // "quantity":"0.0010000000", // "fee":"0.0000000000", // "status":"pending", // "is_stop":0, // "stop_condition":null, // "stop_price":null, // "ceiling":null, // }, // ], // "first_page_url":"http:\/\/api.vcc.exchange\/v3\/orders\/open?page=1", // "from":1, // "last_page":1, // "last_page_url":"http:\/\/api.vcc.exchange\/v3\/orders\/open?page=1", // "next_page_url":null, // "path":"http:\/\/api.vcc.exchange\/v3\/orders\/open", // "per_page":10, // "prev_page_url":null, // "to":1, // "total":1, // }, // } // let data = this.safeValue (response, 'data', {}); data = this.safeValue (data, 'data', []); return this.parseOrders (data, market, since, limit); } async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { return await this.fetchOrdersWithMethod ('privateGetOrdersOpen', symbol, since, limit, params); } async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { return await this.fetchOrdersWithMethod ('privateGetOrders', symbol, since, limit, params); } async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const request = { // 'page': 1, // 'limit': limit, // max 1000 // 'start_date': since, // 'end_date': this.milliseconds (), // 'currency': market['quoteId'], // 'coin': market['baseId'], // 'trade_type': 'buy', // or 'sell' }; let market = undefined; if (symbol !== undefined) { market = this.market (symbol); request['coin'] = market['baseId']; request['currency'] = market['quoteId']; } if (since !== undefined) { request['start_date'] = since;