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

Update ml_engine/patterns.py

Browse files
Files changed (1) hide show
  1. ml_engine/patterns.py +28 -52
ml_engine/patterns.py CHANGED
@@ -1,5 +1,5 @@
1
  # ml_engine/patterns.py
2
- # (V9.0 - XGBoost Multi-Timeframe Engine with Weighted Voting)
3
 
4
  import os
5
  import json
@@ -9,16 +9,17 @@ import xgboost as xgb
9
  import asyncio
10
  import io
11
  import logging
 
12
 
13
  # استيراد الـ Pipeline الجديد
14
  try:
15
  from .xgboost_pattern_v2 import transform_candles_for_ml
16
  except ImportError:
17
- print("❌ [PatternEngineV9] فشل استيراد 'xgboost_pattern_v2'. تأكد من وجود الملف.")
18
  transform_candles_for_ml = None
19
 
20
  # إعداد التسجيل
21
- logging.basicConfig(level=logging.INFO, format='%(asctime)s - [PatternEngineV9] - %(message)s')
22
  logger = logging.getLogger(__name__)
23
 
24
  class ChartPatternAnalyzer:
@@ -26,34 +27,31 @@ class ChartPatternAnalyzer:
26
  """
27
  تهيئة محرك الأنماط الجديد المعتمد على XGBoost.
28
  Args:
29
- r2_service: خدمة R2 (اختياري، للتحميل من السحابة مستقبلاً).
30
  models_dir: المجلد المحلي الذي يحتوي على نماذج JSON.
31
  """
32
  self.r2_service = r2_service
33
  self.models_dir = models_dir
34
- self.models = {} # لتخزين النماذج المحملة: {'15m': model, '1h': model, ...}
35
 
36
  # الأطر الزمنية المدعومة وأوزان التصويت الجديدة (التركيز على القصير)
37
  self.timeframe_weights = {
38
  '15m': 0.40,
39
  '1h': 0.30,
40
- '5m': 0.20, # (سنحاول تحميله إذا وُجد، وإلا سيتم تجاهله)
41
  '4h': 0.10,
42
- '1d': 0.00 # (وزن صفري، لكن قد نحلله كمرجع)
43
  }
44
-
45
  self.supported_timeframes = list(self.timeframe_weights.keys())
46
  self.initialized = False
47
 
48
  async def initialize(self):
49
  """
50
- تحميل جميع نماذج XGBoost المتوفرة في المجلد المحدد.
51
  """
52
- if self.initialized:
53
- return True
54
 
55
  logger.info(f"بدء تحميل نماذج XGBoost من: {self.models_dir}...")
56
-
57
  if not os.path.exists(self.models_dir):
58
  logger.error(f"❌ المجلد غير موجود: {self.models_dir}")
59
  return False
@@ -63,7 +61,6 @@ class ChartPatternAnalyzer:
63
  model_path = os.path.join(self.models_dir, f"xgb_{tf}.json")
64
  if os.path.exists(model_path):
65
  try:
66
- # تحميل النموذج باستخدام واجهة XGBoost الحديثة
67
  model = xgb.Booster()
68
  model.load_model(model_path)
69
  self.models[tf] = model
@@ -73,25 +70,19 @@ class ChartPatternAnalyzer:
73
  logger.error(f" ❌ فشل تحميل نموذج {tf}: {e}")
74
  else:
75
  if self.timeframe_weights.get(tf, 0) > 0:
76
- logger.warning(f" ⚠️ نموذج {tf} غير موجود (وهو مطلوب بوزن {self.timeframe_weights[tf]}).")
77
 
78
  if loaded_count > 0:
79
  self.initialized = True
80
- logger.info(f"✅ تم تهيئة المحرك بنجاح. عدد النماذج المحملة: {loaded_count}/{len(self.supported_timeframes)}")
81
  return True
82
  else:
83
- logger.error("❌ لم يتم تحميل أي نموذج. المحرك لن يعمل.")
84
  return False
85
 
86
  async def detect_chart_patterns(self, ohlcv_data: dict) -> dict:
87
  """
88
  تحليل الأنماط باستخدام النماذج المتاحة وتطبيق التصويت الموزون.
89
- Returns:
90
- dict: {
91
- 'pattern_detected': str (e.g., "Bullish (High Confidence)"),
92
- 'pattern_confidence': float (0.0 - 1.0, المجموع الموزون),
93
- 'details': dict (نتائج كل إطار زمني على حدة)
94
- }
95
  """
