diff --git a/boot.js b/boot.js index fa1c77afeb..de34d02e38 100644 --- a/boot.js +++ b/boot.js @@ -11,6 +11,8 @@ module.exports = function (cb) { var config = {} var overrides = {} + module.exports.debug = args.debug + // 1. load conf overrides file if present if(!_.isUndefined(args.conf)){ try { diff --git a/commands/trade.js b/commands/trade.js index 4d5af3eada..edb64984b6 100644 --- a/commands/trade.js +++ b/commands/trade.js @@ -14,6 +14,7 @@ var tb = require('timebucket') , objectifySelector = require('../lib/objectify-selector') , engineFactory = require('../lib/engine') , collectionService = require('../lib/services/collection-service') + , debug = require('../lib/debug') module.exports = function (program, conf) { program @@ -519,8 +520,8 @@ module.exports = function (program, conf) { console.log('\nDumping statistics...'.grey) toggleStats() } else if (key === 'L' && !info.ctrl) { - so.debug = !so.debug - console.log('\nDEBUG mode: ' + (so.debug ? 'ON'.green.inverse : 'OFF'.red.inverse)) + debug.flip() + console.log('\nDEBUG mode: ' + (debug.on ? 'ON'.green.inverse : 'OFF'.red.inverse)) } else if (info.name === 'c' && info.ctrl) { // @todo: cancel open orders before exit console.log() diff --git a/lib/debug.js b/lib/debug.js new file mode 100644 index 0000000000..ac2cbebea1 --- /dev/null +++ b/lib/debug.js @@ -0,0 +1,15 @@ +const boot = require('../boot') +const moment = require('moment') + +let debug = boot.debug +module.exports = { + flip: function() { + module.exports.on = debug = !debug + }, + msg: function(str) { + if (debug) { + console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - ' + str) + } + }, + on: debug +} \ No newline at end of file diff --git a/lib/engine.js b/lib/engine.js index d143ddecca..8b3284ecfd 100644 --- a/lib/engine.js +++ b/lib/engine.js @@ -13,6 +13,7 @@ let tb = require('timebucket') , async = require('async') , lolex = require('lolex') , { formatAsset, formatPercent, formatCurrency } = require('./format') + , debug = require('./debug') let clock let nice_errors = new RegExp(/(slippage protection|loss protection)/) @@ -69,7 +70,7 @@ module.exports = function (s, conf) { } function memDump () { - if (!so.debug) return + if (!debug.on) return let s_copy = JSON.parse(JSON.stringify(s)) delete s_copy.options.mongo delete s_copy.lookback @@ -110,12 +111,6 @@ module.exports = function (s, conf) { } } - function msg (str) { - if (so.debug) { - console.error('\n' + moment().format('YYYY-MM-DD HH:mm:ss') + ' - ' + str) - } - } - var notifier = notify(conf) function pushMessage(title, message) { @@ -263,7 +258,7 @@ module.exports = function (s, conf) { order.product_id = s.product_id order.post_only = conf.post_only - msg('placing ' + type + ' order...') + debug.msg('placing ' + type + ' order...') let order_copy = JSON.parse(JSON.stringify(order)) s.exchange[type](order_copy, function (err, api_order) { if (err) return cb(err) @@ -271,24 +266,24 @@ module.exports = function (s, conf) { if (api_order.status === 'rejected') { if (api_order.reject_reason === 'post only') { // trigger immediate price adjustment and re-order - msg('post-only ' + type + ' failed, re-ordering') + debug.msg('post-only ' + type + ' failed, re-ordering') return cb(null, null) } else if (api_order.reject_reason === 'balance') { // treat as a no-op. - msg('not enough balance for ' + type + ', aborting') + debug.msg('not enough balance for ' + type + ', aborting') return cb(null, false) } else if (api_order.reject_reason === 'price') { // treat as a no-op. - msg('invalid price for ' + type + ', aborting') + debug.msg('invalid price for ' + type + ', aborting') return cb(null, false) } err = new Error('\norder rejected') err.order = api_order return cb(err) } - msg(type + ' order placed at ' + formatCurrency(order.price, s.currency)) + debug.msg(type + ' order placed at ' + formatCurrency(order.price, s.currency)) order.order_id = api_order.id if (!order.time) { order.orig_time = new Date(api_order.created_at).getTime() @@ -355,7 +350,7 @@ module.exports = function (s, conf) { } syncBalance(function (err, { quote }) { if (err) { - msg('error getting balance') + debug.msg('error getting balance') } let reorder_pct, fee, trade_balance, tradeable_balance, expected_fee if (err) { @@ -368,7 +363,7 @@ module.exports = function (s, conf) { } else { reorder_pct = n(size).divide(s.balance.asset).multiply(100) } - msg('price changed, resizing order, ' + reorder_pct + '% remain') + debug.msg('price changed, resizing order, ' + reorder_pct + '% remain') size = null } if (s.my_prev_trades.length) { @@ -404,7 +399,7 @@ module.exports = function (s, conf) { if (s.product.max_size && Number(size) > Number(s.product.max_size)) { size = s.product.max_size } - msg('preparing buy order over ' + formatAsset(size, s.asset) + ' of ' + formatCurrency(tradeable_balance, s.currency) + ' (' + buy_pct + '%) tradeable balance with a expected fee of ' + formatCurrency(expected_fee, s.currency) + ' (' + fee + '%)') + debug.msg('preparing buy order over ' + formatAsset(size, s.asset) + ' of ' + formatCurrency(tradeable_balance, s.currency) + ' (' + buy_pct + '%) tradeable balance with a expected fee of ' + formatCurrency(expected_fee, s.currency) + ' (' + fee + '%)') let latest_low_sell = _.chain(trades).dropRightWhile(['type','buy']).takeRightWhile(['type','sell']).sortBy(['price']).head().value() // return lowest price let buy_loss = latest_low_sell ? (latest_low_sell.price - Number(price)) / latest_low_sell.price * -100 : null if (so.max_buy_loss_pct != null && buy_loss > so.max_buy_loss_pct) { @@ -422,7 +417,7 @@ module.exports = function (s, conf) { } } if (n(s.balance.deposit).subtract(s.balance.currency_hold || 0).value() < n(price).multiply(size).value() && s.balance.currency_hold > 0) { - msg('buy delayed: ' + formatPercent(n(s.balance.currency_hold || 0).divide(s.balance.deposit).value()) + ' of funds (' + formatCurrency(s.balance.currency_hold, s.currency) + ') on hold') + debug.msg('buy delayed: ' + formatPercent(n(s.balance.currency_hold || 0).divide(s.balance.deposit).value()) + ' of funds (' + formatCurrency(s.balance.currency_hold, s.currency) + ') on hold') return setTimeout(function () { if (s.last_signal === signal) { executeSignal(signal, cb, size, true) @@ -470,7 +465,7 @@ module.exports = function (s, conf) { } } if (n(s.balance.asset).subtract(s.balance.asset_hold || 0).value() < n(size).value()) { - msg('sell delayed: ' + formatPercent(n(s.balance.asset_hold || 0).divide(s.balance.asset).value()) + ' of funds (' + formatAsset(s.balance.asset_hold, s.asset) + ') on hold') + debug.msg('sell delayed: ' + formatPercent(n(s.balance.asset_hold || 0).divide(s.balance.asset).value()) + ' of funds (' + formatAsset(s.balance.asset_hold, s.asset) + ') on hold') return setTimeout(function () { if (s.last_signal === signal) { executeSignal(signal, cb, size, true) @@ -503,19 +498,19 @@ module.exports = function (s, conf) { if (!order) { if (order === false) { // not enough balance, or signal switched. - msg('not enough balance, or signal switched, cancel ' + signal) + debug.msg('not enough balance, or signal switched, cancel ' + signal) return cb(null, null) } if (s.last_signal !== signal) { // order timed out but a new signal is taking its place - msg('signal switched, cancel ' + signal) + debug.msg('signal switched, cancel ' + signal) return cb(null, null) } // order timed out and needs adjusting - msg(signal + ' order timed out, adjusting price') + debug.msg(signal + ' order timed out, adjusting price') let remaining_size = s[signal + '_order'] ? s[signal + '_order'].remaining_size : size if (remaining_size !== size) { - msg('remaining size: ' + remaining_size) + debug.msg('remaining size: ' + remaining_size) } return executeSignal(signal, _cb, remaining_size, true) } @@ -793,7 +788,7 @@ module.exports = function (s, conf) { if (api_order.status === 'done') { order.time = new Date(api_order.done_at).getTime() order.price = api_order.price || order.price // Use actual price if possible. In market order the actual price (api_order.price) could be very different from trade price - msg('cancel failed, order done, executing') + debug.msg('cancel failed, order done, executing') executeOrder(order, type) return syncBalance(function () { cb(null, order) @@ -812,7 +807,7 @@ module.exports = function (s, conf) { if (on_hold && s.balance.currency_hold > 0) { // wait a bit for settlement - msg('funds on hold after cancel, waiting 5s') + debug.msg('funds on hold after cancel, waiting 5s') setTimeout(function() { checkHold(do_reorder, cb) }, conf.wait_for_settlement) } else { @@ -827,7 +822,7 @@ module.exports = function (s, conf) { function checkOrder (order, type, cb) { if (!s[type + '_order']) { // signal switched, stop checking order - msg('signal switched during ' + type + ', aborting') + debug.msg('signal switched during ' + type + ', aborting') return cancelOrder(order, type, false, cb) } s.exchange.getOrder({order_id: order.order_id, product_id: s.product_id}, function (err, api_order) { @@ -844,11 +839,11 @@ module.exports = function (s, conf) { }) } if (order.status === 'rejected' && (order.reject_reason === 'post only' || api_order.reject_reason === 'post only')) { - msg('post-only ' + type + ' failed, re-ordering') + debug.msg('post-only ' + type + ' failed, re-ordering') return cb(null, null) } if (order.status === 'rejected' && order.reject_reason === 'balance') { - msg('not enough balance for ' + type + ', aborting') + debug.msg('not enough balance for ' + type + ', aborting') return cb(null, null) } if (now() - order.local_time >= so.order_adjust_time) { @@ -861,11 +856,11 @@ module.exports = function (s, conf) { if (type === 'buy') { marked_price = nextBuyForQuote(s, quote) if (so.exact_buy_orders && n(order.price).value() != marked_price) { - msg(marked_price + ' vs! our ' + order.price) + debug.msg(marked_price + ' vs! our ' + order.price) cancelOrder(order, type, true, cb) } else if (n(order.price).value() < marked_price) { - msg(marked_price + ' vs our ' + order.price) + debug.msg(marked_price + ' vs our ' + order.price) cancelOrder(order, type, true, cb) } else { @@ -876,11 +871,11 @@ module.exports = function (s, conf) { else { marked_price = nextSellForQuote(s, quote) if (so.exact_sell_orders && n(order.price).value() != marked_price) { - msg(marked_price + ' vs! our ' + order.price) + debug.msg(marked_price + ' vs! our ' + order.price) cancelOrder(order, type, true, cb) } else if (n(order.price).value() > marked_price) { - msg(marked_price + ' vs our ' + order.price) + debug.msg(marked_price + ' vs our ' + order.price) cancelOrder(order, type, true, cb) } else {