Multi-strategy engine with per-strategy capital allocation

Adds MultiStrategyManager: it runs several strategies concurrently, each with
its own TradingEngine seeded with starting_balance * allocation, so one
strategy's losses cannot eat into another's capital. Weights are normalised
across the run ([1,3] -> 25%/75%). Risk limits stay per strategy (each engine
owns a RiskManager).

New API: POST /api/bot/start-many and GET /api/bot/status. The existing
single-strategy endpoints delegate to the manager, so their behaviour is
unchanged. Adds manager tests (allocation, isolation, duplicate keys) and API
tests.
This commit is contained in:
matitos committed 2026-09-21 20:10:28 +00:00
1 parent e07536542f
commit 8b6cf8130c
6 files changed
+469 -28

No files matched your search

+17
View File
@@ -18,8 +18,10 @@ from app.schemas import (
EventOut,
KillRequest,
ManualOrderRequest,
MultiStatusOut,
OrderOut,
PositionOut,
StartManyRequest,
StartRequest,
StatusOut,
StrategyConfigIn,
@@ -96,6 +98,21 @@ async def start_bot(payload: StartRequest, runtime: GuardedRuntimeDep) -> Status
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.get("/bot/status", response_model=MultiStatusOut)
def multi_status(runtime: GuardedRuntimeDep) -> MultiStatusOut:
return runtime.multi_status()
@router.post("/bot/start-many", response_model=MultiStatusOut)
async def start_many(payload: StartManyRequest, runtime: GuardedRuntimeDep) -> MultiStatusOut:
try:
return await runtime.start_many(payload)
except KeyError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except (ValueError, RuntimeError) as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.post("/bot/stop", response_model=StatusOut)
async def stop_bot(runtime: GuardedRuntimeDep) -> StatusOut:
return await runtime.stop()