96
  if not self.initialized or not transform_candles_for_ml:
97
  return self._get_empty_result("Engine not initialized or pipeline missing")
@@ -100,53 +91,34 @@ class ChartPatternAnalyzer:
100
  weighted_score_sum = 0.0
101
  total_weight_used = 0.0
102
 
103
- # 1. التحليل لكل إطار زمني بالتوازي (أو تسلسلي سريع لأن النماذج خفيفة)
104
  for tf, model in self.models.items():
105
  candles = ohlcv_data.get(tf)
106
  if candles and len(candles) >= 200:
107
  try:
108
- # أ. تحويل الشموع إلى DataFrame
109
  df = pd.DataFrame(candles, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
110
-
111
- # ب. تجهيز البيانات باستخدام Pipeline V6
112
- # (ملاحظة: الدالة ليست async، لذا نستدعيها مباشرة)
113
  X_features = transform_candles_for_ml(df)
114
 
115
  if X_features is not None:
116
- # ج. التنبؤ (XGBoost يتوقع DMatrix)
117
  dtest = xgb.DMatrix(X_features)
118
- # predict تعيد احتمالية الفئة 1 (الصعود) لأن objective='binary:logistic'
119
  prob_up = model.predict(dtest)[0]
120
-
121
  details[tf] = float(prob_up)
122
 
123
- # د. تجميع النقاط الموزونة
124
  weight = self.timeframe_weights.get(tf, 0.0)
125
  if weight > 0:
126
  weighted_score_sum += prob_up * weight
127
  total_weight_used += weight
128
-
129
- except Exception as e:
130
- # logger.warning(f"فشل تحليل {tf}: {e}") # (تفعيل عند الحاجة للتنقيح)
131
  details[tf] = None
132
  else:
133
- details[tf] = None # بيانات غير كافية لهذا الإطار
134
 
135
- # 2. حساب النتيجة النهائية
136
  final_score = 0.0
137
  if total_weight_used > 0:
138
  final_score = weighted_score_sum / total_weight_used
139
 
140
- # 3. صياغة النتيجة النصية
141
- pattern_text = "Neutral / No Clear Pattern"
142
- if final_score >= 0.75:
143
- pattern_text = "Strong Bullish Signal"
144
- elif final_score >= 0.60:
145
- pattern_text = "Bullish Signal"
146
- elif final_score <= 0.25:
147
- pattern_text = "Strong Bearish Signal"
148
- elif final_score <= 0.40:
149
- pattern_text = "Bearish Signal"
150
 
151
  return {
152
  'pattern_detected': pattern_text,
@@ -155,10 +127,14 @@ class ChartPatternAnalyzer:
155
  }
156
 
157
  def _get_empty_result(self, reason=""):
158
- return {
159
- 'pattern_detected': 'Neutral / Error',
160
- 'pattern_confidence': 0.0,
161
- 'details': {'error': reason}
162
- }
 
 
 
 
163
 
164
- print("✅ ML Module: Pattern Engine V9.0 (XGBoost Multi-TF) loaded")
 
1
  # ml_engine/patterns.py
2
+ # (V11.1 - XGBoost Multi-Timeframe Engine with Memory Management)
3
 
4
  import os
5
  import json
 
9
  import asyncio
10
  import io
11
  import logging
12
+ import gc # استيراد garbage collector لتنظيف الذاكرة
13
 
14
  # استيراد الـ Pipeline الجديد
15
  try:
16
  from .xgboost_pattern_v2 import transform_candles_for_ml
17
  except ImportError:
18
+ print("❌ [PatternEngineV11.1] فشل استيراد 'xgboost_pattern_v2'. تأكد من وجود الملف.")
19
  transform_candles_for_ml = None
20
 
21
  # إعداد التسجيل
22
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - [PatternEngine] - %(message)s')
23
  logger = logging.getLogger(__name__)
24
 
25
  class ChartPatternAnalyzer:
 
27
  """
28
  تهيئة محرك الأنماط الجديد المعتمد على XGBoost.
29
  Args:
30
+ r2_service: خدمة R2 (اختياري).
31
  models_dir: المجلد المحلي الذي يحتوي على نماذج JSON.
32
  """
33
  self.r2_service = r2_service
34
  self.models_dir = models_dir
35
+ self.models = {} # لتخزين النماذج المحملة
36
 
37
  # الأطر الزمنية المدعومة وأوزان التصويت الجديدة (التركيز على القصير)
38
  self.timeframe_weights = {
39
  '15m': 0.40,
40
  '1h': 0.30,
41
+ '5m': 0.20,
42
  '4h': 0.10,
43
+ '1d': 0.00
44
  }
 
45
  self.supported_timeframes = list(self.timeframe_weights.keys())
46
  self.initialized = False
47
 
48
  async def initialize(self):
49
  """
50
+ تحميل جميع نماذج XGBoost المتوفرة.
51
  """
52
+ if self.initialized: return True
 
53
 
54
  logger.info(f"بدء تحميل نماذج XGBoost من: {self.models_dir}...")
 
55
  if not os.path.exists(self.models_dir):
56
  logger.error(f"❌ المجلد غير موجود: {self.models_dir}")
57
  return False
 
61
  model_path = os.path.join(self.models_dir, f"xgb_{tf}.json")
62
  if os.path.exists(model_path):
63
  try:
 
64
  model = xgb.Booster()
65
  model.load_model(model_path)
66
  self.models[tf] = model
 
70
  logger.error(f" ❌ فشل تحميل نموذج {tf}: {e}")
71
  else:
72
  if self.timeframe_weights.get(tf, 0) > 0:
73
+ logger.warning(f" ⚠️ نموذج {tf} غير موجود (مطلوب بوزن {self.timeframe_weights[tf]}).")
74
 
75
  if loaded_count > 0:
76
  self.initialized = True
77
+ logger.info(f"✅ تم تهيئة المحرك. النماذج المحملة: {loaded_count}/{len(self.supported_timeframes)}")
78
  return True
79
  else:
80
+ logger.error("❌ لم يتم تحميل أي نموذج.")
81
  return False
82
 
83
  async def detect_chart_patterns(self, ohlcv_data: dict) -> dict:
84
  """
85
  تحليل الأنماط باستخدام النماذج المتاحة وتطبيق التصويت الموزون.
 
 
 
 
 
 
86
  """
87
  if not self.initialized or not transform_candles_for_ml:
88
  return self._get_empty_result("Engine not initialized or pipeline missing")
 
91
  weighted_score_sum = 0.0
92
  total_weight_used = 0.0
93
 
 
94
  for tf, model in self.models.items():
95
  candles = ohlcv_data.get(tf)
96
  if candles and len(candles) >= 200:
97
  try:
 
98
  df = pd.DataFrame(candles, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
 
 
 
99
  X_features = transform_candles_for_ml(df)
100
 
101
  if X_features is not None:
 
102
  dtest = xgb.DMatrix(X_features)
 
103
  prob_up = model.predict(dtest)[0]
 
104
  details[tf] = float(prob_up)
105
 
 
106
  weight = self.timeframe_weights.get(tf, 0.0)
107
  if weight > 0:
108
  weighted_score_sum += prob_up * weight
109
  total_weight_used += weight
110
+ except Exception:
 
 
111
  details[tf] = None
112
  else:
113
+ details[tf] = None
114
 
 
115
  final_score = 0.0
116
  if total_weight_used > 0:
117
  final_score = weighted_score_sum / total_weight_used
118
 
119
+ pattern_text = "Neutral"
120
+ if final_score >= 0.60: pattern_text = "Bullish Signal"
121
+ elif final_score <= 0.40: pattern_text = "Bearish Signal"
 
 
 
 
 
 
 
122
 
123
  return {
124
  'pattern_detected': pattern_text,
 
127
  }
128
 
129
  def _get_empty_result(self, reason=""):
130
+ return {'pattern_detected': 'Neutral / Error', 'pattern_confidence': 0.0, 'details': {'error': reason}}
131
+
132
+ # 🔴 دالة جديدة لتنظيف الذاكرة
133
+ def clear_memory(self):
134
+ """تحرير النماذج من الذاكرة"""
135
+ self.models.clear()
136
+ self.initialized = False
137
+ gc.collect()
138
+ logger.info("🧹 [PatternEngine] تم تنظيف الذاكرة وتحرير النماذج.")
139
 
140
+ print("✅ ML Module: Pattern Engine V11.1 (Memory Managed) loaded")