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:
1 parent
e07536542f
commit
8b6cf8130c
6 files changed
+469
-28
No files matched your search
@@ -111,6 +111,42 @@ def test_backtest_limit_validation(runtime: Runtime) -> None:
|
||||
)
|
||||
|
||||
|
||||
def test_start_many_and_multi_status(runtime: Runtime, market: FakeMarketData) -> None:
|
||||
app = create_app(runtime.settings, runtime)
|
||||
with TestClient(app) as client:
|
||||
started = client.post(
|
||||
"/api/bot/start-many",
|
||||
json={
|
||||
"strategies": [
|
||||
{"strategy_key": "sma_cross", "params": {"fast": 2, "slow": 4}, "weight": 1},
|
||||
{"strategy_key": "ema_cross", "params": {"fast": 2, "slow": 4}, "weight": 3},
|
||||
],
|
||||
"starting_balance": 10000,
|
||||
},
|
||||
)
|
||||
assert started.status_code == 200
|
||||
body = started.json()
|
||||
assert body["running"] is True
|
||||
assert len(body["strategies"]) == 2
|
||||
assert [s["allocation"] for s in body["strategies"]] == [0.25, 0.75]
|
||||
|
||||
status = client.get("/api/bot/status").json()
|
||||
assert status["running"] is True
|
||||
assert len(status["strategies"]) == 2
|
||||
assert status["equity"] == 10000
|
||||
|
||||
client.post("/api/bot/stop")
|
||||
|
||||
|
||||
def test_start_many_rejects_unknown_strategy(runtime: Runtime) -> None:
|
||||
app = create_app(runtime.settings, runtime)
|
||||
with TestClient(app) as client:
|
||||
response = client.post(
|
||||
"/api/bot/start-many", json={"strategies": [{"strategy_key": "nope"}]}
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_kill_endpoint(runtime: Runtime) -> None:
|
||||
app = create_app(runtime.settings, runtime)
|
||||
with TestClient(app) as client:
|
||||
|
||||
Reference in new issue
Block a user