diff options
| author | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-04-02 14:17:43 +0900 |
|---|---|---|
| committer | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-04-02 14:17:43 +0900 |
| commit | 35aa61c651217663406c9cd6df404f85338b2d68 (patch) | |
| tree | 9d85dd87e725984d45d7b6bdfef8b316ddfc4ae7 /services | |
| parent | 17540c99d5e28576a6642e23d7bd6b297513e2d8 (diff) | |
style: fix lint and formatting issues across news collector and shared
Diffstat (limited to 'services')
15 files changed, 155 insertions, 64 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": "<p>We are imposing 25% tariffs on all steel imports!</p>", "created_at": "2026-04-02T12:00:00.000Z", "url": "https://truthsocial.com/@realDonaldTrump/12345", "id": "12345"}, + { + "content": "<p>We are imposing 25% tariffs on all steel imports!</p>", + "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 == [] |
