Riy777 commited on
Commit
05182f8
·
1 Parent(s): de31db6

Update learning_hub/hub_manager.py

Browse files
Files changed (1) hide show
  1. learning_hub/hub_manager.py +98 -146
learning_hub/hub_manager.py CHANGED
@@ -1,181 +1,157 @@
1
  # learning_hub/hub_manager.py
2
- # (V4.3 - NO_LLM toggle, auto-disable if llm_service is None, zero LLM calls)
3
 
4
- import os
5
  import asyncio
6
- from typing import Any, Dict
 
7
  from datetime import datetime, timezone
8
  from collections import defaultdict
9
 
10
- # مكونات المشروع
 
11
  from .policy_engine import PolicyEngine
12
  from .memory_store import MemoryStore
13
  from .statistical_analyzer import StatisticalAnalyzer
14
  from .reflector import Reflector
15
  from .curator import Curator
16
 
17
- # (اختياري) تعلم الحيتان
18
  try:
19
  import numpy as np
20
  from scipy.stats import pearsonr
21
  NUMPY_AVAILABLE = True
22
- except Exception:
23
- print("❌ [HubManager] numpy/scipy غير متوفرين. تعطيل تعلم الحيتان المتقدم.", flush=True)
24
  NUMPY_AVAILABLE = False
25
 
26
-
27
  class LearningHubManager:
28
- def __init__(self, r2_service: Any, llm_service: Any, data_manager: Any, disable_llm: bool = None):
29
- """
30
- تبديل مؤقت لتعطيل LLM:
31
- - disable_llm=True تعطيل كامل.
32
- - disable_llm=None ⇒ يُقرأ من NO_LLM.
33
- - إذا llm_service هو None ⇒ يُعطل تلقائياً حتى لو كان NO_LLM غير مفعّل.
34
- """
35
- env_flag = os.getenv("NO_LLM", "").strip().lower() in ("1", "true", "yes", "on")
36
- user_flag = bool(disable_llm) if disable_llm is not None else False
37
- auto_flag = (llm_service is None)
38
- self.llm_disabled = env_flag or user_flag or auto_flag
39
-
40
- print("🚀 Initializing Learning Hub Manager (V4.3 - NO_LLM toggle + auto-disable)...", flush=True)
41
-
42
- # الخدمات الأساسية
43
  self.r2_service = r2_service
44
- self.llm_service = None if self.llm_disabled else llm_service
45
  self.data_manager = data_manager
46
 
47
- # المكونات الجوهرية
48
  self.policy_engine = PolicyEngine()
49
  self.memory_store = MemoryStore(
50
- r2_service=self.r2_service,
51
  policy_engine=self.policy_engine,
52
- llm_service=(None if self.llm_disabled else self.llm_service)
53
  )
54
-
55
- # Reflector/Curator تُنشأ فقط عند تفعيل LLM فعلياً
56
- self.reflector = None if self.llm_disabled else Reflector(
57
  llm_service=self.llm_service,
58
  memory_store=self.memory_store
59
  )
60
- self.curator = None if self.llm_disabled else Curator(
61
  llm_service=self.llm_service,
62
  memory_store=self.memory_store
63
  )
64
-
65
- # الإحصاء يعمل دائماً
66
  self.statistical_analyzer = StatisticalAnalyzer(
67
  r2_service=self.r2_service,
68
  data_manager=self.data_manager
69
  )
70
-
71
- # تعلم الحيتان
72
  self.whale_learning_lock = asyncio.Lock()
73
- self.optimal_whale_config: Dict[str, Any] = {}
74
-
75
  self.initialized = False
76
- print("✅ Learning Hub Manager constructed. Ready for initialization.", flush=True)
77
- print(f"ℹ️ [HubManager] LLM mode: {'DISABLED' if self.llm_disabled else 'ENABLED'}", flush=True)
78
 
79
  async def initialize(self):
80
- if self.initialized:
81
- return
82
- print("🔄 [HubManager] Initializing all sub-modules...", flush=True)
83
-
 
84
  await self.statistical_analyzer.initialize()
85
-
 
86
  if hasattr(self.r2_service, 'load_whale_learning_config_async'):
87
- try:
88
- self.optimal_whale_config = await self.r2_service.load_whale_learning_config_async()
89
- if self.optimal_whale_config:
90
- bm = self.optimal_whale_config.get('best_metric', 'N/A')
91
- print(f"✅ [HubManager] Loaded optimal whale config: {bm}", flush=True)
92
- except Exception as e:
93
- print(f"⚠️ [HubManager] load_whale_learning_config_async failed: {e}", flush=True)
94
-
95
  self.initialized = True
96
- state = "NO_LLM" if self.llm_disabled else "LLM_ENABLED"
97
- print(f"✅ [HubManager] All sub-modules initialized. Learning Hub is LIVE ({state}).", flush=True)
98
 
99
  async def analyze_trade_and_learn(self, trade_object: Dict[str, Any], close_reason: str):
100
- if not self.initialized:
101
- return
102
 
103
- print(f"🧠 [HubManager] Learning from trade {trade_object.get('symbol')}...", flush=True)
104
 
105
- # Reflector: ممنوع النداء إذا كان LLM معطلاً أو الخدمة غير متاحة
106
- if not self.llm_disabled and self.reflector is not None and self.llm_service is not None and hasattr(self.llm_service, "_call_llm"):
107
- try:
108
- await self.reflector.analyze_trade_outcome(trade_object, close_reason)
109
- except Exception as e:
110
- print(f"❌ [HubManager] Reflector failed: {e}", flush=True)
111
- else:
112
- print("ℹ️ [HubManager] Reflector skipped (NO_LLM).", flush=True)
113
 
114
- # التحليل الإحصائي وتكييف الأوزان
115
  try:
116
  await self.statistical_analyzer.update_statistics(trade_object, close_reason)
117
  except Exception as e:
118
- print(f"❌ [HubManager] StatisticalAnalyzer failed: {e}", flush=True)
119
-
120
- print(f"✅ [HubManager] Learning complete for {trade_object.get('symbol')}.", flush=True)
121
 
122
  async def get_optimized_weights(self, market_condition: str = None) -> Dict[str, Any]:
 
 
 
 
123
  if not self.initialized:
124
- return await self.statistical_analyzer.get_default_strategy_weights()
 
 
125
  return self.statistical_analyzer.weights
126
 
127
- # واجهات LLM تبقى موجودة للتوافق ولكنها تُرجع رسالة عند التعطيل
128
  async def get_active_context_for_llm(self, domain: str, query: str) -> str:
129
- if self.llm_disabled:
130
- return "LLM disabled by configuration (NO_LLM)."
131
- if not self.initialized:
132
- return "Learning Hub not initialized."
133
  return await self.memory_store.get_active_context(domain, query)
134
-
135
  async def get_statistical_feedback_for_llm(self, entry_strategy: str) -> str:
136
- if self.llm_disabled:
137
- return "LLM disabled by configuration (NO_LLM)."
138
- if not self.initialized:
139
- return "Learning Hub not initialized."
140
  best_profile = await self.statistical_analyzer.get_best_exit_profile(entry_strategy)
141
  if best_profile != "unknown":
142
  return f"Statistical Feedback: For '{entry_strategy}', '{best_profile}' exit profile performed best."
143
  return "No statistical feedback available yet."
144
 
 
 
 
 
145
  async def run_distillation_check(self):
146
- if not self.initialized or self.llm_disabled or self.curator is None:
147
- return
 
148
  for domain in self.memory_store.domain_files.keys():
149
- try:
150
- await self.curator.check_and_distill_domain(domain)
151
- except Exception:
152
- pass
153
 
154
  async def shutdown(self):
155
- if not self.initialized:
156
- return
157
- print("🔄 [HubManager] Shutting down... Saving learning data.", flush=True)
158
  try:
 
