feat: LLM 판단 상세 로깅 + 텔레그램 메시지에 LLM 응답 포함

- get_entry_price/get_exit_price가 전체 dict 반환 (action, price, confidence, reason, market_status, watch_needed)
- 매수: 시그널→LLM 승인/스킵 사유, 확신도, 시장 상태 텔레그램 전송
- 매도: LLM 지정가 설정 시 진입 대비 수익률, 확신도, 관망 여부 텔레그램 전송
- 청산: LLM/cascade 구분 태그 (텔레그램 + 로그)
- cascade fallback 전환 시 로그 명시

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
joungmin
2026-03-05 21:57:19 +09:00
parent 19a35e1009
commit 4f9e2c44c7
2 changed files with 69 additions and 28 deletions

View File

@@ -567,20 +567,21 @@ F&G지수: {fng} ({'공포' if fng <= 40 else '중립' if fng <= 50 else '탐욕
data = _call_llm(prompt, ticker)
if data is None:
log.info(f'[LLM매수] {ticker} → LLM 오류/무응답')
return None
reason = data.get('reason', '')
status = data.get('market_status', '')
reason = data.get('reason', '')
status = data.get('market_status', '')
confidence = data.get('confidence', '?')
if data.get('action') == 'skip':
log.info(f'[LLM매수] {ticker} → skip | {status} | {reason}')
return None
log.info(f'[LLM매수] {ticker} → skip | {confidence} | {status} | {reason}')
return data # action=skip
if data.get('action') == 'buy':
price = float(data['price'])
confidence = data.get('confidence', '?')
log.info(f'[LLM매수] {ticker} → buy {price:,.0f}원 | {confidence} | {status} | {reason}')
return price
data['price'] = float(data['price'])
log.info(f'[LLM매수] {ticker} → buy {data["price"]:,.0f}원 | {confidence} | {status} | {reason}')
return data # action=buy, price=float
log.warning(f'[LLM매수] {ticker} 알 수 없는 action: {data}')
return None
@@ -620,16 +621,22 @@ def get_exit_price(
data = _call_llm(prompt, ticker)
if data is None:
log.info(f'[LLM매도] {ticker} → LLM 오류/무응답 → cascade fallback')
return None
reason = data.get('reason', '')
status = data.get('market_status', '')
reason = data.get('reason', '')
status = data.get('market_status', '')
confidence = data.get('confidence', '?')
watch = data.get('watch_needed', False)
if data.get('action') == 'hold':
log.info(f'[LLM매도] {ticker} → hold | {status} | {reason}')
return None
log.info(f'[LLM매도] {ticker} → hold | {confidence} | {status} | watch={watch} | {reason}')
return data # action=hold
suggested = float(data['price'])
confidence = data.get('confidence', '?')
log.info(f'[LLM매도] {ticker} 지정가 교체: {current_target:,.0f}{suggested:,.0f}원 | {confidence} | {status} | {reason}')
return suggested
data['price'] = float(data['price'])
pnl_from_entry = (data['price'] - entry_price) / entry_price * 100
log.info(
f'[LLM매도] {ticker} 지정가 교체: {current_target:,.0f}{data["price"]:,.0f}'
f'(진입 대비 {pnl_from_entry:+.2f}%) | {confidence} | {status} | watch={watch} | {reason}'
)
return data # action=sell, price=float