feat: add paper trading capital controls — API endpoint + UI with presets, fix status/metrics to read real state, fix migration duplicates

This commit is contained in:
Celes Renata
2026-04-16 14:06:30 +00:00
parent 14e411daf9
commit 58a8726306
4 changed files with 156 additions and 4 deletions
+61
View File
@@ -50,6 +50,13 @@ class ConfigUpdateRequest(BaseModel):
absolute_position_cap: Optional[float] = None
active_pool_minimum: Optional[float] = None
micro_trading_enabled: Optional[bool] = None
max_open_positions: Optional[int] = None
class CapitalRequest(BaseModel):
"""Body for PUT /api/trading/capital."""
initial_capital: float
class BacktestRequest(BaseModel):
@@ -255,6 +262,60 @@ async def resume_engine() -> dict[str, bool]:
return {"paused": False}
@app.put("/api/trading/capital")
async def set_capital(body: CapitalRequest) -> dict[str, Any]:
"""Set or reset the paper trading capital.
Allocates the given amount as initial capital, splitting between
active pool and reserve pool based on the current reserve_siphon_pct.
"""
if engine is None:
raise HTTPException(503, "Engine not initialised")
capital = body.initial_capital
if capital <= 0:
raise HTTPException(400, "initial_capital must be positive")
reserve_pct = engine.config.reserve_siphon_pct
reserve = capital * reserve_pct
active = capital - reserve
ps = engine.portfolio_state
previous = {
"total_value": ps.total_value if ps else 0.0,
"active_pool": ps.active_pool if ps else 0.0,
"reserve_pool": ps.reserve_pool if ps else 0.0,
}
from services.trading.models import PortfolioState
engine.portfolio_state = PortfolioState(
total_value=capital,
cash=capital,
active_pool=active,
reserve_pool=reserve,
)
# Record in reserve pool ledger
if engine.pool:
try:
await engine.pool.execute(
"INSERT INTO reserve_pool_ledger (amount, balance_after, trigger_type, notes) "
"VALUES ($1, $2, 'capital_reset', $3)",
reserve, reserve,
f"Capital set to ${capital:,.2f} (active=${active:,.2f}, reserve=${reserve:,.2f})",
)
except Exception:
pass # Non-critical
return {
"initial_capital": capital,
"active_pool": active,
"reserve_pool": reserve,
"reserve_siphon_pct": reserve_pct,
"previous": previous,
}
# ---------------------------------------------------------------------------
# Decision Audit Trail
# ---------------------------------------------------------------------------