-
Notifications
You must be signed in to change notification settings - Fork 187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Built-in Bollinger band transform #548
Comments
Using Plot.window we benefit from standard options such as anchor, skipping NaNs &c: bollinger = (K) => (data) => d3.mean(data) + K * d3.deviation(data)
Plot.windowY({
reduce: bollinger(K),
k: N,
x: "date",
y: "close",
anchor: "end"
}) the current names of params is a bit unfortunate (k is N, K is the multiplier). For K = 0 the solution is even simpler :) Plot.windowY({
reduce: "mean",
k: N,
x: "date",
y: "close"
}) In terms of performance we loop a little bit more than your code (since sum and sum2 are not computed with a sliding window, but repeatedly). However I think it's a negligible cost compared to the simplicity of the formula. (We haven't optimized the variance/deviation reducer either at this point.) It's a bit more work to |
For the band as an area, this doesn't work: I'm opening #549 for this. However we're not blocked: we can take advantage of the symmetry of the bollinger function, and write: Plot.areaY(
aapl,
((A) => ({ ...A, y1: { transform: () => A.y1.transform().map((d) => -d) } }))(
Plot.windowY({
reduce: (data) => d3.mean(data) + K * d3.deviation(data),
y1: (d) => -d.close,
y2: "close",
k: N,
x: "date",
fill: "lightblue"
})
)
) And if you prefer the log version:
The log version allows to see that the volatility (I think that's the name of the relative deviation?) was higher in the 2008 episodes than in 2012. I suppose that this doesn't matter much when you're using the band to base a decision on the latest values, but if if you're doing history/time analysis it seems wrong to work on linear values. Note that you can compute the log version without using a log scale to plot, and it makes the chart arguably more interesting (or "accurate") than the all-linear chart; at least the prices never go below zero! |
I’m pretty happy with our solution using Plot.window, so going to close this now, but we could always add something more built-in in the future if desired. |
I still think this would be nice to include, especially given how concise it could be with a compound mark that does both the bands and the center line. Something like: function bollingerBandY(data, options) {
return Plot.marks(
Plot.areaY(data, bollingerMapY(4, 2, {x: "date", y: "value", fillOpacity: 0.2})),
Plot.lineY(data, Plot.map({y: bollinger(4, 0)}, {x: "date", y: "value", stroke: "blue"})),
Plot.lineY(data, {x: "date", y: "value", strokeWidth: 1})
);
} function bollingerMapY(N, K, options) {
return Plot.map({y1: bollinger(N, -K), y2: bollinger(N, K)}, options);
} function bollinger(N, K) {
return Plot.window({k: N, reduce: (Y) => d3.mean(Y) + K * d3.deviation(Y), strict: true, anchor: "end"});
} |
With options passed as k (window size, formerly N), and multiplier (formerly K)? |
Like so
The text was updated successfully, but these errors were encountered: