Local changes: Updated model training, removed debug instrumentation, and configuration improvements
This commit is contained in:
310
backend/api/strategies.py
Normal file
310
backend/api/strategies.py
Normal file
@@ -0,0 +1,310 @@
|
||||
"""Strategy API endpoints."""
|
||||
|
||||
from typing import List
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from sqlalchemy import select
|
||||
|
||||
from ..core.dependencies import get_strategy_registry
|
||||
from ..core.schemas import (
|
||||
StrategyCreate, StrategyUpdate, StrategyResponse
|
||||
)
|
||||
from src.core.database import Strategy, get_database
|
||||
from src.strategies.scheduler import get_scheduler as _get_scheduler
|
||||
|
||||
def get_strategy_scheduler():
|
||||
"""Get strategy scheduler instance."""
|
||||
return _get_scheduler()
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/", response_model=List[StrategyResponse])
|
||||
async def list_strategies():
|
||||
"""List all strategies."""
|
||||
try:
|
||||
db = get_database()
|
||||
async with db.get_session() as session:
|
||||
stmt = select(Strategy).order_by(Strategy.created_at.desc())
|
||||
result = await session.execute(stmt)
|
||||
strategies = result.scalars().all()
|
||||
return [StrategyResponse.model_validate(s) for s in strategies]
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/available")
|
||||
async def list_available_strategies(
|
||||
registry=Depends(get_strategy_registry)
|
||||
):
|
||||
"""List available strategy types."""
|
||||
try:
|
||||
return {"strategies": registry.list_available()}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/", response_model=StrategyResponse)
|
||||
async def create_strategy(strategy_data: StrategyCreate):
|
||||
"""Create a new strategy."""
|
||||
try:
|
||||
db = get_database()
|
||||
async with db.get_session() as session:
|
||||
strategy = Strategy(
|
||||
name=strategy_data.name,
|
||||
description=strategy_data.description,
|
||||
strategy_type=strategy_data.strategy_type,
|
||||
class_name=strategy_data.class_name,
|
||||
parameters=strategy_data.parameters,
|
||||
timeframes=strategy_data.timeframes,
|
||||
paper_trading=strategy_data.paper_trading,
|
||||
schedule=strategy_data.schedule,
|
||||
enabled=False
|
||||
)
|
||||
session.add(strategy)
|
||||
await session.commit()
|
||||
await session.refresh(strategy)
|
||||
return StrategyResponse.model_validate(strategy)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/{strategy_id}", response_model=StrategyResponse)
|
||||
async def get_strategy(strategy_id: int):
|
||||
"""Get strategy by ID."""
|
||||
try:
|
||||
db = get_database()
|
||||
async with db.get_session() as session:
|
||||
stmt = select(Strategy).where(Strategy.id == strategy_id)
|
||||
result = await session.execute(stmt)
|
||||
strategy = result.scalar_one_or_none()
|
||||
if not strategy:
|
||||
raise HTTPException(status_code=404, detail="Strategy not found")
|
||||
return StrategyResponse.model_validate(strategy)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.put("/{strategy_id}", response_model=StrategyResponse)
|
||||
async def update_strategy(strategy_id: int, strategy_data: StrategyUpdate):
|
||||
"""Update a strategy."""
|
||||
try:
|
||||
db = get_database()
|
||||
async with db.get_session() as session:
|
||||
stmt = select(Strategy).where(Strategy.id == strategy_id)
|
||||
result = await session.execute(stmt)
|
||||
strategy = result.scalar_one_or_none()
|
||||
if not strategy:
|
||||
raise HTTPException(status_code=404, detail="Strategy not found")
|
||||
|
||||
if strategy_data.name is not None:
|
||||
strategy.name = strategy_data.name
|
||||
if strategy_data.description is not None:
|
||||
strategy.description = strategy_data.description
|
||||
if strategy_data.parameters is not None:
|
||||
strategy.parameters = strategy_data.parameters
|
||||
if strategy_data.timeframes is not None:
|
||||
strategy.timeframes = strategy_data.timeframes
|
||||
if strategy_data.enabled is not None:
|
||||
strategy.enabled = strategy_data.enabled
|
||||
if strategy_data.schedule is not None:
|
||||
strategy.schedule = strategy_data.schedule
|
||||
|
||||
await session.commit()
|
||||
await session.refresh(strategy)
|
||||
return StrategyResponse.model_validate(strategy)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.delete("/{strategy_id}")
|
||||
async def delete_strategy(strategy_id: int):
|
||||
"""Delete a strategy."""
|
||||
try:
|
||||
db = get_database()
|
||||
async with db.get_session() as session:
|
||||
stmt = select(Strategy).where(Strategy.id == strategy_id)
|
||||
result = await session.execute(stmt)
|
||||
strategy = result.scalar_one_or_none()
|
||||
if not strategy:
|
||||
raise HTTPException(status_code=404, detail="Strategy not found")
|
||||
|
||||
await session.delete(strategy)
|
||||
await session.commit()
|
||||
return {"status": "deleted", "strategy_id": strategy_id}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/{strategy_id}/start")
|
||||
async def start_strategy(strategy_id: int):
|
||||
"""Start a strategy manually (bypasses Autopilot)."""
|
||||
try:
|
||||
db = get_database()
|
||||
async with db.get_session() as session:
|
||||
stmt = select(Strategy).where(Strategy.id == strategy_id)
|
||||
result = await session.execute(stmt)
|
||||
strategy = result.scalar_one_or_none()
|
||||
if not strategy:
|
||||
raise HTTPException(status_code=404, detail="Strategy not found")
|
||||
|
||||
# Start strategy via scheduler
|
||||
scheduler = get_strategy_scheduler()
|
||||
scheduler.start_strategy(strategy_id)
|
||||
|
||||
strategy.running = True # Only set running, not enabled
|
||||
await session.commit()
|
||||
|
||||
return {"status": "started", "strategy_id": strategy_id}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/{strategy_id}/stop")
|
||||
async def stop_strategy(strategy_id: int):
|
||||
"""Stop a manually running strategy."""
|
||||
try:
|
||||
db = get_database()
|
||||
async with db.get_session() as session:
|
||||
stmt = select(Strategy).where(Strategy.id == strategy_id)
|
||||
result = await session.execute(stmt)
|
||||
strategy = result.scalar_one_or_none()
|
||||
if not strategy:
|
||||
raise HTTPException(status_code=404, detail="Strategy not found")
|
||||
|
||||
# Stop strategy via scheduler
|
||||
scheduler = get_strategy_scheduler()
|
||||
scheduler.stop_strategy(strategy_id)
|
||||
|
||||
strategy.running = False # Only set running, not enabled
|
||||
await session.commit()
|
||||
|
||||
return {"status": "stopped", "strategy_id": strategy_id}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/{strategy_type}/optimize")
|
||||
async def optimize_strategy(
|
||||
strategy_type: str,
|
||||
symbol: str = "BTC/USD",
|
||||
method: str = "genetic",
|
||||
population_size: int = 50,
|
||||
generations: int = 100
|
||||
):
|
||||
"""Optimize strategy parameters using genetic algorithm.
|
||||
|
||||
This endpoint queues an optimization task and returns immediately.
|
||||
Use /api/tasks/{task_id} to monitor progress.
|
||||
|
||||
Args:
|
||||
strategy_type: Type of strategy to optimize (e.g., 'rsi', 'macd')
|
||||
symbol: Trading symbol for backtesting
|
||||
method: Optimization method ('genetic', 'grid')
|
||||
population_size: Population size for genetic algorithm
|
||||
generations: Number of generations
|
||||
|
||||
Returns:
|
||||
Task ID for monitoring
|
||||
"""
|
||||
try:
|
||||
from src.worker.tasks import optimize_strategy_task
|
||||
|
||||
# Get parameter ranges for the strategy type
|
||||
registry = get_strategy_registry()
|
||||
strategy_class = registry.get(strategy_type)
|
||||
|
||||
if not strategy_class:
|
||||
raise HTTPException(status_code=404, detail=f"Strategy type '{strategy_type}' not found")
|
||||
|
||||
# Default parameter ranges based on strategy type
|
||||
param_ranges = {
|
||||
"rsi": {"period": (5, 50), "overbought": (60, 90), "oversold": (10, 40)},
|
||||
"macd": {"fast_period": (5, 20), "slow_period": (15, 40), "signal_period": (5, 15)},
|
||||
"moving_average": {"short_period": (5, 30), "long_period": (20, 100)},
|
||||
"bollinger_mean_reversion": {"period": (10, 50), "std_dev": (1.5, 3.0)},
|
||||
}.get(strategy_type.lower(), {"period": (10, 50)})
|
||||
|
||||
# Queue the optimization task
|
||||
task = optimize_strategy_task.delay(
|
||||
strategy_type=strategy_type,
|
||||
symbol=symbol,
|
||||
param_ranges=param_ranges,
|
||||
method=method,
|
||||
population_size=population_size,
|
||||
generations=generations
|
||||
)
|
||||
|
||||
return {
|
||||
"task_id": task.id,
|
||||
"status": "queued",
|
||||
"strategy_type": strategy_type,
|
||||
"symbol": symbol,
|
||||
"method": method
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/{strategy_id}/status")
|
||||
async def get_strategy_status(strategy_id: int):
|
||||
"""Get real-time status of a running strategy.
|
||||
|
||||
Returns execution info including last tick time, last signal, and stats.
|
||||
"""
|
||||
try:
|
||||
scheduler = get_strategy_scheduler()
|
||||
status = scheduler.get_strategy_status(strategy_id)
|
||||
|
||||
if not status:
|
||||
# Check if strategy exists but isn't running
|
||||
db = get_database()
|
||||
async with db.get_session() as session:
|
||||
stmt = select(Strategy).where(Strategy.id == strategy_id)
|
||||
result = await session.execute(stmt)
|
||||
strategy = result.scalar_one_or_none()
|
||||
|
||||
if not strategy:
|
||||
raise HTTPException(status_code=404, detail="Strategy not found")
|
||||
|
||||
return {
|
||||
"strategy_id": strategy_id,
|
||||
"name": strategy.name,
|
||||
"type": strategy.strategy_type,
|
||||
"symbol": strategy.parameters.get('symbol') if strategy.parameters else None,
|
||||
"running": False,
|
||||
"enabled": strategy.enabled,
|
||||
}
|
||||
|
||||
return status
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/running/all")
|
||||
async def get_all_running_strategies():
|
||||
"""Get status of all currently running strategies."""
|
||||
try:
|
||||
scheduler = get_strategy_scheduler()
|
||||
active = scheduler.get_all_active_strategies()
|
||||
return {
|
||||
"total_running": len(active),
|
||||
"strategies": active
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
Reference in New Issue
Block a user