diff --git a/README.md b/README.md index a05ae787a..31599fcaa 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,11 @@ If you want to contribute or are interested in how Gekko works: * More exchanges (bitfinex, btcchina) * More indicators * Webbased interface +* Write more tests + +## Running mocha tests + npm install mocha -g + mocha mocha_test ## Credits diff --git a/core/portfolioManager.js b/core/portfolioManager.js index b2242959b..d63134fd2 100644 --- a/core/portfolioManager.js +++ b/core/portfolioManager.js @@ -118,7 +118,7 @@ Manager.prototype.getBalance = function(fund) { // is this a directExchange? (does it support MKT orders) // is this a infinityOrderExchange (does it support order // requests bigger then the current balance?) -Manager.prototype.trade = function(what) { +Manager.prototype.trade = function(what, callback) { if(what !== 'BUY' && what !== 'SELL') return; @@ -135,7 +135,7 @@ Manager.prototype.trade = function(what) { if(this.infinityOrderExchange) amount = 10000; else - amount = this.getBalance(this.currency) / (this.ticker.ask+(this.ticker.ask*this.fee)); + amount = parseFloat((this.getBalance(this.currency) / (parseFloat(this.ticker.ask) + (parseFloat(this.ticker.ask)*this.fee))).toFixed(4)); // can we just create a MKT order? if(this.directExchange) @@ -156,7 +156,7 @@ Manager.prototype.trade = function(what) { if(this.infinityOrderExchange) amount = 10000; else - amount = this.getBalance(this.asset); + amount = parseFloat(this.getBalance(this.asset) - this.getBalance(this.asset) * this.fee).toFixed(4); // can we just create a MKT order? if(this.directExchange) @@ -171,6 +171,10 @@ Manager.prototype.trade = function(what) { this.sell(amount, price); } + + if(callback) { + callback(); + } }; async.series([ this.setTicker, diff --git a/exchanges/bitstamp.js b/exchanges/bitstamp.js index b73125bfd..a1dc9d84b 100644 --- a/exchanges/bitstamp.js +++ b/exchanges/bitstamp.js @@ -78,7 +78,7 @@ Trader.prototype.buy = function(amount, price, callback) { }; // TODO: fees are hardcoded here? - amount *= 0.995; // remove fees + // amount *= 0.995; // remove fees // prevent: Ensure that there are no more than 8 digits in total. amount *= 100000000; amount = Math.floor(amount); @@ -94,6 +94,11 @@ Trader.prototype.sell = function(amount, price, callback) { callback(null, result.id); }; + + amount *= 10000000; + amount = Math.floor(amount); + amount /= 10000000; + this.bitstamp.sell(amount, price, _.bind(set, this)); } @@ -128,4 +133,4 @@ Trader.prototype.getTrades = function(since, callback, descending) { } -module.exports = Trader; \ No newline at end of file +module.exports = Trader; diff --git a/mocha_test/portfolioManager.js b/mocha_test/portfolioManager.js new file mode 100644 index 000000000..60c995410 --- /dev/null +++ b/mocha_test/portfolioManager.js @@ -0,0 +1,139 @@ +'use strict'; +var Manager = require('../core/PortfolioManager.js'); +var util = require('../core/util.js'); +var _ = require('lodash'); +var chai = chai || require('chai'); +var sinon = sinon || require('sinon'); +var should = chai.should(); + +describe('Portfolio Manager', function(){ + + var config = util.getConfig(); + var manager; + + config.watch = { + enabled: true, + exchange: 'bitstamp', // @link https://github.com/askmike/gekko#supported-exchanges + key: 'LIVzgHi4vS1YKyuae9TUGNR4k2C55BYF', + secret: 'itUNBJMLGKrjQI1UGIqJT7o9pqDAFPkk', + currency: 'USD', + asset: 'BTC' + } + + config.trader = { + enabled: true, + tradePercent: 10, + username: '100000' // your username, only fill in when using bitstamp or cexio + } + + + manager = new Manager(_.extend(config.trader, config.watch)); + + var stubInit = sinon.stub(manager, "init", function(callback) { + // setportfolio + // setfee + this.portfolio = [ { name: 'BTC', amount: 0.99 }, { name: 'USD', amount: 242.2 } ]; + this.fee = 0.0025; + callback(); + }); + + var setPortfolioStub = sinon.stub(manager, "setPortfolio", function(callback) { + this.portfolio = [ { name: 'BTC', amount: 0.99 }, { name: 'USD', amount: 242.2 } ]; + callback(); + }.bind(manager)); + + + it('should fail to create an instance without config', function() { + (function(){ + new Manager({}); + }).should.throw(); + }); + + + it('should not fail to create an instance with config', function() { + (function(){ + new Manager(_.extend(config.trader, config.watch)); + }).should.not.throw(); + }); + + + describe('#init', function(){ + + it('should successfully initialize', function(done) { + manager.init(done); + }); + + it('should have fee', function(){ + manager.fee.should.equal(0.0025); + }); + + it('should have fee type that is number', function(){ + manager.fee.should.be.a('number'); + }); + + it('should have a portfolio', function(){ + manager.portfolio.should.be.an('array'); + }); + + }); + + + describe('#trade', function(){ + it('should buy if necessary balance exists', function(done){ + manager.trade('BUY', done); + }); + + it('should buy if necessary balance exists', function(done){ + manager.trade('BUY', done); + }); + }); + + + describe('#getFund', function(){ + + }); + + + describe('#getBalance', function(){ + + }); + + + describe('#getMinimum', function(){ + + }); + + + describe('#buy', function(){ + + }); + + + describe('#sell', function(){ + + }); + + + describe('#noteOrder', function(){ + + }); + + + describe('#checkOrder', function(){ + + }); + + + describe('#logPortfolio', function(){ + + }); + + + describe('#recheckPortfolio', function(){ + + }); + + describe('#enforcePosition', function(){ + + }); +}); diff --git a/package.json b/package.json index fd59c56b4..0335721bd 100644 --- a/package.json +++ b/package.json @@ -26,11 +26,14 @@ "semver": "2.2.1", "kraken-api": "0.1.x", "lakebtc_nodejs": "0.1.x", - "pushbullet": "1.4.3", + "pushbullet": "1.4.3", "mexbt": "0.0.x" }, "devDependencies": { - "nodeunit": "0.8.2" + "nodeunit": "0.8.2", + "mocha": "latest", + "sinon": "latest", + "chai": "latest" }, "engines": { "node": ">=0.10.x" }, "repository": {