diff --git a/conf-sample.js b/conf-sample.js index e8e8dabd4e..aafa031529 100644 --- a/conf-sample.js +++ b/conf-sample.js @@ -134,6 +134,11 @@ c.balance_snapshot_period = '15m' // avg. amount of slippage to apply to sim trades c.avg_slippage_pct = 0.045 +// send updates via slack webhook +// https://api.slack.com/incoming-webhooks +c.slack_enable = false +c.slack_webhook_url = '' + //xmpp configs c.xmppon=0 // 0 xmpp disabled; 1 xmpp enabled (credentials should be correct) diff --git a/lib/_codemap.js b/lib/_codemap.js index d591669916..27c1205683 100644 --- a/lib/_codemap.js +++ b/lib/_codemap.js @@ -11,5 +11,6 @@ module.exports = { 'rsi': require('./rsi'), 'sma': require('./sma'), 'srsi': require('./srsi'), - 'stddev': require('./stddev') + 'stddev': require('./stddev'), + 'slack': require('./slack') } diff --git a/lib/engine.js b/lib/engine.js index 3707fb469f..99d5a9e0b7 100644 --- a/lib/engine.js +++ b/lib/engine.js @@ -565,8 +565,12 @@ module.exports = function container (get, set, clear) { order_type: so.order_type } s.my_trades.push(my_trade) + var body = '\nbuy order completed at ' + moment(trade.time).format('YYYY-MM-DD HH:mm:ss') + ':\n\n' + fa(my_trade.size) + ' at ' + fc(my_trade.price) + '\ntotal ' + fc(my_trade.size * my_trade.price) + '\n' + n(my_trade.slippage).format('0.0000%') + ' slippage (orig. price ' + fc(s.buy_order.orig_price) + ')\nexecution: ' + moment.duration(my_trade.execution_time).humanize() + '\n' if (so.stats) { - console.log(('\nbuy order completed at ' + moment(trade.time).format('YYYY-MM-DD HH:mm:ss') + ':\n\n' + fa(my_trade.size) + ' at ' + fc(my_trade.price) + '\ntotal ' + fc(my_trade.size * my_trade.price) + '\n' + n(my_trade.slippage).format('0.0000%') + ' slippage (orig. price ' + fc(s.buy_order.orig_price) + ')\nexecution: ' + moment.duration(my_trade.execution_time).humanize() + '\n').cyan) + console.log(body.cyan) + } + if (c.slack_enable) { + get('lib.slack')(c, body) } s.last_buy_price = my_trade.price delete s.buy_order @@ -613,8 +617,12 @@ module.exports = function container (get, set, clear) { order_type: so.order_type } s.my_trades.push(my_trade) + var body = '\nsell order completed at ' + moment(trade.time).format('YYYY-MM-DD HH:mm:ss') + ':\n\n' + fa(my_trade.size) + ' at ' + fc(my_trade.price) + '\ntotal ' + fc(my_trade.size * my_trade.price) + '\n' + n(my_trade.slippage).format('0.0000%') + ' slippage (orig. price ' + fc(s.sell_order.orig_price) + ')\nexecution: ' + moment.duration(my_trade.execution_time).humanize() + '\n'; if (so.stats) { - console.log(('\nsell order completed at ' + moment(trade.time).format('YYYY-MM-DD HH:mm:ss') + ':\n\n' + fa(my_trade.size) + ' at ' + fc(my_trade.price) + '\ntotal ' + fc(my_trade.size * my_trade.price) + '\n' + n(my_trade.slippage).format('0.0000%') + ' slippage (orig. price ' + fc(s.sell_order.orig_price) + ')\nexecution: ' + moment.duration(my_trade.execution_time).humanize() + '\n').cyan) + console.log(body.cyan) + } + if (c.slack_enable) { + get('lib.slack')(c, body) } s.last_sell_price = my_trade.price delete s.sell_order diff --git a/lib/slack.js b/lib/slack.js new file mode 100644 index 0000000000..d11ebc7257 --- /dev/null +++ b/lib/slack.js @@ -0,0 +1,16 @@ +var IncomingWebhook = require('@slack/client').IncomingWebhook; + +module.exports = function container (get, set, clear) { + return function slack (c, body) { + var slackWebhook = new IncomingWebhook(c.slack_webhook_url || ''); + + slackWebhook.send(body, function (err, header, statusCode, body) { + if (err) { + console.error('\nerror: slack webhook') + console.error(err) + } else { + console.log('\nslack webhook statusCode = ', statusCode) + } + }); + } +} diff --git a/package-lock.json b/package-lock.json index 56d2b5e170..84fb17d66e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,76 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@slack/client": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/@slack/client/-/client-3.14.0.tgz", + "integrity": "sha512-4xPKELXtERI8k6EwbAioXZEjYhIzzk3/QDwIZMGMr+IsE5fLlLCqMR/3RC8sf8eyvh+pqlCmIPIveQsqvQkIJg==", + "requires": { + "async": "1.5.2", + "bluebird": "3.5.0", + "eventemitter3": "1.2.0", + "https-proxy-agent": "1.0.0", + "inherits": "2.0.3", + "lodash": "4.17.4", + "pkginfo": "0.4.1", + "request": "2.81.0", + "retry": "0.9.0", + "url-join": "0.0.1", + "winston": "2.4.0", + "ws": "1.1.4" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" + }, + "pkginfo": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz", + "integrity": "sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8=" + }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" + }, + "winston": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.0.tgz", + "integrity": "sha1-gIBQuT1SZh7Z+2wms/DIJnCLCu4=", + "requires": { + "async": "1.0.0", + "colors": "1.0.3", + "cycle": "1.0.3", + "eyes": "0.1.8", + "isstream": "0.1.2", + "stack-trace": "0.0.10" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" + } + } + }, + "ws": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz", + "integrity": "sha1-V/QNA2gy5fUFVmKjl8Tedu1mv2E=", + "requires": { + "options": "0.0.6", + "ultron": "1.0.2" + } + } + } + }, "@xmpp/jid": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/@xmpp/jid/-/jid-0.0.2.tgz", @@ -51,6 +121,22 @@ } } }, + "agent-base": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", + "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "requires": { + "extend": "3.0.1", + "semver": "5.0.3" + }, + "dependencies": { + "semver": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=" + } + } + }, "ajv": { "version": "5.1.5", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.1.5.tgz", @@ -732,6 +818,11 @@ "through": "2.3.8" } }, + "eventemitter3": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", + "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=" + }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", @@ -1149,6 +1240,16 @@ "sshpk": "1.13.1" } }, + "https-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "requires": { + "agent-base": "2.1.1", + "debug": "2.6.8", + "extend": "3.0.1" + } + }, "iconv-lite": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", @@ -2342,6 +2443,11 @@ "signal-exit": "3.0.2" } }, + "retry": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.9.0.tgz", + "integrity": "sha1-b2l+UKDk3cjI9/tUeptg3q1DZ40=" + }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", @@ -2697,6 +2803,11 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=" }, + "url-join": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-0.0.1.tgz", + "integrity": "sha1-HbSK1CLTQCRpqH99l73r/k+x48g=" + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index ee687b1403..95d5fe479d 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "zenbot": "./zenbot.sh" }, "dependencies": { + "@slack/client": "^3.14.0", "async": "^2.5.0", "bitfinex-api-node": "^1.2.0", "bitstamp": "^1.0.4",