2026-04-17-bbsb-sampled-report.md 15 KB

BBSB 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-bbsb-report command that samples multiple non-overlapping historical windows, runs a fixed Bollinger Band squeeze-breakout strategy on each window, and outputs one single-page HTML report with client-side segment switching.

Architecture: Keep the existing report paths intact. Add one parallel bbsb_report.py module that follows the same public-candle pool and deterministic block-sampler shape as bbmr_report.py, but swaps in breakout entry rules plus fixed intrabar TP/SL exits. The CLI gets one new command and the HTML shell stays journal-first.

Tech Stack: Python 3.11+, pandas, bokeh, 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-bbsb-report CLI command and dispatch
  • Create: /home/lxy/okx-codex-trader/okx_codex_trader/bbsb_report.py
    • deterministic sampler
    • local dataclasses for sampled segment definitions/results
    • BBSB strategy runner
    • aggregate and per-segment result shaping
  • Modify: /home/lxy/okx-codex-trader/tests/test_cli.py
    • CLI contract for new command
  • Create: /home/lxy/okx-codex-trader/tests/test_bbsb_report.py
    • sampler, strategy, generator, 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-bbsb-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

def test_backtest_bbsb_report_generates_single_page_report(capsys, tmp_path):
    main, client, _, _, bbsb_calls = build_main_with_stubs()
    output_file = tmp_path / "bbsb.html"

    exit_code = main(
        [
            "backtest-bbsb-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 bbsb_calls[0]["segments"] == 8
    assert bbsb_calls[0]["window_size"] == 300
    parser = build_parser()
    assert tuple(parser._option_string_actions["--symbol"].choices) == ("BTC-USDT-SWAP", "ETH-USDT-SWAP")
  • 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 bbsb -q Expected: FAIL because backtest-bbsb-report is not implemented

  • Step 3: Write minimal CLI implementation
bbsb_report = subparsers.add_parser("backtest-bbsb-report")
bbsb_report.add_argument("--symbol", choices=("BTC-USDT-SWAP", "ETH-USDT-SWAP"), required=True)
bbsb_report.add_argument("--bar", required=True)
bbsb_report.add_argument("--history-limit", type=int, required=True)
bbsb_report.add_argument("--leverage", type=int, choices=(1, 2, 3), required=True)
bbsb_report.add_argument("--segments", type=int, required=True)
bbsb_report.add_argument("--window-size", type=int, required=True)
bbsb_report.add_argument("--output-file", required=True)
if args.command == "backtest-bbsb-report":
    candles = client.get_candles(args.symbol, args.bar, args.history_limit)
    report = bbsb_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
  • 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 bbsb -q Expected: PASS

Task 2: Deterministic Sampler Contract

Files:

  • Create: /home/lxy/okx-codex-trader/tests/test_bbsb_report.py
  • Create: /home/lxy/okx-codex-trader/okx_codex_trader/bbsb_report.py

  • [ ] Step 1: Write the failing sampler tests

def test_sample_segments_rejects_history_pool_too_small():
    candles = build_linear_candles(1_000)

    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_linear_candles(5_000)

    sampled = sample_segments(candles=candles, segments=4, window_size=300, warmup_bars=69, seed=7)

    for left_index, left in enumerate(sampled):
        for right in sampled[left_index + 1 :]:
            assert left.report_end <= right.context_start or right.report_end <= left.context_start


def test_sample_segments_is_deterministic_for_same_seed():
    candles = build_linear_candles(5_000)

    first = sample_segments(candles=candles, segments=4, window_size=300, warmup_bars=69, seed=7)
    second = sample_segments(candles=candles, segments=4, window_size=300, warmup_bars=69, seed=7)

    assert first == second


def test_sample_segments_uses_exact_block_candidates_and_drops_partial_tail():
    candles = build_linear_candles(1_300)

    sampled = sample_segments(candles=candles, segments=3, window_size=300, warmup_bars=69, seed=7)

    assert [segment.context_start for segment in sampled] == sorted(segment.context_start for segment in sampled)
    assert all(segment.context_start % (300 + 69) == 0 for segment in sampled)
    assert all(segment.report_end <= 1_300 for segment in sampled)


def test_generate_bbsb_sampled_report_rejects_invalid_sampling_result(tmp_path, monkeypatch):
    monkeypatch.setattr("okx_codex_trader.bbsb_report.sample_segments", lambda **_: [])

    with pytest.raises(ValueError, match="invalid sampling result"):
        generate_bbsb_sampled_report(
            candles=build_linear_candles(5_000),
            leverage=2,
            output_file=tmp_path / "bbsb.html",
            symbol="BTC-USDT-SWAP",
            bar="3m",
            segments=2,
            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_bbsb_report.py -k "sample_segments or invalid_sampling" -q Expected: FAIL because sampler functions do not exist

  • Step 3: Write minimal deterministic sampler
WARMUP_BARS = 69
SAMPLER_SEED = 7
def sample_segments(...):
    block_size = window_size + warmup_bars
    if len(candles) < segments * block_size:
        raise ValueError("history pool is too small")
    context_starts = list(range(0, len(candles) - block_size + 1, block_size))
    ...
  • Step 4: Run tests to verify they pass

Run: cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbsb_report.py -k "sample_segments or invalid_sampling" -q Expected: PASS

Task 3: BBSB Strategy Rules

Files:

  • Modify: /home/lxy/okx-codex-trader/tests/test_bbsb_report.py
  • Modify: /home/lxy/okx-codex-trader/okx_codex_trader/bbsb_report.py

  • [ ] Step 1: Write the failing strategy tests

def test_run_bbsb_segment_produces_long_breakout_trade():
    result = run_bbsb_segment(candles=build_long_breakout_fixture(), leverage=2, warmup_bars=69)

    assert result.trade_count == 1
    assert result.trades[0]["side"] == "Long"


def test_run_bbsb_segment_produces_short_breakout_trade():
    result = run_bbsb_segment(candles=build_short_breakout_fixture(), leverage=2, warmup_bars=69)

    assert result.trade_count == 1
    assert result.trades[0]["side"] == "Short"


def test_run_bbsb_segment_stop_loss_takes_precedence_over_take_profit():
    result = run_bbsb_segment(candles=build_ambiguous_exit_fixture(), leverage=2, warmup_bars=69)

    assert result.trades[0]["exit_price"] == pytest.approx(expected_stop_price)


def test_run_bbsb_segment_does_not_generate_entry_from_final_reported_candle():
    result = run_bbsb_segment(candles=build_final_bar_breakout_fixture(), leverage=2, warmup_bars=69)

    assert result.trade_count == 0


def test_run_bbsb_segment_marks_open_position_to_market_but_keeps_journal_realized_only():
    result = run_bbsb_segment(candles=build_open_tail_fixture(), leverage=2, warmup_bars=69)

    assert result.trade_count == 0
    assert result.trades == []
    assert result.total_return != 0
    assert result.open_position is not None


def test_run_bbsb_segment_uses_population_std_and_previous_50_completed_bandwidths_only():
    result = run_bbsb_segment(candles=build_indicator_contract_fixture(), leverage=2, warmup_bars=69)

    assert result.trade_count == 1
    assert result.trades[0]["entry_time"] == "expected timestamp from the first bar that only passes with ddof=0 and previous-50 median"


def test_run_bbsb_segment_does_not_allow_tp_or_sl_on_entry_candle():
    result = run_bbsb_segment(candles=build_entry_bar_tp_sl_fixture(), leverage=2, warmup_bars=69)

    assert result.trade_count == 0
    assert result.open_position is not None


def test_run_bbsb_segment_exit_exhausts_bar_without_same_bar_reentry():
    result = run_bbsb_segment(candles=build_same_bar_reentry_fixture(), leverage=2, warmup_bars=69)

    assert result.trade_count == 1
    assert len(result.entries) == 1
  • Step 2: Run tests to verify they fail

Run: cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbsb_report.py -k run_bbsb_segment -q Expected: FAIL because BBSB runner does not exist

  • Step 3: Write minimal BBSB segment runner
def run_bbsb_segment(...):
    ...
    if position is not None and index > int(position["entry_index"]):
        if stop_hit:
            ...
            continue
        if take_profit_hit:
            ...
            continue
    ...
  • Step 4: Run tests to verify they pass

Run: cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbsb_report.py -k run_bbsb_segment -q Expected: PASS

Task 4: Generator And Single-Page HTML Report

Files:

  • Modify: /home/lxy/okx-codex-trader/tests/test_bbsb_report.py
  • Modify: /home/lxy/okx-codex-trader/okx_codex_trader/bbsb_report.py

  • [ ] Step 1: Write the failing generator and HTML tests

def test_generate_bbsb_sampled_report_rejects_insufficient_history_pool(tmp_path):
    candles = build_linear_candles(1_000)

    with pytest.raises(ValueError, match="history pool is too small"):
        generate_bbsb_sampled_report(
            candles=candles,
            leverage=2,
            output_file=tmp_path / "bbsb.html",
            symbol="BTC-USDT-SWAP",
            bar="3m",
            segments=8,
            window_size=300,
        )


def test_render_bbsb_sampled_report_contains_summary_and_segment_switcher():
    html = render_bbsb_sampled_report(...)

    assert "BBSB sampled report" in html
    assert "Average Return Across Segments" in html
    assert "Median Return Across Segments" in html
    assert "Best Segment Return" in html
    assert "Worst Segment Return" in html
    assert "segment-selector" in html


def test_render_bbsb_sampled_report_contains_trade_journal_and_plot_payload():
    html = render_bbsb_sampled_report(...)

    assert "Trade Journal" in html
    assert "Sampled Range Start Time" in html
    assert "plot0" in html


def test_generate_bbsb_sampled_report_hides_warmup_labels_and_reports_ranges(tmp_path):
    report = generate_bbsb_sampled_report(...)

    assert report["segment_count"] == 2
    html = Path(report["report_file"]).read_text()
    assert "expected reported start time" in html
    assert "expected reported end time" in html
    assert "warmup timestamp" not in html


def test_render_bbsb_sampled_report_embeds_exact_metric_values():
    html = render_bbsb_sampled_report(
        ...,
        aggregate_summary={
            "aggregate_trade_count": 12,
            "average_return": 0.125,
            "median_return": 0.05,
            "best_segment_return": 0.3,
            "worst_segment_return": -0.2,
        },
        segment_results=[
            {
                "index": 0,
                "start_time": "2026-04-01 00:00",
                "end_time": "2026-04-01 15:00",
                "trade_count": 3,
                "total_return": 0.1,
                "win_rate": 0.6667,
                "max_drawdown": 0.05,
                "trades": [...],
                "plot_div": "<div>plot0</div>",
            }
        ],
        ...,
    )

    assert "0.125" in html
    assert "0.05" in html
    assert "0.3" in html
    assert "-0.2" in html
    assert "0.6667" in html
  • Step 2: Run tests to verify they fail

Run: cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbsb_report.py -k "generate_bbsb or render_bbsb" -q Expected: FAIL because generator and renderer do not exist

  • Step 3: Write minimal renderer and generator
def render_bbsb_sampled_report(...):
    return f"""<!DOCTYPE html>..."""
def generate_bbsb_sampled_report(...):
    sampled = sample_segments(...)
    ...
    return {
        "report_file": str(output_file),
        "segment_count": segments,
        "window_size": window_size,
        "aggregate_trade_count": aggregate_trade_count,
        "average_return": round(average_return, 6),
    }
  • Step 4: Run tests to verify they pass

Run: cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbsb_report.py -q Expected: PASS

Task 5: Docs And End-To-End Verification

Files:

  • Modify: /home/lxy/okx-codex-trader/README.md

  • [ ] Step 1: Write the failing README expectation test only if one already exists

No new README-only test is needed because this repo does not enforce README snapshots.

  • Step 2: Update README with the new command
python -m okx_codex_trader.cli backtest-bbsb-report --symbol BTC-USDT-SWAP --bar 3m --history-limit 5000 --leverage 2 --segments 8 --window-size 300 --output-file bbsb-sampled-report.html
  • Step 3: Run the focused and full verification

Run:

cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_cli.py -k bbsb -q
cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest tests/test_bbsb_report.py -q
cd /home/lxy/okx-codex-trader && .venv/bin/python -m pytest -q

Expected:

  • new BBSB tests pass
  • full suite stays green

  • [ ] Step 4: Generate one real report

Run:

cd /home/lxy/okx-codex-trader && .venv/bin/python -m okx_codex_trader.cli backtest-bbsb-report --symbol BTC-USDT-SWAP --bar 3m --history-limit 5000 --leverage 2 --segments 8 --window-size 300 --output-file bbsb-sampled-report.html

Expected:

  • command exits 0
  • bbsb-sampled-report.html exists
  • JSON summary prints report_file, segment_count, window_size, aggregate_trade_count, average_return