stock-indicators/lib/indicator/on-balance-volume.js
2025-03-31 11:20:04 +02:00

93 lines
2.2 KiB
JavaScript
Executable File

'use strict';
import _ from 'underscore';
import NumberUtil from '../utils/number.js';
import ValidateMixin from '../mixin/validate.js';
import SetOptionsMixin from '../mixin/set-options.js';
import HandleGeneratorMixin from '../mixin/handle-generator.js';
/**
* @param {object} [options]
* @param {number} [options.startIndex]
* @param {number} [options.endIndex}]
* @param {boolean} [options.lazyEvaluation=true]
* @param {number} [option.maxTickDuration=10]
*/
function OBV(options = {}) {
if (!new.target) throw new Error('ERROR: OBV() must be called with new');
this._options = {
startIndex: null,
endIndex: null,
lazyEvaluation: true,
maxTickDuration: 10,
}
let m = [SetOptionsMixin, ValidateMixin, HandleGeneratorMixin];
Object.assign(this, ...m);
this.setOptions(options);
this._collection = [];
}
OBV.prototype = {
setValues(values) {
if (!Array.isArray(values)) {
throw new Error('ERROR: values param is not an array');
}
values.forEach((item) => {
if (_.has(item, 'price') && _.has(item, 'volume')) {
let { price, volume } = item;
this._collection.push({ price, volume });
}
else throw new Error('ERROR: Invalid value');
});
},
calculate() {
this._validate(this._collection, this._options);
return this._handleGenerator(this._compute());
},
_compute: function* () {
let result = [];
let sum = 0;
let { startIndex, endIndex, lazyEvaluation } = this._options;
if (!NumberUtil.isNumeric(startIndex)) startIndex = 0;
if (!NumberUtil.isNumeric(endIndex)) endIndex = this._collection.length - 1;
let collection = this._collection.slice(startIndex, endIndex + 1);
for (let i = 0; i < collection.length; i++) {
let currItem = collection[i];
let resultItem = {
obv: 0,
price: currItem.price,
};
if (!i) {
result.push(resultItem);
yield resultItem;
continue;
}
let prevItem = collection[i - 1];
if (prevItem.price > currItem.price) sum -= currItem.volume;
else if (prevItem.price < currItem.price) sum += currItem.volume;
resultItem.obv = sum;
result.push(resultItem);
if (lazyEvaluation) yield resultItem;
};
return result;
},
}
export default OBV;