File size: 23,338 Bytes
56b50dd
c0d1d16
413ec05
c0d1d16
 
413ec05
 
 
4871cfe
 
413ec05
4871cfe
413ec05
 
4871cfe
413ec05
 
 
 
 
 
4871cfe
 
413ec05
4871cfe
 
 
 
0f7f748
 
 
 
 
4871cfe
0f7f748
4871cfe
0f7f748
4871cfe
0f7f748
 
 
 
 
cf52831
4871cfe
cf52831
0f7f748
 
 
 
cf52831
 
 
 
 
 
 
 
 
 
 
0f7f748
cf52831
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0f7f748
 
 
4871cfe
0f7f748
 
 
 
 
4871cfe
 
1cab813
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c0d1d16
 
 
 
 
 
56b50dd
c0d1d16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1cab813
 
 
 
 
 
 
 
cf52831
1cab813
 
 
 
 
 
 
 
 
 
cf52831
1cab813
 
 
 
cf52831
 
 
 
 
1cab813
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf52831
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
# helpers.py
import os, re, json, hashlib
from datetime import datetime
import pandas as pd
import numpy as np

def safe_float_conversion(value, default=0.0):
    try:
        if value is None: return default
        if isinstance(value, (int, float)): return float(value)
        if isinstance(value, str):
            cleaned = ''.join(c for c in value if c.isdigit() or c in '.-')
            return float(cleaned) if cleaned else default
        return default
    except (ValueError, TypeError): return default

def _apply_patience_logic(decision, hold_minutes, trade_data, processed_data):
    action = decision.get('action')
    if action == "CLOSE_TRADE" and hold_minutes < 20:
        current_price = processed_data.get('current_price', 0)
        entry_price = trade_data.get('entry_price', 0)
        try: profit_loss_percent = ((current_price - entry_price) / entry_price) * 100
        except (TypeError, ZeroDivisionError): profit_loss_percent = 0
        if profit_loss_percent < 2:
            decision.update({
                'action': "HOLD",
                'reasoning': f"Patience Filter: Blocked premature sell. Held for {hold_minutes:.1f}m. Giving trade more time."
            })
    return decision

def parse_json_from_response(response_text: str):
    try:
        json_match = re.search(r'```json\n(.*?)\n```', response_text, re.DOTALL)
        if json_match: return json_match.group(1).strip()
        json_match = re.search(r'\{.*\}', response_text, re.DOTALL)
        if json_match: return json_match.group()
        return None
    except Exception: return None

def validate_required_fields(data_dict: dict, required_fields: list) -> bool:
    return all(field in data_dict for field in required_fields)

