Riy777 commited on
Commit
3cdd892
·
1 Parent(s): 1cd9326

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -46
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # app.py (محدث)
2
  import os
3
  import traceback
4
  import signal
@@ -26,8 +26,7 @@ except ImportError as e:
26
  print(f"❌ خطأ في استيراد الوحدات: {e}")
27
  sys.exit(1)
28
 
29
- # (المتغيرات العالمية و StateManager كما هي)
30
- # ...
31
  r2_service_global = None
32
  data_manager_global = None
33
  llm_service_global = None
@@ -68,8 +67,6 @@ class StateManager:
68
 
69
  state_manager = StateManager()
70
 
71
- # (initialize_services و monitor_market_async كما هي)
72
- # ...
73
  async def initialize_services():
74
  """تهيئة جميع الخدمات بشكل منفصل"""
75
  global r2_service_global, data_manager_global, llm_service_global
@@ -116,8 +113,6 @@ async def monitor_market_async():
116
  except Exception as e: print(f"❌ فشل تشغيل مراقبة السوق: {e}")
117
 
118
 
119
- # 🔴 --- تعديل: إزالة Semaphore من هنا --- 🔴
120
- # منظم السرعة الآن داخل مهمة جلب الحيتان ومهمة معالجة ML
121
  async def process_batch_parallel(batch, ml_processor, batch_num, total_batches, preloaded_whale_data):
122
  """
123
  (معدلة) معالجة دفعة من الرموز بشكل متوازي وإرجاع نتائج مفصلة
@@ -173,8 +168,6 @@ async def process_batch_parallel(batch, ml_processor, batch_num, total_batches,
173
  return {'success': [], 'low_score': [], 'failures': []}
174
 
175
 
176
- # 🔴 --- بدء التعديل الجوهري --- 🔴
177
- # تم إعادة هيكلة هذه الدالة بالكامل
178
  async def run_3_layer_analysis():
179
  """
180
  (معدلة) تشغيل النظام الطبقي (مع فصل جلب بيانات الحيتان)
@@ -210,8 +203,7 @@ async def run_3_layer_analysis():
210
 
211
  # مهمة جلب بيانات الحيتان
212
  async def fetch_whale_data_task(symbols, results_dict):
213
- # استخدام منظم سرعة خاص لهذه المهمة (يمكن تعديل القيمة حسب الحاجة)
214
- WHALE_FETCH_CONCURRENCY = 3 # عدد طلبات الحيتان المتزامنة
215
  semaphore = asyncio.Semaphore(WHALE_FETCH_CONCURRENCY)
216
  tasks = []
217
 
@@ -221,18 +213,16 @@ async def run_3_layer_analysis():
221
  data = await data_manager_global.get_whale_data_for_symbol(symbol)
222
  if data:
223
  results_dict[symbol] = data
224
- # else: # Optional: Log if data is None
225
- # print(f" ⚠️ [Whale Fetch] No whale data returned for {symbol}")
226
  except Exception as e:
227
  print(f" ❌ [Whale Fetch] فشل جلب بيانات الحيتان لـ {symbol}: {e}")
228
- results_dict[symbol] = {'data_available': False, 'error': str(e)} # Store error
229
 
230
  for symbol in symbols:
231
  tasks.append(asyncio.create_task(get_data_with_semaphore(symbol)))
232
 
233
- await asyncio.gather(*tasks) # انتظار اكتمال جميع مهام جلب الحيتان
234
 
235
- # تشغيل مهمة جلب الحيتان في الخلفية (لا ننتظرها هنا)
236
  whale_fetcher_task = asyncio.create_task(fetch_whale_data_task(layer1_symbols, preloaded_whale_data_dict))
237
  print(" ⏳ مهمة جلب بيانات الحيتان تعمل في الخلفية...")
238
  # 🔴 --- نهاية الطبقة 1.5 --- 🔴
@@ -301,7 +291,6 @@ async def run_3_layer_analysis():
301
 
302
  # 9. تجميع النتائج (كما كان، لكن بيانات الحيتان موجودة الآن)
303
  print("🔄 تجميع جميع النتائج...")
304
- # ... (الكود لتجميع layer2_candidates, all_low_score_candidates, all_failed_candidates كما هو) ...
305
  for batch_result in ml_results_list:
306
  for success_item in batch_result['success']:
307
  symbol = success_item['symbol']
@@ -309,16 +298,14 @@ async def run_3_layer_analysis():
309
  if l1_data:
310
  success_item['reasons_for_candidacy'] = l1_data.get('reasons', [])
311
  success_item['layer1_score'] = l1_data.get('layer1_score', 0)
312
- # Ensure whale data from preloading is in the final result item
313
  if symbol in preloaded_whale_data_dict:
314
  success_item['whale_data'] = preloaded_whale_data_dict[symbol]
315
- elif 'whale_data' not in success_item: # If ML processor didn't add a default
316
  success_item['whale_data'] = {'data_available': False, 'reason': 'Failed during preload'}
317
  layer2_candidates.append(success_item)
318
  all_low_score_candidates.extend(batch_result['low_score'])
319
  all_failed_candidates.extend(batch_result['failures'])
320
 
321
-
322
  print(f"✅ اكتمل التحليل المتقدم: {len(layer2_candidates)} نجاح (عالي) | {len(all_low_score_candidates)} نجاح (منخفض) | {len(all_failed_candidates)} فشل")
323
 
324
  if not layer2_candidates: print("❌ لم يتم العثور على مرشحين في الطبقة 2")
@@ -330,7 +317,6 @@ async def run_3_layer_analysis():
330
  print(f"🎯 تم اختيار {len(final_layer2_candidates)} عملة للطبقة 3 (الأقوى فقط)")
331
  await r2_service_global.save_candidates_async(final_layer2_candidates)
332
  print("\n🏆 أفضل 10 عملات من الطبقة 2:")
333
- # ... (كود عرض أفضل 10 كما هو، سيشمل بيانات الحيتان الآن) ...
334
  for i, candidate in enumerate(final_layer2_candidates):
335
  score = candidate.get('enhanced_final_score', 0)
336
  strategy = candidate.get('target_strategy', 'GENERIC')
@@ -348,13 +334,9 @@ async def run_3_layer_analysis():
348
  print(f" 🐋 حيتان: {signal.get('action', 'HOLD')} (ثقة: {signal.get('confidence', 0):.2f}){' ⚠️' if signal.get('critical_alert') else ''}")
349
  elif whale_data and whale_data.get('error'):
350
  print(f" 🐋 حيتان: خطأ ({whale_data.get('error')[:50]}...)")
351
- # else:
352
- # print(f" 🐋 حيتان: غير متاحة")
353
-
354
 
355
  # 11. الطبقة 3: التحليل بالنموذج الضخم (كما كان)
356
  print("\n🧠 الطبقة 3: التحليل بالنموذج الضخم (LLMService)...")
357
- # ... (كود الطبقة 3 كما هو) ...
358
  for candidate in final_layer2_candidates:
359
  try:
360
  symbol = candidate['symbol']
@@ -383,7 +365,6 @@ async def run_3_layer_analysis():
383
  print(f" ⚠️ {symbol}: لا يوجد قرار تداول من النموذج الضخم ({action})")
384
  except Exception as e: print(f"❌ خطأ في تحليل النموذج الضخم لـ {candidate.get('symbol')}: {e}"); continue
385
 
386
-
387
  if final_opportunities:
388
  final_opportunities.sort(key=lambda x: (x['llm_confidence'] + x['enhanced_score']) / 2, reverse=True)
389
  print(f"\n🏆 النظام الطبقي اكتمل: {len(final_opportunities)} فرصة تداول")
@@ -392,7 +373,6 @@ async def run_3_layer_analysis():
392
 
393
  # 12. سجل التدقيق (كما كان)
394
  try:
395
- # ... (كود سجل التدقيق كما هو، سيستخدم البيانات المجمعة الآن) ...
396
  top_10_detailed_summary = []
397
  for c in final_layer2_candidates:
398
  whale_summary = "Not Available"
@@ -437,10 +417,7 @@ async def run_3_layer_analysis():
437
  print("⚠️ تم حفظ سجل تدقيق جزئي بعد الفشل.")
