Riy777 commited on
Commit
1ec0cc0
·
verified ·
1 Parent(s): 5b4dadd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +149 -165
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # app.py (V11.0 - Full Real Data Integration & New Engines)
2
  import os
3
  import traceback
4
  import signal
@@ -6,82 +6,81 @@ import sys
6
  import uvicorn
7
  import asyncio
8
  import json
 
9
  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
- # استيراد الخدمات الأساسية
16
  try:
17
  from r2 import R2Service
18
  from LLM import LLMService
19
- from data_manager import DataManager
20
  from ml_engine.processor import MLProcessor
21
  from learning_hub.hub_manager import LearningHubManager
22
  from trade_manager import TradeManager
23
- # لم نعد بحاجة لاستيراد WhaleMonitor أو NewsFetcher هنا مباشرة،
24
- # سيتم التعامل معها داخل DataManager أو Processor عند الحاجة.
25
  except ImportError as e:
26
- print(f"❌ [App] خطأ فادح في استيراد الوحدات: {e}")
27
  sys.exit(1)
28
 
29
- # المتغيرات العالمية للنظام
30
  r2_service_global = None
31
  data_manager_global = None
32
  llm_service_global = None
33
  learning_hub_global = None
34
  trade_manager_global = None
35
- ml_processor_global = None # (V11.0) إضافة المعالج كمتغير عالمي
36
 
37
  MARKET_STATE_OK = True
38
 
 
39
  class StateManager:
40
  def __init__(self):
41
- self.market_analysis_lock = asyncio.Lock()
42
- self.trade_analysis_lock = asyncio.Lock()
43
  self.initialization_complete = False
44
  self.initialization_error = None
45
  self.services_initialized = {
46
- 'r2': False, 'data': False, 'llm': False, 'hub': False, 'trade': False
 
47
  }
48
 
49
- async def wait_for_initialization(self, timeout=60):
50
- start_time = time.time()
51
- while not self.initialization_complete and (time.time() - start_time) < timeout:
52
- if self.initialization_error: raise Exception(f"فشل التهيئة: {self.initialization_error}")
53
- await asyncio.sleep(2)
54
- if not self.initialization_complete: raise Exception(f"انتهت مهلة التهيئة ({timeout} ثانية)")
55
- return self.initialization_complete
56
-
57
  def set_service_initialized(self, service_name):
58
  self.services_initialized[service_name] = True
59
  if all(self.services_initialized.values()):
60
  self.initialization_complete = True
61
- print("🎯 [System] جميع الخدمات مهيأة وجاهزة للعمل.")
62
 
63
- def set_initialization_error(self, error):
64
- self.initialization_error = error
65
- print(f"❌ خطأ في التهيئة: {error}")
 
 
 
 
 
 
 
 
 
66
 
67
  state_manager = StateManager()
68
 
 
69
  async def initialize_services():
70
- """تهيئة مركزية لجميع خدمات النظام بترتيب محدد"""
71
  global r2_service_global, data_manager_global, llm_service_global
72
  global learning_hub_global, trade_manager_global, ml_processor_global
73
 
74
  try:
75
- print("🚀 [System V11.0] بدء تهيئة الخدمات...")
76
 
77
  # 1. الطبقة الأساسية (R2 & Data)
78
  r2_service_global = R2Service()
79
  state_manager.set_service_initialized('r2')
80
 
81
- # تحميل قاعدة بيانات العقود (اختياري، يمكن أن يكون فارغاً إذا لم يستخدم)
82
  contracts_db = await r2_service_global.load_contracts_db_async() or {}
83
 
84
- # تهيئة DataManager بدون WhaleMonitor مؤقتاً (سيتم ربطه لاحقاً إذا لزم الأمر)
85
  data_manager_global = DataManager(contracts_db, whale_monitor=None, r2_service=r2_service_global)
86
  await data_manager_global.initialize()
87
  state_manager.set_service_initialized('data')
@@ -96,223 +95,208 @@ async def initialize_services():
96
  state_manager.set_service_initialized('llm')
97
  state_manager.set_service_initialized('hub')
98
 
