@@ -23,6 +23,22 @@ def _floor_quantity(quantity: float) -> int:
2323 return max (0 , int (float (quantity or 0.0 )))
2424
2525
26+ def _sell_budget (
27+ * ,
28+ delta_value : float ,
29+ target_value : float ,
30+ sellable_quantity : float ,
31+ price : float ,
32+ order_notional_cap : float ,
33+ ) -> float :
34+ sellable_notional = max (0.0 , float (sellable_quantity or 0.0 )) * max (0.0 , float (price or 0.0 ))
35+ if sellable_notional <= 0.0 :
36+ return 0.0
37+ value_delta_budget = max (0.0 , abs (float (delta_value or 0.0 )))
38+ position_budget = max (0.0 , sellable_notional - max (0.0 , float (target_value or 0.0 )))
39+ return min (max (value_delta_budget , position_budget ), sellable_notional , max (0.0 , float (order_notional_cap or 0.0 )))
40+
41+
2642def _safe_haven_cash_symbols (* , portfolio : dict [str , Any ], allocation : dict [str , Any ]) -> tuple [str , ...]:
2743 symbols : list [str ] = []
2844 for symbol in allocation .get ("safe_haven_symbols" , ()):
@@ -167,7 +183,13 @@ def execute_value_target_plan(
167183 for symbol , delta_value , price in [item for item in tradable_deltas if item [1 ] < 0 ]:
168184 if delta_value < 0 :
169185 sellable = sellable_quantities .get (symbol , 0.0 )
170- sell_budget = min (abs (delta_value ), sellable * price , order_notional_cap )
186+ sell_budget = _sell_budget (
187+ delta_value = delta_value ,
188+ target_value = targets .get (symbol , 0.0 ),
189+ sellable_quantity = sellable ,
190+ price = price ,
191+ order_notional_cap = order_notional_cap ,
192+ )
171193 quantity = _floor_quantity (sell_budget / price )
172194 if quantity <= 0 :
173195 skipped .append (
0 commit comments