Initial commit
This commit is contained in:
118
backend/app/api/endpoints/trades.py
Normal file
118
backend/app/api/endpoints/trades.py
Normal file
@@ -0,0 +1,118 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select
|
||||
from typing import List, Optional
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.models.models import TradeHistory
|
||||
from pydantic import BaseModel
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
class TradeHistoryResponse(BaseModel):
|
||||
id: int
|
||||
rule_id: Optional[int]
|
||||
stock_code: str
|
||||
stock_name: Optional[str]
|
||||
order_type: str
|
||||
order_price: Optional[Decimal]
|
||||
order_quantity: int
|
||||
executed_price: Optional[Decimal]
|
||||
executed_quantity: Optional[int]
|
||||
status: str
|
||||
order_id: Optional[str]
|
||||
message: Optional[str]
|
||||
created_at: datetime
|
||||
executed_at: Optional[datetime]
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
@router.get("", response_model=List[TradeHistoryResponse])
|
||||
async def get_trade_history(
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
stock_code: Optional[str] = None,
|
||||
status: Optional[str] = None,
|
||||
order_type: Optional[str] = None,
|
||||
days: int = 30,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""거래 이력 조회"""
|
||||
query = select(TradeHistory)
|
||||
|
||||
# 날짜 필터
|
||||
since_date = datetime.utcnow() - timedelta(days=days)
|
||||
query = query.where(TradeHistory.created_at >= since_date)
|
||||
|
||||
# 종목 코드 필터
|
||||
if stock_code:
|
||||
query = query.where(TradeHistory.stock_code == stock_code)
|
||||
|
||||
# 상태 필터
|
||||
if status:
|
||||
query = query.where(TradeHistory.status == status)
|
||||
|
||||
# 주문 유형 필터
|
||||
if order_type:
|
||||
query = query.where(TradeHistory.order_type == order_type)
|
||||
|
||||
query = query.order_by(TradeHistory.created_at.desc())
|
||||
query = query.offset(skip).limit(limit)
|
||||
|
||||
result = await db.execute(query)
|
||||
trades = result.scalars().all()
|
||||
return trades
|
||||
|
||||
|
||||
@router.get("/{trade_id}", response_model=TradeHistoryResponse)
|
||||
async def get_trade(trade_id: int, db: AsyncSession = Depends(get_db)):
|
||||
"""특정 거래 조회"""
|
||||
result = await db.execute(select(TradeHistory).where(TradeHistory.id == trade_id))
|
||||
trade = result.scalar_one_or_none()
|
||||
|
||||
if not trade:
|
||||
raise HTTPException(status_code=404, detail="Trade not found")
|
||||
|
||||
return trade
|
||||
|
||||
|
||||
@router.get("/stats/summary")
|
||||
async def get_trade_stats(
|
||||
days: int = 30,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""거래 통계 조회"""
|
||||
since_date = datetime.utcnow() - timedelta(days=days)
|
||||
|
||||
result = await db.execute(
|
||||
select(TradeHistory).where(TradeHistory.created_at >= since_date)
|
||||
)
|
||||
trades = result.scalars().all()
|
||||
|
||||
total_trades = len(trades)
|
||||
buy_trades = len([t for t in trades if t.order_type == "BUY"])
|
||||
sell_trades = len([t for t in trades if t.order_type == "SELL"])
|
||||
executed_trades = len([t for t in trades if t.status == "EXECUTED"])
|
||||
failed_trades = len([t for t in trades if t.status == "FAILED"])
|
||||
|
||||
# 총 거래 금액 계산
|
||||
total_amount = sum(
|
||||
float(t.executed_price or 0) * (t.executed_quantity or 0)
|
||||
for t in trades if t.status == "EXECUTED"
|
||||
)
|
||||
|
||||
return {
|
||||
"period_days": days,
|
||||
"total_trades": total_trades,
|
||||
"buy_trades": buy_trades,
|
||||
"sell_trades": sell_trades,
|
||||
"executed_trades": executed_trades,
|
||||
"failed_trades": failed_trades,
|
||||
"success_rate": executed_trades / total_trades if total_trades > 0 else 0,
|
||||
"total_amount": total_amount
|
||||
}
|
||||
Reference in New Issue
Block a user