feat(stock): news_issues (감성 기반 악재 flag)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -172,6 +172,43 @@ def market_events(ticker: str, ticker_prices: "pd.DataFrame",
|
||||
return events
|
||||
|
||||
|
||||
# ---- Task 3.2: news_issues ----
|
||||
|
||||
NEG_SENTIMENT = -0.3 # 이하면 악재 후보
|
||||
|
||||
|
||||
def _news_sentiment_map(date: str) -> dict:
|
||||
"""date 기준 news_sentiment 테이블에서 ticker → {score_raw, news_count} 맵 반환."""
|
||||
with db._conn() as conn:
|
||||
try:
|
||||
rows = conn.execute(
|
||||
"SELECT ticker, score_raw, news_count FROM news_sentiment WHERE date=?",
|
||||
(date,),
|
||||
).fetchall()
|
||||
except Exception:
|
||||
return {}
|
||||
return {r["ticker"]: {"score_raw": r["score_raw"], "news_count": r["news_count"]}
|
||||
for r in rows}
|
||||
|
||||
|
||||
def news_issues(tickers: list[str], date: str, use_llm: bool = True) -> dict[str, list]:
|
||||
"""news_sentiment 음수 → 악재 flag. (LLM 요약은 best-effort; 단위 테스트는 use_llm=False로.)"""
|
||||
senti = _news_sentiment_map(date)
|
||||
out: dict[str, list] = {}
|
||||
for t in tickers:
|
||||
s = senti.get(t)
|
||||
if not s or s["score_raw"] is None:
|
||||
continue
|
||||
if s["score_raw"] <= NEG_SENTIMENT:
|
||||
sev = "high" if s["score_raw"] <= NEG_SENTIMENT * 2 else "med"
|
||||
out.setdefault(t, []).append({
|
||||
"type": "news",
|
||||
"severity": sev,
|
||||
"summary": f"부정 뉴스 감성({s['score_raw']:+.2f}, {s.get('news_count', 0)}건)",
|
||||
})
|
||||
return out
|
||||
|
||||
|
||||
def decide_action(tech_score: float, exit_flags: dict, pnl: float | None,
|
||||
add_score: float = ADD_SCORE) -> tuple[str, str]:
|
||||
"""액션 결정 매트릭스: sell > trim > add > hold (우선순위 순).
|
||||
|
||||
@@ -203,3 +203,13 @@ def test_market_events_detects_move_and_volume():
|
||||
types = {e["type"] for e in evts}
|
||||
assert "price_move" in types
|
||||
assert "volume_surge" in types
|
||||
|
||||
|
||||
def test_news_issues_flags_negative_sentiment(monkeypatch):
|
||||
# news_sentiment: 005930 음수 점수 → 악재 flag
|
||||
monkeypatch.setattr(hi, "_news_sentiment_map", lambda date: {
|
||||
"005930": {"score_raw": -0.6, "news_count": 8}})
|
||||
issues = hi.news_issues(["005930"], date="2026-05-29", use_llm=False)
|
||||
assert "005930" in issues
|
||||
assert issues["005930"][0]["type"] == "news"
|
||||
assert issues["005930"][0]["severity"] in ("med", "high")
|
||||
|
||||
Reference in New Issue
Block a user