|
4 | 4 | from dataclasses import replace |
5 | 5 | from typing import Any |
6 | 6 |
|
7 | | -from us_equity_strategies.cash_only_equity import build_portfolio_inputs_from_snapshot |
| 7 | +from us_equity_strategies.cash_only_equity import ( |
| 8 | + build_portfolio_inputs_from_snapshot, |
| 9 | + resolve_weight_translation_equity, |
| 10 | +) |
8 | 11 | from quant_platform_kit.strategy_contracts import ( |
9 | 12 | PositionTarget, |
10 | 13 | StrategyContractValidationError, |
@@ -307,32 +310,39 @@ def _normalize_to_value_decision( |
307 | 310 | *, |
308 | 311 | portfolio_inputs, |
309 | 312 | runtime_metadata: Mapping[str, Any] | None, |
| 313 | + cash_only_execution: bool = True, |
310 | 314 | ) -> tuple[StrategyDecision, ValueTargetExecutionAnnotations | None]: |
311 | 315 | target_mode = resolve_decision_target_mode(decision) |
312 | 316 | no_execute = "no_execute" in set(decision.risk_flags) |
313 | 317 | if target_mode == "value" and not no_execute: |
314 | 318 | return decision, None |
315 | 319 | if target_mode == "weight" and not no_execute: |
316 | | - total_equity = float(portfolio_inputs.total_equity) |
317 | | - if total_equity <= 0.0: |
| 320 | + total_equity, block_execution, deleverage_mode = resolve_weight_translation_equity( |
| 321 | + portfolio_inputs, |
| 322 | + cash_only_execution=cash_only_execution, |
| 323 | + ) |
| 324 | + if block_execution: |
318 | 325 | diagnostics = { |
319 | 326 | **dict(runtime_metadata or {}), |
320 | 327 | **dict(decision.diagnostics), |
321 | 328 | "execution_blocked_reason": "non_positive_total_equity", |
322 | | - "portfolio_total_equity": total_equity, |
| 329 | + "portfolio_total_equity": float(portfolio_inputs.total_equity), |
323 | 330 | } |
324 | 331 | return _build_zero_equity_no_execute_decision( |
325 | 332 | decision, |
326 | 333 | portfolio_inputs=portfolio_inputs, |
327 | 334 | diagnostics=diagnostics, |
328 | 335 | ), _build_weight_translation_annotations( |
329 | 336 | decision, |
330 | | - total_equity=total_equity, |
| 337 | + total_equity=float(portfolio_inputs.total_equity), |
331 | 338 | liquid_cash=float(portfolio_inputs.liquid_cash), |
332 | 339 | runtime_metadata=runtime_metadata, |
333 | 340 | ) |
| 341 | + diagnostics = dict(decision.diagnostics) |
| 342 | + if deleverage_mode: |
| 343 | + diagnostics["cash_only_deleverage_mode"] = True |
334 | 344 | translated = translate_decision_to_target_mode( |
335 | | - decision, |
| 345 | + replace(decision, diagnostics=diagnostics) if deleverage_mode else decision, |
336 | 346 | target_mode="value", |
337 | 347 | total_equity=total_equity, |
338 | 348 | ) |
@@ -416,6 +426,7 @@ def map_strategy_decision_to_plan( |
416 | 426 | decision, |
417 | 427 | portfolio_inputs=portfolio_inputs, |
418 | 428 | runtime_metadata=runtime_metadata, |
| 429 | + cash_only_execution=cash_only_execution, |
419 | 430 | ) |
420 | 431 | annotations = translated_annotations or _build_annotations( |
421 | 432 | normalized_decision, |
|
0 commit comments