@amcharts/amcharts5
Version:
amCharts 5
186 lines • 7.54 kB
JavaScript
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