Automated Action b7f18dcaec Add CRUD endpoints for opportunities, trades, and system events
- Add GET endpoint for individual arbitrage opportunities
- Add POST endpoint for creating arbitrage opportunities
- Add GET endpoint for individual trades
- Add POST endpoint for creating trades
- Add endpoints for system events (GET list, GET by ID, POST)
- Update API router to include the new events endpoints
- Fix linting issues
2025-06-05 19:43:15 +00:00

97 lines
3.7 KiB
Python

from datetime import datetime
from typing import Any, Optional
from fastapi import APIRouter, Depends, Query, HTTPException, status
from sqlalchemy.orm import Session
from sqlalchemy import desc
from app.db.session import get_db
from app.models.arbitrage import ArbitrageOpportunity
from app.schemas.arbitrage import OpportunitiesList, ArbitrageOpportunityCreate, ArbitrageOpportunity as ArbitrageOpportunitySchema
router = APIRouter()
@router.get("", response_model=OpportunitiesList)
async def get_arbitrage_opportunities(
viable_only: bool = Query(True, description="Show only viable opportunities that meet profit threshold"),
token_address: Optional[str] = Query(None, description="Filter by specific token address"),
min_profit_percent: Optional[float] = Query(None, description="Filter by minimum profit percentage"),
limit: int = Query(20, ge=1, le=100, description="Number of opportunities to return"),
offset: int = Query(0, ge=0, description="Pagination offset"),
db: Session = Depends(get_db)
) -> Any:
"""
Retrieve arbitrage opportunities with optional filtering.
"""
query = db.query(ArbitrageOpportunity)
# Apply filters
if viable_only:
query = query.filter(ArbitrageOpportunity.is_viable.is_(True))
if token_address:
query = query.filter(ArbitrageOpportunity.token_address == token_address)
if min_profit_percent is not None:
query = query.filter(ArbitrageOpportunity.price_difference_percent >= min_profit_percent)
# Get total count
total_count = query.count()
# Get paginated results
opportunities = query.order_by(desc(ArbitrageOpportunity.created_at)).offset(offset).limit(limit).all()
return {
"opportunities": opportunities,
"count": total_count,
"timestamp": datetime.utcnow()
}
@router.get("/{opportunity_id}", response_model=ArbitrageOpportunitySchema)
async def get_arbitrage_opportunity(
opportunity_id: int,
db: Session = Depends(get_db)
) -> Any:
"""
Get a specific arbitrage opportunity by ID.
"""
opportunity = db.query(ArbitrageOpportunity).filter(ArbitrageOpportunity.id == opportunity_id).first()
if not opportunity:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Arbitrage opportunity with ID {opportunity_id} not found"
)
return opportunity
@router.post("", response_model=ArbitrageOpportunitySchema, status_code=status.HTTP_201_CREATED)
async def create_arbitrage_opportunity(
opportunity_in: ArbitrageOpportunityCreate,
db: Session = Depends(get_db)
) -> Any:
"""
Create a new arbitrage opportunity.
"""
db_opportunity = ArbitrageOpportunity(
token_address=opportunity_in.token_address,
token_symbol=opportunity_in.token_symbol,
source_dex=opportunity_in.source_dex,
target_dex=opportunity_in.target_dex,
source_price=opportunity_in.source_price,
target_price=opportunity_in.target_price,
price_difference=opportunity_in.price_difference,
price_difference_percent=opportunity_in.price_difference_percent,
estimated_profit_usd=opportunity_in.estimated_profit_usd,
estimated_profit_token=opportunity_in.estimated_profit_token,
max_trade_amount_usd=opportunity_in.max_trade_amount_usd,
max_trade_amount_token=opportunity_in.max_trade_amount_token,
slippage_estimate=opportunity_in.slippage_estimate,
fees_estimate=opportunity_in.fees_estimate,
is_viable=opportunity_in.is_viable,
was_executed=False
)
db.add(db_opportunity)
db.commit()
db.refresh(db_opportunity)
return db_opportunity