Riy777 commited on
Commit
4696baa
·
1 Parent(s): 113d926

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -142
app.py CHANGED
@@ -16,7 +16,7 @@ try:
16
  from r2 import R2Service
17
  from LLM import LLMService
18
  from data_manager import DataManager
19
- from ml_engine.processor import MLProcessor # 🔴 تم تعديل هذا السطر
20
  from learning_engine import LearningEngine
21
  from sentiment_news import SentimentAnalyzer
22
  from trade_manager import TradeManager
@@ -118,7 +118,7 @@ async def initialize_services():
118
  llm_service_global = LLMService()
119
  llm_service_global.r2_service = r2_service_global
120
  state_manager.set_service_initialized('llm_service')
121
- print(" ✅ LLMService مهيأ")
122
 
123
  # 6. تهيئة محلل المشاعر
124
  print(" 🔄 تهيئة محلل المشاعر...")
@@ -191,12 +191,12 @@ async def monitor_market_async():
191
  print(f"❌ فشل تشغيل مراقبة السوق: {e}")
192
 
193
  #
194
- # 🔴 تم التعديل: الدالة الآن ترجع قاموساً مفصلاً بدلاً من قائمة واحدة
195
  #
196
  async def process_batch_parallel(batch, ml_processor, batch_num, total_batches):
197
  """معالجة دفعة من الرموز بشكل متوازي وإرجاع نتائج مفصلة"""
198
  try:
199
- print(f" 🔄 معالجة الدفعة {batch_num}/{total_batches} ({len(batch)} عملة)...")
200
 
201
  # إنشاء مهام للدفعة الحالية
202
  batch_tasks = []
@@ -207,30 +207,23 @@ async def process_batch_parallel(batch, ml_processor, batch_num, total_batches):
207
  # انتظار انتهاء جميع مهام الدفعة الحالية
208
  batch_results = await asyncio.gather(*batch_tasks, return_exceptions=True)
209
 
210
- #
211
- # 🔴 تم التعديل: تصفية النتائج إلى ثلاث فئات
212
- #
213
  successful_results = []
214
  low_score_results = []
215
  failed_results = []
216
 
217
  for i, result in enumerate(batch_results):
218
- symbol = batch[i].get('symbol', 'unknown') # جلب الرمز من بيانات الدفعة الأصلية
219
 
220
  if isinstance(result, Exception):
221
- # فشل على مستوى المهمة (مثل Timeout)
222
  failed_results.append({"symbol": symbol, "error": f"Task Execution Error: {str(result)}"})
223
  elif result is None:
224
- # فشل المعالجة داخل ML.py (سيرجع None)
225
  failed_results.append({"symbol": symbol, "error": "ML.py processing returned None (Check logs for internal error)"})
226
  elif result.get('enhanced_final_score', 0) > 0.4:
227
- # نجاح - درجة عالية
228
  successful_results.append(result)
229
  else:
230
- # نجاح - درجة منخفضة
231
  low_score_results.append(result)
232
 
233
- print(f" ✅ اكتملت الدفعة {batch_num}: {len(successful_results)} نجاح | {len(low_score_results)} منخفض | {len(failed_results)} فشل")
234
 
235
  # إرجاع قاموس مفصل
236
  return {
@@ -240,19 +233,20 @@ async def process_batch_parallel(batch, ml_processor, batch_num, total_batches):
240
  }
241
 
242
  except Exception as error:
243
- print(f"❌ خطأ في معالجة الدفعة {batch_num}: {error}")
244
- # إرجاع هيكل فارغ في حالة فشل الدفعة بالكامل
245
  return {'success': [], 'low_score': [], 'failures': []}
246
 
 
 
 
247
  async def run_3_layer_analysis():
248
  """
249
- تشغيل النظام الطبقي المكون من 3 طبقات:
250
  الطبقة 1: data_manager - الفحص السريع
251
- الطبقة 2: MLProcessor - التحليل المتقدم
252
  الطبقة 3: LLMService - النموذج الضخم
253
  """
254
 
255
- # 🔴 تعريف متغيرات السجل في بداية الدالة
256
  layer1_candidates = []
257
  layer2_candidates = []
258
  all_low_score_candidates = []
@@ -261,13 +255,13 @@ async def run_3_layer_analysis():
261
  final_opportunities = []
262
 
263
  try:
264
- print("🎯 بدء النظام الطبقي المكون من 3 طبقات...")
265
 
266
  if not await state_manager.wait_for_initialization():
267
  print("❌ الخدمات غير مهيأة بالكامل")
268
  return None
269
 
270
- # الطبقة 1: الفحص السريع لجميع العملات
271
  print("\n🔍 الطبقة 1: الفحص السريع (data_manager)...")
272
  layer1_candidates = await data_manager_global.layer1_rapid_screening()
273
 
@@ -277,69 +271,98 @@ async def run_3_layer_analysis():
277
 
278
  print(f"✅ تم اختيار {len(layer1_candidates)} عملة للطبقة 2")
279
 