159
  await self.statistical_analyzer.save_weights_to_r2()
160
  await self.statistical_analyzer.save_performance_history()
161
  await self.statistical_analyzer.save_exit_profile_effectiveness()
162
  await self.statistical_analyzer.save_vader_effectiveness()
163
- print("✅ [HubManager] Data saved successfully.", flush=True)
164
  except Exception as e:
165
- print(f"❌ [HubManager] Save failed: {e}", flush=True)
166
 
167
- # --- Whale Learning Loop (لا يعتمد على LLM) ---
168
  async def run_whale_learning_check(self):
169
- if not self.initialized:
170
- await asyncio.sleep(60)
171
- print("🧠 [Whale-Logger] Starting background learning loop...", flush=True)
172
- await asyncio.sleep(600)
173
  while True:
174
  try:
175
- if not hasattr(self.r2_service, 'get_pending_whale_learning_records_async'):
176
- await asyncio.sleep(600)
177
- continue
178
-
179
  pending = await self.r2_service.get_pending_whale_learning_records_async()
180
  if not pending:
181
  await asyncio.sleep(600)
@@ -186,49 +162,34 @@ class LearningHubManager:
186
  try:
187
  target_time = datetime.fromisoformat(record['target_time_utc'])
188
  if now_utc >= target_time:
189
- symbol = record.get('symbol')
190
- if hasattr(self.data_manager, 'get_latest_price_async'):
191
- target_price = await self.data_manager.get_latest_price_async(symbol)
192
- else:
193
- target_price = None
194
-
195
- if target_price and target_price > 0 and record.get('start_price_usd', 0) > 0:
196
  pct_change = ((target_price - record['start_price_usd']) / record['start_price_usd']) * 100
197
- record.update({
198
- 'target_price_usd': target_price,
199
- 'price_change_percentage': pct_change,
200
- 'status': "COMPLETED"
201
- })
202
- if hasattr(self.r2_service, 'update_completed_whale_learning_record_async'):
203
- await self.r2_service.update_completed_whale_learning_record_async(record)
204
- except Exception:
205
- pass
206
-
207
  await self.update_optimal_whale_window()
208
- await asyncio.sleep(300)
209
  except Exception as e:
210
- print(f"❌ [Whale-Logger] Error: {e}", flush=True)
211
  await asyncio.sleep(600)
212
 
213
  async def update_optimal_whale_window(self):
214
- if not NUMPY_AVAILABLE:
215
- return
216
  async with self.whale_learning_lock:
217
  try:
218
- if not hasattr(self.r2_service, 'get_all_completed_whale_records_async'):
219
- return
220
  all_completed = await self.r2_service.get_all_completed_whale_records_async()
221
- if not all_completed or len(all_completed) < 20:
222
- return
223
 
224
  price_changes = []
225
  metrics_data = defaultdict(lambda: defaultdict(list))
226
  windows = ['30m', '1h', '2h', '4h', '24h']
227
  metric_keys = ['relative_net_flow_percent', 'transaction_density', 'net_flow_usd']
228
-
229
  for r in all_completed:
230
- if r.get('price_change_percentage') is None:
231
- continue
232
  price_changes.append(r['price_change_percentage'])
233
  analysis = r.get('window_analysis', {})
234
  for w in windows:
@@ -236,33 +197,24 @@ class LearningHubManager:
236
  metrics_data[w][k].append(analysis.get(w, {}).get(k, 0.0))
237
 
238
  price_np = np.array(price_changes)
239
- best_corr = 0.0
240
  best_key = None
241
 
242
  for w in windows:
243
  for k in metric_keys:
244
  metric_np = np.array(metrics_data[w][k])
245
- if len(metric_np) == len(price_np) and len(price_np) > 0:
246
- try:
247
- corr, p_val = pearsonr(metric_np, price_np)
248
- except Exception:
249
- continue
250
  if not np.isnan(corr) and p_val < 0.1 and abs(corr) > best_corr:
