Trad / LLM.py
Riy777's picture
Update LLM.py
1af938b
raw
history blame
25 kB
# 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):
@wraps(func)
@on_exception(expo, RateLimitError, max_tries=5)
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
@_rate_limit_nvidia_api
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")