280
- # جلب بيانات OHLCV كاملة للمرشحين
281
- layer1_symbols = [candidate['symbol'] for candidate in layer1_candidates]
282
- ohlcv_data_list = await data_manager_global.get_ohlcv_data_for_symbols(layer1_symbols)
283
-
284
- if not ohlcv_data_list:
285
- print("❌ فشل جلب بيانات OHLCV للمرشحين")
286
- return None
287
 
288
- print(f"📊 تم جلب بيانات OHLCV لـ {len(ohlcv_data_list)} عملة بنجاح")
 
 
 
 
 
 
 
289
 
290
- # الطبقة 2: التحليل المتقدم بشكل متوازي حقيقي
291
- print(f"\n📈 الطبقة 2: التحليل المتقدم (MLProcessor) بشكل متوازي لـ {len(ohlcv_data_list)} عملة...")
292
  market_context = await data_manager_global.get_market_context_async()
293
-
294
- # إنشاء معالج ML
295
  ml_processor = MLProcessor(market_context, data_manager_global, learning_engine_global)
296
 
297
- # تجهيز البيانات للطبقة 2
298
- layer2_data = []
299
- for ohlcv_data in ohlcv_data_list:
300
- try:
301
- # إضافة أسباب الترشيح من الطبقة 1
302
- symbol = ohlcv_data['symbol']
303
- layer1_candidate = next((c for c in layer1_candidates if c['symbol'] == symbol), None)
304
- if layer1_candidate:
305
- ohlcv_data['reasons_for_candidacy'] = layer1_candidate.get('reasons', [])
306
- ohlcv_data['layer1_score'] = layer1_candidate.get('layer1_score', 0)
307
- ohlcv_data['successful_timeframes'] = ohlcv_data.get('successful_timeframes', 0)
308
-
309
- layer2_data.append(ohlcv_data)
310
-
311
- except Exception as e:
312
- continue
313
-
314
- if not layer2_data:
315
- print("❌ فشل إعداد بيانات الطبقة 2")
316
- return None
317
-
318
- # تقسيم العمل إلى دفعات للمعالجة المتوازية
319
- batch_size = 15
320
- batches = [layer2_data[i:i + batch_size] for i in range(0, len(layer2_data), batch_size)]
321
- total_batches = len(batches)
322
 
