80 lines
2.2 KiB
TypeScript
80 lines
2.2 KiB
TypeScript
import { OpenRouterClient } from "../lib/openrouter";
|
|
import type { AnalystReport, AgentSignal, SignalType } from "../types/agents";
|
|
|
|
export interface FundamentalsConfig {
|
|
model?: string;
|
|
}
|
|
|
|
export class FundamentalsAnalyst {
|
|
private client: OpenRouterClient;
|
|
private model: string;
|
|
|
|
constructor(client: OpenRouterClient, config?: FundamentalsConfig) {
|
|
this.client = client;
|
|
this.model = config?.model ?? "google/gemini-2.0-flash-exp:free";
|
|
}
|
|
|
|
getModel(): string {
|
|
return this.model;
|
|
}
|
|
|
|
async analyze(ticker: string, financialData: string): Promise<AnalystReport> {
|
|
const messages = [
|
|
{
|
|
role: "system" as const,
|
|
content:
|
|
"You are a fundamental analyst. Analyze the financial data 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} fundamentals:\n${financialData}`,
|
|
},
|
|
];
|
|
|
|
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 {
|
|
// If not valid JSON, check for keywords in the response
|
|
const lowerContent = content.toLowerCase();
|
|
if (lowerContent.includes("bullish")) signal = "bullish";
|
|
else if (lowerContent.includes("bearish")) signal = "bearish";
|
|
}
|
|
|
|
const agentSignal: AgentSignal = {
|
|
agent: "fundamentals",
|
|
signal,
|
|
confidence,
|
|
reasoning,
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
|
|
return {
|
|
analyst: "fundamentals",
|
|
report: content,
|
|
signal: agentSignal,
|
|
};
|
|
}
|
|
} |