Update helpers.py
Browse files- helpers.py +102 -6
helpers.py
CHANGED
|
@@ -41,15 +41,50 @@ def validate_required_fields(data_dict: dict, required_fields: list) -> bool:
|
|
| 41 |
return all(field in data_dict for field in required_fields)
|
| 42 |
|
| 43 |
def format_technical_indicators(advanced_indicators):
|
|
|
|
| 44 |
if not advanced_indicators: return "No data for advanced indicators."
|
|
|
|
| 45 |
summary = []
|
| 46 |
for timeframe, indicators in advanced_indicators.items():
|
| 47 |
if indicators:
|
| 48 |
parts = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
if 'rsi' in indicators: parts.append(f"RSI: {indicators['rsi']:.2f}")
|
| 50 |
-
if 'macd_hist' in indicators: parts.append(f"MACD Hist: {indicators['macd_hist']:.
|
| 51 |
-
if '
|
| 52 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
return "\n".join(summary) if summary else "Insufficient indicator data."
|
| 54 |
|
| 55 |
def format_strategy_scores(strategy_scores, recommended_strategy):
|
|
@@ -159,7 +194,7 @@ def format_enhanced_analysis_for_llm(candidate_data, whale_analysis=None, market
|
|
| 159 |
|
| 160 |
# المعلومات الأساسية
|
| 161 |
formatted += f"💰 العملة: {candidate_data.get('symbol', 'N/A')}\n"
|
| 162 |
-
formatted += f"💰 السعر الحالي: ${safe_float_conversion(candidate_data.get('current_price', 0)):.
|
| 163 |
formatted += f"🎯 النتيجة المحسنة: {safe_float_conversion(candidate_data.get('enhanced_final_score', 0)):.3f}\n"
|
| 164 |
|
| 165 |
# المؤشرات الفنية
|
|
@@ -170,11 +205,16 @@ def format_enhanced_analysis_for_llm(candidate_data, whale_analysis=None, market
|
|
| 170 |
if indicators:
|
| 171 |
tech_parts = []
|
| 172 |
if 'rsi' in indicators: tech_parts.append(f"RSI: {indicators['rsi']:.1f}")
|
| 173 |
-
if 'macd_hist' in indicators: tech_parts.append(f"MACD: {indicators['macd_hist']:.
|
| 174 |
if 'volume_ratio' in indicators: tech_parts.append(f"Volume: {indicators['volume_ratio']:.1f}x")
|
| 175 |
if 'ema_9' in indicators and 'ema_21' in indicators:
|
| 176 |
ema_signal = "↑" if indicators['ema_9'] > indicators['ema_21'] else "↓"
|
| 177 |
tech_parts.append(f"EMA: {ema_signal}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
if tech_parts:
|
| 179 |
formatted += f" • {timeframe}: {', '.join(tech_parts)}\n"
|
| 180 |
|
|
@@ -366,4 +406,60 @@ def should_override_trade_decision(base_decision, whale_analysis):
|
|
| 366 |
base_action == 'BUY' and whale_action == 'STRONG_SELL' and whale_confidence > 0.7,
|
| 367 |
base_action == 'SELL' and whale_action == 'STRONG_BUY' and whale_confidence > 0.7
|
| 368 |
]
|
| 369 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
return all(field in data_dict for field in required_fields)
|
| 42 |
|
| 43 |
def format_technical_indicators(advanced_indicators):
|
| 44 |
+
"""تنسيق جميع المؤشرات الفنية بشكل شامل للنموذج الضخم"""
|
| 45 |
if not advanced_indicators: return "No data for advanced indicators."
|
| 46 |
+
|
| 47 |
summary = []
|
| 48 |
for timeframe, indicators in advanced_indicators.items():
|
| 49 |
if indicators:
|
| 50 |
parts = []
|
| 51 |
+
|
| 52 |
+
# مؤشرات الاتجاه
|
| 53 |
+
if 'ema_9' in indicators: parts.append(f"EMA9: {indicators['ema_9']:.6f}")
|
| 54 |
+
if 'ema_21' in indicators: parts.append(f"EMA21: {indicators['ema_21']:.6f}")
|
| 55 |
+
if 'ema_50' in indicators: parts.append(f"EMA50: {indicators['ema_50']:.6f}")
|
| 56 |
+
if 'ema_200' in indicators: parts.append(f"EMA200: {indicators['ema_200']:.6f}")
|
| 57 |
+
if 'adx' in indicators: parts.append(f"ADX: {indicators['adx']:.2f}")
|
| 58 |
+
if 'ichimoku_conversion' in indicators: parts.append(f"Ichimoku Conv: {indicators['ichimoku_conversion']:.6f}")
|
| 59 |
+
if 'ichimoku_base' in indicators: parts.append(f"Ichimoku Base: {indicators['ichimoku_base']:.6f}")
|
| 60 |
+
|
| 61 |
+
# مؤشرات الزخم
|
| 62 |
if 'rsi' in indicators: parts.append(f"RSI: {indicators['rsi']:.2f}")
|
| 63 |
+
if 'macd_hist' in indicators: parts.append(f"MACD Hist: {indicators['macd_hist']:.6f}")
|
| 64 |
+
if 'macd_line' in indicators: parts.append(f"MACD Line: {indicators['macd_line']:.6f}")
|
| 65 |
+
if 'stoch_rsi_k' in indicators: parts.append(f"Stoch RSI: {indicators['stoch_rsi_k']:.2f}")
|
| 66 |
+
if 'williams_r' in indicators: parts.append(f"Williams %R: {indicators['williams_r']:.2f}")
|
| 67 |
+
|
| 68 |
+
# مؤشرات التقلب
|
| 69 |
+
if 'bb_upper' in indicators: parts.append(f"BB Upper: {indicators['bb_upper']:.6f}")
|
| 70 |
+
if 'bb_lower' in indicators: parts.append(f"BB Lower: {indicators['bb_lower']:.6f}")
|
| 71 |
+
if 'bb_middle' in indicators: parts.append(f"BB Middle: {indicators['bb_middle']:.6f}")
|
| 72 |
+
if 'atr' in indicators: parts.append(f"ATR: {indicators['atr']:.6f}")
|
| 73 |
+
if 'atr_percent' in indicators: parts.append(f"ATR %: {indicators['atr_percent']:.2f}%")
|
| 74 |
+
|
| 75 |
+
# مؤشرات الحجم
|
| 76 |
+
if 'volume_ratio' in indicators: parts.append(f"Volume Ratio: {indicators['volume_ratio']:.2f}x")
|
| 77 |
+
if 'vwap' in indicators: parts.append(f"VWAP: {indicators['vwap']:.6f}")
|
| 78 |
+
if 'obv' in indicators: parts.append(f"OBV: {indicators['obv']:.0f}")
|
| 79 |
+
if 'mfi' in indicators: parts.append(f"MFI: {indicators['mfi']:.2f}")
|
| 80 |
+
|
| 81 |
+
# مؤشرات الدورة
|
| 82 |
+
if 'hull_ma' in indicators: parts.append(f"Hull MA: {indicators['hull_ma']:.6f}")
|
| 83 |
+
if 'supertrend' in indicators: parts.append(f"Supertrend: {indicators['supertrend']:.6f}")
|
| 84 |
+
|
| 85 |
+
if parts:
|
| 86 |
+
summary.append(f"{timeframe.upper()}: {', '.join(parts)}")
|
| 87 |
+
|
| 88 |
return "\n".join(summary) if summary else "Insufficient indicator data."
|
| 89 |
|
| 90 |
def format_strategy_scores(strategy_scores, recommended_strategy):
|
|
|
|
| 194 |
|
| 195 |
# المعلومات الأساسية
|
| 196 |
formatted += f"💰 العملة: {candidate_data.get('symbol', 'N/A')}\n"
|
| 197 |
+
formatted += f"💰 السعر الحالي: ${safe_float_conversion(candidate_data.get('current_price', 0)):.6f}\n"
|
| 198 |
formatted += f"🎯 النتيجة المحسنة: {safe_float_conversion(candidate_data.get('enhanced_final_score', 0)):.3f}\n"
|
| 199 |
|
| 200 |
# المؤشرات الفنية
|
|
|
|
| 205 |
if indicators:
|
| 206 |
tech_parts = []
|
| 207 |
if 'rsi' in indicators: tech_parts.append(f"RSI: {indicators['rsi']:.1f}")
|
| 208 |
+
if 'macd_hist' in indicators: tech_parts.append(f"MACD: {indicators['macd_hist']:.6f}")
|
| 209 |
if 'volume_ratio' in indicators: tech_parts.append(f"Volume: {indicators['volume_ratio']:.1f}x")
|
| 210 |
if 'ema_9' in indicators and 'ema_21' in indicators:
|
| 211 |
ema_signal = "↑" if indicators['ema_9'] > indicators['ema_21'] else "↓"
|
| 212 |
tech_parts.append(f"EMA: {ema_signal}")
|
| 213 |
+
if 'adx' in indicators: tech_parts.append(f"ADX: {indicators['adx']:.1f}")
|
| 214 |
+
if 'bb_upper' in indicators and 'bb_lower' in indicators:
|
| 215 |
+
bb_position = (candidate_data.get('current_price', 0) - indicators['bb_lower']) / (indicators['bb_upper'] - indicators['bb_lower'])
|
| 216 |
+
bb_signal = "HIGH" if bb_position > 0.8 else "LOW" if bb_position < 0.2 else "MID"
|
| 217 |
+
tech_parts.append(f"BB: {bb_signal}")
|
| 218 |
if tech_parts:
|
| 219 |
formatted += f" • {timeframe}: {', '.join(tech_parts)}\n"
|
| 220 |
|
|
|
|
| 406 |
base_action == 'BUY' and whale_action == 'STRONG_SELL' and whale_confidence > 0.7,
|
| 407 |
base_action == 'SELL' and whale_action == 'STRONG_BUY' and whale_confidence > 0.7
|
| 408 |
]
|
| 409 |
+
|
| 410 |
+
return any(mandatory_override_conditions)
|
| 411 |
+
|
| 412 |
+
def format_candle_data_for_pattern_analysis(ohlcv_data, timeframe='1h'):
|
| 413 |
+
"""تنسيق بيانات الشموع لتحليل الأنماط البيانية"""
|
| 414 |
+
if not ohlcv_data or timeframe not in ohlcv_data:
|
| 415 |
+
return "لا توجد بيانات شموع كافية لتحليل الأنماط"
|
| 416 |
+
|
| 417 |
+
candles = ohlcv_data[timeframe]
|
| 418 |
+
if len(candles) < 20:
|
| 419 |
+
return f"بيانات غير كافية ({len(candles)} شمعة فقط)"
|
| 420 |
+
|
| 421 |
+
# أخذ آخر 50 شمعة للتحليل
|
| 422 |
+
recent_candles = candles[-50:] if len(candles) > 50 else candles
|
| 423 |
+
|
| 424 |
+
formatted = f"📊 بيانات الشموع للإطار {timeframe.upper()} (آخر {len(recent_candles)} شمعة):\n"
|
| 425 |
+
|
| 426 |
+
# تحليل الاتجاه
|
| 427 |
+
first_close = recent_candles[0][4]
|
| 428 |
+
last_close = recent_candles[-1][4]
|
| 429 |
+
price_change = ((last_close - first_close) / first_close) * 100
|
| 430 |
+
trend = "🟢 صاعد" if price_change > 2 else "🔴 هابط" if price_change < -2 else "⚪ جانبي"
|
| 431 |
+
|
| 432 |
+
# تحليل التقلب
|
| 433 |
+
highs = [c[2] for c in recent_candles]
|
| 434 |
+
lows = [c[3] for c in recent_candles]
|
| 435 |
+
high_max = max(highs)
|
| 436 |
+
low_min = min(lows)
|
| 437 |
+
volatility = ((high_max - low_min) / low_min) * 100
|
| 438 |
+
|
| 439 |
+
# تحليل الحجم
|
| 440 |
+
volumes = [c[5] for c in recent_candles]
|
| 441 |
+
avg_volume = sum(volumes) / len(volumes)
|
| 442 |
+
current_volume = recent_candles[-1][5]
|
| 443 |
+
volume_ratio = current_volume / avg_volume if avg_volume > 0 else 1
|
| 444 |
+
|
| 445 |
+
formatted += f"📈 الاتجاه: {trend} ({price_change:+.2f}%)\n"
|
| 446 |
+
formatted += f"🌊 التقلب: {volatility:.2f}% (النطاق: {low_min:.6f} - {high_max:.6f})\n"
|
| 447 |
+
formatted += f"📦 الحجم: {volume_ratio:.2f}x المتوسط\n\n"
|
| 448 |
+
|
| 449 |
+
# عرض آخر 10 شموع بالتفصيل
|
| 450 |
+
formatted += "🕯️ آخر 10 شموع (من الأحدث إلى الأقدم):\n"
|
| 451 |
+
for i in range(min(10, len(recent_candles))):
|
| 452 |
+
idx = len(recent_candles) - 1 - i
|
| 453 |
+
candle = recent_candles[idx]
|
| 454 |
+
timestamp = datetime.fromtimestamp(candle[0] / 1000).strftime('%H:%M')
|
| 455 |
+
open_price, high, low, close, volume = candle[1], candle[2], candle[3], candle[4], candle[5]
|
| 456 |
+
|
| 457 |
+
candle_type = "🟢" if close > open_price else "🔴" if close < open_price else "⚪"
|
| 458 |
+
body_size = abs(close - open_price) / open_price * 100
|
| 459 |
+
wick_upper = (high - max(open_price, close)) / high * 100
|
| 460 |
+
wick_lower = (min(open_price, close) - low) / low * 100
|
| 461 |
+
|
| 462 |
+
formatted += f" {timestamp} {candle_type} O:{open_price:.6f} H:{high:.6f} L:{low:.6f} C:{close:.6f} V:{volume:.0f}\n"
|
| 463 |
+
formatted += f" الجسم: {body_size:.2f}% | الظلال: علوية {wick_upper:.2f}% / سفلية {wick_lower:.2f}%\n"
|
| 464 |
+
|
| 465 |
+
return formatted
|