Riy777 commited on
Commit
33d07ee
·
1 Parent(s): 11b4dc5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -69
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # app.py (Fully updated to Explorer-Sentry-Executor architecture V5.2 - Fixed typing import)
2
  import os
3
  import traceback
4
  import signal
@@ -10,9 +10,8 @@ import time
10
  from contextlib import asynccontextmanager
11
  from fastapi import FastAPI, HTTPException
12
  from datetime import datetime
13
- from typing import List, Dict, Any # (إضافة الاستيراد الناقص)
14
 
15
- # استيراد الخدمات (بما في ذلك TradeManager المحدث)
16
  try:
17
  from r2 import R2Service
18
  from LLM import LLMService
@@ -20,12 +19,8 @@ try:
20
  from ml_engine.processor import MLProcessor
21
  from learning_hub.hub_manager import LearningHubManager
22
  from sentiment_news import SentimentAnalyzer
23
- from trade_manager import TradeManager # (الملف المحدث)
24
-
25
- # 🔴 --- START OF CHANGE --- 🔴
26
- # (استيراد الدالة المساعدة للتعقيم من ملف مونت كارلو)
27
  from ml_engine.monte_carlo import _sanitize_results_for_json
28
- # 🔴 --- END OF CHANGE --- 🔴
29
 
30
  from helpers import safe_float_conversion, validate_candidate_data_enhanced
31
  except ImportError as e:
@@ -43,11 +38,9 @@ trade_manager_global = None
43
  sentiment_analyzer_global = None
44
  symbol_whale_monitor_global = None
45
 
46
- # (تم تعريف حالة السوق هنا بدلاً من استيرادها - إصلاح سابق)
47
  MARKET_STATE_OK = True
48
 
49
 
50
- # (StateManager - لا تغيير، هذا هو الكلاس الصحيح)
51
  class StateManager:
52
  def __init__(self):
53
  self.market_analysis_lock = asyncio.Lock()
@@ -78,7 +71,6 @@ class StateManager:
78
  self.initialization_error = error
79
  print(f"❌ خطأ في التهيئة: {error}")
80
 
81
- # (استخدام النسخة المحلية الصحيحة)
82
  state_manager = StateManager()
83
 
84
  async def initialize_services():
@@ -87,24 +79,21 @@ async def initialize_services():
87
  global learning_hub_global, trade_manager_global, sentiment_analyzer_global
88
  global symbol_whale_monitor_global
89
  try:
90
- print("🚀 بدء تهيئة الخدمات (بنية Sentry الجديدة V5.2)...")
91
  print(" 🔄 تهيئة R2Service..."); r2_service_global = R2Service(); state_manager.set_service_initialized('r2_service'); print(" ✅ R2Service مهيأة")
92
  print(" 🔄 جلب قاعدة بيانات العقود..."); contracts_database = await r2_service_global.load_contracts_db_async(); print(f" ✅ تم تحميل {len(contracts_database)} عقد")
93
 
94
  print(" 🔄 تهيئة مراقب الحيتان (Layer 1 Data)...");
95
  try:
96
- # (استخدام المسار الجديد الذي قمت بإنشائه)
97
  from whale_monitor.core import EnhancedWhaleMonitor
98
 
99
  symbol_whale_monitor_global = EnhancedWhaleMonitor(contracts_database, r2_service_global)
100
  state_manager.set_service_initialized('symbol_whale_monitor'); print(" ✅ مراقب الحيتان مهيأ")
101
 
102
- # (هذا هو الإصلاح الحاسم لمشكلة الـ Timeout)
103
  except Exception as e:
104
  print(f" ⚠️ فشل تهيئة مراقب الحيتان: {e}");
105
- traceback.print_exc() # (إضافة تتبع الخطأ لمعرفة السبب الحقيقي)
106
  symbol_whale_monitor_global = None
107
- # (إخبار مدير الحالة بأن الخدمة "انتهت" حتى لو فشلت)
108
  state_manager.set_service_initialized('symbol_whale_monitor');
109
  print(" ℹ️ مراقبة الحيتان معطلة. استمرار التهيئة...")
