Skip to content

Instantly share code, notes, and snippets.

@memeyou
Last active August 29, 2015 13:56
Show Gist options
  • Select an option

  • Save memeyou/9031171 to your computer and use it in GitHub Desktop.

Select an option

Save memeyou/9031171 to your computer and use it in GitHub Desktop.
var Bter = require('bter');
var moment = require('moment');
var util = require('../core/util');
var _ = require('lodash');
var log = require('../core/log')
var Trader = function(config) {
this.key = config.key;
this.secret = config.secret;
this.pair = [config.asset, config.currency].join('_').toLowerCase();
this.asset = config.asset;
this.currency = config.currency;
this.name = 'Bter';
_.bindAll(this);
this.bter = Bter;
}
Trader.prototype.round = function(amount) {
// Prevent "You incorrectly entered one of fields."
// because of more than 8 decimals.
amount *= 100000000;
amount = Math.floor(amount);
amount /= 100000000;
return amount;
}
Trader.prototype.buy = function(amount, price, callback) {
amount = this.round(amount);
var set = function(err, data) {
if(err)
return log.error('unable to buy:', err);
callback(null, data.order_id);
};
// workaround for nonce error
setTimeout(_.bind(function() {
this.bter.placeOrder({ API_KEY: this.key, SECRET_KEY: this.secret, PAIR: this.pair, TYPE: 'BUY', RATE: price, AMOUNT: amount }, _.bind(set, this));
}, this), 1000);
}
Trader.prototype.sell = function(amount, price, callback) {
amount = this.round(amount);
var set = function(err, data) {
if(err)
return log.error('unable to sell:\n\n', err);
// returned order id is meaningless :(
callback(null, data.order_id);
};
// workaround for nonce error
setTimeout(_.bind(function() {
this.bter.placeOrder({ API_KEY: this.key, SECRET_KEY: this.secret, PAIR: this.pair, TYPE: 'SELL', RATE: price, AMOUNT: amount }, _.bind(set, this));
}, this), 1000);
}
// if the exchange errors we try the same call again after
// waiting 10 seconds
Trader.prototype.retry = function(method, args) {
var wait = +moment.duration(10, 'seconds');
log.debug(this.name, 'returned an error, retrying..');
var self = this;
// make sure the callback (and any other fn)
// is bound to Trader
_.each(args, function(arg, i) {
if(_.isFunction(arg))
args[i] = _.bind(arg, self);
});
// run the failed method again with the same
// arguments after wait
setTimeout(
function() { method.apply(self, args) },
wait
);
}
Trader.prototype.getPortfolio = function(callback) {
var calculate = function(err, data) {
if(err) {
if(err.message === 'invalid api key')
util.die('Your ' + this.name + ' API keys are invalid');
return this.retry(this.bter.getFunds({ API_KEY: this.key, SECRET_KEY: this.secret}, _.bind(calculate, this)));
}
var portfolio = [];
_.each(data.available_funds, function(amount, asset) {
portfolio.push({name: asset.toUpperCase(), amount: amount});
});
callback(err, portfolio);
}
this.bter.getFunds({ API_KEY: this.key, SECRET_KEY: this.secret}, function(err, data) {
if (err)
throw err;
});
this.bter.getFunds({ API_KEY: this.key, SECRET_KEY: this.secret}, _.bind(calculate, this))
}
Trader.prototype.getTicker = function(callback) {
var args = _.toArray(arguments);
// Bter-e doesn't state asks and bids in its
// ticker
var set = function(err, data) {
if (!data) {
return this.retry(this.getTicker, args);
}
var ticker = _.extend(data, {
ask: data.asks[data.asks.length - 1][0],
bid: data.bids[0][0]
});
callback(err, data);
}
var currs = this.pair.split('_');
this.bter.getDepth({ CURR_A: currs[0], CURR_B: currs[1] }, _.bind(set, this));
}
Trader.prototype.getFee = function(callback) {
// Bter doesn't have different fees based on orders
// at this moment it is always 0.2%
callback(false, 0.002);
}
Trader.prototype.checkOrder = function(order, callback) {
var check = function(err, order_id) {
callback(err, !(order_id));
};
this.getOrderId(order, _.bind(check, this));
}
Trader.prototype.cancelOrder = function(order, callback) {
var check = function(err, order_id) {
if(order_id) {
var set = function(err, result) {
if(err || !result)
log.error('unable to cancel order', order, '(', err, result, ')');
};
this.bter.cancelOrder({ API_KEY: this.key, SECRET_KEY: this.secret, ORDER_ID: order_id }, _.bind(set, this));
}
};
this.getOrderId(order, _.bind(check, this));
}
Trader.prototype.getOrderId = function(order, callback) {
var order_id;
var args = _.toArray(arguments);
var get = function(err, result) {
if (err || !result) {
return this.retry(this.getOrderId, args);
} else {
for (var i = 0; i < result.orders.length; i++) {
if ((result.orders[i].sell_type == this.asset
&& result.orders[i].buy_type == this.currency)
|| (result.orders[i].sell_type == this.currency
&& result.orders[i].buy_type == this.asset))
callback(err, result.orders[i].id);
}
}
return false
};
this.bter.getOrderList({ API_KEY: this.key, SECRET_KEY: this.secret}, _.bind(get, this));
}
Trader.prototype.getTrades = function(since, callback, descending) {
var args = _.toArray(arguments);
var process = function(err, trades) {
if(err)
return this.retry(this.getTrades, args);
if(!descending)
callback(false, trades.data);
else
callback(false, trades.data.reverse());
}
var currs = this.pair.split('_');
this.bter.getHistory({ CURR_A: currs[0], CURR_B: currs[1] }, _.bind(process, this));
}
module.exports = Trader;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment