diff --git a/config.default.jsonc b/config.default.jsonc index 1d295cc3..8d29b138 100644 --- a/config.default.jsonc +++ b/config.default.jsonc @@ -43,7 +43,6 @@ /** List of supported exchanges **/ "exchanges": [ - "CoinDeal", "Resfinex", "P2PB2B" ], diff --git a/trade/api/coindeal_api.js b/trade/api/coindeal_api.js deleted file mode 100644 index ae4a99fd..00000000 --- a/trade/api/coindeal_api.js +++ /dev/null @@ -1,291 +0,0 @@ -const axios = require('axios'); -const FormData = require('form-data'); - -module.exports = function() { - const DEFAULT_HEADERS = { - 'Accept': 'application/json', - }; - - let WEB_BASE = ''; // API server like https://apigateway.coindeal.com - let config = { - 'apiKey': '', - 'secret_key': '', - 'tradePwd': '', - }; - let log = {}; - - function protectedRequest(path, data, type = 'get') { - let url = `${WEB_BASE}${path}`; - const params = []; - for (const key in data) { - const v = data[key]; - params.push(key + '=' + v); - } - const paramsString = params.join('&'); - if (paramsString && type !== 'post') { - url = url + '?' + paramsString; - } - let headersWithSign = Object.assign({ 'Authorization': setSign() }, DEFAULT_HEADERS); - - return new Promise((resolve, reject) => { - try { - - let httpOptions; - - if (type === 'get' || type === 'delete') { - - httpOptions = { - url: url, - method: type, - timeout: 10000, - headers: headersWithSign, - }; - - axios(httpOptions) - .then(function(response) { - const data = response.data; - resolve(data); - }) - .catch(function(error) { - // We can get 4xx with data - if (error.response && typeof error.response.data === 'object' && Object.keys(error.response.data).length !== 0) { - log.log(`${type.toUpperCase()}-request to ${url} with data ${JSON.stringify(data)} failed. ${error}. Reply data: ${JSON.stringify(error.response.data)}.`); - resolve(error.response.data); - } else if ( - type === 'delete' && - error.response && - error.response.status === 404 && - typeof error.response.data === 'string' && - error.response.data.includes('') && - error.response.data.includes('404 Not Found') - ) { - log.log(`${type.toUpperCase()}-request to ${url} with data ${JSON.stringify(data)} failed. ${error}. We assume that user doesn't have this order (but this may be a temporary server error, can't be sure).`); - if (error.response.status < 500) { - resolve(error.response.data); - } else { - reject(error.response.data); - } - } else { - log.log(`${type.toUpperCase()}-request to ${url} with data ${JSON.stringify(data)} failed. ${error}.`); - reject(error); - } - }); - } else { // post - const form = new FormData(); - Object.keys(data).forEach((key) => { - form.append(key, data[key]); - }); - - headersWithSign = Object.assign(headersWithSign, form.getHeaders()); - httpOptions = { - timeout: 10000, - headers: headersWithSign, - }; - - axios.post(url, form, httpOptions) - .then(function(response) { - const data = response.data; - resolve(data); - }) - .catch(function(error) { - // We can get 4xx with data - if (error.response && typeof error.response.data === 'object' && Object.keys(error.response.data).length !== 0) { - log.log(`${type.toUpperCase()}-request to ${url} with data ${JSON.stringify(data)} failed. ${error}. Reply data: ${JSON.stringify(error.response.data)}.`); - if (error.response.status < 500) { - resolve(error.response.data); - } else { - reject(error.response.data); - } - } else { - log.log(`${type.toUpperCase()}-request to ${url} with data ${JSON.stringify(data)} failed. ${error}.`); - reject(error); - } - }); - } - } catch (err) { - log.log(`Processing of ${type}-request to ${url} with data ${JSON.stringify(data)} failed. ${err}.`); - reject(null); - } - }); - } - - function publicRequest(url, data, type = 'get') { - return new Promise((resolve, reject) => { - try { - const httpOptions = { - url: url, - method: type, - timeout: 10000, - }; - axios(httpOptions) - .then(function(response) { - const data = response.data; - resolve(data); - }) - .catch(function(error) { - // We can get 4xx with data - if (error.response && typeof error.response.data === 'object' && Object.keys(error.response.data).length !== 0) { - log.log(`${type.toUpperCase()}-request to ${url} failed. ${error}. Reply data: ${JSON.stringify(error.response.data)}.`); - if (error.response.status < 500) { - resolve(error.response.data); - } else { - reject(error.response.data); - } - } else { - log.log(`${type.toUpperCase()}-request to ${url} failed. ${error}.`); - reject(error); - } - }); - - } catch (err) { - log.log(`Processing of ${type}-request to ${url} failed. ${err}.`); - reject(null); - } - }); - } - - function setSign() { - signString = 'Basic '; - signString += Buffer.from(config.apiKey + ':' + config.secret_key).toString('base64'); - return signString; - } - - const EXCHANGE_API = { - - setConfig: function(apiServer, apiKey, secretKey, tradePwd, logger, publicOnly = false) { - - if (apiServer) { - WEB_BASE = apiServer; - } - - if (logger) { - log = logger; - } - - if (!publicOnly) { - config = { - 'apiKey': apiKey, - 'secret_key': secretKey, - 'tradePwd': tradePwd || '', - }; - } - - }, - - /** - * ------------------------------------------------------------------ - * (Get user balances) - * ------------------------------------------------------------------ - */ - getUserAssets: function() { - return protectedRequest('/api/v1/trading/balance'); - }, - /** - * ------------------------------------------------------------------ - * (Get user open orders) - * ------------------------------------------------------------------ - */ - getUserNowEntrustSheet: function(coinFrom, coinTo) { - const data = {}; - data.symbol = coinFrom + coinTo; - // no limit/size parameter according to docs - // https://apigateway.coindeal.com/api/doc#operation/v1getOrder - return protectedRequest('/api/v1/order', data); - }, - /** - * ------------------------------------------------------------------ - * (Place a Limit order) - * @param symbol string "ADMBTC" - * @param amount float - * @param price float - * @param side string buy, sell - * ------------------------------------------------------------------ - */ - addEntrustSheet: function(symbol, amount, price, side) { - const data = {}; - data.symbol = symbol; - data.price = price; - data.quantity = amount; - data.side = side; - data.type = 'limit'; - return protectedRequest('/api/v1/order', data, 'post'); - }, - /** - * ------------------------------------------------------------------ - * (Cancel the order) - * @param entrustSheetId string - * ------------------------------------------------------------------ - */ - cancelEntrustSheet: function(entrustSheetId) { - const data = {}; - return protectedRequest(`/api/v1/order/${entrustSheetId}`, data, 'delete'); - }, - - /** - * ------------------------------------------------------------------ - * (Get the price data) - * @param symbol ADMBTC - * ------------------------------------------------------------------ - */ - orderBook: function(symbol, size) { - const data = {}; - // default limit/size is 100; - // no limit according to docs; 0 - full orderbook otherwise number of levels - // https://apigateway.coindeal.com/api/doc#operation/v1getPublicOrderbookCurrencyPair - if (size) { - data.limit = size; - } else { - data.limit = 0; - } - return publicRequest(`${WEB_BASE}/api/v1/public/orderbook/${symbol}`, data); - }, - - /** - * Get trades history - * @param pair Trading pair, like BTCUSDT - * @param {Number} limit Default: 100. — It is wrong, tested: max limit = 20 - * @param {String} sort Enum: "DESC", "ASC". Default: "DESC" - * @param {String} by Enum: "timestamp", "id". Default: "timestamp". Filter field: timestamp in milliseconds or id - * @param {String} from If filtered by timestamp, then timestamp in millisecond otherwise trade id. Example: from=1572356518965 - * @param {String} till If filtered by timestamp, then timestamp in millisecond otherwise trade id. Example: from=1572356518965 - * @param {Number} offset Example: offset=10 - * @return {Array of Object} Last trades - */ - getTradesHistory: function(symbol, limit, sort, by, from, till, offset) { - const data = {}; - data.symbol = symbol; - if (limit) data.limit = limit; - if (sort) data.sort = sort; - if (by) data.by = by; - if (from) data.from = from; - if (till) data.till = till; - if (offset) data.offset = offset; - return protectedRequest(`/api/v2/history/trades`, data, 'get'); - }, - - /** - * ------------------------------------------------------------------ - * (Get the deposit address) - * @param symbol ADM - * ------------------------------------------------------------------ - */ - getDepositAddress: function(symbol) { - const data = {}; - return protectedRequest(`/api/v1/deposits/${symbol}/addresses`, data); - }, - - /** - * ------------------------------------------------------------------ - * (Get stats) - * @param symbol eth_btc - * ------------------------------------------------------------------ - */ - stats: function(symbol) { - return publicRequest(`https://coinmarketcap.coindeal.com/api/v1/ticker`); - }, - - - }; - - return EXCHANGE_API; -}; diff --git a/trade/settings/tradeParams_coindeal.js b/trade/settings/tradeParams_coindeal.js deleted file mode 100644 index fe1cb32f..00000000 --- a/trade/settings/tradeParams_coindeal.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = { - 'mm_buyPercent': 0.67, - 'mm_minInterval': 60000, - 'mm_maxInterval': 360000, - 'mm_isActive': false, - 'mm_minAmount': 0.1, - 'mm_maxAmount': 202, - 'mm_Policy': 'optimal', - 'mm_isOrderBookActive': true, - 'mm_orderBookHeight': 10, - 'mm_orderBookOrdersCount': 10, - 'mm_orderBookMaxOrderPercent': 50, - 'mm_isLiquidityActive': false, - 'mm_liquiditySellAmount': 100, - 'mm_liquidityBuyQuoteAmount': 50, - 'mm_liquiditySpreadPercent': 2, - 'mm_liquidityTrend': 'middle', - 'mm_isPriceWatcherActive': false, - 'mm_priceWatcherLowPriceInSourceCoin': 0, - 'mm_priceWatcherMidPriceInSourceCoin': 0, - 'mm_priceWatcherHighPriceInSourceCoin': 0, - 'mm_priceWatcherDeviationPercent': 0, - 'mm_priceWatcherSource': '#', - 'mm_priceWatcherSourcePolicy': 'smart', - 'mm_priceWatcherAction': 'fill', -}; diff --git a/trade/trader_coindeal.js b/trade/trader_coindeal.js deleted file mode 100644 index 0bc544e6..00000000 --- a/trade/trader_coindeal.js +++ /dev/null @@ -1,432 +0,0 @@ -const Coindeal = require('./api/coindeal_api'); -const utils = require('../helpers/utils'); - -// API endpoints: -// https://apigateway.coindeal.com - -const apiServer = 'https://apigateway.coindeal.com'; -const exchangeName = 'CoinDeal'; - -module.exports = (apiKey, secretKey, pwd, log, publicOnly = false) => { - const CoindealClient = Coindeal(); - - CoindealClient.setConfig(apiServer, apiKey, secretKey, pwd, log, publicOnly); - - // CoinDeal API doesn't provide market info - const defaultMarketInfo = { - coin1Decimals: 8, - coin2Decimals: 8, - }; - - return { - get markets() { - return {}; - }, - marketInfo(pair) { - pair = pair.toUpperCase().trim(); - const [coin1, coin2] = pair.split('/'); - return { - ...defaultMarketInfo, - pairPlain: pair, - coin1, - coin2, - }; - }, - features() { - return { - getMarkets: false, - placeMarketOrder: false, - getDepositAddress: true, - getDepositAddressLimit: 'Only created on website', - createDepositAddressWithWebsiteOnly: true, - getFundHistory: false, - getFundHistoryImplemented: false, - allowAmountForMarketBuy: false, - amountForMarketOrderNecessary: false, - }; - }, - - getBalances(nonzero = true) { - return new Promise((resolve, reject) => { - CoindealClient.getUserAssets().then(function(data) { - try { - let assets = data; - if (!assets) { - assets = []; - } - let result = []; - assets.forEach((crypto) => { - result.push({ - code: crypto.symbol, - free: +crypto.available, - freezed: +crypto.reserved, - total: +crypto.available + +crypto.reserved, - btc: +crypto.estimatedBalanceBtc, - usd: +crypto.estimatedBalanceUsd, - pending: +crypto.pending, - }); - }); - if (nonzero) { - result = result.filter((crypto) => crypto.free || crypto.freezed); - } - resolve(result); - } catch (e) { - resolve(false); - log.warn('Error while processing getBalances() request: ' + e); - }; - }).catch((err) => { - log.warn(`API request getBalances(nonzero: ${nonzero}) of ${utils.getModuleName(module.id)} module failed. ${err}`); - resolve(undefined); - }); - }); - }, - getOpenOrders(pair) { - pair_ = formatPairName(pair); - return new Promise((resolve, reject) => { - CoindealClient.getUserNowEntrustSheet(pair_.coin1, pair_.coin2).then(function(data) { - try { - let openOrders = data; - if (!openOrders) { - openOrders = []; - } - - const result = []; - openOrders.forEach((order) => { - let orderStatus; - switch (order.status) { - case 'new': - orderStatus = 'new'; - break; - case 'canceled': - orderStatus = 'closed'; - break; - case 'filled': - orderStatus = 'filled'; - break; - case 'partiallyFilled': - orderStatus = 'part_filled'; - break; - case 'suspended': - break; - case 'expired': - break; - default: - break; - } - result.push({ - orderId: order.id?.toString(), - symbol: order.symbol, - price: +order.price, - side: order.side, // sell or buy - type: order.type, // limit or market, etc. - timestamp: order.createdAt, - amount: +order.cumQuantity, - amountExecuted: +order.cumQuantity - +order.quantity, - amountLeft: +order.quantity, - status: orderStatus, - uid: order.clientOrderId.toString(), - // coin2Amount: order.total, - coinFrom: order.baseCurrency, - coinTo: order.quoteCurrency, - }); - }); - - resolve(result); - - } catch (e) { - resolve(false); - log.warn('Error while processing getOpenOrders() request: ' + e); - }; - }).catch((err) => { - log.warn(`API request getOpenOrders(pair: ${pair}) of ${utils.getModuleName(module.id)} module failed. ${err}`); - resolve(undefined); - }); - }); - }, - cancelOrder(orderId) { - /* - Watch this: sometimes cancelled orders on Coindeal switched to "CANCELLING" state - Balances stay frozen. To fix them, you need to contact Coindeal support. - */ - return new Promise((resolve, reject) => { - CoindealClient.cancelEntrustSheet(orderId).then(function(data) { - try { - if (data.id) { - log.log(`Cancelling order ${orderId}…`); - resolve(true); - } else { - log.log(`Order ${orderId} not found. Unable to cancel it.`); - resolve(false); - } - } catch (e) { - if (e instanceof SyntaxError) { - /* - Watch this: Sometimes you'll get