From 5c8d9ad22bfbe41ca7bad6d9caaa0466217a64f6 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Sat, 16 May 2026 10:20:22 +0800 Subject: [PATCH 1/2] Use shared cash sweep whole-share helper --- application/execution_service.py | 52 ++++++++++++++++++++++++++------ tests/test_execution_service.py | 4 +-- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/application/execution_service.py b/application/execution_service.py index a746859..dcf4b09 100644 --- a/application/execution_service.py +++ b/application/execution_service.py @@ -2,7 +2,6 @@ from __future__ import annotations -import math import hashlib import json import tempfile @@ -12,6 +11,35 @@ from typing import Any import pandas as pd +try: + from quant_platform_kit.common.cash_sweep import should_sell_cash_sweep_to_fund_whole_share_buy +except ImportError: # pragma: no cover - compatibility with older pinned shared wheels + def should_sell_cash_sweep_to_fund_whole_share_buy( + max_quantity, + cash_sweep_price, + base_buying_power, + funding_needs, + ): + if max_quantity <= 0: + return False + sweep_price = float(cash_sweep_price or 0.0) + if sweep_price <= 0.0: + return False + current_buying_power = max(0.0, float(base_buying_power or 0.0)) + sweep_capacity = float(max_quantity) * sweep_price + if sweep_capacity <= 0.0: + return False + + for underweight_value, ask_price in funding_needs: + _ = underweight_value + quote_price = float(ask_price or 0.0) + if quote_price <= 0.0: + continue + if current_buying_power >= quote_price: + return False + if current_buying_power + sweep_capacity >= quote_price: + return True + return False from quant_platform_kit.common.quantity import ( floor_to_quantity_step, format_quantity, @@ -663,6 +691,7 @@ def cash_sweep_sale_quantity_to_fund_buy(max_quantity: int, candidate_symbols: t if max_quantity <= 0 or not safe_haven_symbol or cash_sweep_price <= 0.0: return 0 base_buying_power = max(0.0, float(anticipated_buying_power)) + funding_needs = [] for symbol in candidate_symbols: underweight_value = target_mv[symbol] - current_mv.get(symbol, 0.0) if underweight_value <= threshold: @@ -670,16 +699,19 @@ def cash_sweep_sale_quantity_to_fund_buy(max_quantity: int, candidate_symbols: t ask = prices.get(symbol) if not ask or ask <= 0.0: continue - max_buy_quantity = int(underweight_value // ask) - if max_buy_quantity <= 0: - continue - required_buying_power = max_buy_quantity * ask * 1.0 - if base_buying_power >= required_buying_power: - return 0 - return min( - max_quantity, - max(1, math.ceil((required_buying_power - base_buying_power) / cash_sweep_price)), + funding_needs.append( + ( + underweight_value, + round(ask * limit_buy_premium, 2), + ) ) + if should_sell_cash_sweep_to_fund_whole_share_buy( + float(max_quantity), + cash_sweep_price, + base_buying_power, + funding_needs, + ): + return int(max_quantity) return 0 has_sell_plan = False diff --git a/tests/test_execution_service.py b/tests/test_execution_service.py index 46f16d2..f1e8d47 100644 --- a/tests/test_execution_service.py +++ b/tests/test_execution_service.py @@ -482,7 +482,7 @@ def fills(self): def accountValues(self): self._account_values_calls += 1 - buying_power = "124" if self._account_values_calls == 1 else "324" + buying_power = "24" if self._account_values_calls == 1 else "224" return [SimpleNamespace(tag="AvailableFunds", currency="USD", value=buying_power)] submitted = [] @@ -497,7 +497,7 @@ def fake_submit_order_intent(_ib, intent): FakeIB(), {"VOO": 0.8, "BOXX": 0.2}, {"VOO": {"quantity": 0}, "BOXX": {"quantity": 2}}, - {"equity": 1000.0, "buying_power": 124.0}, + {"equity": 1000.0, "buying_power": 24.0}, fetch_quote_snapshots=lambda *_args, **_kwargs: { "VOO": SimpleNamespace(last_price=100.0), "BOXX": SimpleNamespace(last_price=100.0), From 95da3cb0daa769315e844853e9001e4353338953 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Sat, 16 May 2026 10:28:15 +0800 Subject: [PATCH 2/2] Fix IBKR cash sweep test account matching --- tests/test_execution_service.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test_execution_service.py b/tests/test_execution_service.py index f1e8d47..9d52a0b 100644 --- a/tests/test_execution_service.py +++ b/tests/test_execution_service.py @@ -483,7 +483,14 @@ def fills(self): def accountValues(self): self._account_values_calls += 1 buying_power = "24" if self._account_values_calls == 1 else "224" - return [SimpleNamespace(tag="AvailableFunds", currency="USD", value=buying_power)] + return [ + SimpleNamespace( + account="DU123", + tag="AvailableFunds", + currency="USD", + value=buying_power, + ) + ] submitted = []