bot18
Version:
A high-frequency cryptocurrency trading bot by Zenbot creator @carlos8f
505 lines (423 loc) • 7.78 kB
JavaScript
/**
* Module dependencies.
*/
var State = require('./state');
/**
* Expose `Context2d`.
*/
exports = module.exports = Context2d;
/**
* Math.
*/
var abs = Math.abs
, round = Math.round;
/**
* Color map.
*/
exports.colors = {
black: 0
, red: 1
, green: 2
, yellow: 3
, blue: 4
, magenta: 5
, cyan: 6
, white: 7
, normal: 9
};
/**
* Initialize a new 2d canvas rendering context.
*
* @param {Canvas} canvas
* @api private
*/
function Context2d(canvas) {
this.canvas = canvas;
this.beginPath();
this.states = [];
this.save();
}
/**
* Return the current `State` object.
*
* @return {State}
* @api private
*/
Context2d.prototype.state = function(){
return this.states[this.states.length - 1];
};
/**
* Get additive state `prop`.
*
* @param {String} prop
* @return {Number}
* @api private
*/
Context2d.prototype.getState = function(prop){
return this.states.reduce(function(sum, state){
return sum + state[prop];
}, 0);
};
/**
* Push a new `State` object to the stack.
*
* @api public
*/
Context2d.prototype.save = function(){
this.states.push(new State);
};
/**
* Pop the state stack.
*
* @api public
*/
Context2d.prototype.restore = function(){
this.states.pop();
};
/**
* Begin a new path.
*
* @api public
*/
Context2d.prototype.beginPath = function(){
this.path = [];
};
/**
* Write the given `str`.
*
* @param {String} str
* @api public
*/
Context2d.prototype.write = function(str){
if (process.env.DEBUG) {
console.dir(str);
} else {
this.canvas.stream.write(str);
}
};
/**
* Hide the cursor.
*
* @api public
*/
Context2d.prototype.hideCursor = function(){
this.write('\033[?25l');
};
/**
* Show the cursor.
*
* @api public
*/
Context2d.prototype.showCursor = function(){
this.write('\033[?25h');
};
/**
* Set fill style.
*
* @param {String} val
* @api public
*/
Context2d.prototype.__defineSetter__('fillStyle', function(val){
this.state().fill = val;
});
/**
* Set stroke style.
*
* @param {String} val
* @api public
*/
Context2d.prototype.__defineSetter__('strokeStyle', function(val){
this.state().stroke = val;
});
/**
* Move to the given point.
*
* @param {Number} x
* @param {Number} y
* @api public
*/
Context2d.prototype.moveTo = function(x, y){
x = round(x);
y = round(y);
this.write('\033[' + y + ';' + x + 'H');
};
/**
* Scale (`x`, `y`) or (`x`, `x`).
*
* @param {Number} x
* @param {Number} y
* @return {Context2d}
* @api public
*/
Context2d.prototype.scale = function(x, y){
if (2 == arguments.length) {
this.state().scaleX = Math.max(x, 0);
this.state().scaleY = Math.max(y, 0);
return this;
} else {
return this.scale(x, x);
}
};
/**
* Translate (`x`, `y`).
*
* @param {Number} x
* @param {Number} y
* @return {Context2d}
* @api public
*/
Context2d.prototype.translate = function(x, y){
this.state().translateX = Math.max(x, 0);
this.state().translateY = Math.max(y, 0);
return this;
};
/**
* Plot line with the given points using
* Bresenham's line algo.
*
* @param {Object} a
* @param {Object} b
* @api private
*/
Context2d.prototype.line = function(a, b){
var steep = abs(b.y - a.y) > abs(b.x - a.x)
, tmp;
if (steep) {
tmp = a.y;
a.y = a.x;
a.x = tmp;
tmp = b.y;
b.y = b.x;
b.x = tmp;
}
if (a.x > b.x) {
tmp = b.x;
b.x = a.x;
a.x = tmp;
tmp = b.y;
b.y = a.y;
a.y = tmp;
}
var dx = b.x - a.x
, dy = abs(b.y - a.y)
, err = 0
, derr = dy / dx;
var ystep
, y = a.y;
ystep = a.y < b.y
? 1
: -1;
for (var x = a.x; x < b.x; ++x) {
if (steep) {
this.moveTo(y, x);
this.write(' ');
} else {
this.moveTo(x, y);
this.write(' ');
}
err += derr;
if (err > .5) {
y += ystep;
err -= 1;
}
}
};
/**
* Stroke the current path.
*
* @api public
*/
Context2d.prototype.stroke = function(){
var self = this
, path = this.path
, len = path.length
, prev
, curr;
this.applyStrokeStyle();
for (var i = 1; i < len; ++i) {
prev = path[i-1];
curr = path[i];
this.line(prev, curr);
}
};
/**
* Add a line to the given point.
*
* @param {Number} x
* @param {Number} y
* @api public
*/
Context2d.prototype.lineTo = function(x, y){
this.path.push({ x: x, y: y });
};
/**
* Clear rect.
*
* @param {Number} x
* @param {Number} y
* @param {Number} w
* @param {Number} h
* @api public
*/
Context2d.prototype.clearRect = function(ox, oy, w, h){
if ( 0 == ox
&& 0 == oy
&& w == this.canvas.width
&& h == this.canvas.height) {
return this.clear();
}
for (var y = 0; y < h; ++y) {
for (var x = 0; x < w; ++x) {
this.moveTo(ox + x, oy + y);
this.write('\033[0m ');
}
}
};
/**
* Clear the line.
*
* @api private
*/
Context2d.prototype.clearLine = function(){
this.write('\033[2K');
};
/**
* Clear down.
*
* @api private
*/
Context2d.prototype.clearDown = function(){
this.write('\033[J');
};
/**
* Clear.
*
* @api public
*/
Context2d.prototype.clear = function(){
this.write('\033[0m\033[1J');
this.clearDown();
};
/**
* Write text at the given point.
*
* @param {String} str
* @param {Number} x
* @param {Number} y
* @api public
*/
Context2d.prototype.fillText = function(str, x, y){
x += this.getState('translateX');
y += this.getState('translateY');
this.applyForegroundFillStyle();
this.moveTo(x, y);
this.write(str);
};
/**
* Reset the terminal state.
*
* @api public
*/
Context2d.prototype.reset = function(){
this.clear();
this.showCursor();
this.moveTo(0, 0);
this.resetState();
};
/**
* Reset state.
*
* @api public
*/
Context2d.prototype.resetState = function(){
this.state().fill = 'normal';
this.state().stroke = 'normal';
this.applyFillStyle();
this.applyStrokeStyle();
};
/**
* Stroke a rect.
*
* TODO: use lineTo()
*
* @param {Number} x
* @param {Number} y
* @param {Number} w
* @param {Number} h
* @api public
*/
Context2d.prototype.strokeRect = function(x, y, w, h){
var sx = this.state().scaleX;
var sy = this.state().scaleY;
var tx = this.getState('translateX');
var ty = this.getState('translateY');
w *= sx;
h *= sy;
x += tx;
y += ty;
var hr = Array(Math.round(w + 1)).join(' ');
this.applyStrokeStyle();
this.moveTo(x, y);
this.write(hr);
for (var i = 1; i < h; ++i) {
this.moveTo(x, y + i);
this.write(' ');
this.moveTo(x + w - 1, y + i);
this.write(' ');
}
this.moveTo(x, y + h);
this.write(hr);
};
/**
* Fill a rect.
*
* @param {Number} x
* @param {Number} y
* @param {Number} w
* @param {Number} h
* @api public
*/
Context2d.prototype.fillRect = function(ox, oy, w, h){
var sx = this.state().scaleX;
var sy = this.state().scaleY;
var tx = this.getState('translateX');
var ty = this.getState('translateY');
w *= sx;
h *= sy;
ox += tx;
oy += ty;
this.applyFillStyle();
for (var y = 0; y < h; ++y) {
for (var x = 0; x < w; ++x) {
this.moveTo(ox + x, oy + y);
this.write(' ');
}
}
};
/**
* Apply the current fg fill style.
*
* @api private
*/
Context2d.prototype.applyForegroundFillStyle = function(){
color = exports.colors[this.state().fill];
this.write('\033[3' + color + 'm');
};
/**
* Apply the current fill style.
*
* @api private
*/
Context2d.prototype.applyFillStyle = function(){
color = exports.colors[this.state().fill];
this.write('\033[4' + color + 'm');
};
/**
* Apply the current stroke style.
*
* @api private
*/
Context2d.prototype.applyStrokeStyle = function(){
color = exports.colors[this.state().stroke];
this.write('\033[4' + color + 'm');
};