110
 
@@ -138,7 +127,7 @@ async def initialize_services():
138
  r2_service=r2_service_global,
139
  learning_hub=learning_hub_global,
140
  data_manager=data_manager_global,
141
- state_manager=state_manager # (تمرير النسخة المحلية الصحيحة)
142
  )
143
  await trade_manager_global.initialize_sentry_exchanges()
144
  state_manager.set_service_initialized('trade_manager');
@@ -174,7 +163,7 @@ async def monitor_market_async():
174
  await asyncio.sleep(60)
175
  except Exception as error:
176
  print(f"❌ خطأ أثناء مراقبة السوق: {error}");
177
- MARKET_STATE_OK = True; # (الحالة الآمنة عند الفشل)
178
  await asyncio.sleep(60)
179
  except Exception as e: print(f"❌ فشل تشغيل مراقبة السوق: {e}")
180
 
@@ -200,7 +189,6 @@ async def run_periodic_distillation():
200
 
201
  async def process_batch_parallel(batch, ml_processor, batch_num, total_batches, preloaded_whale_data):
202
  """(لا تغيير) معالج الدفعات لـ Layer 1"""
203
- # (ملاحظة: preloaded_whale_data سيكون فارغاً الآن، وهذا طبيعي)
204
  try:
205
  batch_tasks = []
206
  for symbol_data in batch:
@@ -240,17 +228,14 @@ async def process_batch_parallel(batch, ml_processor, batch_num, total_batches,
240
 
241
  async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
242
  """
243
- (معدل) - هذا هو "المستكشف" (Layer 1).
244
- يجلب بيانات الحيتان *فقط* لأفضل 10 مرشحين ويعيد حساب النقاط.
245
  """
246
-
247
  layer1_candidates = []
248
  layer2_candidates = []
249
  final_layer2_candidates = []
250
  watchlist_candidates = []
251
 
252
- # (لم نعد بحاجة لهذا القاموس الكبير مقدماً)
253
- preloaded_whale_data_dict = {} # (سيبقى فارغاً)
254
 
255
  try:
256
  print("🎯 Starting Explorer Analysis (Layer 1)...")
@@ -258,15 +243,16 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
258
  if not await state_manager.wait_for_initialization():
259
  print("❌ Services not fully initialized (Explorer)"); return []
260
 
261
- print("\n🔍 Layer 1.1: Rapid Screening (data_manager)...")
 
262
  layer1_candidates = await data_manager_global.layer1_rapid_screening()
263
  if not layer1_candidates: print("❌ No candidates found in Layer 1.1"); return []
264
  print(f"✅ Selected {len(layer1_candidates)} symbols for Layer 1.2")
265
- layer1_symbols = [c['symbol'] for c in layer1_candidates]
266
-
267
- # (تم حذف كتلة 'Layer 1.2: Fetching whale data' بالكامل من هنا)
268
 
269
- print(f"\n📊 Layer 1.2: Fetching OHLCV data for {len(layer1_symbols)} symbols (Streaming)...")
270
  DATA_QUEUE_MAX_SIZE = 2
271
  ohlcv_data_queue = asyncio.Queue(maxsize=DATA_QUEUE_MAX_SIZE)
272
  ml_results_list = []
@@ -283,43 +269,42 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
283
  try:
284
  batch_data = await queue.get()
285
  if batch_data is None:
286
- queue.task_done() # (هام: استدعاء task_done() للـ None)
287
  break
288
  batch_num += 1
289
- # (سيتم تمرير whale_data_store الفارغ، وهذا صحيح)
290
  batch_results_dict = await process_batch_parallel(
291
  batch_data, ml_processor, batch_num, total_batches, whale_data_store
292
  )
293
  results_list.append(batch_results_dict)
294
- queue.task_done() # (هام: استدعاء task_done() للدفعة)
295
  except Exception as e:
296
  print(f"❌ [ML Consumer] Fatal Error: {e}");
297
  traceback.print_exc();
298
- queue.task_done() # (هام: استدعاء task_done() عند الخطأ)
299
 
300
  consumer_task = asyncio.create_task(ml_consumer_task(ohlcv_data_queue, ml_results_list, preloaded_whale_data_dict))
301
- producer_task = asyncio.create_task(data_manager_global.stream_ohlcv_data(layer1_symbols, ohlcv_data_queue))
302
 
303
- # (إصلاح الـ Deadlock)
304
- await producer_task; # (انتظار انتهاء المنتج - المنتج يرسل None بنفسه)
 
 
305
 
306
- # (تم حذف السطر المسبب للجمود)
307
-
308
- await ohlcv_data_queue.join() # (انتظار المستهلك لإنهاء جميع المهام)
309
- await consumer_task; # (التأكد من أن مهمة المستهلك قد خرجت)
310
-
311
- # (تم حذف كتلة 'asyncio.wait_for(whale_fetcher_task, ...)' بالكامل من هنا)
312
 
313
  print("🔄 Aggregating all ML (Layer 1.3) results...")
314
  for batch_result in ml_results_list:
315
  for success_item in batch_result['success']:
316
  symbol = success_item['symbol']
317
- l1_data = next((c for c in layer1_candidates if c['symbol'] == symbol), None)
 
 
 
318
  if l1_data:
319
- success_item['reasons_for_candidacy'] = l1_data.get('reasons', [])
320
  success_item['layer1_score'] = l1_data.get('layer1_score', 0)
321
 
322
- # (لم نعد نضيف بيانات الحيتان هنا)
323
  success_item['whale_data'] = {'data_available': False, 'reason': 'Not fetched yet'}
324
 
325
  layer2_candidates.append(success_item)
@@ -330,7 +315,6 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
330
  target_count = min(10, len(layer2_candidates))
331
  final_layer2_candidates = layer2_candidates[:target_count]
332
 
333
- # (المنطق الجديد: جلب بيانات الحيتان فقط لأفضل 10)
334
  print(f"\n🐋 Layer 1.3 (Optimized): Fetching whale data for top {len(final_layer2_candidates)} candidates...")
335
 
336
  whale_tasks = []
@@ -338,7 +322,6 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
338
  """دالة مساعدة لجلب وتحديث بيانات الحيتان للمرشح"""
339
  symbol = candidate.get('symbol', 'UNKNOWN')
340
  try:
341
- # (هذا الاستدعاء هو الآن محدود بـ 10 طلبات فقط)
342
  data = await data_manager_global.get_whale_data_for_symbol(symbol)
343
  if data:
344
  candidate['whale_data'] = data
@@ -348,25 +331,20 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
348
  print(f" ❌ [Whale Fetch] {symbol} - Error: {e}")
349
  candidate['whale_data'] = {'data_available': False, 'error': str(e)}
350
 
351
- # إنشاء المهام
352
  for candidate in final_layer2_candidates:
353
  whale_tasks.append(asyncio.create_task(get_whale_data_for_candidate(candidate)))
354
 
355
- # انتظار اكتمال جلب بيانات الحيتان (سيكون هذا سريعاً جداً الآن)
356
  await asyncio.gather(*whale_tasks)
357
  print(" ✅ Whale data fetched for top candidates.")
358
 
359
- # (المنطق الجديد: إعادة حساب النقاط وإعادة الفرز)
360
  print(" 🔄 Re-calculating enhanced scores with new whale data...")
361
  for candidate in final_layer2_candidates:
362
  try:
363
- # (استدعاء دالة حساب النقاط من processor لتحديث النتيجة)
364
  new_score = ml_processor._calculate_enhanced_final_score(candidate)
365
  candidate['enhanced_final_score'] = new_score
366
  except Exception as e:
367
  print(f" ❌ [Score Recalc] {candidate.get('symbol')} - Error: {e}")
368
 
369
- # (إعادة الفرز بناءً على النقاط الجديدة والكاملة)
370
  final_layer2_candidates.sort(key=lambda x: x.get('enhanced_final_score', 0), reverse=True)
371
  print(" ✅ Top 10 scores updated and re-sorted.")
372
 
@@ -392,34 +370,28 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
392
  candidate['advanced_mc_run'] = False
393
  updated_candidates_for_llm.append(candidate)
394
 
395
- # 🔴 --- START OF CHANGE (FIX JSON BUG) --- 🔴
396
- # (تعقيم القائمة *قبل* إرسالها إلى R2 أو LLM)
397
  print(" 🔄 Sanitizing final candidates for JSON serialization...")
398
  sanitized_candidates = []
399
  for cand in updated_candidates_for_llm:
400
  sanitized_candidates.append(_sanitize_results_for_json(cand))
401
 
402
  final_layer2_candidates = sanitized_candidates
403
- # 🔴 --- END OF CHANGE (FIX JSON BUG) --- 🔴
404
-
405
- # (الآن هذا الاستدعاء آمن ولن يفشل)
406
  await r2_service_global.save_candidates_async(final_layer2_candidates)
407
 
408
  print("\n🧠 Layer 1.5: LLM Strategic Analysis (Explorer Brain)...")
409
  for candidate in final_layer2_candidates:
410
  try:
411
  symbol = candidate['symbol']
412
- ohlcv_data = candidate.get('ohlcv'); # (لا يزال موجوداً حتى بعد التعقيم كـ list)
413
  if not ohlcv_data: continue
414
 
415
- # (نمرر البيانات الخام المعقمة)
416
  candidate['raw_ohlcv'] = ohlcv_data
417
  total_candles = sum(len(data) for data in ohlcv_data.values()) if ohlcv_data else 0
418
  if total_candles < 30: continue
419
 
420
  candidate['sentiment_data'] = await data_manager_global.get_market_context_async()
421
 
422
- # (الآن، 'candidate' تحتوي على بيانات الحيتان + وهي معقمة JSON)
423
  llm_analysis = await llm_service_global.get_trading_decision(candidate)
424
 
425
  if llm_analysis and llm_analysis.get('action') in ['WATCH']:
@@ -434,7 +406,7 @@ async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
434
  'analysis_timestamp': datetime.now().isoformat(),
435
  'llm_decision_context': {
436
  'decision': llm_analysis,
437
- 'full_candidate_data': candidate # (هذه آمنة الآن)
438
  }
439
  }
440
  watchlist_candidates.append(watchlist_entry)
@@ -469,7 +441,13 @@ async def re_analyze_open_trade_async(trade_data):
469
  market_context = await data_manager_global.get_market_context_async()
470
  ohlcv_data_list = []
471
  temp_queue = asyncio.Queue()
472
- await data_manager_global.stream_ohlcv_data([symbol], temp_queue)
 
 
 
 
 
 
473
  while True:
474
  try:
475
  batch = await asyncio.wait_for(temp_queue.get(), timeout=1.0)
@@ -483,8 +461,9 @@ async def re_analyze_open_trade_async(trade_data):
483
  if not ohlcv_data_list: print(f"⚠️ Failed to get re-analysis data for {symbol}"); return None
484
  ohlcv_data = ohlcv_data_list[0]
485
 
486
- l1_data = await data_manager_global._get_detailed_symbol_data(symbol)
487
- if l1_data: ohlcv_data.update(l1_data); ohlcv_data['reasons_for_candidacy'] = ['re-analysis']
 
488
 
489
  re_analysis_whale_data = await data_manager_global.get_whale_data_for_symbol(symbol)
490
 
@@ -610,7 +589,7 @@ async def lifespan(application: FastAPI):
610
  await cleanup_on_shutdown()
611
 
612
 
613
- application = FastAPI(lifespan=lifespan, title="AI Trading Bot", description="Explorer-Sentry-Executor Architecture (V5.2)", version="5.2.0")
614
 
615
  @application.get("/")
616
  async def root(): return {"message": "Welcome to the AI Trading System", "system": "Explorer-Sentry-Executor", "status": "running" if state_manager.initialization_complete else "initializing", "timestamp": datetime.now().isoformat()}
@@ -622,7 +601,7 @@ async def run_cycle_api():
622
  return {"message": "Explorer (Layer 1) cycle initiated", "system": "Explorer-Sentry-Executor"}