99
- # 3. طبقة التنفيذ والمعالجة (Trade Manager & Processor)
100
- # تهيئة المعالج المركزي الذي يربط كل شيء
101
  ml_processor_global = MLProcessor(
102
  market_context=None, # سيتم تحديثه في كل دورة
103
  data_manager=data_manager_global,
104
  learning_hub=learning_hub_global
105
  )
 
106
 
107
  trade_manager_global = TradeManager(
108
  r2_service_global, learning_hub_global, data_manager_global,
109
- state_manager, callback_on_close=run_bot_cycle_async
110
  )
111
  await trade_manager_global.initialize_sentry_exchanges()
112
  state_manager.set_service_initialized('trade')
113
 
114
  return True
115
  except Exception as e:
116
- error_msg = f"فشل تهيئة الخدمات: {str(e)}"
117
- print(f"❌ {error_msg}")
118
- state_manager.set_initialization_error(error_msg)
 
119
  return False
120
 
121
- async def monitor_market_async():
122
- global MARKET_STATE_OK
123
- try:
124
- if not await state_manager.wait_for_initialization(): return
125
- while True:
126
- try:
127
- async with state_manager.market_analysis_lock:
128
- market_ctx = await data_manager_global.get_market_context_async()
129
- ml_processor_global.market_context = market_ctx # تحديث سياق المعالج
130
-
131
- # فحص بسيط لحالة السوق (يمكن تعقيده لاحقاً)
132
- if market_ctx.get('btc_sentiment') == 'BEARISH' and market_ctx.get('fear_and_greed_index', 50) < 25:
133
- if MARKET_STATE_OK:
134
- print("⚠️ [Market Monitor] ظروف سوق هابطة شديدة. إيقاف مؤقت.")
135
- MARKET_STATE_OK = False
136
- else:
137
- if not MARKET_STATE_OK:
138
- print("✅ [Market Monitor] تحسن ظروف السوق. استئناف العمل.")
139
- MARKET_STATE_OK = True
140
-
141
- await asyncio.sleep(300) # فحص كل 5 دقائق
142
- except Exception as e:
143
- print(f"❌ [Market Monitor] خطأ: {e}")
144
- await asyncio.sleep(60)
145
- except Exception: pass
146
-
147
  async def run_explorer_cycle():
148
- """دورة المستكشف الرئيسية (Layer 1 Complete Cycle)"""
149
- if not state_manager.initialization_complete:
150
- print("❌ [Explorer] الخدمات غير جاهزة.")
151
- return
 
 
 
 
 
152
 
153
- print("🔭 [Explorer] بدء دورة استكشاف جديدة...")
 
154
  try:
155
- if not MARKET_STATE_OK:
156
- print("⏸️ [Explorer] السوق في حالة توقف. تخطي الدورة.")
157
- return
 
 
 
 
 
 
 
 
 
 
 
158
 
159
- # 1. الغربلة الأولية السريعة (Layer 1.1)
160
- # تستخدم الآن (Ranker + XGB 1h + MC) داخلياً
161
  candidates_l1 = await data_manager_global.layer1_rapid_screening()
162
  if not candidates_l1:
163
  print("😴 [Explorer] لم يتم العثور على مرشحين في الغربلة الأولية.")
164
- # تحديث الحارس بقائمة فارغة إذا لم نجد شيئاً
165
- await trade_manager_global.update_sentry_watchlist([])
166
  return
167
 
168
- # 2. التحليل العميق المتوازي (Layer 1.2 & 1.3)
169
  print(f"🔬 [Explorer] تحليل عميق لـ {len(candidates_l1)} عملة...")
170
  analyzed_candidates = []
 
171
 
172
- # نستخدم Queue لتدفق البيانات بين DataManager و Processor
173
- data_queue = asyncio.Queue(maxsize=5)
174
- # بدء منتج البيانات في الخلفية
175
  producer_task = asyncio.create_task(data_manager_global.stream_ohlcv_data(candidates_l1, data_queue))
176
 
177
  while True:
178
- # انتظار دفعة من البيانات
179
  batch = await data_queue.get()
180
- if batch is None: # إشارة نهاية التدفق
181
  data_queue.task_done()
182
- break
183
 
184
- # معالجة الدفعة بالتوازي باستخدام Processor المحدث
185
  tasks = [ml_processor_global.process_and_score_symbol_enhanced(c) for c in batch]