251
- best_corr = float(abs(corr))
252
  best_key = f"{w}_{k}"
253
 
254
  if best_key:
255
  w, m = best_key.split('_', 1)
256
- new_config = {
257
- "best_window": w,
258
- "best_metric": m,
259
- "correlation_score": best_corr,
260
- "total_samples": int(len(price_np)),
261
- "last_updated_utc": datetime.now(timezone.utc).isoformat()
262
- }
263
  self.optimal_whale_config = new_config
264
- if hasattr(self.r2_service, 'save_whale_learning_config_async'):
265
- await self.r2_service.save_whale_learning_config_async(new_config)
266
- print(f"🏆 [Whale-Teacher] New best signal: {m} on {w} (Corr: {best_corr:.2f})", flush=True)
267
  except Exception as e:
268
- print(f"❌ [Whale-Teacher] Error: {e}", flush=True)
 
1
  # learning_hub/hub_manager.py
2
+ # (محدث بالكامل - V4 - Adaptive Hybrid Weights Support)
3
 
 
4
  import asyncio
5
+ import traceback
6
+ from typing import Any, Dict, List
7
  from datetime import datetime, timezone
8
  from collections import defaultdict
9
 
10
+ # (استيراد جميع المكونات الداخلية للمركز)
11
+ from .schemas import *
12
  from .policy_engine import PolicyEngine
13
  from .memory_store import MemoryStore
14
  from .statistical_analyzer import StatisticalAnalyzer
15
  from .reflector import Reflector
16
  from .curator import Curator
17
 
18
+ # استيراد لتحليل الارتباط (Whale Learning)
19
  try:
20
  import numpy as np
21
  from scipy.stats import pearsonr
22
  NUMPY_AVAILABLE = True
23
+ except ImportError:
24
+ print("❌ [HubManager] مكتبة numpy أو scipy غير مثبتة! لن يعمل تعلم الحيتان.")
25
  NUMPY_AVAILABLE = False
26
 
 
27
  class LearningHubManager:
28
+ def __init__(self, r2_service: Any, llm_service: Any, data_manager: Any):
29
+ print("🚀 Initializing Learning Hub Manager (V4 - Adaptive)...")
30
+
31
+ # 1. الخدمات الأساسية
 
 
 
 
 
 
 
 
 
 
 
32
  self.r2_service = r2_service
33
+ self.llm_service = llm_service
34
  self.data_manager = data_manager
35
 
36
+ # 2. تهيئة المكونات
37
  self.policy_engine = PolicyEngine()
38
  self.memory_store = MemoryStore(
39
+ r2_service=self.r2_service,
40
  policy_engine=self.policy_engine,
41
+ llm_service=self.llm_service
42
  )
43
+ self.reflector = Reflector(
 
 
44
  llm_service=self.llm_service,
45
  memory_store=self.memory_store
46
  )
47
+ self.curator = Curator(
48
  llm_service=self.llm_service,
49
  memory_store=self.memory_store
50
  )
 
 
51
  self.statistical_analyzer = StatisticalAnalyzer(
52
  r2_service=self.r2_service,
53
  data_manager=self.data_manager
54
  )
55
+
56
+ # متغيرات حالة لتعلم الحيتان
57
  self.whale_learning_lock = asyncio.Lock()
58
+ self.optimal_whale_config = {}
59
+
60
  self.initialized = False
61
+ print("✅ Learning Hub Manager constructed. Ready for initialization.")
 
62
 
63
  async def initialize(self):
64
+ """تهيئة جميع الأنظمة الفرعية"""
65
+ if self.initialized: return
66
+ print("🔄 [HubManager] Initializing all sub-modules...")
67
+
68
+ # تهيئة المحلل الإحصائي (المسؤول عن الأوزان المتكيفة)
69
  await self.statistical_analyzer.initialize()
