4ffde8cc06
- Database migration 018 with 13 tables for trading engine state - Trading engine service (services/trading/) with 12 pure computation modules: position sizer, stop-loss manager, reserve pool, circuit breaker, risk tier controller, correlation matrix, tax lots, trading window, gradual entry, notifications, micro-trading, backtester - Core TradingEngine with pre-trade evaluation pipeline and integration wiring - FastAPI HTTP service with 14 endpoints (health, config, decisions, metrics, backtest) - Performance tracker with Sharpe ratio, drawdown, profit factor computation - 194 Python tests (165 property-based + 29 integration) - Frontend: 13 TanStack Query hooks, 7 dashboard panels, tabbed Trading Engine page - Helm chart entry, network policy, nginx proxy, ingress for trading-engine - Shared infrastructure: enums, Redis keys, TradingConfig in AppConfig
113 lines
3.8 KiB
Python
113 lines
3.8 KiB
Python
"""Reserve Pool Controller — pure computation module.
|
||
|
||
Manages the untouchable cash reserve that grows from realized profits.
|
||
All methods are pure computations; persistence is handled by the caller.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from services.trading.models import ReservePoolState # noqa: F401 — re-export for convenience
|
||
|
||
|
||
class ReservePoolController:
|
||
"""Compute reserve-pool operations without touching the database.
|
||
|
||
Parameters
|
||
----------
|
||
siphon_pct:
|
||
Fraction of realized profit transferred to the reserve on each
|
||
profitable position close (default 20 %).
|
||
high_water_pct:
|
||
When the reserve exceeds this fraction of total portfolio value
|
||
the risk-tier controller should consider upgrading (default 30 %).
|
||
"""
|
||
|
||
def __init__(
|
||
self,
|
||
siphon_pct: float = 0.20,
|
||
high_water_pct: float = 0.30,
|
||
) -> None:
|
||
self.siphon_pct = siphon_pct
|
||
self.high_water_pct = high_water_pct
|
||
|
||
# ------------------------------------------------------------------
|
||
# Profit siphoning
|
||
# ------------------------------------------------------------------
|
||
|
||
def siphon_profit(
|
||
self,
|
||
realized_profit: float,
|
||
current_balance: float,
|
||
) -> tuple[float, float]:
|
||
"""Compute the amount to transfer into the reserve pool.
|
||
|
||
Only positive profits are siphoned.
|
||
|
||
Returns
|
||
-------
|
||
(transfer_amount, new_balance)
|
||
*transfer_amount* is ``realized_profit * siphon_pct`` when
|
||
the profit is positive, otherwise ``0.0``.
|
||
*new_balance* is ``current_balance + transfer_amount``.
|
||
"""
|
||
if realized_profit <= 0:
|
||
return 0.0, current_balance
|
||
|
||
transfer = realized_profit * self.siphon_pct
|
||
return transfer, current_balance + transfer
|
||
|
||
# ------------------------------------------------------------------
|
||
# Emergency liquidation
|
||
# ------------------------------------------------------------------
|
||
|
||
def emergency_liquidate(self, current_balance: float) -> float:
|
||
"""Return the full reserve balance to be released into the active pool.
|
||
|
||
The caller is responsible for zeroing the persisted balance and
|
||
recording the ledger entry.
|
||
|
||
Returns
|
||
-------
|
||
float
|
||
The amount to release (equal to *current_balance*).
|
||
"""
|
||
return current_balance
|
||
|
||
# ------------------------------------------------------------------
|
||
# Active pool computation
|
||
# ------------------------------------------------------------------
|
||
|
||
def compute_active_pool(
|
||
self,
|
||
total_portfolio_value: float,
|
||
reserve_balance: float,
|
||
) -> float:
|
||
"""Active Pool = total portfolio value − reserve balance."""
|
||
return total_portfolio_value - reserve_balance
|
||
|
||
# ------------------------------------------------------------------
|
||
# High-water mark detection
|
||
# ------------------------------------------------------------------
|
||
|
||
def is_high_water(
|
||
self,
|
||
reserve_balance: float,
|
||
total_portfolio_value: float,
|
||
) -> bool:
|
||
"""Return ``True`` when the reserve exceeds *high_water_pct* of total portfolio."""
|
||
if total_portfolio_value <= 0:
|
||
return False
|
||
return reserve_balance > self.high_water_pct * total_portfolio_value
|
||
|
||
# ------------------------------------------------------------------
|
||
# Emergency liquidation trigger check
|
||
# ------------------------------------------------------------------
|
||
|
||
def should_emergency_liquidate(
|
||
self,
|
||
current_drawdown_pct: float,
|
||
emergency_threshold_pct: float,
|
||
) -> bool:
|
||
"""Return ``True`` when drawdown exceeds the emergency threshold."""
|
||
return current_drawdown_pct > emergency_threshold_pct
|