186
  results = await asyncio.gather(*tasks, return_exceptions=True)
187
 
188
  for res in results:
189
- # قبول العملات التي تجاوزت درجة 60% فقط
190
- if res and isinstance(res, dict) and res.get('enhanced_final_score', 0) >= 0.60:
191
- analyzed_candidates.append(res)
 
192
 
193
  data_queue.task_done()
194
 
195
- # التأكد من انتهاء مهمة المنتج
196
  await producer_task
197
 
198
- # 3. الترشيح النهائي والاختيار (Layer 1.4 LLM)
199
  if analyzed_candidates:
200
- # ترتيب حسب الدرجة النهائية الجديدة
201
  analyzed_candidates.sort(key=lambda x: x['enhanced_final_score'], reverse=True)
202
- top_5 = analyzed_candidates[:5]
203
 
204
- print(f"🧠 [Explorer] إرسال أفضل {len(top_5)} عملة إلى LLM للقرار النهائي...")
205
  watchlist = []
206
- for cand in top_5:
207
- # استشارة النموذج اللغوي لاتخاذ قرار استراتيجي
208
  decision = await llm_service_global.get_trading_decision(cand)
209
  if decision and decision.get('action') == 'WATCH':
210
  watchlist.append({
211
  'symbol': cand['symbol'],
212
  'strategy_hint': decision.get('strategy_to_watch', 'GENERIC'),
213
- # نحتفظ بالسياق الكامل للقرار لاستخدامه لاحقاً في الحارس
214
- 'llm_decision_context': {'decision': decision}
215
  })
216
-
217
- # تحديث قائمة مراقبة الحارس بالنتائج النهائية
218
- if watchlist:
219
- print(f"✅ [Explorer] تم اختيار {len(watchlist)} عملة للمراقبة.")
220
- await trade_manager_global.update_sentry_watchlist(watchlist)
221
- else:
222
- print("⚠️ [Explorer] رفض LLM جميع المرشحين.")
223
- await trade_manager_global.update_sentry_watchlist([])
224
  else:
225
- print("📉 [Explorer] لم تنجح أي عملة في التحليل العميق (Score < 60%).")
226
  await trade_manager_global.update_sentry_watchlist([])
227
 
228
  except Exception as e:
229
- print(f"❌ [Explorer Error] {e}")
230
  traceback.print_exc()
231
 
232
- async def run_bot_cycle_async():
233
- """دورة البوت الرئيسية (تستدعى دورياً أو عند الطلب)"""
234
- if not state_manager.initialization_complete: return
235
-
236
- # استخدام قفل R2 لمنع تداخل الدورات
237
- if not r2_service_global.acquire_lock():
238
- print("⚠️ [System] دورة أخرى قيد التشغيل. تخطي.")
239
- return
 
 
240
 
241
- try:
242
- # 1. إدارة الصفقات المفتوحة (إعادة التحليل إذا لزم الأمر)
243
- open_trades = await trade_manager_global.get_open_trades()
244
- if open_trades:
245
- now = datetime.now()
246
- # إعادة تحليل الصفقات التي تجاوزت وقت هدفها المتوقع
247
- trades_to_reanalyze = [t for t in open_trades if now >= datetime.fromisoformat(t.get('expected_target_time', now.isoformat()))]
248
- for trade in trades_to_reanalyze:
249
- print(f"🔄 [Re-Analyze] إعادة تحليل {trade['symbol']}...")
250
- # (يمكن إضافة منطق إعادة التحليل هنا باستخدام LLM و Processor)
251
- # حالياً سنقوم فقط بتمديد الوقت لتجنب التكرار المستمر
252
- trade['expected_target_time'] = (now + timedelta(minutes=15)).isoformat()
253
- await trade_manager_global._update_trade_in_db(trade)
254
 
255
- # 2. تشغيل دورة المستكشف للبحث عن فرص جديدة
256
- # (نبحث فقط إذا كان لدينا رأس مال متاح أو عدد صفقات قليل)
257
- if len(open_trades) < 3:
258
- await run_explorer_cycle()
259
- else:
260
- print("ℹ️ [System] الحد الأقصى للصفقات مفتوح. تخطي الاستكشاف.")
261
-
262
- finally:
263
- if r2_service_global.lock_acquired:
264
- r2_service_global.release_lock()
 
 
 
 
265
 
 
266
  @asynccontextmanager
