fix(stock): AI 뉴스 리포트 하루 밀림 해소 — asof를 KST로 보정 + LLM에 현재 일자 주입
근본원인: stock 컨테이너는 python:3.12-alpine + tzdata 미설치라 TZ=Asia/Seoul이 무효 → date.today()가 UTC를 반환. AI 뉴스 리포트 cron은 08:00 KST(=전날 23:00 UTC)라 asof가 어제로 계산돼 라벨·기사 윈도우·news_sentiment 저장이 전부 하루 밀렸음 (월요일은 일요일 UTC로 계산돼 skip_weekend까지). - screener/router.py: _today_kst()(=utcnow+9h, holdings_intel 관용) 추가. /snapshot/refresh · /snapshot/refresh-news-sentiment의 asof 기본값을 KST로. - ai_news/analyzer.py: score_sentiment(asof=...) → 프롬프트 앞에 "오늘 날짜" 명시, LLM이 현재 일자 기준으로 뉴스 평가(사용자 요청). - ai_news/pipeline.py: refresh_daily가 asof를 score_sentiment까지 스레딩. - 테스트: _today_kst KST 보정 + analyzer asof 주입 2종 TDD Red→Green. 기존 pipeline 목 시그니처에 asof 반영. stock 전체 149 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EqCYBhvTcdeCTUDX3RhWx9
This commit is contained in:
@@ -39,7 +39,7 @@ async def test_refresh_daily_happy_path(conn):
|
||||
scores_by_ticker = {
|
||||
"005930": 7.5, "000660": 4.0, "373220": -6.0,
|
||||
}
|
||||
async def fake_score(llm, ticker, news, *, name=None, model="m"):
|
||||
async def fake_score(llm, ticker, news, *, name=None, model="m", asof=None):
|
||||
return {
|
||||
"ticker": ticker, "score_raw": scores_by_ticker[ticker],
|
||||
"reason": f"r{ticker}", "news_count": 1,
|
||||
@@ -81,7 +81,7 @@ async def test_refresh_daily_failures_isolated(conn):
|
||||
}
|
||||
fake_stats = {"total_articles": 3, "matched_pairs": 3, "hit_tickers": 3}
|
||||
|
||||
async def fake_score(llm, ticker, news, *, name=None, model="m"):
|
||||
async def fake_score(llm, ticker, news, *, name=None, model="m", asof=None):
|
||||
if ticker == "000660":
|
||||
raise RuntimeError("llm exploded")
|
||||
return {
|
||||
@@ -116,7 +116,7 @@ async def test_refresh_daily_no_match_ticker_skipped(conn):
|
||||
}
|
||||
fake_stats = {"total_articles": 1, "matched_pairs": 1, "hit_tickers": 1}
|
||||
|
||||
async def fake_score(llm, ticker, news, *, name=None, model="m"):
|
||||
async def fake_score(llm, ticker, news, *, name=None, model="m", asof=None):
|
||||
return {
|
||||
"ticker": ticker, "score_raw": 5.0, "reason": "r",
|
||||
"news_count": 1, "tokens_input": 100, "tokens_output": 20,
|
||||
@@ -152,7 +152,7 @@ async def test_refresh_daily_sign_gate_no_positive_in_neg(conn):
|
||||
fake_stats = {"total_articles": 3, "matched_pairs": 3, "hit_tickers": 3}
|
||||
scores = {"005930": 6.0, "000660": 2.0, "373220": 0.5} # 모두 양수
|
||||
|
||||
async def fake_score(llm, ticker, news, *, name=None, model="m"):
|
||||
async def fake_score(llm, ticker, news, *, name=None, model="m", asof=None):
|
||||
return {
|
||||
"ticker": ticker, "score_raw": scores[ticker], "reason": "r",
|
||||
"news_count": 1, "tokens_input": 1, "tokens_output": 1, "model": model,
|
||||
@@ -183,7 +183,7 @@ async def test_refresh_daily_sign_gate_excludes_neutral(conn):
|
||||
fake_stats = {"total_articles": 3, "matched_pairs": 3, "hit_tickers": 3}
|
||||
scores = {"005930": 3.0, "000660": 0.0, "373220": -3.0}
|
||||
|
||||
async def fake_score(llm, ticker, news, *, name=None, model="m"):
|
||||
async def fake_score(llm, ticker, news, *, name=None, model="m", asof=None):
|
||||
return {
|
||||
"ticker": ticker, "score_raw": scores[ticker], "reason": "r",
|
||||
"news_count": 1, "tokens_input": 1, "tokens_output": 1, "model": model,
|
||||
|
||||
Reference in New Issue
Block a user