feat: API gateway trading endpoints, controls, backtest, WebSocket
This commit is contained in:
parent
e0d138c457
commit
6fe586f722
11 changed files with 1304 additions and 0 deletions
111
services/api_gateway/routes/strategies.py
Normal file
111
services/api_gateway/routes/strategies.py
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
"""Strategy endpoints — list strategies, weight history, metrics."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
||||
|
||||
from services.api_gateway.auth.middleware import get_current_user
|
||||
from sqlalchemy import select, desc
|
||||
|
||||
router = APIRouter(prefix="/api/strategies", tags=["strategies"])
|
||||
|
||||
|
||||
@router.get("")
|
||||
async def list_strategies(
|
||||
request: Request,
|
||||
_user: dict = Depends(get_current_user),
|
||||
) -> list[dict]:
|
||||
"""All strategies with current weights."""
|
||||
from shared.models.trading import Strategy
|
||||
|
||||
db = request.app.state.db_session_factory
|
||||
async with db() as session:
|
||||
result = await session.execute(select(Strategy))
|
||||
strategies = result.scalars().all()
|
||||
|
||||
return [
|
||||
{
|
||||
"id": str(s.id),
|
||||
"name": s.name,
|
||||
"description": s.description,
|
||||
"current_weight": s.current_weight,
|
||||
"active": s.active,
|
||||
"created_at": s.created_at.isoformat() if s.created_at else None,
|
||||
}
|
||||
for s in strategies
|
||||
]
|
||||
|
||||
|
||||
@router.get("/{strategy_id}/history")
|
||||
async def get_strategy_weight_history(
|
||||
strategy_id: UUID,
|
||||
request: Request,
|
||||
_user: dict = Depends(get_current_user),
|
||||
) -> list[dict]:
|
||||
"""Weight history for a specific strategy."""
|
||||
from shared.models.trading import StrategyWeightHistory, Strategy
|
||||
|
||||
db = request.app.state.db_session_factory
|
||||
async with db() as session:
|
||||
# Verify strategy exists
|
||||
strategy = (
|
||||
await session.execute(
|
||||
select(Strategy).where(Strategy.id == strategy_id)
|
||||
)
|
||||
).scalar_one_or_none()
|
||||
if strategy is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Strategy not found",
|
||||
)
|
||||
|
||||
result = await session.execute(
|
||||
select(StrategyWeightHistory)
|
||||
.where(StrategyWeightHistory.strategy_id == strategy_id)
|
||||
.order_by(desc(StrategyWeightHistory.created_at))
|
||||
)
|
||||
history = result.scalars().all()
|
||||
|
||||
return [
|
||||
{
|
||||
"id": str(h.id),
|
||||
"old_weight": h.old_weight,
|
||||
"new_weight": h.new_weight,
|
||||
"reason": h.reason,
|
||||
"created_at": h.created_at.isoformat() if h.created_at else None,
|
||||
}
|
||||
for h in history
|
||||
]
|
||||
|
||||
|
||||
@router.get("/{strategy_id}/metrics")
|
||||
async def get_strategy_metrics(
|
||||
strategy_id: UUID,
|
||||
request: Request,
|
||||
_user: dict = Depends(get_current_user),
|
||||
) -> list[dict]:
|
||||
"""Performance metrics over time for a specific strategy."""
|
||||
from shared.models.timeseries import StrategyMetric
|
||||
|
||||
db = request.app.state.db_session_factory
|
||||
async with db() as session:
|
||||
result = await session.execute(
|
||||
select(StrategyMetric)
|
||||
.where(StrategyMetric.strategy_id == strategy_id)
|
||||
.order_by(desc(StrategyMetric.timestamp))
|
||||
.limit(100)
|
||||
)
|
||||
metrics = result.scalars().all()
|
||||
|
||||
return [
|
||||
{
|
||||
"timestamp": m.timestamp.isoformat(),
|
||||
"win_rate": m.win_rate,
|
||||
"total_pnl": m.total_pnl,
|
||||
"trade_count": m.trade_count,
|
||||
"sharpe_ratio": m.sharpe_ratio,
|
||||
}
|
||||
for m in metrics
|
||||
]
|
||||
Loading…
Add table
Add a link
Reference in a new issue