def format_technical_indicators(advanced_indicators):
    """تنسيق جميع المؤشرات الفنية بشكل شامل للنموذج الضخم"""
    if not advanced_indicators: return "No data for advanced indicators."
    
    summary = []
    for timeframe, indicators in advanced_indicators.items():
        if indicators:
            parts = []
            
            # مؤشرات الاتجاه
            if 'ema_9' in indicators: parts.append(f"EMA9: {indicators['ema_9']:.6f}")
            if 'ema_21' in indicators: parts.append(f"EMA21: {indicators['ema_21']:.6f}")
            if 'ema_50' in indicators: parts.append(f"EMA50: {indicators['ema_50']:.6f}")
            if 'ema_200' in indicators: parts.append(f"EMA200: {indicators['ema_200']:.6f}")
            if 'adx' in indicators: parts.append(f"ADX: {indicators['adx']:.2f}")
            if 'ichimoku_conversion' in indicators: parts.append(f"Ichimoku Conv: {indicators['ichimoku_conversion']:.6f}")
            if 'ichimoku_base' in indicators: parts.append(f"Ichimoku Base: {indicators['ichimoku_base']:.6f}")
            
            # مؤشرات الزخم
            if 'rsi' in indicators: parts.append(f"RSI: {indicators['rsi']:.2f}")
            if 'macd_hist' in indicators: parts.append(f"MACD Hist: {indicators['macd_hist']:.6f}")
            if 'macd_line' in indicators: parts.append(f"MACD Line: {indicators['macd_line']:.6f}")
            if 'stoch_rsi_k' in indicators: parts.append(f"Stoch RSI: {indicators['stoch_rsi_k']:.2f}")
            if 'williams_r' in indicators: parts.append(f"Williams %R: {indicators['williams_r']:.2f}")
            
            # مؤشرات التقلب
            if 'bb_upper' in indicators: parts.append(f"BB Upper: {indicators['bb_upper']:.6f}")
            if 'bb_lower' in indicators: parts.append(f"BB Lower: {indicators['bb_lower']:.6f}")
            if 'bb_middle' in indicators: parts.append(f"BB Middle: {indicators['bb_middle']:.6f}")
            if 'atr' in indicators: parts.append(f"ATR: {indicators['atr']:.6f}")
            if 'atr_percent' in indicators: parts.append(f"ATR %: {indicators['atr_percent']:.2f}%")
            
            # مؤشرات الحجم
            if 'volume_ratio' in indicators: parts.append(f"Volume Ratio: {indicators['volume_ratio']:.2f}x")
            if 'vwap' in indicators: parts.append(f"VWAP: {indicators['vwap']:.6f}")
            if 'obv' in indicators: parts.append(f"OBV: {indicators['obv']:.0f}")
            if 'mfi' in indicators: parts.append(f"MFI: {indicators['mfi']:.2f}")
            
            # مؤشرات الدورة
            if 'hull_ma' in indicators: parts.append(f"Hull MA: {indicators['hull_ma']:.6f}")
            if 'supertrend' in indicators: parts.append(f"Supertrend: {indicators['supertrend']:.6f}")
            
            if parts:
                summary.append(f"{timeframe.upper()}: {', '.join(parts)}")
    
    return "\n".join(summary) if summary else "Insufficient indicator data."

