You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
4.4 KiB
Python

"""Helpers for shadow-only non-core allocator v2 diagnostics."""
from __future__ import annotations
import math
def compute_native_rank_pct(rank_index: int, total: int) -> float:
if total <= 1:
return 1.0
clamped_index = max(0, min(rank_index, total - 1))
return max(0.0, 1.0 - (clamped_index / float(total - 1)))
def normalize_hold_days_est(hold_days_est: int | float | None) -> float:
hold_days = max(0.0, float(hold_days_est or 0.0))
return min(hold_days, 30.0) / 30.0
def normalize_liquidity_penalty(
requested_cash_est: int | float | None,
avg_dollar_volume: int | float | None,
) -> float:
requested_cash = max(0.0, float(requested_cash_est or 0.0))
adv = max(0.0, float(avg_dollar_volume or 0.0))
denom = max(adv * 0.02, 1.0)
return min(requested_cash / denom, 1.0)
def classify_parking_class(parking_symbol: str | None) -> str:
normalized = str(parking_symbol or "").strip().lower()
if normalized == "sgov":
return "cash"
if normalized == "gld":
return "gold"
if normalized in {"qqqm", "qqq", "tqqq", "spy"}:
return "equity_beta"
return "cash"
def classify_non_core_overlap_class(
family: str,
*,
trade_symbol_mode: str | None = None,
engine_id: str | None = None,
symbol: str | None = None,
) -> str:
normalized_family = str(family or "").strip().lower()
normalized_engine = str(engine_id or "").strip().lower()
normalized_symbol = str(symbol or "").strip().lower()
normalized_mode = str(trade_symbol_mode or "").strip().lower()
if normalized_family == "risk_off_alpha" and normalized_symbol == "gld":
return "gold"
if normalized_family == "idle_alpha" and (
normalized_engine == "idle_macro_breadth_smh_postalloc"
or normalized_mode == "sector_etf"
or normalized_symbol == "smh"
):
return "equity_beta_high"
if normalized_family in {"idle_alpha", "form4", "ownership"}:
return "equity_beta_med"
if normalized_family == "risk_off_alpha":
return "gold" if normalized_symbol == "gld" else "cash"
return "cash"
def compute_overlap_penalty(candidate_class: str, parking_class: str) -> float:
candidate = str(candidate_class or "").strip().lower()
parking = str(parking_class or "").strip().lower()
if parking == "cash" or candidate == "cash":
return 0.0
if candidate == "gold" and parking == "gold":
return 1.0
if candidate == "equity_beta_high" and parking == "equity_beta":
return 1.0
if candidate == "equity_beta_med" and parking == "equity_beta":
return 0.6
return 0.0
def normalize_parking_proxy(
parking_symbol: str | None,
*,
parking_momentum_20: int | float | None,
hold_days_est: int | float | None,
sgov_annual_rate: int | float | None,
) -> float:
normalized_symbol = str(parking_symbol or "").strip().lower()
hold_days = max(0.0, float(hold_days_est or 0.0))
if normalized_symbol == "sgov":
annual_rate = max(0.0, float(sgov_annual_rate or 0.0))
return min(((annual_rate * hold_days / 252.0) / 0.02), 1.0)
momentum = max(0.0, float(parking_momentum_20 or 0.0))
scaled_momentum = momentum * (min(hold_days, 20.0) / 20.0)
return min(scaled_momentum / 0.10, 1.0)
def compute_marginal_score(
*,
native_rank_pct: int | float | None,
hold_norm: int | float | None,
liquidity_penalty_norm: int | float | None,
overlap_penalty_norm: int | float | None,
parking_proxy_norm: int | float | None,
native_strength: int | float = 1.0,
hold_penalty: int | float = 0.20,
liquidity_penalty: int | float = 0.25,
overlap_penalty: int | float = 0.20,
parking_opportunity_penalty: int | float = 0.35,
) -> float:
values = (
float(native_rank_pct or 0.0),
float(hold_norm or 0.0),
float(liquidity_penalty_norm or 0.0),
float(overlap_penalty_norm or 0.0),
float(parking_proxy_norm or 0.0),
)
if any(math.isnan(value) or math.isinf(value) for value in values):
return 0.0
return (
float(native_strength) * float(native_rank_pct or 0.0)
- float(hold_penalty) * float(hold_norm or 0.0)
- float(liquidity_penalty) * float(liquidity_penalty_norm or 0.0)
- float(overlap_penalty) * float(overlap_penalty_norm or 0.0)
- float(parking_opportunity_penalty) * float(parking_proxy_norm or 0.0)
)