70
+
71
+ # تحميل إعدادات تعلم الحيتان
72
  if hasattr(self.r2_service, 'load_whale_learning_config_async'):
73
+ self.optimal_whale_config = await self.r2_service.load_whale_learning_config_async()
74
+ if self.optimal_whale_config:
75
+ print(f"✅ [HubManager] Loaded optimal whale config: {self.optimal_whale_config.get('best_metric', 'N/A')}")
76
+
 
 
 
 
77
  self.initialized = True
78
+ print("✅ [HubManager] All sub-modules initialized. Learning Hub is LIVE.")
 
79
 
80
  async def analyze_trade_and_learn(self, trade_object: Dict[str, Any], close_reason: str):
81
+ """الدالة الرئيسية للتعلم من الصفقات المغلقة"""
82
+ if not self.initialized: return
83
 
84
+ print(f"🧠 [HubManager] Learning from trade {trade_object.get('symbol')}...")
85
 
86
+ # 1. التعلم السريع (Reflector)
87
+ try:
88
+ await self.reflector.analyze_trade_outcome(trade_object, close_reason)
89
+ except Exception as e:
90
+ print(f"❌ [HubManager] Reflector failed: {e}")
 
 
 
91
 
92
+ # 2. التعلم البطيء وتكييف الأوزان (StatisticalAnalyzer)
93
  try:
94
  await self.statistical_analyzer.update_statistics(trade_object, close_reason)
95
  except Exception as e:
96
+ print(f"❌ [HubManager] StatisticalAnalyzer failed: {e}")
97
+
98
+ print(f"✅ [HubManager] Learning complete for {trade_object.get('symbol')}.")
99
 
100
  async def get_optimized_weights(self, market_condition: str = None) -> Dict[str, Any]:
101
+ """
102
+ جلب الأوزان المحسنة (بما في ذلك الأوزان الهجينة المتكيفة).
103
+ يستخدمها MLProcessor لتحديث معادلته الهجينة.
104
+ """
105
  if not self.initialized:
106
+ return await self.statistical_analyzer.get_default_strategy_weights()
107
+
108
+ # إرجاع قاموس الأوزان الكامل من المحلل الإحصائي
109
  return self.statistical_analyzer.weights
110
 
111
+ # --- دوال مساعدة أخرى (للـ LLM وغيرها) ---
112
  async def get_active_context_for_llm(self, domain: str, query: str) -> str:
113
+ if not self.initialized: return "Learning Hub not initialized."
 
 
 
114
  return await self.memory_store.get_active_context(domain, query)
115
+
116
  async def get_statistical_feedback_for_llm(self, entry_strategy: str) -> str:
117
+ if not self.initialized: return "Learning Hub not initialized."
 
 
 
118
  best_profile = await self.statistical_analyzer.get_best_exit_profile(entry_strategy)
119
  if best_profile != "unknown":
120
  return f"Statistical Feedback: For '{entry_strategy}', '{best_profile}' exit profile performed best."
121
  return "No statistical feedback available yet."
122
 
123
+ async def get_statistical_news_score(self, raw_vader_score: float) -> float:
124
+ if not self.initialized: return 0.0
125
+ return await self.statistical_analyzer.get_statistical_vader_pnl(raw_vader_score)
126
+
127
  async def run_distillation_check(self):
128
+ """تشغيل دوري للتقطير (Curator)"""
129
+ if not self.initialized: return
130
+ # print("ℹ️ [HubManager] Running distillation check...")
131
  for domain in self.memory_store.domain_files.keys():
132
+ await self.curator.check_and_distill_domain(domain)
 
 
 
133
 
134
  async def shutdown(self):
135
+ """حفظ كل البيانات عند الإغلاق"""
136
+ if not self.initialized: return
137
+ print("🔄 [HubManager] Shutting down... Saving learning data.")
138
  try:
139
+ # المحلل الإحصائي يحفظ الأوزان المتكيفة وسجل الأداء
140
  await self.statistical_analyzer.save_weights_to_r2()
