| var util = require('../../core/util'); | | var util = require('../../core/util'); |
| var _ = require('lodash'); | | var _ = require('lodash'); |
| var fs = require('fs'); | | var fs = require('fs'); |
| var toml = require('toml'); | | var toml = require('toml'); |
| | | |
| var config = util.getConfig(); | | var config = util.getConfig(); |
| var dirs = util.dirs(); | | var dirs = util.dirs(); |
| var log = require(dirs.core + 'log'); | | var log = require(dirs.core + 'log'); |
| var CandleBatcher = require(dirs.core + 'candleBatcher'); | | var CandleBatcher = require(dirs.core + 'candleBatcher'); |
| | | |
| var moment = require('moment'); | | var moment = require('moment'); |
| var isLeecher = config.market && config.market.type === 'leech'; | | var isLeecher = config.market && config.market.type === 'leech'; |
| | | |
| var Actor = function(done) { | | var Actor = function(done) { |
| _.bindAll(this); | | _.bindAll(this); |
| | | |
| this.done = done; | | this.done = done; |
| | | |
| this.batcher = new CandleBatcher(config.tradingAdvisor.candleSize); | | this.batcher = new CandleBatcher(config.tradingAdvisor.candleSize); |
| | | |
| this.strategyName = config.tradingAdvisor.method; | | this.strategyName = config.tradingAdvisor.method; |
| | | |
| this.setupStrategy(); | | this.setupStrategy(); |
| | | |
| var mode = util.gekkoMode(); | | var mode = util.gekkoMode(); |
| | | |
| // the stitcher will try to pump in historical data | | // the stitcher will try to pump in historical data |
| // so that the strat can use this data as a "warmup period" | | // so that the strat can use this data as a "warmup period" |
| // | | // |
| // the realtime "leech" market won't use the stitcher | | // the realtime "leech" market won't use the stitcher |
| if(mode === 'realtime' && !isLeecher) { | | if(mode === 'realtime' && !isLeecher) { |
| var Stitcher = require(dirs.tools + 'dataStitcher'); | | var Stitcher = require(dirs.tools + 'dataStitcher'); |
| var stitcher = new Stitcher(this.batcher); | | var stitcher = new Stitcher(this.batcher); |
| stitcher.prepareHistoricalData(done); | | stitcher.prepareHistoricalData(done); |
| } else | | } else |
| done(); | | done(); |
| } | | } |
| | | |
| Actor.prototype.setupStrategy = function() { | | Actor.prototype.setupStrategy = function() { |
| | | |
| if(!fs.existsSync(dirs.methods + this.strategyName + '.js')) | | if(!fs.existsSync(dirs.methods + this.strategyName + '.js')) |
| util.die('Gekko can\'t find the strategy "' + this.strategyName + '"'); | | util.die('Gekko can\'t find the strategy "' + this.strategyName + '"'); |
| | | |
| log.info('\t', 'Using the strategy: ' + this.strategyName); | | log.info('\t', 'Using the strategy: ' + this.strategyName); |
| | | |
| const strategy = require(dirs.methods + this.strategyName); | | const strategy = require(dirs.methods + this.strategyName); |
| | | |
| // bind all trading strategy specific functions | | // bind all trading strategy specific functions |
| // to the WrappedStrategy. | | // to the WrappedStrategy. |
| const WrappedStrategy = require('./baseTradingMethod'); | | const WrappedStrategy = require('./baseTradingMethod'); |
| | | |
| _.each(strategy, function(fn, name) { | | _.each(strategy, function(fn, name) { |
| WrappedStrategy.prototype[name] = fn; | | WrappedStrategy.prototype[name] = fn; |
| }); | | }); |
| | | |
| let stratSettings; | | let stratSettings; |
| if(config[this.strategyName]) { | | if(config[this.strategyName]) { |
| stratSettings = config[this.strategyName]; | | stratSettings = config[this.strategyName]; |
| } | | } |
| | | |
| this.strategy = new WrappedStrategy(stratSettings); | | this.strategy = new WrappedStrategy(stratSettings); |
| this.strategy | | this.strategy |
| .on('advice', this.relayAdvice) | | .on('advice', this.relayAdvice) |
| .on( | | .on( |
| 'stratWarmupCompleted', | | 'stratWarmupCompleted', |
| e => this.deferredEmit('stratWarmupCompleted', e) | | e => this.deferredEmit('stratWarmupCompleted', e) |
| ) | | ) |
| .on( | | .on( |
| 'stratUpdate', | | 'stratUpdate', |
| e => this.deferredEmit('stratUpdate', e) | | e => this.deferredEmit('stratUpdate', e) |
| ).on('stratNotification', | | ).on('stratNotification', |
| e => this.deferredEmit('stratNotification', e) | | e => this.deferredEmit('stratNotification', e) |
| ) | | ) |
| | | |
| this.strategy | | this.strategy |
| .on('tradeCompleted', this.processTradeCompleted); | | .on('tradeCompleted', this.processTradeCompleted); |
| | | |
| this.batcher | | this.batcher |
| .on('candle', _candle => { | | .on('candle', _candle => { |
| const { id, ...candle } = _candle; | | const { id, ...candle } = _candle; |
| this.deferredEmit('stratCandle', candle); | | this.deferredEmit('stratCandle', candle); |
| this.emitStratCandle(candle); | | this.emitStratCandle(candle); |
| | | // save when the next bigCandle should be. |
| | | this.nextBigCandleAt = candle.start.clone().add(4, 'hours'); |
| }); | | }); |
| } | | } |
| | | |
| // HANDLERS | | // HANDLERS |
| // process the 1m candles | | // process the 1m candles |
| Actor.prototype.processCandle = function(candle, done) { | | Actor.prototype.processCandle = function(candle, done) { |
| | | if(!this.nextBigCandleAt) { |
| | | // on first candle we know the next one will be in 4 hours |
| | | this.nextBigCandleAt = candle.start.clone().add(4, 'hours'); |
| | | } |
| | | log.info('\t Next Candle Update:', this.nextBigCandleAt.fromNow()) |
| | | |
| this.candle = candle; | | this.candle = candle; |
| const completedBatch = this.batcher.write([candle]); | | const completedBatch = this.batcher.write([candle]); |
| if(completedBatch) { | | if(completedBatch) { |
| this.next = done; | | this.next = done; |
| } else { | | } else { |
| done(); | | done(); |
| this.next = _.noop; | | this.next = _.noop; |
| } | | } |
| this.batcher.flush(); | | this.batcher.flush(); |
| } | | } |
| | | |
| // propogate a custom sized candle to the trading strategy | | // propogate a custom sized candle to the trading strategy |
| Actor.prototype.emitStratCandle = function(candle) { | | Actor.prototype.emitStratCandle = function(candle) { |
| this.strategy.tick(candle, this.next); | | this.strategy.tick(candle, this.next); |
| } | | } |
| | | |
| Actor.prototype.processTradeCompleted = function(trade) { | | Actor.prototype.processTradeCompleted = function(trade) { |
| this.strategy.processTrade(trade); | | this.strategy.processTrade(trade); |
| } | | } |
| | | |
| // pass through shutdown handler | | // pass through shutdown handler |
| Actor.prototype.finish = function(done) { | | Actor.prototype.finish = function(done) { |
| this.strategy.finish(done); | | this.strategy.finish(done); |
| } | | } |
| | | |
| // EMITTERS | | // EMITTERS |
| Actor.prototype.relayAdvice = function(advice) { | | Actor.prototype.relayAdvice = function(advice) { |
| advice.date = this.candle.start.clone().add(1, 'minute'); | | advice.date = this.candle.start.clone().add(1, 'minute'); |
| this.deferredEmit('advice', advice); | | this.deferredEmit('advice', advice); |
| } | | } |
| | | |
| | | |
| module.exports = Actor; | | module.exports = Actor; |
| | | |