From 24cd869302cfacad53ecd00cec0cef0a9393745b Mon Sep 17 00:00:00 2001 From: TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> Date: Thu, 2 Apr 2026 13:48:17 +0900 Subject: feat: add NewsItem, sentiment scoring, and stock selection models Add NewsCategory enum and NewsItem model to shared/models.py. Create sentiment_models.py with SymbolScore, MarketSentiment, SelectedStock, Candidate. --- shared/src/shared/models.py | 23 ++++++++++++++++++ shared/src/shared/sentiment_models.py | 44 +++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 shared/src/shared/sentiment_models.py (limited to 'shared/src') diff --git a/shared/src/shared/models.py b/shared/src/shared/models.py index 70820b5..a436c03 100644 --- a/shared/src/shared/models.py +++ b/shared/src/shared/models.py @@ -74,3 +74,26 @@ class Position(BaseModel): @property def unrealized_pnl(self) -> Decimal: return self.quantity * (self.current_price - self.avg_entry_price) + + +class NewsCategory(str, Enum): + POLICY = "policy" + EARNINGS = "earnings" + MACRO = "macro" + SOCIAL = "social" + FILING = "filing" + FED = "fed" + + +class NewsItem(BaseModel): + id: str = Field(default_factory=lambda: str(uuid.uuid4())) + source: str + headline: str + summary: Optional[str] = None + url: Optional[str] = None + published_at: datetime + symbols: list[str] = [] + sentiment: float + category: NewsCategory + raw_data: dict = {} + created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) diff --git a/shared/src/shared/sentiment_models.py b/shared/src/shared/sentiment_models.py new file mode 100644 index 0000000..a009601 --- /dev/null +++ b/shared/src/shared/sentiment_models.py @@ -0,0 +1,44 @@ +"""Sentiment scoring and stock selection models.""" + +from datetime import datetime +from typing import Optional + +from pydantic import BaseModel + +from shared.models import OrderSide + + +class SymbolScore(BaseModel): + symbol: str + news_score: float + news_count: int + social_score: float + policy_score: float + filing_score: float + composite: float + updated_at: datetime + + +class MarketSentiment(BaseModel): + fear_greed: int + fear_greed_label: str + vix: Optional[float] = None + fed_stance: str + market_regime: str + updated_at: datetime + + +class SelectedStock(BaseModel): + symbol: str + side: OrderSide + conviction: float + reason: str + key_news: list[str] + + +class Candidate(BaseModel): + symbol: str + source: str + direction: Optional[OrderSide] = None + score: float + reason: str -- cgit v1.2.3