Skip to content

Commit

Permalink
Add local exchanges
Browse files Browse the repository at this point in the history
  • Loading branch information
lopezjurip committed Jan 12, 2018
1 parent ac01429 commit 6c725e8
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 47 deletions.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
"@cryptolatam/cryptomkt": "^0.2.1",
"@cryptolatam/money": "^0.1.7",
"@cryptolatam/surbtc": "^0.2.1",
"@cryptolw/error": "^0.0.3",
"@cryptolw/exchange-cryptomkt": "^0.0.2",
"@cryptolw/exchange-surbtc": "^0.0.2",
"@cryptolw/money-data": "^0.0.2",
"@cryptolw/money-format": "^0.0.2",
"@cryptolw/money-parse": "^0.0.3",
Expand All @@ -46,11 +49,12 @@
"koa-logger": "^3.1.0",
"koa-router": "^7.3.0",
"lodash": "^4.17.4",
"millisecond": "^0.1.2",
"moment": "^2.19.1",
"mz": "^2.7.0",
"nconf": "^0.8.5",
"numeral": "^2.0.6",
"rxjs": "^5.4.2",
"rxjs": "^5.5.6",
"scrape-it": "^4.1.2",
"telegraf": "^3.17.2",
"winston": "^2.4.0",
Expand Down
213 changes: 182 additions & 31 deletions src/bot.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use strict";

const Telegraf = require("telegraf");
const Bluebird = require("bluebird");
const dedent = require("dedent");
const numeral = require("numeral");
const columnify = require("columnify");
Expand All @@ -13,11 +14,14 @@ const moneyData = require("@cryptolw/money-data");

const coins = require("./data/meta");
const { getCountry } = require("./data/countries");
const { watchPairs } = require("./providers/exchanges");
const CoinMarketCap = require("./providers/CoinMarketCap");

module.exports = function createBot(options) {
const { logger, config, info } = options;

const { sources } = watchPairs(options);

const { format } = formatter([moneyData.crypto, moneyData.fiat]);
const cmc = new CoinMarketCap();

Expand Down Expand Up @@ -92,8 +96,6 @@ module.exports = function createBot(options) {
});

bot.command("start", async ctx => {
await ctx.replyWithChatAction("typing");

await ctx.replyWithMarkdown(dedent`
👋 Hi there! This is Cryptowl Bot 🦉🔮
Expand All @@ -105,26 +107,38 @@ module.exports = function createBot(options) {
});

bot.command("help", async ctx => {
await ctx.replyWithChatAction("typing");

await ctx.replyWithMarkdown(dedent`
*Some commands:*
\`/top[number][_convert]\`
Ranked coins and optionally convert the _fiat_ value.
/top /top\_CLP /top20 /top20\_CLP
/top
/top\_CLP
/top20
/top20\_CLP
\`/(coin)[_convert]\`
Particular coin and optionally convert the _fiat_ value.
/BTC /eth /MIOTA\_CLP /neo\_eur
/BTC
/eth
/MIOTA\_CLP
/neo\_eur
\`/exchanges_(coin)_(convert)\`
Get exchanges with that pair
/exchanges\_BTC\_CLP
/exchanges\_ETH\_CLP
\`/rates_(coin)[_convert]\`
Get global exchange rates for that pair and convert
/rates\_BTC
/rates\_BTC\_CLP
👉 Type /donations to keep this bot alive 🙂
`);
});

