"""Gradual entry logic for the autonomous trading engine. Pure computation module that determines whether an order should be split into multiple tranches and performs the splitting. The ``GradualEntryManager`` class (which tracks pending tranches at runtime and re-evaluates conditions) is intentionally left as a thin wrapper here — the core logic is in the pure functions below. """ from __future__ import annotations from dataclasses import dataclass # --------------------------------------------------------------------------- # Tranche dataclass # --------------------------------------------------------------------------- @dataclass class Tranche: """A single tranche within a gradual-entry order sequence.""" tranche_index: int quantity: int parent_decision_id: str status: str = "pending" # --------------------------------------------------------------------------- # Pure computation helpers # --------------------------------------------------------------------------- def should_use_gradual_entry( position_size_dollars: float, active_pool: float, threshold_dollars: float = 30.0, ) -> bool: """Return True when the position size exceeds the gradual-entry threshold. The effective threshold is ``min(threshold_dollars, 5% of active_pool)``. """ effective_threshold = min(threshold_dollars, 0.05 * active_pool) return position_size_dollars > effective_threshold def split_into_tranches(total_quantity: int, num_tranches: int = 3) -> list[int]: """Split *total_quantity* into *num_tranches* approximately equal parts. The remainder is distributed one unit at a time to the first tranches so that: * ``sum(result) == total_quantity`` * All values differ by at most 1 """ if num_tranches <= 0: return [] if total_quantity <= 0: return [0] * num_tranches base, remainder = divmod(total_quantity, num_tranches) return [base + (1 if i < remainder else 0) for i in range(num_tranches)] def create_tranches( total_quantity: int, parent_decision_id: str, num_tranches: int = 3, ) -> list[Tranche]: """Create :class:`Tranche` objects linked to *parent_decision_id*. Uses :func:`split_into_tranches` for the quantity distribution. """ quantities = split_into_tranches(total_quantity, num_tranches) return [ Tranche( tranche_index=i, quantity=q, parent_decision_id=parent_decision_id, ) for i, q in enumerate(quantities) ]