import { OpenRouterClient } from "../lib/openrouter"; import type { AnalystReport, AgentSignal, SignalType } from "../types/agents"; export interface TechnicalData { prices: number[]; sma: number; ema: number; rsi: number; macd: number; } export interface TechnicalAnalystConfig { model?: string; } export class TechnicalAnalyst { private client: OpenRouterClient; private model: string; constructor(client: OpenRouterClient, config?: TechnicalAnalystConfig) { this.client = client; this.model = config?.model ?? "google/gemini-2.0-flash-exp:free"; } getModel(): string { return this.model; } async analyze(ticker: string, data: TechnicalData): Promise { const messages = [ { role: "system" as const, content: "You are a technical analyst. Analyze the technical indicators (SMA, EMA, RSI, MACD) for the given ticker and provide a bullish, bearish, or neutral signal with reasoning. Respond in JSON format with 'signal', 'confidence', and 'reasoning' fields.", }, { role: "user" as const, content: `Analyze ${ticker} technical data: SMA: ${data.sma} EMA: ${data.ema} RSI: ${data.rsi} MACD: ${data.macd} Prices: ${data.prices.slice(-10).join(", ")}`, }, ]; const response = await this.client.createChatCompletion( messages, this.model ); const parsedResponse = response as { choices?: Array<{ message?: { content?: string } }>; }; const content = parsedResponse.choices?.[0]?.message?.content ?? ""; let signal: SignalType = "neutral"; let confidence = 0.5; let reasoning = content; try { const parsed = JSON.parse(content); if ( parsed.signal === "bullish" || parsed.signal === "bearish" || parsed.signal === "neutral" ) { signal = parsed.signal; confidence = parsed.confidence ?? 0.5; reasoning = parsed.reasoning ?? content; } } catch { const lowerContent = content.toLowerCase(); if (lowerContent.includes("bullish")) signal = "bullish"; else if (lowerContent.includes("bearish")) signal = "bearish"; } const agentSignal: AgentSignal = { agent: "technical", signal, confidence, reasoning, timestamp: new Date().toISOString(), }; return { analyst: "technical", report: content, signal: agentSignal, }; } }