feat: add trader agent
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { OpenRouterClient } from "../lib/openrouter";
|
||||
import type { AnalystReport, DebateRound, TradingDecision } from "../types/agents";
|
||||
|
||||
type ChatResponse = {
|
||||
choices?: Array<{ message?: { content?: string } }>;
|
||||
};
|
||||
|
||||
export class Trader {
|
||||
private client: OpenRouterClient;
|
||||
private model: string;
|
||||
|
||||
constructor(client: OpenRouterClient, model?: string) {
|
||||
this.client = client;
|
||||
this.model = model ?? "google/gemini-2.0-flash-exp:free";
|
||||
}
|
||||
|
||||
async decide(
|
||||
ticker: string,
|
||||
reports: AnalystReport[],
|
||||
debates: DebateRound[]
|
||||
): Promise<TradingDecision> {
|
||||
const signalSummaries = reports
|
||||
.map((r) => `${r.analyst}: ${r.signal.signal} (confidence: ${r.signal.confidence}) - ${r.report}`)
|
||||
.join("\n");
|
||||
|
||||
const debateSummaries = debates
|
||||
.map((d) => `Bullish: ${d.bullishView}\nBearish: ${d.bearishView}`)
|
||||
.join("\n");
|
||||
|
||||
const allSignals = reports.map((r) => r.signal);
|
||||
|
||||
const prompt = `Analyze all signals and debate rounds for ${ticker}:
|
||||
|
||||
Signals:
|
||||
${signalSummaries}
|
||||
|
||||
Debate Rounds:
|
||||
${debateSummaries}
|
||||
|
||||
Based on all the information above, make a trading decision. Respond with:
|
||||
- action: "buy", "sell", or "hold"
|
||||
- confidence: a number between 0 and 1
|
||||
- reasoning: brief explanation
|
||||
|
||||
Format your response as JSON with these fields.`;
|
||||
|
||||
const response = await this.client.createChatCompletion(
|
||||
[
|
||||
{ role: "system", content: "You are a trading agent that makes buy/sell/hold decisions based on all available signals." },
|
||||
{ role: "user", content: prompt },
|
||||
],
|
||||
this.model
|
||||
);
|
||||
|
||||
const content = ((response as ChatResponse).choices?.[0]?.message?.content) ?? "";
|
||||
|
||||
let action: 'buy' | 'sell' | 'hold' = 'hold';
|
||||
let confidence = 0.5;
|
||||
let reasoning = content;
|
||||
|
||||
const actionMatch = content.match(/"action"\s*:\s*"(buy|sell|hold)"/);
|
||||
if (actionMatch) {
|
||||
action = actionMatch[1] as 'buy' | 'sell' | 'hold';
|
||||
}
|
||||
|
||||
const confidenceMatch = content.match(/"confidence"\s*:\s*([0-9.]+)/);
|
||||
if (confidenceMatch) {
|
||||
confidence = parseFloat(confidenceMatch[1]);
|
||||
}
|
||||
|
||||
const reasoningMatch = content.match(/"reasoning"\s*:\s*"([^"]+)"/);
|
||||
if (reasoningMatch) {
|
||||
reasoning = reasoningMatch[1];
|
||||
}
|
||||
|
||||
return {
|
||||
action,
|
||||
confidence,
|
||||
reasoning,
|
||||
agentSignals: allSignals,
|
||||
debateRounds: debates,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user