Spaces:
Running
Running
| import os, traceback, asyncio, json, re, ast | |
| from datetime import datetime, timedelta | |
| from functools import wraps | |
| from backoff import on_exception, expo | |
| from openai import OpenAI, RateLimitError, APITimeoutError, APIStatusError | |
| import numpy as np, httpx, pandas as pd | |
| from gnews import GNews | |
| import feedparser | |
| NVIDIA_API_KEY = os.getenv("NVIDIA_API_KEY") | |
| PRIMARY_MODEL = "nvidia/llama-3.1-nemotron-ultra-253b-v1" | |
| NVIDIA_RATE_LIMIT_CALLS = 20 | |
| NVIDIA_RATE_LIMIT_PERIOD = 60 | |
| CRYPTO_RSS_FEEDS = { | |
| "Cointelegraph": "https://cointelegraph.com/rss", | |
| "CoinDesk": "https://www.coindesk.com/arc/outboundfeeds/rss/", | |
| "CryptoSlate": "https://cryptoslate.com/feed/", | |
| "NewsBTC": "https://www.newsbtc.com/feed/", | |
| "Bitcoin.com": "https://news.bitcoin.com/feed/" | |
| } | |
| class NewsFetcher: | |
| def __init__(self): | |
| self.http_client = httpx.AsyncClient( | |
| timeout=10.0, follow_redirects=True, | |
| headers={ | |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', | |
| 'Accept': 'application/json, text/plain, */*', | |
| 'Accept-Language': 'en-US,en;q=0.9', | |
| 'Cache-Control': 'no-cache' | |
| } | |
| ) | |
| self.gnews = GNews(language='en', country='US', period='3h', max_results=8) | |
| async def _fetch_from_gnews(self, symbol: str) -> list: | |
| try: | |
| base_symbol = symbol.split("/")[0] | |
| query = f'"{base_symbol}" cryptocurrency -bitcoin -ethereum -BTC -ETH' | |
| print(f"📰 Fetching specific news from GNews for {base_symbol}...") | |
| news_items = await asyncio.to_thread(self.gnews.get_news, query) | |
| print(f"✅ GNews fetched {len(news_items)} specific items for {base_symbol}.") | |
| return news_items | |
| except Exception as e: | |
| print(f"❌ Failed to fetch specific news from GNews for {symbol}: {e}") | |
| return [] | |
| async def _fetch_from_rss_feed(self, feed_url: str, source_name: str, symbol: str) -> list: | |
| try: | |
| base_symbol = symbol.split('/')[0] | |
| print(f"📰 Fetching specific news from {source_name} RSS for {base_symbol}...") | |
| max_redirects = 2 | |
| current_url = feed_url | |
| for attempt in range(max_redirects): | |
| try: | |
| response = await self.http_client.get(current_url) | |
| response.raise_for_status() | |
| break | |
| except httpx.HTTPStatusError as e: | |
| if e.response.status_code in [301, 302, 307, 308] and 'Location' in e.response.headers: | |
| current_url = e.response.headers['Location'] | |
| print(f"🔄 Following redirect to: {current_url}") | |
| continue | |
| else: | |
| raise | |
| feed = feedparser.parse(response.text) | |
| news_items = [] | |
| search_term = base_symbol.lower() | |
| for entry in feed.entries[:15]: | |
| title = entry.title.lower() if hasattr(entry, 'title') else '' | |
| summary = entry.summary.lower() if hasattr(entry, 'summary') else entry.description.lower() if hasattr(entry, 'description') else '' | |
| if search_term in title or search_term in summary: | |
| news_items.append({ | |
| 'title': entry.title, | |
| 'description': summary, | |
| 'source': source_name, | |
| 'published': entry.get('published', '') | |
| }) | |
| print(f"✅ {source_name} RSS fetched {len(news_items)} specific items for {base_symbol}.") | |
| return news_items | |
| except Exception as e: | |
| print(f"❌ Failed to fetch specific news from {source_name} RSS for {symbol}: {e}") | |
| return [] | |
| async def get_news_for_symbol(self, symbol: str) -> str: | |
| base_symbol = symbol.split("/")[0] | |
| tasks = [self._fetch_from_gnews(symbol)] | |
| for name, url in CRYPTO_RSS_FEEDS.items(): | |
| tasks.append(self._fetch_from_rss_feed(url, name, symbol)) | |
| results = await asyncio.gather(*tasks, return_exceptions=True) | |
| all_news_text = [] | |
| for result in results: | |
| if isinstance(result, Exception): | |
| print(f"⚠️ A news source failed with error: {result}") | |
| continue | |
| for item in result: | |
| if self._is_directly_relevant_to_symbol(item, base_symbol): | |
| title = item.get('title', 'No Title') | |
| description = item.get('description', 'No Description') | |
| source = item.get('source', 'Unknown Source') | |
| published = item.get('published', '') | |
| news_entry = f"[{source}] {title}. {description}" | |
| if published: | |
| news_entry += f" (Published: {published})" | |
| all_news_text.append(news_entry) | |
| if not all_news_text: | |
| return f"📰 No specific news found for {base_symbol} in the last 3 hours." | |
| important_news = all_news_text[:5] | |
| return " | ".join(important_news) | |
| def _is_directly_relevant_to_symbol(self, news_item, base_symbol): | |
| title = news_item.get('title', '').lower() | |
| description = news_item.get('description', '').lower() | |
| symbol_lower = base_symbol.lower() | |
| if symbol_lower not in title and symbol_lower not in description: | |
| return False | |
| crypto_keywords = [ | |
| 'crypto', 'cryptocurrency', 'token', 'blockchain', | |
| 'price', 'market', 'trading', 'exchange', 'defi', | |
| 'coin', 'digital currency', 'altcoin' | |
| ] | |
| return any(keyword in title or keyword in description for keyword in crypto_keywords) | |
| class PatternAnalysisEngine: | |
| def __init__(self, llm_service): | |
| self.llm = llm_service | |
| self.pattern_templates = { | |
| 'reversal': ['head_shoulders', 'double_top', 'triple_top', 'rising_wedge', 'falling_wedge'], | |
| 'continuation': ['flags', 'pennants', 'triangles', 'rectangles', 'cup_and_handle'], | |
| 'consolidation': ['symmetrical_triangle', 'ascending_triangle', 'descending_triangle'] | |
| } | |
| def _format_chart_data_for_llm(self, ohlcv_data): | |
| """تنسيق بيانات الشموع بشكل محسن للنموذج""" | |
| if not ohlcv_data or len(ohlcv_data) < 20: | |
| return "❌ Insufficient chart data for pattern analysis (minimum 20 candles required)" | |
| try: | |
| # استخدام آخر 50 شمعة للتحليل الدقيق | |
| candles_to_analyze = ohlcv_data[-50:] if len(ohlcv_data) > 50 else ohlcv_data | |
| chart_description = [ | |
| "📊 **CANDLE DATA FOR PATTERN ANALYSIS:**", | |
| f"Total candles available: {len(ohlcv_data)}", | |
| f"Candles used for analysis: {len(candles_to_analyze)}", | |
| "" | |
| ] | |
| # إضافة معلومات عن الشموع الرئيسية | |
| if len(candles_to_analyze) >= 10: | |
| recent_candles = candles_to_analyze[-10:] | |
| chart_description.append("**Recent 10 Candles (Latest First):**") | |
| for i, candle in enumerate(reversed(recent_candles)): | |
| candle_idx = len(candles_to_analyze) - i | |
| desc = f"Candle {candle_idx}: O:{candle[1]:.6f} H:{candle[2]:.6f} L:{candle[3]:.6f} C:{candle[4]:.6f} V:{candle[5]:.0f}" | |
| chart_description.append(f" {desc}") | |
| # تحليل الاتجاه العام | |
| if len(candles_to_analyze) >= 2: | |
| first_close = candles_to_analyze[0][4] | |
| last_close = candles_to_analyze[-1][4] | |
| price_change = ((last_close - first_close) / first_close) * 100 | |
| trend = "📈 BULLISH" if price_change > 2 else "📉 BEARISH" if price_change < -2 else "➡️ SIDEWAYS" | |
| # حساب أعلى وأقل سعر | |
| highs = [c[2] for c in candles_to_analyze] | |
| lows = [c[3] for c in candles_to_analyze] | |
| high_max = max(highs) | |
| low_min = min(lows) | |
| volatility = ((high_max - low_min) / low_min) * 100 | |
| chart_description.extend([ | |
| "", | |
| "**MARKET STRUCTURE ANALYSIS:**", | |
| f"Trend Direction: {trend}", | |
| f"Price Change: {price_change:+.2f}%", | |
| f"Volatility Range: {volatility:.2f}%", | |
| f"Highest Price: {high_max:.6f}", | |
| f"Lowest Price: {low_min:.6f}" | |
| ]) | |
| # تحليل حجم التداول | |
| if len(candles_to_analyze) >= 5: | |
| volumes = [c[5] for c in candles_to_analyze] | |
| avg_volume = sum(volumes) / len(volumes) | |
| current_volume = candles_to_analyze[-1][5] | |
| volume_ratio = current_volume / avg_volume if avg_volume > 0 else 1 | |
| volume_signal = "🚀 HIGH" if volume_ratio > 2 else "📊 NORMAL" if volume_ratio > 0.5 else "📉 LOW" | |
| chart_description.extend([ | |
| "", | |
| "**VOLUME ANALYSIS:**", | |
| f"Current Volume: {current_volume:,.0f}", | |
| f"Volume Ratio: {volume_ratio:.2f}x average", | |
| f"Volume Signal: {volume_signal}" | |
| ]) | |
| return "\n".join(chart_description) | |
| except Exception as e: | |
| return f"❌ Error formatting chart data: {str(e)}" | |
| async def analyze_chart_patterns(self, symbol, ohlcv_data): | |
| """تحليل الأنماط البيانية مع تحسينات كبيرة""" | |
| try: | |
| if not ohlcv_data or len(ohlcv_data) < 20: | |
| return { | |
| "pattern_detected": "insufficient_data", | |
| "pattern_confidence": 0.1, | |
| "pattern_strength": "weak", | |
| "predicted_direction": "unknown", | |
| "pattern_analysis": "Insufficient candle data for pattern analysis" | |
| } | |
| chart_text = self._format_chart_data_for_llm(ohlcv_data) | |
| prompt = f""" | |
| 🔍 **CRYPTO CHART PATTERN ANALYSIS REQUEST** | |
| You are an expert cryptocurrency technical analyst with 10+ years experience. | |
| Analyze the following candle data for {symbol} and identify STRONG, ACTIONABLE patterns. | |
| **ANALYSIS REQUIREMENTS:** | |
| 1. Focus on CLEAR, HIGH-PROBABILITY patterns only | |
| 2. Consider volume confirmation for all patterns | |
| 3. Evaluate pattern strength based on candle formations | |
| 4. Provide SPECIFIC price targets and stop levels | |
| 5. Assess timeframe suitability for 5-45 minute trades | |
| **CANDLE DATA FOR ANALYSIS:** | |
| {chart_text} | |
| **PATTERNS TO LOOK FOR:** | |
| 🎯 REVERSAL PATTERNS: Head & Shoulders, Double Top/Bottom, Triple Top/Bottom | |
| 🎯 CONTINUATION PATTERNS: Flags, Pennants, Triangles, Rectangles | |
| 🎯 CONSOLIDATION PATTERNS: Symmetrical/Descending/Ascending Triangles | |
| 🎯 SUPPORT/RESISTANCE: Key levels from recent highs/lows | |
| **MANDATORY OUTPUT FORMAT (JSON):** | |
| {{ | |
| "pattern_detected": "pattern_name", | |
| "pattern_confidence": 0.85, | |
| "pattern_strength": "strong/medium/weak", | |
| "predicted_direction": "up/down/sideways", | |
| "predicted_movement_percent": 5.50, | |
| "timeframe_expectation": "15-25 minutes", | |
| "entry_suggestion": 0.1234, | |
| "target_suggestion": 0.1357, | |
| "stop_suggestion": 0.1189, | |
| "key_support": 0.1200, | |
| "key_resistance": 0.1300, | |
| "pattern_analysis": "Detailed explanation of the pattern, why it's valid, and volume confirmation" | |
| }} | |
| **CRITICAL:** | |
| - Only identify patterns if you have ≥ 70% confidence | |
| - MUST consider volume in pattern confirmation | |
| - Provide SPECIFIC numbers for entry/target/stop | |
| - If no clear pattern, set pattern_detected to "no_clear_pattern" | |
| """ | |
| print(f"🔍 Analyzing chart patterns for {symbol} with {len(ohlcv_data)} candles...") | |
| response = await self.llm._call_llm(prompt) | |
| pattern_result = self._parse_pattern_response(response) | |
| if pattern_result and pattern_result.get('pattern_detected') != 'no_clear_pattern': | |
| print(f"✅ Pattern detected for {symbol}: {pattern_result.get('pattern_detected')} " | |
| f"(Confidence: {pattern_result.get('pattern_confidence', 0):.2f})") | |
| else: | |
| print(f"ℹ️ No clear patterns for {symbol}") | |
| return pattern_result | |
| except Exception as e: | |
| print(f"❌ Chart pattern analysis failed for {symbol}: {e}") | |
| return None | |
| def _parse_pattern_response(self, response_text): | |
| """تحليل رد النموذج مع تحسينات التعامل مع الأخطاء""" | |
| try: | |
| # البحث عن JSON في الرد | |
| json_match = re.search(r'\{.*\}', response_text, re.DOTALL) | |
| if not json_match: | |
| return { | |
| "pattern_detected": "parse_error", | |
| "pattern_confidence": 0.1, | |
| "pattern_analysis": "Could not parse pattern analysis response" | |
| } | |
| pattern_data = json.loads(json_match.group()) | |
| # التحقق من الحقول الأساسية | |
| required = ['pattern_detected', 'pattern_confidence', 'predicted_direction'] | |
| if not all(field in pattern_data for field in required): | |
| return { | |
| "pattern_detected": "incomplete_data", | |
| "pattern_confidence": 0.1, | |
| "pattern_analysis": "Incomplete pattern analysis data" | |
| } | |
| return pattern_data | |
| except Exception as e: | |
| print(f"❌ Error parsing pattern response: {e}") | |
| return { | |
| "pattern_detected": "parse_error", | |
| "pattern_confidence": 0.1, | |
| "pattern_analysis": f"Error parsing pattern analysis: {str(e)}" | |
| } | |
| class LLMService: | |
| def __init__(self, api_key=NVIDIA_API_KEY, model_name=PRIMARY_MODEL, temperature=0.7): | |
| self.api_key = api_key | |
| self.model_name = model_name | |
| self.temperature = temperature | |
| self.client = OpenAI(base_url="https://integrate.api.nvidia.com/v1", api_key=self.api_key) | |
| self.news_fetcher = NewsFetcher() | |
| self.pattern_engine = PatternAnalysisEngine(self) | |
| self.semaphore = asyncio.Semaphore(5) | |
| def _rate_limit_nvidia_api(func): | |
| async def wrapper(*args, **kwargs): | |
| return await func(*args, **kwargs) | |
| return wrapper | |
| async def get_trading_decision(self, data_payload: dict): | |
| try: | |
| symbol = data_payload.get('symbol', 'unknown') | |
| target_strategy = data_payload.get('target_strategy', 'GENERIC') | |
| print(f"🧠 Starting LLM analysis for {symbol} with strategy: {target_strategy}...") | |
| news_text = await self.news_fetcher.get_news_for_symbol(symbol) | |
| pattern_analysis = await self._get_pattern_analysis(data_payload) | |
| prompt = self._create_enhanced_trading_prompt(data_payload, news_text, pattern_analysis) | |
| print(f"🧠 Sending enhanced prompt to LLM for {symbol}...") | |
| async with self.semaphore: | |
| response = await self._call_llm(prompt) | |
| decision_dict = self._parse_llm_response_enhanced(response, target_strategy, symbol) | |
| if decision_dict: | |
| decision_dict['model_source'] = self.model_name | |
| decision_dict['pattern_analysis'] = pattern_analysis | |
| # ✅ التحقق النهائي من الاستراتيجية | |
| final_strategy = decision_dict.get('strategy') | |
| if not final_strategy or final_strategy == 'unknown' or final_strategy is None: | |
| decision_dict['strategy'] = target_strategy | |
| print(f"🔧 Final strategy correction for {symbol}: {target_strategy}") | |
| else: | |
| print(f"✅ LLM successfully selected strategy '{final_strategy}' for {symbol}.") | |
| print(f"✅ LLM analysis completed for {symbol} - Strategy: {decision_dict['strategy']}") | |
| else: | |
| print(f"❌ LLM analysis failed for {symbol}") | |
| return local_analyze_opportunity(data_payload) | |
| return decision_dict | |
| except Exception as e: | |
| print(f"❌ An error occurred while getting LLM decision for {data_payload.get('symbol', 'unknown')}: {e}") | |
| traceback.print_exc() | |
| return local_analyze_opportunity(data_payload) | |
| def _parse_llm_response_enhanced(self, response_text: str, fallback_strategy: str = 'GENERIC', symbol: str = 'unknown') -> dict: | |
| """✅ الإصلاح النهائي: تحليل رد الـ LLM مع إعطاء الثقة لقراره""" | |
| try: | |
| json_match = re.search(r'```json\n(.*?)\n```', response_text, re.DOTALL) | |
| if json_match: | |
| json_str = json_match.group(1).strip() | |
| else: | |
| json_match = re.search(r'\{.*\}', response_text, re.DOTALL) | |
| if json_match: | |
| json_str = json_match.group() | |
| else: | |
| print(f"❌ No JSON found in LLM response for {symbol}: {response_text}") | |
| return None | |
| decision_data = json.loads(json_str) | |
| required_fields = ['action', 'reasoning', 'risk_assessment', 'trade_type', | |
| 'stop_loss', 'take_profit', 'expected_target_minutes', 'confidence_level'] | |
| for field in required_fields: | |
| if field not in decision_data: | |
| print(f"❌ Missing required field '{field}' in LLM response for {symbol}") | |
| return None | |
| strategy_value = decision_data.get('strategy') | |
| # 💡 التحقق: هل الاستراتيجية التي أرجعها النموذج صالحة؟ | |
| if not strategy_value or strategy_value == 'unknown' or strategy_value is None: | |
| # إذا كانت غير صالحة، استخدم الاستراتيجية العامة كخطة بديلة آمنة | |
| print(f"⚠️ LLM returned invalid strategy '{strategy_value}' for {symbol}. Forcing fallback: {fallback_strategy}") | |
| decision_data['strategy'] = fallback_strategy | |
| else: | |
| # إذا كانت صالحة، اعتمدها مباشرةً! | |
| print(f"✅ LLM successfully selected strategy '{strategy_value}' for {symbol}.") | |
| return decision_data | |
| except Exception as e: | |
| print(f"❌ Unexpected error parsing LLM response for {symbol}: {e}") | |
| return None | |
| async def _get_pattern_analysis(self, data_payload): | |
| try: | |
| symbol = data_payload['symbol'] | |
| # ✅ الحصول على بيانات الشموع الخام من البيانات المعالجة | |
| if 'raw_ohlcv' in data_payload and '1h' in data_payload['raw_ohlcv']: | |
| ohlcv_data = data_payload['raw_ohlcv']['1h'] | |
| if ohlcv_data and len(ohlcv_data) >= 20: | |
| print(f"🔍 Using raw OHLCV data for pattern analysis: {len(ohlcv_data)} candles") | |
| return await self.pattern_engine.analyze_chart_patterns(symbol, ohlcv_data) | |
| # ✅ الحصول على بيانات OHLCV من 'advanced_indicators' كبديل | |
| if 'advanced_indicators' in data_payload and '1h' in data_payload['advanced_indicators']: | |
| ohlcv_data = data_payload['advanced_indicators']['1h'] | |
| if ohlcv_data and len(ohlcv_data) >= 20: | |
| print(f"🔍 Using advanced indicators data for pattern analysis: {len(ohlcv_data)} candles") | |
| return await self.pattern_engine.analyze_chart_patterns(symbol, ohlcv_data) | |
| print(f"⚠️ No sufficient OHLCV data for pattern analysis on {symbol}") | |
| return None | |
| except Exception as e: | |
| print(f"⚠️ Pattern analysis failed for {data_payload.get('symbol')}: {e}") | |
| return None | |
| def _create_enhanced_trading_prompt(self, payload: dict, news_text: str, pattern_analysis: dict) -> str: | |
| symbol = payload.get('symbol', 'N/A') | |
| current_price = payload.get('current_price', 'N/A') | |
| reasons = payload.get('reasons_for_candidacy', []) | |
| sentiment_data = payload.get('sentiment_data', {}) | |
| advanced_indicators = payload.get('advanced_indicators', {}) | |
| strategy_scores = payload.get('strategy_scores', {}) | |
| recommended_strategy = payload.get('recommended_strategy', 'N/A') | |
| target_strategy = payload.get('target_strategy', 'GENERIC') | |
| final_score = payload.get('final_score', 'N/A') | |
| enhanced_final_score = payload.get('enhanced_final_score', 'N/A') | |
| whale_data = payload.get('whale_data', {}) | |
| general_whale_activity = sentiment_data.get('general_whale_activity', {}) | |
| final_score_display = f"{final_score:.2f}" if isinstance(final_score, (int, float)) else str(final_score) | |
| enhanced_score_display = f"{enhanced_final_score:.2f}" if isinstance(enhanced_final_score, (int, float)) else str(enhanced_final_score) | |
| indicators_summary = self._format_advanced_indicators(advanced_indicators) | |
| strategies_summary = self._format_strategies_analysis(strategy_scores, recommended_strategy) | |
| pattern_summary = self._format_pattern_analysis_enhanced(pattern_analysis, payload) | |
| # 🆕 استخدام البيانات المحسنة من data_manager | |
| whale_analysis_section = self._format_enhanced_whale_analysis_for_llm(general_whale_activity, whale_data, symbol) | |
| strategy_instructions = { | |
| "AGGRESSIVE_GROWTH": "**Strategy: AGGRESSIVE_GROWTH**: Focus on strong price movements (5-10%) and accept higher risk for higher rewards. Aim for 8-15% on successful trades.", | |
| "DEFENSIVE_GROWTH": "**Strategy: DEFENSIVE_GROWTH**: Look for safer 3-6% moves with tight stop-losses. Aim for 4-8% while protecting capital.", | |
| "CONSERVATIVE": "**Strategy: CONSERVATIVE**: Focus on only 2-4% moves with wider stop-losses. Aim for 2-5% with minimal risk.", | |
| "HIGH_FREQUENCY": "**Strategy: HIGH_FREQUENCY**: Look for quick 1-3% scalps with very tight stop-losses. Aim for 1-4% on multiple trades.", | |
| "WHALE_FOLLOWING": "**Strategy: WHALE_FOLLOWING**: Prioritize whale tracking signals and unusual volume. Aim for 5-12% with medium risk.", | |
| "GENERIC": "**Strategy: GENERIC**: Make balanced decisions considering risk and reward across all factors." | |
| } | |
| strategy_instruction = strategy_instructions.get(target_strategy, strategy_instructions["GENERIC"]) | |
| data_availability_section = self._format_data_availability(sentiment_data, whale_data, news_text, pattern_analysis) | |
| prompt = f""" | |
| 🎯 **ENHANCED TRADING ANALYSIS WITH CHART PATTERNS** | |
| **ACTIVE STRATEGY: {target_strategy}** | |
| {strategy_instruction} | |
| **CRITICAL CHART PATTERN ANALYSIS:** | |
| {pattern_summary} | |
| **STRATEGIC TIMEFRAME:** | |
| - Max trade duration: 45 minutes (will be automatically enforced). | |
| - Optimal range: 8-25 minutes for ideal capital rotation. | |
| - Minimum duration: 5 minutes for active monitoring. | |
| {data_availability_section} | |
| **AVAILABLE DATA FOR {symbol}:** | |
| **1. 🎯 CANDIDACY REASON:** | |
| - This symbol was selected for: {reasons} | |
| **2. 📊 OVERVIEW:** | |
| - Symbol: {symbol} | |
| - Current Price: {current_price} USDT | |
| - Initial System Score: {final_score_display} | |
| - Enhanced System Score: {enhanced_score_display} | |
| - Recommended Internal Strategy: {recommended_strategy} | |
| - **Target Trading Strategy: {target_strategy}** | |
| **3. 🎪 STRATEGY ANALYSIS (INTERNAL SCORES):** | |
| {strategies_summary} | |
| **4. 📈 ADVANCED TECHNICAL INDICATORS:** | |
| {indicators_summary} | |
| **5. 🌍 COMPREHENSIVE MARKET CONTEXT:** | |
| - BTC Trend: {sentiment_data.get('btc_sentiment', 'N/A')} | |
| - Fear & Greed Index: {sentiment_data.get('fear_and_greed_index', 'N/A')} ({sentiment_data.get('sentiment_class', 'N/A')}) | |
| - Market Regime: {sentiment_data.get('market_trend', 'N/A')} | |
| **6. 🐋 ADVANCED WHALE ANALYSIS (ENHANCED NETFLOW):** | |
| {whale_analysis_section} | |
| **7. 📰 RECENT NEWS (LAST 3 HOURS):** | |
| {news_text} | |
| **YOUR MISSION:** | |
| Integrate the chart pattern analysis above with all other available data to make a FINAL trading decision. | |
| **IF PATTERN ANALYSIS SHOWS STRONG SIGNALS:** | |
| - Give it significant weight in your decision | |
| - Use the pattern's entry/target/stop suggestions | |
| - Consider the pattern's confidence level | |
| **IF NO CLEAR PATTERNS:** | |
| - Rely more on technical indicators and market context | |
| - Be more conservative with targets and stops | |
| **REQUIRED OUTPUTS (JSON ONLY):** | |
| - `action`: Must be one of ("BUY", "SELL", "HOLD") | |
| - `reasoning`: Detailed explanation focusing on {target_strategy} AND SPECIFICALLY MENTIONING chart pattern analysis | |
| - `risk_assessment`: Risk analysis aligned with {target_strategy} and available data | |
| - `trade_type`: ("LONG" for BUY, "SHORT" for SELL) | |
| - `stop_loss`: Stop loss price (consider {target_strategy} risk profile AND pattern suggestions) | |
| - `take_profit`: Take profit price (realistic for {target_strategy} AND pattern targets) | |
| - `expected_target_minutes`: Realistic expectation (5-45 minutes) | |
| - `confidence_level`: Your confidence level (0.00-1.00) based on data quality AND pattern confidence | |
| - `strategy`: "{target_strategy}" # ⚠️ MUST BE EXACTLY: {target_strategy} | |
| - `pattern_influence`: "Describe how chart pattern affected decision" | |
| **CRITICAL: You MUST include the 'strategy' field with the exact value: "{target_strategy}"** | |
| **SPECIAL INSTRUCTIONS FOR PATTERN INTEGRATION:** | |
| - If pattern_confidence > 0.7, you MUST reference it prominently in reasoning | |
| - If pattern suggests specific levels, strongly consider using them | |
| - Always explain how patterns influenced your final decision in 'pattern_influence' | |
| **Example output format (JSON only):** | |
| ```json | |
| {{ | |
| "action": "BUY", | |
| "reasoning": "Strong bullish signals aligned with {target_strategy}. High-confidence Double Top pattern detected with 85% confidence suggesting upward movement. Whale activity is positive. Limited news data, but technicals and pattern are strong.", | |
| "risk_assessment": "Moderate risk suitable for {target_strategy}. Pattern provides clear stop and target levels. Note: Some data sources unavailable.", | |
| "trade_type": "LONG", | |
| "stop_loss": 0.0285, | |
| "take_profit": 0.0320, | |
| "expected_target_minutes": 12, | |
| "confidence_level": 0.82, | |
| "strategy": "{target_strategy}", | |
| "pattern_influence": "Double Top pattern provided clear entry and target levels, increasing confidence in the trade setup." | |
| }} | |
| ``` | |
| """ | |
| return prompt | |
| def _format_data_availability(self, sentiment_data, whale_data, news_text, pattern_analysis): | |
| general_whale_available = sentiment_data.get('general_whale_activity', {}).get('data_available', False) | |
| symbol_whale_available = whale_data.get('data_available', False) | |
| news_available = "No specific news found" not in news_text | |
| pattern_available = pattern_analysis is not None and pattern_analysis.get('pattern_detected') != 'no_clear_pattern' | |
| return f""" | |
| **📊 REAL DATA AVAILABILITY STATUS:** | |
| - Market Sentiment: {'✅ Available' if sentiment_data.get('fear_and_greed_index') else '❌ Not Available'} | |
| - General Whale Activity: {'✅ Available' if general_whale_available else '❌ Not Available'} | |
| - Symbol Whale Activity: {'✅ Available' if symbol_whale_available else '❌ Not Available'} | |
| - News Data: {'✅ Available' if news_available else '❌ Not Available'} | |
| - Chart Patterns: {'✅ STRONG PATTERN' if pattern_available and pattern_analysis.get('pattern_confidence', 0) > 0.7 else '✅ WEAK PATTERN' if pattern_available else '❌ Not Available'} | |
| **⚠️ IMPORTANT: Decisions should be based ONLY on available real data.** | |
| **🎯 PATTERN PRIORITY: Give significant weight to chart patterns when available with high confidence.** | |
| """ | |
| def _format_advanced_indicators(self, advanced_indicators): | |
| if not advanced_indicators: | |
| return "❌ No data for advanced indicators." | |
| summary = [] | |
| for timeframe, indicators in advanced_indicators.items(): | |
| if indicators: | |
| parts = [] | |
| if 'rsi' in indicators: parts.append(f"RSI: {indicators['rsi']:.2f}") | |
| if 'macd_hist' in indicators: parts.append(f"MACD Hist: {indicators['macd_hist']:.4f}") | |
| if 'volume_ratio' in indicators: parts.append(f"Volume: {indicators['volume_ratio']:.2f}x") | |
| if parts: | |
| summary.append(f"\n📊 **{timeframe}:** {', '.join(parts)}") | |
| return "\n".join(summary) if summary else "⚠️ Insufficient indicator data." | |
| def _format_strategies_analysis(self, strategy_scores, recommended_strategy): | |
| if not strategy_scores: | |
| return "❌ No strategy data available." | |
| summary = [f"🎯 **Recommended Strategy:** {recommended_strategy}"] | |
| sorted_scores = sorted(strategy_scores.items(), key=lambda item: item[1], reverse=True) | |
| for strategy, score in sorted_scores: | |
| if isinstance(score, (int, float)): | |
| score_display = f"{score:.3f}" | |
| else: | |
| score_display = str(score) | |
| summary.append(f" • {strategy}: {score_display}") | |
| return "\n".join(summary) | |
| def _format_pattern_analysis_enhanced(self, pattern_analysis, payload): | |
| """تنسيق محسن لقسم تحليل النمط""" | |
| if not pattern_analysis: | |
| return """ | |
| ❌ **CHART PATTERN STATUS: NO CLEAR PATTERNS DETECTED** | |
| - Reason: Insufficient data or no recognizable patterns in current chart | |
| - Impact: Decision will rely more on technical indicators and market context | |
| - Recommendation: Proceed with caution, use wider stops | |
| """ | |
| confidence = pattern_analysis.get('pattern_confidence', 0) | |
| pattern_name = pattern_analysis.get('pattern_detected', 'unknown') | |
| strength = pattern_analysis.get('pattern_strength', 'unknown') | |
| if confidence >= 0.7: | |
| status = "✅ **HIGH-CONFIDENCE PATTERN DETECTED**" | |
| influence = "This pattern should SIGNIFICANTLY influence your trading decision" | |
| elif confidence >= 0.5: | |
| status = "⚠️ **MEDIUM-CONFIDENCE PATTERN DETECTED**" | |
| influence = "Consider this pattern but verify with other indicators" | |
| else: | |
| status = "📊 **LOW-CONFIDENCE PATTERN DETECTED**" | |
| influence = "Use this pattern as supplementary information only" | |
| analysis_lines = [ | |
| status, | |
| f"**Pattern:** {pattern_name}", | |
| f"**Confidence:** {confidence:.1%}", | |
| f"**Strength:** {strength}", | |
| f"**Predicted Move:** {pattern_analysis.get('predicted_direction', 'N/A')} " | |
| f"by {pattern_analysis.get('predicted_movement_percent', 0):.2f}%", | |
| f"**Timeframe:** {pattern_analysis.get('timeframe_expectation', 'N/A')}", | |
| f"**Influence:** {influence}", | |
| "", | |
| "**PATTERN-SPECIFIC SUGGESTIONS:**", | |
| f"Entry: {pattern_analysis.get('entry_suggestion', 'N/A')}", | |
| f"Target: {pattern_analysis.get('target_suggestion', 'N/A')}", | |
| f"Stop: {pattern_analysis.get('stop_suggestion', 'N/A')}", | |
| f"Key Support: {pattern_analysis.get('key_support', 'N/A')}", | |
| f"Key Resistance: {pattern_analysis.get('key_resistance', 'N/A')}", | |
| "", | |
| f"**Analysis:** {pattern_analysis.get('pattern_analysis', 'No detailed analysis available')}" | |
| ] | |
| return "\n".join(analysis_lines) | |
| def _format_enhanced_whale_analysis_for_llm(self, general_whale_activity, symbol_whale_data, symbol): | |
| """🆕 تنسيق محسن لتحليل الحيتان مع بيانات صافي التدفق""" | |
| analysis_parts = [] | |
| if general_whale_activity.get('data_available', False): | |
| # استخدام البيانات المحسنة من data_manager | |
| netflow_analysis = general_whale_activity.get('netflow_analysis', {}) | |
| critical_flag = " 🚨 CRITICAL ALERT" if general_whale_activity.get('critical_alert') else "" | |
| if netflow_analysis: | |
| inflow = netflow_analysis.get('inflow_to_exchanges', 0) | |
| outflow = netflow_analysis.get('outflow_from_exchanges', 0) | |
| net_flow = netflow_analysis.get('net_flow', 0) | |
| flow_direction = netflow_analysis.get('flow_direction', 'BALANCED') | |
| market_impact = netflow_analysis.get('market_impact', 'UNKNOWN') | |
| analysis_parts.append(f"📊 **General Market Netflow Analysis:**") | |
| analysis_parts.append(f" • Inflow to Exchanges: ${inflow:,.0f}") | |
| analysis_parts.append(f" • Outflow from Exchanges: ${outflow:,.0f}") | |
| analysis_parts.append(f" • Net Flow: ${net_flow:,.0f} ({flow_direction})") | |
| analysis_parts.append(f" • Market Impact: {market_impact}{critical_flag}") | |
| # إضافة إشارات التداول من تحليل صافي التدفق | |
| trading_signals = general_whale_activity.get('trading_signals', []) | |
| if trading_signals: | |
| analysis_parts.append(f" • Trading Signals: {len(trading_signals)} active signals") | |
| for signal in trading_signals[:3]: # عرض أول 3 إشارات فقط | |
| analysis_parts.append(f" ◦ {signal.get('action')}: {signal.get('reason')} (Confidence: {signal.get('confidence', 0):.2f})") | |
| else: | |
| analysis_parts.append(f"📊 **General Market:** {general_whale_activity.get('description', 'Activity detected')}{critical_flag}") | |
| else: | |
| analysis_parts.append("📊 **General Market:** No significant general whale data available") | |
| if symbol_whale_data.get('data_available', False): | |
| activity_level = symbol_whale_data.get('activity_level', 'UNKNOWN') | |
| large_transfers = symbol_whale_data.get('large_transfers_count', 0) | |
| total_volume = symbol_whale_data.get('total_volume', 0) | |
| analysis_parts.append(f"🎯 **{symbol} Specific Whale Activity:**") | |
| analysis_parts.append(f" • Activity Level: {activity_level}") | |
| analysis_parts.append(f" • Large Transfers: {large_transfers}") | |
| analysis_parts.append(f" • Total Volume: ${total_volume:,.0f}") | |
| recent_transfers = symbol_whale_data.get('recent_large_transfers', []) | |
| if recent_transfers: | |
| analysis_parts.append(f" • Recent Large Transfers: {len(recent_transfers)}") | |
| else: | |
| analysis_parts.append(f"🎯 **{symbol} Specific:** No contract-based whale data available") | |
| return "\n".join(analysis_parts) | |
| def _format_whale_analysis_for_llm(self, general_whale_activity, symbol_whale_data, symbol): | |
| """النسخة القديمة للحفاظ على التوافق - استخدام النسخة المحسنة بدلاً منها""" | |
| return self._format_enhanced_whale_analysis_for_llm(general_whale_activity, symbol_whale_data, symbol) | |
| async def re_analyze_trade_async(self, trade_data: dict, processed_data: dict): | |
| try: | |
| symbol = trade_data['symbol'] | |
| original_strategy = trade_data.get('strategy', 'GENERIC') | |
| if not original_strategy or original_strategy == 'unknown': | |
| original_strategy = trade_data.get('decision_data', {}).get('strategy', 'GENERIC') | |
| print(f"🔧 Fixed missing original strategy for {symbol}: {original_strategy}") | |
| print(f"🧠 Starting LLM re-analysis for {symbol} with strategy: {original_strategy}...") | |
| news_text = await self.news_fetcher.get_news_for_symbol(symbol) | |
| pattern_analysis = await self._get_pattern_analysis(processed_data) | |
| prompt = self._create_enhanced_re_analysis_prompt(trade_data, processed_data, news_text, pattern_analysis) | |
| async with self.semaphore: | |
| response = await self._call_llm(prompt) | |
| re_analysis_dict = self._parse_re_analysis_response_enhanced(response, original_strategy, symbol) | |
| if re_analysis_dict: | |
| re_analysis_dict['model_source'] = self.model_name | |
| final_strategy = re_analysis_dict.get('strategy') | |
| if not final_strategy or final_strategy == 'unknown': | |
| re_analysis_dict['strategy'] = original_strategy | |
| print(f"🔧 Final re-analysis strategy correction for {symbol}: {original_strategy}") | |
| else: | |
| print(f"✅ LLM re-analysis confirmed strategy '{final_strategy}' for {symbol}.") | |
| print(f"✅ LLM re-analysis completed for {symbol} - Strategy: {re_analysis_dict['strategy']}") | |
| else: | |
| print(f"❌ LLM re-analysis failed for {symbol}") | |
| return local_re_analyze_trade(trade_data, processed_data) | |
| return re_analysis_dict | |
| except Exception as e: | |
| print(f"❌ Unexpected error in enhanced LLM re-analysis: {e}") | |
| return local_re_analyze_trade(trade_data, processed_data) | |
| def _parse_re_analysis_response_enhanced(self, response_text: str, fallback_strategy: str = 'GENERIC', symbol: str = 'unknown') -> dict: | |
| """✅ الإصلاح النهائي: تحليل رد إعادة التحليل مع إعطاء الثقة لقراره""" | |
| try: | |
| json_match = re.search(r'```json\n(.*?)\n```', response_text, re.DOTALL) | |
| if json_match: | |
| json_str = json_match.group(1).strip() | |
| else: | |
| json_match = re.search(r'\{.*\}', response_text, re.DOTALL) | |
| if json_match: | |
| json_str = json_match.group() | |
| else: | |
| print(f"❌ No JSON found in re-analysis response for {symbol}: {response_text}") | |
| return None | |
| decision_data = json.loads(json_str) | |
| strategy_value = decision_data.get('strategy') | |
| # 💡 التحقق: هل الاستراتيجية التي أرجعها النموذج صالحة؟ | |
| if not strategy_value or strategy_value == 'unknown' or strategy_value is None: | |
| # إذا كانت غير صالحة، استخدم الاستراتيجية الأصلية كخطة بديلة آمنة | |
| print(f"⚠️ LLM re-analysis returned invalid strategy '{strategy_value}' for {symbol}. Forcing fallback: {fallback_strategy}") | |
| decision_data['strategy'] = fallback_strategy | |
| else: | |
| # إذا كانت صالحة، اعتمدها مباشرةً! | |
| print(f"✅ LLM re-analysis confirmed strategy '{strategy_value}' for {symbol}.") | |
| return decision_data | |
| except Exception as e: | |
| print(f"❌ Unexpected error parsing re-analysis response for {symbol}: {e}") | |
| return None | |
| def _create_enhanced_re_analysis_prompt(self, trade_data: dict, processed_data: dict, news_text: str, pattern_analysis: dict) -> str: | |
| symbol = trade_data.get('symbol', 'N/A') | |
| entry_price = trade_data.get('entry_price', 'N/A') | |
| current_price = processed_data.get('current_price', 'N/A') | |
| strategy = trade_data.get('strategy', 'GENERIC') | |
| if not strategy or strategy == 'unknown': | |
| strategy = 'GENERIC' | |
| try: | |
| price_change = ((current_price - entry_price) / entry_price) * 100 | |
| performance_status = "Profit" if price_change > 0 else "Loss" | |
| price_change_display = f"{price_change:+.2f}%" | |
| except (TypeError, ZeroDivisionError): | |
| price_change_display = "N/A" | |
| performance_status = "Unknown" | |
| indicators_summary = self._format_advanced_indicators(processed_data.get('advanced_indicators', {})) | |
| pattern_summary = self._format_pattern_analysis_enhanced(pattern_analysis, processed_data) | |
| # 🆕 استخدام البيانات المحسنة من data_manager | |
| whale_analysis_section = self._format_enhanced_whale_analysis_for_llm( | |
| processed_data.get('sentiment_data', {}).get('general_whale_activity', {}), | |
| processed_data.get('whale_data', {}), | |
| symbol | |
| ) | |
| prompt = f""" | |
| 🔄 **ENHANCED TRADE RE-ANALYSIS WITH CHART PATTERNS** | |
| You are re-analyzing an open trade with new market data and chart patterns. | |
| **TRADE CONTEXT ({strategy} STRATEGY):** | |
| - Original Strategy: {strategy} | |
| - Symbol: {symbol} | |
| - Entry Price: {entry_price} USDT | |
| - Current Price: {current_price} USDT | |
| - Current Performance: {price_change_display} ({performance_status}) | |
| - Original Strategy: {strategy} | |
| **UPDATED CHART PATTERN ANALYSIS:** | |
| {pattern_summary} | |
| **NEW MARKET DATA:** | |
| - Updated Technicals: {indicators_summary} | |
| - Updated Whale Intel: {whale_analysis_section} | |
| - Latest News: {news_text} | |
| **DECISION STRATEGY FOR {strategy}:** | |
| - If pattern shows MORE profit potential: UPDATE with new targets and time | |
| - If pattern suggests WEAKNESS: CLOSE immediately | |
| - If pattern still VALID but needs more time: UPDATE with extended timing | |
| - If pattern INVALIDATED: CLOSE to protect capital | |
| **PATTERN-BASED DECISION GUIDELINES:** | |
| - High-confidence patterns (>70%): Give them primary decision weight | |
| - Medium-confidence patterns (50-70%): Use as supporting evidence | |
| - Low-confidence patterns (<50%): Use cautiously with other factors | |
| **REQUIRED OUTPUTS (JSON ONLY):** | |
| - `action`: Must be ("HOLD", "CLOSE_TRADE", "UPDATE_TRADE") | |
| - `reasoning`: Justification based on new data AND pattern analysis | |
| - `new_stop_loss`: New stop loss if updating (consider pattern levels) | |
| - `new_take_profit`: New take profit if updating (consider pattern targets) | |
| - `new_expected_minutes`: New expected time if updating (null otherwise) | |
| - `confidence_level`: Confidence in this decision (0.00-1.00) | |
| - `strategy`: "{strategy}" # ⚠️ MUST BE EXACTLY: {strategy} | |
| - `pattern_influence_reanalysis`: "Describe how updated pattern analysis affected decision" | |
| **CRITICAL: You MUST include the 'strategy' field with the exact value: "{strategy}"** | |
| """ | |
| return prompt | |
| async def _call_llm(self, prompt: str) -> str: | |
| try: | |
| response = self.client.chat.completions.create( | |
| model=self.model_name, | |
| messages=[{"role": "user", "content": prompt}], | |
| temperature=self.temperature, | |
| seed=42 | |
| ) | |
| return response.choices[0].message.content | |
| except (RateLimitError, APITimeoutError) as e: | |
| print(f"❌ LLM API Error: {e}. Retrying...") | |
| raise | |
| except Exception as e: | |
| print(f"❌ Unexpected LLM API error: {e}") | |
| raise | |
| # نظام تتبع أداء الأنماط | |
| class PatternPerformanceTracker: | |
| def __init__(self): | |
| self.pattern_success_rates = {} | |
| self.pattern_history = [] | |
| async def track_pattern_performance(self, trade_data, pattern_analysis, outcome, profit_percent): | |
| """تتبع أداء الأنماط المختلفة""" | |
| pattern_name = pattern_analysis.get('pattern_detected', 'unknown') | |
| confidence = pattern_analysis.get('pattern_confidence', 0) | |
| if pattern_name not in self.pattern_success_rates: | |
| self.pattern_success_rates[pattern_name] = { | |
| 'success_count': 0, | |
| 'total_count': 0, | |
| 'total_profit': 0, | |
| 'avg_profit': 0, | |
| 'confidence_sum': 0, | |
| 'avg_confidence': 0 | |
| } | |
| stats = self.pattern_success_rates[pattern_name] | |
| stats['total_count'] += 1 | |
| stats['confidence_sum'] += confidence | |
| success = outcome in ["SUCCESS", "CLOSED_BY_REANALYSIS", "CLOSED_BY_MONITOR"] and profit_percent > 0 | |
| if success: | |
| stats['success_count'] += 1 | |
| stats['total_profit'] += profit_percent | |
| stats['avg_profit'] = stats['total_profit'] / stats['success_count'] | |
| stats['avg_confidence'] = stats['confidence_sum'] / stats['total_count'] | |
| success_rate = stats['success_count'] / stats['total_count'] | |
| # تسجيل التاريخ | |
| self.pattern_history.append({ | |
| 'timestamp': datetime.now().isoformat(), | |
| 'pattern': pattern_name, | |
| 'confidence': confidence, | |
| 'success': success, | |
| 'profit_percent': profit_percent, | |
| 'symbol': trade_data.get('symbol', 'unknown') | |
| }) | |
| print(f"📊 Pattern {pattern_name}: Success Rate {success_rate:.1%}, Avg Profit: {stats['avg_profit']:.2f}%, Avg Confidence: {stats['avg_confidence']:.1%}") | |
| return success_rate | |
| def get_pattern_recommendations(self): | |
| """الحصول على توصيات بناءً على أداء الأنماط""" | |
| recommendations = [] | |
| for pattern, stats in self.pattern_success_rates.items(): | |
| if stats['total_count'] >= 3: # على الأقل 3 صفقات لتكوين توصية | |
| success_rate = stats['success_count'] / stats['total_count'] | |
| if success_rate > 0.7: | |
| recommendations.append(f"✅ **{pattern}**: Excellent performance ({success_rate:.1%} success) - Prioritize this pattern") | |
| elif success_rate > 0.5: | |
| recommendations.append(f"⚠️ **{pattern}**: Good performance ({success_rate:.1%} success) - Use with confidence") | |
| elif success_rate < 0.3: | |
| recommendations.append(f"❌ **{pattern}**: Poor performance ({success_rate:.1%} success) - Use cautiously") | |
| return recommendations | |
| # إنشاء نسخة عالمية من متتبع الأداء | |
| pattern_tracker_global = PatternPerformanceTracker() | |
| def local_analyze_opportunity(candidate_data): | |
| """تحليل محسن مع مراعاة مخاطر RSI""" | |
| score = candidate_data.get('enhanced_final_score', candidate_data.get('final_score', 0)) | |
| quality_warnings = candidate_data.get('quality_warnings', []) | |
| strategy = candidate_data.get('target_strategy', 'GENERIC') | |
| rsi_critical = any('🚨 RSI CRITICAL' in warning for warning in quality_warnings) | |
| rsi_warning = any('⚠️ RSI WARNING' in warning for warning in quality_warnings) | |
| if rsi_critical: | |
| return { | |
| "action": "HOLD", | |
| "reasoning": "Local analysis: CRITICAL RSI levels detected - extreme overbought condition. High risk of correction.", | |
| "trade_type": "NONE", | |
| "stop_loss": None, | |
| "take_profit": None, | |
| "expected_target_minutes": 15, | |
| "confidence_level": 0.1, | |
| "model_source": "local_safety_filter", | |
| "strategy": strategy | |
| } | |
| advanced_indicators = candidate_data.get('advanced_indicators', {}) | |
| strategy_scores = candidate_data.get('strategy_scores', {}) | |
| if not advanced_indicators: | |
| return { | |
| "action": "HOLD", | |
| "reasoning": "Local analysis: Insufficient advanced indicator data.", | |
| "trade_type": "NONE", | |
| "stop_loss": None, | |
| "take_profit": None, | |
| "expected_target_minutes": 15, | |
| "confidence_level": 0.3, | |
| "model_source": "local", | |
| "strategy": strategy | |
| } | |
| action = "HOLD" | |
| reasoning = "Local analysis: No strong buy signal based on enhanced rules." | |
| trade_type = "NONE" | |
| stop_loss = None | |
| take_profit = None | |
| expected_minutes = 15 | |
| confidence = 0.3 | |
| five_minute_indicators = advanced_indicators.get('5m', {}) | |
| one_hour_indicators = advanced_indicators.get('1h', {}) | |
| buy_conditions = 0 | |
| total_conditions = 0 | |
| if isinstance(score, (int, float)) and score > 0.70: | |
| buy_conditions += 1 | |
| total_conditions += 1 | |
| rsi_five_minute = five_minute_indicators.get('rsi', 50) | |
| if 30 <= rsi_five_minute <= 65: | |
| buy_conditions += 1 | |
| total_conditions += 1 | |
| if five_minute_indicators.get('macd_hist', 0) > 0: | |
| buy_conditions += 1 | |
| total_conditions += 1 | |
| if (five_minute_indicators.get('ema_9', 0) > five_minute_indicators.get('ema_21', 0) and | |
| one_hour_indicators.get('ema_9', 0) > one_hour_indicators.get('ema_21', 0)): | |
| buy_conditions += 1 | |
| total_conditions += 1 | |
| if five_minute_indicators.get('volume_ratio', 0) > 1.5: | |
| buy_conditions += 1 | |
| total_conditions += 1 | |
| confidence = buy_conditions / total_conditions if total_conditions > 0 else 0.3 | |
| if rsi_warning: | |
| confidence *= 0.7 | |
| reasoning += " RSI warning applied." | |
| if confidence >= 0.6: | |
| action = "BUY" | |
| current_price = candidate_data['current_price'] | |
| trade_type = "LONG" | |
| if rsi_warning: | |
| stop_loss = current_price * 0.93 | |
| else: | |
| stop_loss = current_price * 0.95 | |
| if 'bb_upper' in five_minute_indicators: | |
| take_profit = five_minute_indicators['bb_upper'] * 1.02 | |
| else: | |
| take_profit = current_price * 1.05 | |
| if confidence >= 0.8: | |
| expected_minutes = 10 | |
| elif confidence >= 0.6: | |
| expected_minutes = 18 | |
| else: | |
| expected_minutes = 25 | |
| reasoning = f"Local enhanced analysis: Strong buy signal with {buy_conditions}/{total_conditions} conditions met. Strategy: {strategy}. Confidence: {confidence:.2f}" | |
| if rsi_warning: | |
| reasoning += " (RSI warning - trading with caution)" | |
| return { | |
| "action": action, | |
| "reasoning": reasoning, | |
| "trade_type": trade_type, | |
| "stop_loss": stop_loss, | |
| "take_profit": take_profit, | |
| "expected_target_minutes": expected_minutes, | |
| "confidence_level": confidence, | |
| "model_source": "local", | |
| "strategy": strategy | |
| } | |
| def local_re_analyze_trade(trade_data, processed_data): | |
| current_price = processed_data['current_price'] | |
| stop_loss = trade_data['stop_loss'] | |
| take_profit = trade_data['take_profit'] | |
| action = "HOLD" | |
| reasoning = "Local re-analysis: No significant change to trigger an update or close." | |
| if stop_loss and current_price <= stop_loss: | |
| action = "CLOSE_TRADE" | |
| reasoning = "Local re-analysis: Stop loss has been hit." | |
| elif take_profit and current_price >= take_profit: | |
| action = "CLOSE_TRADE" | |
| reasoning = "Local re-analysis: Take profit has been hit." | |
| strategy = trade_data.get('strategy', 'GENERIC') | |
| if strategy == 'unknown': | |
| strategy = trade_data.get('decision_data', {}).get('strategy', 'GENERIC') | |
| return { | |
| "action": action, | |
| "reasoning": reasoning, | |
| "new_stop_loss": None, | |
| "new_take_profit": None, | |
| "new_expected_minutes": None, | |
| "model_source": "local", | |
| "strategy": strategy | |
| } | |
| print("✅ ENHANCED LLM Service loaded successfully - ADVANCED PATTERN ANALYSIS - Performance Tracking - Real-time Pattern Integration - Enhanced Whale Analysis") |