import httpx import json from typing import List from app.config import settings from app.schemas.schemas import ( AIAnalysisRequest, AIAnalysisResponse, Recommendation, RiskLevel, SupportResistance, ) class OpenRouterService: def __init__(self): self.base_url = settings.OPENROUTER_BASE_URL self.api_key = settings.OPENROUTER_API_KEY self.model = settings.OPENROUTER_MODEL async def analyze_scenario(self, request: AIAnalysisRequest) -> AIAnalysisResponse: """ Analyze trading scenario using Claude 3.5 Sonnet via OpenRouter Args: request: AIAnalysisRequest with price data and indicators Returns: AIAnalysisResponse with recommendation and analysis """ # Prepare recent price data for analysis recent_prices = request.price_data[-50:] if len(request.price_data) > 50 else request.price_data # Format price data for the AI price_summary = f"Current Price: ${request.current_price:.2f}\n" price_summary += f"Recent Close Prices: {[f'${p.close:.2f}' for p in recent_prices[-10:]]}\n" # Calculate basic statistics prices = [p.close for p in recent_prices] avg_price = sum(prices) / len(prices) price_range = max(prices) - min(prices) # Create analysis prompt prompt = f"""You are a senior quantitative analyst specializing in gold (XAU/USD) trading. Analyze the following market data and provide a trading recommendation. Market Data: {price_summary} Average Price (last 50 periods): ${avg_price:.2f} Price Range: ${price_range:.2f} Technical Indicators: {json.dumps(request.indicators, indent=2)} Based on this data, provide: 1. A clear recommendation: BUY, SELL, or HOLD 2. Confidence level (0-100%) 3. Detailed reasoning (2-3 sentences) 4. Support and resistance levels (up to 3 each) 5. Risk level assessment: LOW, MEDIUM, or HIGH Respond in JSON format: {{ "recommendation": "BUY|SELL|HOLD", "confidence": 0-100, "reasoning": "Your detailed analysis here", "support_levels": [price1, price2, price3], "resistance_levels": [price1, price2, price3], "risk_level": "LOW|MEDIUM|HIGH" }} """ headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", "HTTP-Referer": settings.OPENROUTER_SITE_URL, "X-Title": settings.OPENROUTER_SITE_NAME, } payload = { "model": self.model, "messages": [ { "role": "system", "content": "You are a professional gold trading analyst. Always respond with valid JSON.", }, {"role": "user", "content": prompt}, ], "temperature": 0.7, "max_tokens": 1000, } async with httpx.AsyncClient(timeout=60.0) as client: response = await client.post( f"{self.base_url}/chat/completions", headers=headers, json=payload, ) response.raise_for_status() data = response.json() # Extract AI response ai_content = data["choices"][0]["message"]["content"] # Parse JSON response try: # Try to extract JSON from markdown code blocks if present if "```json" in ai_content: json_start = ai_content.find("```json") + 7 json_end = ai_content.find("```", json_start) ai_content = ai_content[json_start:json_end].strip() elif "```" in ai_content: json_start = ai_content.find("```") + 3 json_end = ai_content.find("```", json_start) ai_content = ai_content[json_start:json_end].strip() analysis_data = json.loads(ai_content) except json.JSONDecodeError: # Fallback to default response if JSON parsing fails return AIAnalysisResponse( recommendation=Recommendation.HOLD, confidence=50.0, reasoning="Unable to parse AI response. Please try again.", support_resistance=SupportResistance(support=[], resistance=[]), risk_level=RiskLevel.MEDIUM, ) # Map to response schema return AIAnalysisResponse( recommendation=Recommendation(analysis_data.get("recommendation", "HOLD")), confidence=float(analysis_data.get("confidence", 50)), reasoning=analysis_data.get("reasoning", "Analysis completed."), support_resistance=SupportResistance( support=analysis_data.get("support_levels", []), resistance=analysis_data.get("resistance_levels", []), ), risk_level=RiskLevel(analysis_data.get("risk_level", "MEDIUM")), ) async def generate_trading_plan(self, prompt: str) -> dict: """ Generate a comprehensive trading plan using AI Args: prompt: Detailed prompt with market data and user preferences Returns: Dictionary with trading plan data """ headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", "HTTP-Referer": settings.OPENROUTER_SITE_URL, "X-Title": settings.OPENROUTER_SITE_NAME, } payload = { "model": self.model, "messages": [ { "role": "system", "content": "You are an expert gold (XAU/USD) trading analyst. Always respond with valid JSON only, no additional text or explanations.", }, {"role": "user", "content": prompt}, ], "temperature": 0.7, "max_tokens": 2000, } async with httpx.AsyncClient(timeout=90.0) as client: response = await client.post( f"{self.base_url}/chat/completions", headers=headers, json=payload, ) response.raise_for_status() data = response.json() # Extract AI response ai_content = data["choices"][0]["message"]["content"] # Parse JSON response try: # Try to extract JSON from markdown code blocks if present if "```json" in ai_content: json_start = ai_content.find("```json") + 7 json_end = ai_content.find("```", json_start) ai_content = ai_content[json_start:json_end].strip() elif "```" in ai_content: json_start = ai_content.find("```") + 3 json_end = ai_content.find("```", json_start) ai_content = ai_content[json_start:json_end].strip() plan_data = json.loads(ai_content) return plan_data except json.JSONDecodeError as e: raise Exception(f"Failed to parse AI trading plan response: {str(e)}") openrouter_service = OpenRouterService()