feat: Binance WS, news client, and social client
Add ThreadedWebsocketManager-based BinanceWSClient for real-time price streaming, NewsClient for CryptoPanic/NewsAPI fetching with coin filtering, and SocialClient for Reddit post retrieval with keyword filtering and simple keyword-based sentiment scoring. Includes unit tests for news and social clients (4/4 passing). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
31
tests/test_news_client.py
Normal file
31
tests/test_news_client.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import pytest
|
||||
from data.news_client import NewsClient
|
||||
|
||||
@pytest.fixture
|
||||
def client():
|
||||
return NewsClient(cryptopanic_key="test", newsapi_key="test")
|
||||
|
||||
def test_parse_cryptopanic_response(client):
|
||||
raw = {
|
||||
"results": [
|
||||
{"title": "Bitcoin hits new high", "published_at": "2026-03-20T10:00:00Z",
|
||||
"currencies": [{"code": "BTC"}], "kind": "news",
|
||||
"votes": {"positive": 10, "negative": 2}},
|
||||
{"title": "ETH upgrade coming", "published_at": "2026-03-20T09:00:00Z",
|
||||
"currencies": [{"code": "ETH"}], "kind": "news",
|
||||
"votes": {"positive": 5, "negative": 1}},
|
||||
]
|
||||
}
|
||||
articles = client.parse_cryptopanic(raw)
|
||||
assert len(articles) == 2
|
||||
assert articles[0]["coin"] == "BTC"
|
||||
assert articles[0]["title"] == "Bitcoin hits new high"
|
||||
|
||||
def test_get_news_for_coin_filters(client):
|
||||
articles = [
|
||||
{"coin": "BTC", "title": "BTC news", "sentiment_votes": {"positive": 5, "negative": 1}},
|
||||
{"coin": "ETH", "title": "ETH news", "sentiment_votes": {"positive": 3, "negative": 3}},
|
||||
]
|
||||
btc_news = client.filter_by_coin(articles, "BTC")
|
||||
assert len(btc_news) == 1
|
||||
assert btc_news[0]["coin"] == "BTC"
|
||||
25
tests/test_social_client.py
Normal file
25
tests/test_social_client.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import pytest
|
||||
from data.social_client import SocialClient
|
||||
|
||||
def test_analyze_reddit_posts():
|
||||
client = SocialClient(reddit_client_id="x", reddit_secret="x", reddit_user_agent="x")
|
||||
posts = [
|
||||
{"title": "Bitcoin is amazing! Going to the moon!", "score": 100, "num_comments": 50},
|
||||
{"title": "BTC crash incoming, sell everything now", "score": 20, "num_comments": 10},
|
||||
{"title": "Bitcoin steady at 40k, not bad", "score": 50, "num_comments": 30},
|
||||
]
|
||||
result = client.simple_sentiment(posts)
|
||||
assert "positive" in result
|
||||
assert "negative" in result
|
||||
assert "neutral" in result
|
||||
assert result["positive"] + result["negative"] + result["neutral"] == len(posts)
|
||||
|
||||
def test_keyword_match():
|
||||
client = SocialClient(reddit_client_id="x", reddit_secret="x", reddit_user_agent="x")
|
||||
posts = [
|
||||
{"title": "Bitcoin BTC going up"},
|
||||
{"title": "Ethereum news today"},
|
||||
{"title": "BTC and ETH analysis"},
|
||||
]
|
||||
filtered = client.filter_posts_by_coin(posts, "BTC")
|
||||
assert len(filtered) == 2
|
||||
Reference in New Issue
Block a user