- git mv stock-lab/ → stock/ - docker-compose.yml: 서비스 키 + container_name + build.context + frontend.depends_on + agent-office STOCK_LAB_URL → STOCK_URL - agent-office/app: config.py, service_proxy.py, agents/stock.py, tests/ STOCK_LAB_URL → STOCK_URL - nginx/default.conf: proxy_pass http://stock-lab → http://stock (3 lines) - CLAUDE.md / README.md / STATUS.md / scripts/ 문구 갱신 - stock/ 내부 자기 참조 갱신 lab 네이밍 정책 (feedback_lab_naming.md) graduation. API URL / Python import / DB 파일명 변경 없음.
58 lines
1.8 KiB
Python
58 lines
1.8 KiB
Python
import datetime as dt
|
|
import pandas as pd
|
|
import pytest
|
|
from app.screener.nodes.ai_news import AiNewsSentiment
|
|
|
|
|
|
class FakeCtx:
|
|
def __init__(self, df=None):
|
|
self.news_sentiment = df
|
|
self.asof = dt.date(2026, 5, 13)
|
|
|
|
|
|
def test_compute_empty_context():
|
|
out = AiNewsSentiment().compute(FakeCtx(None), {"min_news_count": 1})
|
|
assert out.empty
|
|
|
|
|
|
def test_compute_with_data_percentile_ranks():
|
|
df = pd.DataFrame([
|
|
{"ticker": "A", "score_raw": -5.0, "news_count": 3},
|
|
{"ticker": "B", "score_raw": 0.0, "news_count": 3},
|
|
{"ticker": "C", "score_raw": 8.0, "news_count": 3},
|
|
])
|
|
out = AiNewsSentiment().compute(FakeCtx(df), {"min_news_count": 1})
|
|
assert len(out) == 3
|
|
# percentile rank: A (lowest) < B < C (highest)
|
|
assert out.loc["A"] < out.loc["B"] < out.loc["C"]
|
|
# all within [0, 100]
|
|
assert (out >= 0).all() and (out <= 100).all()
|
|
|
|
|
|
def test_compute_filters_by_min_news_count():
|
|
df = pd.DataFrame([
|
|
{"ticker": "A", "score_raw": -5.0, "news_count": 0}, # 필터됨
|
|
{"ticker": "B", "score_raw": 0.0, "news_count": 2},
|
|
{"ticker": "C", "score_raw": 8.0, "news_count": 5},
|
|
])
|
|
out = AiNewsSentiment().compute(FakeCtx(df), {"min_news_count": 1})
|
|
assert "A" not in out.index
|
|
assert "B" in out.index
|
|
assert "C" in out.index
|
|
|
|
|
|
def test_compute_all_filtered_returns_empty():
|
|
df = pd.DataFrame([
|
|
{"ticker": "A", "score_raw": 5.0, "news_count": 0},
|
|
])
|
|
out = AiNewsSentiment().compute(FakeCtx(df), {"min_news_count": 1})
|
|
assert out.empty
|
|
|
|
|
|
def test_metadata():
|
|
n = AiNewsSentiment()
|
|
assert n.name == "ai_news"
|
|
assert "AI" in n.label or "뉴스" in n.label
|
|
assert n.default_params == {"min_news_count": 1}
|
|
assert "min_news_count" in n.param_schema["properties"]
|