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

+75
View File
@@ -0,0 +1,75 @@
/*
* CCI
*/
var log = require('../../core/log');
var Indicator = function(settings) {
this.input = 'candle';
this.tp = 0.0;
this.result = false;
this.hist = []; // needed for mean?
this.mean = 0.0;
this.size = 0;
this.constant = settings.constant;
this.maxSize = settings.history;
for (var i = 0; i < this.maxSize; i++)
this.hist.push(0.0);
}
Indicator.prototype.update = function(candle) {
// We need sufficient history to get the right result.
var tp = (candle.high + candle.close + candle.low) / 3;
if (this.size < this.maxSize) {
this.hist[this.size] = tp;
this.size++;
} else {
for (var i = 0; i < this.maxSize-1; i++) {
this.hist[i] = this.hist[i+1];
}
this.hist[this.maxSize-1] = tp;
}
if (this.size < this.maxSize) {
this.result = false;
} else {
this.calculate(tp);
}
}
/*
* Handle calculations
*/
Indicator.prototype.calculate = function(tp) {
var sumtp = 0.0
for (var i = 0; i < this.size; i++) {
sumtp = sumtp + this.hist[i];
}
this.avgtp = sumtp / this.size;
this.tp = tp;
var sum = 0.0;
// calculate tps
for (var i = 0; i < this.size; i++) {
var z = (this.hist[i] - this.avgtp);
if (z < 0) z = z * -1.0;
sum = sum + z;
}
this.mean = (sum / this.size);
this.result = (this.tp - this.avgtp) / (this.constant * this.mean);
// log.debug("===\t", this.mean, "\t", this.tp, '\t', this.TP.result, "\t", sum, "\t", avgtp, '\t', this.result.toFixed(2));
}
module.exports = Indicator;
+19
View File
@@ -0,0 +1,19 @@
// required indicators
var EMA = require('./EMA.js');
var Indicator = function(config) {
this.input = 'price';
this.result = false;
this.inner = new EMA(config.weight);
this.outer = new EMA(config.weight);
}
// add a price and calculate the EMAs and
// the result
Indicator.prototype.update = function(price) {
this.inner.update(price);
this.outer.update(this.inner.result);
this.result = 2 * this.inner.result - this.outer.result;
}
module.exports = Indicator;
+36
View File
@@ -0,0 +1,36 @@
// @link http://en.wikipedia.org/wiki/Exponential_moving_average#Exponential_moving_average
var Indicator = function(weight) {
this.input = 'price';
this.weight = weight;
this.result = false;
this.age = 0;
}
Indicator.prototype.update = function(price) {
// The first time we can't calculate based on previous
// ema, because we haven't calculated any yet.
if(this.result === false)
this.result = price;
this.age++;
this.calculate(price);
return this.result;
}
// calculation (based on tick/day):
// EMA = Price(t) * k + EMA(y) * (1 – k)
// t = today, y = yesterday, N = number of days in EMA, k = 2 / (N+1)
Indicator.prototype.calculate = function(price) {
// weight factor
var k = 2 / (this.weight + 1);
// yesterday
var y = this.result;
// calculation
this.result = price * k + y * (1 - k);
}
module.exports = Indicator;
+115
View File
@@ -0,0 +1,115 @@
/*
* Linear regression curve
*/
var log = require('../../core/log');
var Indicator = function(settings) {
this.input = 'price';
this.depth = settings;
this.result = false;
this.age = 0;
this.history = [];
this.x = [];
/*
* Do not use array(depth) as it might not be implemented
*/
for (var i = 0; i < this.depth; i++) {
this.history.push(0.0);
this.x.push(i);
}
// log.debug("Created LRC indicator with h: ", this.depth);
}
Indicator.prototype.update = function(price) {
// We need sufficient history to get the right result.
if(this.result === false && this.age < this.depth) {
this.history[this.age] = price;
this.age++;
this.result = false;
// log.debug("Waiting for sufficient age: ", this.age, " out of ", this.depth);
//
return;
}
this.age++;
// shift history
for (var i = 0; i < (this.depth - 1); i++) {
this.history[i] = this.history[i+1];
}
this.history[this.depth-1] = price;
this.calculate(price);
// log.debug("Checking LRC: ", this.result.toFixed(8), "\tH: ", this.age);
return;
}
/*
* Least squares linear regression fitting.
*/
function linreg(values_x, values_y) {
var sum_x = 0;
var sum_y = 0;
var sum_xy = 0;
var sum_xx = 0;
var count = 0;
/*
* We'll use those variables for faster read/write access.
*/
var x = 0;
var y = 0;
var values_length = values_x.length;
if (values_length != values_y.length) {
throw new Error('The parameters values_x and values_y need to have same size!');
}
/*
* Nothing to do.
*/
if (values_length === 0) {
return [ [], [] ];
}
/*
* Calculate the sum for each of the parts necessary.
*/
for (var v = 0; v < values_length; v++) {
x = values_x[v];
y = values_y[v];
sum_x += x;
sum_y += y;
sum_xx += x*x;
sum_xy += x*y;
count++;
}
/*
* Calculate m and b for the formular:
* y = x * m + b
*/
var m = (count*sum_xy - sum_x*sum_y) / (count*sum_xx - sum_x*sum_x);
var b = (sum_y/count) - (m*sum_x)/count;
return [m, b];
}
/*
* Handle calculations
*/
Indicator.prototype.calculate = function(price) {
// get the reg
var reg = linreg(this.x, this.history);
// y = a * x + b
this.result = ((this.depth-1) * reg[0]) + reg[1];
}
module.exports = Indicator;
+27
View File
@@ -0,0 +1,27 @@
// required indicators
var EMA = require('./EMA.js');
var Indicator = function(config) {
this.input = 'price';
this.diff = false;
this.short = new EMA(config.short);
this.long = new EMA(config.long);
this.signal = new EMA(config.signal);
}
Indicator.prototype.update = function(price) {
this.short.update(price);
this.long.update(price);
this.calculateEMAdiff();
this.signal.update(this.diff);
this.result = this.diff - this.signal.result;
}
Indicator.prototype.calculateEMAdiff = function() {
var shortEMA = this.short.result;
var longEMA = this.long.result;
this.diff = shortEMA - longEMA;
}
module.exports = Indicator;
+37
View File
@@ -0,0 +1,37 @@
// required indicators
var EMA = require('./EMA.js');
var Indicator = function(config) {
this.result = {};
this.input = 'price';
this.macd = 0;
this.ppo = 0;
this.short = new EMA(config.short);
this.long = new EMA(config.long);
this.MACDsignal = new EMA(config.signal);
this.PPOsignal = new EMA(config.signal);
}
Indicator.prototype.update = function(price) {
this.short.update(price);
this.long.update(price);
this.calculatePPO();
this.MACDsignal.update(this.result.macd);
this.MACDhist = this.result.macd - this.MACDsignal.result;
this.PPOsignal.update(this.result.ppo);
this.PPOhist = this.result.ppo - this.PPOsignal.result;
this.result.MACDsignal = this.MACDsignal.result;
this.result.MACDhist = this.MACDhist;
this.result.PPOsignal = this.PPOsignal.result;
this.result.PPOhist = this.PPOhist;
}
Indicator.prototype.calculatePPO = function() {
this.result.shortEMA = this.short.result;
this.result.longEMA = this.long.result;
this.result.macd = this.result.shortEMA - this.result.longEMA;
this.result.ppo = 100 * (this.result.macd / this.result.longEMA);
}
module.exports = Indicator;
+53
View File
@@ -0,0 +1,53 @@
// required indicators
var SMMA = require('./SMMA.js');
var Indicator = function (settings) {
this.input = 'candle';
this.lastClose = null;
this.weight = settings.interval;
this.avgU = new SMMA(this.weight);
this.avgD = new SMMA(this.weight);
this.u = 0;
this.d = 0;
this.rs = 0;
this.result = 0;
this.age = 0;
}
Indicator.prototype.update = function (candle) {
var currentClose = candle.close;
if (this.lastClose === null) {
// Set initial price to prevent invalid change calculation
this.lastClose = currentClose;
// Do not calculate RSI for this reason - there's no change!
this.age++;
return;
}
if (currentClose > this.lastClose) {
this.u = currentClose - this.lastClose;
this.d = 0;
} else {
this.u = 0;
this.d = this.lastClose - currentClose;
}
this.avgU.update(this.u);
this.avgD.update(this.d);
this.rs = this.avgU.result / this.avgD.result;
this.result = 100 - (100 / (1 + this.rs));
if (this.avgD.result === 0 && this.avgU.result !== 0) {
this.result = 100;
} else if (this.avgD.result === 0) {
this.result = 0;
}
this.lastClose = currentClose;
this.age++;
}
module.exports = Indicator;
+21
View File
@@ -0,0 +1,21 @@
// required indicators
// Simple Moving Average - O(1) implementation
var Indicator = function(windowLength) {
this.input = 'price';
this.windowLength = windowLength;
this.prices = [];
this.result = 0;
this.age = 0;
this.sum = 0;
}
Indicator.prototype.update = function(price) {
var tail = this.prices[this.age] || 0; // oldest price in window
this.prices[this.age] = price;
this.sum += price - tail;
this.result = this.sum / this.prices.length;
this.age = (this.age + 1) % this.windowLength
}
module.exports = Indicator;
+28
View File
@@ -0,0 +1,28 @@
// required indicators
var SMA = require('./SMA');
var Indicator = function (weight) {
this.input = 'price';
this.sma = new SMA(weight);
this.weight = weight;
this.prices = [];
this.result = 0;
this.age = 0;
}
Indicator.prototype.update = function (price) {
this.prices[this.age] = price;
if(this.prices.length < this.weight) {
this.sma.update(price);
} else if(this.prices.length === this.weight) {
this.sma.update(price);
this.result = this.sma.result;
} else {
this.result = (this.result * (this.weight - 1) + price) / this.weight;
}
this.age++;
}
module.exports = Indicator;
+38
View File
@@ -0,0 +1,38 @@
// required indicators
var EMA = require('./EMA.js');
var Indicator = function(settings) {
this.input = 'candle';
this.lastClose = null;
this.tsi = 0;
this.inner = new EMA(settings.long);
this.outer = new EMA(settings.short);
this.absoluteInner = new EMA(settings.long);
this.absoluteOuter = new EMA(settings.short);
}
Indicator.prototype.update = function(candle) {
var close = candle.close;
var prevClose = this.lastClose;
if (prevClose === null) {
// Set initial price to prevent invalid change calculation
this.lastClose = close;
// Do not calculate TSI on first close
return;
}
var momentum = close - prevClose;
this.inner.update(momentum);
this.outer.update(this.inner.result);
this.absoluteInner.update(Math.abs(momentum));
this.absoluteOuter.update(this.absoluteInner.result);
this.tsi = 100 * this.outer.result / this.absoluteOuter.result;
this.lastClose = close;
}
module.exports = Indicator;
+45
View File
@@ -0,0 +1,45 @@
// required indicators
var SMA = require('./SMA.js');
var Indicator = function(settings) {
this.input = 'candle';
this.lastClose = 0;
this.uo = 0;
this.firstWeight = settings.first.weight;
this.secondWeight = settings.second.weight;
this.thirdWeight = settings.third.weight;
this.firstLow = new SMA(settings.first.period);
this.firstHigh = new SMA(settings.first.period);
this.secondLow = new SMA(settings.second.period);
this.secondHigh = new SMA(settings.second.period);
this.thirdLow = new SMA(settings.third.period);
this.thirdHigh = new SMA(settings.third.period);
}
Indicator.prototype.update = function(candle) {
var close = candle.close;
var prevClose = this.lastClose;
var low = candle.low;
var high = candle.high;
var bp = close - Math.min(low, prevClose);
var tr = Math.max(high, prevClose) - Math.min(low, prevClose);
this.firstLow.update(tr);
this.secondLow.update(tr);
this.thirdLow.update(tr);
this.firstHigh.update(bp);
this.secondHigh.update(bp);
this.thirdHigh.update(bp);
var first = this.firstHigh.result / this.firstLow.result;
var second = this.secondHigh.result / this.secondLow.result;
var third = this.thirdHigh.result / this.thirdLow.result;
this.uo = 100 * (this.firstWeight * first + this.secondWeight * second + this.thirdWeight * third) / (this.firstWeight + this.secondWeight + this.thirdWeight);
this.lastClose = close;
}
module.exports = Indicator;