UNPKG

preidman-ccxt

Version:

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

554 lines (535 loc) 20 kB
'use strict'; // --------------------------------------------------------------------------- const liqui = require ('./liqui.js'); const { ArgumentsRequired } = require ('./base/errors'); // --------------------------------------------------------------------------- module.exports = class dsx extends liqui { describe () { return this.deepExtend (super.describe (), { 'id': 'dsx', 'name': 'DSX', 'countries': [ 'UK' ], 'rateLimit': 1500, 'version': 'v2', 'has': { 'CORS': false, 'fetchOrder': true, 'fetchOrders': true, 'fetchOpenOrders': true, 'fetchClosedOrders': false, 'fetchOrderBooks': false, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/27990275-1413158a-645a-11e7-931c-94717f7510e3.jpg', 'api': { 'public': 'https://dsx.uk/mapi', // market data 'private': 'https://dsx.uk/tapi', // trading 'dwapi': 'https://dsx.uk/dwapi', // deposit/withdraw }, 'www': 'https://dsx.uk', 'doc': [ 'https://api.dsx.uk', 'https://dsx.uk/api_docs/public', 'https://dsx.uk/api_docs/private', '', ], }, 'api': { // market data (public) 'public': { 'get': [ 'barsFromMoment/{id}/{period}/{start}', // empty reply :\ 'depth/{pair}', 'info', 'lastBars/{id}/{period}/{amount}', // period is (m, h or d) 'periodBars/{id}/{period}/{start}/{end}', 'ticker/{pair}', 'trades/{pair}', ], }, // trading (private) 'private': { 'post': [ 'info/account', 'history/transactions', 'history/trades', 'history/orders', 'orders', 'order/cancel', 'order/cancel/all', 'order/status', 'order/new', 'volume', 'fees', // trading fee schedule ], }, // deposit / withdraw (private) 'dwapi': { 'post': [ 'deposit/cryptoaddress', 'withdraw/crypto', 'withdraw/fiat', 'withdraw/submit', 'withdraw/cancel', 'transaction/status', // see 'history/transactions' in private tapi above ], }, }, 'options': { 'fetchOrderMethod': 'privatePostOrderStatus', 'fetchMyTradesMethod': 'privatePostHistoryTrades', 'cancelOrderMethod': 'privatePostOrderCancel', 'fetchTickersMaxLength': 250, }, }); } async fetchMarkets (params = {}) { let response = await this.publicGetInfo (); let markets = response['pairs']; let keys = Object.keys (markets); let result = []; for (let i = 0; i < keys.length; i++) { let id = keys[i]; let market = markets[id]; let baseId = this.safeString (market, 'base_currency'); let quoteId = this.safeString (market, 'quoted_currency'); let base = this.commonCurrencyCode (baseId); let quote = this.commonCurrencyCode (quoteId); let symbol = base + '/' + quote; let precision = { 'amount': this.safeInteger (market, 'decimal_places'), 'price': this.safeInteger (market, 'decimal_places'), }; let amountLimits = { 'min': this.safeFloat (market, 'min_amount'), 'max': this.safeFloat (market, 'max_amount'), }; let priceLimits = { 'min': this.safeFloat (market, 'min_price'), 'max': this.safeFloat (market, 'max_price'), }; let costLimits = { 'min': this.safeFloat (market, 'min_total'), }; let limits = { 'amount': amountLimits, 'price': priceLimits, 'cost': costLimits, }; let hidden = this.safeInteger (market, 'hidden'); let active = (hidden === 0); result.push ({ 'id': id, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'active': active, 'taker': market['fee'] / 100, 'precision': precision, 'limits': limits, 'info': market, }); } return result; } async fetchBalance (params = {}) { await this.loadMarkets (); let response = await this.privatePostInfoAccount (); // // { // "success" : 1, // "return" : { // "funds" : { // "BTC" : { // "total" : 0, // "available" : 0 // }, // "USD" : { // "total" : 0, // "available" : 0 // }, // "USDT" : { // "total" : 0, // "available" : 0 // } // }, // "rights" : { // "info" : 1, // "trade" : 1 // }, // "transactionCount" : 0, // "openOrders" : 0, // "serverTime" : 1537451465 // } // } // let balances = response['return']; let result = { 'info': balances }; let funds = balances['funds']; let ids = Object.keys (funds); for (let c = 0; c < ids.length; c++) { let id = ids[c]; let code = this.commonCurrencyCode (id); let account = { 'free': funds[id]['available'], 'used': 0.0, 'total': funds[id]['total'], }; account['used'] = account['total'] - account['free']; result[code] = account; } return this.parseBalance (result); } parseTicker (ticker, market = undefined) { // // { high: 0.03492, // low: 0.03245, // avg: 29.46133, // vol: 500.8661, // vol_cur: 17.000797104, // last: 0.03364, // buy: 0.03362, // sell: 0.03381, // updated: 1537521993, // pair: "ethbtc" } // let timestamp = ticker['updated'] * 1000; let symbol = undefined; // dsx has 'pair' in the ticker, liqui does not have it let marketId = this.safeString (ticker, 'pair'); market = this.safeValue (this.markets_by_id, marketId, market); if (market !== undefined) { symbol = market['symbol']; } // dsx average is inverted, liqui average is not let average = this.safeFloat (ticker, 'avg'); if (average !== undefined) { if (average > 0) { average = 1 / average; } } let last = this.safeFloat (ticker, 'last'); return { 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'high': this.safeFloat (ticker, 'high'), 'low': this.safeFloat (ticker, 'low'), 'bid': this.safeFloat (ticker, 'buy'), 'bidVolume': undefined, 'ask': this.safeFloat (ticker, 'sell'), 'askVolume': undefined, 'vwap': undefined, 'open': undefined, 'close': last, 'last': last, 'previousClose': undefined, 'change': undefined, 'percentage': undefined, 'average': average, 'baseVolume': this.safeFloat (ticker, 'vol'), // dsx shows baseVolume in 'vol', liqui shows baseVolume in 'vol_cur' 'quoteVolume': this.safeFloat (ticker, 'vol_cur'), // dsx shows baseVolume in 'vol_cur', liqui shows baseVolume in 'vol' 'info': ticker, }; } signBodyWithSecret (body) { return this.decode (this.hmac (this.encode (body), this.encode (this.secret), 'sha512', 'base64')); } getVersionString () { return ''; } getPrivatePath (path, params) { return '/' + this.version + '/' + this.implodeParams (path, params); } getOrderIdKey () { return 'orderId'; } async createOrder (symbol, type, side, amount, price = undefined, params = {}) { await this.loadMarkets (); let market = this.market (symbol); if (type === 'market' && price === undefined) { throw new ArgumentsRequired (this.id + ' createOrder requires a price argument even for market orders, that is the worst price that you agree to fill your order for'); } let request = { 'pair': market['id'], 'type': side, 'volume': this.amountToPrecision (symbol, amount), 'rate': this.priceToPrecision (symbol, price), 'orderType': type, }; price = parseFloat (price); amount = parseFloat (amount); let response = await this.privatePostOrderNew (this.extend (request, params)); // // { // "success": 1, // "return": { // "received": 0, // "remains": 10, // "funds": { // "BTC": { // "total": 100, // "available": 95 // }, // "USD": { // "total": 10000, // "available": 9995 // }, // "EUR": { // "total": 1000, // "available": 995 // }, // "LTC": { // "total": 1000, // "available": 995 // } // }, // "orderId": 0, // https://github.com/ccxt/ccxt/issues/3677 // } // } // let status = 'open'; let filled = 0.0; let remaining = amount; let responseReturn = this.safeValue (response, 'return'); let id = this.safeString2 (responseReturn, 'orderId', 'order_id'); if (id === '0') { id = this.safeString (responseReturn, 'initOrderId', 'init_order_id'); status = 'closed'; } filled = this.safeFloat (responseReturn, 'received', 0.0); remaining = this.safeFloat (responseReturn, 'remains', amount); let timestamp = this.milliseconds (); return { 'info': response, 'id': id, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': undefined, 'status': status, 'symbol': symbol, 'type': type, 'side': side, 'price': price, 'cost': price * filled, 'amount': amount, 'remaining': remaining, 'filled': filled, 'fee': undefined, // 'trades': this.parseTrades (order['trades'], market), }; } parseOrderStatus (status) { const statuses = { '0': 'open', // Active '1': 'closed', // Filled '2': 'canceled', // Killed '3': 'canceling', // Killing '7': 'canceled', // Rejected }; return this.safeString (statuses, status, status); } parseOrder (order, market = undefined) { // // fetchOrder // // { // "pair": "btcusd", // "type": "buy", // "remainingVolume": 10, // "volume": 10, // "rate": 1000.0, // "timestampCreated": 1496670, // "status": 0, // "orderType": "limit", // "deals": [ // { // "pair": "btcusd", // "type": "buy", // "amount": 1, // "rate": 1000.0, // "orderId": 1, // "timestamp": 1496672724, // "commission": 0.001, // "commissionCurrency": "btc" // } // ] // } // let id = this.safeString (order, 'id'); let status = this.parseOrderStatus (this.safeString (order, 'status')); let timestamp = this.safeInteger (order, 'timestampCreated'); if (timestamp !== undefined) { timestamp = timestamp * 1000; } let marketId = this.safeString (order, 'pair'); market = this.safeValue (this.markets_by_id, marketId, market); let symbol = undefined; if (market !== undefined) { symbol = market['symbol']; } let remaining = this.safeFloat (order, 'remainingVolume'); let amount = this.safeFloat (order, 'volume'); let price = this.safeFloat (order, 'rate'); let filled = undefined; let cost = undefined; if (amount !== undefined) { if (remaining !== undefined) { filled = amount - remaining; cost = price * filled; } } let orderType = this.safeString (order, 'orderType'); let side = this.safeString (order, 'type'); let fee = undefined; let deals = this.safeValue (order, 'deals', []); let numDeals = deals.length; let trades = undefined; let lastTradeTimestamp = undefined; if (numDeals > 0) { trades = this.parseTrades (deals); let feeCost = undefined; let feeCurrency = undefined; for (let i = 0; i < trades.length; i++) { let trade = trades[i]; if (feeCost === undefined) { feeCost = 0; } feeCost += trade['fee']['cost']; feeCurrency = trade['fee']['currency']; lastTradeTimestamp = trade['timestamp']; } if (feeCost !== undefined) { fee = { 'cost': feeCost, 'currency': feeCurrency, }; } } return { 'info': order, 'id': id, 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'lastTradeTimestamp': lastTradeTimestamp, 'type': orderType, 'side': side, 'price': price, 'cost': cost, 'amount': amount, 'remaining': remaining, 'filled': filled, 'status': status, 'fee': fee, 'trades': trades, }; } async fetchOrder (id, symbol = undefined, params = {}) { await this.loadMarkets (); const request = { 'orderId': parseInt (id), }; const response = await this.privatePostOrderStatus (this.extend (request, params)); // // { // "success": 1, // "return": { // "pair": "btcusd", // "type": "buy", // "remainingVolume": 10, // "volume": 10, // "rate": 1000.0, // "timestampCreated": 1496670, // "status": 0, // "orderType": "limit", // "deals": [ // { // "pair": "btcusd", // "type": "buy", // "amount": 1, // "rate": 1000.0, // "orderId": 1, // "timestamp": 1496672724, // "commission": 0.001, // "commissionCurrency": "btc" // } // ] // } // } // return this.parseOrder (this.extend ({ 'id': id, }, response['return'])); } parseOrdersById (orders, symbol = undefined, since = undefined, limit = undefined) { let ids = Object.keys (orders); let result = []; for (let i = 0; i < ids.length; i++) { let id = ids[i]; let order = this.parseOrder (this.extend ({ 'id': id.toString (), }, orders[id])); result.push (order); } return this.filterBySymbolSinceLimit (result, symbol, since, limit); } async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const request = { // 'count': 10, // Decimal, The maximum number of orders to return // 'fromId': 123, // Decimal, ID of the first order of the selection // 'endId': 321, // Decimal, ID of the last order of the selection // 'order': 'ASC', // String, Order in which orders shown. Possible values are "ASC" — from first to last, "DESC" — from last to first. }; const response = await this.privatePostHistoryOrders (this.extend (request, params)); // // { // "success": 1, // "return": { // "0": { // "pair": "btcusd", // "type": "buy", // "remainingVolume": 10, // "volume": 10, // "rate": 1000.0, // "timestampCreated": 1496670, // "status": 0, // "orderType": "limit" // } // } // } // return this.parseOrdersById (this.safeValue (response, 'return', {})); } async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const request = { // 'count': 10, // Decimal, The maximum number of orders to return // 'fromId': 123, // Decimal, ID of the first order of the selection // 'endId': 321, // Decimal, ID of the last order of the selection // 'order': 'ASC', // String, Order in which orders shown. Possible values are "ASC" — from first to last, "DESC" — from last to first. }; const response = await this.privatePostHistoryOrders (this.extend (request, params)); // // { // "success": 1, // "return": { // "0": { // "pair": "btcusd", // "type": "buy", // "remainingVolume": 10, // "volume": 10, // "rate": 1000.0, // "timestampCreated": 1496670, // "status": 0, // "orderType": "limit" // } // } // } // return this.parseOrdersById (this.safeValue (response, 'return', {})); } };