Skip to content

Commit cfe3a7e

Browse files
feat(altair): implement indicator-bollinger (#3248)
## Implementation: `indicator-bollinger` - altair Implements the **altair** version of `indicator-bollinger`. **File:** `plots/indicator-bollinger/implementations/altair.py` **Parent Issue:** #3237 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20795214151)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3e86c95 commit cfe3a7e

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""pyplots.ai
2+
indicator-bollinger: Bollinger Bands Indicator Chart
3+
Library: altair | Python 3.13
4+
Quality: pending | Created: 2025-01-07
5+
"""
6+
7+
import altair as alt
8+
import numpy as np
9+
import pandas as pd
10+
11+
12+
# Data - Generate realistic stock price data with Bollinger Bands
13+
np.random.seed(42)
14+
15+
# Generate 120 trading days of price data
16+
n_periods = 120
17+
dates = pd.date_range("2024-01-02", periods=n_periods, freq="B") # Business days
18+
19+
# Generate realistic price movement (random walk with drift)
20+
returns = np.random.normal(0.001, 0.02, n_periods) # Small positive drift, 2% daily volatility
21+
price_base = 150.0
22+
close_prices = price_base * np.cumprod(1 + returns)
23+
24+
# Calculate Bollinger Bands (20-period SMA, 2 standard deviations)
25+
window = 20
26+
df = pd.DataFrame({"date": dates, "close": close_prices})
27+
df["sma"] = df["close"].rolling(window=window).mean()
28+
df["std"] = df["close"].rolling(window=window).std()
29+
df["upper_band"] = df["sma"] + 2 * df["std"]
30+
df["lower_band"] = df["sma"] - 2 * df["std"]
31+
32+
# Drop NaN values from rolling calculation
33+
df = df.dropna().reset_index(drop=True)
34+
35+
# Create base chart
36+
base = alt.Chart(df).encode(x=alt.X("date:T", title="Date", axis=alt.Axis(format="%b %Y", labelAngle=-45)))
37+
38+
# Upper band line
39+
upper_line = base.mark_line(strokeWidth=2, color="#306998", opacity=0.7).encode(
40+
y=alt.Y("upper_band:Q", title="Price ($)", scale=alt.Scale(zero=False))
41+
)
42+
43+
# Lower band line
44+
lower_line = base.mark_line(strokeWidth=2, color="#306998", opacity=0.7).encode(
45+
y=alt.Y("lower_band:Q", scale=alt.Scale(zero=False))
46+
)
47+
48+
# Band fill area (between upper and lower bands)
49+
band_area = (
50+
alt.Chart(df)
51+
.mark_area(opacity=0.15, color="#306998")
52+
.encode(x=alt.X("date:T"), y=alt.Y("upper_band:Q", scale=alt.Scale(zero=False)), y2="lower_band:Q")
53+
)
54+
55+
# Middle band (SMA) - dashed line
56+
sma_line = base.mark_line(strokeWidth=2.5, strokeDash=[8, 4], color="#306998", opacity=0.9).encode(
57+
y=alt.Y("sma:Q", scale=alt.Scale(zero=False))
58+
)
59+
60+
# Close price line - prominent
61+
price_line = base.mark_line(strokeWidth=3, color="#FFD43B").encode(y=alt.Y("close:Q", scale=alt.Scale(zero=False)))
62+
63+
# Combine all layers
64+
chart = (
65+
alt.layer(band_area, upper_line, lower_line, sma_line, price_line)
66+
.properties(
67+
width=1600,
68+
height=900,
69+
title=alt.Title(text="indicator-bollinger · altair · pyplots.ai", fontSize=28, anchor="middle"),
70+
)
71+
.configure_axis(labelFontSize=18, titleFontSize=22, gridOpacity=0.3)
72+
.configure_view(strokeWidth=0)
73+
.configure_legend(titleFontSize=18, labelFontSize=16)
74+
)
75+
76+
# Save as PNG and HTML
77+
chart.save("plot.png", scale_factor=3.0)
78+
chart.save("plot.html")
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Per-library metadata for altair implementation of indicator-bollinger
2+
# Auto-generated by impl-generate.yml
3+
4+
library: altair
5+
specification_id: indicator-bollinger
6+
created: '2026-01-07T20:19:32Z'
7+
updated: '2026-01-07T20:19:32Z'
8+
generated_by: claude-opus-4-5-20251101
9+
workflow_run: 20795214151
10+
issue: 3237
11+
python_version: 3.13.11
12+
library_version: 6.0.0
13+
preview_url: https://storage.googleapis.com/pyplots-images/plots/indicator-bollinger/altair/plot.png
14+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/indicator-bollinger/altair/plot_thumb.png
15+
preview_html: https://storage.googleapis.com/pyplots-images/plots/indicator-bollinger/altair/plot.html
16+
quality_score: null
17+
review:
18+
strengths: []
19+
weaknesses: []

0 commit comments

Comments
 (0)