79 lines
2.8 KiB
Python
79 lines
2.8 KiB
Python
|
|
"""Backtesting API endpoints."""
|
||
|
|
|
||
|
|
from fastapi import APIRouter, HTTPException, Depends, BackgroundTasks
|
||
|
|
from typing import Dict, Any
|
||
|
|
from sqlalchemy import select
|
||
|
|
import uuid
|
||
|
|
|
||
|
|
from ..core.dependencies import get_backtesting_engine, get_strategy_registry
|
||
|
|
from ..core.schemas import BacktestRequest, BacktestResponse
|
||
|
|
from src.core.database import Strategy, get_database
|
||
|
|
|
||
|
|
router = APIRouter()
|
||
|
|
|
||
|
|
# Store running backtests
|
||
|
|
_backtests: Dict[str, Dict[str, Any]] = {}
|
||
|
|
|
||
|
|
|
||
|
|
@router.post("/run", response_model=BacktestResponse)
|
||
|
|
async def run_backtest(
|
||
|
|
backtest_data: BacktestRequest,
|
||
|
|
background_tasks: BackgroundTasks,
|
||
|
|
backtest_engine=Depends(get_backtesting_engine)
|
||
|
|
):
|
||
|
|
"""Run a backtest."""
|
||
|
|
try:
|
||
|
|
db = get_database()
|
||
|
|
async with db.get_session() as session:
|
||
|
|
# Get strategy
|
||
|
|
stmt = select(Strategy).where(Strategy.id == backtest_data.strategy_id)
|
||
|
|
result = await session.execute(stmt)
|
||
|
|
strategy_db = result.scalar_one_or_none()
|
||
|
|
if not strategy_db:
|
||
|
|
raise HTTPException(status_code=404, detail="Strategy not found")
|
||
|
|
|
||
|
|
# Create strategy instance
|
||
|
|
registry = get_strategy_registry()
|
||
|
|
strategy_instance = registry.create_instance(
|
||
|
|
strategy_id=strategy_db.id,
|
||
|
|
name=strategy_db.class_name,
|
||
|
|
parameters=strategy_db.parameters,
|
||
|
|
timeframes=strategy_db.timeframes or [backtest_data.timeframe]
|
||
|
|
)
|
||
|
|
|
||
|
|
if not strategy_instance:
|
||
|
|
raise HTTPException(status_code=400, detail="Failed to create strategy instance")
|
||
|
|
|
||
|
|
# Run backtest
|
||
|
|
results = backtest_engine.run_backtest(
|
||
|
|
strategy=strategy_instance,
|
||
|
|
symbol=backtest_data.symbol,
|
||
|
|
exchange=backtest_data.exchange,
|
||
|
|
timeframe=backtest_data.timeframe,
|
||
|
|
start_date=backtest_data.start_date,
|
||
|
|
end_date=backtest_data.end_date,
|
||
|
|
initial_capital=backtest_data.initial_capital,
|
||
|
|
slippage=backtest_data.slippage,
|
||
|
|
fee_rate=backtest_data.fee_rate
|
||
|
|
)
|
||
|
|
|
||
|
|
if "error" in results:
|
||
|
|
raise HTTPException(status_code=400, detail=results["error"])
|
||
|
|
|
||
|
|
return BacktestResponse(
|
||
|
|
results=results,
|
||
|
|
status="completed"
|
||
|
|
)
|
||
|
|
except HTTPException:
|
||
|
|
raise
|
||
|
|
except Exception as e:
|
||
|
|
raise HTTPException(status_code=500, detail=str(e))
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/results/{backtest_id}")
|
||
|
|
async def get_backtest_results(backtest_id: str):
|
||
|
|
"""Get backtest results by ID."""
|
||
|
|
if backtest_id not in _backtests:
|
||
|
|
raise HTTPException(status_code=404, detail="Backtest not found")
|
||
|
|
return _backtests[backtest_id]
|