68 lines
2.2 KiB
Python
68 lines
2.2 KiB
Python
"""Web smoke for the paper cockpit: /paper renders equity + a position; /paper/live returns updated MTM;
|
|
empty live prices degrade gracefully (never 500)."""
|
|
from __future__ import annotations
|
|
|
|
import datetime as dt
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from fxhnt.adapters.persistence.paper_repo import PaperRepo
|
|
from fxhnt.adapters.web.app import create_app
|
|
from fxhnt.application.paper_book import PaperBookService
|
|
from fxhnt.ports.live_price import FakeLivePrice
|
|
|
|
|
|
def _seeded_repo() -> PaperRepo:
|
|
repo = PaperRepo("sqlite://")
|
|
repo.migrate()
|
|
svc = PaperBookService(repo, capital=100_000.0)
|
|
svc.derive_and_persist(
|
|
run_date="2026-06-21",
|
|
sleeve_weights={"stablecoin_rotation": 0.5},
|
|
symbol_weights_by_sleeve={"stablecoin_rotation": {"USDTUSD": -1.0}},
|
|
prices={"USDTUSD": 2.0},
|
|
at=dt.datetime(2026, 6, 21, tzinfo=dt.UTC))
|
|
return repo
|
|
|
|
|
|
def _client(live: FakeLivePrice) -> TestClient:
|
|
repo = _seeded_repo()
|
|
# Forward-nav repo only feeds the existing fleet routes; the paper routes use paper_repo + live.
|
|
from fxhnt.adapters.persistence.forward_nav import ForwardNavRepo
|
|
fwd = ForwardNavRepo("sqlite://")
|
|
fwd.migrate()
|
|
return TestClient(create_app(fwd, paper_repo=repo, live=live))
|
|
|
|
|
|
def test_paper_page_renders_equity_and_position() -> None:
|
|
c = _client(FakeLivePrice({"USDTUSD": 1.9})) # short profits as price fell
|
|
r = c.get("/paper")
|
|
assert r.status_code == 200
|
|
assert "Paper" in r.text
|
|
assert "USDTUSD" in r.text
|
|
assert "equity" in r.text.lower()
|
|
|
|
|
|
def test_paper_live_partial_returns_updated_mtm() -> None:
|
|
c = _client(FakeLivePrice({"USDTUSD": 1.9}))
|
|
r = c.get("/paper/live")
|
|
assert r.status_code == 200
|
|
assert "equity" in r.text.lower()
|
|
assert "USDTUSD" in r.text
|
|
|
|
|
|
def test_paper_degrades_gracefully_with_empty_prices() -> None:
|
|
c = _client(FakeLivePrice({})) # no live prices at all
|
|
r = c.get("/paper")
|
|
assert r.status_code == 200
|
|
r2 = c.get("/paper/live")
|
|
assert r2.status_code == 200
|
|
|
|
|
|
def test_fleet_page_links_to_paper() -> None:
|
|
c = _client(FakeLivePrice({"USDTUSD": 1.9}))
|
|
r = c.get("/")
|
|
assert r.status_code == 200
|
|
assert "/paper" in r.text
|