UNPKG

@proton/ccxt

Version:

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

994 lines (991 loc) 41.6 kB
// ---------------------------------------------------------------------------- // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN: // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code // EDIT THE CORRESPONDENT .ts FILE INSTEAD // --------------------------------------------------------------------------- import Exchange from './abstract/bitflyer.js'; import { ExchangeError, ArgumentsRequired, OrderNotFound } from './base/errors.js'; import { TICK_SIZE } from './base/functions/number.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; // --------------------------------------------------------------------------- export default class bitflyer extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'bitflyer', 'name': 'bitFlyer', 'countries': ['JP'], 'version': 'v1', 'rateLimit': 1000, 'hostname': 'bitflyer.com', 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': undefined, 'future': undefined, 'option': false, 'cancelOrder': true, 'createOrder': true, 'fetchBalance': true, 'fetchClosedOrders': 'emulated', 'fetchDeposits': true, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMyTrades': true, 'fetchOpenOrders': 'emulated', 'fetchOrder': 'emulated', 'fetchOrderBook': true, 'fetchOrders': true, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchTicker': true, 'fetchTrades': true, 'fetchTradingFee': true, 'fetchTradingFees': false, 'fetchTransfer': false, 'fetchTransfers': false, 'fetchWithdrawals': true, 'transfer': false, 'withdraw': true, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/28051642-56154182-660e-11e7-9b0d-6042d1e6edd8.jpg', 'api': { 'rest': 'https://api.{hostname}', }, 'www': 'https://bitflyer.com', 'doc': 'https://lightning.bitflyer.com/docs?lang=en', }, 'api': { 'public': { 'get': [ 'getmarkets/usa', 'getmarkets/eu', 'getmarkets', 'getboard', 'getticker', 'getexecutions', 'gethealth', 'getboardstate', 'getchats', ], }, 'private': { 'get': [ 'getpermissions', 'getbalance', 'getbalancehistory', 'getcollateral', 'getcollateralhistory', 'getcollateralaccounts', 'getaddresses', 'getcoinins', 'getcoinouts', 'getbankaccounts', 'getdeposits', 'getwithdrawals', 'getchildorders', 'getparentorders', 'getparentorder', 'getexecutions', 'getpositions', 'gettradingcommission', ], 'post': [ 'sendcoin', 'withdraw', 'sendchildorder', 'cancelchildorder', 'sendparentorder', 'cancelparentorder', 'cancelallchildorders', ], }, }, 'fees': { 'trading': { 'maker': this.parseNumber('0.002'), 'taker': this.parseNumber('0.002'), }, }, 'precisionMode': TICK_SIZE, }); } parseExpiryDate(expiry) { const day = expiry.slice(0, 2); const monthName = expiry.slice(2, 5); const year = expiry.slice(5, 9); const months = { 'JAN': '01', 'FEB': '02', 'MAR': '03', 'APR': '04', 'MAY': '05', 'JUN': '06', 'JUL': '07', 'AUG': '08', 'SEP': '09', 'OCT': '10', 'NOV': '11', 'DEC': '12', }; const month = this.safeString(months, monthName); return this.parse8601(year + '-' + month + '-' + day + 'T00:00:00Z'); } safeMarket(marketId = undefined, market = undefined, delimiter = undefined, marketType = undefined) { // Bitflyer has a different type of conflict in markets, because // some of their ids (ETH/BTC and BTC/JPY) are duplicated in US, EU and JP. // Since they're the same we just need to return one return super.safeMarket(marketId, market, delimiter, 'spot'); } async fetchMarkets(params = {}) { /** * @method * @name bitflyer#fetchMarkets * @description retrieves data on all markets for bitflyer * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ const jp_markets = await this.publicGetGetmarkets(params); // // [ // // spot // { "product_code": "BTC_JPY", "market_type": "Spot" }, // { "product_code": "BCH_BTC", "market_type": "Spot" }, // // forex swap // { "product_code": "FX_BTC_JPY", "market_type": "FX" }, // // future // { // "product_code": "BTCJPY11FEB2022", // "alias": "BTCJPY_MAT1WK", // "market_type": "Futures", // }, // ]; // const us_markets = await this.publicGetGetmarketsUsa(params); // // [ // { "product_code": "BTC_USD", "market_type": "Spot" }, // { "product_code": "BTC_JPY", "market_type": "Spot" }, // ]; // const eu_markets = await this.publicGetGetmarketsEu(params); // // [ // { "product_code": "BTC_EUR", "market_type": "Spot" }, // { "product_code": "BTC_JPY", "market_type": "Spot" }, // ]; // let markets = this.arrayConcat(jp_markets, us_markets); markets = this.arrayConcat(markets, eu_markets); const result = []; for (let i = 0; i < markets.length; i++) { const market = markets[i]; const id = this.safeString(market, 'product_code'); const currencies = id.split('_'); const marketType = this.safeString(market, 'market_type'); const swap = (marketType === 'FX'); const future = (marketType === 'Futures'); const spot = !swap && !future; let type = 'spot'; let settle = undefined; let baseId = undefined; let quoteId = undefined; let expiry = undefined; if (spot) { baseId = this.safeString(currencies, 0); quoteId = this.safeString(currencies, 1); } else if (swap) { type = 'swap'; baseId = this.safeString(currencies, 1); quoteId = this.safeString(currencies, 2); } else if (future) { const alias = this.safeString(market, 'alias'); if (alias === undefined) { // no alias: // { product_code: 'BTCJPY11MAR2022', market_type: 'Futures' } // TODO this will break if there are products with 4 chars baseId = id.slice(0, 3); quoteId = id.slice(3, 6); // last 9 chars are expiry date const expiryDate = id.slice(-9); expiry = this.parseExpiryDate(expiryDate); } else { const splitAlias = alias.split('_'); const currencyIds = this.safeString(splitAlias, 0); baseId = currencyIds.slice(0, -3); quoteId = currencyIds.slice(-3); const splitId = id.split(currencyIds); const expiryDate = this.safeString(splitId, 1); expiry = this.parseExpiryDate(expiryDate); } type = 'future'; } const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); let symbol = base + '/' + quote; let taker = this.fees['trading']['taker']; let maker = this.fees['trading']['maker']; const contract = swap || future; if (contract) { maker = 0.0; taker = 0.0; settle = 'JPY'; symbol = symbol + ':' + settle; if (future) { symbol = symbol + '-' + this.yymmdd(expiry); } } result.push({ 'id': id, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': undefined, 'type': type, 'spot': spot, 'margin': false, 'swap': swap, 'future': future, 'option': false, 'active': true, 'contract': contract, 'linear': spot ? undefined : true, 'inverse': spot ? undefined : false, 'taker': taker, 'maker': maker, 'contractSize': undefined, 'expiry': expiry, 'expiryDatetime': this.iso8601(expiry), 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': undefined, 'price': undefined, }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': undefined, 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'info': market, }); } return result; } parseBalance(response) { const result = { 'info': response }; for (let i = 0; i < response.length; i++) { const balance = response[i]; const currencyId = this.safeString(balance, 'currency_code'); const code = this.safeCurrencyCode(currencyId); const account = this.account(); account['total'] = this.safeString(balance, 'amount'); account['free'] = this.safeString(balance, 'available'); result[code] = account; } return this.safeBalance(result); } async fetchBalance(params = {}) { /** * @method * @name bitflyer#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 bitflyer 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.privateGetGetbalance(params); // // [ // { // "currency_code": "JPY", // "amount": 1024078, // "available": 508000 // }, // { // "currency_code": "BTC", // "amount": 10.24, // "available": 4.12 // }, // { // "currency_code": "ETH", // "amount": 20.48, // "available": 16.38 // } // ] // return this.parseBalance(response); } async fetchOrderBook(symbol, limit = undefined, params = {}) { /** * @method * @name bitflyer#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 bitflyer api endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'product_code': market['id'], }; const orderbook = await this.publicGetGetboard(this.extend(request, params)); return this.parseOrderBook(orderbook, market['symbol'], undefined, 'bids', 'asks', 'price', 'size'); } parseTicker(ticker, market = undefined) { const symbol = this.safeSymbol(undefined, market); const timestamp = this.parse8601(this.safeString(ticker, 'timestamp')); const last = this.safeString(ticker, 'ltp'); return this.safeTicker({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'high': undefined, 'low': undefined, 'bid': this.safeString(ticker, 'best_bid'), 'bidVolume': undefined, 'ask': this.safeString(ticker, 'best_ask'), 'askVolume': undefined, 'vwap': undefined, 'open': undefined, 'close': last, 'last': last, 'previousClose': undefined, 'change': undefined, 'percentage': undefined, 'average': undefined, 'baseVolume': this.safeString(ticker, 'volume_by_product'), 'quoteVolume': undefined, 'info': ticker, }, market); } async fetchTicker(symbol, params = {}) { /** * @method * @name bitflyer#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 bitflyer api endpoint * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'product_code': market['id'], }; const response = await this.publicGetGetticker(this.extend(request, params)); return this.parseTicker(response, market); } parseTrade(trade, market = undefined) { // // fetchTrades (public) v1 // // { // "id":2278466664, // "side":"SELL", // "price":56810.7, // "size":0.08798, // "exec_date":"2021-11-19T11:46:39.323", // "buy_child_order_acceptance_id":"JRF20211119-114209-236525", // "sell_child_order_acceptance_id":"JRF20211119-114639-236919" // } // // { // "id":2278463423, // "side":"BUY", // "price":56757.83, // "size":0.6003,"exec_date":"2021-11-19T11:28:00.523", // "buy_child_order_acceptance_id":"JRF20211119-112800-236526", // "sell_child_order_acceptance_id":"JRF20211119-112734-062017" // } // // // let side = this.safeStringLower(trade, 'side'); if (side !== undefined) { if (side.length < 1) { side = undefined; } } let order = undefined; if (side !== undefined) { const idInner = side + '_child_order_acceptance_id'; if (idInner in trade) { order = trade[idInner]; } } if (order === undefined) { order = this.safeString(trade, 'child_order_acceptance_id'); } const timestamp = this.parse8601(this.safeString(trade, 'exec_date')); const priceString = this.safeString(trade, 'price'); const amountString = this.safeString(trade, 'size'); const id = this.safeString(trade, 'id'); market = this.safeMarket(undefined, market); return this.safeTrade({ 'id': id, 'info': trade, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': market['symbol'], 'order': order, 'type': undefined, 'side': side, 'takerOrMaker': undefined, 'price': priceString, 'amount': amountString, 'cost': undefined, 'fee': undefined, }, market); } async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name bitflyer#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 bitflyer 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 = { 'product_code': market['id'], }; if (limit !== undefined) { request['count'] = limit; } const response = await this.publicGetGetexecutions(this.extend(request, params)); return this.parseTrades(response, market, since, limit); } async fetchTradingFee(symbol, params = {}) { /** * @method * @name bitflyer#fetchTradingFee * @description fetch the trading fees for a market * @param {string} symbol unified market symbol * @param {object} params extra parameters specific to the bitflyer api endpoint * @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure} */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'product_code': market['id'], }; const response = await this.privateGetGettradingcommission(this.extend(request, params)); // // { // commission_rate: '0.0020' // } // const fee = this.safeNumber(response, 'commission_rate'); return { 'info': response, 'symbol': market['symbol'], 'maker': fee, 'taker': fee, }; } async createOrder(symbol, type, side, amount, price = undefined, params = {}) { /** * @method * @name bitflyer#createOrder * @description create a trade order * @param {string} symbol unified symbol of the market to create an order in * @param {string} type 'market' or 'limit' * @param {string} side 'buy' or 'sell' * @param {float} amount how much of currency you want to trade in units of base currency * @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders * @param {object} params extra parameters specific to the bitflyer api endpoint * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); const request = { 'product_code': this.marketId(symbol), 'child_order_type': type.toUpperCase(), 'side': side.toUpperCase(), 'price': price, 'size': amount, }; const result = await this.privatePostSendchildorder(this.extend(request, params)); // { "status": - 200, "error_message": "Insufficient funds", "data": null } const id = this.safeString(result, 'child_order_acceptance_id'); return this.safeOrder({ 'id': id, 'info': result, }); } async cancelOrder(id, symbol = undefined, params = {}) { /** * @method * @name bitflyer#cancelOrder * @description cancels an open order * @param {string} id order id * @param {string} symbol unified symbol of the market the order was made in * @param {object} params extra parameters specific to the bitflyer api endpoint * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ if (symbol === undefined) { throw new ArgumentsRequired(this.id + ' cancelOrder() requires a `symbol` argument'); } await this.loadMarkets(); const request = { 'product_code': this.marketId(symbol), 'child_order_acceptance_id': id, }; return await this.privatePostCancelchildorder(this.extend(request, params)); } parseOrderStatus(status) { const statuses = { 'ACTIVE': 'open', 'COMPLETED': 'closed', 'CANCELED': 'canceled', 'EXPIRED': 'canceled', 'REJECTED': 'canceled', }; return this.safeString(statuses, status, status); } parseOrder(order, market = undefined) { const timestamp = this.parse8601(this.safeString(order, 'child_order_date')); const price = this.safeString(order, 'price'); const amount = this.safeString(order, 'size'); const filled = this.safeString(order, 'executed_size'); const remaining = this.safeString(order, 'outstanding_size'); const status = this.parseOrderStatus(this.safeString(order, 'child_order_state')); const type = this.safeStringLower(order, 'child_order_type'); const side = this.safeStringLower(order, 'side'); const marketId = this.safeString(order, 'product_code'); const symbol = this.safeSymbol(marketId, market); let fee = undefined; const feeCost = this.safeNumber(order, 'total_commission'); if (feeCost !== undefined) { fee = { 'cost': feeCost, 'currency': undefined, 'rate': undefined, }; } const id = this.safeString(order, 'child_order_acceptance_id'); return this.safeOrder({ 'id': id, 'clientOrderId': undefined, 'info': order, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'lastTradeTimestamp': undefined, 'status': status, 'symbol': symbol, 'type': type, 'timeInForce': undefined, 'postOnly': undefined, 'side': side, 'price': price, 'stopPrice': undefined, 'triggerPrice': undefined, 'cost': undefined, 'amount': amount, 'filled': filled, 'remaining': remaining, 'fee': fee, 'average': undefined, 'trades': undefined, }, market); } async fetchOrders(symbol = undefined, since = undefined, limit = 100, params = {}) { /** * @method * @name bitflyer#fetchOrders * @description fetches information on multiple orders made by the user * @param {string} symbol unified market symbol of the market orders were made in * @param {int|undefined} since the earliest time in ms to fetch orders for * @param {int|undefined} limit the maximum number of orde structures to retrieve * @param {object} params extra parameters specific to the bitflyer api endpoint * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ if (symbol === undefined) { throw new ArgumentsRequired(this.id + ' fetchOrders() requires a `symbol` argument'); } await this.loadMarkets(); const market = this.market(symbol); const request = { 'product_code': market['id'], 'count': limit, }; const response = await this.privateGetGetchildorders(this.extend(request, params)); let orders = this.parseOrders(response, market, since, limit); if (symbol !== undefined) { orders = this.filterBy(orders, 'symbol', symbol); } return orders; } async fetchOpenOrders(symbol = undefined, since = undefined, limit = 100, params = {}) { /** * @method * @name bitflyer#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 bitflyer api endpoint * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ const request = { 'child_order_state': 'ACTIVE', }; return await this.fetchOrders(symbol, since, limit, this.extend(request, params)); } async fetchClosedOrders(symbol = undefined, since = undefined, limit = 100, params = {}) { /** * @method * @name bitflyer#fetchClosedOrders * @description fetches information on multiple closed orders made by the user * @param {string|undefined} symbol unified market symbol of the market orders were made in * @param {int|undefined} since the earliest time in ms to fetch orders for * @param {int|undefined} limit the maximum number of orde structures to retrieve * @param {object} params extra parameters specific to the bitflyer api endpoint * @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ const request = { 'child_order_state': 'COMPLETED', }; return await this.fetchOrders(symbol, since, limit, this.extend(request, params)); } async fetchOrder(id, symbol = undefined, params = {}) { /** * @method * @name bitflyer#fetchOrder * @description fetches information on an order made by the user * @param {string} symbol unified symbol of the market the order was made in * @param {object} params extra parameters specific to the bitflyer api endpoint * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ if (symbol === undefined) { throw new ArgumentsRequired(this.id + ' fetchOrder() requires a `symbol` argument'); } const orders = await this.fetchOrders(symbol); const ordersById = this.indexBy(orders, 'id'); if (id in ordersById) { return ordersById[id]; } throw new OrderNotFound(this.id + ' No order found with id ' + id); } async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name bitflyer#fetchMyTrades * @description fetch all trades made by the user * @param {string} 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 bitflyer api endpoint * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} */ if (symbol === undefined) { throw new ArgumentsRequired(this.id + ' fetchMyTrades() requires a `symbol` argument'); } await this.loadMarkets(); const market = this.market(symbol); const request = { 'product_code': market['id'], }; if (limit !== undefined) { request['count'] = limit; } const response = await this.privateGetGetexecutions(this.extend(request, params)); return this.parseTrades(response, market, since, limit); } async fetchPositions(symbols = undefined, params = {}) { /** * @method * @name bitflyer#fetchPositions * @description fetch all open positions * @param {[string]} symbols list of unified market symbols * @param {object} params extra parameters specific to the bitflyer api endpoint * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure} */ if (symbols === undefined) { throw new ArgumentsRequired(this.id + ' fetchPositions() requires a `symbols` argument, exactly one symbol in an array'); } await this.loadMarkets(); const request = { 'product_code': this.marketIds(symbols), }; const response = await this.privateGetGetpositions(this.extend(request, params)); // // [ // { // "product_code": "FX_BTC_JPY", // "side": "BUY", // "price": 36000, // "size": 10, // "commission": 0, // "swap_point_accumulate": -35, // "require_collateral": 120000, // "open_date": "2015-11-03T10:04:45.011", // "leverage": 3, // "pnl": 965, // "sfd": -0.5 // } // ] // // todo unify parsePosition/parsePositions return response; } async withdraw(code, amount, address, tag = undefined, params = {}) { /** * @method * @name bitflyer#withdraw * @description make a withdrawal * @param {string} code unified currency code * @param {float} amount the amount to withdraw * @param {string} address the address to withdraw to * @param {string|undefined} tag * @param {object} params extra parameters specific to the bitflyer api endpoint * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure} */ this.checkAddress(address); await this.loadMarkets(); if (code !== 'JPY' && code !== 'USD' && code !== 'EUR') { throw new ExchangeError(this.id + ' allows withdrawing JPY, USD, EUR only, ' + code + ' is not supported'); } const currency = this.currency(code); const request = { 'currency_code': currency['id'], 'amount': amount, // 'bank_account_id': 1234, }; const response = await this.privatePostWithdraw(this.extend(request, params)); // // { // "message_id": "69476620-5056-4003-bcbe-42658a2b041b" // } // return this.parseTransaction(response, currency); } async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name bitflyer#fetchDeposits * @description fetch all deposits made to an account * @param {string|undefined} code unified currency code * @param {int|undefined} since the earliest time in ms to fetch deposits for * @param {int|undefined} limit the maximum number of deposits structures to retrieve * @param {object} params extra parameters specific to the bitflyer api endpoint * @returns {[object]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} */ await this.loadMarkets(); let currency = undefined; const request = {}; if (code !== undefined) { currency = this.currency(code); } if (limit !== undefined) { request['count'] = limit; // default 100 } const response = await this.privateGetGetcoinins(this.extend(request, params)); // // [ // { // "id": 100, // "order_id": "CDP20151227-024141-055555", // "currency_code": "BTC", // "amount": 0.00002, // "address": "1WriteySQufKZ2pVuM1oMhPrTtTVFq35j", // "tx_hash": "9f92ee65a176bb9545f7becb8706c50d07d4cee5ffca34d8be3ef11d411405ae", // "status": "COMPLETED", // "event_date": "2015-11-27T08:59:20.301" // } // ] // return this.parseTransactions(response, currency, since, limit); } async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name bitflyer#fetchWithdrawals * @description fetch all withdrawals made from an account * @param {string|undefined} code unified currency code * @param {int|undefined} since the earliest time in ms to fetch withdrawals for * @param {int|undefined} limit the maximum number of withdrawals structures to retrieve * @param {object} params extra parameters specific to the bitflyer api endpoint * @returns {[object]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure} */ await this.loadMarkets(); let currency = undefined; const request = {}; if (code !== undefined) { currency = this.currency(code); } if (limit !== undefined) { request['count'] = limit; // default 100 } const response = await this.privateGetGetcoinouts(this.extend(request, params)); // // [ // { // "id": 500, // "order_id": "CWD20151224-014040-077777", // "currency_code": "BTC", // "amount": 0.1234, // "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", // "tx_hash": "724c07dfd4044abcb390b0412c3e707dd5c4f373f0a52b3bd295ce32b478c60a", // "fee": 0.0005, // "additional_fee": 0.0001, // "status": "COMPLETED", // "event_date": "2015-12-24T01:40:40.397" // } // ] // return this.parseTransactions(response, currency, since, limit); } parseDepositStatus(status) { const statuses = { 'PENDING': 'pending', 'COMPLETED': 'ok', }; return this.safeString(statuses, status, status); } parseWithdrawalStatus(status) { const statuses = { 'PENDING': 'pending', 'COMPLETED': 'ok', }; return this.safeString(statuses, status, status); } parseTransaction(transaction, currency = undefined) { // // fetchDeposits // // { // "id": 100, // "order_id": "CDP20151227-024141-055555", // "currency_code": "BTC", // "amount": 0.00002, // "address": "1WriteySQufKZ2pVuM1oMhPrTtTVFq35j", // "tx_hash": "9f92ee65a176bb9545f7becb8706c50d07d4cee5ffca34d8be3ef11d411405ae", // "status": "COMPLETED", // "event_date": "2015-11-27T08:59:20.301" // } // // fetchWithdrawals // // { // "id": 500, // "order_id": "CWD20151224-014040-077777", // "currency_code": "BTC", // "amount": 0.1234, // "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", // "tx_hash": "724c07dfd4044abcb390b0412c3e707dd5c4f373f0a52b3bd295ce32b478c60a", // "fee": 0.0005, // "additional_fee": 0.0001, // "status": "COMPLETED", // "event_date": "2015-12-24T01:40:40.397" // } // // withdraw // // { // "message_id": "69476620-5056-4003-bcbe-42658a2b041b" // } // const id = this.safeString2(transaction, 'id', 'message_id'); const address = this.safeString(transaction, 'address'); const currencyId = this.safeString(transaction, 'currency_code'); const code = this.safeCurrencyCode(currencyId, currency); const timestamp = this.parse8601(this.safeString(transaction, 'event_date')); const amount = this.safeNumber(transaction, 'amount'); const txId = this.safeString(transaction, 'tx_hash'); const rawStatus = this.safeString(transaction, 'status'); let type = undefined; let status = undefined; let fee = undefined; if ('fee' in transaction) { type = 'withdrawal'; status = this.parseWithdrawalStatus(rawStatus); const feeCost = this.safeNumber(transaction, 'fee'); const additionalFee = this.safeNumber(transaction, 'additional_fee'); fee = { 'currency': code, 'cost': feeCost + additionalFee }; } else { type = 'deposit'; status = this.parseDepositStatus(rawStatus); } return { 'info': transaction, 'id': id, 'txid': txId, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'network': undefined, 'address': address, 'addressTo': address, 'addressFrom': undefined, 'tag': undefined, 'tagTo': undefined, 'tagFrom': undefined, 'type': type, 'amount': amount, 'currency': code, 'status': status, 'updated': undefined, 'internal': undefined, 'fee': fee, }; } sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { let request = '/' + this.version + '/'; if (api === 'private') { request += 'me/'; } request += path; if (method === 'GET') { if (Object.keys(params).length) { request += '?' + this.urlencode(params); } } const baseUrl = this.implodeHostname(this.urls['api']['rest']); const url = baseUrl + request; if (api === 'private') { this.checkRequiredCredentials(); const nonce = this.nonce().toString(); let auth = [nonce, method, request].join(''); if (Object.keys(params).length) { if (method !== 'GET') { body = this.json(params); auth += body; } } headers = { 'ACCESS-KEY': this.apiKey, 'ACCESS-TIMESTAMP': nonce, 'ACCESS-SIGN': this.hmac(this.encode(auth), this.encode(this.secret), sha256), 'Content-Type': 'application/json', }; } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } }