Files
stonks-oracle/services/trading/reserve_pool.py
T
Celes Renata 4ffde8cc06 feat: autonomous trading engine — full implementation
- 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
2026-04-15 16:12:22 +00:00

113 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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