323
- print(f" 🚀 تقسيم العمل إلى {total_batches} دفعة ({batch_size} عملة لكل دفعة)...")
324
-
325
- # معالجة جميع الدفعات بشكل متوازي
326
- batch_tasks = []
327
- for i, batch in enumerate(batches):
328
- task = asyncio.create_task(process_batch_parallel(batch, ml_processor, i+1, total_batches))
329
- batch_tasks.append(task)
330
-
331
- #
332
- # 🔴 تم التعديل: تجميع النتائج المفصلة
333
- #
334
- batch_results_list = await asyncio.gather(*batch_tasks)
335
-
336
- # دمج جميع النتائج
337
- layer2_candidates = []
338
- all_low_score_candidates = []
339
- all_failed_candidates = []
340
-
341
- for batch_result in batch_results_list:
342
- layer2_candidates.extend(batch_result['success'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
  all_low_score_candidates.extend(batch_result['low_score'])
344
  all_failed_candidates.extend(batch_result['failures'])
345
 
@@ -347,19 +370,17 @@ async def run_3_layer_analysis():
347
 
348
  if not layer2_candidates:
349
  print("❌ لم يتم العثور على مرشحين في الطبقة 2")
350
- # 🔴 استمرار لتسجيل السجل
351
 
352
- # ترتيب المرشحين (الناجحين فقط) حسب الدرجة المحسنة وأخذ أقوى 10
353
  layer2_candidates.sort(key=lambda x: x.get('enhanced_final_score', 0), reverse=True)
354
  target_count = min(10, len(layer2_candidates))
355
  final_layer2_candidates = layer2_candidates[:target_count]
356
 
357
  print(f"🎯 تم اختيار {len(final_layer2_candidates)} عملة للطبقة 3 (الأقوى فقط)")
358
-
359
- # ✅ حفظ المرشحين العشرة في ملف Candidates في R2
360
  await r2_service_global.save_candidates_async(final_layer2_candidates)
361
 
362
- # عرض أفضل 10 عملات من الطبقة 2
363
  print("\n🏆 أفضل 10 عملات من الطبقة 2:")
364
  for i, candidate in enumerate(final_layer2_candidates):
365
  score = candidate.get('enhanced_final_score', 0)
@@ -374,49 +395,33 @@ async def run_3_layer_analysis():
374
  print(f" 🎯 مونت كارلو: {mc_score:.3f}")
375
  print(f" 🎯 استراتيجية: {strategy} | نمط: {pattern}")
376
 
377
- # الطبقة 3: التحليل بالنموذج الضخم
378
  print("\n🧠 الطبقة 3: التحليل بالنموذج الضخم (LLMService)...")
379
- final_opportunities = []
380
 
381
  for candidate in final_layer2_candidates:
382
  try:
383
  symbol = candidate['symbol']
384
  print(f" 🤔 تحليل {symbol} بالنموذج الضخم...")
385
 
386
- # الإصلاح الرئيسي: التأكد من وجود بيانات الشموع في candidate
387
- ohlcv_data = candidate.get('ohlcv') # التغيير هنا: استخدام 'ohlcv' بدلاً من 'raw_ohlcv'
388
 
389
  if not ohlcv_data:
390
  print(f" ⚠️ لا توجد بيانات شموع لـ {symbol}")
391
- # محاولة الحصول على البيانات من المصدر الأصلي
392
- symbol_ohlcv_list = await data_manager_global.get_ohlcv_data_for_symbols([symbol])
393
- if symbol_ohlcv_list and len(symbol_ohlcv_list) > 0:
394
- ohlcv_data = symbol_ohlcv_list[0].get('ohlcv')
395
- candidate['ohlcv'] = ohlcv_data
396
- candidate['raw_ohlcv'] = ohlcv_data
397
-
398
- if not ohlcv_data:
399
- print(f" ⚠️ فشل جلب بيانات شموع لـ {symbol}")
400
  continue
401
 
402
- # ✅ التأكد من تمرير البيانات الخام للنموذج - الإصلاح الرئيسي
403
  candidate['raw_ohlcv'] = ohlcv_data
404
- candidate['ohlcv'] = ohlcv_data
405
 
406
- # ✅ التحقق من جودة البيانات قبل الإرسال للنموذج
407
  timeframes_count = candidate.get('successful_timeframes', 0)
408
  total_candles = sum(len(data) for data in ohlcv_data.values()) if ohlcv_data else 0
409
 
410
- if total_candles < 30: # تخفيف الشرط من 50 إلى 30 شمعة
411
  print(f" ⚠️ بيانات شموع غير كافية لـ {symbol}: {total_candles} شمعة فقط")
412
  continue
413
 
414
  print(f" 📊 إرسال {symbol} للنموذج: {total_candles} شمعة في {timeframes_count} إطار زمني")
415
 
416
- # ✅ إرسال كل عملة للنموذج الضخم على حدة
417
  llm_analysis = await llm_service_global.get_trading_decision(candidate)
418
 
419
- # ✅ التحقق من وجود قرار صالح من النموذج
420
  if llm_analysis and llm_analysis.get('action') in ['BUY', 'SELL']:
421
  opportunity = {
422
  'symbol': symbol,
@@ -441,20 +446,15 @@ async def run_3_layer_analysis():
441
  continue
442
 
443
  if final_opportunities:
444
- # ترتيب الفرص النهائية حسب الثقة والدرجة
445
  final_opportunities.sort(key=lambda x: (x['llm_confidence'] + x['enhanced_score']) / 2, reverse=True)
446
-
447
  print(f"\n🏆 النظام الطبقي اكتمل: {len(final_opportunities)} فرصة تداول")
448
  for i, opportunity in enumerate(final_opportunities[:5]):
449
  print(f" {i+1}. {opportunity['symbol']}: {opportunity['decision'].get('action')} - ثقة: {opportunity['llm_confidence']:.2f} - أطر: {opportunity['timeframes_count']}")
450
 
451
- #
452
- # 🔴 --- بدء سجل تدقيق التحليل ---
453
- #
454
  try:
455
- # 1. ملخص الـ 10 الأوائل (لـ LLM)
456
  top_10_detailed_summary = []
457
- for c in final_layer2_candidates: # هذه هي قائمة الـ 10 الأوائل
458
  whale_summary = "Not Available"
459
  whale_data = c.get('whale_data')
460
  if whale_data and whale_data.get('data_available'):
@@ -473,30 +473,17 @@ async def run_3_layer_analysis():
473
  "pattern": c.get('pattern_analysis', {}).get('pattern_detected', 'N/A'),
474
  })
475
 
476
- # 2. ملخص باقي الناجحين (الذين لم يتم إرسالهم للنموذج)
477
  other_successful_candidates = layer2_candidates[target_count:]
478
  other_success_summary = [
479
- {
480
- "symbol": c['symbol'],
481
- "score": c.get('enhanced_final_score', 0),
482
- "timeframes": f"{c.get('successful_timeframes', 'N/A')}/6",
483
- "whale_data": "Available" if c.get('whale_data', {}).get('data_available') else "Not Available"
484
- }
485
  for c in other_successful_candidates
486
  ]
487
 
488
- # 3. ملخص الدرجات المنخفضة (نجاح < 0.4)
489
  low_score_summary = [
490
- {
491
- "symbol": c['symbol'],
492
- "score": c.get('enhanced_final_score', 0),
493
- "timeframes": f"{c.get('successful_timeframes', 'N/A')}/6",
494
- "whale_data": "Available" if c.get('whale_data', {}).get('data_available') else "Not Available"
495
- }
496
  for c in all_low_score_candidates
497
  ]
498
 
499
- # 4. تجميع السجل النهائي
500
  audit_data = {
501
  "timestamp": datetime.now().isoformat(),
502
  "total_layer1_candidates": len(layer1_candidates),
@@ -507,23 +494,18 @@ async def run_3_layer_analysis():
507
  "success_low_score": len(all_low_score_candidates),
508
  "failures": len(all_failed_candidates)
509
  },
510
-
511
  "top_candidates_for_llm": top_10_detailed_summary,
512
  "other_successful_candidates": other_success_summary,
513
  "low_score_candidates": low_score_summary,
514
- "failed_candidates": all_failed_candidates, # {"symbol": ..., "error": ...}
515
  }
516
 
517
- # 5. حفظ السجل
518
  await r2_service_global.save_analysis_audit_log_async(audit_data)
519
  print(f"✅ تم حفظ سجل تدقيق التحليل في R2.")
520
 
521
  except Exception as audit_error:
522
  print(f"❌ فشل حفظ سجل تدقيق التحليل: {audit_error}")
523
  traceback.print_exc()
524
- #
525
- # 🔴 --- نهاية سجل تدقيق التحليل ---
526
- #
527
 
528
  if not final_opportunities:
529
  print("❌ لم يتم العثور على فرص تداول مناسبة")
@@ -535,7 +517,6 @@ async def run_3_layer_analysis():
535
  print(f"❌ خطأ في النظام الطبقي: {error}")
536
  traceback.print_exc()
537
 
538
- # 🔴 تسجيل السجل حتى في حالة الفشل
539
  try:
540
  audit_data = {
541
  "timestamp": datetime.now().isoformat(),
@@ -545,7 +526,7 @@ async def run_3_layer_analysis():
545
  "total_layer1_candidates": len(layer1_candidates),
546
  "counts": {
547
  "sent_to_llm": 0,
548
- "success_not_top_10": len(layer2_candidates[target_count:]) if 'target_count' in locals() else 0,
549
  "success_low_score": len(all_low_score_candidates),
550
  "failures": len(all_failed_candidates)
551
  },
@@ -557,6 +538,8 @@ async def run_3_layer_analysis():
557
  print(f"❌ فشل حفظ سجل التدقيق أثناء معالجة خطأ آخر: {audit_fail_error}")
558
 
559
  return None
 
 
560
 
561
  async def re_analyze_open_trade_async(trade_data):
562
  """إعادة تحليل الصفقة المفتوحة"""
@@ -565,13 +548,23 @@ async def re_analyze_open_trade_async(trade_data):
565
  async with state_manager.trade_analysis_lock:
566
  # جلب البيانات الحالية
567
  market_context = await data_manager_global.get_market_context_async()
568
- ohlcv_data_list = await data_manager_global.get_ohlcv_data_for_symbols([symbol])
 
 
 
 
 
569
 
570
  if not ohlcv_data_list:
571
  return None
572
 
573
  ohlcv_data = ohlcv_data_list[0]
574
- ohlcv_data['reasons_for_candidacy'] = ['re-analysis']
 
 
 
 
 
575
 
576
  # استخدام ML للتحليل
577
  ml_processor = MLProcessor(market_context, data_manager_global, learning_engine_global)
@@ -656,7 +649,7 @@ async def run_bot_cycle_async():
656
  current_capital = portfolio_state.get("current_capital_usd", 0)
657
 
658
  if current_capital > 1:
659
- print("🎯 البحث عن فرص تداول جديدة...")
660
  best_opportunity = await run_3_layer_analysis()
661
 
662
  if best_opportunity:
@@ -706,7 +699,7 @@ async def lifespan(application: FastAPI):
706
  asyncio.create_task(trade_manager_global.start_trade_monitoring())
707
 
708
  await r2_service_global.save_system_logs_async({"application_started": True})
709
- print("🎯 التطبيق جاهز للعمل - نظام الطبقات 3 فعال")
710
 
711
  yield
712
 
@@ -725,8 +718,8 @@ async def lifespan(application: FastAPI):
725
  application = FastAPI(
726
  lifespan=lifespan,
727
  title="AI Trading Bot",
728
- description="نظام تداول ذكي بثلاث طبقات تحليلية",
729
- version="3.0.0"
730
  )
731
 
732
  @application.get("/")
@@ -734,7 +727,7 @@ async def root():
734
  """الصفحة الرئيسية"""
735
  return {
736
  "message": "مرحباً بك في نظام التداول الذكي",
737
- "system": "3-Layer Analysis System",
738
  "status": "running" if state_manager.initialization_complete else "initializing",
739
  "timestamp": datetime.now().isoformat()
740
  }
@@ -745,7 +738,7 @@ async def run_cycle_api():
745
  if not state_manager.initialization_complete:
746
  raise HTTPException(status_code=503, detail="الخدمات غير مهيأة بالكامل")
747
  asyncio.create_task(run_bot_cycle_async())
748
- return {"message": "Bot cycle initiated", "system": "3-Layer Analysis"}
749
 
750
  @application.get("/health")
751
  async def health_check():
@@ -756,10 +749,10 @@ async def health_check():
756
  "services_initialized": state_manager.services_initialized,
757
  "initialization_error": state_manager.initialization_error,
758
  "timestamp": datetime.now().isoformat(),
759
- "system_architecture": "3-Layer Analysis System",
760
  "layers": {
761
  "layer1": "Data Manager - Rapid Screening",
762
- "layer2": "ML Processor - Advanced Analysis",
763
  "layer3": "LLM Service - Deep Analysis"
764
  }
765
  }
