bot18
Version:
A high-frequency cryptocurrency trading bot by Zenbot creator @carlos8f
261 lines (207 loc) • 7.8 kB
JavaScript
var blessed = require('blessed')
, Node = blessed.Node
, Canvas = require('../canvas')
, utils = require('../../utils.js')
, _ = require('lodash')
function Line(options) {
var self = this
if (!(this instanceof Node)) {
return new Line(options);
}
options.showNthLabel = options.showNthLabel || 1
options.style = options.style || {}
options.style.line = options.style.line || "yellow"
options.style.text = options.style.text || "green"
options.style.baseline = options.style.baseline || "black"
options.xLabelPadding = options.xLabelPadding || 5
options.xPadding = options.xPadding || 10
options.numYLabels = options.numYLabels || 5
options.legend = options.legend || {}
options.wholeNumbersOnly = options.wholeNumbersOnly || false
options.minY = options.minY || 0
Canvas.call(this, options);
}
Line.prototype.calcSize = function() {
this.canvasSize = {width: this.width*2-12, height: this.height*4-8}
}
Line.prototype.__proto__ = Canvas.prototype;
Line.prototype.type = 'line';
Line.prototype.setData = function(data) {
if (!this.ctx) {
throw "error: canvas context does not exist. setData() for line charts must be called after the chart has been added to the screen via screen.append()"
}
//compatability with older api
if (!Array.isArray(data)) data = [data]
var self = this
var xLabelPadding = this.options.xLabelPadding
var yLabelPadding = 3
var xPadding = this.options.xPadding
var yPadding = 11
var c = this.ctx
var labels = data[0].x
function addLegend() {
if (!self.options.showLegend) return
if (self.legend) self.remove(self.legend)
var legendWidth = self.options.legend.width || 15
self.legend = blessed.box({
height: data.length+2,
top: 1,
width: legendWidth,
left: self.width-legendWidth-3,
content: '',
fg: "green",
tags: true,
border: {
type: 'line',
fg: 'black'
},
style: {
fg: 'blue',
},
screen: self.screen
});
var legandText = ""
var maxChars = legendWidth-2
for (var i=0; i<data.length; i++) {
var style = data[i].style || {}
var color = utils.getColorCode(style.line || self.options.style.line)
legandText += '{'+color+'-fg}'+ data[i].title.substring(0, maxChars)+'{/'+color+'-fg}\r\n'
}
self.legend.setContent(legandText)
self.append(self.legend)
}
//iteratee for lodash _.max
function getMax(v, i){
return parseFloat(v);
}
function getMaxY() {
if (self.options.maxY) {
return self.options.maxY;
}
var max = -Infinity;
for(var i = 0; i < data.length; i++) {
if (data[i].y.length) {
var current = _.max(data[i].y, parseFloat);
if (current > max) {
max = current;
}
}
}
return max + (max - self.options.minY) * 0.2;
}
function formatYLabel(value, max, min, numLabels, wholeNumbersOnly, abbreviate) {
var fixed = (max/numLabels<1 && value!=0 && !wholeNumbersOnly) ? 2 : 0
var res = value.toFixed(fixed)
return abbreviate?utils.abbreviateNumber(res):res
}
function getMaxXLabelPadding(numLabels, wholeNumbersOnly, abbreviate, min) {
var max = getMaxY()
return formatYLabel(max, max, min, numLabels, wholeNumbersOnly, abbreviate).length * 2;
}
var maxPadding = getMaxXLabelPadding(this.options.numYLabels, this.options.wholeNumbersOnly, this.options.abbreviate, this.options.minY)
if (xLabelPadding < maxPadding) {
xLabelPadding = maxPadding;
};
if ((xPadding - xLabelPadding) < 0) {
xPadding = xLabelPadding;
}
function getMaxX() {
var maxLength = 0;
for(var i = 0; i < labels.length; i++) {
if(labels[i] === undefined) {
console.log("label[" + i + "] is undefined");
} else if(labels[i].length > maxLength) {
maxLength = labels[i].length;
}
}
return maxLength;
}
function getXPixel(val) {
return ((self.canvasSize.width - xPadding) / labels.length) * val + (xPadding * 1.0) + 2;
}
function getYPixel(val, minY) {
var res = self.canvasSize.height - yPadding - (((self.canvasSize.height - yPadding) / (getMaxY()-minY)) * (val-minY));
res-=2 //to separate the baseline and the data line to separate chars so canvas will show separate colors
return res
}
// Draw the line graph
function drawLine(values, style, minY) {
style = style || {}
var color = self.options.style.line
c.strokeStyle = style.line || color
c.moveTo(0, 0)
c.beginPath();
c.lineTo(getXPixel(0), getYPixel(values[0], minY));
for(var k = 1; k < values.length; k++) {
c.lineTo(getXPixel(k), getYPixel(values[k], minY));
}
c.stroke();
}
addLegend()
c.fillStyle = this.options.style.text
c.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height);
var yLabelIncrement = (getMaxY()-this.options.minY)/this.options.numYLabels
if (this.options.wholeNumbersOnly) yLabelIncrement = Math.floor(yLabelIncrement)
//if (getMaxY()>=10) {
// yLabelIncrement = yLabelIncrement + (10 - yLabelIncrement % 10)
//}
//yLabelIncrement = Math.max(yLabelIncrement, 1) // should not be zero
if (yLabelIncrement==0) yLabelIncrement = 1
// Draw the Y value texts
var maxY = getMaxY()
for(var i = this.options.minY; i < maxY; i += yLabelIncrement) {
c.fillText(formatYLabel(i, maxY, this.options.minY, this.options.numYLabels, this.options.wholeNumbersOnly, this.options.abbreviate), xPadding - xLabelPadding, getYPixel(i, this.options.minY));
}
for (var h=0; h<data.length; h++) {
drawLine(data[h].y, data[h].style, this.options.minY)
}
c.strokeStyle = this.options.style.baseline
// Draw the axises
c.beginPath();
c.lineTo(xPadding, 0);
c.lineTo(xPadding, this.canvasSize.height - yPadding);
c.lineTo(this.canvasSize.width, this.canvasSize.height - yPadding);
c.stroke();
// Draw the X value texts
var charsAvailable = (this.canvasSize.width - xPadding) / 2;
var maxLabelsPossible = charsAvailable / (getMaxX() + 2);
var pointsPerMaxLabel = Math.ceil(data[0].y.length / maxLabelsPossible);
var showNthLabel = this.options.showNthLabel;
if (showNthLabel < pointsPerMaxLabel) {
showNthLabel = pointsPerMaxLabel;
}
for(var i = 0; i < labels.length; i += showNthLabel) {
if((getXPixel(i) + (labels[i].length * 2)) <= this.canvasSize.width) {
c.fillText(labels[i], getXPixel(i), this.canvasSize.height - yPadding + yLabelPadding);
}
}
}
Line.prototype.getOptionsPrototype = function() {
return { width: 80
, height: 30
, left: 15
, top: 12
, xPadding: 5
, label: 'Title'
, showLegend: true
, legend: {width: 12}
, data: [ { title: 'us-east',
x: ['t1', 't2', 't3', 't4'],
y: [5, 1, 7, 5],
style: {
line: 'red'
}
}
, { title: 'us-west',
x: ['t1', 't2', 't3', 't4'],
y: [2, 4, 9, 8],
style: {line: 'yellow'}
}
, {title: 'eu-north-with-some-long-string',
x: ['t1', 't2', 't3', 't4'],
y: [22, 7, 12, 1],
style: {line: 'blue'}
}]
}
}
module.exports = Line