Files
auto-stock/backend/tests/test_ai_analysis_buy_amount.py
shuim acbd9f35ea feat: AI 투자 분석에 매수 추천 금액 표시
BUY 신호일 때 실제 자동매매와 동일한 기준으로 매수 금액·수량을 계산해 패널 상단에 표시.
  · 종목당 상한 = 총자산 × MAX_POSITION_SIZE(적응형 모드면 그 값)
  · 신뢰도 보정 = 예산 × (confidence/0.7), 0.5~1.2배
  · 현금 여력(최소 현금보유 제외)·스윙 합산 상한(SWING_MAX_CAPITAL_RATIO) 잔여로 클램프
BUY 가 아니거나 예산이 1주 미만이면 금액 대신 사유를 표시. 테스트 6건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 13:33:06 +09:00

69 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""AI 투자 분석 — 매수 추천 금액 산출 검증 (자동매매 사이징과 동일 기준)."""
from unittest.mock import patch
import pytest
from app.api.endpoints.market_data import _suggest_buy_amount
from app.api.endpoints.portfolio import portfolio_cache
def _summary(total_assets=10_000_000, cash=5_000_000, stock_value=3_000_000):
return {"total_assets": total_assets, "available_cash": cash, "total_value": stock_value}
@pytest.fixture(autouse=True)
def _cache():
portfolio_cache.summary = _summary()
yield
portfolio_cache.summary = None
class _Adp:
fallback_used = False
position_size = 0.06
def test_buy_amount_uses_position_cap_and_confidence():
with patch("app.services.adaptive_strategy.get_current_adaptive_params", return_value=_Adp()):
out = _suggest_buy_amount(current_price=70_000, recommendation="BUY",
confidence=0.7, stock_code="005930")
# 1,000만 × 6% = 60만, 신뢰도 0.7 → 보정 1.0 → 70,000원 × 8주 = 560,000
assert out["suggested_quantity"] == 8
assert out["suggested_amount"] == 560_000
assert out["position_ratio"] == pytest.approx(5.6, abs=0.01)
assert "6%" in out["sizing_note"]
def test_high_confidence_scales_up_capped_at_120pct():
with patch("app.services.adaptive_strategy.get_current_adaptive_params", return_value=_Adp()):
out = _suggest_buy_amount(70_000, "BUY", 1.0, "005930")
# 60만 × min(1.2, 1.0/0.7=1.43) = 72만 → 10주
assert out["suggested_quantity"] == 10
def test_non_buy_recommendation_returns_zero():
for rec in ("HOLD", "SELL"):
out = _suggest_buy_amount(70_000, rec, 0.8, "005930")
assert out["suggested_amount"] == 0 and rec in out["sizing_note"]
def test_limited_by_available_cash_and_reserve():
portfolio_cache.summary = _summary(cash=600_000) # 예수금 60만, 최소보유 5% = 50만
with patch("app.services.adaptive_strategy.get_current_adaptive_params", return_value=_Adp()):
out = _suggest_buy_amount(70_000, "BUY", 0.7, "005930")
assert out["suggested_quantity"] == 1 # 사용 가능 10만 → 1주
def test_limited_by_swing_capital_cap():
# 스윙 상한 50% = 500만, 이미 490만 보유 → 잔여 10만
portfolio_cache.summary = _summary(stock_value=4_900_000)
with patch("app.services.adaptive_strategy.get_current_adaptive_params", return_value=_Adp()):
out = _suggest_buy_amount(70_000, "BUY", 0.7, "005930")
assert out["suggested_quantity"] == 1
def test_no_balance_info_reports_reason():
portfolio_cache.summary = None
out = _suggest_buy_amount(70_000, "BUY", 0.8, "005930")
assert out["suggested_amount"] == 0 and "잔고" in out["sizing_note"]