@@ -859,7 +852,7 @@ signal.signal(signal.SIGINT, signal_handler)
859
  signal.signal(signal.SIGTERM, signal_handler)
860
 
861
  if __name__ == "__main__":
862
- print("🚀 Starting AI Trading Bot with 3-Layer Analysis System...")
863
  uvicorn.run(
864
  application,
865
  host="0.0.0.0",
 
16
  from r2 import R2Service
17
  from LLM import LLMService
18
  from data_manager import DataManager
19
+ from ml_engine.processor import MLProcessor # هذا الاستيراد صحيح
20
  from learning_engine import LearningEngine
21
  from sentiment_news import SentimentAnalyzer
22
  from trade_manager import TradeManager
 
118
  llm_service_global = LLMService()
119
  llm_service_global.r2_service = r2_service_global
120
  state_manager.set_service_initialized('llm_service')
121
+ print(" ✅ LLMService مهيأة")
122
 
123
  # 6. تهيئة محلل المشاعر
124
  print(" 🔄 تهيئة محلل المشاعر...")
 
191
  print(f"❌ فشل تشغيل مراقبة السوق: {e}")
192
 
193
  #
194
+ # 🔴 هذه الدالة (المستهلك) لم تتغير، لأنها بالفعل تعالج الدفعات
195
  #
196
  async def process_batch_parallel(batch, ml_processor, batch_num, total_batches):
197
  """معالجة دفعة من الرموز بشكل متوازي وإرجاع نتائج مفصلة"""
198
  try:
199
+ print(f" 🔄 [المستهلك] بدء معالجة الدفعة {batch_num}/{total_batches} ({len(batch)} عملة)...")
200
 
201
  # إنشاء مهام للدفعة الحالية
202
  batch_tasks = []
 
207
  # انتظار انتهاء جميع مهام الدفعة الحالية
208
  batch_results = await asyncio.gather(*batch_tasks, return_exceptions=True)
209
 
 
 
 
210
  successful_results = []
211
  low_score_results = []
212
  failed_results = []
213
 
214
  for i, result in enumerate(batch_results):
215
+ symbol = batch[i].get('symbol', 'unknown')
216
 
217
  if isinstance(result, Exception):
 
218
  failed_results.append({"symbol": symbol, "error": f"Task Execution Error: {str(result)}"})
219
  elif result is None:
 
220
  failed_results.append({"symbol": symbol, "error": "ML.py processing returned None (Check logs for internal error)"})
221
  elif result.get('enhanced_final_score', 0) > 0.4:
 
222
  successful_results.append(result)
223
  else:
 
224
  low_score_results.append(result)
225
 
226
+ print(f" ✅ [المستهلك] اكتملت معالجة الدفعة {batch_num}: {len(successful_results)} نجاح | {len(low_score_results)} منخفض | {len(failed_results)} فشل")
227
 
228
  # إرجاع قاموس مفصل
229
  return {
 
233
  }
234
 
235
  except Exception as error:
236
+ print(f"❌ [المستهلك] خطأ في معالجة الدفعة {batch_num}: {error}")
 
237
  return {'success': [], 'low_score': [], 'failures': []}
238
 
239
+
240
+ # 🔴 --- بدء التعديل الجوهري --- 🔴
241
+ # تم إعادة هيكلة هذه الدالة بالكامل لاستخدام نموذج المنتج/المستهلك
242
  async def run_3_layer_analysis():
243
  """
244
+ (معدلة) تشغيل النظام الطبقي (منتج/مستهلك)
245
  الطبقة 1: data_manager - الفحص السريع
246
+ الطبقة 2: MLProcessor - التحليل المتدفق
247
  الطبقة 3: LLMService - النموذج الضخم
248
  """
249
 
 
250
  layer1_candidates = []
251
  layer2_candidates = []
252
  all_low_score_candidates = []
 
255
  final_opportunities = []
256
 
257
  try:
258
+ print("🎯 بدء النظام الطبقي المكون من 3 طبقات (بنموذج التدفق)...")
259
 
260
  if not await state_manager.wait_for_initialization():
261
  print("❌ الخدمات غير مهيأة بالكامل")
262
  return None
263
 
264
+ # الطبقة 1: الفحص السريع لجميع العملات (لا تغيير هنا)
265
  print("\n🔍 الطبقة 1: الفحص السريع (data_manager)...")
266
  layer1_candidates = await data_manager_global.layer1_rapid_screening()
267
 
 
271
 
272
  print(f"✅ تم اختيار {len(layer1_candidates)} عملة للطبقة 2")
273
 
274
+ # 🔴 --- إعداد نموذج المنتج والمستهلك --- 🔴
 
 
 
 
 
 
275
 
276
+ # 1. إنشاء الطابور (Queue)
277
+ # maxsize=2 يعني أن المنتج (جلب البيانات) سيتوقف مؤقتاً إذا كان متقدماً
278
+ # على المستهلك (تحليل ML) بأكثر من دفعتين. هذا يمنع استهلاك ذاكرة مفرط.
279
+ DATA_QUEUE_MAX_SIZE = 2
280
+ ohlcv_data_queue = asyncio.Queue(maxsize=DATA_QUEUE_MAX_SIZE)
281
+
282
+ # قائمة لتجميع كل النتائج النهائية من المستهلك
283
+ ml_results_list = []
284
 
285
+ # 2. إعداد المستهلك (MLProcessor)
 
286
  market_context = await data_manager_global.get_market_context_async()
 
 
287
  ml_processor = MLProcessor(market_context, data_manager_global, learning_engine_global)
288
 
289
+ # حساب إجمالي عدد الدفعات للمستهلك
290
+ batch_size = 15 # يجب أن يتطابق هذا مع حجم الدفعة في data_manager
291
+ total_batches = (len(layer1_candidates) + batch_size - 1) // batch_size
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
 
293
+ print(f" 🚀 إعداد المنتج/المستهلك: {total_batches} دفعة متوقعة (بحجم {batch_size})")
294
+
295
+ # 3. تعريف وظيفة المستهلك (Consumer)
296
+ async def ml_consumer_task(queue: asyncio.Queue, results_list: list):
297
+ batch_num = 0
298
+ while True:
299
+ try:
300
+ # انتظار بيانات من المنتج
301
+ batch_data = await queue.get()
302
+
303
+ # 🔴 إشارة التوقف (None)
304
+ if batch_data is None:
305
+ queue.task_done()
306
+ print(" 🛑 [المستهلك] تلقى إشارة التوقف.")
307
+ break
308
+
309
+ batch_num += 1
310
+ print(f" 📬 [المستهلك] استلم الدفعة {batch_num}/{total_batches} ({len(batch_data)} عملة)")
311
+
312
+ # تشغيل المعالجة المتوازية للدفعة (هذا ما كان يحدث سابقاً)
313
+ batch_results_dict = await process_batch_parallel(
314
+ batch_data, ml_processor, batch_num, total_batches
315
+ )
316
+
317
+ results_list.append(batch_results_dict)
318
+
319
+ # إبلاغ الطابور بانتهاء معالجة هذه المهمة
320
+ queue.task_done()
321
+
322
+ except Exception as e:
323
+ print(f"❌ [المستهلك] خطأ فادح في مهمة المستهلك: {e}")
324
+ traceback.print_exc()
325
+ queue.task_done() # يجب استدعاؤها حتى عند الفشل
326
+
327
+ # 4. تشغيل مهمة المستهلك
328
+ print(" ▶️ [المستهلك] بدء تشغيل مهمة المستهلك...")
329
+ consumer_task = asyncio.create_task(ml_consumer_task(ohlcv_data_queue, ml_results_list))
330
+
331
+ # 5. تشغيل مهمة المنتج (Producer)
332
+ layer1_symbols = [candidate['symbol'] for candidate in layer1_candidates]
333
+ # دمج بيانات الطبقة 1 مع بيانات OHLCV
334
+ # 🔴 (تعديل بسيط): دمج بيانات الطبقة 1 *بعد* جلب OHLCV لتبسيط التدفق
335
+ print(" ▶️ [المنتج] بدء تشغيل مهمة المنتج (تدفق بيانات OHLCV)...")
336
+ producer_task = asyncio.create_task(
337
+ data_manager_global.stream_ohlcv_data(layer1_symbols, ohlcv_data_queue)
338
+ )
339
+
340
+ # 6. انتظار انتهاء المنتج (جلب كل البيانات)
341
+ await producer_task
342
+ print(" ✅ [المنتج] أنهى جلب جميع البيانات.")
343
+
344
+ # 7. إرسال إشارة التوقف للمستهلك
345
+ await ohlcv_data_queue.put(None)
346
+
347
+ # 8. انتظار انتهاء المستهلك من معالجة كل شيء في الطابور
348
+ await ohlcv_data_queue.join() # انتظار اكتمال كل task_done()
349
+ await consumer_task # انتظار إغلاق مهمة المستهلك نفسها
350
+ print(" ✅ [المستهلك] أنهى معالجة جميع الدفعات.")
351
+
352
+ # 🔴 --- انتهاء نموذج المنتج والمستهلك --- 🔴
353
+
354
+ # 9. تجميع النتائج
355
+ print("🔄 تجميع جميع النتائج...")
356
+ for batch_result in ml_results_list:
357
+ # دمج بيانات الطبقة 1 (الدرجة والأسباب) مع نتائج الطبقة 2
358
+ for success_item in batch_result['success']:
359
+ symbol = success_item['symbol']
360
+ l1_data = next((c for c in layer1_candidates if c['symbol'] == symbol), None)
361
+ if l1_data:
362
+ success_item['reasons_for_candidacy'] = l1_data.get('reasons', [])
363
+ success_item['layer1_score'] = l1_data.get('layer1_score', 0)
364
+ layer2_candidates.append(success_item)
365
+
366
  all_low_score_candidates.extend(batch_result['low_score'])
367
  all_failed_candidates.extend(batch_result['failures'])
368
 
 
370
 
371
  if not layer2_candidates:
372
  print("❌ لم يتم العثور على مرشحين في الطبقة 2")
373
+ # استمرار لتسجيل السجل
374
 
375
+ # 10. الترتيب والفلترة (نفس المنطق السابق)
376
  layer2_candidates.sort(key=lambda x: x.get('enhanced_final_score', 0), reverse=True)
377
  target_count = min(10, len(layer2_candidates))
378
  final_layer2_candidates = layer2_candidates[:target_count]
379
 
380
  print(f"🎯 تم اختيار {len(final_layer2_candidates)} عملة للطبقة 3 (الأقوى فقط)")
381
+
 
382
  await r2_service_global.save_candidates_async(final_layer2_candidates)
383
 
 
384
  print("\n🏆 أفضل 10 عملات من الطبقة 2:")
385
  for i, candidate in enumerate(final_layer2_candidates):
386
  score = candidate.get('enhanced_final_score', 0)
 
395
  print(f" 🎯 مونت كارلو: {mc_score:.3f}")
396
  print(f" 🎯 استراتيجية: {strategy} | نمط: {pattern}")
397
 
398
+ # 11. الطبقة 3: التحليل بالنموذج الضخم (نفس المنطق السابق)
399
  print("\n🧠 الطبقة 3: التحليل بالنموذج الضخم (LLMService)...")
 
400
 
401
  for candidate in final_layer2_candidates:
402
  try:
403
  symbol = candidate['symbol']
404
  print(f" 🤔 تحليل {symbol} بالنموذج الضخم...")
405
 
406
+ ohlcv_data = candidate.get('ohlcv')
 
407
 
408
  if not ohlcv_data:
409
  print(f" ⚠️ لا توجد بيانات شموع لـ {symbol}")
 
 
 
 
 
 
 
 
 
410
  continue
411
 
 
412
  candidate['raw_ohlcv'] = ohlcv_data
 
413
 
 
414
  timeframes_count = candidate.get('successful_timeframes', 0)
415
  total_candles = sum(len(data) for data in ohlcv_data.values()) if ohlcv_data else 0
416
 
417
+ if total_candles < 30:
418
  print(f" ⚠️ بيانات شموع غير كافية لـ {symbol}: {total_candles} شمعة فقط")
419
  continue
420
 
421
  print(f" 📊 إرسال {symbol} للنموذج: {total_candles} شمعة في {timeframes_count} إطار زمني")
422
 
 
423
  llm_analysis = await llm_service_global.get_trading_decision(candidate)
424
 
 
425
  if llm_analysis and llm_analysis.get('action') in ['BUY', 'SELL']:
426
  opportunity = {
427
  'symbol': symbol,
 
446
  continue
447
 
448
  if final_opportunities:
 
449
  final_opportunities.sort(key=lambda x: (x['llm_confidence'] + x['enhanced_score']) / 2, reverse=True)
 
450
  print(f"\n🏆 النظام الطبقي اكتمل: {len(final_opportunities)} فرصة تداول")
451
  for i, opportunity in enumerate(final_opportunities[:5]):
452
  print(f" {i+1}. {opportunity['symbol']}: {opportunity['decision'].get('action')} - ثقة: {opportunity['llm_confidence']:.2f} - أطر: {opportunity['timeframes_count']}")
453
 
454
+ # 12. سجل التدقيق (نفس المنطق السابق)
 
 
455
  try:
 
456
  top_10_detailed_summary = []
457
+ for c in final_layer2_candidates:
458
  whale_summary = "Not Available"
459
  whale_data = c.get('whale_data')
460
  if whale_data and whale_data.get('data_available'):
 
473
  "pattern": c.get('pattern_analysis', {}).get('pattern_detected', 'N/A'),
474
  })