267
- async def lifespan(application: FastAPI):
268
- """إدارة دورة حياة التطبيق"""
269
- print("🏁 [System] بدء تشغيل التطبيق...")
270
- success = await initialize_services()
271
- if success:
272
- # تشغيل المهام الخلفية
273
- asyncio.create_task(monitor_market_async())
274
- asyncio.create_task(trade_manager_global.start_sentry_and_monitoring_loops())
275
- # تشغيل دورة استكشاف أولية بعد وقت قصير
276
- asyncio.get_event_loop().call_later(10, lambda: asyncio.create_task(run_bot_cycle_async()))
277
- yield
278
- else:
279
- print("❌ [System] فشل بدء التشغيل. الخروج...")
280
- yield
281
-
282
- # تنظيف عند الإغلاق
283
- print("🛑 [System] إيقاف التشغيل...")
284
  if trade_manager_global: await trade_manager_global.stop_sentry_loops()
285
  if data_manager_global: await data_manager_global.close()
286
- if learning_hub_global: await learning_hub_global.shutdown()
287
 
288
- app = FastAPI(lifespan=lifespan, title="AI Trading Bot V11.0")
289
 
 
290
  @app.get("/")
291
  async def root():
292
  return {
293
  "status": "running" if state_manager.initialization_complete else "initializing",
294
- "system": "V11.0 (Real Data + XGBoost Integrated)",
295
  "timestamp": datetime.now().isoformat()
296
  }
297
 
298
- @app.get("/force-cycle")
299
- async def force_cycle():
300
- """نقطة نهاية لتشغيل دورة استكشاف يدوياً"""
301
  if not state_manager.initialization_complete:
302
- raise HTTPException(status_code=503, detail="System not ready")
303
- asyncio.create_task(run_bot_cycle_async())
304
- return {"message": "Explorer cycle initiated manually"}
305
 
306
  @app.get("/status")
307
- async def system_status():
308
- """عرض حالة النظام والحارس"""
309
- sentry_status = trade_manager_global.get_sentry_status() if trade_manager_global else {}
 
 
 
310
  return {
311
  "initialization": state_manager.initialization_complete,
312
- "market_ok": MARKET_STATE_OK,
313
  "sentry": sentry_status,
314
- "timestamp": datetime.now().isoformat()
315
  }
316
 
 
 
 
 
 
 
 
 
317
  if __name__ == "__main__":
318
- uvicorn.run(app, host="0.0.0.0", port=8000)
 
 
1
+ # app.py (V11.1 - Full Integration with Memory Management for HF Spaces)
2
  import os
3
  import traceback
4
  import signal
 
6
  import uvicorn
7
  import asyncio
8
  import json
9
+ import gc
10
  import time
11
  from contextlib import asynccontextmanager
12
+ from fastapi import FastAPI, HTTPException, BackgroundTasks
13
  from datetime import datetime
14
  from typing import List, Dict, Any
15
 
16
+ # --- استيراد الخدمات الأساسية للنظام ---
17
  try:
18
  from r2 import R2Service
19
  from LLM import LLMService
20
+ from ml_engine.data_manager import DataManager
21
  from ml_engine.processor import MLProcessor
22
  from learning_hub.hub_manager import LearningHubManager
23
  from trade_manager import TradeManager
 
 
24
  except ImportError as e:
25
+ print(f"❌ [App] خطأ فادح في استيراد الوحدات الأساسية: {e}")
26
  sys.exit(1)
27
 
28
+ # --- المتغيرات العالمية (Global Instances) ---
29
  r2_service_global = None
30
  data_manager_global = None
31
  llm_service_global = None
32
  learning_hub_global = None
33
  trade_manager_global = None
34
+ ml_processor_global = None
35
 
36
  MARKET_STATE_OK = True
37
 
38
+ # --- مدير حالة النظام ---
39
  class StateManager:
40
  def __init__(self):
 
 
41
  self.initialization_complete = False
42
  self.initialization_error = None
43
  self.services_initialized = {
44
+ 'r2': False, 'data': False, 'llm': False,
45
+ 'hub': False, 'processor': False, 'trade': False
46
  }
