Refactor the current sampled-report path so new sampled backtest strategies can be added without copying the full sampler, plot builder, HTML shell, and CLI plumbing each time.
The design must also make strategy parameters easy to tune from the CLI without turning the repo into a generic framework.
This spec covers the shared architecture seam first. Strategy additions listed later are intended consumers of that seam, not part of the seam itself.
This design does not:
backtest SMA path in backtest.pyThe repo now has two sampled-report strategies:
BBMR in bbmr_report.pyBBSB in bbsb_report.pyTheir strategy loops are meaningfully different, but the surrounding report shell is almost identical:
Adding each new strategy by copying one more *_report.py file will keep duplicating those same pieces.
Do not abstract the strategy loop itself.
The clean seam is outside the strategy loop:
This preserves correctness because:
BBMR has deferred next-open exitsBBSB has intrabar TP/SL exitsTrying to force those into one generic per-bar lifecycle now would be over-abstraction.
okx_codex_trader/
sampled_report.py
SampledSegment
SegmentResult
sample_segments()
trade_equity()
mark_to_market()
build_segment_plot()
render_sampled_report()
generate_sampled_report()
bbmr_report.py
BBMRConfig
run_bbmr_segment()
generate_bbmr_sampled_report() # thin wrapper
bbsb_report.py
BBSBConfig
run_bbsb_segment()
generate_bbsb_sampled_report() # thin wrapper
<future_strategy>_report.py
<Strategy>Config
run_<strategy>_segment()
generate_<strategy>_sampled_report() # thin wrapper
Create one shared sampled-report module, responsible only for the duplicated shell.
sampled_report.py ownsSampledSegmentSegmentResultsampled_report.py does not ownThe shared generator takes:
candlesleverageoutput_filesymbolbarsegmentswindow_sizereport_titlestrategy_labelstrategy_descriptionstrategy_paramsrun_segmentwarmup_barsThe shared generator must:
run_segment once per sampled windowstrategy_paramsEach strategy module exports one local run_*_segment() function.
That function takes:
candlesleveragewarmup_barsIt returns one shared SegmentResult.
This is the only required boundary between a strategy and the sampled-report shell.
Do not create a generic --strategy key=value,key=value parser.
Keep the CLI explicit and readable.
Use one sampled-report command family per strategy:
backtest-bbmr-reportbacktest-bbsb-reportbacktest-donchian-reportbacktest-rsi2-reportbacktest-ema-pullback-reportEach command keeps the existing common arguments:
--symbol--bar--history-limit--leverage--segments--window-size--output-fileEach command may add only its own strategy-specific arguments.
cli.py should stop repeating the same sampled-report parser block.
Extract one tiny helper:
_add_sampled_report_parser(...)And one handler map:
strategy_paramsThis is enough. No registry system, no plugin architecture.
Parameters must be explicit CLI flags, not hidden in code.
Rules:
Donchian might expose:
--entry-window--exit-window--stop-loss-pctRSI2 trend pullback might expose:
--trend-sma--rsi-length--rsi-long-threshold--rsi-short-threshold--exit-rsiEMA pullback reclaim might expose:
--fast-ema--slow-ema--stop-buffer-pctNo nested config syntax.
After the shared seam exists, add three more OHLCV-only strategies because they are materially different from the current sampled-report pair plus the separate SMA backtest path.
Core rule shape:
N barsN barsM-bar Donchian break or a fixed percent stopWhy add it:
Core rule shape:
close > SMA(trend_window)close < SMA(trend_window)RSI(2) drops below a low thresholdRSI(2) rises above a high thresholdWhy add it:
Core rule shape:
EMA(fast) > EMA(slow)EMA(fast) < EMA(slow)Why add it:
To minimize risk and keep each addition testable:
BBMR and BBSB onto that shell with no behavior changeDonchian strategyRSI2 trend pullback strategyEMA pullback reclaim strategyAdd tests for:
For BBMR and BBSB:
Each new strategy must have:
This design is complete when: