tean-js
Version:
A simple forex and stock technical analysis module
294 lines (276 loc) • 11.7 kB
JavaScript
'use strict';
const
finance = require('yahoo-finance');
class StockWatcher {
constructor(stock, interval) {
this.symbol = stock;
this.interval = interval;
}
/* Retrieves a snapshot object of the stock
* @function getSnapshot
*
*/
getSnapshot() {
let self = this;
return new Promise(function (fulfill, reject) {
finance.snapshot({
symbol:self.symbol,
fields: ['s', 'n', 'd1', 'l1', 'y', 'r']
}, function (err, snapshot) {
if (err != null)
reject(err);
else
fulfill(snapshot);
});
});
}
/* Retrieves an array of objects containing the historical values of the stock
*
* @param {Date} from - Start period Ex: '2015-06-01'
* @param {Date} end = period Ex: '2015-06-14'
* @param {callback} [cb] - callback function with 2 params
*/
getHistorical(start, end, cb) {
let self = this;
if (cb === undefined) {
return new Promise(function (fulfill, reject) {
finance.historical({
symbol: self.symbol,
from: start,
to: end,
period: self.interval
}, function (err, quotes) {
if (err != null)
reject(err);
else
fulfill(quotes);
});
});
}
finance.historical({
symbol: this.symbol,
from: start,
to: end,
period: this.interval
}, function (err, quotes) {
cb(err, quotes);
});
}
/* Gets the max close price from the period
* @param {integer} period - period of the max price search
* @param {callback} cb - callback with the result
*/
getMax(period, cb) {
if (this.interval == 'd')
var from = new Date((new Date()).getTime() - (new Date(period * 24 * 60 * 60 * 1000)));
else if (this.interval == 'w')
var from = new Date((new Date()).getTime() - (new Date(period * 7 * 24 * 60 * 60 * 1000)));
else if (this.interval == 'm')
var from = new Date((new Date()).getTime() - (new Date(period * 30 * 24 * 60 * 60 * 1000)));
this.getHistorical(from, new Date(), function (err, quotes) {
if (err == null)
cb(null);
var max = 0;
for (var i = 0; i < quotes.length; i++)
if (quotes[i].close > max)
max = quotes[i].close;
cb(max);
});
}
/* Gets the min close price from the period
* @param {integer} period - period of the min price search
* @param {callback} cb - callback with the result
*/
getMin(period, cb) {
if (this.interval == 'd')
var from = new Date((new Date()).getTime() - (new Date(period * 24 * 60 * 60 * 1000)));
else if (this.interval == 'w')
var from = new Date((new Date()).getTime() - (new Date(period * 7 * 24 * 60 * 60 * 1000)));
else if (this.interval == 'm')
var from = new Date((new Date()).getTime() - (new Date(period * 30 * 24 * 60 * 60 * 1000)));
this.getHistorical(from, new Date(), function (err, quotes) {
if (err == null)
cb(null);
var min = this.getMax();
for (var i = 0; i < quotes.length; i++)
if (quotes[i].close < min)
max = quotes[i].close;
cb(max);
});
}
/* Gets the SMA close price from the period
* @param {integer} period - period of the SMA price search
* @returns {object} {high, low}
*/
getSMA(period) {
if (this.interval == 'd')
var from = new Date((new Date()).getTime() - (new Date(period * 24 * 60 * 60 * 1000)));
else if (this.interval == 'w')
var from = new Date((new Date()).getTime() - (new Date(period * 7 * 24 * 60 * 60 * 1000)));
else if (this.interval == 'm')
var from = new Date((new Date()).getTime() - (new Date(period * 30 * 24 * 60 * 60 * 1000)));
return new Promise(function (fulfill, reject) {
this.getHistorical(from, new Date(), function (err, quotes) {
if (err != null)
reject(err);
var sum = 0;
for (var i = 0; i < quotes.length; i++) {
sum = sum + quotes[i].close;
if (i == (quotes.length - 1))
fulfill(sum/quotes.length)
};
});
});
}
/* Gets the MAHL(Moving Average High Low) from the period
* @param {integer} period - period of the MAHL search
* @returns {integer} the MAHL of the period.
*/
getMAHL(period) {
if (this.interval == 'd')
var from = new Date((new Date()).getTime() - (new Date(period * 24 * 60 * 60 * 1000)));
else if (this.interval == 'w')
var from = new Date((new Date()).getTime() - (new Date(period * 7 * 24 * 60 * 60 * 1000)));
else if (this.interval == 'm')
var from = new Date((new Date()).getTime() - (new Date(period * 30 * 24 * 60 * 60 * 1000)));
return new Promise(function (fulfill, reject) {
this.getHistorical(from, new Date(), function (err, quotes) {
if (err != null)
reject(err);
var high = 0;
var low = 0;
for (var i = 0; i < quotes.length; i++) {
high = high + quotes[i].high;
low = low + quotes[i].low;
if (i == (quotes.length - 1))
fulfill({
ma_high: high / quotes.length,
ma_low: low /quotes.length
});
};
});
});
}
/* Gets the RSI close price from the period
* @param {integer} period - period of the RSI price search
* @returns {integer} the RSI of the period.
*/
getRSI(period) {
let self = this;
if (this.interval == 'd')
var from = new Date((new Date()).getTime() - (new Date(period * 24 * 60 * 60 * 1000)));
else if (this.interval == 'w')
var from = new Date((new Date()).getTime() - (new Date(period * 7 * 24 * 60 * 60 * 1000)));
else if (this.interval == 'm')
var from = new Date((new Date()).getTime() - (new Date(period * 30 * 24 * 60 * 60 * 1000)));
return new Promise(function (fulfill, reject) {
self.getHistorical(from, new Date(), function (err, quotes) {
if (err != null)
reject(err);
var up = 0;
var down = 0;
for (var i = 0; i < quotes.length; i++) {
if (quotes[i].close > quotes[i].open)
up++;
if (quotes[i].close < quotes[i].open)
down++;
if (i == (quotes.length - 1))
fulfill(100 - 100 / (1 + ((up /quotes.length) / (down /quotes.length))));
};
});
});
}
/* Gets the Average True Range(ATR) of the stock
* @param {integer} period - the period of the ATR
* @param {inteher} method - the method to calculate the True Range( 1 for High-low; 2 for High-close;3 for Low-close)
* @result {float} the ATR
*/
getATR(period, method) {
let self = this;
if (this.interval == 'd')
var from = new Date((new Date()).getTime() - (new Date(period * 24 * 60 * 60 * 1000)));
else if (this.interval == 'w')
var from = new Date((new Date()).getTime() - (new Date(period * 7 * 24 * 60 * 60 * 1000)));
else if (this.interval == 'm')
var from = new Date((new Date()).getTime() - (new Date(period * 30 * 24 * 60 * 60 * 1000)));
return new Promise(function (fulfill, reject) {
self.getHistorical(from, new Date(), function (err, quotes) {
if (err != null)
reject(err);
var sum = 0;
for (var i = 0; i < quotes.length; i++) {
switch (method) {
case 1:
sum = sum + quotes[i].high - quotes[i].low;
break;
case 2:
sum = sum + Math.abs(quotes[i].high - quotes[i].close);
break;
case 3:
sum = sum + Math.abs(quotes[i].low - quotes[i].close);
break;
};
if (i == quotes.length - 1)
fulfill(sum / quotes.length);
};
});
});
}
/* Returns if it's a good idea to buy based on the technical indicatiors of the module
* @param {integer} period - period of the buy, if its a quick buy set to low values, and a long-term bet big values.
* @param {integer} precision - this precision is the min quotient of the buy/dont buy list of technical indications
* @returns {bool} true if it's a good idea to buy, false if it's not.
*/
isGoodToBuy(period, precision) {
var good = 0;
var not = 0;
let self = this;
return new Promise(function (fulfill, reject) {
self.getRSI(period).then(function (rsi) {
if (rsi <= 30) good++;
else not++;
self.getSMA(period).then(function (sma) {
self.getSnapshot().then(function (snapshot) {
if (sma > snapshot.lastTradePriceOnly)
good++;
else
not++;
if (precision <= (good / not))
fulfill(true);
else
fulfill(false);
});
});
});
});
}
/* Returns if it's a good idea to sell based on the technical indicatiors of the module
* @param {integer} period - period of the sell, if its a quick buy set to low values, and a long-term bet big values.
* @param {integer} precision - this precision is the min quotient of the sell/dont sell list of technical indications
* @returns {bool} true if it's a good idea to sell, false if it's not.
*/
isGoodToSell(period, precision) {
var good = 0;
var not = 0;
let self = this;
return new Promise(function (fulfill, reject) {
self.getRSI(period).then(function (rsi) {
if (rsi >= 70) good++;
else not++;
self.getSMA(period).then(function (sma) {
self.getSnapshot().then(function (snapshot) {
if (sma < snapshot.lastTradePriceOnly)
good++;
else
not++;
if (precision <= (good / not))
fulfill(true);
else
fulfill(false);
});
});
});
});
}
}
module.exports = StockWatcher;