47
 
 
 
 
 
 
 
 
 
48
  def set_service_initialized(self, service_name):
49
  self.services_initialized[service_name] = True
50
  if all(self.services_initialized.values()):
51
  self.initialization_complete = True
52
+ print("🎯 [System] اكتملت تهيئة جميع الخدمات بنجاح.")
53
 
54
+ async def wait_for_initialization(self, timeout=120):
55
+ """انتظار آمن لاكتمال التهيئة مع مهلة زمنية"""
56
+ start_time = time.time()
57
+ while not self.initialization_complete:
58
+ if time.time() - start_time > timeout:
59
+ print("⚠️ [System] تجاوزت مهلة انتظار التهيئة.")
60
+ return False
61
+ if self.initialization_error:
62
+ print(f"❌ [System] توقف الانتظار بسبب خطأ في التهيئة: {self.initialization_error}")
63
+ return False
64
+ await asyncio.sleep(2)
65
+ return True
66
 
67
  state_manager = StateManager()
68
 
69
+ # --- دالة التهيئة المركزية ---
70
  async def initialize_services():
 
71
  global r2_service_global, data_manager_global, llm_service_global
72
  global learning_hub_global, trade_manager_global, ml_processor_global
73
 
74
  try:
75
+ print("🚀 [System V11.1] بدء تهيئة الخدمات (وضع توفير الذاكرة)...")
76
 
77
  # 1. الطبقة الأساسية (R2 & Data)
78
  r2_service_global = R2Service()
79
  state_manager.set_service_initialized('r2')
80
 
81
+ # تحميل قاعدة العقود (إن وجدت)
82
  contracts_db = await r2_service_global.load_contracts_db_async() or {}
83
 
 
84
  data_manager_global = DataManager(contracts_db, whale_monitor=None, r2_service=r2_service_global)
85
  await data_manager_global.initialize()
86
  state_manager.set_service_initialized('data')
 
95
  state_manager.set_service_initialized('llm')
96
  state_manager.set_service_initialized('hub')
97
 
98
+ # 3. طبقة التنفيذ والمعالجة
 
99
  ml_processor_global = MLProcessor(
100
  market_context=None, # سيتم تحديثه في كل دورة
101
  data_manager=data_manager_global,
102
  learning_hub=learning_hub_global
103
  )
104
+ state_manager.set_service_initialized('processor')
105
 
106
  trade_manager_global = TradeManager(
107
  r2_service_global, learning_hub_global, data_manager_global,
108
+ state_manager, callback_on_close=run_bot_cycle_wrapper
109
  )
110
  await trade_manager_global.initialize_sentry_exchanges()
111
  state_manager.set_service_initialized('trade')
112
 
113
  return True
114
  except Exception as e:
115
+ error_msg = f"فشل تهيئة الخدمات: {e}"
116
+ print(f"❌ [System] {error_msg}")
117
+ traceback.print_exc()
118
+ state_manager.initialization_error = error_msg
119
  return False
120
 
121
+ # --- دورة المستكشف الرئيسية (مع إدارة الذاكرة) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  async def run_explorer_cycle():
123
+ """
124
+ دورة المستكشف الكاملة (Layer 1).
125
+ تقوم بتحميل النماذج عند البدء، وتفريغها عند الانتهاء لتوفير الذاكرة.
126
+ """
127
+ if not await state_manager.wait_for_initialization():
128
+ print("⏳ [Explorer] الخدمات غير جاهزة بعد. تم تخطي الدورة.")
129
+ return
130
+
131
+ print("\n🔭 [Explorer V11.1] بدء دورة استكشاف جديدة...")
132
 
133
+ # 🔴 1. [إدارة الذاكرة] إعادة تحميل النماذج قبل البدء
134
+ print("🔄 [Memory] التأكد من تحميل نماذج ML للدورة الحالية...")
135
  try:
