feat(sentiment): search crypto communities on Reddit for a crypto ticker (#1461)

- a crypto pair is searched in r/CryptoCurrency and r/CryptoMarkets, plus r/Bitcoin, r/ethereum or r/solana for those coins, still in one request
- the Sentiment Analyst's prompt names the subreddits actually searched
This commit is contained in:
Yijia-Xiao
2026-10-03 21:27:43 +00:00
parent df630b9aea
commit c925f60328
4 changed files with 81 additions and 8 deletions
+22
View File
@@ -311,3 +311,25 @@ def test_an_unavailable_screen_keeps_every_post_and_says_so():
screened = reddit.fetch_reddit_posts("NVDA", subreddits=("a", "b"), screen=unavailable)
plain = reddit.fetch_reddit_posts("NVDA", subreddits=("a", "b"))
assert screened == "<Jev screening unavailable (HTTP 529); posts are unscreened>\n\n" + plain
@pytest.mark.unit
@pytest.mark.parametrize("ticker, expected", [
("NVDA", ("wallstreetbets", "stocks", "investing")),
("BTC-USD", ("Bitcoin", "CryptoCurrency", "CryptoMarkets")),
("ETH-USD", ("ethereum", "CryptoCurrency", "CryptoMarkets")),
("SOL-USD", ("solana", "CryptoCurrency", "CryptoMarkets")),
("DOGE-USD", ("CryptoCurrency", "CryptoMarkets")),
])
def test_a_crypto_ticker_is_searched_in_crypto_communities(ticker, expected):
assert reddit.subreddits_for(ticker) == expected
@pytest.mark.unit
def test_a_crypto_pair_is_fetched_from_its_communities_in_one_request():
with patch.object(reddit, "_fetch_subreddit_rss", return_value=[]) as fetch:
out = reddit.fetch_reddit_posts("ETH-USD")
fetch.assert_called_once()
query, subs = fetch.call_args.args[:2]
assert (query, subs) == ("ETH", "ethereum+CryptoCurrency+CryptoMarkets")
assert "r/wallstreetbets" not in out
+20
View File
@@ -146,3 +146,23 @@ def test_constraint_text_is_unambiguous():
# No template braces: it is embedded in ChatPromptTemplate strings, where
# braces would be parsed as input variables.
assert "{" not in NO_EXTERNAL_TOOLS and "}" not in NO_EXTERNAL_TOOLS
@pytest.mark.unit
def test_the_sentiment_prompt_names_the_subreddits_searched(monkeypatch):
from tradingagents.agents.schemas import SentimentBand, SentimentReport
monkeypatch.setattr(sentiment, "fetch_stocktwits_messages", lambda *a, **k: "st")
monkeypatch.setattr(sentiment, "fetch_reddit_posts", lambda *a, **k: "rd")
monkeypatch.setattr(sentiment.get_news, "func", lambda *a, **k: "news", raising=False)
captured = {}
llm = _capturing_llm(captured, SentimentReport(
overall_band=SentimentBand.NEUTRAL, overall_score=5.0, confidence="low", narrative="n",
))
sentiment.create_sentiment_analyst(llm)({
"company_of_interest": "BTC-USD", "trade_date": "2026-01-15",
"asset_type": "crypto", "messages": [],
})
text = _prompt_text(captured["prompt"])
assert "r/Bitcoin, r/CryptoCurrency, r/CryptoMarkets" in text
assert "wallstreetbets" not in text