475
 
 
476
  other_successful_candidates = layer2_candidates[target_count:]
477
  other_success_summary = [
478
+ {"symbol": c['symbol'], "score": c.get('enhanced_final_score', 0), "timeframes": f"{c.get('successful_timeframes', 'N/A')}/6", "whale_data": "Available" if c.get('whale_data', {}).get('data_available') else "Not Available"}
 
 
 
 
 
479
  for c in other_successful_candidates
480
  ]
481
 
 
482
  low_score_summary = [
483
+ {"symbol": c['symbol'], "score": c.get('enhanced_final_score', 0), "timeframes": f"{c.get('successful_timeframes', 'N/A')}/6", "whale_data": "Available" if c.get('whale_data', {}).get('data_available') else "Not Available"}
 
 
 
 
 
484
  for c in all_low_score_candidates
485
  ]
486
 
 
487
  audit_data = {
488
  "timestamp": datetime.now().isoformat(),
489
  "total_layer1_candidates": len(layer1_candidates),
 
494
  "success_low_score": len(all_low_score_candidates),
495
  "failures": len(all_failed_candidates)
496
  },
 
497
  "top_candidates_for_llm": top_10_detailed_summary,
498
  "other_successful_candidates": other_success_summary,
499
  "low_score_candidates": low_score_summary,
