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
24 changes: 23 additions & 1 deletion application/execution_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ class ExecutionCycleResult:

DEFAULT_SAFE_HAVEN_CASH_SUBSTITUTE_THRESHOLD_USD = 1000.0
SMALL_ACCOUNT_SAFE_HAVEN_CASH_SUBSTITUTE_LIMIT_USD = 2000.0
SMALL_ACCOUNT_EXISTING_WHOLE_SHARE_RETENTION_SYMBOLS = frozenset({"TQQQ", "SOXL"})


def _floor_quantity(quantity: float) -> int:
Expand Down Expand Up @@ -246,9 +247,26 @@ def _apply_small_account_whole_share_compatibility(
price = _quote_price(market_data_port, str(symbol).strip().upper())
if price is not None:
prices[str(symbol).strip().upper()] = price
retained_symbols = []
quantities = {
str(symbol or "").strip().upper(): float(quantity or 0.0)
for symbol, quantity in dict(portfolio.get("quantities") or {}).items()
}
compatibility_targets = {
str(symbol or "").strip().upper(): float(value or 0.0)
for symbol, value in targets.items()
}
for symbol in candidate_symbols:
if symbol not in SMALL_ACCOUNT_EXISTING_WHOLE_SHARE_RETENTION_SYMBOLS:
continue
target_value = max(0.0, float(compatibility_targets.get(symbol, 0.0) or 0.0))
price = max(0.0, float(prices.get(symbol, 0.0) or 0.0))
if price > 0.0 and 0.0 < target_value < price and quantities.get(symbol, 0.0) >= 1.0:
compatibility_targets[symbol] = price
Comment on lines +264 to +265

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Account for the trade threshold when retaining one share

When the default $100 min-trade floor is used and TQQQ is below $100, an account holding exactly two TQQQ shares with a positive sub-share target gets its target raised to one quote here; the later threshold check then sees only a one-share delta (<$100) and skips the sell, leaving two leveraged shares instead of the intended single retained share. The added regression sets current_min_trade to 10, so it misses this production-default path.

Useful? React with 👍 / 👎.

retained_symbols.append(symbol)
safe_haven_symbols = _safe_haven_cash_symbols(portfolio=portfolio, allocation=allocation)
compatibility = apply_small_account_cash_compatibility(
targets,
compatibility_targets,
prices,
candidate_symbols=candidate_symbols,
safe_haven_cash_symbols=safe_haven_symbols,
Expand All @@ -263,6 +281,10 @@ def _apply_small_account_whole_share_compatibility(
allocation["small_account_whole_share_substituted_symbols"] = substituted
if safe_haven_substituted:
allocation["small_account_safe_haven_cash_substituted_symbols"] = tuple(safe_haven_substituted)
if retained_symbols:
allocation["small_account_existing_whole_share_retained_symbols"] = tuple(
dict.fromkeys(retained_symbols)
)
if compatibility.cash_substitution_notes:
allocation["small_account_whole_share_cash_notes"] = tuple(compatibility.cash_substitution_notes)
adjusted_plan["allocation"] = allocation
Expand Down
26 changes: 26 additions & 0 deletions tests/test_execution_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,32 @@ def test_execute_value_target_plan_uses_sellable_quantity_when_market_value_is_s
]


def test_execute_value_target_plan_keeps_existing_whole_share_when_positive_target_is_unbuyable():
execution_port = FakeExecutionPort()
result = execute_value_target_plan(
plan={
"allocation": {
"targets": {"TQQQ": 60.94, "QQQM": 320.0},
"risk_symbols": ("TQQQ", "QQQM"),
},
"portfolio": {
"market_values": {"TQQQ": 541.31, "QQQM": 0.0},
"quantities": {"TQQQ": 7.0, "QQQM": 0.0},
"sellable_quantities": {"TQQQ": 7.0, "QQQM": 0.0},
"liquid_cash": 539.70,
},
"execution": {"current_min_trade": 10.0, "investable_cash": 539.70},
},
market_data_port=FakeMarketDataPort({"TQQQ": 77.33, "QQQM": 297.19}),
execution_port=execution_port,
dry_run_only=True,
)

assert [(order.side, order.symbol, order.quantity) for order in execution_port.orders if order.side == "sell"] == [
("sell", "TQQQ", 6.0),
]


def test_execute_value_target_plan_skips_when_cap_cannot_buy_one_share():
execution_port = FakeExecutionPort()
result = execute_value_target_plan(
Expand Down