288 lines
9.0 KiB
Python
288 lines
9.0 KiB
Python
from anthropic import Anthropic
|
|
from config import settings
|
|
from typing import Dict, Any, List
|
|
import json
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ClaudeClient:
|
|
"""Claude AI 클라이언트"""
|
|
|
|
def __init__(self):
|
|
self.client = Anthropic(api_key=settings.ANTHROPIC_API_KEY)
|
|
self.model = settings.CLAUDE_MODEL
|
|
|
|
async def analyze(
|
|
self,
|
|
system_prompt: str,
|
|
user_message: str,
|
|
tools: List[Dict[str, Any]] = None
|
|
) -> Dict[str, Any]:
|
|
"""Claude를 통한 분석 실행"""
|
|
try:
|
|
messages = [
|
|
{"role": "user", "content": user_message}
|
|
]
|
|
|
|
params = {
|
|
"model": self.model,
|
|
"max_tokens": settings.MAX_TOKENS,
|
|
"temperature": settings.TEMPERATURE,
|
|
"system": system_prompt,
|
|
"messages": messages
|
|
}
|
|
|
|
if tools:
|
|
params["tools"] = tools
|
|
|
|
response = self.client.messages.create(**params)
|
|
|
|
# 응답 파싱
|
|
result = {
|
|
"content": [],
|
|
"stop_reason": response.stop_reason,
|
|
"usage": {
|
|
"input_tokens": response.usage.input_tokens,
|
|
"output_tokens": response.usage.output_tokens
|
|
}
|
|
}
|
|
|
|
for block in response.content:
|
|
if block.type == "text":
|
|
result["content"].append({
|
|
"type": "text",
|
|
"text": block.text
|
|
})
|
|
elif block.type == "tool_use":
|
|
result["content"].append({
|
|
"type": "tool_use",
|
|
"id": block.id,
|
|
"name": block.name,
|
|
"input": block.input
|
|
})
|
|
|
|
return result
|
|
|
|
except Exception as e:
|
|
logger.error(f"Claude analysis error: {e}")
|
|
raise
|
|
|
|
async def validate_trading_rule(
|
|
self,
|
|
rule: Dict[str, Any],
|
|
market_data: Dict[str, Any]
|
|
) -> Dict[str, Any]:
|
|
"""트레이딩 규칙 검증"""
|
|
system_prompt = """당신은 주식 트레이딩 규칙을 분석하고 검증하는 전문가입니다.
|
|
주어진 규칙과 시장 데이터를 분석하여 다음을 제공하세요:
|
|
1. 규칙이 현재 시장 상황에 적합한지 여부
|
|
2. 실행 가능성 (0-1 사이의 점수)
|
|
3. 리스크 평가
|
|
4. 추천 사항
|
|
|
|
JSON 형식으로 응답하세요."""
|
|
|
|
user_message = f"""
|
|
트레이딩 규칙:
|
|
{json.dumps(rule, ensure_ascii=False, indent=2)}
|
|
|
|
시장 데이터:
|
|
{json.dumps(market_data, ensure_ascii=False, indent=2)}
|
|
|
|
이 규칙이 현재 시장 상황에서 실행되어야 하는지 분석해주세요.
|
|
"""
|
|
|
|
response = await self.analyze(system_prompt, user_message)
|
|
|
|
# 텍스트 응답 파싱
|
|
for content in response["content"]:
|
|
if content["type"] == "text":
|
|
try:
|
|
# JSON 응답 파싱 시도
|
|
return json.loads(content["text"])
|
|
except json.JSONDecodeError:
|
|
# JSON이 아닌 경우 기본 구조로 반환
|
|
return {
|
|
"decision": "HOLD",
|
|
"confidence": 0.5,
|
|
"analysis": content["text"]
|
|
}
|
|
|
|
return {
|
|
"decision": "HOLD",
|
|
"confidence": 0.0,
|
|
"analysis": "분석 실패"
|
|
}
|
|
|
|
async def analyze_market(
|
|
self,
|
|
stock_code: str,
|
|
market_data: Dict[str, Any],
|
|
news: List[Dict[str, Any]] = None
|
|
) -> Dict[str, Any]:
|
|
"""시장 분석"""
|
|
system_prompt = """당신은 주식 시장 분석 전문가입니다.
|
|
주어진 시장 데이터와 뉴스를 분석하여 다음을 제공하세요:
|
|
1. 시장 트렌드 (상승/하락/횡보)
|
|
2. 주요 기술적 지표 분석
|
|
3. 뉴스 센티먼트 (긍정/부정/중립)
|
|
4. 투자 추천 (매수/매도/보유)
|
|
5. 신뢰도 (0-1)
|
|
|
|
JSON 형식으로 응답하세요."""
|
|
|
|
news_text = ""
|
|
if news:
|
|
news_text = "\n\n최근 뉴스:\n" + "\n".join([
|
|
f"- {item.get('title', '')}: {item.get('content', '')[:200]}"
|
|
for item in news[:5]
|
|
])
|
|
|
|
user_message = f"""
|
|
종목 코드: {stock_code}
|
|
|
|
시장 데이터:
|
|
{json.dumps(market_data, ensure_ascii=False, indent=2)}
|
|
{news_text}
|
|
|
|
이 종목에 대한 종합적인 시장 분석을 제공해주세요.
|
|
"""
|
|
|
|
response = await self.analyze(system_prompt, user_message)
|
|
|
|
for content in response["content"]:
|
|
if content["type"] == "text":
|
|
try:
|
|
return json.loads(content["text"])
|
|
except json.JSONDecodeError:
|
|
return {
|
|
"trend": "SIDEWAYS",
|
|
"sentiment": "NEUTRAL",
|
|
"recommendation": "HOLD",
|
|
"confidence": 0.5,
|
|
"analysis": content["text"]
|
|
}
|
|
|
|
return {
|
|
"trend": "UNKNOWN",
|
|
"sentiment": "NEUTRAL",
|
|
"recommendation": "HOLD",
|
|
"confidence": 0.0
|
|
}
|
|
|
|
async def calculate_fair_price(
|
|
self,
|
|
stock_code: str,
|
|
market_data: Dict[str, Any],
|
|
financial_data: Dict[str, Any] = None
|
|
) -> Dict[str, Any]:
|
|
"""AI 기반 적정 매수/매도 가격 산출"""
|
|
system_prompt = """당신은 주식 가치 평가 및 가격 전략 전문가입니다.
|
|
기술적 분석과 시장 데이터를 기반으로 다음을 제공하세요:
|
|
1. 적정 매수 가격 (공격적, 중립적, 보수적)
|
|
2. 적정 매도 가격 (목표가 1, 2, 3)
|
|
3. 손절가
|
|
4. 근거 및 전략
|
|
5. 신뢰도 (0-1)
|
|
|
|
JSON 형식으로 응답하세요. 예시:
|
|
{
|
|
"buy_prices": {
|
|
"aggressive": 100000,
|
|
"neutral": 105000,
|
|
"conservative": 110000
|
|
},
|
|
"sell_prices": {
|
|
"target1": 120000,
|
|
"target2": 130000,
|
|
"target3": 140000
|
|
},
|
|
"stop_loss": 95000,
|
|
"strategy": "기술적 분석 기반 설명...",
|
|
"confidence": 0.75
|
|
}"""
|
|
|
|
user_message = f"""
|
|
종목 코드: {stock_code}
|
|
|
|
시장 데이터:
|
|
- 현재가: {market_data.get('current_price')}
|
|
- 고가: {market_data.get('high_price')}
|
|
- 저가: {market_data.get('low_price')}
|
|
- 거래량: {market_data.get('volume')}
|
|
- 기술적 지표: {json.dumps(market_data.get('indicators', {}), ensure_ascii=False)}
|
|
|
|
이 종목의 적정 매수/매도 가격과 전략을 제시해주세요.
|
|
"""
|
|
|
|
response = await self.analyze(system_prompt, user_message)
|
|
|
|
for content in response["content"]:
|
|
if content["type"] == "text":
|
|
try:
|
|
return json.loads(content["text"])
|
|
except json.JSONDecodeError:
|
|
return {
|
|
"buy_prices": {"neutral": market_data.get('current_price', 0)},
|
|
"sell_prices": {"target1": market_data.get('current_price', 0) * 1.05},
|
|
"stop_loss": market_data.get('current_price', 0) * 0.97,
|
|
"strategy": content["text"],
|
|
"confidence": 0.5
|
|
}
|
|
|
|
return {
|
|
"error": "분석 실패",
|
|
"confidence": 0.0
|
|
}
|
|
|
|
async def assess_risk(
|
|
self,
|
|
portfolio: Dict[str, Any],
|
|
trade_plan: Dict[str, Any]
|
|
) -> Dict[str, Any]:
|
|
"""리스크 평가"""
|
|
system_prompt = """당신은 투자 리스크 관리 전문가입니다.
|
|
현재 포트폴리오와 계획된 거래를 분석하여 다음을 제공하세요:
|
|
1. 리스크 레벨 (LOW/MEDIUM/HIGH/CRITICAL)
|
|
2. 주요 리스크 요인
|
|
3. 포트폴리오 다양성 평가
|
|
4. 추천 사항
|
|
5. 승인 여부 (APPROVED/REJECTED)
|
|
|
|
JSON 형식으로 응답하세요."""
|
|
|
|
user_message = f"""
|
|
현재 포트폴리오:
|
|
{json.dumps(portfolio, ensure_ascii=False, indent=2)}
|
|
|
|
계획된 거래:
|
|
{json.dumps(trade_plan, ensure_ascii=False, indent=2)}
|
|
|
|
이 거래의 리스크를 평가하고 실행 여부를 결정해주세요.
|
|
"""
|
|
|
|
response = await self.analyze(system_prompt, user_message)
|
|
|
|
for content in response["content"]:
|
|
if content["type"] == "text":
|
|
try:
|
|
return json.loads(content["text"])
|
|
except json.JSONDecodeError:
|
|
return {
|
|
"risk_level": "MEDIUM",
|
|
"approval": "HOLD",
|
|
"confidence": 0.5,
|
|
"analysis": content["text"]
|
|
}
|
|
|
|
return {
|
|
"risk_level": "UNKNOWN",
|
|
"approval": "REJECTED",
|
|
"confidence": 0.0
|
|
}
|
|
|
|
|
|
claude_client = ClaudeClient()
|