438
  except Exception as audit_fail_error: print(f"❌ فشل حفظ سجل التدقيق أثناء معالجة خطأ آخر: {audit_fail_error}")
439
  return None
440
- # 🔴 --- نهاية التعديل الجوهري --- 🔴
441
 
442
- # (بقية الملف: re_analyze_open_trade_async, run_bot_cycle_async, lifespan, endpoints, cleanup, etc. كما هي)
443
- # ...
444
  async def re_analyze_open_trade_async(trade_data):
445
  """إعادة تحليل الصفقة المفتوحة"""
446
  symbol = trade_data.get('symbol')
@@ -450,21 +427,31 @@ async def re_analyze_open_trade_async(trade_data):
450
  ohlcv_data_list = []
451
  temp_queue = asyncio.Queue()
452
  await data_manager_global.stream_ohlcv_data([symbol], temp_queue)
453
- while not temp_queue.empty():
454
- batch = await temp_queue.get(); temp_queue.task_done() # Need task_done here too
455
- if batch: ohlcv_data_list.extend(batch)
456
-
 
 
 
 
 
 
 
 
 
 
 
 
457
  if not ohlcv_data_list: print(f"⚠️ فشل جلب بيانات إعادة التحليل لـ {symbol}"); return None
458
  ohlcv_data = ohlcv_data_list[0]
459
 
460
  l1_data = await data_manager_global._get_detailed_symbol_data(symbol)
461
  if l1_data: ohlcv_data.update(l1_data); ohlcv_data['reasons_for_candidacy'] = ['re-analysis']
462
 
463
- # 🔴 جلب بيانات الحيتان بشكل منفصل لإعادة التحليل
464
  re_analysis_whale_data = await data_manager_global.get_whale_data_for_symbol(symbol)
465
 
466
  ml_processor = MLProcessor(market_context, data_manager_global, learning_engine_global)
467
- # 🔴 تمرير بيانات الحيتان للمعالج
468
  processed_data = await ml_processor.process_and_score_symbol_enhanced(ohlcv_data, {symbol: re_analysis_whale_data} if re_analysis_whale_data else {})
469
 
470
  if not processed_data: return None
@@ -478,7 +465,8 @@ async def re_analyze_open_trade_async(trade_data):
478
  await r2_service_global.save_system_logs_async({ "trade_reanalyzed": True, "symbol": symbol, "action": re_analysis_decision.get('action'), 'strategy': re_analysis_decision.get('strategy', 'GENERIC') })
479
  return {"symbol": symbol, "decision": re_analysis_decision, "current_price": processed_data.get('current_price')}
480
  else: return None
481
- except Exception as error: await r2_service_global.save_system_logs_async({ "reanalysis_error": True, "symbol": symbol, "error": str(error) }); return None
 
482
 
483
  async def run_bot_cycle_async():
484
  """دورة التداول الرئيسية"""
@@ -486,6 +474,8 @@ async def run_bot_cycle_async():
486
  if not await state_manager.wait_for_initialization(): print("❌ الخدمات غير مهيأة بالكامل - تخطي الدورة"); return
487
  print("🔄 بدء دورة التداول..."); await r2_service_global.save_system_logs_async({"cycle_started": True})
488
  if not r2_service_global.acquire_lock(): print("❌ فشل الحصول على القفل - تخطي الدورة"); return
 
 
489
  try:
490
  open_trades = await trade_manager_global.get_open_trades(); print(f"📋 الصفقات المفتوحة: {len(open_trades)}")
491
  should_look_for_new_trade = len(open_trades) == 0
@@ -494,10 +484,29 @@ async def run_bot_cycle_async():
494
  trades_to_reanalyze = [t for t in open_trades if now >= datetime.fromisoformat(t.get('expected_target_time', now.isoformat()))]
495
  if trades_to_reanalyze:
496
  print(f"🔄 إعادة تحليل {len(trades_to_reanalyze)} صفقة")
