diff --git a/README.md b/README.md index fb9ea77c..e4550c75 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Features: * Easy to install and configure * Free and open source * Fill order books +* Place buy and sell limit or market orders * Market making * Stores and displays statistics @@ -15,6 +16,7 @@ Supported exchanges (more in progress): * [IDCM](https://idcm.io/invitation/receive?code=LM5510&lang=en) * [Bit-Z](https://u.bit-z.com/register?invite_code=2423317) +* [CoinDeal](https://coindeal.com/ref/9WZN) Available commands: ask a bot with `/help` command. Read more: [Crypto trading & Market making bot in ADAMANT](https://medium.com/adamant-im/crypto-trading-market-making-bot-in-adamant-82fa48b78f51). diff --git a/config.json b/config.json index f0fdca1a..acaac880 100644 --- a/config.json +++ b/config.json @@ -39,7 +39,7 @@ /** Notify non-admins that they are not admins. If false, bot will be silent. **/ "notify_non_admins": true, - /** Exchange to work with. Available values: "idcm". Case insensitive. **/ + /** Exchange to work with. Available values: "IDCM", "Bit-Z", "CoinDeal". Case insensitive. **/ "exchange": "IDCM", /** Pair to trade **/ diff --git a/modules/commandTxs.js b/modules/commandTxs.js index 81ebabdd..25837f56 100644 --- a/modules/commandTxs.js +++ b/modules/commandTxs.js @@ -481,7 +481,7 @@ async function fill(params) { items = 0; let id; for (i=0; i < orderList.length; i++) { - id = await traderapi.placeOrder(type, pair, orderList[i].price, orderList[i].amount, 1); + id = (await traderapi.placeOrder(type, pair, orderList[i].price, orderList[i].amount, 1, null, pairObj)).orderid; if (id) { items += 1; total1 += +orderList[i].amount; @@ -499,19 +499,155 @@ async function fill(params) { } -/* -function buy_sell(params) { +async function buy(params) { - /buy 10 ADM at 0.00000123 on ADM/BTC - /buy 10 ADM on ADM/BTC - /buy ADM for 0.1 BTC on ADM/BTC + let result = getBuySellParams(params, 'buy'); + return await buy_sell(result, 'buy'); - /sell 10 ADM at 0.00000123 on ADM/BTC - /sell 10 ADM on ADM/BTC - /sell ADM for 0.1 BTC on ADM/BTC +} + +async function sell(params) { + + let result = getBuySellParams(params, 'sell'); + return await buy_sell(result, 'sell'); + +} + +function getBuySellParams(params, type) { + + // default: pair={config} BaseCurrency/QuoteCurrency, price=market + // amount XOR quote + // buy ADM/BTC amount=200 price=0.00000224 — buy 200 ADM at 0.00000224 + // sell ADM/BTC amount=200 price=0.00000224 — sell 200 ADM at 0.00000224 + // buy ADM/BTC quote=0.01 price=0.00000224 — buy ADM for 0.01 BTC at 0.00000224 + // sell ADM/BTC quote=0.01 price=0.00000224 — sell ADM to get 0.01 BTC at 0.00000224 + + // when Market order, buy should follow quote, sell — amount + // buy ADM/BTC quote=0.01 — buy ADM for 0.01 BTC at market price + // buy ADM/BTC quote=0.01 price=market — the same + // buy ADM/BTC quote=0.01 — buy ADM for 0.01 BTC at market price + // sell ADM/BTC amount=8 — sell 8 ADM at market price + + let amount, quote, price = 'market'; + params.forEach(param => { + try { + if (param.startsWith('quote')) { + quote = +param.split('=')[1].trim(); + } + if (param.startsWith('amount')) { + amount = +param.split('=')[1].trim(); + } + if (param.startsWith('price')) { + price = param.split('=')[1].trim(); + if (price.toLowerCase() === 'market') + price = 'market' + else + price = +price; + } + } catch (e) { + return { + msgNotify: ``, + msgSendBack: 'Wrong arguments. Command works like this: */sell ADM/BTC amount=200 price=market*.', + notifyType: 'log' + } + } + }); + + if (params.length < 1) { + return { + msgNotify: ``, + msgSendBack: 'Wrong arguments. Command works like this: */sell ADM/BTC amount=200 price=market*.', + notifyType: 'log' + } + } + + if ((quote && amount) || (!quote && !amount)) { + return { + msgNotify: ``, + msgSendBack: 'You should specify amount _or_ quote, and not both of them.', + notifyType: 'log' + } + } + + let amountOrQuote = quote || amount; + + let output = ''; + if (((!price || price === Infinity || price <= 0) && (price != 'market')) || (!amountOrQuote || amountOrQuote === Infinity || amountOrQuote <= 0)) { + output = `Incorrect params: ${amountOrQuote}, ${price}. Command works like this: */sell ADM/BTC amount=200 price=market*.`; + return { + msgNotify: ``, + msgSendBack: `${output}`, + notifyType: 'log' + } + } + + // when Market order, buy should follow quote, sell — amount + if (price === 'market') { + if ((type === 'buy' && !quote) || ((type === 'sell' && !amount))) { + output = `When placing Market order, buy should follow with _quote_, sell with _amount_. Command works like this: */sell ADM/BTC amount=200 price=market*.`; + return { + msgNotify: ``, + msgSendBack: `${output}`, + notifyType: 'log' + } + } + } + + const pairObj = setPair(params[0]); + const pair = pairObj.pair; + const coin1 = pairObj.coin1; + const coin2 = pairObj.coin2; + const coin1Decimals = pairObj.coin1Decimals; + const coin2Decimals = pairObj.coin2Decimals; + + if (!pair || !pair.length) { + output = 'Please specify market to make an order.'; + return { + msgNotify: ``, + msgSendBack: `${output}`, + notifyType: 'log' + } + } + + return { + amount, + price, + quote, + pair, + coin1, + coin2, + coin1Decimals, + coin2Decimals, + pairObj + } + +} + +async function buy_sell(params, type) { + + if (params.msgSendBack) + return params; + + if (!params.amount) { + params.amount = params.quote / params.price; + } else { + params.quote = params.amount * params.price; + } + + let result; + if (params.price === 'market') { + result = await traderapi.placeOrder(type, params.pair, null, params.amount, 0, params.quote, params.pairObj); + } else { + result = await traderapi.placeOrder(type, params.pair, params.price, params.amount, 1, params.quote, params.pairObj); + } + + return { + msgNotify: `${config.notifyName}: ${result.message}`, + msgSendBack: result.message, + notifyType: 'log' + } } -*/ function params() { @@ -557,6 +693,8 @@ Commands: **/fill**: Fill sell or buy order book. Works like this: */fill ADM/BTC buy amount=0.00200000 low=0.00000050 high=0.00000182 count=7*. +**/buy** and **/sell**: Place a limit or market order. If _price_ is not specified, market order placed. Examples: */buy ADM/BTC amount=200 price=0.00000224* — buy 200 ADM at 0.00000224 BTC. */sell ADM/BTC quote=0.01 price=0.00000224* — sell ADM to get 0.01 BTC at 0.00000224 BTC. */sell ADM/BTC amount=200* — sell 200 ADM at market price. + **/clear**: Cancel [*mm*, td, all] active orders. F. e., */clear ETH/BTC all* or just */clear* for mm-orders of default pair. **/params**: Show current trading settings @@ -677,9 +815,13 @@ Ask: ${exchangeRates.ask.toFixed(coin2Decimals)}, bid: ${exchangeRates.bid.toFix output += "\n\n" + `Market making stats for ${pair} pair:` + "\n"; if (orderStats.coin1AmountTotalDayCount != 0) { output += `24h: ${orderStats.coin1AmountTotalDayCount} orders with ${$u.thousandSeparator(+orderStats.coin1AmountTotalDay.toFixed(coin1Decimals), true)} ${coin1} and ${$u.thousandSeparator(+orderStats.coin2AmountTotalDay.toFixed(coin2Decimals), true)} ${coin2}` + } else { + output += `24h: no orders`; } if (orderStats.coin1AmountTotalMonthCount > orderStats.coin1AmountTotalDayCount) { output += `, 30d: ${orderStats.coin1AmountTotalMonthCount} orders with ${$u.thousandSeparator(+orderStats.coin1AmountTotalMonth.toFixed(coin1Decimals), true)} ${coin1} and ${$u.thousandSeparator(+orderStats.coin2AmountTotalMonth.toFixed(coin2Decimals), true)} ${coin2}` + } else if (orderStats.coin1AmountTotalMonthCount === 0) { + output += `30d: no orders`; } if (orderStats.coin1AmountTotalAllCount > orderStats.coin1AmountTotalMonthCount) { output += `, all time: ${orderStats.coin1AmountTotalAllCount} orders with ${$u.thousandSeparator(+orderStats.coin1AmountTotalAll.toFixed(coin1Decimals), true)} ${coin1} and ${$u.thousandSeparator(+orderStats.coin2AmountTotalAll.toFixed(coin2Decimals), true)} ${coin2}` @@ -842,6 +984,7 @@ async function balances() { ${output}`, notifyType: 'log' } + } function version() { @@ -872,5 +1015,7 @@ const commands = { interval, clear, fill, - params + params, + buy, + sell } \ No newline at end of file diff --git a/package.json b/package.json index f27ee2ce..c57edecd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "adamant-tradebot", - "version": "0.8.0", + "version": "0.9.0", "description": "ADAMANT Trading and Market Making bot", "main": "index.js", "scripts": { diff --git a/trade/coindeal_api.js b/trade/coindeal_api.js new file mode 100644 index 00000000..ab134dfc --- /dev/null +++ b/trade/coindeal_api.js @@ -0,0 +1,186 @@ +const request = require('request'); +const DEFAULT_HEADERS = { + "Accept": "application/json" +} + +var WEB_BASE = ''; // API server like https://apigateway.coindeal.com +var config = { + 'apiKey': '', + 'secret_key': '', + 'tradePwd': '' +}; + +function sign_api(path, data, type = 'get') { + var url = `${WEB_BASE}${path}`; + var pars = []; + for (let key in data) { + let v = data[key]; + pars.push(key + "=" + v); + } + var p = pars.join("&"); + if (p & type != 'post') + url = url + "?" + p; + let headersWithSign = Object.assign({"Authorization": setSign()}, DEFAULT_HEADERS); + + return new Promise((resolve, reject) => { + try { + var httpOptions = { + url: url, + method: type, + timeout: 3000, + headers: headersWithSign + } + if (type === 'post') { + headersWithSign = Object.assign(headersWithSign, {"Content-Type": "multipart/form-data"}); + httpOptions = Object.assign(httpOptions, {"formData": data}); + } + + // console.log(httpOptions); + request(httpOptions, function(err, res, data) { + if (err) { + reject(err); + } else { + resolve(data); + } + }).on('error', function(err){ + console.log('http get err:'+url); + reject(null); + }); + }catch(err){ + console.log('http get err:'+url); + reject(null); + } + }); +} + +function public_api(url, data, type = 'get') { + return new Promise((resolve, reject) => { + try { + var httpOptions = { + url: url, + method: type, + timeout: 10000, + } + request(httpOptions, function(err, res, data) { + if (err) { + reject(err); + } else { + resolve(data); + } + }).on('error', function(err){ + console.log('http get err:'+url); + reject(null); + }); + }catch(err){ + console.log('http get err:'+url); + reject(null); + } + }); +} + +function setSign() { + signString = 'Basic '; + signString += Buffer.from(config.apiKey + ':' + config.secret_key).toString('base64'); + return signString; +} + +var EXCHANGE_API = { + setConfig : function(apiServer,apiKey,secretKey,tradePwd){ + WEB_BASE = apiServer; + config = { + 'apiKey': apiKey , + 'secret_key': secretKey , + 'tradePwd': tradePwd || '', + }; + }, + + /** + * ------------------------------------------------------------------ + * (Get user balances) + * ------------------------------------------------------------------ + */ + getUserAssets: function() { + return sign_api("/api/v1/trading/balance"); + }, + /** + * ------------------------------------------------------------------ + * (Get user open orders) + * ------------------------------------------------------------------ + */ + getUserNowEntrustSheet: function(coinFrom, coinTo) { + let data = {}; + data.symbol = coinFrom + coinTo; + return sign_api("/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) { + var data = {}; + data.symbol = symbol; + data.price = price; + data.quantity = amount; + data.side = side; + data.type = 'limit'; + return sign_api("/api/v1/order", data, 'post'); + }, + /** + * ------------------------------------------------------------------ + * (Place a Market order) + * @param symbol string "ADMBTC" + * @param total float, Incoming amount at the time of purchase, incoming quantity at the time of sale + * @param type int "1":"buy" "2":"sale" + * ------------------------------------------------------------------ + */ + // addMarketOrder: function(symbol, total, type) { + // var data = getSignBaseParams(); + // data.symbol = symbol; + // data.total = total; + // data.type = type; + // data.tradePwd = config.tradePwd;//# + // return sign_api("/Trade/MarketTrade", data); + // }, + /** + * ------------------------------------------------------------------ + * (Cancel the order) + * @param entrustSheetId string + * ------------------------------------------------------------------ + */ + cancelEntrustSheet: function(entrustSheetId) { + return sign_api(`/api/v1/order/${entrustSheetId}`, null, 'delete'); + }, + + /** + * ------------------------------------------------------------------ + * (Get the price data) + * @param symbol ADMBTC + * ------------------------------------------------------------------ + */ + ticker: function(symbol) { + let data = {}; + data.limit = '1'; + return sign_api(`/api/v1/public/orderbook/${symbol}`, data); + }, + + /** + * ------------------------------------------------------------------ + * (Get stats) + * @param symbol eth_btc + * ------------------------------------------------------------------ + */ + stats: function(symbol) { + return public_api(`https://coinmarketcap.coindeal.com/api/v1/ticker`); + } + + + +} + + +module.exports = EXCHANGE_API; \ No newline at end of file diff --git a/trade/mm_trader.js b/trade/mm_trader.js index ab39c42f..f838f1c8 100644 --- a/trade/mm_trader.js +++ b/trade/mm_trader.js @@ -61,7 +61,7 @@ module.exports = { return; } - order1 = await traderapi.placeOrder(crossType(type), config.pair, price, coin1Amount, 1); + order1 = (await traderapi.placeOrder(crossType(type), config.pair, price, coin1Amount, 1)).orderid; if (order1) { const {ordersDb} = db; const order = new ordersDb({ @@ -84,9 +84,9 @@ module.exports = { isCancelled: false }); await order.save(); - order2 = await traderapi.placeOrder(type, config.pair, price, coin1Amount, 1); + order2 = (await traderapi.placeOrder(type, config.pair, price, coin1Amount, 1)).orderid; if (order2) { - output = `${type} ${coin1Amount.toFixed(0)} ${config.coin1} for ${coin2Amount.toFixed(8)} ${config.coin2}`; + output = `${type} ${coin1Amount.toFixed(config.coin1Decimals)} ${config.coin1} for ${coin2Amount.toFixed(config.coin2Decimals)} ${config.coin2}`; log.info(`Successfully executed mm-order to ${output}.`); order.update({ isProcessed: true, diff --git a/trade/tradeParams_coindeal.js b/trade/tradeParams_coindeal.js new file mode 100644 index 00000000..85614a9e --- /dev/null +++ b/trade/tradeParams_coindeal.js @@ -0,0 +1,8 @@ +module.exports = { + "mm_buyPercent": 0.8, + "mm_minInterval": 60000, + "mm_maxInterval": 360000, + "mm_isActive": false, + "mm_minAmount": 0.1, + "mm_maxAmount": 202 +} \ No newline at end of file diff --git a/trade/trader_bit-z.js b/trade/trader_bit-z.js index 22bc1b57..5730d8b6 100644 --- a/trade/trader_bit-z.js +++ b/trade/trader_bit-z.js @@ -140,15 +140,30 @@ module.exports = (apiKey, secretKey, pwd) => { }); }, - placeOrder(orderType, pair, price, coin1Amount, limit = 1, coin2Amount) { + placeOrder(orderType, pair, price, coin1Amount, limit = 1, coin2Amount, pairObj) { let pair_ = formatPairName(pair); let output = ''; + let message; + let order = {}; let type = (orderType === 'sell') ? 2 : 1; + if (pairObj) { // Set precision (decimals) + if (coin1Amount) { + coin1Amount = +coin1Amount.toFixed(pairObj.coin1Decimals); + if (price) + price = +price.toFixed(pairObj.coin2Decimals); + } + if (coin2Amount) { + coin2Amount = +coin2Amount.toFixed(pairObj.coin2Decimals) + if (price) + price = +price.toFixed(pairObj.coin1Decimals); + } + } + if (limit) { // Limit order - output = `${orderType} ${coin1Amount} ${pair_.coin1} at ${price} ${pair_.coin2}.`; + output = `${orderType} ${coin1Amount} ${pair_.coin1.toUpperCase()} at ${price} ${pair_.coin2.toUpperCase()}.`; return new Promise((resolve, reject) => { BITZ.addEntrustSheet(pair_.pair, +coin1Amount, +price, type).then(function (data) { @@ -156,15 +171,24 @@ module.exports = (apiKey, secretKey, pwd) => { // console.log(data); let result = JSON.parse(data).data; if (result) { - log.info(`Order placed to ${output} Order Id: ${result.id}.`); - resolve(result.id); + message = `Order placed to ${output} Order Id: ${result.id}.`; + log.info(message); + order.orderid = result.id; + order.message = message; + resolve(order); } else { - resolve(false); - log.warn(`Unable to place order to ${output} Check parameters and balances.`); + message = `Unable to place order to ${output} Check parameters and balances.`; + log.warn(message); + order.orderid = false; + order.message = message; + resolve(order); } } catch (e) { - resolve(false); - log.warn('Error while making placeOrder() request: ' + e); + message = 'Error while making placeOrder() request: ' + e; + log.warn(message); + order.orderid = false; + order.message = message; + resolve(order); }; }); }); @@ -174,18 +198,24 @@ module.exports = (apiKey, secretKey, pwd) => { if (orderType === 'sell') { if (coin1Amount) { size = coin1Amount - output = `${orderType} ${coin1Amount} ${pair_.coin1} at Market Price on ${pair_.pair} market.`; + output = `${orderType} ${coin1Amount} ${pair_.coin1.toUpperCase()} at Market Price on ${pair} market.`; } else { - log.warn(`Unable to place order to ${orderType} ${pair_.coin1} at Market Price on ${pair_.pair} market. Set ${pair_.coin1} amount.`); - return false; + message = `Unable to place order to ${orderType} ${pair_.coin1.toUpperCase()} at Market Price on ${pair} market. Set ${pair_.coin1.toUpperCase()} amount.`; + log.warn(message); + order.orderid = false; + order.message = message; + return order; } } else { // buy if (coin2Amount) { size = coin2Amount - output = `${orderType} ${pair_.coin1} for ${coin2Amount} ${pair_.coin2} at Market Price on ${pair_.pair} market.`; + output = `${orderType} ${pair_.coin1} for ${coin2Amount} ${pair_.coin2.toUpperCase()} at Market Price on ${pair} market.`; } else { - log.warn(`Unable to place order to ${orderType} ${pair_.coin1} for ${pair_.coin2} at Market Price on ${pair_.pair} market. Set ${pair_.coin2} amount.`); - return false; + message = `Unable to place order to ${orderType} ${pair_.coin1.toUpperCase()} for ${pair_.coin2.toUpperCase()} at Market Price on ${pair} market. Set ${pair_.coin2.toUpperCase()} amount.`; + log.warn(message); + order.orderid = false; + order.message = message; + return order; } } @@ -195,15 +225,24 @@ module.exports = (apiKey, secretKey, pwd) => { // console.log(data); let result = JSON.parse(data).data; if (result) { - log.info(`Order placed to ${output} Order Id: ${result.id}.`); - resolve(result.id); + message = `Order placed to ${output} Order Id: ${result.id}.`; + log.info(message); + order.orderid = result.id; + order.message = message; + resolve(order); } else { - resolve(false); - log.warn(`Unable to place order to ${output} Check parameters and balances.`); + message = `Unable to place order to ${output} Check parameters and balances.`; + log.warn(message); + order.orderid = false; + order.message = message; + resolve(order); } } catch (e) { - resolve(false); - log.warn('Error while making placeOrder() request: ' + e); + message = 'Error while making placeOrder() request: ' + e; + log.warn(message); + order.orderid = false; + order.message = message; + resolve(order); }; }); }); diff --git a/trade/trader_coindeal.js b/trade/trader_coindeal.js new file mode 100644 index 00000000..b8fdd450 --- /dev/null +++ b/trade/trader_coindeal.js @@ -0,0 +1,240 @@ +const COINDEAL = require('./coindeal_api'); +const apiServer = 'https://apigateway.coindeal.com'; +const log = require('../helpers/log'); +const $u = require('../helpers/utils'); + +// API endpoints: +// https://apigateway.coindeal.com + +module.exports = (apiKey, secretKey, pwd) => { + + COINDEAL.setConfig(apiServer, apiKey, secretKey, pwd); + + return { + getBalances(nonzero = true) { + return new Promise((resolve, reject) => { + COINDEAL.getUserAssets().then(function (data) { + try { + // console.log(data); + let assets = JSON.parse(data); + if (!assets) + assets = []; + let result = []; + assets.forEach(crypto => { + result.push({ + code: crypto.symbol, + free: +crypto.available, + freezed: +crypto.reserved, + btc: +crypto.estimatedBalanceBtc, + usd: +crypto.estimatedBalanceUsd + }); + }) + if (nonzero) { + result = result.filter(crypto => crypto.free || crypto.freezed); + } + // console.log(result); + resolve(result); + } catch (e) { + resolve(false); + log.warn('Error while making getBalances() request: ' + e); + }; + }); + }); + }, + getOpenOrders(pair) { + pair_ = formatPairName(pair); + return new Promise((resolve, reject) => { + COINDEAL.getUserNowEntrustSheet(pair_.coin1, pair_.coin2).then(function (data) { + try { + // console.log(data); + // console.log(2); + + let openOrders = JSON.parse(data); + if (!openOrders) + openOrders = []; + + let result = []; + openOrders.forEach(order => { + result.push({ + orderid: order.id, + 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, + executedamount: order.cumQuantity - order.quantity, + status: order.status, + uid: order.clientOrderId, + // coin2Amount: order.total, + coinFrom: order.baseCurrency, + coinTo: order.quoteCurrency + }); + }) + // console.log(result[0]); + // console.log(3); + + resolve(result); + + } catch (e) { + resolve(false); + log.warn('Error while making getOpenOrders() request: ' + e); + }; + }); + }); + }, + cancelOrder(orderId) { + return new Promise((resolve, reject) => { + COINDEAL.cancelEntrustSheet(orderId).then(function (data) { + try { + // console.log(data); + if (JSON.parse(data).id) { + log.info(`Cancelling order ${orderId}..`); + resolve(true); + } else { + log.info(`Order ${orderId} not found. Unable to cancel it.`); + resolve(false); + } + } catch (e) { + resolve(false); + log.warn('Error while making cancelOrder() request: ' + e); + }; + }); + }); + }, + getRates(pair) { + pair_ = formatPairName(pair); + return new Promise((resolve, reject) => { + COINDEAL.stats().then(function (data2) { + data2 = JSON.parse(data2)[pair_.coin1 + '_' + pair_.coin2]; + // console.log(data2); + try { + if (data2) { + resolve({ + volume: +data2.baseVolume, + volume_Coin2: +data2.quoteVolume, + high: +data2.high24hr, + low: +data2.low24hr, + ask: +data2.lowestAsk, + bid: +data2.highestBid + }); + } else { + resolve(false); + } + } catch (e) { + resolve(false); + log.warn('Error while making getRates() stats() request: ' + e); + }; + }); + }); + }, + + placeOrder(orderType, pair, price, coin1Amount, limit = 1, coin2Amount, pairObj) { + + let pair_ = formatPairName(pair); + let output = ''; + let message; + let order = {}; + + let type = (orderType === 'sell') ? 'sell' : 'buy'; + + if (pairObj) { // Set precision (decimals) + if (coin1Amount) { + coin1Amount = +coin1Amount.toFixed(pairObj.coin1Decimals); + if (price) + price = +price.toFixed(pairObj.coin2Decimals); + } + if (coin2Amount) { + coin2Amount = +coin2Amount.toFixed(pairObj.coin2Decimals) + if (price) + price = +price.toFixed(pairObj.coin1Decimals); + } + } + + if (limit) { // Limit order + output = `${orderType} ${coin1Amount} ${pair_.coin1.toUpperCase()} at ${price} ${pair_.coin2.toUpperCase()}.`; + + return new Promise((resolve, reject) => { + COINDEAL.addEntrustSheet(pair_.pair, +coin1Amount, +price, type).then(function (data) { + try { + // console.log(data); + let result = JSON.parse(data); + if (result) { + message = `Order placed to ${output} Order Id: ${result.id}.`; + log.info(message); + order.orderid = result.id; + order.message = message; + resolve(order); + } else { + message = `Unable to place order to ${output} Check parameters and balances.`; + log.warn(message); + order.orderid = false; + order.message = message; + resolve(order); + } + } catch (e) { + message = 'Error while making placeOrder() request: ' + e; + log.warn(message); + order.orderid = false; + order.message = message; + resolve(order); + }; + }); + }); + + } else { // Market order + let size = 0; + if (orderType === 'sell') { + if (coin1Amount) { + size = coin1Amount + output = `${orderType} ${coin1Amount} ${pair_.coin1.toUpperCase()} at Market Price on ${pair} market.`; + } else { + message = `Unable to place order to ${orderType} ${pair_.coin1.toUpperCase()} at Market Price on ${pair} market. Set ${pair_.coin1.toUpperCase()} amount.`; + log.warn(message); + order.orderid = false; + order.message = message; + return order; + } + } else { // buy + if (coin2Amount) { + size = coin2Amount + output = `${orderType} ${pair_.coin1} for ${coin2Amount} ${pair_.coin2.toUpperCase()} at Market Price on ${pair} market.`; + } else { + message = `Unable to place order to ${orderType} ${pair_.coin1.toUpperCase()} for ${pair_.coin2.toUpperCase()} at Market Price on ${pair} market. Set ${pair_.coin2.toUpperCase()} amount.`; + log.warn(message); + order.orderid = false; + order.message = message; + return order; + } + } + + message = `Unable to place order to ${output} CoinDeal doesn't support Market orders yet.`; + log.warn(message); + order.orderid = false; + order.message = message; + return order; + + } + } + } +} + +function formatPairName(pair) { + let pair_, coin1, coin2; + if (pair.indexOf('-') > -1) { + pair_ = pair.replace('-', '').toUpperCase(); + [coin1, coin2] = pair.split('-'); + } else if (pair.indexOf('_') > -1) { + pair_ = pair.replace('_', '').toUpperCase(); + [coin1, coin2] = pair.split('_'); + } else { + pair_ = pair.replace('/', '').toUpperCase(); + [coin1, coin2] = pair.split('/'); + } + + return { + pair: pair_, + coin1: coin1.toUpperCase(), + coin2: coin2.toUpperCase() + }; +} diff --git a/trade/trader_idcm.js b/trade/trader_idcm.js index f2f8c62f..bf862017 100644 --- a/trade/trader_idcm.js +++ b/trade/trader_idcm.js @@ -57,7 +57,7 @@ module.exports = (PubK, PrivK) => { }); }); }, - placeOrder(orderType, pair, price, coin1Amount, limit = 1, coin2Amount) { + placeOrder(orderType, pair, price, coin1Amount, limit = 1, coin2Amount, pairObj) { let pair_ = formatPairName(pair); const coins = $u.getCoinsFromPair(pair); @@ -66,21 +66,18 @@ module.exports = (PubK, PrivK) => { let opt; let output = ''; - const zeroDecimals = ['ADM']; - price = price.toFixed(8); - if (coin1Amount) - if (zeroDecimals.includes(coins.coin)) { - coin1Amount = coin1Amount.toFixed(0); - } else { - coin1Amount = coin1Amount.toFixed(8) + if (pairObj) { // Set precision (decimals) + if (coin1Amount) { + coin1Amount = +coin1Amount.toFixed(pairObj.coin1Decimals); + if (price) + price = +price.toFixed(pairObj.coin2Decimals); } - if (coin2Amount) - if (zeroDecimals.includes(coins.coin2)) { - coin2Amount = coin2Amount.toFixed(0) - price = price.toFixed(0); - } else { - coin2Amount = coin2Amount.toFixed(8) - } + if (coin2Amount) { + coin2Amount = +coin2Amount.toFixed(pairObj.coin2Decimals) + if (price) + price = +price.toFixed(pairObj.coin1Decimals); + } + } if (limit) { // Limit order opt = { @@ -100,6 +97,7 @@ module.exports = (PubK, PrivK) => { Type: 0 // 1 for limit price. 0 for Market price. }; output = `${orderType} ${coin1Amount} ${coins.coin} at Market Price on ${coins.pair} market.`; + console.log(opt); } else { opt = { Symbol: pair_, @@ -111,22 +109,32 @@ module.exports = (PubK, PrivK) => { } } - // console.log(opt); return new Promise((resolve, reject) => { req('trade', opt, function (data) { + let message; + let order = {}; try { if (data) { // console.log(data); - log.info(`Order placed to ${output} Order Id: ${data.orderid}.`); - resolve(data.orderid); + message = `Order placed to ${output} Order Id: ${data.orderid}.`; + log.info(message); + order.orderid = data.orderid; + order.message = message; + resolve(order); } else { - resolve(false); - log.warn(`Unable to place order to ${output} Check parameters and balances.`); + message = `Unable to place order to ${output} Check parameters and balances.`; + log.warn(message); + order.orderid = false; + order.message = message; + resolve(order); } } catch (e) { - resolve(false); - log.warn('Error while making placeOrder() request: ' + e); + message = 'Error while making placeOrder() request: ' + e; + log.warn(message); + order.orderid = false; + order.message = message; + resolve(order); }; }); });