feat: add stock database with prisma for portfolio persistence

- Initialize Prisma with SQLite and Stock model
- Create database service layer with singleton client
- Add API routes for stock CRUD operations
- Integrate database with analyze page to persist ticker entries
- Add Playwright tests for stock database functionality
This commit is contained in:
2026-05-14 10:23:56 +02:00
parent f40eec1420
commit 3340fd11ca
29 changed files with 2530 additions and 221 deletions
+24 -1
View File
@@ -6,6 +6,11 @@ import { BullishResearcher, BearishResearcher } from "./researchers";
import { Trader } from "./trader";
import type { AnalystReport, DebateRound, TradingDecision, AgentSignal } from "../types/agents";
export interface GraphStep {
step: "analysts" | "debate" | "trader";
data: AnalystReport[] | DebateRound[] | TradingDecision;
}
export class TradingGraph {
private client: OpenRouterClient;
private model: string;
@@ -18,7 +23,7 @@ export class TradingGraph {
constructor(client: OpenRouterClient, model?: string) {
this.client = client;
this.model = model ?? "google/gemini-2.0-flash-exp:free";
this.model = model ?? "openai/gpt-oss-120b:free";
this.fundamentalsAnalyst = new FundamentalsAnalyst(client, { model: this.model });
this.technicalAnalyst = new TechnicalAnalyst(client, { model: this.model });
@@ -36,9 +41,15 @@ export class TradingGraph {
sentimentData: { headlines: string[]; source?: "news" | "social" | "stocktwits" };
}
): Promise<TradingDecision> {
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})`);
return decision;
}
@@ -50,21 +61,33 @@ export class TradingGraph {
sentimentData: { headlines: string[]; source?: "news" | "social" | "stocktwits" };
}
): Promise<AnalystReport[]> {
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<DebateRound[]> {
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,