bot.command("about", async ctx => {
await ctx.replyWithChatAction("typing");

await ctx.replyWithMarkdown(dedent`
*@cryptowl_bot (${info.version})*
*License:* ${info.license}
Expand All @@ -143,8 +157,6 @@ module.exports = function createBot(options) {
});

bot.command("donations", async ctx => {
await ctx.replyWithChatAction("typing");

const wallets = ["BTC", "ETH", "DASH", "BCH", "LTC", "CHA", "ADA"];
await ctx.replyWithMarkdown(dedent`
*Thanks for caring about the project!*
Expand All @@ -171,7 +183,7 @@ module.exports = function createBot(options) {
/top5_CLP
*/
bot.hears(/^\/top(\d+)?_{0,1}([A-z0-9]+)?$/i, async ctx => {
await ctx.replyWithChatAction("typing");
bot.telegram.sendChatAction(ctx.from.id, "typing"); // TODO: ctx.replyWithChatAction("typing") is broken

const [, limit, convert] = ctx.match;

Expand Down Expand Up @@ -220,16 +232,141 @@ module.exports = function createBot(options) {
// ctx.reply([coin, change, convert]);
// });

/*
Example:
/exchanges_BTC_CLP
*/
bot.hears(/^\/exchanges_([A-z0-9]+)_([A-z0-9]+)$/, async ctx => {
bot.telegram.sendChatAction(ctx.from.id, "typing"); // TODO: ctx.replyWithChatAction("typing") is broken

const [, coinId, convert] = ctx.match.map(s => s.toUpperCase());

const houses = [];
const identifier = [coinId, convert].join("/");
if (sources.value.has(identifier)) {
const exchanges = sources.value.get(identifier) || [];
const queries = exchanges
.map(exchange => exchange.getCurrent([[coinId, convert]]))
.map(p => Bluebird.resolve(p).reflect());

const results = await Bluebird.all(queries);

const data = results
.filter(inspection => inspection.isFulfilled())
.map(inspection => inspection.value()[0])
.map(
exchange => dedent`
🏦 *${exchange.exchange}* (${link(...exchange.pair)}):
📤 BID: \`${format(exchange.ask, { code: true })}\`
📥 ASK: \`${format(exchange.bid, { code: true })}\`
📊 Volumen: \`${format(exchange.volume, { code: true })}\`
`
);

houses.push(...data);
}

// Put additional and sources steps here.

if (_.isEmpty(houses)) {
await ctx.replyWithMarkdown(dedent`
Missing exchanges with that support :(
`);
} else {
await ctx.replyWithMarkdown(dedent`
${houses.join("\n\n")}
`);
}
});

/*
Example:
/rates_BTC_CLP
*/
bot.hears(/^\/rates_([A-z0-9]+)_([A-z0-9]+)$/, async ctx => {
bot.telegram.sendChatAction(ctx.from.id, "typing"); // TODO: ctx.replyWithChatAction("typing") is broken

const [, coinId, convert] = ctx.match.map(s => s.toUpperCase());

const data = await cmc.getCoin(coinId, { convert });
const { rates, markets } = await cmc.getCoinRates(coinId, { convert });
const to = _.toUpper(convert);

if (!data) {
return ctx.reply("Coin not found.");
} else if (!rates[to]) {
return ctx.reply("Conversion not supported yet.");
}

const [, units] = cmc.format(data, to);

const rate = rates[to];
const rows = CoinMarketCap.aggregateMarkets(markets, { limit: 10 }).map(market => {
const share = numeral(market.share).format("0.00%");
const price = parse(market.price["USD"][0] / rate, to);
const value = format(price, { code: true }).split(" ")[0];
const about = getCountry(market.symbol) || coins.find(item => _.toUpper(item["symbol"]) === market.symbol) || {};
const emoji = about.emoji || "💎";
return dedent`
💱 ${link(units[0], market.symbol)}${share}
${emoji} \`${value}\` ${link(...units)}
`;
});

await ctx.replyWithMarkdown(dedent`
${rows.join("\n----\n")}
_rate: ${rate < 1 ? `1 USD = ${1 / rate} ${to}` : `1 ${to} = ${rate} USD`}_
`);
});

/*
Example:
/rates_BTC
TODO: DRY
*/
bot.hears(/^\/rates_([A-z0-9]+)$/, async ctx => {
bot.telegram.sendChatAction(ctx.from.id, "typing"); // TODO: ctx.replyWithChatAction("typing") is broken

const [, coinId] = ctx.match.map(s => s.toUpperCase());

const data = await cmc.getCoin(coinId);
const { markets } = await cmc.getCoinRates(coinId);

if (!data) {
return ctx.reply("Coin not found.");
}

const [, units] = cmc.format(data, "USD");

const rows = CoinMarketCap.aggregateMarkets(markets, { limit: 10 }).map(market => {
const share = numeral(market.share).format("0.00%");
const price = parse(market.price["USD"][0], "USD");
const value = format(price, { code: true }).split(" ")[0];
const about = getCountry(market.symbol) || coins.find(item => _.toUpper(item["symbol"]) === market.symbol) || {};
const emoji = about.emoji || "💎";
return dedent`
💱 ${link(units[0], market.symbol)}${share}
${emoji} \`${value}\` ${link(...units)}
`;
});

await ctx.replyWithMarkdown(dedent`
${rows.join("\n----\n")}
`);
});

/*
Example:
/BTC_CLP
*/
bot.hears(/^\/([A-z0-9]+)_([A-z0-9]+)$/, async ctx => {
await ctx.replyWithChatAction("typing");
bot.telegram.sendChatAction(ctx.from.id, "typing"); // TODO: ctx.replyWithChatAction("typing") is broken

const [, coinId, convert] = ctx.match.map(s => s.toUpperCase());

const { result: data, rates } = await cmc.getCoin(coinId, { convert });
const data = await cmc.getCoin(coinId, { convert });
const { rates } = await cmc.getCoinRates(coinId, { convert });
const to = _.toUpper(convert);

if (!data) {
Expand Down Expand Up @@ -273,42 +410,45 @@ module.exports = function createBot(options) {
.toUpperCase();

const rate = rates[to];
const markets = CoinMarketCap.aggregateMarkets(data["markets"]);
const rows = markets.map(market => {
const share = numeral(market.share).format("0.00%");
const price = parse(market.price["USD"][0] / rate, to);
const value = format(price, { code: true }).split(" ")[0];
const about = getCountry(market.symbol) || coins.find(item => _.toUpper(item["symbol"]) === market.symbol) || {};
const emoji = about.emoji || "💎";
return dedent`
💱 ${link(units[0], market.symbol)}${share}
${emoji} \`${value}\` ${link(...units)}
`;
});

await ctx.replyWithMarkdown(dedent`
const header = dedent`
${arrow} *${data.info["name"]}*
🌐 \`${number}\` ${link(...units)}
💰 \`${cap} ${_.toUpper(convert)}\`
🏆 \`#${data["rank"]}\`
`;

${rows.join("\n----\n")}
const links = dedent`
💡 /${data.info["symbol"]}
💡 /exchanges\_${data.info["symbol"]}\_${to}
💡 /rates\_${data.info["symbol"]}\_${to}
`;

const conversions = dedent`
_rate: ${rate < 1 ? `1 USD = ${1 / rate} ${to}` : `1 ${to} = ${rate} USD`}_
`;

await ctx.replyWithMarkdown(dedent`
${header}
${columns}
${links}
${conversions}
`);
// _rate: ${rate < 1 ? `1 USD = ${1 / rate} ${to}` : `1 ${to} = ${rate} USD`}_
});

/*
Example:
/BTC
*/
bot.hears(/^\/([A-z0-9]+)$/, async ctx => {
await ctx.replyWithChatAction("typing");
bot.telegram.sendChatAction(ctx.from.id, "typing"); // TODO: ctx.replyWithChatAction("typing") is broken

const [, coinId] = ctx.match.map(s => s.toUpperCase());

const { result: data } = await cmc.getCoin(coinId);
const data = await cmc.getCoin(coinId);

if (!data) {
return ctx.reply("Coin not found.");
Expand Down Expand Up @@ -347,13 +487,24 @@ module.exports = function createBot(options) {
.format("0.00 a")
.toUpperCase();

await ctx.replyWithMarkdown(dedent`
const header = dedent`
${arrow} *${data.info["name"]}*
🌐 \`${number}\` ${link(...units)}
💰 \`${cap} USD\`
🏆 \`#${data["rank"]}\`
`;

const links = dedent`
💡 /${data.info["symbol"]}\_CLP
💡 /rates\_${data.info["symbol"]}
`;

await ctx.replyWithMarkdown(dedent`
${header}
${columns}
${links}
`);
});

Expand Down
6 changes: 6 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ const dedent = require("dedent");
const _ = require("lodash");
const moment = require("moment");

const SurBTC = require("@cryptolw/exchange-surbtc");
const CryptoMKT = require("@cryptolw/exchange-cryptomkt");

const configuration = require("./configuration");
const createBot = require("./bot");
const createLogger = require("./logger");
Expand All @@ -18,9 +21,12 @@ const config = configuration();

const logger = createLogger(config);

const services = [new SurBTC(), new CryptoMKT()];

// eslint-disable-next-line no-unused-vars
const bot = createBot({
logger,
services,
config,
info,
});
Expand Down
Loading

0 comments on commit 6c725e8

Please sign in to comment.