수정본
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
from anthropic import Anthropic
|
||||
from anthropic import AsyncAnthropic
|
||||
from config import settings
|
||||
from utils import _dumps
|
||||
from typing import Dict, Any, List
|
||||
import json
|
||||
import logging
|
||||
@@ -9,9 +10,9 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class ClaudeClient:
|
||||
"""Claude AI 클라이언트"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.client = Anthropic(api_key=settings.ANTHROPIC_API_KEY)
|
||||
self.client = AsyncAnthropic(api_key=settings.ANTHROPIC_API_KEY)
|
||||
self.model = settings.CLAUDE_MODEL
|
||||
|
||||
async def analyze(
|
||||
@@ -37,7 +38,7 @@ class ClaudeClient:
|
||||
if tools:
|
||||
params["tools"] = tools
|
||||
|
||||
response = self.client.messages.create(**params)
|
||||
response = await self.client.messages.create(**params)
|
||||
|
||||
# 응답 파싱
|
||||
result = {
|
||||
@@ -72,27 +73,18 @@ class ClaudeClient:
|
||||
async def validate_trading_rule(
|
||||
self,
|
||||
rule: Dict[str, Any],
|
||||
market_data: Dict[str, Any]
|
||||
market_data: Dict[str, Any],
|
||||
news_data: List[Dict[str, Any]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""트레이딩 규칙 검증"""
|
||||
system_prompt = """당신은 주식 트레이딩 규칙을 분석하고 검증하는 전문가입니다.
|
||||
주어진 규칙과 시장 데이터를 분석하여 다음을 제공하세요:
|
||||
1. 규칙이 현재 시장 상황에 적합한지 여부
|
||||
2. 실행 가능성 (0-1 사이의 점수)
|
||||
3. 리스크 평가
|
||||
4. 추천 사항
|
||||
system_prompt = """주식 트레이딩 규칙 검증 전문가. 규칙/시장/뉴스를 분석하여 JSON으로 응답.
|
||||
필수 필드: decision(BUY/SELL/HOLD), confidence(0-1), risk_level, recommendation.
|
||||
악재(유상증자,감자,소송,실적악화) 시 confidence 낮추고 경고 포함."""
|
||||
|
||||
JSON 형식으로 응답하세요."""
|
||||
|
||||
user_message = f"""
|
||||
트레이딩 규칙:
|
||||
{json.dumps(rule, ensure_ascii=False, indent=2)}
|
||||
user_message = f"규칙:{_dumps(rule)}\n시장:{_dumps(market_data)}"
|
||||
|
||||
시장 데이터:
|
||||
{json.dumps(market_data, ensure_ascii=False, indent=2)}
|
||||
|
||||
이 규칙이 현재 시장 상황에서 실행되어야 하는지 분석해주세요.
|
||||
"""
|
||||
if news_data:
|
||||
user_message += f"\n뉴스:{_dumps(news_data)}"
|
||||
|
||||
response = await self.analyze(system_prompt, user_message)
|
||||
|
||||
@@ -123,32 +115,17 @@ JSON 형식으로 응답하세요."""
|
||||
news: List[Dict[str, Any]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""시장 분석"""
|
||||
system_prompt = """당신은 주식 시장 분석 전문가입니다.
|
||||
주어진 시장 데이터와 뉴스를 분석하여 다음을 제공하세요:
|
||||
1. 시장 트렌드 (상승/하락/횡보)
|
||||
2. 주요 기술적 지표 분석
|
||||
3. 뉴스 센티먼트 (긍정/부정/중립)
|
||||
4. 투자 추천 (매수/매도/보유)
|
||||
5. 신뢰도 (0-1)
|
||||
system_prompt = """주식 시장 분석 전문가. JSON으로 응답.
|
||||
필수 필드: trend(UP/DOWN/SIDEWAYS), sentiment(POSITIVE/NEGATIVE/NEUTRAL), recommendation(BUY/SELL/HOLD), confidence(0-1), analysis(간략설명)."""
|
||||
|
||||
JSON 형식으로 응답하세요."""
|
||||
|
||||
news_limit = settings.NEWS_LIMIT if settings.TOKEN_SAVE_MODE else 5
|
||||
news_text = ""
|
||||
if news:
|
||||
news_text = "\n\n최근 뉴스:\n" + "\n".join([
|
||||
f"- {item.get('title', '')}: {item.get('content', '')[:200]}"
|
||||
for item in news[:5]
|
||||
news_text = "\n뉴스:" + ",".join([
|
||||
item.get('title', '') for item in news[:news_limit]
|
||||
])
|
||||
|
||||
user_message = f"""
|
||||
종목 코드: {stock_code}
|
||||
|
||||
시장 데이터:
|
||||
{json.dumps(market_data, ensure_ascii=False, indent=2)}
|
||||
{news_text}
|
||||
|
||||
이 종목에 대한 종합적인 시장 분석을 제공해주세요.
|
||||
"""
|
||||
user_message = f"종목:{stock_code}\n시장:{_dumps(market_data)}{news_text}"
|
||||
|
||||
response = await self.analyze(system_prompt, user_message)
|
||||
|
||||
@@ -179,43 +156,10 @@ JSON 형식으로 응답하세요."""
|
||||
financial_data: Dict[str, Any] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""AI 기반 적정 매수/매도 가격 산출"""
|
||||
system_prompt = """당신은 주식 가치 평가 및 가격 전략 전문가입니다.
|
||||
기술적 분석과 시장 데이터를 기반으로 다음을 제공하세요:
|
||||
1. 적정 매수 가격 (공격적, 중립적, 보수적)
|
||||
2. 적정 매도 가격 (목표가 1, 2, 3)
|
||||
3. 손절가
|
||||
4. 근거 및 전략
|
||||
5. 신뢰도 (0-1)
|
||||
system_prompt = """주식 가격 전략 전문가. JSON으로 응답.
|
||||
필수 필드: buy_prices(aggressive,neutral,conservative), sell_prices(target1,target2,target3), stop_loss, strategy, confidence(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)}
|
||||
|
||||
이 종목의 적정 매수/매도 가격과 전략을 제시해주세요.
|
||||
"""
|
||||
user_message = f"종목:{stock_code} 현재가:{market_data.get('current_price')} 고가:{market_data.get('high_price')} 저가:{market_data.get('low_price')} 거래량:{market_data.get('volume')} 지표:{_dumps(market_data.get('indicators', {}))}"
|
||||
|
||||
response = await self.analyze(system_prompt, user_message)
|
||||
|
||||
@@ -243,25 +187,10 @@ JSON 형식으로 응답하세요. 예시:
|
||||
trade_plan: Dict[str, Any]
|
||||
) -> Dict[str, Any]:
|
||||
"""리스크 평가"""
|
||||
system_prompt = """당신은 투자 리스크 관리 전문가입니다.
|
||||
현재 포트폴리오와 계획된 거래를 분석하여 다음을 제공하세요:
|
||||
1. 리스크 레벨 (LOW/MEDIUM/HIGH/CRITICAL)
|
||||
2. 주요 리스크 요인
|
||||
3. 포트폴리오 다양성 평가
|
||||
4. 추천 사항
|
||||
5. 승인 여부 (APPROVED/REJECTED)
|
||||
system_prompt = """투자 리스크 관리 전문가. JSON으로 응답.
|
||||
필수 필드: risk_level(LOW/MEDIUM/HIGH/CRITICAL), risk_factors, approval(APPROVED/REJECTED), recommendation."""
|
||||
|
||||
JSON 형식으로 응답하세요."""
|
||||
|
||||
user_message = f"""
|
||||
현재 포트폴리오:
|
||||
{json.dumps(portfolio, ensure_ascii=False, indent=2)}
|
||||
|
||||
계획된 거래:
|
||||
{json.dumps(trade_plan, ensure_ascii=False, indent=2)}
|
||||
|
||||
이 거래의 리스크를 평가하고 실행 여부를 결정해주세요.
|
||||
"""
|
||||
user_message = f"포트폴리오:{_dumps(portfolio)}\n거래계획:{_dumps(trade_plan)}"
|
||||
|
||||
response = await self.analyze(system_prompt, user_message)
|
||||
|
||||
@@ -277,11 +206,66 @@ JSON 형식으로 응답하세요."""
|
||||
"analysis": content["text"]
|
||||
}
|
||||
|
||||
return {
|
||||
"risk_level": "UNKNOWN",
|
||||
"approval": "REJECTED",
|
||||
"confidence": 0.0
|
||||
}
|
||||
return {"error": "Failed to assess risk"}
|
||||
|
||||
async def optimize_trading_rules(
|
||||
self,
|
||||
stock_code: str,
|
||||
market_data: Dict[str, Any],
|
||||
news_data: List[Dict[str, Any]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""시장 상황에 맞는 트레이딩 규칙 최적화"""
|
||||
system_prompt = """알고리즘 트레이딩 전략가. JSON으로만 응답.
|
||||
필수 필드: strategy_name, market_condition, parameters(buy_conditions,sell_conditions(take_profit_rate,stop_loss_rate,trailing_stop)), risk_assessment, confidence_score(0-100).
|
||||
악재시 보수적, 호재시 적극적 설정."""
|
||||
|
||||
user_message = f"종목:{stock_code}\n시장:{_dumps(market_data)}"
|
||||
|
||||
if news_data:
|
||||
user_message += f"\n뉴스:{_dumps(news_data)}"
|
||||
|
||||
response = await self.analyze(system_prompt, user_message)
|
||||
|
||||
# 텍스트 응답 파싱
|
||||
for content in response["content"]:
|
||||
if content["type"] == "text":
|
||||
try:
|
||||
text = content["text"]
|
||||
json_start = text.find('{')
|
||||
json_end = text.rfind('}') + 1
|
||||
if json_start != -1 and json_end != -1:
|
||||
return json.loads(text[json_start:json_end])
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to parse optimization result: {e}")
|
||||
|
||||
return {"error": "Failed to generate optimized rules"}
|
||||
|
||||
async def generate_trade_journal(
|
||||
self,
|
||||
trade_info: Dict[str, Any],
|
||||
market_data: Dict[str, Any]
|
||||
) -> Dict[str, Any]:
|
||||
"""매매일지 자동 작성"""
|
||||
system_prompt = """매매일지 작성 전문가. JSON으로 응답.
|
||||
필수 필드: title, content(간략 Markdown), mood(평정심/흥분/공포/아쉬움/만족), tags(배열), score(0-100).
|
||||
매매근거, 잘한점/아쉬운점, 개선사항 포함."""
|
||||
|
||||
user_message = f"거래:{_dumps(trade_info)}\n시장:{_dumps(market_data)}"
|
||||
|
||||
response = await self.analyze(system_prompt, user_message)
|
||||
|
||||
for content in response["content"]:
|
||||
if content["type"] == "text":
|
||||
try:
|
||||
text = content["text"]
|
||||
json_start = text.find('{')
|
||||
json_end = text.rfind('}') + 1
|
||||
if json_start != -1 and json_end != -1:
|
||||
return json.loads(text[json_start:json_end])
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to parse journal result: {e}")
|
||||
|
||||
return {"error": "Failed to generate journal"}
|
||||
|
||||
|
||||
claude_client = ClaudeClient()
|
||||
|
||||
Reference in New Issue
Block a user