def format_strategy_scores(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:
        score_display = f"{score:.3f}" if isinstance(score, (int, float)) else str(score)
        summary.append(f"   • {strategy}: {score_display}")
    return "\n".join(summary)

def format_whale_analysis_for_llm(whale_analysis):
    """تنسيق تحليل الحيتان للنموذج الضخم بشكل مفيد وواضح"""
    if not whale_analysis or not whale_analysis.get('data_available', False):
        return "📊 تحليل الحيتان: لا توجد بيانات عن تحركات الحيتان الحديثة"
    
    summary = whale_analysis.get('llm_friendly_summary', {})
    
    if not summary:
        return "📊 تحليل الحيتان: بيانات الحيتان غير متوفرة"
    
    formatted = f"📊 تحليل الحيتان:\n"
    formatted += f"   • النشاط: {summary.get('whale_activity_summary', 'لا توجد معلومات')}\n"
    formatted += f"   • التوصية: {summary.get('recommended_action', 'HOLD')}\n"
    formatted += f"   • مستوى الثقة: {summary.get('confidence', 0.5):.1%}\n"
    
    metrics = summary.get('key_metrics', {})
    if metrics:
        flow_direction = metrics.get('net_flow_direction', 'غير معروف')
        impact_level = metrics.get('whale_movement_impact', 'غير معروف')
        exchange_involvement = metrics.get('exchange_involvement', 'غير معروف')
        
        formatted += f"   • اتجاه التدفق: {flow_direction}\n"
        formatted += f"   • مستوى التأثير: {impact_level}\n"
        formatted += f"   • مشاركة المنصات: {exchange_involvement}"
    
    # إضافة تحذير إذا كان هناك نشاط حرج
    if whale_analysis.get('trading_signal', {}).get('critical_alert', False):
        formatted += "\n   ⚠️  تحذير: نشاط حيتان حرج يتطلب الحذر"
    
    return formatted

def validate_candidate_data_enhanced(candidate):
    try:
        required_fields = ['symbol', 'current_price', 'final_score', 'enhanced_final_score']
        for field in required_fields:
            if field not in candidate: candidate[field] = 0.0 if field.endswith('_score') or field == 'current_price' else 'UNKNOWN'
        candidate['current_price'] = safe_float_conversion(candidate.get('current_price'), 0.0)
        candidate['final_score'] = safe_float_conversion(candidate.get('final_score'), 0.0)  # ❌ تغيير من 0.5 إلى 0.0
        candidate['enhanced_final_score'] = safe_float_conversion(candidate.get('enhanced_final_score'), candidate['final_score'])
        if 'reasons_for_candidacy' not in candidate: candidate['reasons_for_candidacy'] = ['unknown_reason']
        if 'sentiment_data' not in candidate: candidate['sentiment_data'] = {'btc_sentiment': 'NEUTRAL','fear_and_greed_index': 50,'general_whale_activity': {'sentiment': 'NEUTRAL', 'critical_alert': False}}
        if 'advanced_indicators' not in candidate: candidate['advanced_indicators'] = {}
        if 'strategy_scores' not in candidate: candidate['strategy_scores'] = {}
        if 'target_strategy' not in candidate: candidate['target_strategy'] = 'GENERIC'
        return True
    except Exception as error:
        print(f"Failed to validate candidate data for {candidate.get('symbol')}: {error}")
        return False

def normalize_weights(weights_dict):
    total = sum(weights_dict.values())
    if total > 0:
        for strategy in weights_dict:
            weights_dict[strategy] /= total
    return weights_dict

def calculate_market_volatility(market_context):
    try:
        btc_price = market_context.get('bitcoin_price_usd', 0)
        fear_greed = market_context.get('fear_and_greed_index', 50)
        whale_sentiment = market_context.get('general_whale_activity', {}).get('sentiment', 'NEUTRAL')
        
        volatility_score = 0
        
        if btc_price > 0:
            if abs(fear_greed - 50) > 20:
                volatility_score += 1
        
        if whale_sentiment in ['BULLISH', 'BEARISH']:
            volatility_score += 1
        elif whale_sentiment == 'SLIGHTLY_BULLISH':
            volatility_score += 0.5
        
        if volatility_score >= 1.5:
            return "high"
        elif volatility_score >= 0.5:
            return "medium"
        else:
            return "low"
            
    except Exception as e:
        print(f"Volatility calculation error: {e}")
        return "medium"

def generate_trade_id():
    return str(int(time.time()))

def should_update_weights(performance_history_count):
    if performance_history_count <= 10:
        return True
    return performance_history_count % 3 == 0

def format_enhanced_analysis_for_llm(candidate_data, whale_analysis=None, market_context=None):
    """تنسيق تحليل متقدم شامل للنموذج الضخم"""
    formatted = "📈 التحليل الشامل للعملة:\n"
    
    # المعلومات الأساسية
    formatted += f"💰 العملة: {candidate_data.get('symbol', 'N/A')}\n"
    formatted += f"💰 السعر الحالي: ${safe_float_conversion(candidate_data.get('current_price', 0)):.6f}\n"
    formatted += f"🎯 النتيجة المحسنة: {safe_float_conversion(candidate_data.get('enhanced_final_score', 0)):.3f}\n"
    
    # المؤشرات الفنية
    advanced_indicators = candidate_data.get('advanced_indicators', {})
    if advanced_indicators:
        formatted += "\n🔧 المؤشرات الفنية:\n"
        for timeframe, indicators in advanced_indicators.items():
            if indicators:
                tech_parts = []
                if 'rsi' in indicators: tech_parts.append(f"RSI: {indicators['rsi']:.1f}")
                if 'macd_hist' in indicators: tech_parts.append(f"MACD: {indicators['macd_hist']:.6f}")
                if 'volume_ratio' in indicators: tech_parts.append(f"Volume: {indicators['volume_ratio']:.1f}x")
                if 'ema_9' in indicators and 'ema_21' in indicators:
                    ema_signal = "↑" if indicators['ema_9'] > indicators['ema_21'] else "↓"
                    tech_parts.append(f"EMA: {ema_signal}")
                if 'adx' in indicators: tech_parts.append(f"ADX: {indicators['adx']:.1f}")
                if 'bb_upper' in indicators and 'bb_lower' in indicators:
                    bb_position = (candidate_data.get('current_price', 0) - indicators['bb_lower']) / (indicators['bb_upper'] - indicators['bb_lower'])
                    bb_signal = "HIGH" if bb_position > 0.8 else "LOW" if bb_position < 0.2 else "MID"
                    tech_parts.append(f"BB: {bb_signal}")
                if tech_parts:
                    formatted += f"   • {timeframe}: {', '.join(tech_parts)}\n"
    
    # استراتيجيات التداول
    strategy_scores = candidate_data.get('strategy_scores', {})
    if strategy_scores:
        formatted += "\n🎯 استراتيجيات التداول:\n"
        sorted_strategies = sorted(strategy_scores.items(), key=lambda x: x[1], reverse=True)[:3]
        for strategy, score in sorted_strategies:
            formatted += f"   • {strategy}: {score:.3f}\n"
    
    # بيانات الحيتان (إذا كانت متوفرة)
    if whale_analysis:
        formatted += f"\n{format_whale_analysis_for_llm(whale_analysis)}\n"
    
    # سياق السوق (إذا كان متوفراً)
    if market_context:
        formatted += "\n🌍 سياق السوق العام:\n"
        btc_sentiment = market_context.get('btc_sentiment', 'NEUTRAL')
        fear_greed = market_context.get('fear_and_greed_index', 50)
        formatted += f"   • اتجاه البيتكوين: {btc_sentiment}\n"
        formatted += f"   • مؤشر الخوف والجشع: {fear_greed}\n"
    
    # أسباب الترشيح
    reasons = candidate_data.get('reasons_for_candidacy', [])
    if reasons and len(reasons) > 0:
        formatted += "\n📋 أسباب الترشيح:\n"
        for i, reason in enumerate(reasons[:5], 1):
            formatted += f"   {i}. {reason}\n"
    
    return formatted

def create_whale_aware_trading_decision(base_decision, whale_analysis):
    """إنشاء قرار تداول مدرك لبيانات الحيتان"""
    if not whale_analysis or not whale_analysis.get('data_available', False):
        return base_decision
    
    whale_signal = whale_analysis.get('trading_signal', {})
    whale_action = whale_signal.get('action', 'HOLD')
    whale_confidence = whale_signal.get('confidence', 0.5)
    
    base_action = base_decision.get('action', 'HOLD')
    base_confidence = base_decision.get('confidence_level', 0.5)
    
    # إذا كانت إشارة الحيتان حرجة، نعطيها أولوية عالية
    if whale_signal.get('critical_alert', False):
        if whale_action in ['STRONG_SELL', 'SELL'] and base_action == 'BUY':
            return {
                **base_decision,
                'action': 'HOLD',
                'confidence_level': base_confidence * 0.6,
                'reasoning': f"{base_decision.get('reasoning', '')} | تم التصحيح بسبب نشاط الحيتان الحرج: {whale_signal.get('reason', '')}"
            }
        elif whale_action in ['STRONG_BUY', 'BUY'] and base_action == 'HOLD':
            return {
                **base_decision,
                'action': 'BUY',
                'confidence_level': (base_confidence + whale_confidence) / 2,
                'reasoning': f"{base_decision.get('reasoning', '')} | تم التعزيز بسبب نشاط الحيتان الإيجابي: {whale_signal.get('reason', '')}"
            }
    
    # دمج الثقة مع إعطاء وزن 60% لبيانات الحيتان
    combined_confidence = (base_confidence * 0.4) + (whale_confidence * 0.6)
    
    # إذا كانت إشارة الحيتان قوية ومعاكسة، نغير القرار
    if whale_confidence > 0.8:
        if (whale_action in ['STRONG_SELL', 'SELL'] and base_action == 'BUY') or \
           (whale_action in ['STRONG_BUY', 'BUY'] and base_action == 'SELL'):
            return {
                **base_decision,
                'action': 'HOLD',
                'confidence_level': combined_confidence * 0.8,
                'reasoning': f"{base_decision.get('reasoning', '')} | تعارض مع تحركات الحيتان: {whale_signal.get('reason', '')}"
            }
    
    # إذا كانت الإشارات متوافقة، نعزز الثقة
    if (whale_action in ['STRONG_BUY', 'BUY'] and base_action == 'BUY') or \
       (whale_action in ['STRONG_SELL', 'SELL'] and base_action == 'SELL'):
        enhanced_confidence = min(combined_confidence * 1.2, 0.95)
        return {
            **base_decision,
            'confidence_level': enhanced_confidence,
            'reasoning': f"{base_decision.get('reasoning', '')} | متوافق مع تحركات الحيتان"
        }
    
    # في الحالات الأخرى، نعيد القرار الأساسي مع الثقة المجمعة
    return {
        **base_decision,
        'confidence_level': combined_confidence,
        'reasoning': f"{base_decision.get('reasoning', '')} | أخذ بعين الاعتبار نشاط الحيتان"
    }

def validate_whale_analysis_data(whale_data):
    """التحقق من صحة بيانات تحليل الحيتان"""
    if not whale_data:
        return False, "بيانات الحيتان فارغة"
    
    required_fields = ['symbol', 'data_available', 'trading_signal']
    for field in required_fields:
        if field not in whale_data:
            return False, f"حقل {field} مفقود في بيانات الحيتان"
    
    if not whale_data['data_available']:
        return True, "لا توجد بيانات حيتان متاحة"
    
    signal_fields = ['action', 'confidence', 'reason']
    trading_signal = whale_data.get('trading_signal', {})
    for field in signal_fields:
        if field not in trading_signal:
            return False, f"حقل {field} مفقود في إشارة التداول"
    
    valid_actions = ['STRONG_BUY', 'BUY', 'HOLD', 'SELL', 'STRONG_SELL']
    if trading_signal.get('action') not in valid_actions:
        return False, f"إجراء تداول غير صالح: {trading_signal.get('action')}"
    
    confidence = trading_signal.get('confidence', 0)
    if not (0 <= confidence <= 1):
        return False, f"مستوى الثقة خارج النطاق: {confidence}"
    
    return True, "بيانات الحيتان صالحة"

def calculate_whale_impact_score(whale_analysis):
    """حساب درجة تأثير الحيتان من 0 إلى 100"""
    if not whale_analysis or not whale_analysis.get('data_available', False):
        return 0
    
    trading_signal = whale_analysis.get('trading_signal', {})
    action = trading_signal.get('action', 'HOLD')
    confidence = trading_signal.get('confidence', 0.5)
    
    # تعيين أوزان للإجراءات المختلفة
    action_weights = {
        'STRONG_BUY': 100,
        'BUY': 75,
        'HOLD': 50,
        'SELL': 25,
        'STRONG_SELL': 0
    }
    
    base_score = action_weights.get(action, 50)
    
    # تعديل الدرجة بناء على مستوى الثقة
    if confidence > 0.8:
        adjusted_score = base_score * 1.2
    elif confidence > 0.6:
        adjusted_score = base_score * 1.0
    else:
        adjusted_score = base_score * 0.8
    
    # إذا كان هناك تحذير حرج، نعطي وزن إضافي
    if trading_signal.get('critical_alert', False):
        if action in ['STRONG_SELL', 'SELL']:
            adjusted_score = max(0, adjusted_score - 20)
        elif action in ['STRONG_BUY', 'BUY']:
            adjusted_score = min(100, adjusted_score + 20)
    
    return min(100, max(0, adjusted_score))

def format_whale_impact_for_display(whale_analysis):
    """تنسيق تأثير الحيتان للعرض في الواجهة"""
    impact_score = calculate_whale_impact_score(whale_analysis)
    
    if impact_score >= 80:
        return "🟢 تأثير إيجابي قوي"
    elif impact_score >= 60:
        return "🟡 تأثير إيجابي متوسط"
    elif impact_score >= 40:
        return "⚪ تأثير محايد"
    elif impact_score >= 20:
        return "🟠 تأثير سلبي متوسط"
    else:
        return "🔴 تأثير سلبي قوي"

def should_override_trade_decision(base_decision, whale_analysis):
    """تحديد إذا كان يجب تغيير قرار التداول بناء على تحركات الحيتان"""
    if not whale_analysis or not whale_analysis.get('data_available', False):
        return False
    
    whale_signal = whale_analysis.get('trading_signal', {})
    whale_action = whale_signal.get('action', 'HOLD')
    whale_confidence = whale_signal.get('confidence', 0.5)
    
    base_action = base_decision.get('action', 'HOLD')
    
    # شروط التغيير الإلزامي
    mandatory_override_conditions = [
        whale_signal.get('critical_alert', False) and whale_confidence > 0.8,
        whale_confidence > 0.9 and whale_action in ['STRONG_SELL', 'STRONG_BUY'],
        base_action == 'BUY' and whale_action == 'STRONG_SELL' and whale_confidence > 0.7,
        base_action == 'SELL' and whale_action == 'STRONG_BUY' and whale_confidence > 0.7
    ]
    
    return any(mandatory_override_conditions)

def format_candle_data_for_pattern_analysis(ohlcv_data, timeframe='1h'):
    """تنسيق بيانات الشموع لتحليل الأنماط البيانية"""
    if not ohlcv_data or timeframe not in ohlcv_data:
        return "لا توجد بيانات شموع كافية لتحليل الأنماط"
    
    candles = ohlcv_data[timeframe]
    if len(candles) < 20:
        return f"بيانات غير كافية ({len(candles)} شمعة فقط)"
    
    # أخذ آخر 50 شمعة للتحليل
    recent_candles = candles[-50:] if len(candles) > 50 else candles
    
    formatted = f"📊 بيانات الشموع للإطار {timeframe.upper()} (آخر {len(recent_candles)} شمعة):\n"
    
    # تحليل الاتجاه
    first_close = recent_candles[0][4]
    last_close = recent_candles[-1][4]
    price_change = ((last_close - first_close) / first_close) * 100
    trend = "🟢 صاعد" if price_change > 2 else "🔴 هابط" if price_change < -2 else "⚪ جانبي"
    
    # تحليل التقلب
    highs = [c[2] for c in recent_candles]
    lows = [c[3] for c in recent_candles]
    high_max = max(highs)
    low_min = min(lows)
    volatility = ((high_max - low_min) / low_min) * 100
    
    # تحليل الحجم
    volumes = [c[5] for c in recent_candles]
    avg_volume = sum(volumes) / len(volumes)
    current_volume = recent_candles[-1][5]
    volume_ratio = current_volume / avg_volume if avg_volume > 0 else 1
    
    formatted += f"📈 الاتجاه: {trend} ({price_change:+.2f}%)\n"
    formatted += f"🌊 التقلب: {volatility:.2f}% (النطاق: {low_min:.6f} - {high_max:.6f})\n"
    formatted += f"📦 الحجم: {volume_ratio:.2f}x المتوسط\n\n"
    
    # عرض آخر 10 شموع بالتفصيل
    formatted += "🕯️ آخر 10 شموع (من الأحدث إلى الأقدم):\n"
    for i in range(min(10, len(recent_candles))):
        idx = len(recent_candles) - 1 - i
        candle = recent_candles[idx]
        timestamp = datetime.fromtimestamp(candle[0] / 1000).strftime('%H:%M')
        open_price, high, low, close, volume = candle[1], candle[2], candle[3], candle[4], candle[5]
        
        candle_type = "🟢" if close > open_price else "🔴" if close < open_price else "⚪"
        body_size = abs(close - open_price) / open_price * 100
        wick_upper = (high - max(open_price, close)) / high * 100
        wick_lower = (min(open_price, close) - low) / low * 100
        
        formatted += f"   {timestamp} {candle_type} O:{open_price:.6f} H:{high:.6f} L:{low:.6f} C:{close:.6f} V:{volume:.0f}\n"
        formatted += f"      الجسم: {body_size:.2f}% | الظلال: علوية {wick_upper:.2f}% / سفلية {wick_lower:.2f}%\n"
    
    return formatted