Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions executor/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1490,6 +1490,18 @@ def _conviction_rank(ticker_pos):
predictions_date=predictions_date,
)
n_entered = len(opt_entries)
if not opt_entries and not opt_exits:
_diag = (shadow_log or {}).get("diagnostics") or {}
logger.info(
"Optimizer solved %r with no rebalance trades "
"(turnover_one_way=%s below the trade threshold) — "
"the current portfolio already matches target. Order "
"book intentionally carries no optimizer entries/"
"exits today; existing positions are retained with "
"stops. This is a valid HOLD, not a fault.",
_diag.get("status"),
_diag.get("turnover_one_way"),
)
else:
logger.error(
"use_portfolio_optimizer=True but optimizer log is not "
Expand Down
14 changes: 12 additions & 2 deletions executor/optimizer_cutover.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ def is_log_usable(log: dict | None) -> bool:
Conservative gate: refuses anything but a clean ``optimal`` /
``optimal_inaccurate`` solve. Callers fall back to an empty order
book on False (safer than wrong trades).

An ``optimal``/``ok`` solve with an EMPTY ``would_be_trades`` is
*usable* — it is the optimizer's legitimate verdict that the current
portfolio already matches the target within the turnover threshold
("hold" day). It is NOT a failure. Conflating it with a genuine
failure (None / non-ok / non-optimal diag) was a real bug: the
2026-05-19 weekday rerun solved ``optimal`` with turnover 0.17%
(would_be_trades=[]) yet the planner logged a false
``optimizer log is not usable … Operator must investigate`` ERROR
and framed a correct hold as a safety fallback. Emptiness is now the
caller's concern (apply → a safe no-op; log INFO, not ERROR), not a
usability signal.
"""
if not log:
return False
Expand All @@ -49,8 +61,6 @@ def is_log_usable(log: dict | None) -> bool:
diag = log.get("diagnostics") or {}
if diag.get("status") not in _OK_DIAG_STATUSES:
return False
if not log.get("would_be_trades"):
return False
return True


Expand Down
49 changes: 44 additions & 5 deletions tests/test_optimizer_cutover.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
Unit tests for executor/optimizer_cutover.py — PR 5 of portfolio-optimizer arc.

Covers:
- is_log_usable: happy + every failure mode (no log, sentinel, infeasible,
empty would_be_trades)
- is_log_usable: happy + every failure mode (no log, sentinel, infeasible).
An optimal/ok solve with EMPTY would_be_trades is a valid HOLD, not a
failure — it is usable (apply → safe no-op). Regression lock for the
2026-05-19 conflation bug.
- apply_optimizer_targets_to_orderbook:
* BUY → entry record with optimizer-derived shares / dollars / triggers
* SELL @ target=0 → urgent_exit EXIT for full held shares
Expand Down Expand Up @@ -67,13 +69,50 @@ def test_is_log_usable_infeasible_diag():
assert is_log_usable(log) is False


def test_is_log_usable_empty_trades():
def test_is_log_usable_optimal_with_no_trades_is_usable():
"""2026-05-19 regression: an optimal/ok solve with EMPTY
would_be_trades is the optimizer's valid 'current ≈ target, hold'
verdict — usable, NOT a failure. Previously conflated with genuine
failures, producing a false 'operator must investigate' ERROR."""
log = {
"shadow_status": "ok",
"diagnostics": {"status": "optimal"},
"diagnostics": {"status": "optimal", "turnover_one_way": 0.0017},
"would_be_trades": [],
}
assert is_log_usable(log) is False
assert is_log_usable(log) is True


def test_is_log_usable_missing_would_be_trades_key_still_usable():
"""Absent (not just empty) would_be_trades on a clean solve is also a
valid hold — usability depends only on the solve status."""
log = {"shadow_status": "ok", "diagnostics": {"status": "optimal"}}
assert is_log_usable(log) is True


def test_apply_optimizer_empty_trades_is_safe_noop():
"""The caller path for a hold day: usable log + empty would_be_trades
→ zero entries/exits, no exception (planner logs INFO, not ERROR)."""
ob = OrderBook({"date": "2026-05-19", "entries": [], "urgent_exits": [],
"stops": [], "executed_today": []})
entries, exits = apply_optimizer_targets_to_orderbook(
log={"shadow_status": "ok",
"diagnostics": {"status": "optimal"},
"would_be_trades": []},
ob=ob,
ibkr=MagicMock(),
current_positions={},
price_histories={},
atr_map={},
strategy_config={},
vwap_map={},
signals_raw={"date": "2026-05-19", "signals": {}},
predictions_by_ticker={},
market_regime="neutral",
run_date="2026-05-19",
predictions_date="2026-05-19",
)
assert entries == []
assert exits == []


# ── apply_optimizer_targets_to_orderbook ───────────────────────────────────────
Expand Down
Loading