test(stock): Phase 3 커버리지 보강 (volume Z경로·외인매도·severity경계·빈포트)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 22:09:05 +09:00
parent 3056e8d35f
commit c3a3055060
2 changed files with 48 additions and 1 deletions

View File

@@ -152,7 +152,7 @@ def market_events(ticker: str, ticker_prices: "pd.DataFrame",
last_vol = vol.iloc[-1]
if mu > 0 and (
(sd and (last_vol - mu) / sd >= p["vol_z"])
or (not sd and last_vol >= mu * p["vol_z"]) # sd=0 fallback: plain ratio
or (not sd and last_vol >= mu * p["vol_z"]) # sd=0 (평탄 기준선): vol_z를 Z-score가 아닌 단순 배수로 사용
):
z_txt = f"{(last_vol - mu) / sd:.1f}" if sd else f"ratio={last_vol / mu:.1f}x"
events.append({

View File

@@ -226,3 +226,50 @@ def test_portfolio_health():
assert h["positions"] == 2
assert 0 <= h["max_weight"] <= 1.0
assert "total_eval" in h and "total_pnl" in h and "cash_ratio" in h
def test_market_events_volume_surge_zscore_path():
# 변동 있는 기준선 → Z-score 경로(sd>0) 검증 (sd=0 fallback 아님)
import random as _r
_r.seed(1)
base_vols = [1000 + _r.randint(-50, 50) for _ in range(30)]
closes = [1000] * 30 + [1010]
vols = base_vols + [max(base_vols) * 10] # 마지막날 큰 급증
df = _ticker_prices(closes, vols)
evts = hi.market_events("005930", df, None, DEFAULT_EVENT)
assert any(e["type"] == "volume_surge" for e in evts)
def test_market_events_foreign_selling():
closes = [1000] * 5
df = _ticker_prices(closes)
import datetime as _dt
base = _dt.date(2025, 1, 1)
flow = pd.DataFrame({
"ticker": ["005930"] * 5,
"date": [(base + _dt.timedelta(days=i)).isoformat() for i in range(5)],
"foreign_net": [100, 50, -10, -20, -30], # 최근 3일 연속 순매도
"institution_net": [0] * 5,
})
evts = hi.market_events("005930", df, flow, DEFAULT_EVENT)
assert any(e["type"] == "foreign_selling" for e in evts)
def test_news_issues_severity_high_boundary(monkeypatch):
monkeypatch.setattr(hi, "_news_sentiment_map", lambda date: {
"005930": {"score_raw": -0.6, "news_count": 5}}) # 정확히 high 경계
issues = hi.news_issues(["005930"], date="2026-05-29", use_llm=False)
assert issues["005930"][0]["severity"] == "high"
def test_portfolio_health_empty_and_zero():
# 빈 포트 → 0/빈값, 크래시 없음
h0 = hi.portfolio_health([], total_cash=0)
assert h0["positions"] == 0
assert h0["max_weight"] == 0.0
assert h0["total_pnl_rate"] == 0.0
assert h0["cash_ratio"] == 0.0
# total_buy=0 (avg_price 0) → div-by-zero 없이 0.0
h1 = hi.portfolio_health([{"ticker": "X", "quantity": 1, "avg_price": 0,
"current_price": 0, "is_krx": True}], total_cash=0)
assert h1["total_pnl_rate"] == 0.0