Riy777 commited on
Commit
0deef96
·
1 Parent(s): c4a4c71

Update learning_hub/hub_manager.py

Browse files
Files changed (1) hide show
  1. learning_hub/hub_manager.py +184 -5
learning_hub/hub_manager.py CHANGED
@@ -1,7 +1,9 @@
1
  # learning_hub/hub_manager.py
2
- # (محدث بالكامل - V2 - VADER Learning)
3
  import asyncio
4
- from typing import Any, Dict
 
 
5
 
6
  # (استيراد جميع المكونات الداخلية للمركز)
7
  from .schemas import *
@@ -11,9 +13,19 @@ from .statistical_analyzer import StatisticalAnalyzer
11
  from .reflector import Reflector
12
  from .curator import Curator
13
 
 
 
 
 
 
 
 
 
 
 
14
  class LearningHubManager:
15
  def __init__(self, r2_service: Any, llm_service: Any, data_manager: Any):
16
- print("🚀 Initializing Learning Hub Manager...")
17
 
18
  # 1. الخدمات الأساسية (يتم تمريرها من app.py)
19
  self.r2_service = r2_service
@@ -40,6 +52,10 @@ class LearningHubManager:
40
  data_manager=self.data_manager
41
  )
42
 
 
 
 
 
43
  self.initialized = False
44
  print("✅ Learning Hub Manager constructed. Ready for initialization.")
45
 
@@ -52,6 +68,15 @@ class LearningHubManager:
52
 
53
  print("🔄 [HubManager] Initializing all sub-modules...")
54
  await self.statistical_analyzer.initialize()
 
 
 
 
 
 
 
 
 
55
  self.initialized = True
56
  print("✅ [HubManager] All sub-modules initialized. Learning Hub is LIVE.")
57
 
@@ -166,6 +191,160 @@ class LearningHubManager:
166
  print("✅ [HubManager] All statistical (slow-learner) data saved.")
167
  except Exception as e:
168
  print(f"❌ [HubManager] Failed to save learning data on shutdown: {e}")
169
- # 🔴 --- START OF CHANGE --- 🔴
170
- # (تم حذف القوس } الزائد من هنا)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  # 🔴 --- END OF CHANGE --- 🔴
 
1
  # learning_hub/hub_manager.py
2
+ # (محدث بالكامل - V3 - Whale Learning Loop)
3
  import asyncio
4
+ import traceback
5
+ from typing import Any, Dict, List
6
+ from datetime import datetime, timezone
7
 
8
  # (استيراد جميع المكونات الداخلية للمركز)
9
  from .schemas import *
 
13
  from .reflector import Reflector
14
  from .curator import Curator
15
 
16
+ # 🔴 --- (جديد V3) استيراد لتحليل الارتباط --- 🔴
17
+ try:
18
+ import numpy as np
19
+ from scipy.stats import pearsonr
20
+ NUMPY_AVAILABLE = True
21
+ except ImportError:
22
+ print("❌ [HubManager] مكتبة numpy أو scipy غير مثبتة! لن يعمل تعلم الحيتان.")
23
+ NUMPY_AVAILABLE = False
24
+
25
+
26
  class LearningHubManager:
27
  def __init__(self, r2_service: Any, llm_service: Any, data_manager: Any):
28
+ print("🚀 Initializing Learning Hub Manager (V3)...")
29
 
30
  # 1. الخدمات الأساسية (يتم تمريرها من app.py)
31
  self.r2_service = r2_service
 
52
  data_manager=self.data_manager
53
  )
54
 
55
+ # 🔴 --- (جديد V3) متغيرات حالة لتعلم الحيتان --- 🔴
56
+ self.whale_learning_lock = asyncio.Lock()
57
+ self.optimal_whale_config = {} # (الأوزان المتعلمة)
58
+
59
  self.initialized = False
60
  print("✅ Learning Hub Manager constructed. Ready for initialization.")
61
 
 
68
 
69
  print("🔄 [HubManager] Initializing all sub-modules...")
70
  await self.statistical_analyzer.initialize()
