aether_quant.execution¶
Execution gates: order permission, slippage, the cost / net-edge model and position reconciliation (formally verified in formal/AetherFormal/{OrderGate,CostModel,Reconciliation}.lean), plus accounts, secrets, the field test and the paper-to-live scorecard (V6.6.5).
Execution gates: order permission, slippage, the cost / net-edge model and position reconciliation (formally verified in formal/AetherFormal/{OrderGate,CostModel,Reconciliation}.lean), plus accounts, secrets, the field test and the paper-to-live scorecard (V6.6.5).
DEFAULT_THRESHOLDS
module-attribute
¶
DEFAULT_THRESHOLDS: dict[str, float] = {'forward_sessions_min': 60, 'forward_alpha_t_min': 2.0, 'book_dsr_min': 0.95, 'round_pbo_max': 0.5, 'paper_trading_days_min': 120, 'paper_rebalances_min': 6, 'field_test_max_age_days': 90, 'max_total_drawdown_pct_max': 0.15, 'backup_max_age_days': 7, 'verification_max_age_days': 30, 'mutation_score_min': 0.9}
OVERRIDE_KEYS
module-attribute
¶
OVERRIDE_KEYS: dict[str, str] = {'live.max_allowed_daily_drawdown_pct': 'lower', 'live.max_allowed_total_drawdown_pct': 'lower', 'dynamic_risk.max_leverage': 'lower', 'reconciliation.max_tolerated_drift': 'lower', 'risk.kill_switch.min_rolling_sharpe': 'higher', 'risk.kill_switch.max_drawdown_velocity_pct_per_bar': 'lower', 'risk.kill_switch.max_consecutive_losses': 'lower', 'risk.kill_switch.max_slippage_divergence_bps': 'lower', 'risk.kill_switch.max_model_age_days': 'lower', 'runtime.allow_live_orders': 'false'}
SECRET_NAMES
module-attribute
¶
SECRET_NAMES: tuple[str, ...] = ('IB_ACCOUNT', 'IB_USER_NAME', 'IB_PASSWORD', 'IB_TRADING_MODE', 'COINBASE_API_KEY', 'COINBASE_API_SECRET', 'POSTGRES_DSN', 'REDIS_URL', 'TELEGRAM_BOT_TOKEN', 'TELEGRAM_CHAT_ID', 'POLYGON_API_KEY', 'IEX_CLOUD_API_KEY')
Account
dataclass
¶
One deployment. mode, when set, may only lower the config's runtime.mode (observation < paper < live);
capital_usd is the capital the account is funded with, which the readiness scorecard requires for a live account.
risk_overrides
class-attribute
instance-attribute
¶
risk_overrides: Mapping[str, Any] = field(default_factory=dict)
AccountTaggedQueue ¶
Wraps an audit queue so every event it pushes carries the account id (named accounts only).
FieldTestPlan
dataclass
¶
When and how hard to push. Bars count from the algorithm's first on_data.
target_weights
class-attribute
instance-attribute
¶
target_weights: tuple[tuple[str, float], ...] = ()
NetEdgeDecision
dataclass
¶
The net-edge gate's verdict for one order: expected edge, expected cost, net edge and whether it trades.
ReadinessMetric
dataclass
¶
One measured condition: its value, threshold and comparator, pass/fail/unknown, and where the evidence came from.
ReconciliationReport
dataclass
¶
Expected against actual holdings: matched names, drifts, orphan and missing positions, the largest drift and whether it breaches.
ResolvedSecret
dataclass
¶
Scorecard
dataclass
¶
Every metric for one account, ready only when all pass (unknown counts as fail), and the blocking keys.
SecretRef
dataclass
¶
SecretValue ¶
A credential that never shows itself: repr, str and f-strings give ***. reveal() returns the text.
account_output_paths ¶
account_output_paths(root: Path, account: Account) -> dict[str, Path]
The runtime files main.py writes, by name. The default account's are exactly today's.
account_state_dir ¶
account_state_dir(root: Path, account: Account) -> Path
Where an account writes its state: the repo root for the default (today's paths), else state/accounts/<id>.
apply_risk_overrides ¶
apply_risk_overrides(phase_v2: Mapping[str, Any], account: Account) -> dict[str, Any]
A deep copy of phase_v2 with the account's overrides and mode applied; the default account returns an equal
copy. Re-checks every override against this base, so a registry written for another config cannot loosen this one.
build_net_edge_decision ¶
build_net_edge_decision(predicted_rank: float | None, liquidity_payload: dict[str, Any], order_value: float, cost_config: dict[str, Any], *, trade_direction: int = 1, security_type: str | None = None) -> NetEdgeDecision
The one call site analyzer/market_analyzer.py's Priority 6.5 tier and risk/position_sizing.py::cost_sizing_multiplier() both consume.
trade_direction (+1 long, -1 short) must be the sign of the trade
actually being evaluated - see expected_edge_bps()'s docstring for why
this parameter exists at all. Defaults to 1 (long) only so callers
that genuinely never trade short (or existing tests exercising the
long side) do not need to pass it; every live call site must supply
the real signed direction.
FAIL-OPEN, always: returns passes=True, reason="net_edge_gate_disabled"
whenever cost_config["enabled"] is false, edge_bps_per_rank_unit is
0.0 (uncalibrated - see aq evaluate --calibrate-edge), or
predicted_rank is None. An uncalibrated or disabled cost model must
never block a trade - the exact same "missing/degraded signal never
changes trading behavior" contract every other optional overlay in
this codebase (topology_sizing_multiplier(), rank_sizing_multiplier())
already follows.
build_scorecard ¶
build_scorecard(evidence: Mapping[str, Any], thresholds: Mapping[str, float] | None = None, *, now: datetime, account: str = 'default') -> Scorecard
The scorecard from evidence (see execution/live_readiness_io.gather_evidence for the keys). Pure.
classify_order_status ¶
classify_order_status(status_name: str) -> str
Pure string classification, never raises on an unrecognized value - returns "unknown" instead, which callers treat as still-pending (conservative: never mistakes an unrecognized status for a fill).
commission_bps_by_ticker ¶
commission_bps_by_ticker(cost_config: dict[str, Any], security_type_by_ticker: dict[str, str]) -> dict[str, float]
Per-ticker per-side commission bps for every ticker whose security type has a fee override - the
offline simulator's commission_bps_by_ticker, so it charges the same fee the live gate assumes. An override
may carry sim_fee_bps when a dollar floor (min_usd) makes its true cost per fill larger than fee_bps at
realistic order sizes (forex: IB's $2 minimum on ~$2.6k fills is ~7.6 bps) - the simulator has no per-order floor.
commission_terms_for_security_type ¶
commission_terms_for_security_type(cost_config: dict[str, Any], security_type: str | None) -> tuple[float, float]
(commission_bps_per_side, min_commission_usd) for one security type: the per-class override when configured (crypto pays a percentage exchange fee with no dollar floor, unlike IB's per-share equity commission), else the global terms.
compute_fill_slippage_divergence_bps ¶
compute_fill_slippage_divergence_bps(fill_price: float, reference_price: float, expected_cost_bps: float, direction: float | None = None) -> float | None
V5.7.0 (Problems.md #148): with direction (the fill quantity's sign: > 0 buy, < 0 sell) only ADVERSE slippage
counts - a buy filled below the open (or a sell above it) is price improvement, a limit order doing its job, and used
to be added to the kill-switch average as if it were a cost (BT5: crypto limit fills 1-4% under the open locked 24 book
decisions). Without direction the absolute gap is used, as before.
V5.5.0 (Problems.md #88/#96) - realized-minus-expected slippage in bps
for evaluate_kill_switch(). reference_price must be the FILL BAR's
open (what a daily market order actually targets), NOT the prior bar's
close - against the prior close this measured the overnight gap, which
is why the trigger had to be disabled with a 1e12 sentinel. Returns None
on any non-finite/non-positive input so the caller records nothing
rather than a fabricated 0.
default_refs ¶
default_refs(name: str, account_id: str | None = None, env: Mapping[str, str] | None = None) -> tuple[SecretRef, ...]
The lookup order for one secret (see the module docstring).
env_prefix ¶
env_prefix(account_id: str | None) -> str
AETHER_ for the default account, AETHER_<ACCOUNT>_ for any other (dashes become underscores).
estimate_round_trip_cost_bps ¶
estimate_round_trip_cost_bps(liquidity_payload: dict[str, Any], *, commission_bps_per_side: float, min_commission_usd: float, order_value: float, extra_slippage_bps: float) -> float
Reads liquidity_payload["estimated_round_trip_cost"] - already computed by liquidity/market_liquidity.py::build_liquidity_decision() (a fraction, e.g. 0.001 = 10bps) - and NEVER recomputes slippage; one estimate per bar, consistently used everywhere (the same rule main.py:1768-1771's own comment states). Adds the commission leg, expressed as bps of order_value with a min_commission_usd dollar floor (a small order can be commission-dominated even at a low bps rate), plus any extra_slippage_bps buffer (a deliberately simple manual safety margin, config-gated, defaults to 0.0).
order_value <= 0 (no order, or a zero-target-weight decision) returns just the liquidity round-trip cost plus extra_slippage_bps - the commission-floor conversion to bps is undefined at zero order value, so it is skipped rather than divided-by-zero.
V5.4.5 (development/Problems.md #116): the commission leg now covers BOTH sides of the round trip. The original math charged exactly one side's commission (rate leg and min_commission_usd floor alike) against a function whose contract - and this parameter's own name - is per-SIDE cost for a ROUND-TRIP estimate, understating expected cost by up to 2x and letting trades through whose true net edge was below the gate.
evaluate_broker_config ¶
evaluate_broker_config(mode: str, paper_trading_config: dict[str, Any], live_credentials_present: bool = False, risk_config: dict[str, Any] | None = None, live_config: dict[str, Any] | None = None, postgres_dsn: str | None = None) -> tuple[bool, str]
Single entrypoint main.py._order_permission() calls regardless of mode - dispatches to the two functions above. Any mode other than 'live' (including 'backtest'/'observation', where the result is unused since resolve_order_permission() never consults broker_config_present for those modes) goes through the paper path.
evaluate_live_broker_config ¶
evaluate_live_broker_config(paper_trading_config: dict[str, Any], live_credentials_present: bool, risk_config: dict[str, Any] | None = None, live_config: dict[str, Any] | None = None, postgres_dsn: str | None = None) -> tuple[bool, str]
mode='live' gate (V2-22). You cannot go straight to live without a validated paper corridor - the paper check must also pass - AND real broker credentials must be present AND (if risk/live config supplied) the live risk posture must be safe AND (if a Postgres DSN is supplied) it must not still use the published dev-default password.
postgres_dsn is optional and defaults to None (unchecked) so existing
callers/tests are unaffected; main.py threads the real DSN through so a
live run against the public default password fails closed.
evaluate_live_risk_posture ¶
evaluate_live_risk_posture(risk_config: dict[str, Any], live_config: dict[str, Any]) -> tuple[bool, str]
Sanity ceiling for mode='live' - not a redesign of the drawdown circuit breaker, just a guard against live mode running with an accidentally-loose (or disabled) risk config that was fine for paper/observation but is unacceptable once real capital is at risk.
evaluate_observation_readiness ¶
evaluate_observation_readiness(summary: dict[str, Any], thresholds: dict[str, Any]) -> dict[str, Any]
Turns 4 of the 5 bullets in development/infrastructure.md's "Paper" checklist into code, given an already-computed observation summary (experience.observation_metrics.compute_observation_summary() output) and threshold config. The 5th bullet (manual review of trade history for plausible entry/exit prices) is deliberately NOT automated - it stays a human judgment call, surfaced via paper_trading_config's manual_review_confirmed flag (see evaluate_paper_broker_config above).
evaluate_paper_broker_config ¶
evaluate_paper_broker_config(paper_trading_config: dict[str, Any]) -> tuple[bool, str]
mode='paper' gate. All three must be true: - brokerage is a non-empty known value - live_data_provider_configured (human-set attestation - a live market data feed is required for Lean's live-paper environment even though PaperBrokerage itself needs no broker credentials) - manual_review_confirmed (human-set attestation, replaces the old phase6.paper_trading.ready_for_live_paper stub)
evaluate_velocity_decision ¶
evaluate_velocity_decision(config: dict[str, Any]) -> tuple[bool, str]
A target-weights run must not reach a broker on a velocity setting nobody decided (Problems.md #278). R-VEL1 records it in
phase_v2.target_weights.velocity_decision, whichever way it went. Any other path has its own gates.
expected_edge_bps ¶
expected_edge_bps(predicted_rank: float | None, *, edge_bps_per_rank_unit: float, holding_bars: int, horizon_days: int, trade_direction: int = 1) -> float
Linear-in-rank-deviation expected edge estimate, measured IN THE
DIRECTION OF THE TRADE. rank_deviation = (rank - 0.5) * 2 is positive
for a top-ranked asset (expected to rise) and negative for a
bottom-ranked one (expected to fall) - trade_direction (+1 long, -1
short) says which side the caller actually intends to trade, so the
result is the edge realized if that trade is entered, not merely the
raw long-side edge.
A rank of 0.5 (median - no view) always has zero expected edge. A rank of 1.0/0.0 has the full edge_bps_per_rank_unit magnitude, on whichever side the rank itself favors (long the top, short the bottom) - the book case, where trade_direction is derived from the same rank that picked the side, so the product is always the FULL magnitude, never negative. A mismatched trade (e.g. going long a bottom-ranked asset) correctly comes out negative and gets vetoed downstream.
Scaled down by min(1, holding_bars/horizon_days) - the rank head's own forward horizon (horizon_days, e.g. 20 for rank_20d) is how long the FULL predicted move is expected to take; holding for fewer bars than that only captures a fraction of it.
predicted_rank=None (model unavailable this bar) -> 0.0, the safe no-edge default, matching every other "missing prediction never changes trading behavior" contract in this codebase.
GUARDRAIL (Problems.md - net-edge gate blocked 100% of shorts): before this parameter existed, the gate measured only the raw long-side edge and applied it unconditionally to buy/sell/short decisions alike, so every short entry (negative rank_deviation) was vetoed on every bar. trade_direction must always be threaded through from the caller's own signed intent (e.g. sign of the pre-cost target_weight) - never left at the default 1 for a short trade.
expected_fill_fee_bps ¶
expected_fill_fee_bps(is_limit_route: bool, fill_rate: float, maker_bps: float, taker_bps: float) -> float
Expected exchange fee in bps of one fill (V6.0.0): a limit order pays the maker rate when it fills and the taker
rate when it times out into a market order; a market order always pays the taker rate. fill_rate is clipped to
[0, 1].
fee_override_for_security_type ¶
fee_override_for_security_type(cost_config: dict[str, Any], security_type: str | None) -> dict[str, Any] | None
phase_v2.costs.fee_by_type[<security_type>] when it carries a finite, non-negative fee_bps, else None
(the global commission terms apply, exactly as before the key existed).
field_test_allowed ¶
field_test_allowed(plan: FieldTestPlan, *, runtime_mode: str, paper_brokerage: str, env_flag: str | None) -> bool
True only for an enabled plan, AQ_FIELD_TEST=1, and a run that cannot reach real money: observation (no orders at all),
or paper on Lean's own paper brokerage (phase_v2.paper_trading.brokerage). Never live, whatever else is set.
field_test_log_line ¶
field_test_log_line(event: str, bar_index: int, **fields: object) -> str
FIELD_TEST event=<event> bar=<n> key=value ...: one engine-log line the report parses.
field_test_target ¶
field_test_target(plan: FieldTestPlan, bar_index: int) -> dict[str, float] | None
The target row to apply on exactly bar order_after_bars, else None (one decision per run).
find_populated_secret_fields ¶
find_populated_secret_fields(lean_config: dict[str, Any]) -> list[str]
Return the sorted names of every secret-looking lean.json field that has a non-empty string value. Empty template -> empty list.
inject_metrics ¶
inject_metrics(runtime_metrics: Mapping[str, Any], plan: FieldTestPlan, bar_index: int) -> dict[str, Any]
The kill switch's inputs, with the drawdown shock from shock_after_bars on (a copy; the input is not touched).
inject_reconciliation_drift ¶
inject_reconciliation_drift(actual_by_symbol: Mapping[str, float], plan: FieldTestPlan, bar_index: int) -> dict[str, float]
The holdings reconciliation compares, with the drift from drift_after_bars on (a copy).
is_real_order_placement ¶
is_real_order_placement(execution_note: str, orders_allowed: bool) -> bool
True only for a genuinely-placed real order - never a simulated/ observation-mode fill (execution_note prefixed "simulated_") and never one of the known no-op/blocked outcomes above.
is_secret_field ¶
is_secret_field(field: str) -> bool
Whether a config field name holds a secret (an exact name or a secret-like suffix).
is_tracked_env_secret ¶
is_tracked_env_secret(filename: str) -> bool
True if filename is a real .env secret file (must not be committed)
rather than one of the committed *.example templates. Accepts a bare
filename or a path - only the final component matters.
judge_field_test ¶
judge_field_test(evidence: Mapping[str, Any]) -> dict[str, Any]
Pass/fail per check from a run's evidence (scripts/lean_smoke/field_test.py collects it from the engine
logs, the result JSON, the audit chain and the services log). A check without evidence is not_run, which fails.
liquidity_cost_fraction ¶
liquidity_cost_fraction(liquidity_payload: dict[str, Any], source: str) -> float
Pick which liquidity/market_liquidity.py::LiquidityDecision field (already a fraction, e.g. 0.001 = 10bps) feeds the fill-slippage estimate, per resolve_fill_slippage_source()'s normalized source. Missing/malformed field -> 0.0, never raises.
live_mode_allowed ¶
live_mode_allowed(scorecard_doc: Mapping[str, Any] | None, *, enforce: bool) -> bool
With phase_v2.live_readiness.enforce_before_live on, live mode needs the last written scorecard to be ready.
min_commission_usd_by_ticker ¶
min_commission_usd_by_ticker(cost_config: dict[str, Any], security_type_by_ticker: dict[str, str]) -> dict[str, float]
Per-ticker broker dollar floor per order (IB's $1 equity / $2 forex minimum, none for crypto): the simulator's
min_commission_usd_by_ticker, so a small order costs what live pays (V6.0.0).
override_path ¶
override_path(root: Path, account: Account) -> Path
The file the manual trade-lock and kill-switch overrides are read from and written to (aq trade-lock, the API).
parse_accounts ¶
parse_accounts(doc: Mapping[str, Any], base_phase_v2: Mapping[str, Any] | None = None) -> tuple[Account, ...]
{"accounts": [{"id": ..., "broker": ..., ...}]} to accounts, the default first. Raises ValueError on a bad or
duplicate id, a broker/environment mismatch, live on the paper broker, an unknown override key or, given
base_phase_v2, an override looser than the base.
parse_field_test_log ¶
parse_field_test_log(text: str) -> list[dict[str, str]]
Every FIELD_TEST line of an engine log as a dict of its fields.
parse_ref ¶
parse_ref(text: str) -> SecretRef
scheme:target to a SecretRef. A literal value is refused: secrets are never written into config.
reconcile_positions ¶
reconcile_positions(expected_by_symbol: dict[str, float], actual_by_symbol: dict[str, float], *, weight_tolerance: float, value_tolerance_usd: float, portfolio_value: float, max_tolerated_drift: float | None = None) -> ReconciliationReport
Classifies every symbol appearing in EITHER dict
- "matched": both expected and actual are present and within weight_tolerance (as a fraction of portfolio weight) AND within value_tolerance_usd (the dollar-value equivalent of that weight difference) - both must hold, since a large-value portfolio can have a tiny weight_tolerance breach that is still a huge dollar drift, and a small-value portfolio can have a huge weight_tolerance breach that is a trivial dollar amount.
- "drifted": both present, but outside tolerance - full per-symbol delta detail (expected_weight, actual_weight, delta_weight, delta_usd).
- "orphan_broker": held by the broker but not in the expected book at all (expected_weight treated as 0.0) - e.g. a position main.py's book no longer wants but the broker never closed.
- "missing_broker": expected by the book but the broker holds nothing for it (actual_weight treated as 0.0) - e.g. an order that never filled.
max_abs_weight_drift is the single largest |delta_weight| across every NON-matched symbol (drifted + orphan_broker + missing_broker combined - a symbol classified "matched" is, by construction, already within both tolerances, so including it could only ever pull the max down toward a value the genuine drifts already exceed - excluding it keeps this field's value exactly matching what its name and this docstring claim). breach is that value compared against max_tolerated_drift (typically phase_v2.reconciliation.max_tolerated_drift) - the one field a caller checks to decide whether this reconciliation should trip the kill switch (risk/kill_switch.py's "reconciliation_breach" trigger) without re-deriving the comparison itself. max_tolerated_drift=None (the default) always reports breach=False - an unconfigured caller gets a strict no-op, matching every other fail-open contract in this codebase.
Tolerance is checked BEFORE presence: a symbol held/expected only on one side but within weight_tolerance/value_tolerance_usd of the other side's implicit 0.0 (a dust position - a fractional share leftover, a rounding remainder) is "matched", never "orphan_broker"/"missing_broker". Without this, every dust amount was a permanent, unfixable "orphan" no matter how negligible, even though it could never move max_abs_weight_drift past a real drift either - pure report-quality noise.
Pure dict-in/dict-out - result does not depend on either dict's insertion order (both are iterated via a sorted union of keys). Empty inputs (both dicts empty) return an all-empty, non-breaching report, never raise.
V5.4.5 (development/Problems.md #117): a non-finite weight on either
side previously slipped through every comparison silently - abs(nan)
<= tol is False (so the symbol still classified drifted/orphan), but
max(0.0, abs(nan)) kept 0.0, leaving max_abs_weight_drift at 0.0 and
breach False: a real blow-up reported as NaN was a false-clean. A
non-finite weight now forces max_abs_weight_drift to +inf, so any
configured max_tolerated_drift reports breach=True (fail-closed for a
safety trigger). An explicit None value no longer raises float(None)
either - it degrades through this same non-finite path.
redact ¶
redact(text: str, values: Iterable[SecretValue | str | None]) -> str
text with every occurrence of every secret value replaced by ***, longest first (so a value that contains another
is hidden whole). Values shorter than 4 characters are left alone: masking 1 would mangle every number.
redact_url ¶
redact_url(url: object) -> str
url with the password of its user info masked (redis://:***@host:6379/0), for logs. A URL without one, or text
that is not a URL, comes back as it was.
render_markdown ¶
render_markdown(scorecard: Scorecard) -> str
The scorecard as a Markdown table (the docs' generated block and aq live-readiness --markdown).
resolve_account ¶
resolve_account(accounts: tuple[Account, ...], requested: str | None) -> Account
The account named requested; the default when it is empty. An unknown id raises: a deployment must never run
on another account's settings by a typo.
resolve_cash_sweep_order_permission ¶
resolve_cash_sweep_order_permission(mode: str, allow_live_orders: bool, broker_config_present: bool) -> tuple[bool, str]
V6.2.0: whether the T-bill cash sweep may trade. The strategy's risk locks (kill switch, drawdown lock, manual lock) stop the strategy, not cash management, so they are not consulted; every other gate of resolve_order_permission (observation never trades, paper / live need the flag and the broker config) applies.
resolve_combo_limit_price ¶
resolve_combo_limit_price(net_mid: float, spread_fraction: float, is_buy: bool, offset_multiplier: float = 1.0) -> float
Limit for a whole option combo at its net price per unit, which can be a credit (below zero). The same half-spread offset as
resolve_limit_price, on the net's size: a buyer pays up, a seller gives up, whichever side of zero the net is. Rounded to cents, as a combo is quoted.
resolve_exit_order_route ¶
resolve_exit_order_route(asset_class: str | None, exit_reason: str | None, exit_asset_classes: Iterable[str] | None) -> str
"limit" or "market" for a full exit (V6.0.0, todo lead 3: crypto exits were all market orders at 80 bps against
~60 bps for the maker entries). A limit exit needs the class listed in phase_v2.limit_orders.exit_asset_classes
(default empty = every exit stays a market order, as before) and a reason from LIMIT_EXIT_REASONS; the timeout
fallback to a market order is the entry path's own (fallback_to_market_on_timeout).
resolve_field_test_plan ¶
resolve_field_test_plan(raw: Mapping[str, Any] | None) -> FieldTestPlan
The plan from phase_v2.diagnostics.field_test; absent or malformed means disabled.
resolve_fill_slippage ¶
resolve_fill_slippage(symbol_key: str, reference_price: float, slippage_bps_by_symbol: dict[str, Any], max_bps: float = MAX_LIQUIDITY_SLIPPAGE_BPS) -> float
Pure lookup + clamp + apply, used by main.py's real Lean SlippageModel (_LiquidityAwareSlippageModel.GetSlippageApproximation) to turn the per-symbol bps dict into an absolute fill-price delta.
resolve_fill_slippage_source ¶
resolve_fill_slippage_source(raw_source: str | None) -> str
Normalize a phase_v2.liquidity.fill_slippage.source config value, failing safe to DEFAULT_FILL_SLIPPAGE_SOURCE for anything unset/unknown - same fail-safe-normalize convention as resolve_runtime_mode() above.
resolve_limit_order_timeout_action ¶
resolve_limit_order_timeout_action(status: str, quantity_remaining: float, fallback_enabled: bool) -> dict[str, Any]
Mirrors _process_pending_limit_order_timeouts()'s per-leg branch
once a tracked order has sat unfilled for
phase_v2.limit_orders.unfilled_timeout_bars bars: an already-resolved
leg ("filled"/"canceled" - main.py's own comment: resolved by
on_order_event() this bar or an earlier one) needs no action here.
Any other status - "pending", "unknown", or "PartiallyFilled" (which
classify_order_status() maps to "pending") - gets canceled, with a
market-order fallback for exactly quantity_remaining (never the
order's original size, which this function deliberately never
receives - a partial fill's leftover quantity is structurally the
only number that can ever be returned here) when fallback_enabled and
there IS a nonzero remainder.
Returns {"should_cancel": bool, "fallback_market_quantity": float | None}.
resolve_limit_price ¶
resolve_limit_price(reference_price: float, spread_fraction: float, is_buy: bool, offset_multiplier: float = 1.0) -> float
Pure limit-price placement for main.py's real limit orders (execution/risk realism pass, part 2).
Offsets reference_price by half of spread_fraction (already a fraction, e.g. 0.001 = 10bps - the same unit family liquidity_cost_fraction() above consumes) times offset_multiplier (phase_v2.limit_orders.offset_multiplier). Halving matches the standard "bid = mid - spread/2, ask = mid + spread/2" convention - spread_fraction is a round-trip/full-spread estimate (liquidity/market_liquidity.py's spread_proxy), a single-sided limit order should only cross half of it.
A buy limit sits BELOW reference_price (never overpay above the last close); a sell/short limit sits ABOVE it (never undersell below the last close). offset_multiplier > 1.0 places a more passive (further from reference, lower fill probability, more price improvement if filled) limit; < 1.0 places a more aggressive one (closer to/crossing reference, higher fill probability, less improvement).
Returns reference_price unchanged whenever reference_price or spread_fraction is non-positive - never returns a non-positive or crossed-through price, matching slippage_amount()'s fail-safe-to- neutral convention above.
resolve_limit_setting_by_class ¶
resolve_limit_setting_by_class(asset_class: str | None, by_class: dict[str, Any] | None, default: float) -> float
A limit-order setting (offset_multiplier, unfilled_timeout_bars) for one asset class (V6.0.0): the class's entry in
phase_v2.limit_orders.<setting>_by_class when present, else the global value. Classes absent from the dict (every
class by default, the dict being empty) behave exactly as before.
resolve_order_permission ¶
resolve_order_permission(mode: str, allow_live_orders: bool, broker_config_present: bool, risk_locks_healthy: bool) -> tuple[bool, str]
Decide whether a real broker order may be placed in the given mode.
observation always returns False regardless of the other flags - this is the single safety invariant the whole phase depends on.
resolve_pending_order_action ¶
resolve_pending_order_action(existing_pending: dict[str, Any] | None, is_buy: bool, bar_index: int, timeout_bars: int) -> str
V5.5.0 (Problems.md #128) - what _try_submit_limit_order() should do when asked to place a limit order for a symbol that may already have one in flight. Before this, every bar a still-unfilled entry re-fired a NEW order and overwrote the pending record, orphaning the earlier ticket (never cancelled, never timed out - the record's submitted_bar kept resetting) so several orders could all fill (AMZN: 3x its target).
- "submit": nothing in flight, place a fresh order.
- "keep": an order in the SAME direction is still within its timeout - do nothing, let it work (and let the timeout sweep resolve it).
- "cancel_replace": the in-flight order points the other way, or has outlived timeout_bars - cancel its tickets, then submit fresh.
resolve_risk_exit_permission ¶
resolve_risk_exit_permission(mode: str, allow_live_orders: bool, broker_config_present: bool) -> tuple[bool, str]
May a real order close risk while a lock is active? resolve_order_permission with the lock taken as healthy: a lock
stops new risk, and must not also stop the orders that take risk off, or a tripped book freezes open in paper and live
while a backtest liquidates it. Observation still places nothing.
resolve_runtime_mode ¶
resolve_runtime_mode(raw_mode: str | None) -> str
Normalize a config-supplied mode value, failing safe to observation.
resolve_secret ¶
resolve_secret(name: str, *, account_id: str | None = None, env: Mapping[str, str], read_file: Callable[[str], str | None], keyring_get: Callable[[str, str], str | None] | None = None) -> ResolvedSecret
The first non-empty value along default_refs. A file's trailing newline is dropped; a reader that raises counts as
"not there", never as a crash.
resolve_slippage_bps ¶
resolve_slippage_bps(symbol_key: str, slippage_bps_by_symbol: dict[str, Any], max_bps: float = MAX_LIQUIDITY_SLIPPAGE_BPS) -> float
Pure lookup + clamp: how many bps of slippage to charge symbol_key, given the per-symbol bps dict main.py refreshes every bar in on_data()'s Pass 2 (liquidity_cost_fraction()'s selected field, converted to bps). Shared by resolve_fill_slippage() below (real Lean fills) and main.py's observation-mode SimulatedPortfolioState.enter_long() call sites, so both paths apply the identical clamp.
Missing symbol -> 0.0 bps (no liquidity estimate computed yet, e.g. an order placed before Pass 2 has run for it once). Clamped to max_bps (phase_v2.liquidity.fill_slippage.max_bps, defaulting to MAX_LIQUIDITY_SLIPPAGE_BPS) as a guard against a degenerate estimate corrupting a fill price. Non-finite estimates degrade to 0.0 (V5.4.5, Problems.md #117) - max/min pass NaN through untouched, so the clamp alone would not.
resolve_thresholds ¶
resolve_thresholds(raw: Mapping[str, Any] | None) -> dict[str, float]
The defaults, each replaced by a finite number from config (phase_v2.live_readiness.thresholds).
route_aware_fee_bps ¶
route_aware_fee_bps(override: dict[str, Any]) -> float | None
The route-aware per-side fee of a fee_by_type entry, or None when it carries no enabled route_aware block.
route_aware_per_side_fee_bps ¶
route_aware_per_side_fee_bps(route_config: dict[str, Any]) -> float
Per-side fee of a round trip from fee_by_type.<class>.route_aware {maker_bps, taker_bps, entry_limit, exit_limit,
fill_rate, exit_fill_rate (default fill_rate)}: the mean of the entry side and the exit side, each priced by its own
route.
secret_status ¶
secret_status(resolved: Iterable[ResolvedSecret]) -> list[dict[str, str | bool]]
Names and sources only, never values: what aq secrets status prints and the readiness scorecard reads. A secret
from a file or the keyring counts as stored_safely; one from a plain environment variable does not.
should_clear_pending_limit_order ¶
should_clear_pending_limit_order(status: str, all_legs_filled: bool) -> bool
Mirrors on_order_event()'s clearing decision: a tracked pending- limit-order record should be POPPED (stop tracking it) only when it's genuinely resolved - "filled" (and only once every leg of a multi-leg combo has filled, not on the first leg alone) or "canceled". Every other status - "pending", "unknown", and critically "PartiallyFilled" (which classify_order_status() maps to "pending") - returns False, so a partial fill leaves the record tracked for resolve_limit_order_timeout_action() to eventually resolve, exactly as main.py's own on_order_event() docstring already documents.
all_legs_filled is irrelevant (never even inspected) unless
status == "filled" - a "canceled" leg always clears regardless of the
other legs' state, matching main.py's existing elif branch.
should_skip_for_open_order ¶
should_skip_for_open_order(open_order_quantity: float, has_tracked_pending_limit: bool) -> bool
V5.5.0 (Problems.md #133) - an UNTRACKED order is already working for this symbol (e.g. the market fallback _process_pending_limit_order_timeouts() just sent after cancelling a limit order, which also pops the pending record), so entering again would stack a second one. In the 2026-10-07 backtest the same bar then also submitted a fresh limit order: 26 times a market-on-open and a limit order were created together, and in several (TLT -26/-27, -44/-45 shares) BOTH filled, doubling the position. A TRACKED pending limit order is left to resolve_pending_order_action() (keep / cancel-replace). Non-finite quantities count as 'nothing open'.
simulate_fill ¶
simulate_fill(close_price: float, target_weight: float, equity: float, slippage_bps: float = 0.0) -> dict[str, Any]
Pure hypothetical fill-price/quantity/notional math.
Quantity/notional are purely a function of the target portfolio weight, current equity, and fill price - the same math applies whether the caller is entering, exiting (target_weight=0.0), or liquidating.
slippage_amount ¶
slippage_amount(reference_price: float, slippage_bps: float) -> float
Absolute per-unit price slippage for a given bps estimate.
Shared by main.py's Lean SlippageModel (real backtest/live fills, wired
via security.SetSlippageModel()) and simulate_fill() below
(observation-mode simulated fills), so both paths apply the exact same
bps -> price-impact math instead of two independently-drifting
formulas. Returns 0.0 for a non-positive or non-finite price/bps -
slippage is never negative (never improves the fill price), and a NaN
estimate must never reach a fill price (V5.4.5, Problems.md #117:
nan <= 0 is False, so the old guard let NaN straight into
price * nan).
slippage_reference_price ¶
slippage_reference_price(submit_price: float | None, fill_bar_open: float | None, submitted_at: datetime | None = None, filled_at: datetime | None = None, immediate_fill_seconds: float = IMMEDIATE_FILL_SECONDS) -> tuple[float | None, str]
V5.8.0 (todo lead 3): which price a fill's slippage is measured from. An order that fills within
immediate_fill_seconds of its submission (crypto/forex, an open exchange) fills at the price it saw: its reference
is the submission price. An order queued past the close fills at the next session's open: its reference is that fill
bar's open (#88/#96 - against the submission price it would measure the overnight gap). Without timestamps or a
submission price the fill bar's open is used, the pre-V5.8.0 rule. Returns (price, "submit" | "fill_bar_open").
tag_audit_event ¶
tag_audit_event(event: Mapping[str, Any], account: Account) -> dict[str, Any]
The event with payload.account_id set for a named account; the default account's events are left as they are.