feat: AI agent, signal engine, surge detector, portfolio simulator
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
65
agents/ai_analyst.py
Normal file
65
agents/ai_analyst.py
Normal file
@@ -0,0 +1,65 @@
|
||||
import json
|
||||
import logging
|
||||
from anthropic import Anthropic
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class AIAgent:
|
||||
def __init__(self, api_key: str):
|
||||
self.client = Anthropic(api_key=api_key) if api_key else None
|
||||
|
||||
def analyze_batch(self, coins_data: list[dict]) -> dict[str, dict]:
|
||||
if not coins_data or not self.client:
|
||||
return {c.get("symbol",""): {"score": 50, "summary": "AI not configured"} for c in coins_data}
|
||||
|
||||
prompt = self._build_prompt(coins_data)
|
||||
try:
|
||||
response = self.client.messages.create(
|
||||
model="claude-sonnet-4-20250514",
|
||||
max_tokens=2000,
|
||||
messages=[{"role": "user", "content": prompt}],
|
||||
)
|
||||
return self._parse_response(response.content[0].text, coins_data)
|
||||
except Exception as e:
|
||||
logger.error(f"AI analysis failed: {e}")
|
||||
return {c["symbol"]: {"score": 50, "summary": "Analysis unavailable"} for c in coins_data}
|
||||
|
||||
def _build_prompt(self, coins_data: list[dict]) -> str:
|
||||
coins_text = ""
|
||||
for coin in coins_data:
|
||||
coins_text += f"""
|
||||
Coin: {coin['symbol']}
|
||||
- Price: ${coin.get('price', 'N/A')}
|
||||
- 24h Change: {coin.get('change_pct', 'N/A')}%
|
||||
- Technical Score: {coin.get('technical_score', 'N/A')}/100
|
||||
- News Sentiment: {coin.get('news_score', 'N/A')}/100
|
||||
- Social Sentiment: {coin.get('social_score', 'N/A')}/100
|
||||
- Recent Headlines: {', '.join(coin.get('headlines', [])[:3])}
|
||||
"""
|
||||
return f"""You are a crypto market analyst. Analyze these coins for short-term (24h) spot trading potential.
|
||||
|
||||
For each coin, provide:
|
||||
1. A score from 0-100 (0=strong sell, 50=neutral, 100=strong buy)
|
||||
2. A brief 1-2 sentence summary explaining your reasoning
|
||||
|
||||
{coins_text}
|
||||
|
||||
Respond in JSON format:
|
||||
{{
|
||||
"SYMBOL": {{"score": NUMBER, "summary": "TEXT"}},
|
||||
...
|
||||
}}
|
||||
|
||||
Only output the JSON, no other text."""
|
||||
|
||||
def _parse_response(self, text: str, coins_data: list[dict]) -> dict[str, dict]:
|
||||
try:
|
||||
text = text.strip()
|
||||
if text.startswith("```"):
|
||||
text = text.split("```")[1]
|
||||
if text.startswith("json"):
|
||||
text = text[4:]
|
||||
return json.loads(text)
|
||||
except (json.JSONDecodeError, IndexError) as e:
|
||||
logger.warning(f"Failed to parse AI response: {e}")
|
||||
return {c["symbol"]: {"score": 50, "summary": "Parse error"} for c in coins_data}
|
||||
Reference in New Issue
Block a user