bluebot
Version:
A bitcoin trading bot for auto trading at various exchanges
176 lines (133 loc) • 4.33 kB
JavaScript
const _ = require('lodash');
const moment = require('moment');
const stats = require('../../core/stats');
const util = require('../../core/util');
const ENV = util.bluebotEnv();
const config = util.getConfig();
const perfConfig = config.performanceAnalyzer;
const watchConfig = config.watch;
// Load the proper module that handles the results
var Handler;
if(ENV === 'child-process')
Handler = require('./cpRelay');
else
Handler = require('./logger');
const PerformanceAnalyzer = function() {
_.bindAll(this);
this.dates = {
start: false,
end: false
}
this.startPrice = 0;
this.endPrice = 0;
this.currency = watchConfig.currency;
this.asset = watchConfig.asset;
this.handler = new Handler(watchConfig);
this.trades = 0;
this.sharpe = 0;
this.roundTrips = [];
this.roundTrip = {
entry: false,
exit: false
}
}
PerformanceAnalyzer.prototype.processCandle = function(candle, done) {
this.price = candle.close;
this.dates.end = candle.start;
if(!this.dates.start) {
this.dates.start = candle.start;
this.startPrice = candle.close;
}
this.endPrice = candle.close;
done();
}
PerformanceAnalyzer.prototype.processPortfolioUpdate = function(portfolio) {
this.start = portfolio;
this.current = _.clone(portfolio);
}
PerformanceAnalyzer.prototype.processTrade = function(trade) {
this.trades++;
this.current = trade.portfolio;
const report = this.calculateReportStatistics();
this.handler.handleTrade(trade, report);
this.logRoundtripPart(trade);
}
PerformanceAnalyzer.prototype.logRoundtripPart = function(trade) {
// this is not part of a valid roundtrip
if(this.trades === 1 && trade.action === 'sell') {
return;
}
if(trade.action === 'buy') {
this.roundTrip.entry = {
date: trade.date,
price: trade.price,
total: trade.portfolio.asset * trade.price,
}
} else if(trade.action === 'sell') {
this.roundTrip.exit = {
date: trade.date,
price: trade.price,
total: trade.portfolio.currency
}
this.handleRoundtrip();
}
}
PerformanceAnalyzer.prototype.round = function(amount) {
return amount.toFixed(8);
}
PerformanceAnalyzer.prototype.handleRoundtrip = function() {
var roundtrip = {
entryAt: this.roundTrip.entry.date,
entryPrice: this.roundTrip.entry.price,
entryBalance: this.roundTrip.entry.total,
exitAt: this.roundTrip.exit.date,
exitPrice: this.roundTrip.exit.price,
exitBalance: this.roundTrip.exit.total,
duration: this.roundTrip.exit.date.diff(this.roundTrip.entry.date)
}
roundtrip.pnl = roundtrip.exitBalance - roundtrip.entryBalance;
roundtrip.profit = (100 * roundtrip.exitBalance / roundtrip.entryBalance) - 100;
this.roundTrips.push(roundtrip);
this.handler.handleRoundtrip(roundtrip);
// we need a cache for sharpe
// every time we have a new roundtrip
// update the cached sharpe ratio
this.sharpe = stats.sharpe(
this.roundTrips.map(r => r.profit),
perfConfig.riskFreeReturn
);
}
PerformanceAnalyzer.prototype.calculateReportStatistics = function() {
// the portfolio's balance is measured in {currency}
let balance = this.current.currency + this.price * this.current.asset;
let profit = balance - this.start.balance;
let timespan = moment.duration(
this.dates.end.diff(this.dates.start)
);
let relativeProfit = balance / this.start.balance * 100 - 100
let report = {
currency: this.currency,
asset: this.asset,
startTime: this.dates.start.utc().format('YYYY-MM-DD HH:mm:ss'),
endTime: this.dates.end.utc().format('YYYY-MM-DD HH:mm:ss'),
timespan: timespan.humanize(),
market: this.endPrice * 100 / this.startPrice - 100,
balance: balance,
profit: profit,
relativeProfit: relativeProfit,
yearlyProfit: this.round(profit / timespan.asYears()),
relativeYearlyProfit: this.round(relativeProfit / timespan.asYears()),
startPrice: this.startPrice,
endPrice: this.endPrice,
trades: this.trades,
startBalance: this.start.balance,
sharpe: this.sharpe
}
report.alpha = report.profit - report.market;
return report;
}
PerformanceAnalyzer.prototype.finalize = function() {
const report = this.calculateReportStatistics();
this.handler.finalize(report);
}
module.exports = PerformanceAnalyzer;