UNPKG

@amcharts/amcharts5

Version:
186 lines • 7.54 kB
import { __awaiter } from "tslib"; import { MovingAverage } from "./MovingAverage"; import { LineSeries } from "../../xy/series/LineSeries"; /** * An implementation of a [[StockChart]] indicator. * * @see {@link https://www.amcharts.com/docs/v5/charts/stock/indicators/} for more info */ export class BollingerBands extends MovingAverage { constructor() { super(...arguments); this._editableSettings = [{ key: "period", name: this.root.language.translateAny("Period"), type: "number", minValue: 5, maxValue: 100, step: 1 }, { key: "standardDeviations", name: this.root.language.translateAny("Deviation"), type: "number", minValue: 1, maxValue: 4, step: 0.1 }, { key: "upperColor", name: this.root.language.translateAny("Upper"), type: "color" }, { key: "seriesColor", name: this.root.language.translateAny("Average"), type: "color" }, { key: "lowerColor", name: this.root.language.translateAny("Lower"), type: "color" }, { key: "field", name: this.root.language.translateAny("Field"), type: "dropdown", options: ["open", "close", "low", "high", "hl/2", "hlc/3", "hlcc/4", "ohlc/4"] }, { key: "maType", name: this.root.language.translateAny("Type"), type: "dropdown", options: ["simple", "weighted", "exponential", "dema", "tema"] }]; } _afterNew() { const stockSeries = this.get("stockSeries"); const chart = stockSeries.chart; if (chart) { const upperBandSeries = chart.series.push(LineSeries.new(this._root, { valueXField: "valueX", valueYField: "upper", openValueYField: "lower", calculateAggregates: true, xAxis: stockSeries.get("xAxis"), yAxis: stockSeries.get("yAxis"), groupDataDisabled: true, themeTags: ["indicator", "bollingerbands", "upper"] })); upperBandSeries.fills.template.set("visible", true); upperBandSeries.setPrivate("baseValueSeries", stockSeries); this.upperBandSeries = upperBandSeries; const lowerBandSeries = chart.series.push(LineSeries.new(this._root, { valueXField: "valueX", valueYField: "lower", calculateAggregates: true, xAxis: stockSeries.get("xAxis"), yAxis: stockSeries.get("yAxis"), groupDataDisabled: true, themeTags: ["indicator", "bollingerbands", "lower"] })); lowerBandSeries.setPrivate("baseValueSeries", stockSeries); this.lowerBandSeries = lowerBandSeries; } super._afterNew(); this.series.addTag("bollingerbands"); this.series._applyThemes(); } _prepareChildren() { if (this.isDirty("standardDeviations")) { this.markDataDirty(); } super._prepareChildren(); } _updateChildren() { super._updateChildren(); const upperColor = "upperColor"; if (this.isDirty(upperColor)) { const color = this.get(upperColor); const upperBandSeries = this.upperBandSeries; upperBandSeries.set("stroke", color); upperBandSeries.set("fill", color); upperBandSeries.strokes.template.set("stroke", color); this._updateSeriesColor(upperBandSeries, color, upperColor); } const lowerColor = "lowerColor"; if (this.isDirty(lowerColor)) { const color = this.get(lowerColor); const lowerBandSeries = this.lowerBandSeries; lowerBandSeries.set("stroke", color); lowerBandSeries.strokes.template.set("stroke", color); this._updateSeriesColor(lowerBandSeries, color, lowerColor); } this.setCustomData("standardDeviations", this.get("standardDeviations")); } /** * @ignore */ prepareData() { super.prepareData(); if (this.series) { let period = this.get("period", 20); const stockSeries = this.get("stockSeries"); const dataItems = stockSeries.dataItems; let standardDeviations = this.get("standardDeviations", 2); let smaData = this.series.data.values; // Rolling sum / sum of squares over the window, so the bands are O(n) // instead of O(n * period) and values are read once per bar. let sum = 0; let sumSq = 0; let count = 0; for (let i = 0, len = smaData.length; i < len; i++) { const v = this._getValue(dataItems[i]); if (v != null) { sum += v; sumSq += v * v; count++; } if (i >= period) { const ov = this._getValue(dataItems[i - period]); if (ov != null) { sum -= ov; sumSq -= ov * ov; count--; } } if (i >= period - 1) { // sum((x - m)^2) = sumSq - 2*m*sum + count*m^2, divided by period. const mean = smaData[i].ma; const variance = (sumSq - 2 * mean * sum + count * mean * mean) / period; const std = Math.sqrt(variance < 0 ? 0 : variance); smaData[i].lower = mean - standardDeviations * std; smaData[i].upper = mean + standardDeviations * std; } } this.upperBandSeries.updateData(smaData); this.lowerBandSeries.updateData(smaData); } } _dispose() { this.upperBandSeries.dispose(); this.lowerBandSeries.dispose(); super._dispose(); } hide(duration) { const _super = Object.create(null, { hide: { get: () => super.hide } }); return __awaiter(this, void 0, void 0, function* () { return Promise.all([ _super.hide.call(this, duration), this.upperBandSeries.hide(duration), this.lowerBandSeries.hide(duration) ]); }); } show(duration) { const _super = Object.create(null, { show: { get: () => super.show } }); return __awaiter(this, void 0, void 0, function* () { return Promise.all([ _super.show.call(this, duration), this.upperBandSeries.show(duration), this.lowerBandSeries.show(duration) ]); }); } } BollingerBands.className = "BollingerBands"; BollingerBands.classNames = MovingAverage.classNames.concat([BollingerBands.className]); //# sourceMappingURL=BollingerBands.js.map