136
+ if data_manager_global.pattern_analyzer and not data_manager_global.pattern_analyzer.initialized:
137
+ await data_manager_global.pattern_analyzer.initialize()
138
+ if data_manager_global.layer1_ranker and not data_manager_global.layer1_ranker.model:
139
+ await data_manager_global.layer1_ranker.initialize()
140
+ except Exception as e:
141
+ print(f"⚠️ [Memory] تحذير أثناء إعادة تحميل النماذج: {e}")
142
+
143
+ try:
144
+ # أ. تحديث سياق السوق
145
+ market_ctx = await data_manager_global.get_market_context_async()
146
+ ml_processor_global.market_context = market_ctx
147
+
148
+ if market_ctx.get('market_trend') == 'bear_market' and market_ctx.get('fear_and_greed_index', 50) < 20:
149
+ print("🐻 [Explorer] السوق في حالة خوف شديد. قد يتم تقليل النشاط.")
150
 
151
+ # ب. الغربلة الأولية السريعة (Layer 1.1)
 
152
  candidates_l1 = await data_manager_global.layer1_rapid_screening()
153
  if not candidates_l1:
154
  print("😴 [Explorer] لم يتم العثور على مرشحين في الغربلة الأولية.")
 
 
155
  return
156
 
157
+ # ج. التحليل العميق المتوازي (Layer 1.2 & 1.3)
158
  print(f"🔬 [Explorer] تحليل عميق لـ {len(candidates_l1)} عملة...")
159
  analyzed_candidates = []
160
+ data_queue = asyncio.Queue(maxsize=5) # طابور صغير لتوفير الذاكرة
161
 
162
+ # تشغيل المنتج (جلب البيانات) والمستهلك (التحليل) بالتوازي
 
 
163
  producer_task = asyncio.create_task(data_manager_global.stream_ohlcv_data(candidates_l1, data_queue))
164
 
165
  while True:
 
166
  batch = await data_queue.get()
167
+ if batch is None:
168
  data_queue.task_done()
169
+ break
170
 
171
+ # تحليل الدفعة
172
  tasks = [ml_processor_global.process_and_score_symbol_enhanced(c) for c in batch]
173
  results = await asyncio.gather(*tasks, return_exceptions=True)
174
 
175
  for res in results:
176
+ if res and isinstance(res, dict):
177
+ # شرط التأهل للقرار النهائي: درجة >= 60%
178
+ if res.get('enhanced_final_score', 0) >= 0.60:
179
+ analyzed_candidates.append(res)
180
 
181
  data_queue.task_done()
182
 
 
183
  await producer_task
184
 
185
+ # د. الترشيح النهائي والاختيار (Layer 1.4 LLM)
186
  if analyzed_candidates:
 
187
  analyzed_candidates.sort(key=lambda x: x['enhanced_final_score'], reverse=True)
188
+ top_candidates = analyzed_candidates[:5] # نرسل أفضل 5 فقط
189
 
190
+ print(f"🧠 [Explorer] إرسال أفضل {len(top_candidates)} عملة إلى LLM...")
191
  watchlist = []
192
+ for cand in top_candidates:
193
+ # استدعاء LLM لاتخاذ قرار استراتيجي
194
  decision = await llm_service_global.get_trading_decision(cand)
195
  if decision and decision.get('action') == 'WATCH':
196
  watchlist.append({
197
  'symbol': cand['symbol'],
198
  'strategy_hint': decision.get('strategy_to_watch', 'GENERIC'),
199
+ 'llm_decision_context': {'decision': decision},
200
+ 'explorer_score': cand.get('enhanced_final_score', 0)
201
  })
202
+ print(f" ✅ [LLM] وافق على {cand['symbol']} (Strategy: {decision.get('strategy_to_watch')})")
203
+ else:
204
+ print(f" ❌ [LLM] رفض {cand['symbol']}")
205
+
206
+ # تحديث قائمة الحارس
207
+ await trade_manager_global.update_sentry_watchlist(watchlist)
 
 
208
  else:
209
+ print("📉 [Explorer] لا يوجد مرشحين مؤهلين بعد التحليل العميق.")
210
  await trade_manager_global.update_sentry_watchlist([])
211
 
212
  except Exception as e:
213
+ print(f"❌ [Explorer Error] حدث خطأ غير متوقع أثناء الدورة: {e}")
214
  traceback.print_exc()
215
 
