UNPKG

consequunturatque

Version:

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

1,188 lines (1,160 loc) 63.6 kB
'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { ExchangeError, BadRequest, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound, PermissionDenied, AddressPending } = require ('./base/errors'); const Precise = require ('./base/Precise'); // --------------------------------------------------------------------------- module.exports = class upbit extends Exchange { describe () { return this.deepExtend (super.describe (), { 'id': 'upbit', 'name': 'Upbit', 'countries': [ 'KR' ], 'version': 'v1', 'rateLimit': 1000, 'pro': true, // new metainfo interface 'has': { 'cancelOrder': true, 'CORS': true, 'createDepositAddress': true, 'createMarketOrder': true, 'createOrder': true, 'fetchBalance': true, 'fetchClosedOrders': true, 'fetchDepositAddress': true, 'fetchDeposits': true, 'fetchMarkets': true, 'fetchMyTrades': false, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrderBooks': true, 'fetchOrders': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTrades': true, 'fetchTransactions': false, 'fetchWithdrawals': true, 'withdraw': true, }, 'timeframes': { '1m': 'minutes', '3m': 'minutes', '5m': 'minutes', '15m': 'minutes', '30m': 'minutes', '1h': 'minutes', '4h': 'minutes', '1d': 'days', '1w': 'weeks', '1M': 'months', }, 'hostname': 'api.upbit.com', 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/49245610-eeaabe00-f423-11e8-9cba-4b0aed794799.jpg', 'api': { 'public': 'https://{hostname}', 'private': 'https://{hostname}', }, 'www': 'https://upbit.com', 'doc': 'https://docs.upbit.com/docs/%EC%9A%94%EC%B2%AD-%EC%88%98-%EC%A0%9C%ED%95%9C', 'fees': 'https://upbit.com/service_center/guide', }, 'api': { 'public': { 'get': [ 'market/all', 'candles/{timeframe}', 'candles/{timeframe}/{unit}', 'candles/minutes/{unit}', 'candles/minutes/1', 'candles/minutes/3', 'candles/minutes/5', 'candles/minutes/15', 'candles/minutes/30', 'candles/minutes/60', 'candles/minutes/240', 'candles/days', 'candles/weeks', 'candles/months', 'trades/ticks', 'ticker', 'orderbook', ], }, 'private': { 'get': [ 'accounts', 'orders/chance', 'order', 'orders', 'withdraws', 'withdraw', 'withdraws/chance', 'deposits', 'deposit', 'deposits/coin_addresses', 'deposits/coin_address', ], 'post': [ 'orders', 'withdraws/coin', 'withdraws/krw', 'deposits/generate_coin_address', ], 'delete': [ 'order', ], }, }, 'fees': { 'trading': { 'tierBased': false, 'percentage': true, 'maker': 0.0025, 'taker': 0.0025, }, 'funding': { 'tierBased': false, 'percentage': false, 'withdraw': {}, 'deposit': {}, }, }, 'exceptions': { 'exact': { 'This key has expired.': AuthenticationError, 'Missing request parameter error. Check the required parameters!': BadRequest, 'side is missing, side does not have a valid value': InvalidOrder, }, 'broad': { 'thirdparty_agreement_required': PermissionDenied, 'out_of_scope': PermissionDenied, 'order_not_found': OrderNotFound, 'insufficient_funds': InsufficientFunds, 'invalid_access_key': AuthenticationError, 'jwt_verification': AuthenticationError, 'create_ask_error': ExchangeError, 'create_bid_error': ExchangeError, 'volume_too_large': InvalidOrder, 'invalid_funds': InvalidOrder, }, }, 'options': { 'createMarketBuyOrderRequiresPrice': true, 'fetchTickersMaxLength': 4096, // 2048, 'fetchOrderBooksMaxLength': 4096, // 2048, 'tradingFeesByQuoteCurrency': { 'KRW': 0.0005, }, }, 'commonCurrencies': { 'TON': 'Tokamak Network', }, }); } async fetchCurrency (code, params = {}) { // this method is for retrieving funding fees and limits per currency // it requires private access and API keys properly set up await this.loadMarkets (); const currency = this.currency (code); return await this.fetchCurrencyById (currency['id'], params); } async fetchCurrencyById (id, params = {}) { // this method is for retrieving funding fees and limits per currency // it requires private access and API keys properly set up const request = { 'currency': id, }; const response = await this.privateGetWithdrawsChance (this.extend (request, params)); // // { // "member_level": { // "security_level": 3, // "fee_level": 0, // "email_verified": true, // "identity_auth_verified": true, // "bank_account_verified": true, // "kakao_pay_auth_verified": false, // "locked": false, // "wallet_locked": false // }, // "currency": { // "code": "BTC", // "withdraw_fee": "0.0005", // "is_coin": true, // "wallet_state": "working", // "wallet_support": [ "deposit", "withdraw" ] // }, // "account": { // "currency": "BTC", // "balance": "10.0", // "locked": "0.0", // "avg_krw_buy_price": "8042000", // "modified": false // }, // "withdraw_limit": { // "currency": "BTC", // "minimum": null, // "onetime": null, // "daily": "10.0", // "remaining_daily": "10.0", // "remaining_daily_krw": "0.0", // "fixed": null, // "can_withdraw": true // } // } // const memberInfo = this.safeValue (response, 'member_level', {}); const currencyInfo = this.safeValue (response, 'currency', {}); const withdrawLimits = this.safeValue (response, 'withdraw_limit', {}); const canWithdraw = this.safeValue (withdrawLimits, 'can_withdraw'); const walletState = this.safeString (currencyInfo, 'wallet_state'); const walletLocked = this.safeValue (memberInfo, 'wallet_locked'); const locked = this.safeValue (memberInfo, 'locked'); let active = true; if ((canWithdraw !== undefined) && !canWithdraw) { active = false; } else if (walletState !== 'working') { active = false; } else if ((walletLocked !== undefined) && walletLocked) { active = false; } else if ((locked !== undefined) && locked) { active = false; } const maxOnetimeWithdrawal = this.safeNumber (withdrawLimits, 'onetime'); const maxDailyWithdrawal = this.safeNumber (withdrawLimits, 'daily', maxOnetimeWithdrawal); const remainingDailyWithdrawal = this.safeNumber (withdrawLimits, 'remaining_daily', maxDailyWithdrawal); let maxWithdrawLimit = undefined; if (remainingDailyWithdrawal > 0) { maxWithdrawLimit = remainingDailyWithdrawal; } else { maxWithdrawLimit = maxDailyWithdrawal; } const precision = undefined; const currencyId = this.safeString (currencyInfo, 'code'); const code = this.safeCurrencyCode (currencyId); return { 'info': response, 'id': currencyId, 'code': code, 'name': code, 'active': active, 'fee': this.safeNumber (currencyInfo, 'withdraw_fee'), 'precision': precision, 'limits': { 'withdraw': { 'min': this.safeNumber (withdrawLimits, 'minimum'), 'max': maxWithdrawLimit, }, }, }; } async fetchMarket (symbol, params = {}) { // this method is for retrieving trading fees and limits per market // it requires private access and API keys properly set up await this.loadMarkets (); const market = this.market (symbol); return await this.fetchMarketById (market['id'], params); } async fetchMarketById (id, params = {}) { // this method is for retrieving trading fees and limits per market // it requires private access and API keys properly set up const request = { 'market': id, }; const response = await this.privateGetOrdersChance (this.extend (request, params)); // // { bid_fee: "0.0005", // ask_fee: "0.0005", // market: { id: "KRW-BTC", // name: "BTC/KRW", // order_types: ["limit"], // order_sides: ["ask", "bid"], // bid: { currency: "KRW", // price_unit: null, // min_total: 1000 }, // ask: { currency: "BTC", // price_unit: null, // min_total: 1000 }, // max_total: "1000000000.0", // state: "active" }, // bid_account: { currency: "KRW", // balance: "0.0", // locked: "0.0", // avg_krw_buy_price: "0", // modified: false }, // ask_account: { currency: "BTC", // balance: "0.00780836", // locked: "0.0", // avg_krw_buy_price: "6465564.67", // modified: false } } // const marketInfo = this.safeValue (response, 'market'); const bid = this.safeValue (marketInfo, 'bid'); const ask = this.safeValue (marketInfo, 'ask'); const marketId = this.safeString (marketInfo, 'id'); const baseId = this.safeString (ask, 'currency'); const quoteId = this.safeString (bid, 'currency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; const precision = { 'amount': 8, 'price': 8, }; const state = this.safeString (marketInfo, 'state'); const active = (state === 'active'); const bidFee = this.safeNumber (response, 'bid_fee'); const askFee = this.safeNumber (response, 'ask_fee'); const fee = Math.max (bidFee, askFee); return { 'info': response, 'id': marketId, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'active': active, 'precision': precision, 'maker': fee, 'taker': fee, 'limits': { 'amount': { 'min': this.safeNumber (ask, 'min_total'), 'max': undefined, }, 'price': { 'min': Math.pow (10, -precision['price']), 'max': undefined, }, 'cost': { 'min': this.safeNumber (bid, 'min_total'), 'max': this.safeNumber (marketInfo, 'max_total'), }, }, }; } async fetchMarkets (params = {}) { const response = await this.publicGetMarketAll (params); // // [ { market: "KRW-BTC", // korean_name: "비트코인", // english_name: "Bitcoin" }, // { market: "KRW-DASH", // korean_name: "대시", // english_name: "Dash" }, // { market: "KRW-ETH", // korean_name: "이더리움", // english_name: "Ethereum" }, // { market: "BTC-ETH", // korean_name: "이더리움", // english_name: "Ethereum" }, // ..., // { market: "BTC-BSV", // korean_name: "비트코인에스브이", // english_name: "Bitcoin SV" } ] // const result = []; for (let i = 0; i < response.length; i++) { const market = response[i]; const id = this.safeString (market, 'market'); const [ quoteId, baseId ] = id.split ('-'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; const precision = { 'amount': 8, 'price': 8, }; const active = true; const makerFee = this.safeNumber (this.options['tradingFeesByQuoteCurrency'], quote, this.fees['trading']['maker']); const takerFee = this.safeNumber (this.options['tradingFeesByQuoteCurrency'], quote, this.fees['trading']['taker']); result.push ({ 'id': id, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'active': active, 'info': market, 'precision': precision, 'maker': makerFee, 'taker': takerFee, 'limits': { 'amount': { 'min': Math.pow (10, -precision['amount']), 'max': undefined, }, 'price': { 'min': Math.pow (10, -precision['price']), 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, }); } return result; } async fetchBalance (params = {}) { await this.loadMarkets (); const response = await this.privateGetAccounts (params); // // [ { currency: "BTC", // balance: "0.005", // locked: "0.0", // avg_krw_buy_price: "7446000", // modified: false }, // { currency: "ETH", // balance: "0.1", // locked: "0.0", // avg_krw_buy_price: "250000", // modified: false } ] // const result = { 'info': response, 'timestamp': undefined, 'datetime': undefined, }; for (let i = 0; i < response.length; i++) { const balance = response[i]; const currencyId = this.safeString (balance, 'currency'); const code = this.safeCurrencyCode (currencyId); const account = this.account (); account['free'] = this.safeString (balance, 'balance'); account['used'] = this.safeString (balance, 'locked'); result[code] = account; } return this.parseBalance (result, false); } async fetchOrderBooks (symbols = undefined, limit = undefined, params = {}) { await this.loadMarkets (); let ids = undefined; if (symbols === undefined) { ids = this.ids.join (','); // max URL length is 2083 symbols, including http schema, hostname, tld, etc... if (ids.length > this.options['fetchOrderBooksMaxLength']) { const numIds = this.ids.length; throw new ExchangeError (this.id + ' has ' + numIds.toString () + ' symbols (' + ids.length.toString () + ' characters) exceeding max URL length (' + this.options['fetchOrderBooksMaxLength'].toString () + ' characters), you are required to specify a list of symbols in the first argument to fetchOrderBooks'); } } else { ids = this.marketIds (symbols); ids = ids.join (','); } const request = { 'markets': ids, }; const response = await this.publicGetOrderbook (this.extend (request, params)); // // [ { market: "BTC-ETH", // timestamp: 1542899030043, // total_ask_size: 109.57065201, // total_bid_size: 125.74430631, // orderbook_units: [ { ask_price: 0.02926679, // bid_price: 0.02919904, // ask_size: 4.20293961, // bid_size: 11.65043576 }, // ..., // { ask_price: 0.02938209, // bid_price: 0.0291231, // ask_size: 0.05135782, // bid_size: 13.5595 } ] }, // { market: "KRW-BTC", // timestamp: 1542899034662, // total_ask_size: 12.89790974, // total_bid_size: 4.88395783, // orderbook_units: [ { ask_price: 5164000, // bid_price: 5162000, // ask_size: 2.57606495, // bid_size: 0.214 }, // ..., // { ask_price: 5176000, // bid_price: 5152000, // ask_size: 2.752, // bid_size: 0.4650305 } ] } ] // const result = {}; for (let i = 0; i < response.length; i++) { const orderbook = response[i]; const marketId = this.safeString (orderbook, 'market'); const symbol = this.safeSymbol (marketId, undefined, '-'); const timestamp = this.safeInteger (orderbook, 'timestamp'); result[symbol] = { 'symbol': symbol, 'bids': this.sortBy (this.parseBidsAsks (orderbook['orderbook_units'], 'bid_price', 'bid_size'), 0, true), 'asks': this.sortBy (this.parseBidsAsks (orderbook['orderbook_units'], 'ask_price', 'ask_size'), 0), 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'nonce': undefined, }; } return result; } async fetchOrderBook (symbol, limit = undefined, params = {}) { const orderbooks = await this.fetchOrderBooks ([ symbol ], limit, params); return this.safeValue (orderbooks, symbol); } parseTicker (ticker, market = undefined) { // // { market: "BTC-ETH", // trade_date: "20181122", // trade_time: "104543", // trade_date_kst: "20181122", // trade_time_kst: "194543", // trade_timestamp: 1542883543097, // opening_price: 0.02976455, // high_price: 0.02992577, // low_price: 0.02934283, // trade_price: 0.02947773, // prev_closing_price: 0.02966, // change: "FALL", // change_price: 0.00018227, // change_rate: 0.0061453136, // signed_change_price: -0.00018227, // signed_change_rate: -0.0061453136, // trade_volume: 1.00000005, // acc_trade_price: 100.95825586, // acc_trade_price_24h: 289.58650166, // acc_trade_volume: 3409.85311036, // acc_trade_volume_24h: 9754.40510513, // highest_52_week_price: 0.12345678, // highest_52_week_date: "2018-02-01", // lowest_52_week_price: 0.023936, // lowest_52_week_date: "2017-12-08", // timestamp: 1542883543813 } // const timestamp = this.safeInteger (ticker, 'trade_timestamp'); const marketId = this.safeString2 (ticker, 'market', 'code'); const symbol = this.safeSymbol (marketId, market, '-'); const previous = this.safeNumber (ticker, 'prev_closing_price'); const last = this.safeNumber (ticker, 'trade_price'); const change = this.safeNumber (ticker, 'signed_change_price'); const percentage = this.safeNumber (ticker, 'signed_change_rate'); return { 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'high': this.safeNumber (ticker, 'high_price'), 'low': this.safeNumber (ticker, 'low_price'), 'bid': undefined, 'bidVolume': undefined, 'ask': undefined, 'askVolume': undefined, 'vwap': undefined, 'open': this.safeNumber (ticker, 'opening_price'), 'close': last, 'last': last, 'previousClose': previous, 'change': change, 'percentage': percentage, 'average': undefined, 'baseVolume': this.safeNumber (ticker, 'acc_trade_volume_24h'), 'quoteVolume': this.safeNumber (ticker, 'acc_trade_price_24h'), 'info': ticker, }; } async fetchTickers (symbols = undefined, params = {}) { await this.loadMarkets (); let ids = undefined; if (symbols === undefined) { ids = this.ids.join (','); // max URL length is 2083 symbols, including http schema, hostname, tld, etc... if (ids.length > this.options['fetchTickersMaxLength']) { const numIds = this.ids.length; throw new ExchangeError (this.id + ' has ' + numIds.toString () + ' symbols exceeding max URL length, you are required to specify a list of symbols in the first argument to fetchTickers'); } } else { ids = this.marketIds (symbols); ids = ids.join (','); } const request = { 'markets': ids, }; const response = await this.publicGetTicker (this.extend (request, params)); // // [ { market: "BTC-ETH", // trade_date: "20181122", // trade_time: "104543", // trade_date_kst: "20181122", // trade_time_kst: "194543", // trade_timestamp: 1542883543097, // opening_price: 0.02976455, // high_price: 0.02992577, // low_price: 0.02934283, // trade_price: 0.02947773, // prev_closing_price: 0.02966, // change: "FALL", // change_price: 0.00018227, // change_rate: 0.0061453136, // signed_change_price: -0.00018227, // signed_change_rate: -0.0061453136, // trade_volume: 1.00000005, // acc_trade_price: 100.95825586, // acc_trade_price_24h: 289.58650166, // acc_trade_volume: 3409.85311036, // acc_trade_volume_24h: 9754.40510513, // highest_52_week_price: 0.12345678, // highest_52_week_date: "2018-02-01", // lowest_52_week_price: 0.023936, // lowest_52_week_date: "2017-12-08", // timestamp: 1542883543813 } ] // const result = {}; for (let t = 0; t < response.length; t++) { const ticker = this.parseTicker (response[t]); const symbol = ticker['symbol']; result[symbol] = ticker; } return this.filterByArray (result, 'symbol', symbols); } async fetchTicker (symbol, params = {}) { const tickers = await this.fetchTickers ([ symbol ], params); return this.safeValue (tickers, symbol); } parseTrade (trade, market = undefined) { // // fetchTrades // // { market: "BTC-ETH", // trade_date_utc: "2018-11-22", // trade_time_utc: "13:55:24", // timestamp: 1542894924397, // trade_price: 0.02914289, // trade_volume: 0.20074397, // prev_closing_price: 0.02966, // change_price: -0.00051711, // ask_bid: "ASK", // sequential_id: 15428949259430000 } // // fetchOrder trades // // { // "market": "KRW-BTC", // "uuid": "78162304-1a4d-4524-b9e6-c9a9e14d76c3", // "price": "101000.0", // "volume": "0.77368323", // "funds": "78142.00623", // "ask_fee": "117.213009345", // "bid_fee": "117.213009345", // "created_at": "2018-04-05T14:09:15+09:00", // "side": "bid", // } // const id = this.safeString2 (trade, 'sequential_id', 'uuid'); const orderId = undefined; let timestamp = this.safeInteger (trade, 'timestamp'); if (timestamp === undefined) { timestamp = this.parse8601 (this.safeString (trade, 'created_at')); } let side = undefined; const askOrBid = this.safeStringLower2 (trade, 'ask_bid', 'side'); if (askOrBid === 'ask') { side = 'sell'; } else if (askOrBid === 'bid') { side = 'buy'; } let cost = this.safeNumber (trade, 'funds'); const priceString = this.safeString2 (trade, 'trade_price', 'price'); const amountString = this.safeString2 (trade, 'trade_volume', 'volume'); const price = this.parseNumber (priceString); const amount = this.parseNumber (amountString); if (cost === undefined) { cost = this.parseNumber (Precise.stringMul (priceString, amountString)); } const marketId = this.safeString2 (trade, 'market', 'code'); market = this.safeMarket (marketId, market); let fee = undefined; let feeCurrency = undefined; let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; feeCurrency = market['quote']; } else { const [ baseId, quoteId ] = marketId.split ('-'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); symbol = base + '/' + quote; feeCurrency = quote; } const feeCost = this.safeString (trade, askOrBid + '_fee'); if (feeCost !== undefined) { fee = { 'currency': feeCurrency, 'cost': feeCost, }; } return { 'id': id, 'info': trade, 'order': orderId, '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); if (limit === undefined) { limit = 200; } const request = { 'market': market['id'], 'count': limit, }; const response = await this.publicGetTradesTicks (this.extend (request, params)); // // [ { market: "BTC-ETH", // trade_date_utc: "2018-11-22", // trade_time_utc: "13:55:24", // timestamp: 1542894924397, // trade_price: 0.02914289, // trade_volume: 0.20074397, // prev_closing_price: 0.02966, // change_price: -0.00051711, // ask_bid: "ASK", // sequential_id: 15428949259430000 }, // { market: "BTC-ETH", // trade_date_utc: "2018-11-22", // trade_time_utc: "13:03:10", // timestamp: 1542891790123, // trade_price: 0.02917, // trade_volume: 7.392, // prev_closing_price: 0.02966, // change_price: -0.00049, // ask_bid: "ASK", // sequential_id: 15428917910540000 } ] // return this.parseTrades (response, market, since, limit); } parseOHLCV (ohlcv, market = undefined) { // // { // market: "BTC-ETH", // candle_date_time_utc: "2018-11-22T13:47:00", // candle_date_time_kst: "2018-11-22T22:47:00", // opening_price: 0.02915963, // high_price: 0.02915963, // low_price: 0.02915448, // trade_price: 0.02915448, // timestamp: 1542894473674, // candle_acc_trade_price: 0.0981629437535248, // candle_acc_trade_volume: 3.36693173, // unit: 1 // } // return [ this.parse8601 (this.safeString (ohlcv, 'candle_date_time_utc')), this.safeNumber (ohlcv, 'opening_price'), this.safeNumber (ohlcv, 'high_price'), this.safeNumber (ohlcv, 'low_price'), this.safeNumber (ohlcv, 'trade_price'), this.safeNumber (ohlcv, 'candle_acc_trade_volume'), // base volume ]; } async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const timeframePeriod = this.parseTimeframe (timeframe); const timeframeValue = this.timeframes[timeframe]; if (limit === undefined) { limit = 200; } const request = { 'market': market['id'], 'timeframe': timeframeValue, 'count': limit, }; let method = 'publicGetCandlesTimeframe'; if (timeframeValue === 'minutes') { const numMinutes = Math.round (timeframePeriod / 60); request['unit'] = numMinutes; method += 'Unit'; } if (since !== undefined) { // convert `since` to `to` value request['to'] = this.iso8601 (this.sum (since, timeframePeriod * limit * 1000)); } const response = await this[method] (this.extend (request, params)); // // [ // { // market: "BTC-ETH", // candle_date_time_utc: "2018-11-22T13:47:00", // candle_date_time_kst: "2018-11-22T22:47:00", // opening_price: 0.02915963, // high_price: 0.02915963, // low_price: 0.02915448, // trade_price: 0.02915448, // timestamp: 1542894473674, // candle_acc_trade_price: 0.0981629437535248, // candle_acc_trade_volume: 3.36693173, // unit: 1 // }, // { // market: "BTC-ETH", // candle_date_time_utc: "2018-11-22T10:06:00", // candle_date_time_kst: "2018-11-22T19:06:00", // opening_price: 0.0294, // high_price: 0.02940882, // low_price: 0.02934283, // trade_price: 0.02937354, // timestamp: 1542881219276, // candle_acc_trade_price: 0.0762597110943884, // candle_acc_trade_volume: 2.5949617, // unit: 1 // } // ] // return this.parseOHLCVs (response, market, timeframe, since, limit); } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { if (type === 'market') { // for market buy it requires the amount of quote currency to spend if (side === 'buy') { 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 a 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 { amount = amount * price; } } } } let orderSide = undefined; if (side === 'buy') { orderSide = 'bid'; } else if (side === 'sell') { orderSide = 'ask'; } else { throw new InvalidOrder (this.id + ' createOrder allows buy or sell side only!'); } await this.loadMarkets (); const market = this.market (symbol); const request = { 'market': market['id'], 'side': orderSide, }; if (type === 'limit') { request['volume'] = this.amountToPrecision (symbol, amount); request['price'] = this.priceToPrecision (symbol, price); request['ord_type'] = type; } else if (type === 'market') { if (side === 'buy') { request['ord_type'] = 'price'; request['price'] = this.priceToPrecision (symbol, amount); } else if (side === 'sell') { request['ord_type'] = type; request['volume'] = this.amountToPrecision (symbol, amount); } } const response = await this.privatePostOrders (this.extend (request, params)); // // { // 'uuid': 'cdd92199-2897-4e14-9448-f923320408ad', // 'side': 'bid', // 'ord_type': 'limit', // 'price': '100.0', // 'avg_price': '0.0', // 'state': 'wait', // 'market': 'KRW-BTC', // 'created_at': '2018-04-10T15:42:23+09:00', // 'volume': '0.01', // 'remaining_volume': '0.01', // 'reserved_fee': '0.0015', // 'remaining_fee': '0.0015', // 'paid_fee': '0.0', // 'locked': '1.0015', // 'executed_volume': '0.0', // 'trades_count': 0 // } // return this.parseOrder (response); } async cancelOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); const request = { 'uuid': id, }; const response = await this.privateDeleteOrder (this.extend (request, params)); // // { // "uuid": "cdd92199-2897-4e14-9448-f923320408ad", // "side": "bid", // "ord_type": "limit", // "price": "100.0", // "state": "wait", // "market": "KRW-BTC", // "created_at": "2018-04-10T15:42:23+09:00", // "volume": "0.01", // "remaining_volume": "0.01", // "reserved_fee": "0.0015", // "remaining_fee": "0.0015", // "paid_fee": "0.0", // "locked": "1.0015", // "executed_volume": "0.0", // "trades_count": 0 // } // return this.parseOrder (response); } async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const request = { // 'page': 1, // 'order_by': 'asc', // 'desc' }; let currency = undefined; if (code !== undefined) { currency = this.currency (code); request['currency'] = currency['id']; } if (limit !== undefined) { request['limit'] = limit; // default is 100 } const response = await this.privateGetDeposits (this.extend (request, params)); // // [ // { // "type": "deposit", // "uuid": "94332e99-3a87-4a35-ad98-28b0c969f830", // "currency": "KRW", // "txid": "9e37c537-6849-4c8b-a134-57313f5dfc5a", // "state": "ACCEPTED", // "created_at": "2017-12-08T15:38:02+09:00", // "done_at": "2017-12-08T15:38:02+09:00", // "amount": "100000.0", // "fee": "0.0" // }, // ..., // ] // return this.parseTransactions (response, currency, since, limit); } async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const request = { // 'state': 'submitting', // 'submitted', 'almost_accepted', 'rejected', 'accepted', 'processing', 'done', 'canceled' }; let currency = undefined; if (code !== undefined) { currency = this.currency (code); request['currency'] = currency['id']; } if (limit !== undefined) { request['limit'] = limit; // default is 100 } const response = await this.privateGetWithdraws (this.extend (request, params)); // // [ // { // "type": "withdraw", // "uuid": "9f432943-54e0-40b7-825f-b6fec8b42b79", // "currency": "BTC", // "txid": null, // "state": "processing", // "created_at": "2018-04-13T11:24:01+09:00", // "done_at": null, // "amount": "0.01", // "fee": "0.0", // "krw_amount": "80420.0" // }, // ..., // ] // return this.parseTransactions (response, currency, since, limit); } parseTransactionStatus (status) { const statuses = { 'submitting': 'pending', // 처리 중 'submitted': 'pending', // 처리 완료 'almost_accepted': 'pending', // 출금대기중 'rejected': 'failed', // 거부 'accepted': 'pending', // 승인됨 'processing': 'pending', // 처리 중 'done': 'ok', // 완료 'canceled': 'canceled', // 취소됨 }; return this.safeString (statuses, status, status); } parseTransaction (transaction, currency = undefined) { // // fetchDeposits // // { // "type": "deposit", // "uuid": "94332e99-3a87-4a35-ad98-28b0c969f830", // "currency": "KRW", // "txid": "9e37c537-6849-4c8b-a134-57313f5dfc5a", // "state": "ACCEPTED", // "created_at": "2017-12-08T15:38:02+09:00", // "done_at": "2017-12-08T15:38:02+09:00", // "amount": "100000.0", // "fee": "0.0" // } // // fetchWithdrawals // // { // "type": "withdraw", // "uuid": "9f432943-54e0-40b7-825f-b6fec8b42b79", // "currency": "BTC", // "txid": "cd81e9b45df8da29f936836e58c907a106057e454a45767a7b06fcb19b966bba", // "state": "processing", // "created_at": "2018-04-13T11:24:01+09:00", // "done_at": null, // "amount": "0.01", // "fee": "0.0", // "krw_amount": "80420.0" // } // const id = this.safeString (transaction, 'uuid'); const amount = this.safeNumber (transaction, 'amount'); const address = undefined; // not present in the data structure received from the exchange const tag = undefined; // not present in the data structure received from the exchange const txid = this.safeString (transaction, 'txid'); const updated = this.parse8601 (this.safeString (transaction, 'done_at')); const timestamp = this.parse8601 (this.safeString (transaction, 'created_at', updated)); let type = this.safeString (transaction, 'type'); if (type === 'withdraw') { type = 'withdrawal'; } const currencyId = this.safeString (transaction, 'currency'); const code = this.safeCurrencyCode (currencyId); const status = this.parseTransactionStatus (this.safeStringLower (transaction, 'state')); const feeCost = this.safeNumber (transaction, 'fee'); return { 'info': transaction, 'id': id, 'currency': code, 'amount': amount, 'address': address, 'tag': tag, 'status': status, 'type': type, 'updated': updated, 'txid': txid, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'fee': { 'currency': code, 'cost': feeCost, }, }; } parseOrderStatus (status) { const statuses = { 'wait': 'open', 'done': 'closed', 'cancel': 'canceled', }; return this.safeString (statuses, status, status); } parseOrder (order, market = undefined) { // // { // "uuid": "a08f09b1-1718-42e2-9358-f0e5e083d3ee", // "side": "bid", // "ord_type": "limit", // "price": "17417000.0", // "state": "done", // "market": "KRW-BTC", // "created_at": "2018-04-05T14:09:14+09:00", // "volume": "1.0", // "remaining_volume": "0.0", // "reserved_fee": "26125.5", // "remaining_fee": "25974.0", // "paid_fee": "151.5", // "locked": "17341974.0", // "executed_volume": "1.0", // "trades_count": 2, // "trades": [ // { // "market": "KRW-BTC", // "uuid": "78162304-1a4d-4524-b9e6-c9a9e14d76c3", // "price": "101000.0", // "volume": "0.77368323", // "funds": "78142.00623", // "ask_fee": "117.213009345", // "bid_fee": "117.213009345", // "created_at": "2018-04-05T14:09:15+09:00", // "side": "bid", // }, // { // "market": "KRW-BTC", // "uuid": "f73da467-c42f-407d-92fa-e10d86450a20", // "price": "101000.0", // "volume": "0.22631677", // "funds": "22857.99377", // "ask_fee": "34.286990655", // missing in market orders // "bid_fee": "34.286990655", // missing in market orders // "created_at": "2018-04-05T14:09:15+09:00", // missing in market orders // "side": "bid", // }, // ], // } // const id = this.safeString (order, 'uuid'); let side = this.safeString (order, 'side'); if (side === 'bid') { side = 'buy'; } else { side = 'sell'; } let type = this.safeString (order, 'ord_type'); const timestamp = this.parse8601 (this.safeString (order, 'created_at')); const status = this.parseOrderStatus (this.safeString (order, 'state')); let lastTradeTimestamp = undefined; let price = this.safeNumber (order, 'price'); const amount = this.safeNumber (order, 'volume'); const remaining = this.safeNumber (order, 'remaining_volume'); const filled = this.safeNumber (order, 'executed_volume'); let cost = undefined; if (type === 'price') { type = 'market'; cost = price; price = undefined; } let average = undefined; let fee = undefined; let feeCost = this.safeNumber (order, 'paid_fee'); const marketId = this.safeString (order, 'market'); market = this.safeMarket (marketId, market); let trades = this.safeValue (order, 'trades', []); trades = this.parseTrades (trades, market, undefined, undefined, { 'order': id, 'type': type, }); const numTrades = trades.length; if (numTrades > 0) { // the timestamp in fetchOrder trades is missing lastTradeTimestamp = trades[numTrades - 1]['timestamp']; let getFeesFromTrades = false; if (feeCost === undefined) { getFeesFromTrades = true; feeCost = 0; } cost = 0; for (let i = 0; i < numTrades; i++) { const trade = trades[i]; cost = this.sum (cost, trade['cost']); if (getFeesFromTrades) { const tradeFee = this.safeValue (trades[i], 'fee', {}); const tradeFeeCost = this.safeNumber (tradeFee, 'cost'); if (tradeFeeCost !== undefined) { feeCost = this.sum (feeCost, tradeFeeCost); }