aether_quant.liquidity¶
Spread and liquidity estimates.
Spread and liquidity estimates.
LiquidityDecision
dataclass
¶
The liquidity check of one order: dollar volume, order value, participation, estimated spread and impact, and the verdict.
build_liquidity_decision ¶
build_liquidity_decision(close: float, volume: float, target_weight: float, portfolio_value: float, annualized_volatility: float, security_type: str = 'equity', thin_participation_threshold: float = 0.002, high_impact_participation_threshold: float = 0.01, blocked_participation_threshold: float = 0.05, min_daily_dollar_volume: float = 100000.0, high_impact_size_factor: float = 0.5, slippage_factor: float = 0.1, dynamic_spread: float | None = None, max_round_trip_cost_fraction: float | None = None, zero_volume_fallback_ddv: float | None = None) -> LiquidityDecision
Size an order against the bar's dollar volume: participation, spread and impact estimates, and whether to trade, shrink or skip it.
cap_spread_proxy ¶
cap_spread_proxy(spread_proxy: float | None, security_type: str, caps_by_type: dict[str, Any] | None) -> float | None
V5.5.0 (Problems.md #133) - clamp the spread used by the liquidity GATE
and cost estimate for one asset class. The Corwin-Schultz estimator reads
a daily high-low range as a bid-ask spread; for crypto and forex mid bars
that range is volatility, not spread (the 2026-10-07 run's last bar:
BTCUSD 1.31%, LTCUSD 1.25%, AUDUSD 0.35% against real spreads of a few
bps), so max_round_trip_cost_fraction (0.25%) blocked 126 of 179 forex
and all 24 crypto book selections. ONLY the gate/cost input is capped:
liquidity_spread_proxy as a MODEL FEATURE stays untouched (train/live
parity). No cap configured for the class (or a malformed one) -> the
value passes through unchanged; None passes through (callers then use
their static fallback).
estimate_high_low_spread ¶
estimate_high_low_spread(highs: list[float], lows: list[float]) -> float | None
Corwin & Schultz (2012) high-low bid-ask spread estimator.
Estimates the fractional bid-ask spread (e.g. 0.001 = 10 bps) from nothing but consecutive days' high/low ranges -- no bid/ask/fill data required. Computes one estimate per consecutive 2-bar window and averages them. Per-window estimates are clipped to 0.0 when negative, a known artifact of the estimator in low-volatility/noisy conditions (standard practice, not a bug).
Returns None if fewer than 2 valid (positive, high >= low) bars are available -- callers should fall back to a static proxy in that case.