623
 
624
  @application.get("/health")
625
- async def health_check(): return {"status": "healthy" if state_manager.initialization_complete else "initializing", "initialization_complete": state_manager.initialization_complete, "services_initialized": state_manager.services_initialized, "initialization_error": state_manager.initialization_error, "timestamp": datetime.now().isoformat(), "system_architecture": "Explorer-Sentry-Executor (V5.2)"}
626
 
627
  @application.get("/analyze-market")
628
  async def analyze_market_api():
@@ -641,7 +620,6 @@ async def get_portfolio_api():
641
  async def get_system_status():
642
  monitoring_status = trade_manager_global.get_sentry_status() if trade_manager_global else {};
643
 
644
- # (يستخدم المتغير المحلي بدلاً من state.MARKET_STATE_OK - إصلاح سابق)
645
  return {"initialization_complete": state_manager.initialization_complete, "services_initialized": state_manager.services_initialized, "initialization_error": state_manager.initialization_error, "market_state_ok": MARKET_STATE_OK, "sentry_status": monitoring_status, "timestamp": datetime.now().isoformat()}
646
 
647
  async def cleanup_on_shutdown():
@@ -659,7 +637,6 @@ async def cleanup_on_shutdown():
659
  print("✅ Learning hub data saved")
660
  except Exception as e: print(f"❌ Failed to save learning hub data: {e}")
661
 
662
- # (إضافة إغلاق لخدمة الحيتان)
663
  if symbol_whale_monitor_global:
664
  try:
665
  await symbol_whale_monitor_global.cleanup()
@@ -677,5 +654,5 @@ def signal_handler(signum, frame): print(f"🛑 Received signal {signum}. Initia
677
  signal.signal(signal.SIGINT, signal_handler); signal.signal(signal.SIGTERM, signal_handler)
678
 
679
  if __name__ == "__main__":
680
- print("🚀 Starting AI Trading Bot (Explorer-Sentry-Executor V5.2)...")
681
  uvicorn.run( application, host="0.0.0.0", port=7860, log_level="info", access_log=True )
 
1
+ # app.py (Fully updated to Explorer-Sentry-Executor architecture V5.3 - Fixed Producer Task)
2
  import os
3
  import traceback
4
  import signal
 
10
  from contextlib import asynccontextmanager
11
  from fastapi import FastAPI, HTTPException
12
  from datetime import datetime
13
+ from typing import List, Dict, Any
14
 
 
15
  try:
16
  from r2 import R2Service
17
  from LLM import LLMService
 
19
  from ml_engine.processor import MLProcessor
20
  from learning_hub.hub_manager import LearningHubManager
21
  from sentiment_news import SentimentAnalyzer
22
+ from trade_manager import TradeManager
 
 
 
23
  from ml_engine.monte_carlo import _sanitize_results_for_json
 
24
 
25
  from helpers import safe_float_conversion, validate_candidate_data_enhanced
26
  except ImportError as e:
 
38
  sentiment_analyzer_global = None
39
  symbol_whale_monitor_global = None
40
 
 
41
  MARKET_STATE_OK = True
42
 
43
 
 
44
  class StateManager:
45
  def __init__(self):
46
  self.market_analysis_lock = asyncio.Lock()
 
71
  self.initialization_error = error
72
  print(f"❌ خطأ في التهيئة: {error}")
73
 
 
74
  state_manager = StateManager()
75
 
76
  async def initialize_services():
 
79
  global learning_hub_global, trade_manager_global, sentiment_analyzer_global
80
  global symbol_whale_monitor_global
81
  try:
82
+ print("🚀 بدء تهيئة الخدمات (بنية Sentry الجديدة V5.3)...")
83
  print(" 🔄 تهيئة R2Service..."); r2_service_global = R2Service(); state_manager.set_service_initialized('r2_service'); print(" ✅ R2Service مهيأة")
84
  print(" 🔄 جلب قاعدة بيانات العقود..."); contracts_database = await r2_service_global.load_contracts_db_async(); print(f" ✅ تم تحميل {len(contracts_database)} عقد")
85
 
86
  print(" 🔄 تهيئة مراقب الحيتان (Layer 1 Data)...");
87
  try:
 
88
  from whale_monitor.core import EnhancedWhaleMonitor
89
 
90
  symbol_whale_monitor_global = EnhancedWhaleMonitor(contracts_database, r2_service_global)
91
  state_manager.set_service_initialized('symbol_whale_monitor'); print(" ✅ مراقب الحيتان مهيأ")
92
 
 
93
  except Exception as e:
94
  print(f" ⚠️ فشل تهيئة مراقب الحيتان: {e}");
95
+ traceback.print_exc()
96
  symbol_whale_monitor_global = None
 
97
  state_manager.set_service_initialized('symbol_whale_monitor');
98
  print(" ℹ️ مراقبة الحيتان معطلة. استمرار التهيئة...")
99
 
 
127
  r2_service=r2_service_global,
128
  learning_hub=learning_hub_global,
129
  data_manager=data_manager_global,
130
+ state_manager=state_manager
131
  )
