94 lines
2.0 KiB
JavaScript
94 lines
2.0 KiB
JavaScript
// internally we only use 1m
|
|
// candles, this can easily
|
|
// convert them to any desired
|
|
// size.
|
|
|
|
// Acts as ~fake~ stream: takes
|
|
// 1m candles as input and emits
|
|
// bigger candles.
|
|
//
|
|
// input are transported candles.
|
|
|
|
var _ = require('lodash');
|
|
var util = require(__dirname + '/util');
|
|
|
|
var CandleBatcher = function(candleSize) {
|
|
if(!_.isNumber(candleSize))
|
|
throw new Error('candleSize is not a number');
|
|
|
|
this.candleSize = candleSize;
|
|
this.smallCandles = [];
|
|
this.calculatedCandles = [];
|
|
|
|
_.bindAll(this);
|
|
}
|
|
|
|
util.makeEventEmitter(CandleBatcher);
|
|
|
|
CandleBatcher.prototype.write = function(candles) {
|
|
if(!_.isArray(candles)) {
|
|
throw new Error('candles is not an array');
|
|
}
|
|
|
|
this.emitted = 0;
|
|
|
|
_.each(candles, function(candle) {
|
|
this.smallCandles.push(candle);
|
|
this.check();
|
|
}, this);
|
|
|
|
return this.emitted;
|
|
}
|
|
|
|
CandleBatcher.prototype.check = function() {
|
|
if(_.size(this.smallCandles) % this.candleSize !== 0)
|
|
return;
|
|
|
|
this.emitted++;
|
|
this.calculatedCandles.push(this.calculate());
|
|
this.smallCandles = [];
|
|
}
|
|
|
|
CandleBatcher.prototype.flush = function() {
|
|
_.each(
|
|
this.calculatedCandles,
|
|
candle => this.emit('candle', candle)
|
|
);
|
|
|
|
this.calculatedCandles = [];
|
|
}
|
|
|
|
CandleBatcher.prototype.calculate = function() {
|
|
// remove the id property of the small candle
|
|
var { id, ...first } = this.smallCandles.shift();
|
|
|
|
first.vwp = first.vwp * first.volume;
|
|
|
|
var candle = _.reduce(
|
|
this.smallCandles,
|
|
function(candle, m) {
|
|
candle.high = _.max([candle.high, m.high]);
|
|
candle.low = _.min([candle.low, m.low]);
|
|
candle.close = m.close;
|
|
candle.volume += m.volume;
|
|
candle.vwp += m.vwp * m.volume;
|
|
candle.trades += m.trades;
|
|
return candle;
|
|
},
|
|
first
|
|
);
|
|
|
|
if(candle.volume)
|
|
// we have added up all prices (relative to volume)
|
|
// now divide by volume to get the Volume Weighted Price
|
|
candle.vwp /= candle.volume;
|
|
else
|
|
// empty candle
|
|
candle.vwp = candle.open;
|
|
|
|
candle.start = first.start;
|
|
return candle;
|
|
}
|
|
|
|
module.exports = CandleBatcher;
|