feat: trading bot MVP — ICT Order Block + Liquidity Sweep strategy
Full-stack trading bot with: - FastAPI backend with ICT strategy (Order Block + Liquidity Sweep detection) - Backtester engine with rolling window, spread simulation, and performance metrics - Hybrid market data service (yfinance + TwelveData with rate limiting + SQLite cache) - Simulated exchange for paper trading - React/TypeScript frontend with TradingView lightweight-charts v5 - Live dashboard with candlestick chart, OHLC legend, trade markers - Backtest page with configurable parameters, equity curve, and trade table - WebSocket support for real-time updates - Bot runner with asyncio loop for automated trading Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
53
backend/app/api/routes/trades.py
Normal file
53
backend/app/api/routes/trades.py
Normal file
@@ -0,0 +1,53 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.models.trade import Trade
|
||||
|
||||
router = APIRouter(prefix="/trades", tags=["trades"])
|
||||
|
||||
|
||||
@router.get("")
|
||||
async def get_trades(
|
||||
source: Optional[str] = Query(default=None, description="live | backtest"),
|
||||
status: Optional[str] = Query(default=None, description="open | closed"),
|
||||
instrument: Optional[str] = Query(default=None),
|
||||
limit: int = Query(default=100, ge=1, le=1000),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
stmt = select(Trade).order_by(Trade.opened_at.desc()).limit(limit)
|
||||
if source:
|
||||
stmt = stmt.where(Trade.source == source)
|
||||
if status:
|
||||
stmt = stmt.where(Trade.status == status)
|
||||
if instrument:
|
||||
stmt = stmt.where(Trade.instrument == instrument)
|
||||
|
||||
result = await db.execute(stmt)
|
||||
trades = result.scalars().all()
|
||||
|
||||
return {
|
||||
"total": len(trades),
|
||||
"trades": [
|
||||
{
|
||||
"id": t.id,
|
||||
"source": t.source,
|
||||
"instrument": t.instrument,
|
||||
"direction": t.direction,
|
||||
"units": t.units,
|
||||
"entry_price": t.entry_price,
|
||||
"stop_loss": t.stop_loss,
|
||||
"take_profit": t.take_profit,
|
||||
"exit_price": t.exit_price,
|
||||
"pnl": t.pnl,
|
||||
"status": t.status,
|
||||
"signal_type": t.signal_type,
|
||||
"opened_at": str(t.opened_at),
|
||||
"closed_at": str(t.closed_at) if t.closed_at else None,
|
||||
}
|
||||
for t in trades
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user