From 35aa61c651217663406c9cd6df404f85338b2d68 Mon Sep 17 00:00:00 2001 From: TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> Date: Thu, 2 Apr 2026 14:17:43 +0900 Subject: style: fix lint and formatting issues across news collector and shared --- .../src/news_collector/collectors/fear_greed.py | 5 ++- .../src/news_collector/collectors/fed.py | 23 ++++++++++-- .../src/news_collector/collectors/reddit.py | 4 +- .../src/news_collector/collectors/sec_edgar.py | 43 ++++++++++++++-------- .../src/news_collector/collectors/truth_social.py | 4 +- services/news-collector/tests/test_fed.py | 16 +++++++- services/news-collector/tests/test_finnhub.py | 1 - services/news-collector/tests/test_main.py | 8 ++-- services/news-collector/tests/test_reddit.py | 38 +++++++++++++++++-- services/news-collector/tests/test_rss.py | 1 - services/news-collector/tests/test_sec_edgar.py | 4 +- services/news-collector/tests/test_truth_social.py | 13 ++++++- .../strategy-engine/src/strategy_engine/main.py | 6 +-- .../src/strategy_engine/stock_selector.py | 13 ++++--- .../strategy-engine/tests/test_stock_selector.py | 40 ++++++++++---------- .../alembic/versions/002_news_sentiment_tables.py | 8 +++- shared/src/shared/db.py | 10 ++--- shared/src/shared/notifier.py | 3 +- shared/src/shared/sentiment.py | 6 +-- shared/tests/test_db_news.py | 2 - shared/tests/test_sentiment_aggregator.py | 12 +++++- shared/tests/test_sentiment_models.py | 1 - 22 files changed, 178 insertions(+), 83 deletions(-) diff --git a/services/news-collector/src/news_collector/collectors/fear_greed.py b/services/news-collector/src/news_collector/collectors/fear_greed.py index 305d416..f79f716 100644 --- a/services/news-collector/src/news_collector/collectors/fear_greed.py +++ b/services/news-collector/src/news_collector/collectors/fear_greed.py @@ -7,7 +7,6 @@ from typing import Optional import aiohttp from news_collector.collectors.base import BaseCollector -from shared.models import NewsItem logger = logging.getLogger(__name__) @@ -31,7 +30,9 @@ class FearGreedCollector(BaseCollector): headers = {"User-Agent": "Mozilla/5.0"} try: async with aiohttp.ClientSession() as session: - async with session.get(FEAR_GREED_URL, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp: + async with session.get( + FEAR_GREED_URL, headers=headers, timeout=aiohttp.ClientTimeout(total=10) + ) as resp: if resp.status != 200: return None return await resp.json() diff --git a/services/news-collector/src/news_collector/collectors/fed.py b/services/news-collector/src/news_collector/collectors/fed.py index 47b70f5..fce4842 100644 --- a/services/news-collector/src/news_collector/collectors/fed.py +++ b/services/news-collector/src/news_collector/collectors/fed.py @@ -17,12 +17,27 @@ logger = logging.getLogger(__name__) _FED_RSS_URL = "https://www.federalreserve.gov/feeds/press_all.xml" _HAWKISH_KEYWORDS = [ - "rate hike", "interest rate increase", "tighten", "tightening", "inflation", - "hawkish", "restrictive", "raise rates", "hike rates", + "rate hike", + "interest rate increase", + "tighten", + "tightening", + "inflation", + "hawkish", + "restrictive", + "raise rates", + "hike rates", ] _DOVISH_KEYWORDS = [ - "rate cut", "interest rate decrease", "easing", "ease", "stimulus", - "dovish", "accommodative", "lower rates", "cut rates", "quantitative easing", + "rate cut", + "interest rate decrease", + "easing", + "ease", + "stimulus", + "dovish", + "accommodative", + "lower rates", + "cut rates", + "quantitative easing", ] diff --git a/services/news-collector/src/news_collector/collectors/reddit.py b/services/news-collector/src/news_collector/collectors/reddit.py index 11b855c..226a2f9 100644 --- a/services/news-collector/src/news_collector/collectors/reddit.py +++ b/services/news-collector/src/news_collector/collectors/reddit.py @@ -39,7 +39,9 @@ class RedditCollector(BaseCollector): headers = {"User-Agent": "TradingPlatform/1.0 (research@example.com)"} try: async with aiohttp.ClientSession() as session: - async with session.get(url, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp: + async with session.get( + url, headers=headers, timeout=aiohttp.ClientTimeout(total=10) + ) as resp: if resp.status == 200: data = await resp.json() return data.get("data", {}).get("children", []) diff --git a/services/news-collector/src/news_collector/collectors/sec_edgar.py b/services/news-collector/src/news_collector/collectors/sec_edgar.py index a00abb5..ca1d070 100644 --- a/services/news-collector/src/news_collector/collectors/sec_edgar.py +++ b/services/news-collector/src/news_collector/collectors/sec_edgar.py @@ -12,9 +12,16 @@ from news_collector.collectors.base import BaseCollector logger = logging.getLogger(__name__) TRACKED_CIKS = { - "0000320193": "AAPL", "0000789019": "MSFT", "0001652044": "GOOGL", - "0001018724": "AMZN", "0001318605": "TSLA", "0001045810": "NVDA", - "0001326801": "META", "0000019617": "JPM", "0000078003": "PFE", "0000021344": "KO", + "0000320193": "AAPL", + "0000789019": "MSFT", + "0001652044": "GOOGL", + "0001018724": "AMZN", + "0001318605": "TSLA", + "0001045810": "NVDA", + "0001326801": "META", + "0000019617": "JPM", + "0000078003": "PFE", + "0000021344": "KO", } SEC_USER_AGENT = "TradingPlatform research@example.com" @@ -37,7 +44,9 @@ class SecEdgarCollector(BaseCollector): for cik, ticker in TRACKED_CIKS.items(): try: url = f"https://data.sec.gov/submissions/CIK{cik}.json" - async with session.get(url, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp: + async with session.get( + url, headers=headers, timeout=aiohttp.ClientTimeout(total=10) + ) as resp: if resp.status == 200: data = await resp.json() data["tickers"] = [{"ticker": ticker}] @@ -72,16 +81,20 @@ class SecEdgarCollector(BaseCollector): accession = accessions[i] if i < len(accessions) else "" headline = f"{company_name} ({', '.join(tickers)}): {form} - {desc}" - items.append(NewsItem( - source=self.name, - headline=headline, - summary=desc, - url=f"https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&accession={accession}", - published_at=datetime.strptime(filing_date, "%Y-%m-%d").replace(tzinfo=timezone.utc), - symbols=tickers, - sentiment=self._vader.polarity_scores(headline)["compound"], - category=NewsCategory.FILING, - raw_data={"form": form, "accession": accession}, - )) + items.append( + NewsItem( + source=self.name, + headline=headline, + summary=desc, + url=f"https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&accession={accession}", + published_at=datetime.strptime(filing_date, "%Y-%m-%d").replace( + tzinfo=timezone.utc + ), + symbols=tickers, + sentiment=self._vader.polarity_scores(headline)["compound"], + category=NewsCategory.FILING, + raw_data={"form": form, "accession": accession}, + ) + ) return items diff --git a/services/news-collector/src/news_collector/collectors/truth_social.py b/services/news-collector/src/news_collector/collectors/truth_social.py index 2205257..33ebc86 100644 --- a/services/news-collector/src/news_collector/collectors/truth_social.py +++ b/services/news-collector/src/news_collector/collectors/truth_social.py @@ -37,7 +37,9 @@ class TruthSocialCollector(BaseCollector): headers = {"User-Agent": "TradingPlatform/1.0 (research@example.com)"} try: async with aiohttp.ClientSession() as session: - async with session.get(_API_URL, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp: + async with session.get( + _API_URL, headers=headers, timeout=aiohttp.ClientTimeout(total=10) + ) as resp: if resp.status == 200: return await resp.json() except Exception as exc: diff --git a/services/news-collector/tests/test_fed.py b/services/news-collector/tests/test_fed.py index 8acea5f..d1a736b 100644 --- a/services/news-collector/tests/test_fed.py +++ b/services/news-collector/tests/test_fed.py @@ -1,24 +1,36 @@ """Tests for Federal Reserve collector.""" + import pytest from unittest.mock import AsyncMock, patch from news_collector.collectors.fed import FedCollector + @pytest.fixture def collector(): return FedCollector() + def test_collector_name(collector): assert collector.name == "fed" assert collector.poll_interval == 3600 + async def test_is_available(collector): assert await collector.is_available() is True + async def test_collect_parses_rss(collector): mock_entries = [ - {"title": "Federal Reserve issues FOMC statement", "link": "https://www.federalreserve.gov/newsevents/pressreleases/monetary20260402a.htm", "published_parsed": (2026, 4, 2, 14, 0, 0, 0, 0, 0), "summary": "The Federal Open Market Committee decided to maintain the target range..."}, + { + "title": "Federal Reserve issues FOMC statement", + "link": "https://www.federalreserve.gov/newsevents/pressreleases/monetary20260402a.htm", + "published_parsed": (2026, 4, 2, 14, 0, 0, 0, 0, 0), + "summary": "The Federal Open Market Committee decided to maintain the target range...", + }, ] - with patch.object(collector, "_fetch_fed_rss", new_callable=AsyncMock, return_value=mock_entries): + with patch.object( + collector, "_fetch_fed_rss", new_callable=AsyncMock, return_value=mock_entries + ): items = await collector.collect() assert len(items) == 1 assert items[0].source == "fed" diff --git a/services/news-collector/tests/test_finnhub.py b/services/news-collector/tests/test_finnhub.py index 74bd5e6..a4cf169 100644 --- a/services/news-collector/tests/test_finnhub.py +++ b/services/news-collector/tests/test_finnhub.py @@ -2,7 +2,6 @@ import pytest from unittest.mock import AsyncMock, patch -from datetime import datetime, timezone from news_collector.collectors.finnhub import FinnhubCollector diff --git a/services/news-collector/tests/test_main.py b/services/news-collector/tests/test_main.py index 3ebb094..66190dc 100644 --- a/services/news-collector/tests/test_main.py +++ b/services/news-collector/tests/test_main.py @@ -1,5 +1,5 @@ """Tests for news collector scheduler.""" -import pytest + from unittest.mock import AsyncMock, MagicMock from datetime import datetime, timezone from shared.models import NewsCategory, NewsItem @@ -8,9 +8,11 @@ from news_collector.main import run_collector_once async def test_run_collector_once_stores_and_publishes(): mock_item = NewsItem( - source="test", headline="Test news", + source="test", + headline="Test news", published_at=datetime(2026, 4, 2, tzinfo=timezone.utc), - sentiment=0.5, category=NewsCategory.MACRO, + sentiment=0.5, + category=NewsCategory.MACRO, ) mock_collector = MagicMock() mock_collector.name = "test" diff --git a/services/news-collector/tests/test_reddit.py b/services/news-collector/tests/test_reddit.py index 3626c0a..440b173 100644 --- a/services/news-collector/tests/test_reddit.py +++ b/services/news-collector/tests/test_reddit.py @@ -1,33 +1,63 @@ """Tests for Reddit collector.""" + import pytest from unittest.mock import AsyncMock, patch from news_collector.collectors.reddit import RedditCollector + @pytest.fixture def collector(): return RedditCollector() + def test_collector_name(collector): assert collector.name == "reddit" assert collector.poll_interval == 900 + async def test_is_available(collector): assert await collector.is_available() is True + async def test_collect_parses_posts(collector): mock_posts = [ - {"data": {"title": "NVDA to the moon! AI demand is insane", "selftext": "Just loaded up on NVDA calls", "url": "https://reddit.com/r/wallstreetbets/123", "created_utc": 1711929600, "score": 500, "num_comments": 200, "subreddit": "wallstreetbets"}}, + { + "data": { + "title": "NVDA to the moon! AI demand is insane", + "selftext": "Just loaded up on NVDA calls", + "url": "https://reddit.com/r/wallstreetbets/123", + "created_utc": 1711929600, + "score": 500, + "num_comments": 200, + "subreddit": "wallstreetbets", + } + }, ] - with patch.object(collector, "_fetch_subreddit", new_callable=AsyncMock, return_value=mock_posts): + with patch.object( + collector, "_fetch_subreddit", new_callable=AsyncMock, return_value=mock_posts + ): items = await collector.collect() assert len(items) >= 1 assert items[0].source == "reddit" assert items[0].category.value == "social" + async def test_collect_filters_low_score(collector): mock_posts = [ - {"data": {"title": "Random question", "selftext": "", "url": "https://reddit.com/456", "created_utc": 1711929600, "score": 3, "num_comments": 1, "subreddit": "stocks"}}, + { + "data": { + "title": "Random question", + "selftext": "", + "url": "https://reddit.com/456", + "created_utc": 1711929600, + "score": 3, + "num_comments": 1, + "subreddit": "stocks", + } + }, ] - with patch.object(collector, "_fetch_subreddit", new_callable=AsyncMock, return_value=mock_posts): + with patch.object( + collector, "_fetch_subreddit", new_callable=AsyncMock, return_value=mock_posts + ): items = await collector.collect() assert items == [] diff --git a/services/news-collector/tests/test_rss.py b/services/news-collector/tests/test_rss.py index 58c5f7c..e03250a 100644 --- a/services/news-collector/tests/test_rss.py +++ b/services/news-collector/tests/test_rss.py @@ -2,7 +2,6 @@ import pytest from unittest.mock import AsyncMock, patch -from datetime import datetime, timezone from news_collector.collectors.rss import RSSCollector diff --git a/services/news-collector/tests/test_sec_edgar.py b/services/news-collector/tests/test_sec_edgar.py index a10b47a..5d4f69f 100644 --- a/services/news-collector/tests/test_sec_edgar.py +++ b/services/news-collector/tests/test_sec_edgar.py @@ -40,7 +40,9 @@ async def test_collect_parses_filings(collector): mock_datetime.now.return_value = datetime(2026, 4, 2, tzinfo=timezone.utc) mock_datetime.strptime = datetime.strptime - with patch.object(collector, "_fetch_recent_filings", new_callable=AsyncMock, return_value=[mock_response]): + with patch.object( + collector, "_fetch_recent_filings", new_callable=AsyncMock, return_value=[mock_response] + ): with patch("news_collector.collectors.sec_edgar.datetime", mock_datetime): items = await collector.collect() diff --git a/services/news-collector/tests/test_truth_social.py b/services/news-collector/tests/test_truth_social.py index bcf8a8c..91ddb9d 100644 --- a/services/news-collector/tests/test_truth_social.py +++ b/services/news-collector/tests/test_truth_social.py @@ -1,22 +1,32 @@ """Tests for Truth Social collector.""" + import pytest from unittest.mock import AsyncMock, patch from news_collector.collectors.truth_social import TruthSocialCollector + @pytest.fixture def collector(): return TruthSocialCollector() + def test_collector_name(collector): assert collector.name == "truth_social" assert collector.poll_interval == 900 + async def test_is_available(collector): assert await collector.is_available() is True + async def test_collect_parses_posts(collector): mock_posts = [ - {"content": "

We are imposing 25% tariffs on all steel imports!

", "created_at": "2026-04-02T12:00:00.000Z", "url": "https://truthsocial.com/@realDonaldTrump/12345", "id": "12345"}, + { + "content": "

We are imposing 25% tariffs on all steel imports!

", + "created_at": "2026-04-02T12:00:00.000Z", + "url": "https://truthsocial.com/@realDonaldTrump/12345", + "id": "12345", + }, ] with patch.object(collector, "_fetch_posts", new_callable=AsyncMock, return_value=mock_posts): items = await collector.collect() @@ -24,6 +34,7 @@ async def test_collect_parses_posts(collector): assert items[0].source == "truth_social" assert items[0].category.value == "policy" + async def test_collect_handles_empty(collector): with patch.object(collector, "_fetch_posts", new_callable=AsyncMock, return_value=[]): items = await collector.collect() diff --git a/services/strategy-engine/src/strategy_engine/main.py b/services/strategy-engine/src/strategy_engine/main.py index e9c96b2..5a30766 100644 --- a/services/strategy-engine/src/strategy_engine/main.py +++ b/services/strategy-engine/src/strategy_engine/main.py @@ -126,9 +126,9 @@ async def run() -> None: anthropic_model=config.anthropic_model, max_picks=config.selector_max_picks, ) - tasks.append(asyncio.create_task( - run_stock_selector(selector, notifier, db, config, log) - )) + tasks.append( + asyncio.create_task(run_stock_selector(selector, notifier, db, config, log)) + ) log.info("stock_selector_enabled", time=config.selector_final_time) await asyncio.gather(*tasks) diff --git a/services/strategy-engine/src/strategy_engine/stock_selector.py b/services/strategy-engine/src/strategy_engine/stock_selector.py index e1f2fe7..268d557 100644 --- a/services/strategy-engine/src/strategy_engine/stock_selector.py +++ b/services/strategy-engine/src/strategy_engine/stock_selector.py @@ -4,17 +4,14 @@ import json import logging import re from datetime import datetime, timezone -from decimal import Decimal -from typing import Optional import aiohttp -import pandas as pd from shared.alpaca import AlpacaClient from shared.broker import RedisBroker from shared.db import Database from shared.models import OrderSide -from shared.sentiment_models import Candidate, MarketSentiment, SelectedStock, SymbolScore +from shared.sentiment_models import Candidate, MarketSentiment, SelectedStock logger = logging.getLogger(__name__) @@ -325,7 +322,9 @@ class StockSelector: ema20 = sum(closes[-20:]) / 20 # simple approximation current_price = closes[-1] if current_price <= ema20: - logger.debug("%s price %.2f <= EMA20 %.2f", candidate.symbol, current_price, ema20) + logger.debug( + "%s price %.2f <= EMA20 %.2f", candidate.symbol, current_price, ema20 + ) continue avg_volume = sum(volumes[:-1]) / max(len(volumes) - 1, 1) @@ -333,7 +332,9 @@ class StockSelector: if current_volume <= 0.5 * avg_volume: logger.debug( "%s volume %.0f <= 50%% avg %.0f", - candidate.symbol, current_volume, avg_volume, + candidate.symbol, + current_volume, + avg_volume, ) continue diff --git a/services/strategy-engine/tests/test_stock_selector.py b/services/strategy-engine/tests/test_stock_selector.py index a2f5bca..ff9d09c 100644 --- a/services/strategy-engine/tests/test_stock_selector.py +++ b/services/strategy-engine/tests/test_stock_selector.py @@ -1,12 +1,8 @@ """Tests for stock selector engine.""" -import pytest -from unittest.mock import AsyncMock, MagicMock, patch +from unittest.mock import AsyncMock, MagicMock from datetime import datetime, timezone -from decimal import Decimal -from shared.models import OrderSide -from shared.sentiment_models import SymbolScore, MarketSentiment, SelectedStock, Candidate from strategy_engine.stock_selector import ( SentimentCandidateSource, @@ -17,10 +13,12 @@ from strategy_engine.stock_selector import ( async def test_sentiment_candidate_source(): mock_db = MagicMock() - mock_db.get_top_symbol_scores = AsyncMock(return_value=[ - {"symbol": "AAPL", "composite": 0.8, "news_count": 5}, - {"symbol": "NVDA", "composite": 0.6, "news_count": 3}, - ]) + mock_db.get_top_symbol_scores = AsyncMock( + return_value=[ + {"symbol": "AAPL", "composite": 0.8, "news_count": 5}, + {"symbol": "NVDA", "composite": 0.6, "news_count": 3}, + ] + ) source = SentimentCandidateSource(mock_db) candidates = await source.get_candidates() @@ -64,15 +62,19 @@ def test_parse_llm_selections_with_markdown(): async def test_selector_blocks_on_risk_off(): mock_db = MagicMock() - mock_db.get_latest_market_sentiment = AsyncMock(return_value={ - "fear_greed": 15, - "fear_greed_label": "Extreme Fear", - "vix": 35.0, - "fed_stance": "neutral", - "market_regime": "risk_off", - "updated_at": datetime.now(timezone.utc), - }) - - selector = StockSelector(db=mock_db, broker=MagicMock(), alpaca=MagicMock(), anthropic_api_key="test") + mock_db.get_latest_market_sentiment = AsyncMock( + return_value={ + "fear_greed": 15, + "fear_greed_label": "Extreme Fear", + "vix": 35.0, + "fed_stance": "neutral", + "market_regime": "risk_off", + "updated_at": datetime.now(timezone.utc), + } + ) + + selector = StockSelector( + db=mock_db, broker=MagicMock(), alpaca=MagicMock(), anthropic_api_key="test" + ) result = await selector.select() assert result == [] diff --git a/shared/alembic/versions/002_news_sentiment_tables.py b/shared/alembic/versions/002_news_sentiment_tables.py index b57f1d6..402ff87 100644 --- a/shared/alembic/versions/002_news_sentiment_tables.py +++ b/shared/alembic/versions/002_news_sentiment_tables.py @@ -29,7 +29,9 @@ def upgrade() -> None: sa.Column("sentiment", sa.Float, nullable=False), sa.Column("category", sa.Text, nullable=False), sa.Column("raw_data", sa.Text), - sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), + sa.Column( + "created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now() + ), ) op.create_index("idx_news_items_published", "news_items", ["published_at"]) op.create_index("idx_news_items_source", "news_items", ["source"]) @@ -68,7 +70,9 @@ def upgrade() -> None: sa.Column("reason", sa.Text, nullable=False), sa.Column("key_news", sa.Text), sa.Column("sentiment_snapshot", sa.Text), - sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), + sa.Column( + "created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now() + ), ) op.create_index("idx_stock_selections_date", "stock_selections", ["trade_date"]) diff --git a/shared/src/shared/db.py b/shared/src/shared/db.py index 55f93b4..9cc8686 100644 --- a/shared/src/shared/db.py +++ b/shared/src/shared/db.py @@ -299,11 +299,7 @@ class Database: async def get_top_symbol_scores(self, limit: int = 20) -> list[dict]: """Retrieve top symbol scores ordered by composite descending.""" - stmt = ( - select(SymbolScoreRow) - .order_by(SymbolScoreRow.composite.desc()) - .limit(limit) - ) + stmt = select(SymbolScoreRow).order_by(SymbolScoreRow.composite.desc()).limit(limit) async with self._session_factory() as session: try: result = await session.execute(stmt) @@ -431,7 +427,9 @@ class Database: "conviction": r.conviction, "reason": r.reason, "key_news": json.loads(r.key_news) if r.key_news else [], - "sentiment_snapshot": json.loads(r.sentiment_snapshot) if r.sentiment_snapshot else {}, + "sentiment_snapshot": json.loads(r.sentiment_snapshot) + if r.sentiment_snapshot + else {}, "created_at": r.created_at, } for r in rows diff --git a/shared/src/shared/notifier.py b/shared/src/shared/notifier.py index 9630a18..3d7b6cf 100644 --- a/shared/src/shared/notifier.py +++ b/shared/src/shared/notifier.py @@ -137,8 +137,7 @@ class TelegramNotifier: for i, s in enumerate(selections, 1): emoji = side_emoji.get(s.side.value, "⚪") lines.append( - f"{i}. {s.symbol} {emoji} {s.side.value} " - f"(conviction: {s.conviction:.0%})" + f"{i}. {s.symbol} {emoji} {s.side.value} (conviction: {s.conviction:.0%})" ) lines.append(f" {s.reason}") if s.key_news: diff --git a/shared/src/shared/sentiment.py b/shared/src/shared/sentiment.py index a20227e..449eb76 100644 --- a/shared/src/shared/sentiment.py +++ b/shared/src/shared/sentiment.py @@ -2,7 +2,7 @@ import logging from dataclasses import dataclass, field -from datetime import datetime, timedelta, timezone +from datetime import datetime, timezone from shared.sentiment_models import SymbolScore @@ -82,9 +82,7 @@ class SentimentAggregator: + filing_score * self.WEIGHTS["filing"] ) - def aggregate( - self, news_items: list[dict], now: datetime - ) -> dict[str, SymbolScore]: + def aggregate(self, news_items: list[dict], now: datetime) -> dict[str, SymbolScore]: """Aggregate news items into per-symbol scores. Each dict needs: symbols, sentiment, category, published_at. diff --git a/shared/tests/test_db_news.py b/shared/tests/test_db_news.py index f13cf1e..a2c9140 100644 --- a/shared/tests/test_db_news.py +++ b/shared/tests/test_db_news.py @@ -1,7 +1,5 @@ """Tests for database news/sentiment methods. Uses in-memory SQLite.""" -import json -import uuid import pytest from datetime import datetime, date, timezone diff --git a/shared/tests/test_sentiment_aggregator.py b/shared/tests/test_sentiment_aggregator.py index f9277e7..a99c711 100644 --- a/shared/tests/test_sentiment_aggregator.py +++ b/shared/tests/test_sentiment_aggregator.py @@ -1,4 +1,5 @@ """Tests for sentiment aggregator.""" + import pytest from datetime import datetime, timezone, timedelta from shared.sentiment import SentimentAggregator @@ -35,7 +36,9 @@ def test_freshness_decay_old(): def test_compute_composite(): a = SentimentAggregator() - composite = a._compute_composite(news_score=0.5, social_score=0.3, policy_score=0.8, filing_score=0.2) + composite = a._compute_composite( + news_score=0.5, social_score=0.3, policy_score=0.8, filing_score=0.2 + ) expected = 0.5 * 0.3 + 0.3 * 0.2 + 0.8 * 0.3 + 0.2 * 0.2 assert abs(composite - expected) < 0.001 @@ -44,7 +47,12 @@ def test_aggregate_news_by_symbol(aggregator): now = datetime.now(timezone.utc) news_items = [ {"symbols": ["AAPL"], "sentiment": 0.8, "category": "earnings", "published_at": now}, - {"symbols": ["AAPL"], "sentiment": 0.3, "category": "macro", "published_at": now - timedelta(hours=2)}, + { + "symbols": ["AAPL"], + "sentiment": 0.3, + "category": "macro", + "published_at": now - timedelta(hours=2), + }, {"symbols": ["MSFT"], "sentiment": -0.5, "category": "policy", "published_at": now}, ] scores = aggregator.aggregate(news_items, now) diff --git a/shared/tests/test_sentiment_models.py b/shared/tests/test_sentiment_models.py index 74f1acd..25fc371 100644 --- a/shared/tests/test_sentiment_models.py +++ b/shared/tests/test_sentiment_models.py @@ -1,6 +1,5 @@ """Tests for news and sentiment models.""" -import pytest from datetime import datetime, timezone from shared.models import NewsCategory, NewsItem, OrderSide -- cgit v1.2.3