mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-09-27 06:56:39 +03:00
feat(sentiment): screen social posts with TypeSafe's Jev (#1376)
- with TYPESAFE_API_KEY set, each StockTwits and Reddit post is asked whether it is about the company and its stance on the stock - posts clearly about something else are dropped before the per-source cut, and each block opens with a stance count - any failed request leaves the source's posts unscreened and says so; without a key nothing changes
This commit is contained in:
@@ -8,6 +8,7 @@ transport error must degrade to a placeholder rather than raise.
|
||||
from __future__ import annotations
|
||||
|
||||
import http.client
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
from urllib.error import HTTPError
|
||||
|
||||
@@ -75,3 +76,41 @@ class TestStockTwitsCryptoSymbols:
|
||||
with patch.object(stocktwits, "urlopen", side_effect=fake_urlopen):
|
||||
stocktwits.fetch_stocktwits_messages("BTC-USD")
|
||||
assert "/symbol/BTC.X.json" in seen["url"]
|
||||
|
||||
|
||||
def _stream(*bodies):
|
||||
payload = {"messages": [
|
||||
{"body": b, "created_at": "2026-01-09T15:00:00Z", "user": {"username": "u"},
|
||||
"entities": {"sentiment": {"basic": "Bullish"}}}
|
||||
for b in bodies
|
||||
]}
|
||||
|
||||
class _Resp:
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *a):
|
||||
return False
|
||||
|
||||
def read(self):
|
||||
return json.dumps(payload).encode()
|
||||
return _Resp()
|
||||
|
||||
|
||||
def _drop_spam(texts):
|
||||
return [not t.startswith("SPAM") for t in texts], "Screened: note"
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestStockTwitsScreening:
|
||||
def test_screened_out_messages_leave_the_block_and_its_counts(self):
|
||||
with patch.object(stocktwits, "urlopen", return_value=_stream("SPAM", "long NVDA")):
|
||||
out = stocktwits.fetch_stocktwits_messages("NVDA", screen=_drop_spam)
|
||||
assert out.startswith("Screened: note")
|
||||
assert "long NVDA" in out and "SPAM" not in out
|
||||
assert "Total: 1 most-recent" in out
|
||||
|
||||
def test_all_screened_out_is_not_called_empty(self):
|
||||
with patch.object(stocktwits, "urlopen", return_value=_stream("SPAM")):
|
||||
out = stocktwits.fetch_stocktwits_messages("NVDA", screen=_drop_spam)
|
||||
assert "none of the 1 StockTwits messages is about $NVDA" in out
|
||||
|
||||
Reference in New Issue
Block a user