from __future__ import annotations import json from pathlib import Path from fastapi.testclient import TestClient from drift_quant.api.app import app def test_api_v2_endpoints(tmp_path: Path, monkeypatch: object) -> None: # Set up realistic artifact folder experiments = tmp_path / "experiments" experiments.mkdir(parents=True) cache = tmp_path / "cache" cache.mkdir(parents=True) exp_id = "test-exp-001" index = [ { "experiment_id": exp_id, "strategy_name": "buy_and_hold_baseline", "strategy_version": "1.0.0", "dataset_id": "test_ds", "period_start": "2024-01-01 09:15:00", "period_end_exclusive": "2024-01-10 15:30:00", "metrics": { "cumulative_return": 0.05, "maximum_drawdown": -0.02, "sharpe_ratio": 1.5, "trade_count": 2, "transaction_costs": 150.0, }, "currency": "INR", } ] exp_payload = { **index[0], "config": {"initial_capital": 100000.0, "max_gross_exposure": 0.95}, "equity_curve": [ {"timestamp": "2024-01-01 09:15:00", "equity": 100000.0, "gross_exposure": 0.0}, {"timestamp": "2024-01-02 09:15:00", "equity": 102000.0, "gross_exposure": 95000.0}, {"timestamp": "2024-01-03 09:15:00", "equity": 105000.0, "gross_exposure": 0.0}, ], "trades": [ { "symbol": "RELIANCE", "entry_time": "2024-01-01 09:30:00", "exit_time": "2024-01-03 15:15:00", "quantity": 50, "entry_price": 2000.0, "exit_price": 2100.0, "gross_pnl": 5000.0, "costs": 100.0, "net_pnl": 4900.0, "exit_reason": "strategy_signal", } ], } (experiments / "index.json").write_text(json.dumps(index), encoding="utf-8") (experiments / f"{exp_id}.json").write_text(json.dumps(exp_payload), encoding="utf-8") audit = { "rows": 17808743, "symbols": 488, "archive_bytes": 260079380, "archive_sha256": "039c081e", "first_timestamp": "2019-01-01 09:15:00", "last_timestamp": "2025-07-14 11:00:00", "zero_volume_rows": 34867, "invalid_ohlc_rows": 72, "intraday_unexpected_gaps": 4894, "symbol_stats": { "RELIANCE": { "rows": 39653, "first_timestamp": "2019-01-01 09:15:00", "last_timestamp": "2025-07-14 11:00:00", "zero_volume_rows": 0, "invalid_ohlc_rows": 0, "intraday_unexpected_gaps": 5, "bars_by_weekday": {"Monday": 7810, "Tuesday": 7975}, } }, } (tmp_path / "dataset_audit.json").write_text(json.dumps(audit), encoding="utf-8") monkeypatch.setenv("DRIFT_ARTIFACTS_DIR", str(tmp_path)) # type: ignore[attr-defined] client = TestClient(app) # 1. Health res = client.get("/health") assert res.status_code == 200 assert res.json()["currency"] == "INR" # 2. Dataset summary res = client.get("/api/v1/dataset/summary") assert res.status_code == 200 assert res.json()["total_rows"] == 17808743 assert res.json()["currency"] == "INR" # 3. Symbols catalog res = client.get("/api/v1/dataset/symbols") assert res.status_code == 200 symbols = res.json() assert len(symbols) == 1 assert symbols[0]["symbol"] == "RELIANCE" assert symbols[0]["sector"] == "Energy" # 4. Coverage timeline res = client.get("/api/v1/dataset/coverage-timeline") assert res.status_code == 200 assert len(res.json()["yearly"]) > 0 # 5. Strategies catalog res = client.get("/api/v1/strategies") assert res.status_code == 200 strategies = res.json() assert any(s["name"] == "sector_pairs_reversion" for s in strategies) assert any(s["name"] == "sector_cross_momentum" for s in strategies) # 6. Attribution res = client.get(f"/api/v1/experiments/{exp_id}/attribution") assert res.status_code == 200 attr = res.json() assert len(attr) == 1 assert attr[0]["symbol"] == "RELIANCE" assert attr[0]["net_pnl"] == 4900.0 # 7. Drawdown res = client.get(f"/api/v1/experiments/{exp_id}/drawdown") assert res.status_code == 200 assert len(res.json()) == 3 # 8. Monthly matrix res = client.get(f"/api/v1/experiments/{exp_id}/monthly") assert res.status_code == 200 assert "2024" in res.json()["years"] # 9. CSV Export trades res = client.get(f"/api/v1/reports/{exp_id}/export-csv?kind=trades") assert res.status_code == 200 assert "text/csv" in res.headers["content-type"] assert "RELIANCE" in res.text # 10. CSV Export equity res = client.get(f"/api/v1/reports/{exp_id}/export-csv?kind=equity") assert res.status_code == 200 assert "timestamp,equity" in res.text