132
  await trade_manager_global.initialize_sentry_exchanges()
133
  state_manager.set_service_initialized('trade_manager');
 
163
  await asyncio.sleep(60)
164
  except Exception as error:
165
  print(f"❌ خطأ أثناء مراقبة السوق: {error}");
166
+ MARKET_STATE_OK = True;
167
  await asyncio.sleep(60)
168
  except Exception as e: print(f"❌ فشل تشغيل مراقبة السوق: {e}")
169
 
 
189
 
190
  async def process_batch_parallel(batch, ml_processor, batch_num, total_batches, preloaded_whale_data):
191
  """(لا تغيير) معالج الدفعات لـ Layer 1"""
 
192
  try:
193
  batch_tasks = []
194
  for symbol_data in batch:
 
228
 
229
  async def run_3_layer_analysis_explorer() -> List[Dict[str, Any]]:
230
  """
231
+ (معدل V5.3) - هذا هو "المستكشف" (Layer 1).
 
232
  """
 
233
  layer1_candidates = []
234
  layer2_candidates = []
235
  final_layer2_candidates = []
236
  watchlist_candidates = []
237
 
238
+ preloaded_whale_data_dict = {}
 
239
 
240
  try:
241
  print("🎯 Starting Explorer Analysis (Layer 1)...")
 
243
  if not await state_manager.wait_for_initialization():
244
  print("❌ Services not fully initialized (Explorer)"); return []
245
 
246
+ print("\n🔍 Layer 1.1: Rapid Screening (data_manager V7.1)...")
247
+ # (هذه الآن ترجع قائمة المرشحين الناجحين من الغربلة الذكية)
248
  layer1_candidates = await data_manager_global.layer1_rapid_screening()
249
  if not layer1_candidates: print("❌ No candidates found in Layer 1.1"); return []
250
  print(f"✅ Selected {len(layer1_candidates)} symbols for Layer 1.2")
251
+
252
+ # (لم نعد بحاجة إلى layer1_symbols)
253
+ # layer1_symbols = [c['symbol'] for c in layer1_candidates]
254
 
255
+ print(f"\n📊 Layer 1.2: Fetching OHLCV data for {len(layer1_candidates)} symbols (Streaming)...")
256
  DATA_QUEUE_MAX_SIZE = 2
257
  ohlcv_data_queue = asyncio.Queue(maxsize=DATA_QUEUE_MAX_SIZE)
258
  ml_results_list = []
 
269
  try:
270
  batch_data = await queue.get()
271
  if batch_data is None:
272
+ queue.task_done()
273
  break
274
  batch_num += 1
 
275
  batch_results_dict = await process_batch_parallel(
276
  batch_data, ml_processor, batch_num, total_batches, whale_data_store
277
  )
278
  results_list.append(batch_results_dict)
279
+ queue.task_done()
280
  except Exception as e:
281
  print(f"❌ [ML Consumer] Fatal Error: {e}");
282
  traceback.print_exc();
283
+ queue.task_done()
284
 
285
  consumer_task = asyncio.create_task(ml_consumer_task(ohlcv_data_queue, ml_results_list, preloaded_whale_data_dict))
 
