Spaces:
Building
Building
| # LLM.py | |
| import os, traceback, asyncio, json | |
| from datetime import datetime | |
| from functools import wraps | |
| from backoff import on_exception, expo | |
| from openai import OpenAI, RateLimitError, APITimeoutError | |
| import numpy as np | |
| from sentiment_news import NewsFetcher | |
| from helpers import parse_json_from_response, validate_required_fields, format_technical_indicators, format_strategy_scores, format_candle_data_for_pattern_analysis, format_whale_analysis_for_llm | |
| NVIDIA_API_KEY = os.getenv("NVIDIA_API_KEY") | |
| PRIMARY_MODEL = "nvidia/llama-3.1-nemotron-ultra-253b-v1" | |
| class PatternAnalysisEngine: | |
| def __init__(self, llm_service): | |
| self.llm = llm_service | |
| def _format_chart_data_for_llm(self, ohlcv_data): | |
| """ุชูุณูู ุดุงู ู ูุจูุงูุงุช ุงูุดู ูุน ูุชุญููู ุงูุฃูู ุงุท""" | |
| if not ohlcv_data: | |
| return "Insufficient chart data for pattern analysis" | |
| try: | |
| # ุงุณุชุฎุฏุงู ุฌู ูุน ุงูุฃุทุฑ ุงูุฒู ููุฉ ุงูู ุชุงุญุฉ | |
| all_timeframes = [] | |
| for timeframe, candles in ohlcv_data.items(): | |
| if candles and len(candles) >= 20: | |
| candle_summary = format_candle_data_for_pattern_analysis({timeframe: candles}, timeframe) | |
| all_timeframes.append(f"=== {timeframe.upper()} TIMEFRAME ===\n{candle_summary}") | |
| return "\n\n".join(all_timeframes) if all_timeframes else "No sufficient timeframe data available" | |
| 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: | |
| return {"pattern_detected": "insufficient_data", "pattern_confidence": 0.1, "pattern_analysis": "No candle data available"} | |
| chart_text = self._format_chart_data_for_llm(ohlcv_data) | |
| prompt = f""" | |
| ANALYZE CHART PATTERNS FOR {symbol} | |
| CANDLE DATA FOR TECHNICAL ANALYSIS: | |
| {chart_text} | |
| PATTERN ANALYSIS INSTRUCTIONS: | |
| 1. Analyze ALL available timeframes (1w, 1d, 4h, 1h, 15m, 5m) | |
| 2. Identify clear chart patterns (Double Top/Bottom, Head & Shoulders, Triangles, Flags, etc.) | |
| 3. Assess trend direction and strength | |
| 4. Identify key support and resistance levels | |
| 5. Evaluate volume patterns | |
| 6. Look for convergence/divergence across timeframes | |
| 7. Consider candlestick patterns and formations | |
| CRITICAL: You MUST analyze at least 3 different timeframes to confirm patterns. | |
| 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", | |
| "key_support_levels": [0.1200, 0.1180, 0.1150], | |
| "key_resistance_levels": [0.1300, 0.1320, 0.1350], | |
| "pattern_analysis": "Detailed explanation covering multiple timeframes", | |
| "timeframe_confirmations": {{ | |
| "1h": "pattern_details", | |
| "4h": "pattern_details", | |
| "1d": "pattern_details" | |
| }}, | |
| "risk_assessment": "low/medium/high", | |
| "recommended_entry": 0.1234, | |
| "recommended_targets": [0.1357, 0.1400], | |
| "recommended_stop_loss": 0.1189 | |
| }} | |
| """ | |
| response = await self.llm._call_llm(prompt) | |
| return self._parse_pattern_response(response) | |
| except Exception as e: | |
| print(f"Chart pattern analysis failed for {symbol}: {e}") | |
| return None | |
| def _parse_pattern_response(self, response_text): | |
| try: | |
| json_str = parse_json_from_response(response_text) | |
| if not json_str: | |
| return {"pattern_detected": "parse_error", "pattern_confidence": 0.1, "pattern_analysis": "Could not parse pattern analysis response"} | |
| pattern_data = json.loads(json_str) | |
| required = ['pattern_detected', 'pattern_confidence', 'predicted_direction'] | |
| if not validate_required_fields(pattern_data, 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) | |
| self.r2_service = None # ุณูุชู ุชุนูููู ู ู app.py | |
| 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') | |
| # ุฌูุจ ุฌู ูุน ุงูุจูุงูุงุช ุงูู ุทููุจุฉ | |
| news_text = await self.news_fetcher.get_news_for_symbol(symbol) | |
| pattern_analysis = await self._get_pattern_analysis(data_payload) | |
| whale_data = data_payload.get('whale_data', {}) | |
| # ุฅูุดุงุก ุงูู prompt ุงูุดุงู ู | |
| prompt = self._create_comprehensive_trading_prompt(data_payload, news_text, pattern_analysis, whale_data) | |
| # โ ุญูุธ ุงูู Prompt ูู R2 ูุจู ุฅุฑุณุงูู ูููู ูุฐุฌ | |
| if self.r2_service: | |
| analysis_data = { | |
| 'symbol': symbol, | |
| 'current_price': data_payload.get('current_price'), | |
| 'final_score': data_payload.get('final_score'), | |
| 'enhanced_final_score': data_payload.get('enhanced_final_score'), | |
| 'target_strategy': target_strategy, | |
| 'pattern_analysis': pattern_analysis, | |
| 'whale_data_available': whale_data.get('data_available', False), | |
| 'timestamp': datetime.now().isoformat() | |
| } | |
| await self.r2_service.save_llm_prompts_async( | |
| symbol, 'comprehensive_trading_decision', prompt, analysis_data | |
| ) | |
| 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 | |
| decision_dict['whale_data_integrated'] = whale_data.get('data_available', False) | |
| return decision_dict | |
| else: | |
| print(f"โ ูุดู ุชุญููู ุงููู ูุฐุฌ ุงูุถุฎู ูู {symbol} - ูุง ุชูุฌุฏ ูุฑุงุฑุงุช ุจุฏููุฉ") | |
| return None | |
| except Exception as e: | |
| print(f"โ ุฎุทุฃ ูู ูุฑุงุฑ ุงูุชุฏุงูู ูู {data_payload.get('symbol', 'unknown')}: {e}") | |
| traceback.print_exc() | |
| return None | |
| def _parse_llm_response_enhanced(self, response_text: str, fallback_strategy: str, symbol: str) -> dict: | |
| try: | |
| json_str = parse_json_from_response(response_text) | |
| if not json_str: | |
| print(f"โ ูุดู ุงุณุชุฎุฑุงุฌ JSON ู ู ุงุณุชุฌุงุจุฉ ุงููู ูุฐุฌ ูู {symbol}") | |
| 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'] | |
| if not validate_required_fields(decision_data, required_fields): | |
| print(f"โ ุญููู ู ุทููุจุฉ ู ูููุฏุฉ ูู ุงุณุชุฌุงุจุฉ ุงููู ูุฐุฌ ูู {symbol}") | |
| return None | |
| strategy_value = decision_data.get('strategy') | |
| if not strategy_value or strategy_value == 'unknown': | |
| decision_data['strategy'] = fallback_strategy | |
| return decision_data | |
| except Exception as e: | |
| print(f"โ ุฎุทุฃ ูู ุชุญููู ุงุณุชุฌุงุจุฉ ุงููู ูุฐุฌ ูู {symbol}: {e}") | |
| return None | |
| async def _get_pattern_analysis(self, data_payload): | |
| try: | |
| symbol = data_payload['symbol'] | |
| ohlcv_data = data_payload.get('ohlcv') or data_payload.get('raw_ohlcv') | |
| if ohlcv_data: | |
| return await self.pattern_engine.analyze_chart_patterns(symbol, ohlcv_data) | |
| return None | |
| except Exception as e: | |
| print(f"โ ูุดู ุชุญููู ุงูุฃูู ุงุท ูู {data_payload.get('symbol')}: {e}") | |
| return None | |
| def _create_comprehensive_trading_prompt(self, payload: dict, news_text: str, pattern_analysis: dict, whale_data: 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') | |
| ohlcv_data = payload.get('ohlcv') or payload.get('raw_ohlcv', {}) | |
| final_score_display = f"{final_score:.3f}" if isinstance(final_score, (int, float)) else str(final_score) | |
| enhanced_score_display = f"{enhanced_final_score:.3f}" if isinstance(enhanced_final_score, (int, float)) else str(enhanced_final_score) | |
| # ุชูุณูู ุฌู ูุน ุงูุจูุงูุงุช ุจุดูู ุดุงู ู | |
| indicators_summary = format_technical_indicators(advanced_indicators) | |
| strategies_summary = format_strategy_scores(strategy_scores, recommended_strategy) | |
| pattern_summary = self._format_pattern_analysis(pattern_analysis) | |
| whale_analysis_section = format_whale_analysis_for_llm(whale_data) | |
| candle_data_section = self._format_candle_data_comprehensive(ohlcv_data) | |
| market_context_section = self._format_market_context(sentiment_data) | |
| prompt = f""" | |
| COMPREHENSIVE TRADING ANALYSIS FOR {symbol} | |
| ๐ฏ STRATEGY CONTEXT: | |
| - Target Strategy: {target_strategy} | |
| - Recommended Strategy: {recommended_strategy} | |
| - Current Price: ${current_price} | |
| - System Score: {final_score_display} | |
| - Enhanced Score: {enhanced_score_display} | |
| ๐ TECHNICAL INDICATORS (ALL TIMEFRAMES): | |
| {indicators_summary} | |
| ๐ CANDLE DATA & PATTERN ANALYSIS: | |
| {candle_data_section} | |
| ๐ PATTERN ANALYSIS RESULTS: | |
| {pattern_summary} | |
| ๐ฏ STRATEGY ANALYSIS: | |
| {strategies_summary} | |
| ๐ WHALE ACTIVITY ANALYSIS: | |
| {whale_analysis_section} | |
| ๐ MARKET CONTEXT: | |
| {market_context_section} | |
| ๐ฐ LATEST NEWS: | |
| {news_text if news_text else "No significant news found"} | |
| ๐ REASONS FOR CANDIDACY: | |
| {chr(10).join([f"โข {reason}" for reason in reasons]) if reasons else "No specific reasons provided"} | |
| ๐ฏ TRADING DECISION INSTRUCTIONS: | |
| 1. ANALYZE ALL PROVIDED DATA: technical indicators, whale activity, patterns, market context | |
| 2. CONSIDER STRATEGY ALIGNMENT: {target_strategy} | |
| 3. EVALUATE RISK-REWARD RATIO based on support/resistance levels | |
| 4. INTEGRATE WHALE ACTIVITY signals into your decision | |
| 5. CONSIDER PATTERN STRENGTH and timeframe confirmations | |
| 6. ASSESS MARKET SENTIMENT impact | |
| CRITICAL: You MUST provide specific price levels and time expectations. | |
| OUTPUT FORMAT (JSON): | |
| {{ | |
| "action": "BUY/SELL/HOLD", | |
| "reasoning": "Detailed explanation integrating ALL data sources (technical, whale, patterns, news)", | |
| "risk_assessment": "low/medium/high", | |
| "trade_type": "LONG/SHORT", | |
| "stop_loss": 0.000000, | |
| "take_profit": 0.000000, | |
| "expected_target_minutes": 15, | |
| "confidence_level": 0.85, | |
| "strategy": "{target_strategy}", | |
| "whale_influence": "How whale data influenced the decision", | |
| "pattern_influence": "How chart patterns influenced the decision", | |
| "key_support_level": 0.000000, | |
| "key_resistance_level": 0.000000, | |
| "risk_reward_ratio": 2.5 | |
| }} | |
| """ | |
| return prompt | |
| def _format_pattern_analysis(self, pattern_analysis): | |
| if not pattern_analysis: | |
| return "No clear patterns detected across analyzed timeframes" | |
| confidence = pattern_analysis.get('pattern_confidence', 0) | |
| pattern_name = pattern_analysis.get('pattern_detected', 'unknown') | |
| predicted_direction = pattern_analysis.get('predicted_direction', 'N/A') | |
| movement_percent = pattern_analysis.get('predicted_movement_percent', 'N/A') | |
| analysis_lines = [ | |
| f"๐ฏ Pattern: {pattern_name}", | |
| f"๐ Confidence: {confidence:.1%}", | |
| f"๐ Predicted Direction: {predicted_direction}", | |
| f"๐ฐ Expected Movement: {movement_percent}%", | |
| f"๐ Analysis: {pattern_analysis.get('pattern_analysis', 'No detailed analysis')}" | |
| ] | |
| # ุฅุถุงูุฉ ู ุณุชููุงุช ุงูุฏุนู ูุงูู ูุงูู ุฉ ุฅุฐุง ูุงูุช ู ุชููุฑุฉ | |
| support_levels = pattern_analysis.get('key_support_levels', []) | |
| resistance_levels = pattern_analysis.get('key_resistance_levels', []) | |
| if support_levels: | |
| analysis_lines.append(f"๐ Support Levels: {', '.join([f'{level:.6f}' for level in support_levels[:3]])}") | |
| if resistance_levels: | |
| analysis_lines.append(f"๐ง Resistance Levels: {', '.join([f'{level:.6f}' for level in resistance_levels[:3]])}") | |
| return "\n".join(analysis_lines) | |
| def _format_candle_data_comprehensive(self, ohlcv_data): | |
| """ุชูุณูู ุดุงู ู ูุจูุงูุงุช ุงูุดู ูุน""" | |
| if not ohlcv_data: | |
| return "No candle data available for analysis" | |
| try: | |
| timeframes_available = [] | |
| for timeframe, candles in ohlcv_data.items(): | |
| if candles and len(candles) >= 20: | |
| timeframes_available.append(f"{timeframe.upper()} ({len(candles)} candles)") | |
| if not timeframes_available: | |
| return "Insufficient candle data across all timeframes" | |
| summary = f"๐ Available Timeframes: {', '.join(timeframes_available)}\n\n" | |
| # ุชุญููู ููู ุฅุทุงุฑ ุฒู ูู ุฑุฆูุณู | |
| for timeframe in ['1d', '4h', '1h', '15m']: | |
| if timeframe in ohlcv_data and ohlcv_data[timeframe]: | |
| candles = ohlcv_data[timeframe] | |
| if len(candles) >= 20: | |
| timeframe_analysis = self._analyze_timeframe_candles(candles, timeframe) | |
| summary += f"โฐ {timeframe.upper()} ANALYSIS:\n{timeframe_analysis}\n\n" | |
| return summary | |
| except Exception as e: | |
| return f"Error formatting candle data: {str(e)}" | |
| def _analyze_timeframe_candles(self, candles, timeframe): | |
| """ุชุญููู ุงูุดู ูุน ูุฅุทุงุฑ ุฒู ูู ู ุญุฏุฏ""" | |
| try: | |
| if len(candles) < 20: | |
| return "Insufficient data" | |
| recent_candles = candles[-20:] # ุขุฎุฑ 20 ุดู ุนุฉ | |
| # ุญุณุงุจ ุงูู ุชุบูุฑุงุช ุงูุฃุณุงุณูุฉ | |
| closes = [c[4] for c in recent_candles] | |
| opens = [c[1] for c in recent_candles] | |
| highs = [c[2] for c in recent_candles] | |
| lows = [c[3] for c in recent_candles] | |
| volumes = [c[5] for c in recent_candles] | |
| current_price = closes[-1] | |
| first_price = closes[0] | |
| price_change = ((current_price - first_price) / first_price) * 100 | |
| # ุชุญููู ุงูุงุชุฌุงู | |
| if price_change > 2: | |
| trend = "๐ข UPTREND" | |
| elif price_change < -2: | |
| trend = "๐ด DOWNTREND" | |
| else: | |
| trend = "โช SIDEWAYS" | |
| # ุชุญููู ุงูุชููุจ | |
| high_max = max(highs) | |
| low_min = min(lows) | |
| volatility = ((high_max - low_min) / low_min) * 100 | |
| # ุชุญููู ุงูุญุฌู | |
| avg_volume = sum(volumes) / len(volumes) | |
| current_volume = volumes[-1] | |
| volume_ratio = current_volume / avg_volume if avg_volume > 0 else 1 | |
| # ุชุญููู ุงูุดู ูุน | |
| green_candles = sum(1 for i in range(len(closes)) if closes[i] > opens[i]) | |
| red_candles = len(closes) - green_candles | |
| candle_ratio = green_candles / len(closes) | |
| analysis = [ | |
| f"๐ Trend: {trend} ({price_change:+.2f}%)", | |
| f"๐ Volatility: {volatility:.2f}%", | |
| f"๐ฆ Volume: {volume_ratio:.2f}x average", | |
| f"๐ฏ๏ธ Candles: {green_candles}๐ข/{red_candles}๐ด ({candle_ratio:.1%} green)", | |
| f"๐ฐ Range: {low_min:.6f} - {high_max:.6f}", | |
| f"๐ฏ Current: {current_price:.6f}" | |
| ] | |
| return "\n".join(analysis) | |
| except Exception as e: | |
| return f"Analysis error: {str(e)}" | |
| def _format_market_context(self, sentiment_data): | |
| """ุชูุณูู ุณูุงู ุงูุณูู""" | |
| if not sentiment_data: | |
| return "No market context data available" | |
| btc_sentiment = sentiment_data.get('btc_sentiment', 'N/A') | |
| fear_greed = sentiment_data.get('fear_and_greed_index', 'N/A') | |
| market_trend = sentiment_data.get('market_trend', 'N/A') | |
| lines = [ | |
| "๐ MARKET CONTEXT:", | |
| f"โข Bitcoin Sentiment: {btc_sentiment}", | |
| f"โข Fear & Greed Index: {fear_greed}", | |
| f"โข Market Trend: {market_trend}" | |
| ] | |
| general_whale = sentiment_data.get('general_whale_activity', {}) | |
| if general_whale: | |
| whale_sentiment = general_whale.get('sentiment', 'N/A') | |
| critical_alert = general_whale.get('critical_alert', False) | |
| lines.append(f"โข General Whale Sentiment: {whale_sentiment}") | |
| if critical_alert: | |
| lines.append("โข โ ๏ธ CRITICAL WHALE ALERT") | |
| return "\n".join(lines) | |
| 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') | |
| # ุฌูุจ ุฌู ูุน ุงูุจูุงูุงุช ุงูู ุญุฏุซุฉ | |
| news_text = await self.news_fetcher.get_news_for_symbol(symbol) | |
| pattern_analysis = await self._get_pattern_analysis(processed_data) | |
| whale_data = processed_data.get('whale_data', {}) | |
| prompt = self._create_re_analysis_prompt(trade_data, processed_data, news_text, pattern_analysis, whale_data) | |
| # โ ุญูุธ ุงูู Prompt ูู R2 | |
| if self.r2_service: | |
| analysis_data = { | |
| 'symbol': symbol, | |
| 'entry_price': trade_data.get('entry_price'), | |
| 'current_price': processed_data.get('current_price'), | |
| 'original_strategy': original_strategy, | |
| 'pattern_analysis': pattern_analysis, | |
| 'whale_data_available': whale_data.get('data_available', False) | |
| } | |
| await self.r2_service.save_llm_prompts_async( | |
| symbol, 'trade_reanalysis', prompt, analysis_data | |
| ) | |
| async with self.semaphore: | |
| response = await self._call_llm(prompt) | |
| re_analysis_dict = self._parse_re_analysis_response(response, original_strategy, symbol) | |
| if re_analysis_dict: | |
| re_analysis_dict['model_source'] = self.model_name | |
| re_analysis_dict['whale_data_integrated'] = whale_data.get('data_available', False) | |
| return re_analysis_dict | |
| else: | |
| print(f"โ ูุดู ุฅุนุงุฏุฉ ุชุญููู ุงููู ูุฐุฌ ุงูุถุฎู ูู {symbol}") | |
| return None | |
| except Exception as e: | |
| print(f"โ ุฎุทุฃ ูู ุฅุนุงุฏุฉ ุชุญููู LLM: {e}") | |
| traceback.print_exc() | |
| return None | |
| def _parse_re_analysis_response(self, response_text: str, fallback_strategy: str, symbol: str) -> dict: | |
| try: | |
| json_str = parse_json_from_response(response_text) | |
| if not json_str: | |
| return None | |
| decision_data = json.loads(json_str) | |
| strategy_value = decision_data.get('strategy') | |
| if not strategy_value or strategy_value == 'unknown': | |
| decision_data['strategy'] = fallback_strategy | |
| return decision_data | |
| except Exception as e: | |
| print(f"Error parsing re-analysis response for {symbol}: {e}") | |
| return None | |
| def _create_re_analysis_prompt(self, trade_data: dict, processed_data: dict, news_text: str, pattern_analysis: dict, whale_data: 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') | |
| try: | |
| price_change = ((current_price - entry_price) / entry_price) * 100 | |
| price_change_display = f"{price_change:+.2f}%" | |
| except (TypeError, ZeroDivisionError): | |
| price_change_display = "N/A" | |
| indicators_summary = format_technical_indicators(processed_data.get('advanced_indicators', {})) | |
| pattern_summary = self._format_pattern_analysis(pattern_analysis) | |
| whale_analysis_section = format_whale_analysis_for_llm(whale_data) | |
| market_context_section = self._format_market_context(processed_data.get('sentiment_data', {})) | |
| prompt = f""" | |
| TRADE RE-ANALYSIS FOR {symbol} | |
| ๐ TRADE CONTEXT: | |
| - Strategy: {strategy} | |
| - Entry Price: {entry_price} | |
| - Current Price: {current_price} | |
| - Performance: {price_change_display} | |
| - Trade Age: {trade_data.get('hold_duration_minutes', 'N/A')} minutes | |
| ๐ UPDATED TECHNICAL ANALYSIS: | |
| {indicators_summary} | |
| ๐ UPDATED PATTERN ANALYSIS: | |
| {pattern_summary} | |
| ๐ UPDATED WHALE ACTIVITY: | |
| {whale_analysis_section} | |
| ๐ UPDATED MARKET CONTEXT: | |
| {market_context_section} | |
| ๐ฐ LATEST NEWS: | |
| {news_text if news_text else "No significant news found"} | |
| ๐ฏ RE-ANALYSIS INSTRUCTIONS: | |
| 1. Evaluate if the original thesis still holds | |
| 2. Consider new whale activity and patterns | |
| 3. Assess current risk-reward ratio | |
| 4. Decide whether to hold, close, or adjust the trade | |
| 5. Provide specific updated levels if adjusting | |
| OUTPUT FORMAT (JSON): | |
| {{ | |
| "action": "HOLD/CLOSE_TRADE/UPDATE_TRADE", | |
| "reasoning": "Comprehensive justification based on updated analysis", | |
| "new_stop_loss": 0.000000, | |
| "new_take_profit": 0.000000, | |
| "new_expected_minutes": 15, | |
| "confidence_level": 0.85, | |
| "strategy": "{strategy}", | |
| "whale_influence_reanalysis": "How updated whale data influenced decision", | |
| "pattern_influence_reanalysis": "How updated patterns influenced decision", | |
| "risk_adjustment": "low/medium/high" | |
| }} | |
| """ | |
| 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, | |
| max_tokens=4000 | |
| ) | |
| 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 | |
| print("โ LLM Service loaded - Comprehensive Analysis with Whale Data & Pattern Integration") |