From 4b860dcda8b4daf07052fa9adc03708d7e579372 Mon Sep 17 00:00:00 2001 From: Anton Date: Fri, 25 Apr 2014 16:41:43 -0400 Subject: [PATCH 1/8] Added support for Bitfinex exchange --- exchanges.js | 17 +++++ exchanges/bitfinex.js | 142 ++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 160 insertions(+) create mode 100644 exchanges/bitfinex.js diff --git a/exchanges.js b/exchanges.js index aceda7b69..39b7d097c 100644 --- a/exchanges.js +++ b/exchanges.js @@ -259,6 +259,23 @@ var exchanges = [ requires: ['key', 'secret'], monitorError: 'https://github.com/askmike/gekko/issues/210', providesHistory: false + }, + { + name: 'Bitfinex', + slug: 'bitfinex', + direct: false, + infinityOrder: false, + currencies: ['USD'], + assets: ['BTC'], + markets: [ + { + pair: ['USD', 'BTC'], minimalOrder: { amount: 0.01, unit: 'currency' } + } + ], + requires: ['key', 'secret'], + // TODO: should be possible to enable this for Bitfinex? + providesHistory: false + // fetchTimespan: 60 } ]; diff --git a/exchanges/bitfinex.js b/exchanges/bitfinex.js new file mode 100644 index 000000000..6dc4ecb2d --- /dev/null +++ b/exchanges/bitfinex.js @@ -0,0 +1,142 @@ + +var Bitfinex = require("bitfinex"); +var util = require('../core/util.js'); +var _ = require('lodash'); +var moment = require('moment'); +var log = require('../core/log'); + +// Module-wide constants +var exchangeName = 'bitfinex'; +// Bitfinex supports Litecoin, but this module currently only supports Bitcoin +var defaultAsset = 'btcusd'; + +var Trader = function(config) { + _.bindAll(this); + if(_.isObject(config)) { + this.key = config.key; + this.secret = config.secret; + } + this.name = 'Bitfinex'; + this.balance; + this.price; + + this.bitfinex = new Bitfinex(this.key, this.secret); +} + +// 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) { + this.bitfinex.wallet_balances(function (err, data, body) { + var portfolio = _.map(body, function (asset) { + return { + name: asset.currency.toUpperCase(), + // TODO: use .amount instead of .available? + amount: +asset.available + } + }); + callback(err, portfolio); + }); +} + +Trader.prototype.getTicker = function(callback) { + this.bitfinex.ticker(defaultAsset, function (err, data, body) { + var tick = JSON.parse(body); + callback(err, { bid: +tick.bid, ask: +tick.ask }) + }); +} + +// This assumes that only limit orders are being placed, so fees are the +// "maker fee" of 0.1%. It does not take into account volume discounts. +Trader.prototype.getFee = function(callback) { + var makerFee = 0.1; + callback(false, makerFee / 100); +} + +function submit_order(bfx, type, amount, price, callback) { + // TODO: Bitstamp module included the following - is it necessary? + // amount *= 0.995; // remove fees + amount = Math.floor(amount*100000000)/100000000; + bfx.new_order(defaultAsset, amount, price, exchangeName, + type, + 'exchange limit', + function (err, data, body) { + if (err) + return log.error('unable to ' + type, err, body); + + var order = JSON.parse(body); + callback(err, order.order_id); + }); +} + +Trader.prototype.buy = function(amount, price, callback) { + submit_order(this.bitfinex, 'buy', amount, price, callback); + +} + +Trader.prototype.sell = function(amount, price, callback) { + submit_order(this.bitfinex, 'sell', amount, price, callback); +} + +Trader.prototype.checkOrder = function(order_id, callback) { + this.bitfinex.order_status(order_id, function (err, data, body) { + var result = JSON.parse(body); + callback(err, result.is_live); + }); +} + +Trader.prototype.cancelOrder = function(order_id, callback) { + this.bitfinex.cancel_order(order_id, function (err, data, body) { + var result = JSON.parse(body); + if (err || !result || !result.is_cancelled) + log.error('unable to cancel order', order, '(', err, result, ')'); + }); +} + +Trader.prototype.getTrades = function(since, callback, descending) { + var args = _.toArray(arguments); + var self = this; + + // Bitfinex API module does not support start date, but Bitfinex API does. + // Could implement here as in following comments: + // var start = since ? since.unix() : null; + this.bitfinex.trades(defaultAsset, /* start, */ function (err, data, body) { + if (err) + return self.retry(self.getTrades, args); + + var result = JSON.parse(body); + + var trades = _.map(result, function (trade) { + return { + "date": trade.timestamp, + "price": +trade.price, + "amount": +trade.amount // not mentioned in gekko exchange docs + } + }); + + callback(null, descending ? trades : trades.reverse()); + }); +} + +module.exports = Trader; + diff --git a/package.json b/package.json index ba0b56f60..642bef640 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "btc-e": "0.0.x", "cexio": "0.0.x", "bitstamp": "0.1.x", + "bitfinex": "git+https://github.com/naddison36/bitfinex.git" "async": "0.2.x", "nedb": "0.9.4", "line-reader": "0.2.x", From 5af8860a54e475e3e823e5f3e4aa91855d334cbe Mon Sep 17 00:00:00 2001 From: Anton Date: Fri, 25 Apr 2014 16:46:49 -0400 Subject: [PATCH 2/8] Fix missing comma for bitfinex --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 642bef640..efd519e02 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "btc-e": "0.0.x", "cexio": "0.0.x", "bitstamp": "0.1.x", - "bitfinex": "git+https://github.com/naddison36/bitfinex.git" + "bitfinex": "git+https://github.com/naddison36/bitfinex.git", "async": "0.2.x", "nedb": "0.9.4", "line-reader": "0.2.x", From 1b796092d19cea9e69aacc3b004ed87eabd5e636 Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 29 Apr 2014 03:05:32 -0400 Subject: [PATCH 3/8] Added Bitfinex to supported exchanges list --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d632c35f..017195b9b 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ Gekko works on the following exchanges: - CEX.io - Kraken - BTC-e +- Bitfinex - ~~Cryptsy~~ (In the [pipeline](https://github.com/askmike/gekko/pull/200)) ## Installing Gekko @@ -150,4 +151,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. From 43a41075aa804e85b2ee776f7c94b5f22fe45416 Mon Sep 17 00:00:00 2001 From: ARD Date: Sun, 12 Oct 2014 23:25:31 -0400 Subject: [PATCH 4/8] Added a configuration extender utility. Any configs defined in config-local.js will overrite defaults. Added Plivo SMS plugin. Added Mandril mail plugin. --- .gitignore | 3 + config.js | 37 ++++++++++++ package.json | 3 +- plugins.js | 24 ++++++++ plugins/mandrillMailer.js | 116 ++++++++++++++++++++++++++++++++++++++ plugins/smsPlivo.js | 116 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 plugins/mandrillMailer.js create mode 100644 plugins/smsPlivo.js diff --git a/.gitignore b/.gitignore index 410e87b53..399892a5e 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ node_modules candles.csv cexio.db history + +# local config files +config-local.js diff --git a/config.js b/config.js index 1f53c50df..26de36cf4 100644 --- a/config.js +++ b/config.js @@ -1,6 +1,9 @@ // Everything is explained here: // https://github.com/askmike/gekko/blob/master/docs/Configuring_gekko.md +var fs = require('fs'); +var configExtend = require('config-extend'); + var config = {}; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -176,6 +179,25 @@ config.mailer = { tls: false // Use TLS if true } +config.mandrillMailer = { + enabled: false, + sendMailOnStart: true, + to: '', // to email + toName: 'Gekko user', + from: '', // from email + fromName: 'Gekko bot info', + apiKey: '', // Mandrill api key +} + +config.smsPlivo = { + enabled: false, + sendMailOnStart: true, + smsPrefix: 'GEKKO:', // always start SMS message with this + to: '', // your SMS number + from: '', // SMS number to send from provided by Plivo + authId: '', // your Plivo auth ID + authToken: '' // your Plivo auth token +} config.ircbot = { enabled: false, @@ -241,4 +263,19 @@ config.backtest = { // Not sure? Read this first: https://github.com/askmike/gekko/issues/201 config['I understand that Gekko only automates MY OWN trading strategies'] = false; + +// ---------------------------------------------- +// LOCAL CONFIG SETTINGS +// ---------------------------------------------- + +// If you have a server deployed you may want to store environment specific +// configuration. You can create a file called 'config-local.js' and any settings you +// place in there and export will override the configuration defined in this file. +// Make sure to export the config object in the 'config-local.js' file! +if(fs.existsSync('./config-local.js')){ + var localConfig = require('./config-local'); + // this just deep copies the one object over the other, with last argument taking precedence. + config = configExtend(config, localConfig); +} + module.exports = config; \ No newline at end of file diff --git a/package.json b/package.json index ba0b56f60..1e0752e54 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "nedb": "0.9.4", "line-reader": "0.2.x", "semver": "2.2.1", - "kraken-api" :"0.1.x" + "kraken-api" :"0.1.x", + "config-extend": "0.0.7" }, "devDependencies": { "nodeunit": "0.8.2" diff --git a/plugins.js b/plugins.js index b6c39957b..979cab1e6 100644 --- a/plugins.js +++ b/plugins.js @@ -78,6 +78,30 @@ var actors = [ version: '0.1.1' }] }, + { + name: 'Mandrill Mailer', + description: 'Mandrill Mail module lets sends you email yourself everytime Gekko has new advice.', + slug: 'mandrillMailer', + async: true, + silent: false, + modes: ['realtime'], + dependencies: [{ + module: 'mandrill-api', + version: '1.0.40' + }] + }, + { + name: 'SMS Plivo', + description: 'SMS module to text yourself everytime Gekko has new advice. Uses Plivo.', + slug: 'smsPlivo', + async: true, + silent: false, + modes: ['realtime'], + dependencies: [{ + module: 'plivo', + version: '0.1.0' + }] + }, { name: 'Trader', description: 'Trader will follow the advice and create real orders.', diff --git a/plugins/mandrillMailer.js b/plugins/mandrillMailer.js new file mode 100644 index 000000000..c61e3b1b3 --- /dev/null +++ b/plugins/mandrillMailer.js @@ -0,0 +1,116 @@ +var _ = require('lodash'); +var mandrill = require('mandrill-api/mandrill'); +var log = require('../core/log.js'); +var util = require('../core/util.js'); +var config = util.getConfig(); +var mailConfig = config.mandrillMailer; + +var MandrillMailer = function(done) { + _.bindAll(this); + + this.price = 'N/A'; + this.client; + this.done = done; + this.setup(); +} + +MandrillMailer.prototype.setup = function(done) { + var errors = []; + if(_.isEmpty(mailConfig.to)) + errors.push("No destination address configured for Mandrill Mail Config"); + if(_.isEmpty(mailConfig.from)) + errors.push("No sending address configured for Mandrill Mail Config"); + if(_.isEmpty(mailConfig.apiKey)) + errors.push("No API Key configured for Mandrill Mail Config"); + + // init the client... + var mandrill_client = new mandrill.Mandrill(mailConfig.apiKey); + this.client = mandrill_client; + + debugger; + if(mailConfig.sendMailOnStart && errors.length === 0) { + var subject = "Gekko has started"; + var messageText = [ + "I've just started watching ", + config.watch.exchange, + ' ', + config.watch.currency, + '/', + config.watch.asset, + ". I'll let you know when I got some advice" + ].join(''); + + this.mail( + subject, + messageText, + _.bind(function(err) { + this.checkResults(err); + this.done(); + }, this) + ); + + } else if(errors.length !== 0){ + throw new Error(errors); + } else { + this.done(); + } + + log.debug('Setup email adviser.'); +} + +MandrillMailer.prototype.mail = function(subject, content, done) { + var self = this; + var message = { + "text": content, + "to": [{ + "email": mailConfig.to, + "name": mailConfig.toName, + "type": "to" + }], + "from_name": mailConfig.fromName, + "from_email": mailConfig.from, + "subject": mailConfig.tag + subject + }; + + var ip_pool = "Main Pool"; + self.client.messages.send({ + "message": message, + "async": false, + "ip_pool": ip_pool + }, + function(result){ + done(); + }, function(error){ + self.checkResults(error); + }); +} + +MandrillMailer.prototype.processTrade = function(trade) { + this.price = trade.price; +} + +MandrillMailer.prototype.processAdvice = function(advice) { + var text = [ + 'Gekko is watching ', + config.watch.exchange, + ' and has detected a new trend, advice is to go ', + advice.recommandation, + '.\n\nThe current ', + config.watch.asset, + ' price is ', + this.price + ].join(''); + + var subject = 'New advice: go ' + advice.recommandation; + + this.mail(subject, text); +} + +MandrillMailer.prototype.checkResults = function(err) { + if(err) + log.warn('error sending email', err); + else + log.info('Send advice via email.'); +} + +module.exports = MandrillMailer; diff --git a/plugins/smsPlivo.js b/plugins/smsPlivo.js new file mode 100644 index 000000000..3fcce115b --- /dev/null +++ b/plugins/smsPlivo.js @@ -0,0 +1,116 @@ +var _ = require('lodash'); +var plivo = require('plivo'); +var log = require('../core/log.js'); +var util = require('../core/util.js'); +var config = util.getConfig(); +var smsConfig = config.smsPlivo; + +var SMSPlivo = function(done) { + _.bindAll(this); + + this.price = 'N/A'; + this.client; + this.done = done; + this.setup(); +} + +SMSPlivo.prototype.setup = function(done) { + var errors = []; + if(_.isEmpty(smsConfig.to)) + errors.push("No destination number configured for SMS Plivo Config"); + if(_.isEmpty(smsConfig.from)) + errors.push("No sending number configured for SMS Plivo Config"); + if(_.isEmpty(smsConfig.authId)) + errors.push("No AuthId configured for SMS Plivo Config"); + if(_.isEmpty(smsConfig.authToken)) + errors.push("No AuthToken configured for SMS Plivo Config"); + + // init the client... + var api = plivo.RestAPI({ + authId: smsConfig.authId, + authToken: smsConfig.authToken, + }); + this.client = api; + + debugger; + if(smsConfig.sendMailOnStart && errors.length === 0) { + var messageText = [ + "Watching: ", + config.watch.exchange, + ' ', + config.watch.currency, + '/', + config.watch.asset, + ". Advice soon." + ].join(''); + + this.mail( + messageText, + _.bind(function(err) { + this.checkResults(err); + this.done(); + }, this) + ); + + } else if(errors.length !== 0){ + throw new Error(errors); + } else { + this.done(); + } + + log.debug('Setup email adviser.'); +} + +SMSPlivo.prototype.mail = function(content, done) { + var self = this; + + function buildMessage(){ + var message = smsConfig.smsPrefix + ' ' + content; + var params = { + 'src': smsConfig.from, // Caller Id + 'dst' : smsConfig.to, // User Number to Call + 'text' : message, + 'type' : "sms", + }; + return params; + } + + self.client.send_message(buildMessage(), function(status, response) { + log.debug('SMS Plivo Sending Status: ', status); + log.debug('SMS Plivo API Response: ', response); + var error = null; + if(status != 202 && status != 200){ + error = response; + self.checkResults(error); + } else { + done(); + } + }); +} + +SMSPlivo.prototype.processTrade = function(trade) { + this.price = trade.price; +} + +SMSPlivo.prototype.processAdvice = function(advice) { + var text = [ + 'Watching ', + config.watch.exchange, + '. New trend, go ', + advice.recommandation, + '.\n\nCurrent ', + config.watch.asset, + ' price is ', + this.price + ].join(''); + this.mail(text); +} + +SMSPlivo.prototype.checkResults = function(err) { + if(err) + log.warn('error sending SMS', err); + else + log.info('Send advice via SMS.'); +} + +module.exports = SMSPlivo; From 77e9c82b77a5d1c26cc2c1002f9a20fcb5270d63 Mon Sep 17 00:00:00 2001 From: ARD Date: Sun, 12 Oct 2014 23:28:09 -0400 Subject: [PATCH 5/8] Changed debug message to SMS --- plugins/smsPlivo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/smsPlivo.js b/plugins/smsPlivo.js index 3fcce115b..728b4f8e8 100644 --- a/plugins/smsPlivo.js +++ b/plugins/smsPlivo.js @@ -58,7 +58,7 @@ SMSPlivo.prototype.setup = function(done) { this.done(); } - log.debug('Setup email adviser.'); + log.debug('Setup SMS adviser.'); } SMSPlivo.prototype.mail = function(content, done) { From c23ca3644ccfc8947b327267cd77dd2a661cdb66 Mon Sep 17 00:00:00 2001 From: ARD Date: Mon, 13 Oct 2014 00:46:59 -0400 Subject: [PATCH 6/8] Added debug routes for plugins. --- plugins/mandrillMailer.js | 22 ++++++++++++++++++++-- plugins/smsPlivo.js | 30 +++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/plugins/mandrillMailer.js b/plugins/mandrillMailer.js index c61e3b1b3..6d24aa633 100644 --- a/plugins/mandrillMailer.js +++ b/plugins/mandrillMailer.js @@ -54,8 +54,12 @@ MandrillMailer.prototype.setup = function(done) { } else { this.done(); } + + if(mailConfig.testProcessAdvice){ + this.testProcessAdvice(); + } - log.debug('Setup email adviser.'); + log.debug('Setup email (Mandrill) adviser successfully.'); } MandrillMailer.prototype.mail = function(subject, content, done) { @@ -79,9 +83,15 @@ MandrillMailer.prototype.mail = function(subject, content, done) { "ip_pool": ip_pool }, function(result){ - done(); + log.debug("Mail sent successfully via Mandrill: ", result); + if(done){ + done(); + } }, function(error){ self.checkResults(error); + if(done){ + done(); + } }); } @@ -106,6 +116,14 @@ MandrillMailer.prototype.processAdvice = function(advice) { this.mail(subject, text); } +MandrillMailer.prototype.testProcessAdvice = function(){ + var advice = { + recommandation: "short" + }; + this.price = 0; + this.processAdvice(advice); +} + MandrillMailer.prototype.checkResults = function(err) { if(err) log.warn('error sending email', err); diff --git a/plugins/smsPlivo.js b/plugins/smsPlivo.js index 728b4f8e8..0a25f3a62 100644 --- a/plugins/smsPlivo.js +++ b/plugins/smsPlivo.js @@ -57,8 +57,12 @@ SMSPlivo.prototype.setup = function(done) { } else { this.done(); } + + if(smsConfig.testProcessAdvice){ + this.testProcessAdvice(); + } - log.debug('Setup SMS adviser.'); + log.debug('Setup SMS (Plivo) adviser successfully.'); } SMSPlivo.prototype.mail = function(content, done) { @@ -76,14 +80,18 @@ SMSPlivo.prototype.mail = function(content, done) { } self.client.send_message(buildMessage(), function(status, response) { - log.debug('SMS Plivo Sending Status: ', status); - log.debug('SMS Plivo API Response: ', response); - var error = null; + // 202 and 200 are normal status codes from Plivo. if(status != 202 && status != 200){ - error = response; - self.checkResults(error); + // note, reponse will contain status code. + self.checkResults(response); + if(done){ + done(); + } } else { - done(); + log.debug("SMS sent successfully via Plivo: ", response); + if(done){ + done(); + } } }); } @@ -106,6 +114,14 @@ SMSPlivo.prototype.processAdvice = function(advice) { this.mail(text); } +SMSPlivo.prototype.testProcessAdvice = function(){ + var advice = { + recommandation: "short" + }; + this.price = 0; + this.processAdvice(advice); +} + SMSPlivo.prototype.checkResults = function(err) { if(err) log.warn('error sending SMS', err); From fbe2e4a1f99f6d96349fa71abb2f74ed6682eb40 Mon Sep 17 00:00:00 2001 From: ARD Date: Mon, 13 Oct 2014 01:28:48 -0400 Subject: [PATCH 7/8] Reversed my changes to config system and added a log message to say what config is in use. --- config.js | 18 ------------------ core/util.js | 1 + gekko.js | 3 +++ package.json | 3 +-- 4 files changed, 5 insertions(+), 20 deletions(-) diff --git a/config.js b/config.js index 26de36cf4..86854c953 100644 --- a/config.js +++ b/config.js @@ -1,9 +1,6 @@ // Everything is explained here: // https://github.com/askmike/gekko/blob/master/docs/Configuring_gekko.md -var fs = require('fs'); -var configExtend = require('config-extend'); - var config = {}; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -263,19 +260,4 @@ config.backtest = { // Not sure? Read this first: https://github.com/askmike/gekko/issues/201 config['I understand that Gekko only automates MY OWN trading strategies'] = false; - -// ---------------------------------------------- -// LOCAL CONFIG SETTINGS -// ---------------------------------------------- - -// If you have a server deployed you may want to store environment specific -// configuration. You can create a file called 'config-local.js' and any settings you -// place in there and export will override the configuration defined in this file. -// Make sure to export the config object in the 'config-local.js' file! -if(fs.existsSync('./config-local.js')){ - var localConfig = require('./config-local'); - // this just deep copies the one object over the other, with last argument taking precedence. - config = configExtend(config, localConfig); -} - module.exports = config; \ No newline at end of file diff --git a/core/util.js b/core/util.js index 0636786b9..cbbd303d2 100644 --- a/core/util.js +++ b/core/util.js @@ -16,6 +16,7 @@ var util = { var configFile = path.resolve(util.getArgument('config') || __dirname + '/../config.js'); _config = require(configFile); + _config.resolvedLocation = configFile; return _config; }, // overwrite the whole config diff --git a/gekko.js b/gekko.js index 8fa5b5f80..ee9fbe0e1 100644 --- a/gekko.js +++ b/gekko.js @@ -72,6 +72,9 @@ if( log.info('Gekko v' + util.getVersion(), 'started'); log.info('I\'m gonna make you rich, Bud Fox.', '\n\n'); +// Tell what config file we are using: +log.info('Using config file: ' + config.resolvedLocation); + var gekkoMode = 'realtime'; // currently we only support a single diff --git a/package.json b/package.json index 1e0752e54..ba0b56f60 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,7 @@ "nedb": "0.9.4", "line-reader": "0.2.x", "semver": "2.2.1", - "kraken-api" :"0.1.x", - "config-extend": "0.0.7" + "kraken-api" :"0.1.x" }, "devDependencies": { "nodeunit": "0.8.2" From ed58c6df4301c441ae9b5ef39138111747f63161 Mon Sep 17 00:00:00 2001 From: ARD Date: Mon, 13 Oct 2014 01:30:55 -0400 Subject: [PATCH 8/8] Removed unused ignore --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index 399892a5e..410e87b53 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,3 @@ node_modules candles.csv cexio.db history - -# local config files -config-local.js