crypto-nodes
Version:
308 lines (214 loc) • 7.38 kB
JavaScript
var moment = require('moment');
var per_second = 0;
var binance_obj = {
binance: require('node-binance-api'),
snapshots: {},
add_snapshot: function(sym, data, syms) {
this.snapshots[sym] = data;
if(Object.keys(this.snapshots).length == syms.length) {
//console.log('FILLED');
} else {
//console.log(Object.keys(this.snapshots).length);
//console.log(syms.length);
}
},
init_ws: function (node, symbols) {
var that = this;
console.log('BINANCE :: Markets ' + Object.keys(symbols).join(','));
function get_snapshot() {
that.binance.websockets.depthCache(Object.keys(symbols), function(symbol, data) {
if(symbols[symbol] && !that.snapshots[symbol]) {
that.add_snapshot(symbol, data, Object.keys(symbols));
node.send({
payload: {
'exchange' : 'binance',
fees: that.fees,
sym_from: symbols[symbol][0],
sym_to: symbols[symbol][1],
data: { b: data.bids, a: data.asks, snapshot: true }
}
});
per_second++;
} else {
//console.log('.');
}
});
}
if(this.snapshot_interval) {
clearInterval(this.snapshot_interval);
}
this.snapshot_interval = setInterval(function () {
that.snapshots = {};
// get_snapshot();
}, 60000);
get_snapshot();
this.binance.websockets.depth(Object.keys(symbols), (data) => {
var sym_from;
var sym_to;
//console.log(data);
//console.log(data.a.length + " " + data.b.length);
if(symbols[data.s]) {
node.send({
payload: {
'exchange' : 'binance',
fees: this.fees,
sym_from: symbols[data.s][0],
sym_to: symbols[data.s][1],
data: { b: data.b, a: data.a, snapshot: false }
}
});
per_second++;
}
});
},
fees: {},
interval: false,
connected: false,
exchange_symbols: [],
configured_symbols: [],
enabled_symbols: [],
get_exchange_symbols: function(callback) {
this.binance.exchangeInfo(function (err, data) {
var out = {};
if(err) {
callback(out);
return;
}
for(x in data.symbols) {
var sym = data.symbols[x];
console.log(sym.symbol + " " + sym.baseAsset + "/" + sym.quoteAsset);
out[sym.symbol] = [ sym.baseAsset , sym.quoteAsset ];
}
callback(out);
});
},
get_enabled_symbols: function() {
var out = {};
for(x in this.exchange_symbols) {
var pass = false;
var exc_tmp = this.exchange_symbols[x];
for(y in this.configured_symbols) {
var cfg_tmp = this.configured_symbols[y].split('/');
// If its matching or inverted variant matches its enabled symbol
if((exc_tmp[0] == cfg_tmp[0] && exc_tmp[1] == cfg_tmp[1]) ||
(exc_tmp[0] == cfg_tmp[1] && exc_tmp[1] == cfg_tmp[0])
) {
pass = true;
}
}
if(pass) {
out[x] = this.exchange_symbols[x];
}
}
return out;
},
msg: function(node, channelName, data) {
var that = this;
var sym = channelName.split('_');
var sym_from = sym[0];
var sym_to = sym[1];
node.send({
payload: {
exchange: 'binance',
fees: that.fees,
sym_from: sym_from,
sym_to: sym_to,
data: data
}
});
},
init: function(config, node, symbols, callback) {
var that = this;
this.configured_symbols = symbols;
try { this.fees = JSON.parse(config.fees); } catch (e) {}
var opts = {
test: config.test ? true : false,
useServerTime: true,
}
if(config.api_key && config.api_secret) {
opts.APIKEY = config.api_key;
opts.APISECRET = config.api_secret;
}
this.binance.options(opts);
if(!this.interval) {
this.interval = setInterval(function () {
var color = per_second > 0 ? 'green' : 'red';
// console.log('BINANCE :: ' + per_second + ' requests per second');
//console.log('BINANCE :: LATEST ' + JSON.stringify(latest));
node.status({ fill: color,shape:'ring', text: per_second + ' requests per second' });
per_second = 0;
}, 1000);
}
this.get_exchange_symbols(function (symbols) {
that.exchange_symbols = symbols;
var enabled_symbols = that.get_enabled_symbols();
console.log(enabled_symbols);
that.init_ws(node, enabled_symbols);
});
},
}
module.exports = function(RED) {
const exchange = 'binance';
function binanceConnector(config) {
RED.nodes.createNode(this,config);
var node = this;
node.on('input', function(msg) {
if(config.disabled) {
// Disable UI Updates
if(binance_obj.interval) {
clearInterval(binance_obj.interval);
}
// Set node status
node.status({ fill: 'red',shape:'ring', text: 'Disabled' });
// Emit flush orderbook
node.send({payload: { exchange: 'binance', op: 'flush' }});
return;
}
if(msg.payload && msg.payload.op == 'subscribe') {
binance_obj.init(config, node, msg.payload.symbols);
}
});
node.on('close', function() {
// tidy up any async code here - shutdown connections and so on.
node.status({ fill: 'red',shape:'ring', text: 'Offline' });
node.send({payload: { exchange: 'binance', op: 'flush' }});
});
}
function binanceOrder(config) {
RED.nodes.createNode(this,config);
var node = this;
node.on('input', function(msg) {
//console.log('BINANCE INPUT ::');
//console.log(msg);
});
}
function binanceBalance(config) {
RED.nodes.createNode(this,config);
var node = this;
node.on('input', function(msg) {
//console.log('BINANCE INPUT ::');
//console.log(msg);
if(msg.payload && msg.payload.op && msg.payload.op == 'get_balance') {
if(msg.payload.exchange && (msg.payload.exchange == 'all' || msg.payload.exchange == exchange)) {
binance.balance(function (err, data) {
if(err) {
node.send({ payload: { exchange: exchange, op: 'get_balance', balances: [], err: err } });
} else {
node.status({fill:"green",shape:"dot", text: new moment().format('HH:mm:ss') + ' Received BALANCES' });
console.log(exchange + ' :: Received balance data');
// Lets fix the formatting and keep just what we need..
var out = {};
for(x in data) {
out[x] = { balance: parseFloat(data[x].available) };
}
node.send({ payload: { exchange: exchange, op: 'get_balance', balances: out } });
}
});
}
}
});
}
RED.nodes.registerType("binanceConnector", binanceConnector);
RED.nodes.registerType("binanceOrder", binanceOrder);
RED.nodes.registerType("binanceBalance", binanceBalance);
}