price bot implementation
This commit is contained in:
parent
7718703243
commit
538cc21a34
3 changed files with 182 additions and 1 deletions
7
app.js
7
app.js
|
@ -32,6 +32,9 @@ hashbot.init(slackbot, process.env.MINING_CHANNEL);
|
||||||
var claimbot = require('./bots/claimbot');
|
var claimbot = require('./bots/claimbot');
|
||||||
claimbot.init(slackbot, process.env.CLAIMS_CHANNEL, process.env.RPCUSER, process.env.RPCPASSWORD, process.env.MONGODB_URL);
|
claimbot.init(slackbot, process.env.CLAIMS_CHANNEL, process.env.RPCUSER, process.env.RPCPASSWORD, process.env.MONGODB_URL);
|
||||||
|
|
||||||
|
var pricebot = require('./bots/pricebot');
|
||||||
|
pricebot.init(process.env.MARKET_TRADING_CHANNEL);
|
||||||
|
|
||||||
slackbot.on('start', function() {
|
slackbot.on('start', function() {
|
||||||
slackbot.on('message', function(data) {
|
slackbot.on('message', function(data) {
|
||||||
if (data.type == 'team_join') {
|
if (data.type == 'team_join') {
|
||||||
|
@ -63,6 +66,10 @@ slackbot.on('start', function() {
|
||||||
if (command === tipbot.command) {
|
if (command === tipbot.command) {
|
||||||
tipbot.respond(slackbot, data);
|
tipbot.respond(slackbot, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (command === pricebot.command) {
|
||||||
|
pricebot.respond(slackbot, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
172
bots/pricebot.js
Normal file
172
bots/pricebot.js
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
var jp = require('jsonpath');
|
||||||
|
var moment = require('moment');
|
||||||
|
var numeral = require('numeral');
|
||||||
|
var request = require('request');
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
defaultCurrency: 'USD',
|
||||||
|
|
||||||
|
// supported currencies and api steps to arrive at the final value
|
||||||
|
currencies: {
|
||||||
|
USD: { steps: ['LBCBTC', 'BTCUSD'], format: '$0,0.00' },
|
||||||
|
BTC: { steps: ['LBCBTC'], format: '0,0[.][00000000] BTC' }
|
||||||
|
},
|
||||||
|
|
||||||
|
// api steps
|
||||||
|
api: {
|
||||||
|
LBCBTC: { url: 'https://bittrex.com/api/v1.1/public/getticker?market=BTC-LBC', path: '$.result.Bid' },
|
||||||
|
BTCUSD: { url: 'https://blockchain.info/ticker', path: '$.USD.buy' }
|
||||||
|
},
|
||||||
|
|
||||||
|
// display date/time format
|
||||||
|
dtFormat: 'Do MMM YYYY h:mma [UTC]',
|
||||||
|
|
||||||
|
// refresh rate in milliseconds to retrieve a new price (default to 10 minutes)
|
||||||
|
refreshTime: 600000
|
||||||
|
};
|
||||||
|
|
||||||
|
// store the last retrieved rate
|
||||||
|
var cachedRates = {};
|
||||||
|
|
||||||
|
var mktChannel;
|
||||||
|
|
||||||
|
// !price {currency}
|
||||||
|
// !price {currency} {amount}
|
||||||
|
var command = '!price';
|
||||||
|
|
||||||
|
module.exports={
|
||||||
|
command: command,
|
||||||
|
init: init,
|
||||||
|
respond: respond
|
||||||
|
};
|
||||||
|
|
||||||
|
function init(channel_) {
|
||||||
|
mktChannel = channel_;
|
||||||
|
if (!channel_) {
|
||||||
|
console.log('No market and trading channel. Pricebot will only respond to #bot-sandbox and DMs.');
|
||||||
|
}
|
||||||
|
|
||||||
|
var currencies = Object.keys(options.currencies);
|
||||||
|
for (var i = 0; i < currencies.length; i++) {
|
||||||
|
cachedRates[currencies[i]] = { rate: 0, time: null };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalSlackParams = {};
|
||||||
|
|
||||||
|
function respond(bot, data) {
|
||||||
|
var channel = data.channel,
|
||||||
|
words = data.text.trim().split(' ').filter( function(n){return n !== "";} );
|
||||||
|
|
||||||
|
if (words[0] !== command || (channel != mktChannel && channel !== 'C1TEEBS2Z' && !channel.startsWith('D'))) {
|
||||||
|
// if the received message isn't starting with the trigger,
|
||||||
|
// or the channel is not the market-and-trading channel, nor sandbox, nor a DM -> ignore
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currency = (words.length > 1) ? words[1].toUpperCase() : options.defaultCurrency;
|
||||||
|
var amount = (words.length > 2) ? parseFloat(words[2], 10) : 1;
|
||||||
|
var showHelp = (isNaN(amount)) || (Object.keys(options.currencies).indexOf(currency) === -1);
|
||||||
|
|
||||||
|
var moveToBotSandbox = showHelp && channel !== 'C1TEEBS2Z' && !channel.startsWith("D");
|
||||||
|
if (moveToBotSandbox) {
|
||||||
|
bot.postMessage(channel, 'Please use <#C1TEEBS2Z|bot-sandbox> to talk to bots.', globalSlackParams);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showHelp) {
|
||||||
|
doHelp(bot, channel);
|
||||||
|
} else {
|
||||||
|
doSteps(bot, channel, currency, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doHelp(bot, channel) {
|
||||||
|
var message =
|
||||||
|
'`' + command + '`: show the price of 1 LBC in ' + options.defaultCurrency + '\n' +
|
||||||
|
'`' + command + ' help`: this message\n' +
|
||||||
|
'`' + command + ' CURRENCY`: show the price of 1 LBC in CURRENCY. Supported values for CURRENCY are *btc* and *usd* (case-insensitive)\n' +
|
||||||
|
'`' + command + ' CURRENCY AMOUNT`: show the price of AMOUNT LBC in CURRENCY\n';
|
||||||
|
|
||||||
|
if (!channel.startsWith("D")) {
|
||||||
|
message =
|
||||||
|
'*USE <#C1TEEBS2Z|bot-sandbox> FOR HELP*\n' +
|
||||||
|
message +
|
||||||
|
'\n' +
|
||||||
|
'*Everyone will see what I say. Send me a Direct Message if you want to interact privately.*\n' +
|
||||||
|
'If I\'m not responding in some channel, you can invite me by @mentioning me.\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.postMessage(channel, message, globalSlackParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMessage(amount, rate, option) {
|
||||||
|
var value = numeral(rate.rate * amount).format(option.format);
|
||||||
|
return '*' + numeral(amount).format('0,0[.][00000000]') + ' LBC = ' + value + '*\n_last updated ' + rate.time.utc().format(options.dtFormat) + '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSteps(bot, channel, currency, amount) {
|
||||||
|
var option = options.currencies[currency];
|
||||||
|
var shouldReload = true;
|
||||||
|
if (cachedRates[currency]) {
|
||||||
|
var cache = cachedRates[currency];
|
||||||
|
shouldReload = cache.time === null || moment().diff(cache.time) >= options.refreshTime;
|
||||||
|
if (!shouldReload) {
|
||||||
|
var message = formatMessage(amount, cache, option);
|
||||||
|
bot.postMessage(channel, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldReload) {
|
||||||
|
// copy the steps array
|
||||||
|
var steps = [];
|
||||||
|
for (var i = 0; i < option.steps.length; i++) {
|
||||||
|
steps.push(option.steps[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
processSteps(bot, channel, currency, 0, amount, steps, option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processSteps(bot, channel, currency, rate, amount, steps, option) {
|
||||||
|
if (steps.length > 0) {
|
||||||
|
var pairName = steps[0];
|
||||||
|
if (!options.api[pairName]) {
|
||||||
|
bot.postMessage(channel, 'There was a configuration error. ' + pairName + ' pair was not found.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pair = options.api[pairName];
|
||||||
|
request.get(pair.url, function(error, response, body) {
|
||||||
|
if (error) {
|
||||||
|
bot.postMessage(channel, err.message ? err.message : 'The request could not be completed at this time. Please try again later.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var pairRate = 0;
|
||||||
|
try {
|
||||||
|
pairRate = jp.query(JSON.parse(body), pair.path);
|
||||||
|
if (Array.isArray(pairRate) && pairRate.length > 0) {
|
||||||
|
pairRate = pairRate[0];
|
||||||
|
}
|
||||||
|
} catch (ignored) {
|
||||||
|
// invalid response or pair rate
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pairRate > 0) {
|
||||||
|
rate = (rate === 0) ? pairRate : rate * pairRate;
|
||||||
|
steps.shift();
|
||||||
|
if (steps.length > 0) {
|
||||||
|
processSteps(bot, channel, currency, rate, amount, steps, option);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// final step, cache and then response
|
||||||
|
var result = { rate: rate, time: moment() };
|
||||||
|
cachedRates[currency] = result;
|
||||||
|
bot.postMessage(channel, formatMessage(amount, result, option));
|
||||||
|
} else {
|
||||||
|
bot.postMessage(channel, 'The rate returned for the ' + pairName + ' pair was invalid.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,16 @@
|
||||||
{
|
{
|
||||||
"name": "hashbot",
|
"name": "hashbot",
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"description": "A bot for slack wich displays lbrys current hashrate via the open api.",
|
"description": "A bot for slack wich displays lbrys current hashrate via the open api.",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bitcoin": "^3.0.1",
|
"bitcoin": "^3.0.1",
|
||||||
"imgur": "0.1.7",
|
"imgur": "0.1.7",
|
||||||
|
"jsonpath": "0.2.11",
|
||||||
"moment": "^2.17.1",
|
"moment": "^2.17.1",
|
||||||
"mongodb": "^2.2.22",
|
"mongodb": "^2.2.22",
|
||||||
"needle": "^1.0.0",
|
"needle": "^1.0.0",
|
||||||
|
"numeral": "2.0.6",
|
||||||
"request": "^2.81.0",
|
"request": "^2.81.0",
|
||||||
"slackbots": "^0.5.1",
|
"slackbots": "^0.5.1",
|
||||||
"xmlhttprequest": "1.8.0"
|
"xmlhttprequest": "1.8.0"
|
||||||
|
|
Loading…
Reference in a new issue