141
  await self.statistical_analyzer.save_performance_history()
142
  await self.statistical_analyzer.save_exit_profile_effectiveness()
143
  await self.statistical_analyzer.save_vader_effectiveness()
144
+ print("✅ [HubManager] Data saved successfully.")
145
  except Exception as e:
146
+ print(f"❌ [HubManager] Save failed: {e}")
147
 
148
+ # --- Whale Learning Loop (كما هي من V3) ---
149
  async def run_whale_learning_check(self):
150
+ if not self.initialized: await asyncio.sleep(60)
151
+ print(f"🧠 [Whale-Logger] Starting background learning loop...")
152
+ await asyncio.sleep(600)
 
153
  while True:
154
  try:
 
 
 
 
155
  pending = await self.r2_service.get_pending_whale_learning_records_async()
156
  if not pending:
157
  await asyncio.sleep(600)
 
162
  try:
163
  target_time = datetime.fromisoformat(record['target_time_utc'])
164
  if now_utc >= target_time:
165
+ symbol = record['symbol']
166
+ target_price = await self.data_manager.get_latest_price_async(symbol)
167
+ if target_price and target_price > 0 and record['start_price_usd'] > 0:
 
 
 
 
168
  pct_change = ((target_price - record['start_price_usd']) / record['start_price_usd']) * 100
169
+ record.update({'target_price_usd': target_price, 'price_change_percentage': pct_change, 'status': "COMPLETED"})
170
+ await self.r2_service.update_completed_whale_learning_record_async(record)
171
+ except Exception: pass
172
+
 
 
 
 
 
 
173
  await self.update_optimal_whale_window()
174
+ await asyncio.sleep(300)
175
  except Exception as e:
176
+ print(f"❌ [Whale-Logger] Error: {e}")
177
  await asyncio.sleep(600)
178
 
179
  async def update_optimal_whale_window(self):
180
+ if not NUMPY_AVAILABLE: return
 
181
  async with self.whale_learning_lock:
182
  try:
 
 
183
  all_completed = await self.r2_service.get_all_completed_whale_records_async()
184
+ if len(all_completed) < 20: return
 
185
 
186
  price_changes = []
187
  metrics_data = defaultdict(lambda: defaultdict(list))
188
  windows = ['30m', '1h', '2h', '4h', '24h']
189
  metric_keys = ['relative_net_flow_percent', 'transaction_density', 'net_flow_usd']
190
+
191
  for r in all_completed:
192
+ if r.get('price_change_percentage') is None: continue
 
193
  price_changes.append(r['price_change_percentage'])
194
  analysis = r.get('window_analysis', {})
195
  for w in windows:
 
197
  metrics_data[w][k].append(analysis.get(w, {}).get(k, 0.0))
198
 
199
  price_np = np.array(price_changes)
200
+ best_corr = 0
201
  best_key = None
202
 
203
  for w in windows:
204
  for k in metric_keys:
205
  metric_np = np.array(metrics_data[w][k])
206
+ if len(metric_np) == len(price_np):
207
+ corr, p_val = pearsonr(metric_np, price_np)
 
 
 
208
  if not np.isnan(corr) and p_val < 0.1 and abs(corr) > best_corr:
209
+ best_corr = abs(corr)
210
  best_key = f"{w}_{k}"
211
 
212
  if best_key:
213
  w, m = best_key.split('_', 1)
214
+ new_config = {"best_window": w, "best_metric": m, "correlation_score": best_corr, "total_samples": len(price_np), "last_updated_utc": datetime.now(timezone.utc).isoformat()}
 
 
 
 
 
 
215
  self.optimal_whale_config = new_config
216
+ await self.r2_service.save_whale_learning_config_async(new_config)
217
+ print(f"🏆 [Whale-Teacher] New best signal: {m} on {w} (Corr: {best_corr:.2f})")
218
+
219
  except Exception as e:
220
+ print(f"❌ [Whale-Teacher] Error: {e}")