216
+ finally:
217
+ # 🔴 2. [إدارة الذاكرة] تنظيف الذاكرة بعد انتهاء الدورة
218
+ print("🧹 [System] بدء تنظيف الذاكرة وإسبات النماذج...")
219
+ if data_manager_global.pattern_analyzer:
220
+ data_manager_global.pattern_analyzer.clear_memory()
221
+ if data_manager_global.layer1_ranker:
222
+ data_manager_global.layer1_ranker.clear_memory()
223
+
224
+ gc.collect() # إجبار النظام على تحرير الذاكرة غير المستخدمة
225
+ print("✅ [System] اكتمل التنظيف. النظام في وضع الخمول (Idle).")
226
 
227
+ # غلاف للدورة ليتوافق مع callback مدير الصفقات
228
+ async def run_bot_cycle_wrapper():
229
+ await run_explorer_cycle()
 
 
 
 
 
 
 
 
 
 
230
 
231
+ # --- مهام الخلفية المجدولة ---
232
+ async def scheduled_tasks_loop():
233
+ """حلقة المهام المجدولة (مثل الدورة الرئيسية كل فترة)"""
234
+ await state_manager.wait_for_initialization()
235
+ while True:
236
+ try:
237
+ # تشغيل دورة المستكشف كل 15 دقيقة (مثلاً)
238
+ await asyncio.sleep(900)
239
+ if not trade_manager_global.sentry_watchlist: # إذا كانت القائمة فارغة، نبحث عن فرص جديدة
240
+ await run_explorer_cycle()
241
+ except asyncio.CancelledError: break
242
+ except Exception as e:
243
+ print(f"⚠️ [Scheduler] خطأ في المهام المجدولة: {e}")
244
+ await asyncio.sleep(60)
245
 
246
+ # --- إعداد تطبيق FastAPI ---
247
  @asynccontextmanager
248
+ async def lifespan(app: FastAPI):
249
+ # عند البدء
250
+ print("🏁 [Lifespan] بدء تشغيل النظام...")
251
+ init_task = asyncio.create_task(initialize_services())
252
+ yield # هنا يعمل التطبيق
253
+ # عند الإيقاف
254
+ print("🛑 [Lifespan] إيقاف النظام...")
 
 
 
 
 
 
 
 
 
 
255
  if trade_manager_global: await trade_manager_global.stop_sentry_loops()
256
  if data_manager_global: await data_manager_global.close()
257
+ print("👋 [Lifespan] تم الإيقاف بنجاح.")
258
 
259
+ app = FastAPI(lifespan=lifespan, title="AI Trading Bot V11.1", version="11.1.0")
260
 
261
+ # --- نقاط النهاية (API Endpoints) ---
262
  @app.get("/")
263
  async def root():
264
  return {
265
  "status": "running" if state_manager.initialization_complete else "initializing",
266
+ "system": "Explorer-Sentry-Executor V11.1 (Memory Optimized)",
267
  "timestamp": datetime.now().isoformat()
268
  }
269
 
270
+ @app.get("/run-cycle")
271
+ async def trigger_cycle(background_tasks: BackgroundTasks):
272
+ """تشغيل دورة مستكشف يدوياً في الخلفية"""
273
  if not state_manager.initialization_complete:
274
+ raise HTTPException(status_code=503, detail="System initializing...")
275
+ background_tasks.add_task(run_explorer_cycle)
276
+ return {"message": "Explorer cycle triggered in background"}
277
 
278
  @app.get("/status")
279
+ async def get_status():
280
+ """جلب حالة النظام والحارس"""
281
+ sentry_status = {}
282
+ if trade_manager_global:
283
+ sentry_status = trade_manager_global.get_sentry_status()
284
+
285
  return {
286
  "initialization": state_manager.initialization_complete,
287
+ "services": state_manager.services_initialized,
288
  "sentry": sentry_status,
289
+ "memory_mode": "On-Demand Loading Active"
290
  }
291
 
292
+ @app.on_event("startup")
293
+ async def startup_event():
294
+ """تشغيل حلقات المراقبة الخلفية بعد بدء التطبيق"""
295
+ asyncio.create_task(scheduled_tasks_loop())
296
+ # تشغيل حلقة الحارس إذا كان مهيأ
297
+ if trade_manager_global:
298
+ asyncio.create_task(trade_manager_global.start_sentry_and_monitoring_loops())
299
+
300
  if __name__ == "__main__":
301
+ # تشغيل الخادم
302
+ uvicorn.run(app, host="0.0.0.0", port=7860)