497
- for trade in trades_to_reanalyze:
498
- result = await re_analyze_open_trade_async(trade)
499
- if result and result['decision'].get('action') == "CLOSE_TRADE": await trade_manager_global.close_trade(trade, result['current_price'], 'CLOSED_BY_REANALYSIS'); should_look_for_new_trade = True
500
- elif result and result['decision'].get('action') == "UPDATE_TRADE": await trade_manager_global.update_trade(trade, result['decision'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
501
  if should_look_for_new_trade:
502
  portfolio_state = await r2_service_global.get_portfolio_state_async(); current_capital = portfolio_state.get("current_capital_usd", 0)
503
  if current_capital > 1:
@@ -506,10 +515,18 @@ async def run_bot_cycle_async():
506
  if best_opportunity: print(f"✅ فتح صفقة جديدة: {best_opportunity['symbol']}"); await trade_manager_global.open_trade( best_opportunity['symbol'], best_opportunity['decision'], best_opportunity['current_price'])
507
  else: print("❌ لم يتم العثور على فرص تداول مناسبة")
508
  else: print("❌ رأس المال غير كافي لفتح صفقات جديدة")
 
 
 
509
  finally:
510
- r2_service_global.release_lock(); await r2_service_global.save_system_logs_async({ "cycle_completed": True, "open_trades": len(open_trades) if 'open_trades' in locals() else 0 }); print("✅ اكتملت دورة التداول")
 
 
 
 
511
  except Exception as error:
512
- print(f"❌ Unhandled error in main cycle: {error}"); await r2_service_global.save_system_logs_async({ "cycle_error": True, "error": str(error) });
 
513
  if r2_service_global and r2_service_global.lock_acquired: r2_service_global.release_lock() # Ensure lock release on error
514
 
515
  @asynccontextmanager
@@ -524,9 +541,20 @@ async def lifespan(application: FastAPI):
524
  await r2_service_global.save_system_logs_async({"application_started": True})
525
  print("🎯 التطبيق جاهز للعمل - نظام الطبقات 3 فعال (فصل الحيتان)")
526
  yield
527
- except Exception as error: print(f"❌ Application startup failed: {error}"); traceback.print_exc();
528
- if r2_service_global: await r2_service_global.save_system_logs_async({ "application_startup_failed": True, "error": str(error) }); raise
529
- finally: await cleanup_on_shutdown()
 
 
 
 
 
 
 
 
 
 
 
530
 
531
  application = FastAPI(lifespan=lifespan, title="AI Trading Bot", description="نظام تداول ذكي بثلاث طبقات تحليلية (فصل الحيتان)", version="3.2.0")
532
 
 
1
+ # app.py (محدث بإصلاح IndentationError)
2
  import os
3
  import traceback
4
  import signal
 
26
  print(f"❌ خطأ في استيراد الوحدات: {e}")
27
  sys.exit(1)
28
 
29
+ # المتغيرات العالمية
 
30
  r2_service_global = None
31
  data_manager_global = None
32
  llm_service_global = None
 
67
 
68
  state_manager = StateManager()
69
 
 
 
70
  async def initialize_services():
71
  """تهيئة جميع الخدمات بشكل منفصل"""
72
  global r2_service_global, data_manager_global, llm_service_global
 
113
  except Exception as e: print(f"❌ فشل تشغيل مراقبة السوق: {e}")
114
 
115
 
 
 
116
  async def process_batch_parallel(batch, ml_processor, batch_num, total_batches, preloaded_whale_data):
117
  """
118
  (معدلة) معالجة دفعة من الرموز بشكل متوازي وإرجاع نتائج مفصلة
 
168
  return {'success': [], 'low_score': [], 'failures': []}
169
 
170
 
 
 
171
  async def run_3_layer_analysis():
172
  """
173
  (معدلة) تشغيل النظام الطبقي (مع فصل جلب بيانات الحيتان)
 
203
 
204
  # مهمة جلب بيانات الحيتان
205
  async def fetch_whale_data_task(symbols, results_dict):
206
+ WHALE_FETCH_CONCURRENCY = 3
 
207
  semaphore = asyncio.Semaphore(WHALE_FETCH_CONCURRENCY)
208
  tasks = []
209
 
 
213
  data = await data_manager_global.get_whale_data_for_symbol(symbol)
214
  if data:
215
  results_dict[symbol] = data
 
 
216
  except Exception as e:
217
  print(f" ❌ [Whale Fetch] فشل جلب بيانات الحيتان لـ {symbol}: {e}")
218
+ results_dict[symbol] = {'data_available': False, 'error': str(e)}
219
 
220
  for symbol in symbols:
221
  tasks.append(asyncio.create_task(get_data_with_semaphore(symbol)))
222
 
223
+ await asyncio.gather(*tasks)
224
 
225
+ # تشغيل مهمة جلب الحيتان في الخلفية
226
  whale_fetcher_task = asyncio.create_task(fetch_whale_data_task(layer1_symbols, preloaded_whale_data_dict))
227
  print(" ⏳ مهمة جلب بيانات الحيتان تعمل في الخلفية...")
228
  # 🔴 --- نهاية الطبقة 1.5 --- 🔴
 
291
 
292
  # 9. تجميع النتائج (كما كان، لكن بيانات الحيتان موجودة الآن)
293
  print("🔄 تجميع جميع النتائج...")
 
294
  for batch_result in ml_results_list:
295
  for success_item in batch_result['success']:
296
  symbol = success_item['symbol']
 
298
  if l1_data:
299
  success_item['reasons_for_candidacy'] = l1_data.get('reasons', [])
300
  success_item['layer1_score'] = l1_data.get('layer1_score', 0)
 
301
  if symbol in preloaded_whale_data_dict:
302
  success_item['whale_data'] = preloaded_whale_data_dict[symbol]
303
+ elif 'whale_data' not in success_item:
304
  success_item['whale_data'] = {'data_available': False, 'reason': 'Failed during preload'}
305
  layer2_candidates.append(success_item)
306
  all_low_score_candidates.extend(batch_result['low_score'])
307
  all_failed_candidates.extend(batch_result['failures'])
308
 
 
309
  print(f"✅ اكتمل التحليل المتقدم: {len(layer2_candidates)} نجاح (عالي) | {len(all_low_score_candidates)} نجاح (منخفض) | {len(all_failed_candidates)} فشل")
310
 
311
  if not layer2_candidates: print("❌ لم يتم العثور على مرشحين في الطبقة 2")
 
317
  print(f"🎯 تم اختيار {len(final_layer2_candidates)} عملة للطبقة 3 (الأقوى فقط)")
318
  await r2_service_global.save_candidates_async(final_layer2_candidates)
319
  print("\n🏆 أفضل 10 عملات من الطبقة 2:")
 
320
  for i, candidate in enumerate(final_layer2_candidates):
321
  score = candidate.get('enhanced_final_score', 0)
322
  strategy = candidate.get('target_strategy', 'GENERIC')
 
334
  print(f" 🐋 حيتان: {signal.get('action', 'HOLD')} (ثقة: {signal.get('confidence', 0):.2f}){' ⚠️' if signal.get('critical_alert') else ''}")
335
  elif whale_data and whale_data.get('error'):
336
  print(f" 🐋 حيتان: خطأ ({whale_data.get('error')[:50]}...)")
 
 
 
337
 
338
  # 11. الطبقة 3: التحليل بالنموذج الضخم (كما كان)
339
  print("\n🧠 الطبقة 3: التحليل بالنموذج الضخم (LLMService)...")
 
340
  for candidate in final_layer2_candidates:
341
  try:
342
  symbol = candidate['symbol']
 
365
  print(f" ⚠️ {symbol}: لا يوجد قرار تداول من النموذج الضخم ({action})")
366
  except Exception as e: print(f"❌ خطأ في تحليل النموذج الضخم لـ {candidate.get('symbol')}: {e}"); continue
367
 
 
368
  if final_opportunities:
369
  final_opportunities.sort(key=lambda x: (x['llm_confidence'] + x['enhanced_score']) / 2, reverse=True)
370
  print(f"\n🏆 النظام الطبقي اكتمل: {len(final_opportunities)} فرصة تداول")
 
373
 
374
  # 12. سجل التدقيق (كما كان)
375
  try:
 
376
  top_10_detailed_summary = []
377
  for c in final_layer2_candidates:
378
  whale_summary = "Not Available"
 
417
  print("⚠️ تم حفظ سجل تدقيق جزئي بعد الفشل.")
418
  except Exception as audit_fail_error: print(f"❌ فشل حفظ سجل التدقيق أثناء معالجة خطأ آخر: {audit_fail_error}")
419
  return None
 
420
 
 
 
421
  async def re_analyze_open_trade_async(trade_data):
422
  """إعادة تحليل الصفقة المفتوحة"""
423
  symbol = trade_data.get('symbol')
 
427
  ohlcv_data_list = []
428
  temp_queue = asyncio.Queue()
429
  await data_manager_global.stream_ohlcv_data([symbol], temp_queue)
430
+ # Correctly drain the queue
431
+ while True:
432
+ try:
433
+ batch = await asyncio.wait_for(temp_queue.get(), timeout=1.0) # Add timeout
434
+ if batch is None: # Check for sentinel
435
+ temp_queue.task_done()
436
+ break
437
+ ohlcv_data_list.extend(batch)
438
+ temp_queue.task_done()
439
+ except asyncio.TimeoutError:
440
+ # Queue might be empty or producer finished without sentinel
441
+ if temp_queue.empty(): break # Exit if empty after timeout
442
+ except Exception as q_err:
443
+ print(f"Error draining queue for re-analysis: {q_err}")
444
+ break # Exit on other errors
445
+
446
  if not ohlcv_data_list: print(f"⚠️ فشل جلب بيانات إعادة التحليل لـ {symbol}"); return None
447
  ohlcv_data = ohlcv_data_list[0]
448
 
449
  l1_data = await data_manager_global._get_detailed_symbol_data(symbol)
450
  if l1_data: ohlcv_data.update(l1_data); ohlcv_data['reasons_for_candidacy'] = ['re-analysis']
451
 
 
452
  re_analysis_whale_data = await data_manager_global.get_whale_data_for_symbol(symbol)
453
 
454
  ml_processor = MLProcessor(market_context, data_manager_global, learning_engine_global)
 
455
  processed_data = await ml_processor.process_and_score_symbol_enhanced(ohlcv_data, {symbol: re_analysis_whale_data} if re_analysis_whale_data else {})
456
 
457
  if not processed_data: return None
 
465
  await r2_service_global.save_system_logs_async({ "trade_reanalyzed": True, "symbol": symbol, "action": re_analysis_decision.get('action'), 'strategy': re_analysis_decision.get('strategy', 'GENERIC') })
466
  return {"symbol": symbol, "decision": re_analysis_decision, "current_price": processed_data.get('current_price')}
467
  else: return None
468
+ except Exception as error: await r2_service_global.save_system_logs_async({ "reanalysis_error": True, "symbol": symbol, "error": str(error) }); print(f"❌ Error in re_analyze_open_trade_async for {symbol}: {error}"); traceback.print_exc(); return None
469
+
470
 
471
  async def run_bot_cycle_async():
472
  """دورة التداول الرئيسية"""
 
474
  if not await state_manager.wait_for_initialization(): print("❌ الخدمات غير مهيأة بالكامل - تخطي الدورة"); return
475
  print("🔄 بدء دورة التداول..."); await r2_service_global.save_system_logs_async({"cycle_started": True})
476
  if not r2_service_global.acquire_lock(): print("❌ فشل الحصول على القفل - تخطي الدورة"); return
477
+
478
+ open_trades = [] # Define open_trades before try block
479
  try:
480
  open_trades = await trade_manager_global.get_open_trades(); print(f"📋 الصفقات المفتوحة: {len(open_trades)}")
481
  should_look_for_new_trade = len(open_trades) == 0
 
484
  trades_to_reanalyze = [t for t in open_trades if now >= datetime.fromisoformat(t.get('expected_target_time', now.isoformat()))]
485
  if trades_to_reanalyze:
486
  print(f"🔄 إعادة تحليل {len(trades_to_reanalyze)} صفقة")
487
+ # Use gather for concurrent re-analysis, but process results sequentially
488
+ reanalysis_results = await asyncio.gather(*[re_analyze_open_trade_async(trade) for trade in trades_to_reanalyze], return_exceptions=True)
489
+
490
+ for i, result in enumerate(reanalysis_results):
491
+ trade = trades_to_reanalyze[i] # Get corresponding trade
492
+ if isinstance(result, Exception):
493
+ print(f" ❌ فشل إعادة تحليل {trade.get('symbol')}: {result}")
494
+ elif result and result['decision'].get('action') == "CLOSE_TRADE":
495
+ print(f" ✅ إغلاق {trade.get('symbol')} بناءً على إعادة التحليل.")
496
+ await trade_manager_global.close_trade(trade, result['current_price'], 'CLOSED_BY_REANALYSIS');
497
+ should_look_for_new_trade = True # Now we can look for a new trade
498
+ elif result and result['decision'].get('action') == "UPDATE_TRADE":
499
+ print(f" ✅ تحديث {trade.get('symbol')} بناءً على إعادة التحليل.")
500
+ await trade_manager_global.update_trade(trade, result['decision'])
501
+ elif result: # Handle HOLD case (log or do nothing)
502
+ print(f" ℹ️ الاحتفاظ بـ {trade.get('symbol')} بناءً على إعادة التحليل.")
503
+ else: # Handle case where re-analysis returned None without error
504
+ print(f" ⚠️ إعادة تحليل {trade.get('symbol')} لم تنتج قرارًا.")
505
+
506
+ # Recalculate should_look_for_new_trade after potential closures
507
+ current_open_trades_count = len(await trade_manager_global.get_open_trades())
508
+ should_look_for_new_trade = current_open_trades_count == 0
509
+
510
  if should_look_for_new_trade:
511
  portfolio_state = await r2_service_global.get_portfolio_state_async(); current_capital = portfolio_state.get("current_capital_usd", 0)
512
  if current_capital > 1:
 
515
  if best_opportunity: print(f"✅ فتح صفقة جديدة: {best_opportunity['symbol']}"); await trade_manager_global.open_trade( best_opportunity['symbol'], best_opportunity['decision'], best_opportunity['current_price'])
516
  else: print("❌ لم يتم العثور على فرص تداول مناسبة")
517
  else: print("❌ رأس المال غير كافي لفتح صفقات جديدة")
518
+ else:
519
+ print("ℹ️ يوجد صفقة مفتوحة بالفعل، تخطي البحث عن صفقة جديدة.")
520
+
521
  finally:
522
+ if r2_service_global.lock_acquired: # Check if lock was acquired before releasing
523
+ r2_service_global.release_lock()
524
+ await r2_service_global.save_system_logs_async({ "cycle_completed": True, "open_trades": len(open_trades)}) # Use initial count for log consistency
525
+ print("✅ اكتملت دورة التداول")
526
+
527
  except Exception as error:
528
+ print(f"❌ Unhandled error in main cycle: {error}"); traceback.print_exc() # Print traceback
529
+ await r2_service_global.save_system_logs_async({ "cycle_error": True, "error": str(error) });
530
  if r2_service_global and r2_service_global.lock_acquired: r2_service_global.release_lock() # Ensure lock release on error
531
 
532
  @asynccontextmanager
 
541
  await r2_service_global.save_system_logs_async({"application_started": True})
542
  print("🎯 التطبيق جاهز للعمل - نظام الطبقات 3 فعال (فصل الحيتان)")
543
  yield
544
+ except Exception as error:
545
+ print(f" Application startup failed: {error}");
546
+ traceback.print_exc() # Print traceback here as well
547
+ if r2_service_global:
548
+ await r2_service_global.save_system_logs_async({
549
+ "application_startup_failed": True,
550
+ "error": str(error)
551
+ })
552
+ # 🔴 --- الإصلاح: فصل raise إلى سطر جديد --- 🔴
553
+ raise # Correct indentation
554
+ # 🔴 --- نهاية الإصلاح --- 🔴
555
+ finally:
556
+ await cleanup_on_shutdown()
557
+
558
 
559
  application = FastAPI(lifespan=lifespan, title="AI Trading Bot", description="نظام تداول ذكي بثلاث طبقات تحليلية (فصل الحيتان)", version="3.2.0")
560