@jmparsons/ccxt
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 100+ exchanges
388 lines (369 loc) • 14.9 kB
JavaScript
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
// ---------------------------------------------------------------------------
module.exports = class independentreserve extends Exchange {
describe () {
return this.deepExtend (super.describe (), {
'id': 'independentreserve',
'name': 'Independent Reserve',
'countries': [ 'AU', 'NZ' ], // Australia, New Zealand
'rateLimit': 1000,
'has': {
'CORS': false,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/30521662-cf3f477c-9bcb-11e7-89bc-d1ac85012eda.jpg',
'api': {
'public': 'https://api.independentreserve.com/Public',
'private': 'https://api.independentreserve.com/Private',
},
'www': 'https://www.independentreserve.com',
'doc': 'https://www.independentreserve.com/API',
},
'api': {
'public': {
'get': [
'GetValidPrimaryCurrencyCodes',
'GetValidSecondaryCurrencyCodes',
'GetValidLimitOrderTypes',
'GetValidMarketOrderTypes',
'GetValidOrderTypes',
'GetValidTransactionTypes',
'GetMarketSummary',
'GetOrderBook',
'GetTradeHistorySummary',
'GetRecentTrades',
'GetFxRates',
],
},
'private': {
'post': [
'PlaceLimitOrder',
'PlaceMarketOrder',
'CancelOrder',
'GetOpenOrders',
'GetClosedOrders',
'GetClosedFilledOrders',
'GetOrderDetails',
'GetAccounts',
'GetTransactions',
'GetDigitalCurrencyDepositAddress',
'GetDigitalCurrencyDepositAddresses',
'SynchDigitalCurrencyDepositAddressWithBlockchain',
'WithdrawDigitalCurrency',
'RequestFiatWithdrawal',
'GetTrades',
],
},
},
'fees': {
'trading': {
'taker': 0.5 / 100,
'maker': 0.5 / 100,
'percentage': true,
'tierBased': false,
},
},
});
}
async fetchMarkets () {
let baseCurrencies = await this.publicGetGetValidPrimaryCurrencyCodes ();
let quoteCurrencies = await this.publicGetGetValidSecondaryCurrencyCodes ();
let result = [];
for (let i = 0; i < baseCurrencies.length; i++) {
let baseId = baseCurrencies[i];
let baseIdUppercase = baseId.toUpperCase ();
let base = this.commonCurrencyCode (baseIdUppercase);
for (let j = 0; j < quoteCurrencies.length; j++) {
let quoteId = quoteCurrencies[j];
let quoteIdUppercase = quoteId.toUpperCase ();
let quote = this.commonCurrencyCode (quoteIdUppercase);
let id = baseId + '/' + quoteId;
let symbol = base + '/' + quote;
result.push ({
'id': id,
'symbol': symbol,
'base': base,
'quote': quote,
'baseId': baseId,
'quoteId': quoteId,
'info': id,
});
}
}
return result;
}
async fetchBalance (params = {}) {
await this.loadMarkets ();
let balances = await this.privatePostGetAccounts ();
let result = { 'info': balances };
for (let i = 0; i < balances.length; i++) {
let balance = balances[i];
let currencyCode = balance['CurrencyCode'];
let uppercase = currencyCode.toUpperCase ();
let currency = this.commonCurrencyCode (uppercase);
let account = this.account ();
account['free'] = balance['AvailableBalance'];
account['total'] = balance['TotalBalance'];
account['used'] = account['total'] - account['free'];
result[currency] = account;
}
return this.parseBalance (result);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
let market = this.market (symbol);
let response = await this.publicGetGetOrderBook (this.extend ({
'primaryCurrencyCode': market['baseId'],
'secondaryCurrencyCode': market['quoteId'],
}, params));
let timestamp = this.parse8601 (response['CreatedTimestampUtc']);
return this.parseOrderBook (response, timestamp, 'BuyOrders', 'SellOrders', 'Price', 'Volume');
}
parseTicker (ticker, market = undefined) {
let timestamp = this.parse8601 (ticker['CreatedTimestampUtc']);
let symbol = undefined;
if (market)
symbol = market['symbol'];
let last = ticker['LastPrice'];
return {
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'high': ticker['DayHighestPrice'],
'low': ticker['DayLowestPrice'],
'bid': ticker['CurrentHighestBidPrice'],
'bidVolume': undefined,
'ask': ticker['CurrentLowestOfferPrice'],
'askVolume': undefined,
'vwap': undefined,
'open': undefined,
'close': last,
'last': last,
'previousClose': undefined,
'change': undefined,
'percentage': undefined,
'average': ticker['DayAvgPrice'],
'baseVolume': ticker['DayVolumeXbtInSecondaryCurrrency'],
'quoteVolume': undefined,
'info': ticker,
};
}
async fetchTicker (symbol, params = {}) {
await this.loadMarkets ();
let market = this.market (symbol);
let response = await this.publicGetGetMarketSummary (this.extend ({
'primaryCurrencyCode': market['baseId'],
'secondaryCurrencyCode': market['quoteId'],
}, params));
return this.parseTicker (response, market);
}
parseOrder (order, market = undefined) {
let symbol = undefined;
if (typeof market === 'undefined') {
symbol = market['symbol'];
} else {
market = this.findMarket (order['PrimaryCurrencyCode'] + '/' + order['SecondaryCurrencyCode']);
}
let orderType = this.safeValue (order, 'Type');
if (orderType.indexOf ('Market') >= 0)
orderType = 'market';
else if (orderType.indexOf ('Limit') >= 0)
orderType = 'limit';
let side = undefined;
if (orderType.indexOf ('Bid') >= 0)
side = 'buy';
else if (orderType.indexOf ('Offer') >= 0)
side = 'sell';
let timestamp = this.parse8601 (order['CreatedTimestampUtc']);
let amount = this.safeFloat (order, 'VolumeOrdered');
if (typeof amount === 'undefined')
amount = this.safeFloat (order, 'Volume');
let filled = this.safeFloat (order, 'VolumeFilled');
let remaining = undefined;
let feeRate = this.safeFloat (order, 'FeePercent');
let feeCost = undefined;
if (typeof amount !== 'undefined') {
if (typeof filled !== 'undefined') {
remaining = amount - filled;
if (typeof feeRate !== 'undefined')
feeCost = feeRate * filled;
}
}
let feeCurrency = undefined;
if (typeof market !== 'undefined') {
symbol = market['symbol'];
feeCurrency = market['base'];
}
let fee = {
'rate': feeRate,
'cost': feeCost,
'currency': feeCurrency,
};
let id = order['OrderGuid'];
let status = this.parseOrderStatus (order['Status']);
let cost = this.safeFloat (order, 'Value');
let average = this.safeFloat (order, 'AvgPrice');
let price = this.safeFloat (order, 'Price', average);
return {
'info': order,
'id': id,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': orderType,
'side': side,
'price': price,
'cost': cost,
'average': average,
'amount': amount,
'filled': filled,
'remaining': remaining,
'status': status,
'fee': fee,
};
}
parseOrderStatus (status) {
let statuses = {
'Open': 'open',
'PartiallyFilled': 'open',
'Filled': 'closed',
'PartiallyFilledAndCancelled': 'canceled',
'Cancelled': 'canceled',
'PartiallyFilledAndExpired': 'canceled',
'Expired': 'canceled',
};
if (status in statuses)
return statuses[status];
return status;
}
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privatePostGetOrderDetails (this.extend ({
'orderGuid': id,
}, params));
let market = undefined;
if (typeof symbol !== 'undefined')
market = this.market (symbol);
return this.parseOrder (response, market);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = 50, params = {}) {
await this.loadMarkets ();
let pageIndex = this.safeInteger (params, 'pageIndex', 1);
const request = this.ordered ({
'pageIndex': pageIndex,
'pageSize': limit,
});
const response = await this.privatePostGetTrades (this.extend (request, params));
let market = undefined;
if (typeof symbol !== 'undefined') {
market = this.market (symbol);
}
return this.parseTrades (response['Data'], market, since, limit);
}
parseTrade (trade, market = undefined) {
let timestamp = this.parse8601 (trade['TradeTimestampUtc']);
let id = this.safeString (trade, 'TradeGuid');
let orderId = this.safeString (trade, 'OrderGuid');
let price = this.safeFloat (trade, 'Price');
if (typeof price === 'undefined') {
price = this.safeFloat (trade, 'SecondaryCurrencyTradePrice');
}
let amount = this.safeFloat (trade, 'VolumeTraded');
if (typeof amount === 'undefined') {
amount = this.safeFloat (trade, 'PrimaryCurrencyAmount');
}
let symbol = undefined;
if (typeof market !== 'undefined')
symbol = market['symbol'];
let side = this.safeString (trade, 'OrderType');
if (typeof side !== 'undefined') {
if (side.indexOf ('Bid') >= 0)
side = 'buy';
else if (side.indexOf ('Offer') >= 0)
side = 'sell';
}
return {
'id': id,
'info': trade,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'symbol': symbol,
'order': orderId,
'type': undefined,
'side': side,
'price': price,
'amount': amount,
'fee': undefined,
};
}
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
let market = this.market (symbol);
let response = await this.publicGetGetRecentTrades (this.extend ({
'primaryCurrencyCode': market['baseId'],
'secondaryCurrencyCode': market['quoteId'],
'numberOfRecentTradesToRetrieve': 50, // max = 50
}, params));
return this.parseTrades (response['Trades'], market, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
let market = this.market (symbol);
let capitalizedOrderType = this.capitalize (type);
let method = 'privatePostPlace' + capitalizedOrderType + 'Order';
let orderType = capitalizedOrderType;
orderType += (side === 'sell') ? 'Offer' : 'Bid';
let order = this.ordered ({
'primaryCurrencyCode': market['baseId'],
'secondaryCurrencyCode': market['quoteId'],
'orderType': orderType,
});
if (type === 'limit')
order['price'] = price;
order['volume'] = amount;
let response = await this[method] (this.extend (order, params));
return {
'info': response,
'id': response['OrderGuid'],
};
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
return await this.privatePostCancelOrder ({ 'orderGuid': id });
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
let url = this.urls['api'][api] + '/' + path;
if (api === 'public') {
if (Object.keys (params).length)
url += '?' + this.urlencode (params);
} else {
this.checkRequiredCredentials ();
let nonce = this.nonce ();
let auth = [
url,
'apiKey=' + this.apiKey,
'nonce=' + nonce.toString (),
];
// remove this crap
let keys = Object.keys (params);
let payload = [];
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
payload.push (key + '=' + params[key]);
}
auth = this.arrayConcat (auth, payload);
let message = auth.join (',');
let signature = this.hmac (this.encode (message), this.encode (this.secret));
body = this.json ({
'apiKey': this.apiKey,
'nonce': nonce,
'signature': signature,
});
headers = { 'Content-Type': 'application/json' };
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
};