""" Pine Script Lab Router. Endpoints for Pine Script generation, template browsing, validation, backtesting, and code customization. """ from __future__ import annotations import logging from typing import Any, Dict, List, Optional from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field from app.dependencies import get_current_user from app.models.user import User logger = logging.getLogger(__name__) router = APIRouter(prefix="/pinescript", tags=["Pine Script Lab"]) # ── Schemas ────────────────────────────────────────────────────────────── class GenerateRequest(BaseModel): description: str = Field(..., min_length=5, max_length=2000, description="Natural language description") parameters: Optional[Dict[str, Any]] = None class TemplateRequest(BaseModel): template_id: str = Field(..., min_length=1, max_length=50) parameters: Optional[Dict[str, Any]] = None class ValidateRequest(BaseModel): code: str = Field(..., min_length=10, max_length=10000) class BacktestRequest(BaseModel): code: str = Field(..., min_length=10, max_length=10000) ticker: str = Field("SPY", min_length=1, max_length=20) period: str = Field("3y") initial_capital: float = Field(100000, ge=1000) commission_pct: float = Field(0.1, ge=0, le=5) class CustomizeRequest(BaseModel): code: str = Field(..., min_length=10, max_length=10000) modification: str = Field(..., min_length=5, max_length=2000) # ── Endpoints ──────────────────────────────────────────────────────────── @router.post("/generate") async def generate_pinescript( data: GenerateRequest, user: User = Depends(get_current_user), ): """ Generate Pine Script v5 code from a natural language description. Uses LLM (Groq) for intelligent code generation, falling back to template matching if LLM is unavailable. """ from app.services.pinescript.generator import generate_from_description try: result = await generate_from_description( description=data.description, parameters=data.parameters, ) return result except Exception as e: logger.error("Pine Script generation failed: %s", e, exc_info=True) raise HTTPException(status_code=500, detail="Generation failed") @router.get("/templates") async def list_templates( user: User = Depends(get_current_user), ): """List all available strategy templates.""" from app.services.pinescript.generator import get_all_templates templates = get_all_templates() return {"total": len(templates), "templates": templates} @router.post("/templates/generate") async def generate_from_template_endpoint( data: TemplateRequest, user: User = Depends(get_current_user), ): """Generate Pine Script from a specific template with optional parameter overrides.""" from app.services.pinescript.generator import generate_from_template try: result = generate_from_template( template_id=data.template_id, parameters=data.parameters, ) return result except ValueError as e: raise HTTPException(status_code=404, detail=str(e)) @router.post("/validate") async def validate_pinescript( data: ValidateRequest, user: User = Depends(get_current_user), ): """Validate Pine Script v5 syntax.""" from app.services.pinescript.validator import validate_pine_script return validate_pine_script(data.code) @router.post("/backtest") async def backtest_pinescript( data: BacktestRequest, user: User = Depends(get_current_user), ): """ Run a backtest on Pine Script code using historical data. Returns TradingView-style performance metrics, equity curve, trade log, and monthly returns. """ from app.services.pinescript.pine_backtester import pine_backtester try: result = await pine_backtester.backtest( code=data.code, ticker=data.ticker, period=data.period, initial_capital=data.initial_capital, commission_pct=data.commission_pct, ) return result except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error("Backtest failed: %s", e, exc_info=True) raise HTTPException(status_code=500, detail="Backtest failed") @router.post("/customize") async def customize_pinescript( data: CustomizeRequest, user: User = Depends(get_current_user), ): """Modify existing Pine Script via LLM-powered customization.""" from app.services.pinescript.generator import customize_code try: result = await customize_code( existing_code=data.code, modification=data.modification, ) return result except Exception as e: logger.error("Customization failed: %s", e, exc_info=True) raise HTTPException(status_code=500, detail="Customization failed")