import { OpenRouterClient } from "../lib/openrouter"; import { FundamentalsAnalyst } from "./fundamentals"; import { TechnicalAnalyst } from "./technical"; import { SentimentAnalyst } from "./sentiment"; import { BullishResearcher, BearishResearcher } from "./researchers"; import { Trader } from "./trader"; import type { AnalystReport, DebateRound, TradingDecision, AgentSignal, ExecutionPlan } from "../types/agents"; export interface GraphStep { step: "analysts" | "debate" | "trader" | "execution"; data: AnalystReport[] | DebateRound[] | TradingDecision | ExecutionPlan; } export class TradingGraph { private client: OpenRouterClient; private model: string; private fundamentalsAnalyst: FundamentalsAnalyst; private technicalAnalyst: TechnicalAnalyst; private sentimentAnalyst: SentimentAnalyst; private bullishResearcher: BullishResearcher; private bearishResearcher: BearishResearcher; private trader: Trader; constructor(client: OpenRouterClient, model?: string) { this.client = client; this.model = model ?? "openai/gpt-oss-120b:free"; this.fundamentalsAnalyst = new FundamentalsAnalyst(client, { model: this.model }); this.technicalAnalyst = new TechnicalAnalyst(client, { model: this.model }); this.sentimentAnalyst = new SentimentAnalyst(client, { model: this.model }); this.bullishResearcher = new BullishResearcher(client, this.model); this.bearishResearcher = new BearishResearcher(client, this.model); this.trader = new Trader(client, this.model); } async propagate( ticker: string, input: { financialData: string; technicalData: { prices: number[]; sma: number; ema: number; rsi: number; macd: number }; sentimentData: { headlines: string[]; source?: "news" | "social" | "stocktwits" }; } ): Promise { console.log(`[TradingGraph] Starting analysis for ${ticker} with model ${this.model}`); const reports = await this.runAnalysts(ticker, input); const debates = await this.runDebate(ticker, reports); const decision = await this.trader.decide(ticker, reports, debates); console.log(`[TradingGraph] Analysis complete for ${ticker}`); console.log(`[TradingGraph] Decision: ${decision.action} (confidence: ${decision.confidence})`); // Build workflow steps for observability. Include an execution step when selling. const steps: GraphStep[] = [ { step: "analysts", data: reports }, { step: "debate", data: debates }, { step: "trader", data: decision }, ]; if (decision.action === 'sell' && decision.executionPlan) { steps.push({ step: "execution", data: decision.executionPlan }); console.log(`[TradingGraph] Execution plan: ${JSON.stringify(decision.executionPlan)}`); } // Log steps for debugging; external systems can be extended to consume GraphStep sequence. console.log(`[TradingGraph] Workflow steps: ${JSON.stringify(steps)}`); return decision; } private async runAnalysts( ticker: string, input: { financialData: string; technicalData: { prices: number[]; sma: number; ema: number; rsi: number; macd: number }; sentimentData: { headlines: string[]; source?: "news" | "social" | "stocktwits" }; } ): Promise { console.log(`[TradingGraph] Running analysts for ${ticker}...`); const [fundamentals, technical, sentiment] = await Promise.all([ this.fundamentalsAnalyst.analyze(ticker, input.financialData), this.technicalAnalyst.analyze(ticker, input.technicalData), this.sentimentAnalyst.analyze(ticker, input.sentimentData), ]); console.log(`[TradingGraph] Analyst reports complete:`, { fundamentals: fundamentals.signal, technical: technical.signal, sentiment: sentiment.signal, }); return [fundamentals, technical, sentiment]; } private async runDebate(ticker: string, reports: AnalystReport[]): Promise { console.log(`[TradingGraph] Running debate for ${ticker}...`); const [bullish, bearish] = await Promise.all([ this.bullishResearcher.research(ticker, reports), this.bearishResearcher.research(ticker, reports), ]); console.log(`[TradingGraph] Debate complete`); return [ { bullishView: bullish.bullishView, bearishView: bearish.bearishView, researcher: "bullish", }, ]; } }