71
+
72
+ # 🔴 --- (جديد V3) تحميل إعدادات الحيتان المتعلمة --- 🔴
73
+ if hasattr(self.r2_service, 'load_whale_learning_config_async'):
74
+ self.optimal_whale_config = await self.r2_service.load_whale_learning_config_async()
75
+ if self.optimal_whale_config:
76
+ print(f"✅ [HubManager] تم تحميل إعدادات تعلم الحيتان المثلى: {self.optimal_whale_config}")
77
+ else:
78
+ print("ℹ️ [HubManager] لم يتم العثور على إعدادات تعلم حيتان سابقة.")
79
+
80
  self.initialized = True
81
  print("✅ [HubManager] All sub-modules initialized. Learning Hub is LIVE.")
82
 
 
191
  print("✅ [HubManager] All statistical (slow-learner) data saved.")
192
  except Exception as e:
193
  print(f"❌ [HubManager] Failed to save learning data on shutdown: {e}")
194
+
195
+ # 🔴 --- START OF CHANGE (V3 - Whale Learning Loop) --- 🔴
196
+
197
+ async def run_whale_learning_check(self):
198
+ """
199
+ (جديد V3 - "المُسجّل" Logger)
200
+ يعمل في الخلفية لإكمال سجلات تعلم الحيتان المعلقة.
201
+ """
202
+ if not self.initialized:
203
+ await asyncio.sleep(60) # انتظر حتى تتم التهيئة
204
+
205
+ print(f"🧠 [Whale-Logger] بدء تشغيل حلقة تعلم الحيتان (المُسجّل)...")
206
+
207
+ # (الانتظار 10 دقائق عند بدء التشغيل للسماح بجمع بعض البيانات)
208
+ await asyncio.sleep(600)
209
+
210
+ while True:
211
+ try:
212
+ # (1. جلب السجلات المعلقة)
213
+ pending_records = await self.r2_service.get_pending_whale_learning_records_async()
214
+ if not pending_records:
215
+ # (لا توجد سجلات، انتظر 10 دقائق)
216
+ await asyncio.sleep(600)
217
+ continue
218
+
219
+ print(f"🧠 [Whale-Logger] تم العثور على {len(pending_records)} سجل تعلم معلق. بدء المعالجة...")
220
+ now_utc = datetime.now(timezone.utc)
221
+
222
+ for record in pending_records:
223
+ try:
224
+ target_time_utc = datetime.fromisoformat(record['target_time_utc'])
225
+
226
+ # (2. التحقق من الوقت)
227
+ if now_utc >= target_time_utc:
228
+ print(f" -> [Whale-Logger] معالجة سجل {record['symbol']} (ID: {record['record_id']})...")
229
+ # (حان وقت جلب السعر المستقبلي)
230
+ symbol = record['symbol']
231
+ target_price = await self.data_manager.get_latest_price_async(symbol)
232
+
233
+ if target_price and target_price > 0 and record['start_price_usd'] > 0:
234
+ # (3. حساب النتيجة)
235
+ price_change_pct = ((target_price - record['start_price_usd']) / record['start_price_usd']) * 100
236
+
237
+ record['target_price_usd'] = target_price
238
+ record['price_change_percentage'] = price_change_pct
239
+ record['status'] = "COMPLETED"
240
+
241
+ # (4. تحديث السجل في R2)
242
+ await self.r2_service.update_completed_whale_learning_record_async(record)
243
+ else:
244
+ print(f" ⚠️ [Whale-Logger] فشل جلب السعر المستقبلي لـ {symbol}. سيعاد المحاولة لاحقاً.")
245
+ else:
246
+ # (لم يحن الوقت بعد)
247
+ pass
248
+
249
+ except Exception as e_inner:
250
+ print(f"❌ [Whale-Logger] فشل معالجة سجل فردي: {e_inner}")
251
+
252
+ # (تشغيل "المعلّم" بعد كل دورة تسجيل)
253
+ await self.update_optimal_whale_window()
254
+
255
+ # (الانتظار 5 دقائق قبل التحقق مرة أخرى)
256
+ await asyncio.sleep(300)
257
+
258
+ except Exception as e_outer:
259
+ print(f"❌ [Whale-Logger] خطأ فادح في حلقة تعلم الحيتان: {e_outer}")
260
+ traceback.print_exc()
261
+ await asyncio.sleep(600) # (انتظار 10 دقائق عند الفشل الفادح)
262
+
263
+ async def update_optimal_whale_window(self):
264
+ """
265
+ (جديد V3 - "المعلّم" Teacher)
266
+ يحلل جميع السجلات المكتملة ويجد أفضل "مقياس + نافذة" للارتباط.
267
+ """
268
+ if not NUMPY_AVAILABLE:
269
+ print("⚠️ [Whale-Teacher] لا يمكن تشغيل تحليل الارتباط (numpy/scipy مفقودة).")
270
+ return
271
+
272
+ async with self.whale_learning_lock:
273
+ print("👨‍🏫 [Whale-Teacher] بدء تحليل الارتباط الإحصائي...")
274
+ try:
275
+ # (1. جلب جميع السجلات المكتملة)
276
+ all_completed = await self.r2_service.get_all_completed_whale_records_async()
277
+ if len(all_completed) < 20: # (نحتاج 20 عينة على الأقل لبدء التعلم)
278
+ print(f"👨‍🏫 [Whale-Teacher] نحتاج 20 سجل مكتمل على الأقل (الحالي: {len(all_completed)}). تخطي التحليل.")
279
+ return
280
+
281
+ # (2. استخراج البيانات في مصفوفات Numpy)
282
+ price_changes = []
283
+ metrics_data = defaultdict(lambda: defaultdict(list))
284
+
285
+ # (قائمة بجميع المقاييس التي نريد اختبارها)
286
+ windows = ['30m', '1h', '2h', '4h', '24h']
287
+ metric_keys = ['relative_net_flow_percent', 'transaction_density', 'net_flow_usd']
288
+
289
+ for record in all_completed:
290
+ if record.get('price_change_percentage') is None: continue
291
+
292
+ price_changes.append(record['price_change_percentage'])
293
+ analysis = record.get('window_analysis', {})
294
+
295
+ for w in windows:
296
+ window_data = analysis.get(w, {})
297
+ for k in metric_keys:
298
+ metrics_data[w][k].append(window_data.get(k, 0.0))
299
+
300
+ price_changes_np = np.array(price_changes)
301
+ if len(price_changes_np) < 20:
302
+ print("👨‍🏫 [Whale-Teacher] لا توجد بيانات كافية (NP) للارتباط.")
303
+ return
304
+
305
+ # (3. حساب الارتباط)
306
+ correlation_results = {}
307
+ for w in windows:
308
+ for k in metric_keys:
309
+ metric_np = np.array(metrics_data[w][k])
310
+ if len(metric_np) != len(price_changes_np): continue
311
+
312
+ # (حساب ارتباط بيرسون)
313
+ corr, p_value = pearsonr(metric_np, price_changes_np)
314
+
315
+ if not np.isnan(corr) and p_value < 0.1: # (نهتم فقط بالارتباطات ذات الدلالة الإحصائية)
316
+ correlation_results[f"{w}_{k}"] = abs(corr) # (نهتم بقوة الارتباط، بغض النظر عن الاتجاه)
317
+
318
+ if not correlation_results:
319
+ print("👨‍🏫 [Whale-Teacher] لم يتم العثور على ارتباطات إحصائية ذات دلال��.")
320
+ return
321
+
322
+ # (4. العثور على الفائز وحفظه)
323
+ best_metric_key = max(correlation_results, key=correlation_results.get)
324
+ best_correlation = correlation_results[best_metric_key]
325
+
326
+ # (تقسيم المفتاح: '1h_relative_net_flow_percent')
327
+ best_window, best_metric = best_metric_key.split('_', 1)
328
+
329
+ new_config = {
330
+ "best_window": best_window,
331
+ "best_metric": best_metric,
332
+ "correlation_score": best_correlation,
333
+ "total_samples": len(price_changes_np),
334
+ "last_updated_utc": datetime.now(timezone.utc).isoformat()
335
+ }
336
+
337
+ # (حفظ الإعدادات الجديدة ومشاركتها مع النظام)
338
+ self.optimal_whale_config = new_config
339
+ await self.r2_service.save_whale_learning_config_async(new_config)
340
+
341
+ print(f"🏆 [Whale-Teacher] تم العثور على أفضل إشارة جديدة!")
342
+ print(f" -> المقياس: {best_metric}")
343
+ print(f" -> النافذة: {best_window}")
344
+ print(f" -> الارتباط: {best_correlation:.4f} (على {len(price_changes_np)} عينة)")
345
+
346
+ except Exception as e:
347
+ print(f"❌ [Whale-Teacher] فشل تحليل الارتباط: {e}")
348
+ traceback.print_exc()
349
+
350
  # 🔴 --- END OF CHANGE --- 🔴