first commit

This commit is contained in:
Francois Klieber committed 2021-06-06 20:25:14 +02:00
commit aa7869eb33
386 files changed
+69375

No files matched your search

+108
View File
@@ -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;
+117
View File
@@ -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;
+91
View File
@@ -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;
+19
View File
@@ -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');