Files
crypto_trading/backend/tests/test_api.py
T
matitos 9c3bee87ac
CI/CD / backend (push) Successful in 5m18s
CI/CD / frontend (push) Successful in 5m2s
CI/CD / build (push) Successful in 34s
CI/CD / cleanup (push) Successful in 6s
CI/CD / deploy (push) Successful in 22s
Crypto trading bot: engine, brokers, backtester, dashboard, deploy
FastAPI backend with a single-strategy async engine, paper and Binance
brokers, pure-python indicators, a backtester that shares the engine's
portfolio math, and a Vue dashboard with a live WebSocket feed. Adds the
Gitea Actions CI/CD workflow that deploys to Traefik via docker_default.
2026-09-18 17:02:33 +00:00

85 lines
3.1 KiB
Python

from __future__ import annotations
from fastapi.testclient import TestClient
from app.main import create_app
from app.market.fake import FakeMarketData
from app.runtime import Runtime
def test_health_and_strategies(runtime: Runtime) -> None:
app = create_app(runtime.settings, runtime)
with TestClient(app) as client:
assert client.get("/api/health").json() == {"status": "ok"}
keys = {s["key"] for s in client.get("/api/strategies").json()}
assert {"sma_cross", "rsi_reversion"} <= keys
def test_start_status_stop_flow(runtime: Runtime) -> None:
app = create_app(runtime.settings, runtime)
with TestClient(app) as client:
status = client.get("/api/status").json()
assert status["running"] is False
started = client.post(
"/api/bot/start",
json={"strategy_key": "sma_cross", "params": {"fast": 2, "slow": 4}},
)
assert started.status_code == 200
assert started.json()["running"] is True
assert client.get("/api/positions").status_code == 200
assert client.get("/api/orders").status_code == 200
assert client.get("/api/events").status_code == 200
stopped = client.post("/api/bot/stop").json()
assert stopped["running"] is False
def test_unknown_strategy_returns_404(runtime: Runtime) -> None:
app = create_app(runtime.settings, runtime)
with TestClient(app) as client:
response = client.post("/api/bot/start", json={"strategy_key": "does_not_exist"})
assert response.status_code == 404
def test_backtest_endpoint(runtime: Runtime, market: FakeMarketData) -> None:
market.candles = FakeMarketData.sine_wave(200).candles
app = create_app(runtime.settings, runtime)
with TestClient(app) as client:
response = client.post(
"/api/backtest",
json={"strategy_key": "sma_cross", "params": {"fast": 5, "slow": 20}, "limit": 200},
)
assert response.status_code == 200
data = response.json()
assert data["strategy_key"] == "sma_cross"
assert data["error"] is None
assert len(data["equity_curve"]) == 200
assert "total_return_pct" in data["metrics"]
assert data["metrics"]["num_trades"] >= 1
def test_backtest_unknown_strategy_404(runtime: Runtime) -> None:
app = create_app(runtime.settings, runtime)
with TestClient(app) as client:
response = client.post("/api/backtest", json={"strategy_key": "nope"})
assert response.status_code == 404
def test_backtest_limit_validation(runtime: Runtime) -> None:
app = create_app(runtime.settings, runtime)
with TestClient(app) as client:
assert (
client.post("/api/backtest", json={"strategy_key": "sma_cross", "limit": 5}).status_code
== 422
)
def test_websocket_sends_initial_status(runtime: Runtime) -> None:
app = create_app(runtime.settings, runtime)
with TestClient(app) as client, client.websocket_connect("/api/ws") as websocket:
message = websocket.receive_json()
assert message["type"] == "status"
assert message["data"]["running"] is False