Skip to content

feat(tradingbot): capital allocation optimizer - #15

Merged
wranngle merged 1 commit into
mainfrom
feat/r2-optimizer
May 19, 2026
Merged

feat(tradingbot): capital allocation optimizer#15
wranngle merged 1 commit into
mainfrom
feat/r2-optimizer

Conversation

@wranngle

Copy link
Copy Markdown
Owner

Round-2 feature #4 for tradingbot (per
campaigns/repo-magic/round-2/03-feature-plans.md §7.4).

Given N candidate strategies, recommends portfolio weights that maximize
risk-adjusted return under a historical worst-case drawdown constraint.

Proof

$ python3 -m pytest tests/test_optimizer.py -v
============================== 9 passed in 0.04s ==============================

tests/test_optimizer.py::test_weights_sum_to_one PASSED
tests/test_optimizer.py::test_highest_sharpe_gets_largest_weight PASSED
tests/test_optimizer.py::test_worst_case_fn_is_mocked_not_called_for_real_replay PASSED
tests/test_optimizer.py::test_drawdown_cap_rejects_violating_allocations PASSED
tests/test_optimizer.py::test_no_feasible_allocation_falls_back_to_equal_weight PASSED
tests/test_optimizer.py::test_single_strategy_gets_full_allocation PASSED
tests/test_optimizer.py::test_empty_strategies_raises PASSED
tests/test_optimizer.py::test_invalid_grid_step_raises PASSED
tests/test_optimizer.py::test_result_shape PASSED

Spec-mandated assertions both green:

  • Output weights sum to 1.0 (test_weights_sum_to_one).
  • Highest-Sharpe strategy receives the largest weight on a 3-strategy
    fixture (test_highest_sharpe_gets_largest_weightmean_reverter
    with Sharpe 1.6 wins over trend_follow 1.1 and momentum 0.8).

Full repo suite: 32 passed, no regressions.

Round-1 dependency

Worst-case drawdown cap is sourced from the black-swan replay harness
introduced in #5 (feat(tradingbot): black-swan replay harness for 2008 and COVID windows). The optimizer takes worst_case_fn as a callable
parameter so production wires in the real replay while tests mock the
heavy backtest path — keeping this PR test-runnable in CI without
historical market data.

Design

  • Flat module: optimizer.py at repo root (matches shouldBuy.py,
    sectorAnalysis.py, etc.).
  • Stdlib-only: simplex grid search over the N-dimensional weight space;
    no NumPy/SciPy dep added.
  • Pluggable WorstCaseFn callable so the heavy backtest is mocked in
    tests and supplied by the black-swan replay in production.
  • Equal-weight fallback when no grid point satisfies the cap — the
    optimizer never returns an unallocated portfolio.

Touches

  • optimizer.py (new, 117 LoC)
  • tests/test_optimizer.py (new, 9 tests)

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

@github-actions github-actions Bot added the pr-needs-issue PR has no Closes/Fixes/Resolves reference; auto-applied by pr-link-check label May 15, 2026
@github-actions

Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eed20d830e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread optimizer.py
Comment thread optimizer.py
Comment thread optimizer.py
Comment thread optimizer.py
@github-actions

Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@wranngle
wranngle enabled auto-merge (squash) May 19, 2026 03:04
@github-actions

Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

6 similar comments
@github-actions

Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@github-actions

Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@github-actions

Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@github-actions

Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@github-actions

Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@github-actions

Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

Adds optimizer.py — grid-search over the N-simplex of weight vectors,
maximizing portfolio Sharpe subject to a historical worst-case drawdown
constraint sourced from the black-swan replay harness (round-1 #5).

The replay callable is injected (pluggable WorstCaseFn) so tests mock
the heavy backtest while production wires in the real harness. Equal-
weight fallback when no grid point satisfies the cap, so the function
never returns an unallocated portfolio.

Proof: pytest tests/test_optimizer.py — 9 passed, including weights-
sum-to-1.0 and highest-Sharpe-gets-largest-weight contract checks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@wranngle
wranngle force-pushed the feat/r2-optimizer branch from df442ac to 9ce88a2 Compare May 19, 2026 03:50
@github-actions

Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@wranngle
wranngle merged commit db8d2cc into main May 19, 2026
12 checks passed
@wranngle
wranngle deleted the feat/r2-optimizer branch May 19, 2026 03:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-needs-issue PR has no Closes/Fixes/Resolves reference; auto-applied by pr-link-check

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant