# BBMR Sampled Report Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Add a `backtest-bbmr-report` command that samples multiple non-overlapping historical windows, runs a fixed Bollinger Band mean-reversion strategy on each window, and outputs one single-page HTML report with client-side segment switching. **Architecture:** Extend the current report pipeline instead of replacing it. Add a dedicated BBMR sampler/runner module that fetches one public candle pool, derives deterministic sampled windows with warm-up context, runs one backtest per sampled window, and feeds a single wrapper HTML that switches per-segment journals and plots client-side. **Tech Stack:** Python 3.11+, `backtesting.py`, `pandas`, existing OKX public candle client, existing CLI test harness, plain HTML/CSS/JS --- ## File Structure - Modify: `/home/lxy/okx-codex-trader/okx_codex_trader/cli.py` - add `backtest-bbmr-report` CLI command and dispatch - Create: `/home/lxy/okx-codex-trader/okx_codex_trader/bbmr_report.py` - deterministic non-overlapping sampler - local dataclasses for sampled segment definitions/results - BBMR strategy runner - aggregate and per-segment result shaping - Modify: `/home/lxy/okx-codex-trader/okx_codex_trader/report.py` - add single-page sampled report HTML renderer - Modify: `/home/lxy/okx-codex-trader/tests/test_cli.py` - CLI contract for new command - Create: `/home/lxy/okx-codex-trader/tests/test_bbmr_report.py` - sampler, strategy, and single-page HTML tests - Modify: `/home/lxy/okx-codex-trader/README.md` - add new command example after implementation is stable ### Task 1: CLI Contract For `backtest-bbmr-report` **Files:** - Modify: `/home/lxy/okx-codex-trader/tests/test_cli.py` - Modify: `/home/lxy/okx-codex-trader/okx_codex_trader/cli.py` - [ ] **Step 1: Write the failing CLI test** ```python def test_backtest_bbmr_report_generates_single_page_report(capsys, tmp_path): main, client, bbmr_calls = build_main_with_stubs() output_file = tmp_path / "bbmr.html" exit_code = main( [ "backtest-bbmr-report", "--symbol", "BTC-USDT-SWAP", "--bar", "3m", "--history-limit", "5000", "--leverage", "2", "--segments", "8", "--window-size", "300", "--output-file", str(output_file), ] ) assert exit_code == 0 assert client.get_candles_called_with == ("BTC-USDT-SWAP", "3m", 5000) assert bbmr_calls[0]["segments"] == 8 assert bbmr_calls[0]["window_size"] == 300 ``` - [ ] **Step 2: Run test to verify it fails** Run: `cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_cli.py -k bbmr -q` Expected: FAIL because `backtest-bbmr-report` is not implemented - [ ] **Step 3: Write minimal CLI implementation** ```python bbmr_report = subparsers.add_parser("backtest-bbmr-report") bbmr_report.add_argument("--symbol", choices=SUPPORTED_SYMBOLS, required=True) bbmr_report.add_argument("--bar", required=True) bbmr_report.add_argument("--history-limit", type=int, required=True) bbmr_report.add_argument("--leverage", type=int, choices=(1, 2, 3), required=True) bbmr_report.add_argument("--segments", type=int, required=True) bbmr_report.add_argument("--window-size", type=int, required=True) bbmr_report.add_argument("--output-file", required=True) ``` ```python if args.command == "backtest-bbmr-report": candles = client.get_candles(args.symbol, args.bar, args.history_limit) report = bbmr_report_fn( candles=candles, leverage=args.leverage, output_file=Path(args.output_file), symbol=args.symbol, bar=args.bar, segments=args.segments, window_size=args.window_size, ) print(_dump_json(report)) return 0 ``` ```python def main_factory( *, ..., report_fn: Callable = generate_backtest_report, bbmr_report_fn: Callable = generate_bbmr_sampled_report, ): ... ``` ```python def build_main_with_stubs(...): ... def fake_bbmr_report(...): ... main = main_factory(..., bbmr_report_fn=fake_bbmr_report) ``` - [ ] **Step 4: Run test to verify it passes** Run: `cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_cli.py -k bbmr -q` Expected: PASS - [ ] **Step 5: Commit** ```bash git -C /home/lxy/okx-codex-trader add okx_codex_trader/cli.py tests/test_cli.py git -C /home/lxy/okx-codex-trader commit -m "feat: add bbmr report cli contract" ``` ### Task 2: Deterministic Sampler Contract **Files:** - Create: `/home/lxy/okx-codex-trader/tests/test_bbmr_report.py` - Create: `/home/lxy/okx-codex-trader/okx_codex_trader/bbmr_report.py` - [ ] **Step 1: Write the failing sampler tests** ```python def test_sample_segments_rejects_history_pool_too_small(): candles = build_candles(count=1000) with pytest.raises(ValueError, match="history pool is too small"): sample_segments(candles=candles, segments=8, window_size=300, warmup_bars=69, seed=7) def test_sample_segments_returns_non_overlapping_ranges(): candles = build_candles(count=5000) sampled = sample_segments(candles=candles, segments=4, window_size=300, warmup_bars=69, seed=7) ranges = [(segment.context_start, segment.report_end) for segment in sampled] assert len(ranges) == len(set(ranges)) for left, right in zip(ranges, ranges[1:]): assert left[1] < right[0] or right[1] < left[0] def test_sample_segments_is_deterministic_for_same_seed(): candles = build_candles(count=5000) a = sample_segments(candles=candles, segments=4, window_size=300, warmup_bars=69, seed=7) b = sample_segments(candles=candles, segments=4, window_size=300, warmup_bars=69, seed=7) assert a == b def test_generate_bbmr_sampled_report_rejects_insufficient_history_pool(tmp_path): candles = build_candles(count=1000) with pytest.raises(ValueError, match="history pool is too small"): generate_bbmr_sampled_report( candles=candles, leverage=2, output_file=tmp_path / "bbmr.html", symbol="BTC-USDT-SWAP", bar="3m", segments=8, window_size=300, ) ``` - [ ] **Step 2: Run tests to verify they fail** Run: `cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbmr_report.py -k sample_segments -q` Expected: FAIL because sampler functions do not exist - [ ] **Step 3: Write minimal deterministic sampler** ```python WARMUP_BARS = 69 SAMPLER_SEED = 7 ``` ```python def sample_segments(...): required = segments * (window_size + warmup_bars) if len(candles) < required: raise ValueError("history pool is too small") ... ``` - [ ] **Step 4: Run tests to verify they pass** Run: `cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbmr_report.py -k sample_segments -q` Expected: PASS - [ ] **Step 5: Commit** ```bash git -C /home/lxy/okx-codex-trader add okx_codex_trader/bbmr_report.py tests/test_bbmr_report.py git -C /home/lxy/okx-codex-trader commit -m "feat: add deterministic bbmr segment sampler" ``` ### Task 3: BBMR Strategy Rules **Files:** - Modify: `/home/lxy/okx-codex-trader/tests/test_bbmr_report.py` - Modify: `/home/lxy/okx-codex-trader/okx_codex_trader/bbmr_report.py` - [ ] **Step 1: Write the failing strategy tests** ```python def test_run_bbmr_segment_produces_long_trade_on_lower_band_reversion(): candles = build_lower_band_reversion_fixture() result = run_bbmr_segment(candles=candles, leverage=2) assert result.trade_count == 1 assert result.trades[0]["side"] == "Long" def test_run_bbmr_segment_produces_short_trade_on_upper_band_reversion(): candles = build_upper_band_reversion_fixture() result = run_bbmr_segment(candles=candles, leverage=2) assert result.trade_count == 1 assert result.trades[0]["side"] == "Short" def test_run_bbmr_segment_marks_open_position_to_market_but_keeps_journal_realized_only(): candles = build_open_tail_fixture() result = run_bbmr_segment(candles=candles, leverage=2) assert result.trade_count == 0 assert result.trades == [] assert result.total_return != 0 ``` - [ ] **Step 2: Run tests to verify they fail** Run: `cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbmr_report.py -k run_bbmr_segment -q` Expected: FAIL because BBMR runner does not exist - [ ] **Step 3: Write minimal BBMR segment runner** Implement fixed rules from the spec and lock them with explicit tests: - Bollinger `20/2` - bandwidth `(upper-lower)/middle` - filter against previous `50` completed bandwidth values - stop-loss intrabar at stop price - same-bar sequencing: stop first, then close-based exit, then entry only if flat and no exit occurred - final reported candle cannot generate next-open entry or mean-reversion exit - ending return and drawdown use final-close mark-to-market if trade remains open Add failing tests for: ```python def test_run_bbmr_segment_excludes_warmup_from_reported_trade_times(): ... def test_run_bbmr_segment_does_not_generate_entry_from_final_reported_candle(): ... def test_run_bbmr_segment_stop_loss_takes_precedence_over_close_exit(): ... def test_run_bbmr_segment_does_not_reverse_on_exit_bar(): ... ``` - [ ] **Step 4: Run tests to verify they pass** Run: `cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbmr_report.py -k run_bbmr_segment -q` Expected: PASS - [ ] **Step 5: Commit** ```bash git -C /home/lxy/okx-codex-trader add okx_codex_trader/bbmr_report.py tests/test_bbmr_report.py git -C /home/lxy/okx-codex-trader commit -m "feat: add bbmr segment backtest rules" ``` ### Task 4: Single-Page HTML Wrapper **Files:** - Modify: `/home/lxy/okx-codex-trader/tests/test_bbmr_report.py` - Modify: `/home/lxy/okx-codex-trader/okx_codex_trader/report.py` - Modify: `/home/lxy/okx-codex-trader/okx_codex_trader/bbmr_report.py` - [ ] **Step 1: Write the failing HTML wrapper tests** ```python def test_render_bbmr_sampled_report_contains_summary_and_segment_switcher(): html = render_bbmr_sampled_report(...) assert "history limit" in html.lower() assert "segment count" in html.lower() assert "window size" in html.lower() assert "average return across segments" in html.lower() assert "median return across segments" in html.lower() assert "best segment return" in html.lower() assert "worst segment return" in html.lower() assert "segment-selector" in html assert "data-segment-index=\"0\"" in html def test_render_bbmr_sampled_report_contains_trade_journal_and_plot_reference(): html = render_bbmr_sampled_report(...) assert "Trade Journal" in html assert "/files/segment-0.plot.html" in html assert "sampled range start time" in html.lower() assert "sampled range end time" in html.lower() assert "trade count" in html.lower() assert "total return" in html.lower() assert "win rate" in html.lower() assert "max drawdown" in html.lower() ``` - [ ] **Step 2: Run tests to verify they fail** Run: `cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbmr_report.py -k render_bbmr -q` Expected: FAIL because sampled report wrapper does not exist - [ ] **Step 3: Write minimal single-page wrapper** Render: - top-level aggregate metrics - strategy description - sampled ranges table/list - segment buttons/select element - one active segment panel at a time - client-side JS to switch visible panel and iframe - [ ] **Step 4: Run tests to verify they pass** Run: `cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbmr_report.py -k render_bbmr -q` Expected: PASS - [ ] **Step 5: Commit** ```bash git -C /home/lxy/okx-codex-trader add okx_codex_trader/report.py okx_codex_trader/bbmr_report.py tests/test_bbmr_report.py git -C /home/lxy/okx-codex-trader commit -m "feat: add bbmr sampled single-page html report" ``` ### Task 5: End-To-End Report Generation **Files:** - Modify: `/home/lxy/okx-codex-trader/tests/test_cli.py` - Modify: `/home/lxy/okx-codex-trader/tests/test_bbmr_report.py` - Modify: `/home/lxy/okx-codex-trader/okx_codex_trader/bbmr_report.py` - Modify: `/home/lxy/okx-codex-trader/README.md` - [ ] **Step 1: Write the failing end-to-end generator test** ```python def test_generate_bbmr_sampled_report_writes_wrapper_and_plot_files(tmp_path): candles = build_candles(count=5000) result = generate_bbmr_sampled_report( candles=candles, leverage=2, output_file=tmp_path / "bbmr.html", symbol="BTC-USDT-SWAP", bar="3m", segments=3, window_size=300, ) assert Path(result["report_file"]).exists() assert result["segment_count"] == 3 assert (tmp_path / "bbmr.segment-0.plot.html").exists() ``` - [ ] **Step 2: Run tests to verify they fail** Run: `cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbmr_report.py -k generate_bbmr -q` Expected: FAIL because the assembled generator does not exist - [ ] **Step 3: Write minimal generator and docs** Implement: - one wrapper HTML file - one plot file per segment - aggregate summary JSON return to CLI - README command example - [ ] **Step 4: Run focused tests to verify they pass** Run: `cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_cli.py tests/test_bbmr_report.py -q` Expected: PASS - [ ] **Step 5: Commit** ```bash git -C /home/lxy/okx-codex-trader add README.md okx_codex_trader/bbmr_report.py okx_codex_trader/report.py tests/test_bbmr_report.py tests/test_cli.py git -C /home/lxy/okx-codex-trader commit -m "feat: add sampled bbmr backtest report" ``` ### Task 6: Full Verification And Real Report **Files:** - Verify only: `/home/lxy/okx-codex-trader` - [ ] **Step 1: Run full automated tests** Run: `cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest -q` Expected: PASS - [ ] **Step 2: Generate a real sampled report** Run: ```bash cd /home/lxy/okx-codex-trader .venv/bin/python -m okx_codex_trader.cli backtest-bbmr-report \ --symbol BTC-USDT-SWAP \ --bar 3m \ --history-limit 5000 \ --leverage 2 \ --segments 8 \ --window-size 300 \ --output-file bbmr-sampled-report.html ``` Expected: one wrapper HTML plus segment plot files written next to it - [ ] **Step 3: Commit** ```bash git -C /home/lxy/okx-codex-trader add README.md okx_codex_trader/cli.py okx_codex_trader/bbmr_report.py okx_codex_trader/report.py tests/test_bbmr_report.py tests/test_cli.py git -C /home/lxy/okx-codex-trader commit -m "feat: ship sampled bbmr report flow" ```