Skip to content
This repository has been archived by the owner on Feb 15, 2022. It is now read-only.

Commit

Permalink
Notifier interaction: add events to notifiers, possibly fix #1550 (#2070
Browse files Browse the repository at this point in the history
)

* stale[bot] (#1744)

* fix: upgrade lint-staged from 10.1.1 to 10.1.2 (#2063)

Snyk has created this PR to upgrade lint-staged from 10.1.1 to 10.1.2.

See this package in NPM:
https://www.npmjs.com/package/lint-staged

See this project in Snyk:
https://app.snyk.io/org/deviavir/project/14e19887-e219-40d4-89b6-6c657bf78942?utm_source=github&utm_medium=upgrade-pr

* fix: upgrade ccxt from 1.25.80 to 1.25.81 (#2064)

Snyk has created this PR to upgrade ccxt from 1.25.80 to 1.25.81.

See this package in NPM:
https://www.npmjs.com/package/ccxt

See this project in Snyk:
https://app.snyk.io/org/deviavir/project/14e19887-e219-40d4-89b6-6c657bf78942?utm_source=github&utm_medium=upgrade-pr

* Exchanges: update-products 5838

* fix: upgrade css-loader from 3.4.2 to 3.5.0 (#2067)

Snyk has created this PR to upgrade css-loader from 3.4.2 to 3.5.0.

See this package in NPM:
https://www.npmjs.com/package/css-loader

See this project in Snyk:
https://app.snyk.io/org/deviavir/project/14e19887-e219-40d4-89b6-6c657bf78942?utm_source=github&utm_medium=upgrade-pr

* fix: upgrade ccxt from 1.25.81 to 1.25.83 (#2066)

Snyk has created this PR to upgrade ccxt from 1.25.81 to 1.25.83.

See this package in NPM:
https://www.npmjs.com/package/ccxt

See this project in Snyk:
https://app.snyk.io/org/deviavir/project/14e19887-e219-40d4-89b6-6c657bf78942?utm_source=github&utm_medium=upgrade-pr

* fix: upgrade semver from 7.1.3 to 7.2.1 (#2065)

Snyk has created this PR to upgrade semver from 7.1.3 to 7.2.1.

See this package in NPM:
https://www.npmjs.com/package/semver

See this project in Snyk:
https://app.snyk.io/org/deviavir/project/14e19887-e219-40d4-89b6-6c657bf78942?utm_source=github&utm_medium=upgrade-pr

* Exchanges: update-products 5852

* fix: upgrade css-loader from 3.5.0 to 3.5.1 (#2069)

Snyk has created this PR to upgrade css-loader from 3.5.0 to 3.5.1.

See this package in NPM:
https://www.npmjs.com/package/css-loader

See this project in Snyk:
https://app.snyk.io/org/deviavir/project/14e19887-e219-40d4-89b6-6c657bf78942?utm_source=github&utm_medium=upgrade-pr

* fix: upgrade ccxt from 1.25.83 to 1.25.86 (#2068)

Snyk has created this PR to upgrade ccxt from 1.25.83 to 1.25.86.

See this package in NPM:
https://www.npmjs.com/package/ccxt

See this project in Snyk:
https://app.snyk.io/org/deviavir/project/14e19887-e219-40d4-89b6-6c657bf78942?utm_source=github&utm_medium=upgrade-pr

* Exchanges: update-products 5862

* Notifier interaction: add events to notifiers in order to receive commands also from a connected notifier.

Implemented only for Telegram at the moment.
 - list of accepted commands is the same used in command line
 - check the correct origin of the message looking at chat ID
 - accept the flag 'c.notifiers.telegram.interactive' (default = false)
   to enable/disable this feature

This commit provides a possible solution for feature request #1550

Co-authored-by: Chase <chase@sillevis.net>
Co-authored-by: Snyk bot <snyk-bot@snyk.io>
Co-authored-by: Travis CI <travis@travis-ci.org>
  • Loading branch information
4 people committed Apr 10, 2020
1 parent 360407f commit fe3948f
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 77 deletions.
167 changes: 94 additions & 73 deletions commands/trade.js
Expand Up @@ -120,47 +120,44 @@ module.exports = function (program, conf) {
keyMap.set('d', 'dump statistical output to HTML file'.grey)
keyMap.set('D', 'toggle automatic HTML dump to file'.grey)

var pushStr = ''

function listKeys() {
console.log('\nAvailable command keys:')
printLog('Available command keys:', true)
keyMap.forEach((value, key) => {
console.log(' ' + key + ' - ' + value)
printLog(' ' + key + ' - ' + value)
})
}

function listOptions () {
console.log()
console.log(s.exchange.name.toUpperCase() + ' exchange active trading options:'.grey)
console.log()
process.stdout.write(z(22, 'STRATEGY'.grey, ' ') + '\t' + so.strategy + '\t' + (require(`../extensions/strategies/${so.strategy}/strategy`).description).grey)
console.log('\n')
process.stdout.write([
printLog(s.exchange.name.toUpperCase() + ' exchange active trading options:'.grey, true)
printLog(z(22, 'STRATEGY'.grey, ' ') + '\t' + so.strategy + '\t' + (require(`../extensions/strategies/${so.strategy}/strategy`).description).grey, true)
printLog([
z(24, (so.mode === 'paper' ? so.mode.toUpperCase() : so.mode.toUpperCase()) + ' MODE'.grey, ' '),
z(26, 'PERIOD'.grey, ' '),
z(30, 'ORDER TYPE'.grey, ' '),
z(28, 'SLIPPAGE'.grey, ' '),
z(33, 'EXCHANGE FEES'.grey, ' ')
].join('') + '\n')
process.stdout.write([
].join(''), true)
printLog([
z(15, (so.mode === 'paper' ? ' ' : (so.mode === 'live' && (so.manual === false || typeof so.manual === 'undefined')) ? ' ' + 'AUTO'.black.bgRed + ' ' : ' ' + 'MANUAL'.black.bgGreen + ' '), ' '),
z(13, so.period_length, ' '),
z(29, (so.order_type === 'maker' ? so.order_type.toUpperCase().green : so.order_type.toUpperCase().red), ' '),
z(31, (so.mode === 'paper' ? 'avg. '.grey + so.avg_slippage_pct + '%' : 'max '.grey + so.max_slippage_pct + '%'), ' '),
z(20, (so.order_type === 'maker' ? so.order_type + ' ' + s.exchange.makerFee : so.order_type + ' ' + s.exchange.takerFee), ' ')
].join('') + '\n')
process.stdout.write('')
process.stdout.write([
].join(''))
printLog([
z(19, 'BUY %'.grey, ' '),
z(20, 'SELL %'.grey, ' '),
z(35, 'TRAILING STOP %'.grey, ' '),
z(33, 'TRAILING DISTANCE %'.grey, ' ')
].join('') + '\n')
process.stdout.write([
].join(''))
printLog([
z(9, so.buy_pct + '%', ' '),
z(9, so.sell_pct + '%', ' '),
z(20, so.profit_stop_enable_pct + '%', ' '),
z(20, so.profit_stop_pct + '%', ' ')
].join('') + '\n')
process.stdout.write('')
].join(''))
}

/* Implementing statistical Exit */
Expand Down Expand Up @@ -226,7 +223,7 @@ module.exports = function (program, conf) {
}
if (!statsonly) {
output_lines.forEach(function (line) {
console.log(line)
printLog(line)
})
}
if (quit || dump) {
Expand Down Expand Up @@ -275,9 +272,9 @@ module.exports = function (program, conf) {
function toggleStats(){
shouldSaveStats = !shouldSaveStats
if(shouldSaveStats)
console.log('Auto stats dump enabled')
printLog('Auto stats dump enabled')
else
console.log('Auto stats dump disabled')
printLog('Auto stats dump disabled')
}

function saveStatsLoop(){
Expand Down Expand Up @@ -368,6 +365,79 @@ module.exports = function (program, conf) {

}

function printLog(str, cr = false) {
if (str) {
console.log((cr?'\n':'') + str)
pushStr += str + '\n'
}
}

function executeCommand(command) {
var info = { ctrl: false }
if (conf.debug) {
console.log('\nCommand received: ' + command)
}
executeKey(command, info)
}

function executeKey(key, info) {
if (key === 'l') {
listKeys()
} else if (key === 'b' && !info.ctrl ) {
engine.executeSignal('buy')
printLog('manual'.grey + ' limit ' + 'BUY'.green + ' command executed'.grey, true)
} else if (key === 'B' && !info.ctrl) {
engine.executeSignal('buy', null, null, false, true)
printLog('manual'.grey + ' market ' + 'BUY'.green + ' command executed'.grey, true)
} else if (key === 's' && !info.ctrl) {
engine.executeSignal('sell')
printLog('manual'.grey + ' limit ' + 'SELL'.red + ' command executed'.grey, true)
} else if (key === 'S' && !info.ctrl) {
engine.executeSignal('sell', null, null, false, true)
printLog('manual'.grey + ' market ' + 'SELL'.red + ' command executed'.grey, true)
} else if ((key === 'c' || key === 'C') && !info.ctrl) {
delete s.buy_order
delete s.sell_order
printLog('manual'.grey + ' order cancel' + ' command executed'.grey, true)
} else if (key === 'm' && !info.ctrl && so.mode === 'live') {
so.manual = !so.manual
printLog('MANUAL trade in LIVE mode: ' + (so.manual ? 'ON'.green.inverse : 'OFF'.red.inverse), true)
} else if (key === 'T' && !info.ctrl) {
so.order_type = 'taker'
printLog('Taker fees activated'.bgRed, true)
} else if (key === 'M' && !info.ctrl) {
so.order_type = 'maker'
printLog('Maker fees activated'.black.bgGreen, true)
} else if (key === 'o' && !info.ctrl) {
listOptions()
} else if (key === 'O' && !info.ctrl) {
printLog(cliff.inspect(so), true)
} else if (key === 'P' && !info.ctrl) {
printLog('Writing statistics...'.grey, true)
printTrade(false)
} else if (key === 'X' && !info.ctrl) {
printLog('Exiting... ' + '\nWriting statistics...'.grey, true)
printTrade(true)
} else if (key === 'd' && !info.ctrl) {
printLog('Dumping statistics...'.grey, true)
printTrade(false, true)
} else if (key === 'D' && !info.ctrl) {
printLog('Dumping statistics...'.grey, true)
toggleStats()
} else if (key === 'L' && !info.ctrl) {
debug.flip()
printLog('DEBUG mode: ' + (debug.on ? 'ON'.green.inverse : 'OFF'.red.inverse), true)
} else if (info.name === 'c' && info.ctrl) {
// @todo: cancel open orders before exit
process.exit()
}

if (pushStr) {
engine.pushMessage('Reply', colors.stripColors(pushStr))
pushStr = ''
}
}

var order_types = ['maker', 'taker']
if (!order_types.includes(so.order_type)) {
so.order_type = 'maker'
Expand Down Expand Up @@ -483,62 +553,13 @@ module.exports = function (program, conf) {

forwardScan()
setInterval(forwardScan, so.poll_trades)
if (!so.non_interactive) {
engine.onMessage(executeCommand)
}
readline.emitKeypressEvents(process.stdin)
if (!so.non_interactive && process.stdin.setRawMode) {
process.stdin.setRawMode(true)
process.stdin.on('keypress', function (key, info) {
if (key === 'l') {
listKeys()
} else if (key === 'b' && !info.ctrl ) {
engine.executeSignal('buy')
console.log('\nmanual'.grey + ' limit ' + 'BUY'.green + ' command executed'.grey)
} else if (key === 'B' && !info.ctrl) {
engine.executeSignal('buy', null, null, false, true)
console.log('\nmanual'.grey + ' market ' + 'BUY'.green + ' command executed'.grey)
} else if (key === 's' && !info.ctrl) {
engine.executeSignal('sell')
console.log('\nmanual'.grey + ' limit ' + 'SELL'.red + ' command executed'.grey)
} else if (key === 'S' && !info.ctrl) {
engine.executeSignal('sell', null, null, false, true)
console.log('\nmanual'.grey + ' market ' + 'SELL'.red + ' command executed'.grey)
} else if ((key === 'c' || key === 'C') && !info.ctrl) {
delete s.buy_order
delete s.sell_order
console.log('\nmanual'.grey + ' order cancel' + ' command executed'.grey)
} else if (key === 'm' && !info.ctrl && so.mode === 'live') {
so.manual = !so.manual
console.log('\nMANUAL trade in LIVE mode: ' + (so.manual ? 'ON'.green.inverse : 'OFF'.red.inverse))
} else if (key === 'T' && !info.ctrl) {
so.order_type = 'taker'
console.log('\n' + 'Taker fees activated'.bgRed)
} else if (key === 'M' && !info.ctrl) {
so.order_type = 'maker'
console.log('\n' + 'Maker fees activated'.black.bgGreen)
} else if (key === 'o' && !info.ctrl) {
listOptions()
} else if (key === 'O' && !info.ctrl) {
console.log('\n' + cliff.inspect(so))
} else if (key === 'P' && !info.ctrl) {
console.log('\nWriting statistics...'.grey)
printTrade(false)
} else if (key === 'X' && !info.ctrl) {
console.log('\nExiting... ' + '\nWriting statistics...'.grey)
printTrade(true)
} else if (key === 'd' && !info.ctrl) {
console.log('\nDumping statistics...'.grey)
printTrade(false, true)
} else if (key === 'D' && !info.ctrl) {
console.log('\nDumping statistics...'.grey)
toggleStats()
} else if (key === 'L' && !info.ctrl) {
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()
process.exit()
}
})
process.stdin.on('keypress', executeKey)
}
})
})
Expand Down
1 change: 1 addition & 0 deletions conf-sample.js
Expand Up @@ -262,6 +262,7 @@ c.notifiers.pushover.priority = '0' // choose a priority to send zenbot messages
// telegram configs
c.notifiers.telegram = {}
c.notifiers.telegram.on = false // false telegram disabled; true telegram enabled (key should be correct)
c.notifiers.telegram.interactive = false // true telegram is interactive
c.notifiers.telegram.bot_token = 'YOUR-BOT-TOKEN'
c.notifiers.telegram.chat_id = 'YOUR-CHAT-ID' // the id of the chat the messages should be send in
// end telegram configs
Expand Down
24 changes: 22 additions & 2 deletions extensions/notifiers/telegram.js
Expand Up @@ -3,14 +3,34 @@ process.env['NTBA_FIX_319'] = 1
var TelegramBot = require('node-telegram-bot-api')

module.exports = function telegram (config) {
var bot = new TelegramBot(config.bot_token, { polling: true })
var wrapper = function(cb) {
return function(message) {
if (message.chat.id != config.chat_id) {
console.log('\nChat ID error: command coming from wrong chat: ' + message.chat.id)
return
}
cb(message.text)
}
}
var telegram = {
pushMessage: function(title, message) {
var bot = new TelegramBot(config.bot_token)

bot.sendMessage(config.chat_id, title + ': ' + message).catch(function (error) {
console.error('\nerror: telegram notification')
console.log(error.response.body) // => { ok: false, error_code: 400, description: 'Bad Request: chat not found' }
})
},
onMessage: function (callback) {
bot.on('message', wrapper(callback))
bot.on('webhook_error', (error) => {
console.log('\nwebhook error: telegram event ' + error.code)
})
bot.on('polling_error', (error) => {
console.log('\npolling error: telegram event ' + error.code)
})
bot.on('error', (error) => {
console.log('\nerror: telegram event ' + error.code)
})
}
}
return telegram
Expand Down
8 changes: 8 additions & 0 deletions lib/engine.js
Expand Up @@ -119,6 +119,12 @@ module.exports = function (s, conf) {
}
}

function onMessage(callback) {
if (so.mode === 'live' || so.mode === 'paper') {
notifier.onMessage(callback)
}
}

function isFiat() {
return !s.currency.match(/^BTC|ETH|XMR|USDT$/)
}
Expand Down Expand Up @@ -996,6 +1002,8 @@ module.exports = function (s, conf) {
executeSignal: executeSignal,
writeReport: writeReport,
syncBalance: syncBalance,
pushMessage: pushMessage,
onMessage: onMessage,
}
}

20 changes: 18 additions & 2 deletions lib/notify.js
@@ -1,8 +1,16 @@
module.exports = function notifier (conf) {
var active_notifiers = []
var interactive_notifiers = []

for (var notifier in conf.notifiers) {
if (conf.notifiers[notifier].on) {
active_notifiers.push(require(`../extensions/notifiers/${notifier}`)(conf.notifiers[notifier]))
var notif = require(`../extensions/notifiers/${notifier}`)(conf.notifiers[notifier])
notif.notifier_name = notifier

active_notifiers.push(notif)
if (conf.notifiers[notifier].interactive) {
interactive_notifiers.push(notif)
}
}
}

Expand All @@ -14,10 +22,18 @@ module.exports = function notifier (conf) {

active_notifiers.forEach((notifier) => {
if (conf.debug) {
console.log(`Sending push message via ${notifier}`)
console.log(`Sending push message via ${notifier.notifier_name}`)
}
notifier.pushMessage(title, message)
})
},
onMessage: function (callback) {
interactive_notifiers.forEach((notifier) => {
if (conf.debug) {
console.log(`Receiving message from ${notifier.notifier_name}`)
}
notifier.onMessage(callback)
})
}
}
}

0 comments on commit fe3948f

Please sign in to comment.