UNPKG

trading-signals

Version:

Technical indicators to run technical analysis with JavaScript / TypeScript.

72 lines 3 kB
import { TradingSignal, TrendIndicatorSeries } from '../../base/Indicator.js'; import { pushUpdate } from '../../util/pushUpdate.js'; export class UltimateOscillator extends TrendIndicatorSeries { #candles = []; #overbought; #oversold; shortPeriod; mediumPeriod; longPeriod; constructor({ longPeriod = 28, mediumPeriod = 14, shortPeriod = 7 } = {}, { overbought = 70, oversold = 30 } = {}) { super(); this.shortPeriod = shortPeriod; this.mediumPeriod = mediumPeriod; this.longPeriod = longPeriod; this.#overbought = overbought; this.#oversold = oversold; } getRequiredInputs() { return this.longPeriod + 1; } update(candle, replace) { pushUpdate({ array: this.#candles, item: candle, maxLength: this.getRequiredInputs(), replace: replace }); if (this.#candles.length < this.getRequiredInputs()) { return null; } const buyingPressures = []; const trueRanges = []; for (let i = 1; i < this.#candles.length; i++) { const { close, high, low } = this.#candles[i]; const previousClose = this.#candles[i - 1].close; const trueLow = Math.min(low, previousClose); const trueHigh = Math.max(high, previousClose); buyingPressures.push(close - trueLow); trueRanges.push(trueHigh - trueLow); } const average = (period) => { let buyingPressureSum = 0; let trueRangeSum = 0; for (let i = trueRanges.length - period; i < trueRanges.length; i++) { buyingPressureSum += buyingPressures[i]; trueRangeSum += trueRanges[i]; } return { buyingPressureSum, trueRangeSum }; }; const short = average(this.shortPeriod); if (short.trueRangeSum === 0) { return this.setResult(50, replace); } const medium = average(this.mediumPeriod); const long = average(this.longPeriod); const shortAverage = short.buyingPressureSum / short.trueRangeSum; const mediumAverage = medium.buyingPressureSum / medium.trueRangeSum; const longAverage = long.buyingPressureSum / long.trueRangeSum; return this.setResult((100 * (4 * shortAverage + 2 * mediumAverage + longAverage)) / 7, replace); } calculateSignalState(result) { const hasResult = result !== null && result !== undefined; const isOversold = hasResult && result <= this.#oversold; const isOverbought = hasResult && result >= this.#overbought; switch (true) { case !hasResult: return TradingSignal.UNKNOWN; case isOversold: return TradingSignal.BEARISH; case isOverbought: return TradingSignal.BULLISH; default: return TradingSignal.SIDEWAYS; } } } //# sourceMappingURL=UltimateOscillator.js.map