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
This commit is contained in:
parent
572a7c0dd0
commit
b7f18dcaec
@ -1,8 +1,9 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.api.api_v1.endpoints import status, opportunities, trades
|
||||
from app.api.api_v1.endpoints import status, opportunities, trades, events
|
||||
|
||||
api_router = APIRouter(prefix="/api/v1")
|
||||
api_router.include_router(status.router, prefix="/status", tags=["status"])
|
||||
api_router.include_router(opportunities.router, prefix="/opportunities", tags=["opportunities"])
|
||||
api_router.include_router(trades.router, prefix="/trades", tags=["trades"])
|
||||
api_router.include_router(trades.router, prefix="/trades", tags=["trades"])
|
||||
api_router.include_router(events.router, prefix="/events", tags=["events"])
|
84
app/api/api_v1/endpoints/events.py
Normal file
84
app/api/api_v1/endpoints/events.py
Normal file
@ -0,0 +1,84 @@
|
||||
from typing import Any, Optional, List
|
||||
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 SystemEvent
|
||||
from app.schemas.arbitrage import SystemEventCreate, SystemEvent as SystemEventSchema
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", response_model=List[SystemEventSchema])
|
||||
async def get_system_events(
|
||||
event_type: Optional[str] = Query(None, description="Filter by event type (startup, shutdown, error, warning, info)"),
|
||||
component: Optional[str] = Query(None, description="Filter by component"),
|
||||
limit: int = Query(50, ge=1, le=200, description="Number of events to return"),
|
||||
offset: int = Query(0, ge=0, description="Pagination offset"),
|
||||
db: Session = Depends(get_db)
|
||||
) -> Any:
|
||||
"""
|
||||
Retrieve system events with optional filtering.
|
||||
"""
|
||||
query = db.query(SystemEvent)
|
||||
|
||||
# Apply filters
|
||||
if event_type:
|
||||
query = query.filter(SystemEvent.event_type == event_type)
|
||||
|
||||
if component:
|
||||
query = query.filter(SystemEvent.component == component)
|
||||
|
||||
# Get paginated results
|
||||
events = query.order_by(desc(SystemEvent.timestamp)).offset(offset).limit(limit).all()
|
||||
|
||||
return events
|
||||
|
||||
|
||||
@router.get("/{event_id}", response_model=SystemEventSchema)
|
||||
async def get_system_event(
|
||||
event_id: int,
|
||||
db: Session = Depends(get_db)
|
||||
) -> Any:
|
||||
"""
|
||||
Get a specific system event by ID.
|
||||
"""
|
||||
event = db.query(SystemEvent).filter(SystemEvent.id == event_id).first()
|
||||
if not event:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"System event with ID {event_id} not found"
|
||||
)
|
||||
return event
|
||||
|
||||
|
||||
@router.post("", response_model=SystemEventSchema, status_code=status.HTTP_201_CREATED)
|
||||
async def create_system_event(
|
||||
event_in: SystemEventCreate,
|
||||
db: Session = Depends(get_db)
|
||||
) -> Any:
|
||||
"""
|
||||
Create a new system event.
|
||||
"""
|
||||
# Validate event type
|
||||
valid_event_types = ["startup", "shutdown", "error", "warning", "info"]
|
||||
if event_in.event_type not in valid_event_types:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"Invalid event type. Must be one of: {', '.join(valid_event_types)}"
|
||||
)
|
||||
|
||||
# Create the system event
|
||||
db_event = SystemEvent(
|
||||
event_type=event_in.event_type,
|
||||
component=event_in.component,
|
||||
message=event_in.message,
|
||||
details=event_in.details
|
||||
)
|
||||
|
||||
db.add(db_event)
|
||||
db.commit()
|
||||
db.refresh(db_event)
|
||||
|
||||
return db_event
|
@ -1,12 +1,12 @@
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
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
|
||||
from app.schemas.arbitrage import OpportunitiesList, ArbitrageOpportunityCreate, ArbitrageOpportunity as ArbitrageOpportunitySchema
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@ -45,4 +45,53 @@ async def get_arbitrage_opportunities(
|
||||
"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
|
@ -1,12 +1,12 @@
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Optional
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi import APIRouter, Depends, Query, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import desc, func
|
||||
|
||||
from app.db.session import get_db
|
||||
from app.models.arbitrage import Trade
|
||||
from app.schemas.arbitrage import TradesList
|
||||
from app.models.arbitrage import Trade, ArbitrageOpportunity
|
||||
from app.schemas.arbitrage import TradesList, TradeCreate, Trade as TradeSchema
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@ -53,4 +53,70 @@ async def get_trades(
|
||||
"count": total_count,
|
||||
"timestamp": datetime.utcnow(),
|
||||
"total_profit_usd": total_profit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{trade_id}", response_model=TradeSchema)
|
||||
async def get_trade(
|
||||
trade_id: int,
|
||||
db: Session = Depends(get_db)
|
||||
) -> Any:
|
||||
"""
|
||||
Get a specific trade by ID.
|
||||
"""
|
||||
trade = db.query(Trade).filter(Trade.id == trade_id).first()
|
||||
if not trade:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Trade with ID {trade_id} not found"
|
||||
)
|
||||
return trade
|
||||
|
||||
|
||||
@router.post("", response_model=TradeSchema, status_code=status.HTTP_201_CREATED)
|
||||
async def create_trade(
|
||||
trade_in: TradeCreate,
|
||||
db: Session = Depends(get_db)
|
||||
) -> Any:
|
||||
"""
|
||||
Create a new trade record.
|
||||
"""
|
||||
# Check if the opportunity exists
|
||||
opportunity = db.query(ArbitrageOpportunity).filter(
|
||||
ArbitrageOpportunity.id == trade_in.opportunity_id
|
||||
).first()
|
||||
|
||||
if not opportunity:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Arbitrage opportunity with ID {trade_in.opportunity_id} not found"
|
||||
)
|
||||
|
||||
# Create the trade
|
||||
db_trade = Trade(
|
||||
opportunity_id=trade_in.opportunity_id,
|
||||
token_address=trade_in.token_address,
|
||||
token_symbol=trade_in.token_symbol,
|
||||
source_dex=trade_in.source_dex,
|
||||
target_dex=trade_in.target_dex,
|
||||
input_amount=trade_in.input_amount,
|
||||
input_amount_usd=trade_in.input_amount_usd,
|
||||
output_amount=trade_in.output_amount,
|
||||
output_amount_usd=trade_in.output_amount_usd,
|
||||
profit_amount=trade_in.profit_amount,
|
||||
profit_amount_usd=trade_in.profit_amount_usd,
|
||||
profit_percent=trade_in.profit_percent,
|
||||
tx_signature=trade_in.tx_signature,
|
||||
tx_status=trade_in.tx_status,
|
||||
tx_error=trade_in.tx_error
|
||||
)
|
||||
|
||||
db.add(db_trade)
|
||||
|
||||
# Mark the opportunity as executed
|
||||
opportunity.was_executed = True
|
||||
|
||||
db.commit()
|
||||
db.refresh(db_trade)
|
||||
|
||||
return db_trade
|
@ -3,6 +3,7 @@ import logging
|
||||
from typing import Dict, List, Optional, Any, Tuple
|
||||
import base64
|
||||
import base58
|
||||
from app.core.config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -54,8 +55,6 @@ except ImportError:
|
||||
class TxOpts:
|
||||
pass
|
||||
|
||||
from app.core.config import settings
|
||||
|
||||
# Initialize Solana client
|
||||
solana_client = Client(settings.SOLANA_RPC_URL)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user