500
+ "failed_candidates": all_failed_candidates,
501
  }
502
 
 
503
  await r2_service_global.save_analysis_audit_log_async(audit_data)
504
  print(f"✅ تم حفظ سجل تدقيق التحليل في R2.")
505
 
506
  except Exception as audit_error:
507
  print(f"❌ فشل حفظ سجل تدقيق التحليل: {audit_error}")
508
  traceback.print_exc()
 
 
 
509
 
510
  if not final_opportunities:
511
  print("❌ لم يتم العثور على فرص تداول مناسبة")
 
517
  print(f"❌ خطأ في النظام الطبقي: {error}")
518
  traceback.print_exc()
519
 
 
520
  try:
521
  audit_data = {
522
  "timestamp": datetime.now().isoformat(),
 
526
  "total_layer1_candidates": len(layer1_candidates),
527
  "counts": {
528
  "sent_to_llm": 0,
529
+ "success_not_top_10": 0,
530
  "success_low_score": len(all_low_score_candidates),
531
  "failures": len(all_failed_candidates)
532
  },
 
538
  print(f"❌ فشل حفظ سجل التدقيق أثناء معالجة خطأ آخر: {audit_fail_error}")
539
 
540
  return None
541
+ # 🔴 --- نهاية التعديل الجوهري --- 🔴
542
+
543
 
544
  async def re_analyze_open_trade_async(trade_data):
545
  """إعادة تحليل الصفقة المفتوحة"""
 
548
  async with state_manager.trade_analysis_lock:
549
  # جلب البيانات الحالية
550
  market_context = await data_manager_global.get_market_context_async()
551
+ # 🔴 ملاحظة: هذه الدالة معدلة الآن، لكن استدعاؤها لرمز واحد سيعمل كما كان
552
+ ohlcv_data_list = []
553
+ temp_queue = asyncio.Queue()
554
+ await data_manager_global.stream_ohlcv_data([symbol], temp_queue)
555
+ while not temp_queue.empty():
556
+ ohlcv_data_list.extend(await temp_queue.get())
557
 
558
  if not ohlcv_data_list:
559
  return None
560
 
561
  ohlcv_data = ohlcv_data_list[0]
562
+
563
+ # 🔴 دمج بيانات الطبقة 1 الوهمية لإعادة التحليل
564
+ l1_data = await data_manager_global._get_detailed_symbol_data(symbol)
565
+ if l1_data:
566
+ ohlcv_data['reasons_for_candidacy'] = l1_data.get('reasons', ['re-analysis'])
567
+ ohlcv_data['layer1_score'] = l1_data.get('layer1_score', 0.5) # افتراض درجة متوسطة
568
 
569
  # استخدام ML للتحليل
570
  ml_processor = MLProcessor(market_context, data_manager_global, learning_engine_global)
 
649
  current_capital = portfolio_state.get("current_capital_usd", 0)
650
 
651
  if current_capital > 1:
652
+ print("🎯 البحث عن فرص تداول جديدة (بنموذج التدفق)...")
653
  best_opportunity = await run_3_layer_analysis()
654
 
655
  if best_opportunity:
 
699
  asyncio.create_task(trade_manager_global.start_trade_monitoring())
700
 
701
  await r2_service_global.save_system_logs_async({"application_started": True})
702
+ print("🎯 التطبيق جاهز للعمل - نظام الطبقات 3 فعال (بنموذج التدفق)")
703
 
704
  yield
705
 
 
718
  application = FastAPI(
719
  lifespan=lifespan,
720
  title="AI Trading Bot",
721
+ description="نظام تداول ذكي بثلاث طبقات تحليلية (بنموذج التدفق)",
722
+ version="3.1.0"
723
  )
724
 
725
  @application.get("/")
 
727
  """الصفحة الرئيسية"""
728
  return {
729
  "message": "مرحباً بك في نظام التداول الذكي",
730
+ "system": "3-Layer Analysis System (Streaming Pipeline)",
731
  "status": "running" if state_manager.initialization_complete else "initializing",
732
  "timestamp": datetime.now().isoformat()
733
  }
 
738
  if not state_manager.initialization_complete:
739
  raise HTTPException(status_code=503, detail="الخدمات غير مهيأة بالكامل")
740
  asyncio.create_task(run_bot_cycle_async())
741
+ return {"message": "Bot cycle initiated (Streaming)", "system": "3-Layer Analysis"}
742
 
743
  @application.get("/health")
744
  async def health_check():
 
749
  "services_initialized": state_manager.services_initialized,
750
  "initialization_error": state_manager.initialization_error,
751
  "timestamp": datetime.now().isoformat(),
752
+ "system_architecture": "3-Layer Analysis System (Streaming Pipeline)",
753
  "layers": {
754
  "layer1": "Data Manager - Rapid Screening",
755
+ "layer2": "ML Processor - Advanced Analysis (Streaming Consumer)",
756
  "layer3": "LLM Service - Deep Analysis"
757
  }
758
  }
 
852
  signal.signal(signal.SIGTERM, signal_handler)
853
 
854
  if __name__ == "__main__":
855
+ print("🚀 Starting AI Trading Bot with 3-Layer Analysis System (Streaming)...")
856
  uvicorn.run(
857
  application,
858
  host="0.0.0.0",