286
 
287
+ # 🔴 --- START OF CHANGE (V5.3 - FIX) --- 🔴
288
+ # (تمرير layer1_candidates (List[Dict]) بدلاً من layer1_symbols (List[str]))
289
+ producer_task = asyncio.create_task(data_manager_global.stream_ohlcv_data(layer1_candidates, ohlcv_data_queue))
290
+ # 🔴 --- END OF CHANGE --- 🔴
291
 
292
+ await producer_task;
293
+ await ohlcv_data_queue.join()
294
+ await consumer_task;
 
 
 
295
 
296
  print("🔄 Aggregating all ML (Layer 1.3) results...")
297
  for batch_result in ml_results_list:
298
  for success_item in batch_result['success']:
299
  symbol = success_item['symbol']
300
+
301
+ # (البيانات الأولية موجودة الآن في success_item)
302
+ l1_data = success_item
303
+
304
  if l1_data:
305
+ success_item['reasons_for_candidacy'] = l1_data.get('reasons_for_candidacy', [])
306
  success_item['layer1_score'] = l1_data.get('layer1_score', 0)
307
 
 
308
  success_item['whale_data'] = {'data_available': False, 'reason': 'Not fetched yet'}
309
 
310
  layer2_candidates.append(success_item)
 
315
  target_count = min(10, len(layer2_candidates))
316
  final_layer2_candidates = layer2_candidates[:target_count]
317
 
 
318
  print(f"\n🐋 Layer 1.3 (Optimized): Fetching whale data for top {len(final_layer2_candidates)} candidates...")
319
 
320
  whale_tasks = []
 
322
  """دالة مساعدة لجلب وتحديث بيانات الحيتان للمرشح"""
323
  symbol = candidate.get('symbol', 'UNKNOWN')
324
  try:
 
325
  data = await data_manager_global.get_whale_data_for_symbol(symbol)
326
  if data:
327
  candidate['whale_data'] = data
 
331
  print(f" ❌ [Whale Fetch] {symbol} - Error: {e}")
332
  candidate['whale_data'] = {'data_available': False, 'error': str(e)}
333
 
 
334
  for candidate in final_layer2_candidates:
335
  whale_tasks.append(asyncio.create_task(get_whale_data_for_candidate(candidate)))
336
 
 
337
  await asyncio.gather(*whale_tasks)
338
  print(" ✅ Whale data fetched for top candidates.")
339
 
 
340
  print(" 🔄 Re-calculating enhanced scores with new whale data...")
341
  for candidate in final_layer2_candidates:
342
  try:
 
343
  new_score = ml_processor._calculate_enhanced_final_score(candidate)
344
  candidate['enhanced_final_score'] = new_score
345
  except Exception as e:
346
  print(f" ❌ [Score Recalc] {candidate.get('symbol')} - Error: {e}")
347
 
 
348
  final_layer2_candidates.sort(key=lambda x: x.get('enhanced_final_score', 0), reverse=True)
349
  print(" ✅ Top 10 scores updated and re-sorted.")
350
 
 
370
  candidate['advanced_mc_run'] = False
371
  updated_candidates_for_llm.append(candidate)
372
 
 
 
373
  print(" 🔄 Sanitizing final candidates for JSON serialization...")
374
  sanitized_candidates = []
375
  for cand in updated_candidates_for_llm:
376
  sanitized_candidates.append(_sanitize_results_for_json(cand))
377
 
378
  final_layer2_candidates = sanitized_candidates
379
+
 
 
380
  await r2_service_global.save_candidates_async(final_layer2_candidates)
381
 
382
  print("\n🧠 Layer 1.5: LLM Strategic Analysis (Explorer Brain)...")
383
  for candidate in final_layer2_candidates:
384
  try:
385
  symbol = candidate['symbol']
386
+ ohlcv_data = candidate.get('ohlcv');
387
  if not ohlcv_data: continue
388
 
 
389
  candidate['raw_ohlcv'] = ohlcv_data
390
  total_candles = sum(len(data) for data in ohlcv_data.values()) if ohlcv_data else 0
