first commit
This commit is contained in:
commit
aa7869eb33
386 files changed
+69375
No files matched your search
@@ -0,0 +1,108 @@
|
||||
var _ = require('lodash');
|
||||
var util = require('../util');
|
||||
var config = util.getConfig();
|
||||
var dirs = util.dirs();
|
||||
var log = require(dirs.core + 'log');
|
||||
var moment = require('moment');
|
||||
|
||||
var adapter = config[config.adapter];
|
||||
var Reader = require(dirs.gekko + adapter.path + '/reader');
|
||||
var daterange = config.backtest.daterange;
|
||||
|
||||
var to = moment.utc(daterange.to);
|
||||
var from = moment.utc(daterange.from);
|
||||
|
||||
if(to <= from)
|
||||
util.die('This daterange does not make sense.')
|
||||
|
||||
if(!from.isValid())
|
||||
util.die('invalid `from`');
|
||||
|
||||
if(!to.isValid())
|
||||
util.die('invalid `to`');
|
||||
|
||||
var Market = function() {
|
||||
|
||||
_.bindAll(this);
|
||||
this.pushing = false;
|
||||
this.ended = false;
|
||||
this.closed = false;
|
||||
|
||||
Readable.call(this, {objectMode: true});
|
||||
|
||||
log.write('');
|
||||
log.info('\tWARNING: BACKTESTING FEATURE NEEDS PROPER TESTING');
|
||||
log.info('\tWARNING: ACT ON THESE NUMBERS AT YOUR OWN RISK!');
|
||||
log.write('');
|
||||
|
||||
this.reader = new Reader();
|
||||
this.batchSize = config.backtest.batchSize;
|
||||
this.iterator = {
|
||||
from: from.clone(),
|
||||
to: from.clone().add(this.batchSize, 'm').subtract(1, 's')
|
||||
}
|
||||
}
|
||||
|
||||
var Readable = require('stream').Readable;
|
||||
Market.prototype = Object.create(Readable.prototype, {
|
||||
constructor: { value: Market }
|
||||
});
|
||||
|
||||
Market.prototype._read = _.once(function() {
|
||||
this.get();
|
||||
});
|
||||
|
||||
Market.prototype.get = function() {
|
||||
if(this.iterator.to >= to) {
|
||||
this.iterator.to = to;
|
||||
this.ended = true;
|
||||
}
|
||||
|
||||
this.reader.get(
|
||||
this.iterator.from.unix(),
|
||||
this.iterator.to.unix(),
|
||||
'full',
|
||||
this.processCandles
|
||||
)
|
||||
}
|
||||
|
||||
Market.prototype.processCandles = function(err, candles) {
|
||||
this.pushing = true;
|
||||
var amount = _.size(candles);
|
||||
|
||||
if(amount === 0) {
|
||||
if(this.ended) {
|
||||
this.closed = true;
|
||||
this.reader.close();
|
||||
this.push({isFinished: true});
|
||||
} else {
|
||||
util.die('Query returned no candles (do you have local data for the specified range?)');
|
||||
}
|
||||
}
|
||||
|
||||
if(!this.ended && amount < this.batchSize) {
|
||||
var d = function(ts) {
|
||||
return moment.unix(ts).utc().format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
var from = d(_.first(candles).start);
|
||||
var to = d(_.last(candles).start);
|
||||
log.warn(`Simulation based on incomplete market data (${this.batchSize - amount} missing between ${from} and ${to}).`);
|
||||
}
|
||||
|
||||
_.each(candles, function(c, i) {
|
||||
c.start = moment.unix(c.start);
|
||||
this.push(c);
|
||||
}, this);
|
||||
|
||||
this.pushing = false;
|
||||
|
||||
this.iterator = {
|
||||
from: this.iterator.from.clone().add(this.batchSize, 'm'),
|
||||
to: this.iterator.from.clone().add(this.batchSize * 2, 'm').subtract(1, 's')
|
||||
}
|
||||
|
||||
if(!this.closed)
|
||||
this.get();
|
||||
}
|
||||
|
||||
module.exports = Market;
|
||||
@@ -0,0 +1,117 @@
|
||||
var _ = require('lodash');
|
||||
var util = require('../util');
|
||||
var config = util.getConfig();
|
||||
var dirs = util.dirs();
|
||||
var log = require(dirs.core + 'log');
|
||||
var moment = require('moment');
|
||||
var gekkoEnv = util.gekkoEnv();
|
||||
|
||||
var adapter = config[config.adapter];
|
||||
var daterange = config.importer.daterange;
|
||||
|
||||
var from = moment.utc(daterange.from);
|
||||
|
||||
if(daterange.to) {
|
||||
var to = moment.utc(daterange.to);
|
||||
} else {
|
||||
var to = moment().utc();
|
||||
log.debug(
|
||||
'No end date specified for importing, setting to',
|
||||
to.format()
|
||||
);
|
||||
}
|
||||
log.debug(to.format());
|
||||
|
||||
if(!from.isValid())
|
||||
util.die('invalid `from`');
|
||||
|
||||
if(!to.isValid())
|
||||
util.die('invalid `to`');
|
||||
|
||||
var TradeBatcher = require(dirs.budfox + 'tradeBatcher');
|
||||
var CandleManager = require(dirs.budfox + 'candleManager');
|
||||
var exchangeChecker = require(dirs.gekko + 'exchange/exchangeChecker');
|
||||
|
||||
var error = exchangeChecker.cantFetchFullHistory(config.watch);
|
||||
if(error)
|
||||
util.die(error, true);
|
||||
|
||||
var fetcher = require(dirs.importers + config.watch.exchange);
|
||||
|
||||
if(to <= from)
|
||||
util.die('This daterange does not make sense.')
|
||||
|
||||
var Market = function() {
|
||||
_.bindAll(this);
|
||||
this.exchangeSettings = exchangeChecker.settings(config.watch);
|
||||
|
||||
this.tradeBatcher = new TradeBatcher(this.exchangeSettings.tid);
|
||||
this.candleManager = new CandleManager;
|
||||
this.fetcher = fetcher({
|
||||
to: to,
|
||||
from: from
|
||||
});
|
||||
|
||||
this.done = false;
|
||||
|
||||
this.fetcher.bus.on(
|
||||
'trades',
|
||||
this.processTrades
|
||||
);
|
||||
|
||||
this.fetcher.bus.on(
|
||||
'done',
|
||||
function() {
|
||||
this.done = true;
|
||||
}.bind(this)
|
||||
)
|
||||
|
||||
this.tradeBatcher.on(
|
||||
'new batch',
|
||||
this.candleManager.processTrades
|
||||
);
|
||||
|
||||
this.candleManager.on(
|
||||
'candles',
|
||||
this.pushCandles
|
||||
);
|
||||
|
||||
Readable.call(this, {objectMode: true});
|
||||
|
||||
this.get();
|
||||
}
|
||||
|
||||
var Readable = require('stream').Readable;
|
||||
Market.prototype = Object.create(Readable.prototype, {
|
||||
constructor: { value: Market }
|
||||
});
|
||||
|
||||
Market.prototype._read = _.noop;
|
||||
|
||||
Market.prototype.pushCandles = function(candles) {
|
||||
_.each(candles, this.push);
|
||||
}
|
||||
|
||||
Market.prototype.get = function() {
|
||||
this.fetcher.fetch();
|
||||
}
|
||||
|
||||
Market.prototype.processTrades = function(trades) {
|
||||
this.tradeBatcher.write(trades);
|
||||
|
||||
if(this.done) {
|
||||
log.info('Done importing!');
|
||||
this.emit('end');
|
||||
return;
|
||||
}
|
||||
|
||||
if(_.size(trades) && gekkoEnv === 'child-process') {
|
||||
let lastAtTS = _.last(trades).date;
|
||||
let lastAt = moment.unix(lastAtTS).utc().format();
|
||||
process.send({event: 'marketUpdate', payload: lastAt});
|
||||
}
|
||||
|
||||
setTimeout(this.get, 1000);
|
||||
}
|
||||
|
||||
module.exports = Market;
|
||||
@@ -0,0 +1,91 @@
|
||||
// a leech market is "semi-realtime" and pulls out candles of a
|
||||
// database (which is expected to be updated regularly, like with a
|
||||
// realtime market running in parallel).
|
||||
|
||||
const _ = require('lodash');
|
||||
const moment = require('moment');
|
||||
|
||||
const util = require('../util');
|
||||
const dirs = util.dirs();
|
||||
const config = util.getConfig();
|
||||
|
||||
const exchangeChecker = require(dirs.gekko + 'exchange/exchangeChecker');
|
||||
|
||||
const adapter = config[config.adapter];
|
||||
const Reader = require(dirs.gekko + adapter.path + '/reader');
|
||||
|
||||
const TICKINTERVAL = 20 * 1000; // 20 seconds
|
||||
|
||||
const slug = config.watch.exchange.toLowerCase();
|
||||
const exchange = exchangeChecker.getExchangeCapabilities(slug);
|
||||
|
||||
if(!exchange)
|
||||
util.die(`Unsupported exchange: ${slug}`)
|
||||
|
||||
const error = exchangeChecker.cantMonitor(config.watch);
|
||||
if(error)
|
||||
util.die(error, true);
|
||||
|
||||
if(config.market.from)
|
||||
var fromTs = moment.utc(config.market.from).unix();
|
||||
else
|
||||
var fromTs = moment().startOf('minute').unix();
|
||||
|
||||
|
||||
var Market = function() {
|
||||
|
||||
_.bindAll(this);
|
||||
|
||||
Readable.call(this, {objectMode: true});
|
||||
|
||||
this.reader = new Reader();
|
||||
this.latestTs = fromTs;
|
||||
|
||||
setInterval(
|
||||
this.get,
|
||||
TICKINTERVAL
|
||||
);
|
||||
}
|
||||
|
||||
var Readable = require('stream').Readable;
|
||||
Market.prototype = Object.create(Readable.prototype, {
|
||||
constructor: { value: Market }
|
||||
});
|
||||
|
||||
Market.prototype._read = _.once(function() {
|
||||
this.get();
|
||||
});
|
||||
|
||||
Market.prototype.get = function() {
|
||||
var future = moment().add(1, 'minute').unix();
|
||||
|
||||
this.reader.get(
|
||||
this.latestTs,
|
||||
future,
|
||||
'full',
|
||||
this.processCandles
|
||||
)
|
||||
}
|
||||
|
||||
Market.prototype.processCandles = function(err, candles) {
|
||||
var amount = _.size(candles);
|
||||
if(amount === 0) {
|
||||
// no new candles!
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// verify that the correct amount of candles was passed:
|
||||
//
|
||||
// if `this.latestTs` was at 10:00 and we receive 3 candles with the latest at 11:00
|
||||
// we know we are missing 57 candles...
|
||||
|
||||
_.each(candles, function(c, i) {
|
||||
c.start = moment.unix(c.start).utc();
|
||||
this.push(c);
|
||||
}, this);
|
||||
|
||||
this.latestTs = _.last(candles).start.unix() + 1;
|
||||
}
|
||||
|
||||
module.exports = Market;
|
||||
@@ -0,0 +1,19 @@
|
||||
const _ = require('lodash');
|
||||
|
||||
const util = require('../util');
|
||||
const dirs = util.dirs();
|
||||
|
||||
const exchangeChecker = require(dirs.gekko + 'exchange/exchangeChecker');
|
||||
const config = util.getConfig();
|
||||
|
||||
const slug = config.watch.exchange.toLowerCase();
|
||||
const exchange = exchangeChecker.getExchangeCapabilities(slug);
|
||||
|
||||
if(!exchange)
|
||||
util.die(`Unsupported exchange: ${slug}`)
|
||||
|
||||
const error = exchangeChecker.cantMonitor(config.watch);
|
||||
if(error)
|
||||
util.die(error, true);
|
||||
|
||||
module.exports = require(dirs.budfox + 'budfox');
|
||||
Reference in new issue
Block a user