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:
@@ -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
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user