391
  if total_candles < 30: continue
392
 
393
  candidate['sentiment_data'] = await data_manager_global.get_market_context_async()
394
 
 
395
  llm_analysis = await llm_service_global.get_trading_decision(candidate)
396
 
397
  if llm_analysis and llm_analysis.get('action') in ['WATCH']:
 
406
  'analysis_timestamp': datetime.now().isoformat(),
407
  'llm_decision_context': {
408
  'decision': llm_analysis,
409
+ 'full_candidate_data': candidate
410
  }
411
  }
412
  watchlist_candidates.append(watchlist_entry)
 
441
  market_context = await data_manager_global.get_market_context_async()
442
  ohlcv_data_list = []
443
  temp_queue = asyncio.Queue()
444
+
445
+ # (إصلاح هنا أيضاً: تمرير قائمة Dict)
446
+ await data_manager_global.stream_ohlcv_data(
447
+ [{'symbol': symbol, 'layer1_score': 0, 'reasons': ['re-analysis']}],
448
+ temp_queue
449
+ )
450
+
451
  while True:
452
  try:
453
  batch = await asyncio.wait_for(temp_queue.get(), timeout=1.0)
 
461
  if not ohlcv_data_list: print(f"⚠️ Failed to get re-analysis data for {symbol}"); return None
462
  ohlcv_data = ohlcv_data_list[0]
463
 
464
+ # (لم نعد بحاجة لهذا، البيانات مدمجة)
465
+ # l1_data = await data_manager_global._get_detailed_symbol_data(symbol)
466
+ # if l1_data: ohlcv_data.update(l1_data); ohlcv_data['reasons_for_candidacy'] = ['re-analysis']
467
 
468
  re_analysis_whale_data = await data_manager_global.get_whale_data_for_symbol(symbol)
469
 
 
589
  await cleanup_on_shutdown()
590
 
591
 
592
+ application = FastAPI(lifespan=lifespan, title="AI Trading Bot", description="Explorer-Sentry-Executor Architecture (V5.3)", version="5.3.0")
593
 
594
  @application.get("/")
595
  async def root(): return {"message": "Welcome to the AI Trading System", "system": "Explorer-Sentry-Executor", "status": "running" if state_manager.initialization_complete else "initializing", "timestamp": datetime.now().isoformat()}
 
601
  return {"message": "Explorer (Layer 1) cycle initiated", "system": "Explorer-Sentry-Executor"}
602
 
603
  @application.get("/health")
604
+ async def health_check(): return {"status": "healthy" if state_manager.initialization_complete else "initializing", "initialization_complete": state_manager.initialization_complete, "services_initialized": state_manager.services_initialized, "initialization_error": state_manager.initialization_error, "timestamp": datetime.now().isoformat(), "system_architecture": "Explorer-Sentry-Executor (V5.3)"}
605
 
606
  @application.get("/analyze-market")
607
  async def analyze_market_api():
 
620
  async def get_system_status():
621
  monitoring_status = trade_manager_global.get_sentry_status() if trade_manager_global else {};
622
 
 
623
  return {"initialization_complete": state_manager.initialization_complete, "services_initialized": state_manager.services_initialized, "initialization_error": state_manager.initialization_error, "market_state_ok": MARKET_STATE_OK, "sentry_status": monitoring_status, "timestamp": datetime.now().isoformat()}
624
 
625
  async def cleanup_on_shutdown():
 
637
  print("✅ Learning hub data saved")
638
  except Exception as e: print(f"❌ Failed to save learning hub data: {e}")
639
 
 
640
  if symbol_whale_monitor_global:
641
  try:
642
  await symbol_whale_monitor_global.cleanup()
 
654
  signal.signal(signal.SIGINT, signal_handler); signal.signal(signal.SIGTERM, signal_handler)
655
 
656
  if __name__ == "__main__":
657
+ print("🚀 Starting AI Trading Bot (Explorer-Sentry-Executor V5.3)...")
658
  uvicorn.run( application, host="0.0.0.0", port=7860, log_level="info", access_log=True )