ccxt
Version:
1,161 lines (1,159 loc) • 60.9 kB
JavaScript
// ----------------------------------------------------------------------------
// 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/indodax.js';
import { ExchangeError, ArgumentsRequired, InsufficientFunds, InvalidOrder, OrderNotFound, AuthenticationError, BadSymbol } from './base/errors.js';
import { TICK_SIZE } from './base/functions/number.js';
import { Precise } from './base/Precise.js';
import { sha512 } from './static_dependencies/noble-hashes/sha512.js';
// ---------------------------------------------------------------------------
/**
* @class indodax
* @augments Exchange
*/
export default class indodax extends Exchange {
describe() {
return this.deepExtend(super.describe(), {
'id': 'indodax',
'name': 'INDODAX',
'countries': ['ID'],
// 10 requests per second for making trades => 1000ms / 10 = 100ms
// 180 requests per minute (public endpoints) = 2 requests per second => cost = (1000ms / rateLimit) / 2 = 5
'rateLimit': 50,
'has': {
'CORS': undefined,
'spot': true,
'margin': false,
'swap': false,
'future': false,
'option': false,
'addMargin': false,
'cancelAllOrders': false,
'cancelOrder': true,
'cancelOrders': false,
'closeAllPositions': false,
'closePosition': false,
'createDepositAddress': false,
'createOrder': true,
'createReduceOnlyOrder': false,
'createStopLimitOrder': false,
'createStopMarketOrder': false,
'createStopOrder': false,
'fetchBalance': true,
'fetchBorrowRateHistories': false,
'fetchBorrowRateHistory': false,
'fetchClosedOrders': true,
'fetchCrossBorrowRate': false,
'fetchCrossBorrowRates': false,
'fetchDeposit': false,
'fetchDepositAddress': 'emulated',
'fetchDepositAddresses': true,
'fetchDepositAddressesByNetwork': false,
'fetchDeposits': false,
'fetchDepositsWithdrawals': true,
'fetchFundingHistory': false,
'fetchFundingRate': false,
'fetchFundingRateHistory': false,
'fetchFundingRates': false,
'fetchIndexOHLCV': false,
'fetchIsolatedBorrowRate': false,
'fetchIsolatedBorrowRates': false,
'fetchLeverage': false,
'fetchLeverageTiers': false,
'fetchMarginMode': false,
'fetchMarkets': true,
'fetchMarkOHLCV': false,
'fetchOpenInterestHistory': false,
'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrders': false,
'fetchPosition': false,
'fetchPositionHistory': false,
'fetchPositionMode': false,
'fetchPositions': false,
'fetchPositionsForSymbol': false,
'fetchPositionsHistory': false,
'fetchPositionsRisk': false,
'fetchPremiumIndexOHLCV': false,
'fetchTicker': true,
'fetchTime': true,
'fetchTrades': true,
'fetchTradingFee': false,
'fetchTradingFees': false,
'fetchTransactionFee': true,
'fetchTransactionFees': false,
'fetchTransactions': 'emulated',
'fetchTransfer': false,
'fetchTransfers': false,
'fetchWithdrawal': false,
'fetchWithdrawals': false,
'reduceMargin': false,
'setLeverage': false,
'setMargin': false,
'setMarginMode': false,
'setPositionMode': false,
'transfer': false,
'withdraw': true,
},
'version': '2.0',
'urls': {
'logo': 'https://user-images.githubusercontent.com/51840849/87070508-9358c880-c221-11ea-8dc5-5391afbbb422.jpg',
'api': {
'public': 'https://indodax.com',
'private': 'https://indodax.com/tapi',
},
'www': 'https://www.indodax.com',
'doc': 'https://github.com/btcid/indodax-official-api-docs',
'referral': 'https://indodax.com/ref/testbitcoincoid/1',
},
'api': {
'public': {
'get': {
'api/server_time': 5,
'api/pairs': 5,
'api/price_increments': 5,
'api/summaries': 5,
'api/ticker/{pair}': 5,
'api/ticker_all': 5,
'api/trades/{pair}': 5,
'api/depth/{pair}': 5,
'tradingview/history_v2': 5,
},
},
'private': {
'post': {
'getInfo': 4,
'transHistory': 4,
'trade': 1,
'tradeHistory': 4,
'openOrders': 4,
'orderHistory': 4,
'getOrder': 4,
'cancelOrder': 4,
'withdrawFee': 4,
'withdrawCoin': 4,
'listDownline': 4,
'checkDownline': 4,
'createVoucher': 4, // partner only
},
},
},
'fees': {
'trading': {
'tierBased': false,
'percentage': true,
'maker': 0,
'taker': 0.003,
},
},
'exceptions': {
'exact': {
'invalid_pair': BadSymbol,
'Insufficient balance.': InsufficientFunds,
'invalid order.': OrderNotFound,
'Invalid credentials. API not found or session has expired.': AuthenticationError,
'Invalid credentials. Bad sign.': AuthenticationError,
},
'broad': {
'Minimum price': InvalidOrder,
'Minimum order': InvalidOrder,
},
},
// exchange-specific options
'options': {
'recvWindow': 5 * 1000,
'timeDifference': 0,
'adjustForTimeDifference': false,
'networks': {
'XLM': 'Stellar Token',
'BSC': 'bep20',
'TRC20': 'trc20',
'MATIC': 'polygon',
// 'BEP2': 'bep2',
// 'ARB': 'arb',
// 'ERC20': 'erc20',
// 'KIP7': 'kip7',
// 'MAINNET': 'mainnet', // TODO: does mainnet just mean the default?
// 'OEP4': 'oep4',
// 'OP': 'op',
// 'SPL': 'spl',
// 'TRC10': 'trc10',
// 'ZRC2': 'zrc2'
// 'ETH': 'eth'
// 'BASE': 'base'
},
'timeframes': {
'1m': '1',
'15m': '15',
'30m': '30',
'1h': '60',
'4h': '240',
'1d': '1D',
'3d': '3D',
'1w': '1W',
},
},
'features': {
'spot': {
'sandbox': false,
'createOrder': {
'marginMode': false,
'triggerPrice': false,
'triggerPriceType': undefined,
'triggerDirection': false,
'stopLossPrice': false,
'takeProfitPrice': false,
'attachedStopLossTakeProfit': undefined,
'timeInForce': {
'IOC': true,
'FOK': false,
'PO': false,
'GTD': false,
},
'hedged': false,
'selfTradePrevention': false,
'trailing': false,
'leverage': false,
'marketBuyByCost': false,
'marketBuyRequiresPrice': false,
'iceberg': false,
},
'createOrders': undefined,
'fetchMyTrades': undefined,
'fetchOrder': {
'marginMode': false,
'trigger': false,
'trailing': false,
'symbolRequired': true,
},
'fetchOpenOrders': {
'marginMode': false,
'limit': undefined,
'trigger': false,
'trailing': false,
'symbolRequired': false,
},
'fetchOrders': undefined,
'fetchClosedOrders': {
'marginMode': false,
'limit': 1000,
'daysBack': 100000,
'daysBackCanceled': 1,
'untilDays': undefined,
'trigger': false,
'trailing': false,
'symbolRequired': true,
},
'fetchOHLCV': {
'limit': 2000, // todo: not in request
},
},
'swap': {
'linear': undefined,
'inverse': undefined,
},
'future': {
'linear': undefined,
'inverse': undefined,
},
},
'commonCurrencies': {
'STR': 'XLM',
'BCHABC': 'BCH',
'BCHSV': 'BSV',
'DRK': 'DASH',
'NEM': 'XEM',
},
'precisionMode': TICK_SIZE,
});
}
nonce() {
return this.milliseconds() - this.options['timeDifference'];
}
/**
* @method
* @name indodax#fetchTime
* @description fetches the current integer timestamp in milliseconds from the exchange server
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Public-RestAPI.md#server-time
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {int} the current integer timestamp in milliseconds from the exchange server
*/
async fetchTime(params = {}) {
const response = await this.publicGetApiServerTime(params);
//
// {
// "timezone": "UTC",
// "server_time": 1571205969552
// }
//
return this.safeInteger(response, 'server_time');
}
/**
* @method
* @name indodax#fetchMarkets
* @description retrieves data on all markets for indodax
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Public-RestAPI.md#pairs
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object[]} an array of objects representing market data
*/
async fetchMarkets(params = {}) {
const response = await this.publicGetApiPairs(params);
//
// [
// {
// "id": "btcidr",
// "symbol": "BTCIDR",
// "base_currency": "idr",
// "traded_currency": "btc",
// "traded_currency_unit": "BTC",
// "description": "BTC/IDR",
// "ticker_id": "btc_idr",
// "volume_precision": 0,
// "price_precision": 1000,
// "price_round": 8,
// "pricescale": 1000,
// "trade_min_base_currency": 10000,
// "trade_min_traded_currency": 0.00007457,
// "has_memo": false,
// "memo_name": false,
// "has_payment_id": false,
// "trade_fee_percent": 0.3,
// "url_logo": "https://indodax.com/v2/logo/svg/color/btc.svg",
// "url_logo_png": "https://indodax.com/v2/logo/png/color/btc.png",
// "is_maintenance": 0
// }
// ]
//
const result = [];
for (let i = 0; i < response.length; i++) {
const market = response[i];
const id = this.safeString(market, 'ticker_id');
const baseId = this.safeString(market, 'traded_currency');
const quoteId = this.safeString(market, 'base_currency');
const base = this.safeCurrencyCode(baseId);
const quote = this.safeCurrencyCode(quoteId);
const isMaintenance = this.safeInteger(market, 'is_maintenance');
result.push({
'id': id,
'symbol': base + '/' + quote,
'base': base,
'quote': quote,
'settle': undefined,
'baseId': baseId,
'quoteId': quoteId,
'settleId': undefined,
'type': 'spot',
'spot': true,
'margin': false,
'swap': false,
'future': false,
'option': false,
'active': isMaintenance ? false : true,
'contract': false,
'linear': undefined,
'inverse': undefined,
'taker': this.safeNumber(market, 'trade_fee_percent'),
'contractSize': undefined,
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'percentage': true,
'precision': {
'amount': this.parseNumber('1e-8'),
'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'price_round'))),
'cost': this.parseNumber(this.parsePrecision(this.safeString(market, 'volume_precision'))),
},
'limits': {
'leverage': {
'min': undefined,
'max': undefined,
},
'amount': {
'min': this.safeNumber(market, 'trade_min_traded_currency'),
'max': undefined,
},
'price': {
'min': this.safeNumber(market, 'trade_min_base_currency'),
'max': undefined,
},
'cost': {
'min': undefined,
'max': undefined,
},
},
'created': undefined,
'info': market,
});
}
return result;
}
parseBalance(response) {
const balances = this.safeValue(response, 'return', {});
const free = this.safeValue(balances, 'balance', {});
const used = this.safeValue(balances, 'balance_hold', {});
const timestamp = this.safeTimestamp(balances, 'server_time');
const result = {
'info': response,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
};
const currencyIds = Object.keys(free);
for (let i = 0; i < currencyIds.length; i++) {
const currencyId = currencyIds[i];
const code = this.safeCurrencyCode(currencyId);
const account = this.account();
account['free'] = this.safeString(free, currencyId);
account['used'] = this.safeString(used, currencyId);
result[code] = account;
}
return this.safeBalance(result);
}
/**
* @method
* @name indodax#fetchBalance
* @description query for balance and get the amount of funds available for trading or funds locked in orders
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Private-RestAPI.md#get-info-endpoint
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
*/
async fetchBalance(params = {}) {
await this.loadMarkets();
const response = await this.privatePostGetInfo(params);
//
// {
// "success":1,
// "return":{
// "server_time":1619562628,
// "balance":{
// "idr":167,
// "btc":"0.00000000",
// "1inch":"0.00000000",
// },
// "balance_hold":{
// "idr":0,
// "btc":"0.00000000",
// "1inch":"0.00000000",
// },
// "address":{
// "btc":"1KMntgzvU7iTSgMBWc11nVuJjAyfW3qJyk",
// "1inch":"0x1106c8bb3172625e1f411c221be49161dac19355",
// "xrp":"rwWr7KUZ3ZFwzgaDGjKBysADByzxvohQ3C",
// "zrx":"0x1106c8bb3172625e1f411c221be49161dac19355"
// },
// "user_id":"276011",
// "name":"",
// "email":"testbitcoincoid@mailforspam.com",
// "profile_picture":null,
// "verification_status":"unverified",
// "gauth_enable":true
// }
// }
//
return this.parseBalance(response);
}
/**
* @method
* @name indodax#fetchOrderBook
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Public-RestAPI.md#depth
* @param {string} symbol unified symbol of the market to fetch the order book for
* @param {int} [limit] the maximum amount of order book entries to return
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
*/
async fetchOrderBook(symbol, limit = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'pair': market['base'] + market['quote'],
};
const orderbook = await this.publicGetApiDepthPair(this.extend(request, params));
return this.parseOrderBook(orderbook, market['symbol'], undefined, 'buy', 'sell');
}
parseTicker(ticker, market = undefined) {
//
// {
// "high":"0.01951",
// "low":"0.01877",
// "vol_eth":"39.38839319",
// "vol_btc":"0.75320886",
// "last":"0.01896",
// "buy":"0.01896",
// "sell":"0.019",
// "server_time":1565248908
// }
//
const symbol = this.safeSymbol(undefined, market);
const timestamp = this.safeTimestamp(ticker, 'server_time');
const baseVolume = 'vol_' + market['baseId'].toLowerCase();
const quoteVolume = 'vol_' + market['quoteId'].toLowerCase();
const last = this.safeString(ticker, 'last');
return this.safeTicker({
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'high': this.safeString(ticker, 'high'),
'low': this.safeString(ticker, 'low'),
'bid': this.safeString(ticker, 'buy'),
'bidVolume': undefined,
'ask': this.safeString(ticker, 'sell'),
'askVolume': undefined,
'vwap': undefined,
'open': undefined,
'close': last,
'last': last,
'previousClose': undefined,
'change': undefined,
'percentage': undefined,
'average': undefined,
'baseVolume': this.safeString(ticker, baseVolume),
'quoteVolume': this.safeString(ticker, quoteVolume),
'info': ticker,
}, market);
}
/**
* @method
* @name indodax#fetchTicker
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Public-RestAPI.md#ticker
* @param {string} symbol unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
*/
async fetchTicker(symbol, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'pair': market['base'] + market['quote'],
};
const response = await this.publicGetApiTickerPair(this.extend(request, params));
//
// {
// "ticker": {
// "high":"0.01951",
// "low":"0.01877",
// "vol_eth":"39.38839319",
// "vol_btc":"0.75320886",
// "last":"0.01896",
// "buy":"0.01896",
// "sell":"0.019",
// "server_time":1565248908
// }
// }
//
const ticker = this.safeDict(response, 'ticker', {});
return this.parseTicker(ticker, market);
}
/**
* @method
* @name indodax#fetchTickers
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Public-RestAPI.md#ticker-all
* @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
*/
async fetchTickers(symbols = undefined, params = {}) {
await this.loadMarkets();
//
// {
// "tickers": {
// "btc_idr": {
// "high": "120009000",
// "low": "116735000",
// "vol_btc": "218.13777777",
// "vol_idr": "25800033297",
// "last": "117088000",
// "buy": "117002000",
// "sell": "117078000",
// "server_time": 1571207881
// }
// }
// }
//
const response = await this.publicGetApiTickerAll(params);
const tickers = this.safeDict(response, 'tickers', {});
return this.parseTickers(tickers, symbols);
}
parseTrade(trade, market = undefined) {
const timestamp = this.safeTimestamp(trade, 'date');
return this.safeTrade({
'id': this.safeString(trade, 'tid'),
'info': trade,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'symbol': this.safeSymbol(undefined, market),
'type': undefined,
'side': this.safeString(trade, 'type'),
'order': undefined,
'takerOrMaker': undefined,
'price': this.safeString(trade, 'price'),
'amount': this.safeString(trade, 'amount'),
'cost': undefined,
'fee': undefined,
}, market);
}
/**
* @method
* @name indodax#fetchTrades
* @description get the list of most recent trades for a particular symbol
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Public-RestAPI.md#trades
* @param {string} symbol unified symbol of the market to fetch trades for
* @param {int} [since] timestamp in ms of the earliest trade to fetch
* @param {int} [limit] the maximum amount of trades to fetch
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
*/
async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'pair': market['base'] + market['quote'],
};
const response = await this.publicGetApiTradesPair(this.extend(request, params));
return this.parseTrades(response, market, since, limit);
}
parseOHLCV(ohlcv, market = undefined) {
//
// {
// "Time": 1708416900,
// "Open": 51707.52,
// "High": 51707.52,
// "Low": 51707.52,
// "Close": 51707.52,
// "Volume": "0"
// }
//
return [
this.safeTimestamp(ohlcv, 'Time'),
this.safeNumber(ohlcv, 'Open'),
this.safeNumber(ohlcv, 'High'),
this.safeNumber(ohlcv, 'Low'),
this.safeNumber(ohlcv, 'Close'),
this.safeNumber(ohlcv, 'Volume'),
];
}
/**
* @method
* @name indodax#fetchOHLCV
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
* @param {string} timeframe the length of time each candle represents
* @param {int} [since] timestamp in ms of the earliest candle to fetch
* @param {int} [limit] the maximum amount of candles to fetch
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {int} [params.until] timestamp in ms of the latest candle to fetch
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
*/
async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const timeframes = this.options['timeframes'];
const selectedTimeframe = this.safeString(timeframes, timeframe, timeframe);
const now = this.seconds();
const until = this.safeInteger(params, 'until', now);
params = this.omit(params, ['until']);
const request = {
'to': until,
'tf': selectedTimeframe,
'symbol': market['base'] + market['quote'],
};
if (limit === undefined) {
limit = 1000;
}
if (since !== undefined) {
request['from'] = Math.floor(since / 1000);
}
else {
const duration = this.parseTimeframe(timeframe);
request['from'] = now - limit * duration - 1;
}
const response = await this.publicGetTradingviewHistoryV2(this.extend(request, params));
//
// [
// {
// "Time": 1708416900,
// "Open": 51707.52,
// "High": 51707.52,
// "Low": 51707.52,
// "Close": 51707.52,
// "Volume": "0"
// }
// ]
//
return this.parseOHLCVs(response, market, timeframe, since, limit);
}
parseOrderStatus(status) {
const statuses = {
'open': 'open',
'filled': 'closed',
'cancelled': 'canceled',
};
return this.safeString(statuses, status, status);
}
parseOrder(order, market = undefined) {
//
// {
// "order_id": "12345",
// "submit_time": "1392228122",
// "price": "8000000",
// "type": "sell",
// "order_ltc": "100000000",
// "remain_ltc": "100000000"
// }
//
// market closed orders - note that the price is very high
// and does not reflect actual price the order executed at
//
// {
// "order_id": "49326856",
// "type": "sell",
// "price": "1000000000",
// "submit_time": "1618314671",
// "finish_time": "1618314671",
// "status": "filled",
// "order_xrp": "30.45000000",
// "remain_xrp": "0.00000000"
// }
//
// cancelOrder
//
// {
// "order_id": 666883,
// "client_order_id": "clientx-sj82ks82j",
// "type": "sell",
// "pair": "btc_idr",
// "balance": {
// "idr": "33605800",
// "btc": "0.00000000",
// ...
// "frozen_idr": "0",
// "frozen_btc": "0.00000000",
// ...
// }
// }
//
let side = undefined;
if ('type' in order) {
side = order['type'];
}
const status = this.parseOrderStatus(this.safeString(order, 'status', 'open'));
let symbol = undefined;
let cost = undefined;
const price = this.safeString(order, 'price');
let amount = undefined;
let remaining = undefined;
const marketId = this.safeString(order, 'pair');
market = this.safeMarket(marketId, market);
if (market !== undefined) {
symbol = market['symbol'];
let quoteId = market['quoteId'];
let baseId = market['baseId'];
if ((market['quoteId'] === 'idr') && ('order_rp' in order)) {
quoteId = 'rp';
}
if ((market['baseId'] === 'idr') && ('remain_rp' in order)) {
baseId = 'rp';
}
cost = this.safeString(order, 'order_' + quoteId);
if (!cost) {
amount = this.safeString(order, 'order_' + baseId);
remaining = this.safeString(order, 'remain_' + baseId);
}
}
const timestamp = this.safeInteger(order, 'submit_time');
const fee = undefined;
const id = this.safeString(order, 'order_id');
return this.safeOrder({
'info': order,
'id': id,
'clientOrderId': this.safeString(order, 'client_order_id'),
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': 'limit',
'timeInForce': undefined,
'postOnly': undefined,
'side': side,
'price': price,
'triggerPrice': undefined,
'cost': cost,
'average': undefined,
'amount': amount,
'filled': undefined,
'remaining': remaining,
'status': status,
'fee': fee,
'trades': undefined,
});
}
/**
* @method
* @name indodax#fetchOrder
* @description fetches information on an order made by the user
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Private-RestAPI.md#get-order-endpoints
* @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 exchange API endpoint
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async fetchOrder(id, symbol = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired(this.id + ' fetchOrder() requires a symbol argument');
}
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'pair': market['id'],
'order_id': id,
};
const response = await this.privatePostGetOrder(this.extend(request, params));
const orders = response['return'];
const order = this.parseOrder(this.extend({ 'id': id }, orders['order']), market);
order['info'] = response;
return order;
}
/**
* @method
* @name indodax#fetchOpenOrders
* @description fetch all unfilled currently open orders
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Private-RestAPI.md#open-orders-endpoints
* @param {string} symbol unified market symbol
* @param {int} [since] the earliest time in ms to fetch open orders for
* @param {int} [limit] the maximum number of open orders structures to retrieve
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
let market = undefined;
const request = {};
if (symbol !== undefined) {
market = this.market(symbol);
request['pair'] = market['id'];
}
const response = await this.privatePostOpenOrders(this.extend(request, params));
const rawOrders = response['return']['orders'];
// { success: 1, return: { orders: null }} if no orders
if (!rawOrders) {
return [];
}
// { success: 1, return: { orders: [ ... objects ] }} for orders fetched by symbol
if (symbol !== undefined) {
return this.parseOrders(rawOrders, market, since, limit);
}
// { success: 1, return: { orders: { marketid: [ ... objects ] }}} if all orders are fetched
const marketIds = Object.keys(rawOrders);
let exchangeOrders = [];
for (let i = 0; i < marketIds.length; i++) {
const marketId = marketIds[i];
const marketOrders = rawOrders[marketId];
market = this.safeMarket(marketId);
const parsedOrders = this.parseOrders(marketOrders, market, since, limit);
exchangeOrders = this.arrayConcat(exchangeOrders, parsedOrders);
}
return exchangeOrders;
}
/**
* @method
* @name indodax#fetchClosedOrders
* @description fetches information on multiple closed orders made by the user
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Private-RestAPI.md#order-history
* @param {string} symbol unified market symbol of the market orders were made in
* @param {int} [since] the earliest time in ms to fetch orders for
* @param {int} [limit] the maximum number of order structures to retrieve
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired(this.id + ' fetchClosedOrders() requires a symbol argument');
}
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'pair': market['id'],
};
const response = await this.privatePostOrderHistory(this.extend(request, params));
let orders = this.parseOrders(response['return']['orders'], market);
orders = this.filterBy(orders, 'status', 'closed');
return this.filterBySymbolSinceLimit(orders, symbol, since, limit);
}
/**
* @method
* @name indodax#createOrder
* @description create a trade order
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Private-RestAPI.md#trade-endpoints
* @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} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'pair': market['id'],
'type': side,
'price': price,
};
let priceIsRequired = false;
let quantityIsRequired = false;
if (type === 'market') {
if (side === 'buy') {
let quoteAmount = undefined;
const cost = this.safeNumber(params, 'cost');
params = this.omit(params, 'cost');
if (cost !== undefined) {
quoteAmount = this.costToPrecision(symbol, cost);
}
else {
if (price === undefined) {
throw new InvalidOrder(this.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend (amount * price).');
}
const amountString = this.numberToString(amount);
const priceString = this.numberToString(price);
const costRequest = Precise.stringMul(amountString, priceString);
quoteAmount = this.costToPrecision(symbol, costRequest);
}
request[market['quoteId']] = quoteAmount;
}
else {
quantityIsRequired = true;
}
}
else if (type === 'limit') {
priceIsRequired = true;
quantityIsRequired = true;
if (side === 'buy') {
request[market['quoteId']] = this.parseToNumeric(Precise.stringMul(this.numberToString(amount), this.numberToString(price)));
}
}
if (priceIsRequired) {
if (price === undefined) {
throw new InvalidOrder(this.id + ' createOrder() requires a price argument for a ' + type + ' order');
}
request['price'] = price;
}
if (quantityIsRequired) {
request[market['baseId']] = this.amountToPrecision(symbol, amount);
}
const result = await this.privatePostTrade(this.extend(request, params));
const data = this.safeValue(result, 'return', {});
const id = this.safeString(data, 'order_id');
return this.safeOrder({
'info': result,
'id': id,
}, market);
}
/**
* @method
* @name indodax#cancelOrder
* @description cancels an open order
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Private-RestAPI.md#cancel-order-endpoints
* @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 exchange API endpoint
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async cancelOrder(id, symbol = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
}
const side = this.safeValue(params, 'side');
if (side === undefined) {
throw new ArgumentsRequired(this.id + ' cancelOrder() requires an extra "side" param');
}
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'order_id': id,
'pair': market['id'],
'type': side,
};
const response = await this.privatePostCancelOrder(this.extend(request, params));
//
// {
// "success": 1,
// "return": {
// "order_id": 666883,
// "client_order_id": "clientx-sj82ks82j",
// "type": "sell",
// "pair": "btc_idr",
// "balance": {
// "idr": "33605800",
// "btc": "0.00000000",
// ...
// "frozen_idr": "0",
// "frozen_btc": "0.00000000",
// ...
// }
// }
// }
//
const data = this.safeDict(response, 'return');
return this.parseOrder(data);
}
/**
* @method
* @name indodax#fetchTransactionFee
* @description fetch the fee for a transaction
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Private-RestAPI.md#withdraw-fee-endpoints
* @param {string} code unified currency code
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure}
*/
async fetchTransactionFee(code, params = {}) {
await this.loadMarkets();
const currency = this.currency(code);
const request = {
'currency': currency['id'],
};
const response = await this.privatePostWithdrawFee(this.extend(request, params));
//
// {
// "success": 1,
// "return": {
// "server_time": 1607923272,
// "withdraw_fee": 0.005,
// "currency": "eth"
// }
// }
//
const data = this.safeValue(response, 'return', {});
const currencyId = this.safeString(data, 'currency');
return {
'info': response,
'rate': this.safeNumber(data, 'withdraw_fee'),
'currency': this.safeCurrencyCode(currencyId, currency),
};
}
/**
* @method
* @name indodax#fetchDepositsWithdrawals
* @description fetch history of deposits and withdrawals
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Private-RestAPI.md#transaction-history-endpoints
* @param {string} [code] unified currency code for the currency of the deposit/withdrawals, default is undefined
* @param {int} [since] timestamp in ms of the earliest deposit/withdrawal, default is undefined
* @param {int} [limit] max number of deposit/withdrawals to return, default is undefined
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a list of [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
*/
async fetchDepositsWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const request = {};
if (since !== undefined) {
const startTime = this.iso8601(since).slice(0, 10);
request['start'] = startTime;
request['end'] = this.iso8601(this.milliseconds()).slice(0, 10);
}
const response = await this.privatePostTransHistory(this.extend(request, params));
//
// {
// "success": 1,
// "return": {
// "withdraw": {
// "idr": [
// {
// "status": "success",
// "type": "coupon",
// "rp": "115205",
// "fee": "500",
// "amount": "114705",
// "submit_time": "1539844166",
// "success_time": "1539844189",
// "withdraw_id": "1783717",
// "tx": "BTC-IDR-RDTVVO2P-ETD0EVAW-VTNZGMIR-HTNTUAPI-84ULM9OI",
// "sender": "boris",
// "used_by": "viginia88"
// },
// ...
// ],
// "btc": [],
// "abyss": [],
// ...
// },
// "deposit": {
// "idr": [
// {
// "status": "success",
// "type": "duitku",
// "rp": "393000",
// "fee": "5895",
// "amount": "387105",
// "submit_time": "1576555012",
// "success_time": "1576555012",
// "deposit_id": "3395438",
// "tx": "Duitku OVO Settlement"
// },
// ...
// ],
// "btc": [
// {
// "status": "success",
// "btc": "0.00118769",
// "amount": "0.00118769",
// "success_time": "1539529208",
// "deposit_id": "3602369",
// "tx": "c816aeb35a5b42f389970325a32aff69bb6b2126784dcda8f23b9dd9570d6573"
// },
// ...
// ],
// "abyss": [],
// ...
// }
// }
// }
//
const data = this.safeValue(response, 'return', {});
const withdraw = this.safeValue(data, 'withdraw', {});
const deposit = this.safeValue(data, 'deposit', {});
let transactions = [];
let currency = undefined;
if (code === undefined) {
let keys = Object.keys(withdraw);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
transactions = this.arrayConcat(transactions, withdraw[key]);
}
keys = Object.keys(deposit);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
transactions = this.arrayConcat(transactions, deposit[key]);
}
}
else {
currency = this.currency(code);
const withdraws = this.safeValue(withdraw, currency['id'], []);
const deposits = this.safeValue(deposit, currency['id'], []);
transactions = this.arrayConcat(withdraws, deposits);
}
return this.parseTransactions(transactions, currency, since, limit);
}
/**
* @method
* @name indodax#withdraw
* @description make a withdrawal
* @see https://github.com/btcid/indodax-official-api-docs/blob/master/Private-RestAPI.md#withdraw-coin-endpoints
* @param {string} code unified currency code
* @param {float} amount the amount to withdraw
* @param {string} address the address to withdraw to
* @param {string} tag
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
*/
async withdraw(code, amount, address, tag = undefined, params = {}) {
[tag, params] = this.handleWithdrawTagAndParams(tag, params);
this.checkAddress(address);
await this.loadMarkets();
const currency = this.currency(code);
// Custom string you need to provide to identify each withdrawal.
// Will be