From db3cce268ae3da6ba7ff19769d55e0c5b716c9d7 Mon Sep 17 00:00:00 2001 From: Stefan Jansen Date: Fri, 12 Jun 2026 12:43:14 -0400 Subject: [PATCH] feat: add broker equity accessor --- docs/api/index.md | 1 + docs/user-guide/stateful-strategies.md | 3 ++- src/ml4t/backtest/broker.py | 6 +++++- tests/test_broker.py | 15 +++++++++++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/api/index.md b/docs/api/index.md index 48e8143..51ca30b 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -58,6 +58,7 @@ Auto-generated from source docstrings. - get_position - get_positions - get_cash + - equity - get_account_value - get_rejected_orders - set_position_rules diff --git a/docs/user-guide/stateful-strategies.md b/docs/user-guide/stateful-strategies.md index f20e356..7cd80fa 100644 --- a/docs/user-guide/stateful-strategies.md +++ b/docs/user-guide/stateful-strategies.md @@ -366,7 +366,8 @@ Stateful strategies depend on querying execution state. Key broker methods: |--------|---------|---------| | `get_position(asset)` | Position or None | All patterns | | `get_positions()` | Dict of all positions | Multi-asset | -| `get_account_value()` | Total portfolio value | Sizing | +| `equity()` | Current marked account equity | Sizing | +| `get_account_value()` | Same value as `equity()` | Existing code | | `get_cash()` | Available cash | Capital allocation | | `get_asset_stats(asset)` | Trade statistics | Kelly sizing | | `get_order(order_id)` | Order status | Grid trading | diff --git a/src/ml4t/backtest/broker.py b/src/ml4t/backtest/broker.py index 81bb8c7..aea4e0b 100644 --- a/src/ml4t/backtest/broker.py +++ b/src/ml4t/backtest/broker.py @@ -736,9 +736,13 @@ def get_cash(self) -> float: """ return self.cash + def equity(self) -> float: + """Calculate current marked account equity.""" + return self._portfolio_ledger.get_account_value() + def get_account_value(self) -> float: """Calculate total account value (cash + position values).""" - return self._portfolio_ledger.get_account_value() + return self.equity() def get_rejected_orders(self, asset: str | None = None) -> list[Order]: """Get all rejected orders, optionally filtered by asset. diff --git a/tests/test_broker.py b/tests/test_broker.py index 5a92adc..40f4594 100644 --- a/tests/test_broker.py +++ b/tests/test_broker.py @@ -55,6 +55,21 @@ def test_get_account_value(self, broker): value = broker.get_account_value() assert value == 100000.0 + def test_equity_uses_current_mark_prices(self, broker_with_position): + """Test equity returns cash plus current marked position value.""" + broker_with_position._update_time( + datetime(2024, 1, 2, 9, 30), + {"AAPL": 155.0}, + {"AAPL": 154.0}, + {"AAPL": 156.0}, + {"AAPL": 153.0}, + {"AAPL": 1000.0}, + {}, + ) + + assert broker_with_position.equity() == 115500.0 + assert broker_with_position.get_account_value() == broker_with_position.equity() + def test_get_position_none(self, broker): """Test get_position returns None for no position.""" assert broker.get_position("AAPL") is None