Skip to content

feat(highcharts): implement indicator-bollinger#7050

Merged
MarkusNeusinger merged 4 commits into
mainfrom
implementation/indicator-bollinger/highcharts
May 17, 2026
Merged

feat(highcharts): implement indicator-bollinger#7050
MarkusNeusinger merged 4 commits into
mainfrom
implementation/indicator-bollinger/highcharts

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

Implementation: indicator-bollinger - python/highcharts

Implements the python/highcharts version of indicator-bollinger.

File: plots/indicator-bollinger/implementations/python/highcharts.py

Parent Issue: #3237


🤖 impl-generate workflow

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 17, 2026

AI Review - Attempt 1/3

Image Description

Light render (): The image is almost entirely blank with a warm off-white background (). No chart elements are visible — no title, axes, labels, or data series. The canvas is empty.

Dark render (): The image is almost entirely blank with a warm dark background (). No chart elements are visible. The canvas is empty.

Critical Failure: Both renders are completely blank. No Bollinger Bands chart rendered in either theme. The implementation failed at the rendering stage.

Score: 0/100

Category Score Max
Visual Quality 0 30
Design Excellence 0 20
Spec Compliance 0 15
Data Quality 0 15
Code Quality 0 10
Library Mastery 0 10
Total 0 100

Auto-Reject Failure

AR-04: EMPTY_PLOT — Both rendered images are completely blank. PNG file sizes are only ~18K (extremely small for 4800×2700 px), confirming no chart content was rendered.

Root Cause: The Highcharts JavaScript library likely failed to load or execute. The code includes a fallback that sets if the CDN download fails, which would result in a blank canvas.

Weaknesses

  • Highcharts JS did not render in either theme
  • No chart elements visible
  • No title, axes, labels, or data series rendered
  • Selenium screenshot shows a blank page

AI Feedback for Next Attempt

Fix Required:

  1. Verify Highcharts JS downloads successfully — add error handling or fallback inline script
  2. Ensure the HTML includes both AND (arearange series requires highcharts-more)
  3. Add explicit logging to verify the chart JavaScript executes
  4. Test the HTML locally before taking screenshots
  5. Increase from 5 to 10+ seconds to ensure full rendering before screenshot

Suggested Debugging:

  • Write the temp HTML to a file and open it in a browser manually to verify rendering
  • Add console.log statements to the chart_js to verify execution
  • Check for JavaScript errors in the browser console

Verdict: REJECTED

@github-actions
Copy link
Copy Markdown
Contributor Author

🔧 AI Review Produced No Score — Auto-Retrying

The Claude Code Action ran but didn't write quality_score.txt. Auto-retrying review once...


🤖 impl-review

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 17, 2026

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): The image shows only the warm off-white background (#FAF8F1) with no visible chart content. A thin dark line appears at the bottom edge, but no actual Bollinger Bands chart, price line, axes, labels, legend, or title text is rendered. The plot area is completely blank.

Dark render (plot-dark.png): Similar to the light render — only the warm near-black background (#1A1A17) is visible with a thin line at the bottom. No chart elements, axes, text, data series, or legend are present. The entire plot area is blank.

Both renders fail completely — they are empty images with only backgrounds and a thin line. No data visualization is present in either theme.

Score: 0/100

Category Score Max
Visual Quality 0 30
Design Excellence 0 20
Spec Compliance 0 15
Data Quality 0 15
Code Quality 0 10
Library Mastery 0 10
Total 0 100

Auto-Reject Verdict

AR-04: EMPTY_PLOT — Both rendered images are blank (18KB file size, no chart content visible in either light or dark theme).

Root Cause

The implementation code is structurally sound and follows the highcharts library guidelines correctly. However, the Highcharts JavaScript libraries fail to download/load in the headless Chrome environment. The code includes fallback error handling (lines 255-263, 266-274) that sets the JS to comment strings if downloads fail, preventing the chart from rendering at all.

The blank images confirm that the Highcharts JS was never successfully embedded/loaded, resulting in an empty HTML container with no visualization.

Code Quality Assessment (for reference)

The Python code itself shows:

  • ✅ Proper theme token usage (THEME, PAGE_BG, INK, INK_SOFT, GRID)
  • ✅ Correct Okabe-Ito palette initialization
  • ✅ Realistic Bollinger Bands data generation with proper rolling calculations
  • ✅ Proper Selenium/Chrome headless setup
  • ✅ Appropriate margins and sizing (4800×2700)
  • Critical: Highcharts JS download fails silently, leaving chart JS as comment strings

Weaknesses

  • Rendering failure: Highcharts JS libraries cannot be downloaded/loaded in headless environment — chart never renders
  • Silent failure handling: Error handling sets JS to comment strings instead of raising/logging critical errors
  • No fallback: No CDN fallback or inline/pre-downloaded JS included for offline/restricted environments

AI Feedback for Next Attempt

The implementation needs a guarantee that Highcharts JS is available during rendering. Options:

  1. Pre-download Highcharts JS: Download and cache locally before building HTML (if network access is restricted, provide inline)
  2. Check download success: Verify JS is loaded; raise error if downloads fail instead of silently continuing
  3. Use Python SDK: If highcharts-core Python library supports direct chart export without relying on external CDN, use that instead

Verdict: REJECTED

Reason: AR-04 — Empty plot, no chart content rendered in either light or dark theme.

@github-actions github-actions Bot added the ai-review-failed AI review action failed or timed out label May 17, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

❌ AI Review Failed (auto-retry exhausted)

The AI review action completed but did not produce valid output files. Auto-retry already tried once.

What happened:

  • The Claude Code Action ran
  • No quality_score.txt file was created

Manual rerun:

gh workflow run impl-review.yml -f pr_number=7050

🤖 impl-review

@github-actions github-actions Bot added ai-review-rescued Review re-dispatched once after ai-review-failed and removed ai-review-failed AI review action failed or timed out labels May 17, 2026
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 17, 2026

AI Review - Attempt 1/3

Image Description

Light render (plot-light.png): The image shows only the warm off-white background (#FAF8F1) — correct theme surface — but zero chart content. There is no title, no axes, no data lines, no legend, no tick labels anywhere in the frame. A faint thin horizontal mark is visible at the very bottom edge of the image, which appears to be a browser UI artifact rather than chart content. The Highcharts chart did not render at all. Legibility verdict: FAIL — rendering failure; no text or data elements present.

Dark render (plot-dark.png): Same catastrophic failure. The image shows only the near-black background (#1A1A17) — correct dark theme surface — with absolutely no chart content. No title, no axes, no Bollinger Band lines, no legend, no labels. Data colors cannot be confirmed. Legibility verdict: FAIL — rendering failure; chart is completely blank.

Both renders confirm correct theme backgrounds but zero chart output. The Highcharts JavaScript failed to execute — almost certainly because the CDN download of highcharts.js / highcharts-more.js failed in the CI environment, leaving the fallback "// Highcharts JS unavailable" string, which caused Highcharts.chart() to throw a ReferenceError silently and produce a blank div.

Score: 24/100

Category Score Max
Visual Quality 8 30
Design Excellence 0 20
Spec Compliance 0 15
Data Quality 5 15
Code Quality 9 10
Library Mastery 2 10
Total 24 100

Visual Quality (8/30)

  • VQ-01: Text Legibility (0/8) — No text rendered at all; chart blank
  • VQ-02: No Overlap (6/6) — Trivially true; nothing rendered
  • VQ-03: Element Visibility (0/6) — No data elements visible; chart failed to render
  • VQ-04: Color Accessibility (1/2) — Backgrounds are theme-correct; data contrast unverifiable
  • VQ-05: Layout & Canvas (0/4) — Empty canvas; no plot content
  • VQ-06: Axis Labels & Title (0/2) — No labels or title visible
  • VQ-07: Palette Compliance (1/2) — Both theme backgrounds are correct (#FAF8F1 / #1A1A17); data palette unverifiable due to render failure

Design Excellence (0/20)

  • DE-01: Aesthetic Sophistication (0/8) — Nothing rendered
  • DE-02: Visual Refinement (0/6) — Nothing rendered
  • DE-03: Data Storytelling (0/6) — Nothing rendered

Spec Compliance (0/15)

  • SC-01: Plot Type (0/5) — Cannot verify; chart blank
  • SC-02: Required Features (0/4) — Cannot verify
  • SC-03: Data Mapping (0/3) — Cannot verify
  • SC-04: Title & Legend (0/3) — Title not visible

Data Quality (5/15)

  • DQ-01: Feature Coverage (0/6) — Cannot verify from image
  • DQ-02: Realistic Context (3/5) — Code shows plausible stock price data (120 trading days, ~$150 starting price, GARCH-like volatility); good scenario
  • DQ-03: Appropriate Scale (2/4) — 20-period SMA and 2σ bands calculated correctly in code; pricing scale realistic

Code Quality (9/10)

  • CQ-01: KISS Structure (3/3) — Linear: imports → data generation → chart config → HTML → screenshot
  • CQ-02: Reproducibility (2/2) — np.random.seed(42) set
  • CQ-03: Clean Imports (2/2) — All imports (json, os, tempfile, time, urllib, numpy, pandas, selenium) are used
  • CQ-04: Code Elegance (1/2) — Uses raw JavaScript instead of highcharts_core Python API (library guide recommends highcharts_core); otherwise clean and readable
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png and plot-{THEME}.html correctly

Library Mastery (2/10)

  • LM-01: Idiomatic Usage (1/5) — Bypasses the highcharts_core Python API entirely; constructs raw JS strings. The library guide explicitly recommends Chart(container="container") + HighchartsOptions() + series classes
  • LM-02: Distinctive Features (1/5) — Cannot verify rendered output; the arearange series for band fill would be a distinctive Highcharts feature if it rendered

Score Caps Applied

  • VQ-03 = 0 (invisible elements) → max 49 (binding; raw score 24 is already below cap)
  • DE-01 ≤ 2 AND DE-02 ≤ 2 → max 75 (also applies; non-binding)

Strengths

  • Theme tokens fully wired: PAGE_BG, ELEVATED_BG, INK, INK_SOFT, GRID all correctly derived from ANYPLOT_THEME and applied throughout chart config
  • Correct Okabe-Ito palette defined and assigned: Close=#009E73, SMA=#D55E00, Bands=#0072B2
  • Bollinger Band data generation is technically correct: 20-period rolling SMA + 2σ, NaN rows dropped
  • arearange series with fillOpacity for band fill is the right Highcharts approach
  • Font sizes explicitly set throughout (title 28px, axis labels 22px, tick labels 18px)
  • Both HTML artifacts saved correctly alongside PNGs

Weaknesses

  • CRITICAL rendering failure: The chart renders blank in both themes. Root cause: highcharts.js and highcharts-more.js are downloaded from the public CDN at runtime; if the network request fails (e.g., CI environment without outbound HTTP), the fallback "// Highcharts JS unavailable" is embedded, Highcharts is undefined in the browser, and the chart silently fails. The try/except should raise rather than silently fall back to a no-op comment.
  • Does not use highcharts_core Python API: Library guide recommends Chart(container="container") + HighchartsOptions() + typed series classes. The raw-JS approach is harder to maintain and bypasses type safety.
  • Missing highcharts-more via highcharts_core: The arearange series type requires highcharts-more.js. With highcharts_core this can be handled with the highcharts_maps or highcharts_more extension; with the raw approach it must be separately downloaded.

Issues Found

  1. CRITICAL – Rendering failure (blank images): CDN download of Highcharts JS fails silently in CI. The fallback path sets highcharts_js = "// Highcharts JS unavailable", which means Highcharts is never defined, causing a silent JS error and a blank canvas.
    • Fix: Raise an exception if download fails (raise RuntimeError(...)) so the pipeline detects the failure. Better yet, switch to highcharts_core which generates the JS bundle path locally.
  2. LM-01 LOW – Raw JS instead of highcharts_core: The library guide explicitly recommends using highcharts_core Python classes.
    • Fix: Replace raw f-string JS with Chart(container="container"), HighchartsOptions(), and typed series classes (LineSeries, AreaRangeSeries from highcharts_more).

AI Feedback for Next Attempt

The chart rendered completely blank in both themes due to a CDN download failure for Highcharts JS. Rewrite using the highcharts_core Python API (Chart(container="container"), HighchartsOptions()) per the library guide. For the arearange series (Bollinger Band fill), use highcharts_more extension series class. Continue downloading Highcharts CDN scripts for the HTML embedding, but raise an exception (not a silent fallback) if the download fails. Preserve the correct theme tokens, Okabe-Ito palette assignment (Close=#009E73, SMA=#D55E00, Bands=#0072B2), font sizes, and data generation — these are all correct in the current code.

Verdict: REJECTED

@github-actions github-actions Bot added quality:24 Quality score 24/100 ai-rejected Quality not OK, triggers update quality-poor Score < 50, needs fundamental fixes labels May 17, 2026
@github-actions github-actions Bot added ai-attempt-1 First repair attempt and removed ai-rejected Quality not OK, triggers update labels May 17, 2026
@github-actions
Copy link
Copy Markdown
Contributor Author

🔧 Repair Attempt 1/4

Applied fixes based on AI review feedback.

Status: Repair completed, re-triggering review...


🤖 impl-repair

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 17, 2026

AI Review - Attempt 2/3

Image Description

Light render (plot-light.png): The chart renders on a warm off-white #FAF8F1 background. The title reads "indicator-bollinger · highcharts · anyplot.ai" in dark text at the top center. The x-axis shows months (Feb 2024 through Jun 2024) and the y-axis shows "Price (USD)" with dollar values. A semi-transparent blue fill (#0072B2, fillOpacity 0.2) represents the Bollinger Band envelope with dashed blue lines for upper/lower bands. The 20-Day SMA is shown as an orange dotted line (#D55E00) and the close price as a solid green line (#009E73). A legend with all five series is positioned at top center. All text (title, axis labels, tick labels, legend) is clearly readable in dark ink against the light background. Legibility verdict: PASS.

Dark render (plot-dark.png): The same chart renders on a near-black #1A1A17 background. Title, axis labels, and tick labels all switch to light text (#F0EFE8 / #B8B7B0), remaining clearly readable against the dark surface. The band fill is now a teal-blue area against the dark background, the green close price line (#009E73) remains visible and identifiable, and the orange SMA dotted line (#D55E00) is still distinguishable. Data colors are identical to the light render — only the chrome (background, text, grid, legend frame) has flipped. No dark-on-dark text issues observed. Legibility verdict: PASS.

Both paragraphs are required. A review that only describes one render is invalid.

Score: 84/100

Category Score Max
Visual Quality 26 30
Design Excellence 12 20
Spec Compliance 15 15
Data Quality 15 15
Code Quality 10 10
Library Mastery 6 10
Total 84 100

Visual Quality (26/30)

  • VQ-01: Text Legibility (7/8) — Font sizes correct (title 28px, axis 22px, ticks 18px, legend 18px); both themes readable; minor deduction for legend density
  • VQ-02: No Overlap (5/6) — No significant overlaps; legend slightly dense but readable
  • VQ-03: Element Visibility (5/6) — All series visible; SMA dotted line could be slightly more prominent against the band fill
  • VQ-04: Color Accessibility (2/2) — Okabe-Ito is CVD-safe; no red-green sole differentiator
  • VQ-05: Layout & Canvas (3/4) — 4800×2700, generous margins (T:200, B:250, L:200, R:150); nothing cut off
  • VQ-06: Axis Labels & Title (2/2) — "Date" and "Price (USD)" descriptive; title format correct
  • VQ-07: Palette Compliance (2/2) — Close price (primary series) gets #009E73; SMA #D55E00; bands #0072B2; backgrounds #FAF8F1/#1A1A17

Design Excellence (12/20)

  • DE-01: Aesthetic Sophistication (5/8) — Above default; correct Okabe-Ito palette, semi-transparent band fill, dash/dot differentiation; legend with elevated background and border; not exceptional polish
  • DE-02: Visual Refinement (3/6) — Default Highcharts plot frame visible; grid is dashed which is a nice touch; dash/dot styles distinguish series well; top/right spines not explicitly removed
  • DE-03: Data Storytelling (4/6) — Clear visual hierarchy (solid green price > dashed blue bands > dotted orange SMA); z-index ensures price is always on top; band squeeze/expansion patterns visible

Spec Compliance (15/15)

  • SC-01: Plot Type (5/5) — Correct Bollinger Bands chart (line + arearange)
  • SC-02: Required Features (4/4) — Close price line, upper band, lower band, SMA middle band, semi-transparent band fill, 20-period/2σ parameters noted
  • SC-03: Data Mapping (3/3) — X: datetime axis; Y: price (USD); 100 periods after dropna (within spec range)
  • SC-04: Title & Legend (3/3) — Title: indicator-bollinger · highcharts · anyplot.ai; legend labels all five series

Data Quality (15/15)

  • DQ-01: Feature Coverage (6/6) — Shows all aspects: price, upper/lower bands, SMA, filled envelope; arearange provides full band coverage
  • DQ-02: Realistic Context (5/5) — Synthetic stock price with GARCH-like volatility clustering; neutral financial context; np.random.seed(42)
  • DQ-03: Appropriate Scale (4/4) — Start price $150, realistic movements; 20-day window, 2σ bands; business-day date range; appropriate volatility

Code Quality (10/10)

  • CQ-01: KISS Structure (3/3) — Flat script, no functions or classes
  • CQ-02: Reproducibility (2/2) — np.random.seed(42)
  • CQ-03: Clean Imports (2/2) — All imports used (json, os, tempfile, time, urllib.request, pathlib, numpy, pandas, selenium)
  • CQ-04: Code Elegance (2/2) — No fake UI; clean data pipeline; proper arearange usage
  • CQ-05: Output & API (1/1) — Saves plot-{THEME}.png and plot-{THEME}.html

Library Mastery (6/10)

  • LM-01: Idiomatic Usage (2/5) — Implementation bypasses highcharts_core Python API entirely (no Chart(container="container"), no HighchartsOptions, no typed series classes); builds raw JS string instead. Library guide explicitly requires highcharts_core. Selenium/download pattern is correct.
  • LM-02: Distinctive Features (4/5) — arearange series type for band envelope fill; zIndex layering for correct render order; enableMouseTracking: false on background series; shared crosshair tooltip; per-series dashStyle

Score Caps Applied

  • None

Strengths

  • Perfect spec compliance — all Bollinger Band components present with correct parameters (20-period SMA, 2σ bands, fill, dashed bands, dotted SMA)
  • Correct theme-adaptive chrome throughout: all text, grid, background, legend use ANYPLOT_THEME tokens; both renders pass legibility checks
  • Good visual hierarchy via z-index + line style differentiation (solid/dash/dot) and color assignment

Weaknesses

  • Does not use highcharts_core Python API (Chart, HighchartsOptions, typed series); builds raw JS strings instead — violates library guide's idiomatic pattern
  • Default Highcharts plot frame/border not removed; top/right axis lines persist; reduces visual refinement score
  • DE-02 polish: grid uses Dash style which is slightly heavier than ideal; no explicit spine/frame removal

Issues Found

  1. LM-01 LOW: Raw JavaScript string building instead of highcharts_core Python API
    • Fix: Import from highcharts_core.chart import Chart and use Chart(container="container") with typed series classes (e.g., AreaRangeSeries from highcharts_core.options.series.area)
  2. DE-02 MEDIUM: Default plot border frame visible; grid dash style is heavier than ideal
    • Fix: Add plotBorderWidth: 0 to chart options; change grid to solid thin lines at low opacity

AI Feedback for Next Attempt

Use the highcharts_core Python API (Chart(container="container"), HighchartsOptions, typed series) as specified in the library guide. Add plotBorderWidth: 0 to remove the default frame. Switch grid from Dash to solid with low opacity for a cleaner look. These changes would push LM-01 to 4/5 and DE-02 to 4/6, bringing the total to ~90.

Verdict: APPROVED

@github-actions github-actions Bot added quality:84 Quality score 84/100 ai-approved Quality OK, ready for merge and removed quality:24 Quality score 24/100 labels May 17, 2026
@MarkusNeusinger MarkusNeusinger merged commit ad8f67e into main May 17, 2026
4 checks passed
@MarkusNeusinger MarkusNeusinger deleted the implementation/indicator-bollinger/highcharts branch May 17, 2026 12:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-approved Quality OK, ready for merge ai-attempt-1 First repair attempt ai-review-rescued Review re-dispatched once after ai-review-failed quality:84 Quality score 84/100 quality-poor Score < 50, needs fundamental fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant