File size: 5,639 Bytes
0bf918d
6d09aa0
8961ae5
69e65e0
 
0bf918d
69e65e0
 
8961ae5
 
69e65e0
6d09aa0
8961ae5
69e65e0
8961ae5
69e65e0
8961ae5
6d09aa0
69e65e0
 
 
6d09aa0
69e65e0
0bf918d
 
69e65e0
8961ae5
69e65e0
 
6d09aa0
69e65e0
8961ae5
 
69e65e0
6d09aa0
0bf918d
69e65e0
 
 
 
6d09aa0
69e65e0
6d09aa0
69e65e0
 
 
8961ae5
 
 
6d09aa0
8961ae5
6d09aa0
bf478e8
69e65e0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8961ae5
69e65e0
6d09aa0
8961ae5
69e65e0
 
6d09aa0
69e65e0
 
6d09aa0
69e65e0
8961ae5
 
 
69e65e0
8961ae5
69e65e0
 
 
 
 
 
8961ae5
69e65e0
 
 
8961ae5
69e65e0
 
8961ae5
69e65e0
 
 
 
8961ae5
69e65e0
 
 
 
6d09aa0
69e65e0
 
6d09aa0
8961ae5
69e65e0
 
 
 
6d09aa0
 
 
69e65e0
 
 
 
 
 
8961ae5
69e65e0
6d09aa0
 
 
 
 
 
 
 
 
0bf918d
6d09aa0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# ml_engine/patterns.py
# (V11.1 - XGBoost Multi-Timeframe Engine with Memory Management)

import os
import json
import numpy as np
import pandas as pd
import xgboost as xgb
import asyncio
import io
import logging
import gc # استيراد garbage collector لتنظيف الذاكرة

# استيراد الـ Pipeline الجديد
try:
    from .xgboost_pattern_v2 import transform_candles_for_ml
except ImportError:
    print("❌ [PatternEngineV11.1] فشل استيراد 'xgboost_pattern_v2'. تأكد من وجود الملف.")
    transform_candles_for_ml = None

# إعداد التسجيل
logging.basicConfig(level=logging.INFO, format='%(asctime)s - [PatternEngine] - %(message)s')
logger = logging.getLogger(__name__)

class ChartPatternAnalyzer:
    def __init__(self, r2_service=None, models_dir="ml_models/xgboost_pattern2"):
        """
        تهيئة محرك الأنماط الجديد المعتمد على XGBoost.
        Args:
            r2_service: خدمة R2 (اختياري).
            models_dir: المجلد المحلي الذي يحتوي على نماذج JSON.
        """
        self.r2_service = r2_service
        self.models_dir = models_dir
        self.models = {} # لتخزين النماذج المحملة
        
        # الأطر الزمنية المدعومة وأوزان التصويت الجديدة (التركيز على القصير)
        self.timeframe_weights = {
            '15m': 0.40,
            '1h': 0.30,
            '5m': 0.20,
            '4h': 0.10,
            '1d': 0.00
        }
        self.supported_timeframes = list(self.timeframe_weights.keys())
        self.initialized = False

    async def initialize(self):
        """
        تحميل جميع نماذج XGBoost المتوفرة.
        """
        if self.initialized: return True

        logger.info(f"بدء تحميل نماذج XGBoost من: {self.models_dir}...")
        if not os.path.exists(self.models_dir):
             logger.error(f"❌ المجلد غير موجود: {self.models_dir}")
             return False

        loaded_count = 0
        for tf in self.supported_timeframes:
            model_path = os.path.join(self.models_dir, f"xgb_{tf}.json")
            if os.path.exists(model_path):
                try:
                    model = xgb.Booster()
                    model.load_model(model_path)
                    self.models[tf] = model
                    loaded_count += 1
                    logger.info(f"   ✅ تم تحميل نموذج {tf}")
                except Exception as e:
                    logger.error(f"   ❌ فشل تحميل نموذج {tf}: {e}")
            else:
                if self.timeframe_weights.get(tf, 0) > 0:
                    logger.warning(f"   ⚠️ نموذج {tf} غير موجود (مطلوب بوزن {self.timeframe_weights[tf]}).")

        if loaded_count > 0:
            self.initialized = True
            logger.info(f"✅ تم تهيئة المحرك. النماذج المحملة: {loaded_count}/{len(self.supported_timeframes)}")
            return True
        else:
            logger.error("❌ لم يتم تحميل أي نموذج.")
            return False

    async def detect_chart_patterns(self, ohlcv_data: dict) -> dict:
        """
        تحليل الأنماط باستخدام النماذج المتاحة وتطبيق التصويت الموزون.
        """
        if not self.initialized or not transform_candles_for_ml:
            return self._get_empty_result("Engine not initialized or pipeline missing")

        details = {}
        weighted_score_sum = 0.0
        total_weight_used = 0.0

        for tf, model in self.models.items():
            candles = ohlcv_data.get(tf)
            if candles and len(candles) >= 200:
                try:
                    df = pd.DataFrame(candles, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
                    X_features = transform_candles_for_ml(df)
                    
                    if X_features is not None:
                        dtest = xgb.DMatrix(X_features)
                        prob_up = model.predict(dtest)[0] 
                        details[tf] = float(prob_up)
                        
                        weight = self.timeframe_weights.get(tf, 0.0)
                        if weight > 0:
                            weighted_score_sum += prob_up * weight
                            total_weight_used += weight
                except Exception:
                    details[tf] = None
            else:
                details[tf] = None

        final_score = 0.0
        if total_weight_used > 0:
            final_score = weighted_score_sum / total_weight_used
        
        pattern_text = "Neutral"
        if final_score >= 0.60: pattern_text = "Bullish Signal"
        elif final_score <= 0.40: pattern_text = "Bearish Signal"

        return {
            'pattern_detected': pattern_text,
            'pattern_confidence': float(final_score),
            'details': details
        }

    def _get_empty_result(self, reason=""):
        return {'pattern_detected': 'Neutral / Error', 'pattern_confidence': 0.0, 'details': {'error': reason}}

    # 🔴 دالة جديدة لتنظيف الذاكرة
    def clear_memory(self):
        """تحرير النماذج من الذاكرة"""
        self.models.clear()
        self.initialized = False
        gc.collect()
        logger.info("🧹 [PatternEngine] تم تنظيف الذاكرة وتحرير النماذج.")

print("✅ ML Module: Pattern Engine V11.1 (Memory Managed) loaded")