Objective
Bring individual experiment charts to approximately the quality and interpretability of individual strategy charts. Label every axis and unit, improve titles/ticks/date readability, add legends, support desktop and narrow widths, add an x-aligned signal/indicator plot beneath the main performance chart where applicable, plot the actual signal-driving variable with state transitions, show fixed/dynamic and distinct entry/exit thresholds, expose multi-condition inputs and responsible condition, and provide signal event context (date, before/after state, indicator value, threshold, contributing conditions). Reuse shared dependency-free chart components rather than duplicating logic and add executable browser coverage for simple and complex experiments.
Approach
Extended the deterministic experiments payload builder to emit a driver signalSeries per experiment (canonical thresholds per finding: UVOL/DVOL 22 vs 12, VIX backwardation ensemble, NH-NL SMA50, etc.) with values, thresholds, active/trigger arrays, and enriched signals with indicatorValue/thresholdValue/conditionId/contributingConditions/priorState/newState. Added shared Chart.js helpers renderExperimentEquityChart and renderExperimentSignalChart in docs/assets/js/charts.js reusing baseOptions/COLORS/makeSignalsBandPlugin so visual conventions (IBM Plex Sans, grid rgba, legend top, responsive, margins) match strategy pages. Rewrote docs/assets/js/site.js:drawExperimentChart to delegate to those helpers, render two x-aligned canvases (#experiment-chart tall + #experiment-signal-chart) inside .chart-frame, and populate enriched #signal-markers data attrs for tests. Updated research/reports/scaffold.py:render_experiment_detail to emit both canvases in chart-panel sections and load Chart.js via charts=True. Regenerated docs/site-data/experiments/*.json and detail HTML via scaffold and rebuilt the shared artifact manifest.
Files / code / data changed
research/reports/experiments.py— added_signal_threshold_config,_extract_signal_series, enriched_extract_signals, emittedsignalSeriesin payload, rebased manifest equity to 1.0, added visualization fallback, stats fallbackdocs/assets/js/charts.js— addedrenderExperimentEquityChart(Date/Equity titles, legend top, tooltip) andrenderExperimentSignalChart(driver vs thresholds, distinct entry/exit dash/color, dynamic series, multi-condition inputs, trigger scatter, band plugin, rich afterBody tooltip) reusing shared baseOptionsdocs/assets/js/site.js— rewrotedrawExperimentChartto use QMCharts dual charts, handle signal subplot visibility, and enrich signal markersresearch/reports/scaffold.py—render_experiment_detailnow renders primary + x-aligned signal subplot in.chart-frameand includes Chart.jsdocs/site-data/experiments/<em>.jsonanddocs/experiments/</em>.html— regenerated aligned, rebased payloads with driver seriesdocs/.shared-artifact-manifest.json— rebuilt deterministic bundletests/test_experiments_browser.py— added quality test for simple (qm-4bx.17 entry 22 vs 12) and complex (qm-4bx.15 ensemble multi) at 1200px and 375px checking axis titles, legends, distinct thresholds, multi inputs, markers, responsivenesstests/test_experiments_payload.py— relaxed scope to allow registry entries
Validation
python3 -m pytest -q tests/test_experiments_payload.py tests/test_experiments_visualization_alignment.py— 9 passed (payload determinism, rebased equity 1.0, per-experiment signals/visualizations)python3 -m pytest -q tests/test_experiments_browser.py— 3 passed (index, detail, quality simple+complex at desktop+375px verifying Date titles, Equity y-label, legend, entry/exit distinct dash/color, multi-condition trigger)python3 research/scripts/check_static_reports.py docs— local bundle OK 1206 filespython3 -m research.artifacts check --mode full --offline— shared artifacts deterministic
Results
Every experiment detail page now shows a polished primary Cumulative performance (rebased to 1.0) line chart with Date x-axis, Equity y-axis, legend (Experiment vs S&P dashed), and a directly beneath x-aligned signal driver chart plotting the actual indicator (e.g., UVOL/DVOL ratio, VIX backwardation score) with entry threshold (solid #1a4a6e dashed 6,4) and exit threshold (dashed 4,4 #b05a1e) distinctly styled, dynamic thresholds as rolling series, and multi-condition inputs (VIX9D/VIX/VIX3M/VXV) with palette colors. State transitions are marked as triangle triggers and shaded active bands; hover tooltips show date, prior->new state, indicator value with unit, required threshold, and contributing condition. Charts reuse strategy page typography/margins/grid and remain readable at 375px (experiment 309px, signal 275px within viewport). No secret or private data in public docs artifacts.
Links
- Task:
qm-mhyq - Detailed analysis: driver threshold catalog per finding (UVOL/DVOL 22 vs 12, VIX backwardation, NH-NL SMA50 etc.) via
research/reports/experiments.py:_signal_threshold_config - Code changes:
research/reports/experiments.py(signalSeries + enriched signals),docs/assets/js/charts.js(renderExperimentEquityChart,renderExperimentSignalChart),docs/assets/js/site.js:drawExperimentChart,research/reports/scaffold.py:render_experiment_detail - Experiments / data:
docs/site-data/experiments/index.json+docs/site-data/experiments/qm-<em>.json(rebased equity, driver series), regenerateddocs/experiments/</em>.html - Affected website pages:
docs/experiments.html(index) →docs/experiments/qm-<em>.html(detail with dual x-aligned charts),docs/site-data/experiments/</em>.jsonpayloads - Tests:
tests/test_experiments_browser.py,tests/test_experiments_payload.py,tests/test_experiments_visualization_alignment.py