Riy777 commited on
Commit
1c1eb92
·
1 Parent(s): 0d0a501

Create guard_engine.py

Browse files
Files changed (1) hide show
  1. ml_engine/guard_engine.py +132 -0
ml_engine/guard_engine.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ml_engine/guard_engine.py
2
+ # (V1.0 - Guard Exit Engine V2 - High Precision Protector)
3
+
4
+ import os
5
+ import joblib
6
+ import numpy as np
7
+ import pandas as pd
8
+ import pandas_ta as ta
9
+ import xgboost as xgb
10
+ import logging
11
+ import traceback
12
+
13
+ # إعداد تسجيل بسيط للأخطاء
14
+ logger = logging.getLogger("GuardEngine")
15
+
16
+ class GuardEngine:
17
+ def __init__(self, models_dir="ml_models/guard_v2"):
18
+ self.models_dir = models_dir
19
+ self.exit_model = None
20
+ self.exit_features = None
21
+ self.initialized = False
22
+
23
+ # إعدادات الحارس (V2 Settings)
24
+ self.EXIT_THRESHOLD = 0.80 # العتبة الذهبية التي اكتشفناها في الاختبار
25
+
26
+ async def initialize(self):
27
+ """تحميل نموذج الحماية وقائمة ميزاته"""
28
+ if self.initialized: return
29
+
30
+ try:
31
+ print(f"🛡️ [GuardEngine] Loading V2 models from {self.models_dir}...")
32
+
33
+ # مسارات الملفات (تأكد من نقلها من درايف إلى هذا المجلد في الخادم)
34
+ model_path = os.path.join(self.models_dir, "Guard_Exit_V2.json")
35
+ feat_path = os.path.join(self.models_dir, "Guard_Exit_V2_features.pkl")
36
+
37
+ if os.path.exists(model_path) and os.path.exists(feat_path):
38
+ self.exit_model = xgb.Booster()
39
+ self.exit_model.load_model(model_path)
40
+ self.exit_features = joblib.load(feat_path)
41
+ self.initialized = True
42
+ print(f"✅ [GuardEngine] Exit Guard V2 Loaded! (Threshold: {self.EXIT_THRESHOLD})")
43
+ else:
44
+ print(f"❌ [GuardEngine] CRITICAL: Model files missing in {self.models_dir}")
45
+
46
+ except Exception as e:
47
+ print(f"❌ [GuardEngine] Initialization failed: {e}")
48
+ traceback.print_exc()
49
+
50
+ def _engineer_features(self, df_raw):
51
+ """
52
+ مصنع الميزات الحي (يجب أن يطابق كولاب 100%)
53
+ """
54
+ df = df_raw.copy()
55
+
56
+ # 1. ميزات تيتان (Titan Features)
57
+ df['RSI_14'] = ta.rsi(df['close'], length=14)
58
+ df['MFI_14'] = ta.mfi(df['high'], df['low'], df['close'], df['volume'], length=14)
59
+ macd = ta.macd(df['close'])
60
+ if macd is not None:
61
+ df['MACD'] = macd.iloc[:, 0]
62
+ df['MACD_Hist'] = macd.iloc[:, 1]
63
+
64
+ df['ADX_14'] = ta.adx(df['high'], df['low'], df['close'], length=14).iloc[:, 0]
65
+
66
+ for p in [9, 21, 50, 200]:
67
+ ema = ta.ema(df['close'], length=p)
68
+ df[f'EMA_{p}'] = ema
69
+ df[f'Dist_EMA_{p}'] = (df['close'] / ema) - 1
70
+
71
+ df['ATR_14'] = ta.atr(df['high'], df['low'], df['close'], length=14)
72
+ df['ATR_Pct'] = df['ATR_14'] / df['close']
73
+
74
+ bb = ta.bbands(df['close'], length=20, std=2)
75
+ if bb is not None:
76
+ df['BB_Width'] = (bb.iloc[:, 2] - bb.iloc[:, 0]) / bb.iloc[:, 1]
77
+ df['BB_Pos'] = (df['close'] - bb.iloc[:, 0]) / (bb.iloc[:, 2] - bb.iloc[:, 0])
78
+
79
+ # 2. ميزات الأنماط (Pattern Features) - Lookback=12
80
+ for i in range(1, 13):
81
+ df[f'Close_R_{i}'] = df['close'].shift(i) / df['close']
82
+ df[f'Vol_R_{i}'] = df['volume'].shift(i) / (df['volume'] + 1e-9)
83
+
84
+ df['Body_Size'] = abs(df['close'] - df['open']) / df['open']
85
+ df['Upper_Wick'] = (df['high'] - np.maximum(df['close'], df['open'])) / df['open']
86
+ df['Lower_Wick'] = (np.minimum(df['close'], df['open']) - df['low']) / df['open']
87
+
88
+ return df
89
+
90
+ def check_exit_signal(self, symbol, ohlcv_5m):
91
+ """
92
+ الفحص الحي للخروج: يستقبل شموع 5m ويعيد قرار الحماية
93
+ """
94
+ if not self.initialized or not self.exit_model:
95
+ return {'action': 'HOLD', 'confidence': 0.0, 'reason': 'Guard not ready'}
96
+
97
+ try:
98
+ if len(ohlcv_5m) < 250: # نحتاج بيانات كافية للمؤشرات (200 EMA + هامش)
99
+ return {'action': 'HOLD', 'confidence': 0.0, 'reason': 'Not enough 5m data'}
100
+
101
+ # 1. تجهيز البيانات
102
+ df = pd.DataFrame(ohlcv_5m, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
103
+ df = self._engineer_features(df)
104
+
105
+ # نأخذ آخر صف فقط (الوضع الحالي)
106
+ latest_row = df.iloc[-1:].copy()
107
+
108
+ # 2. ترتيب الميزات بالضبط كما في التدريب
109
+ # (أي ميزة ناقصة سنملأها بـ NaN، وسيتعامل معها XGBoost)
110
+ dmatrix = xgb.DMatrix(latest_row[self.exit_features])
111
+
112
+ # 3. التنبؤ
113
+ prob = self.exit_model.predict(dmatrix)[0]
114
+
115
+ # 4. اتخاذ القرار بناءً على العتبة الذهبي�� (0.80)
116
+ if prob >= self.EXIT_THRESHOLD:
117
+ return {
118
+ 'action': 'EXIT_NOW',
119
+ 'confidence': float(prob),
120
+ 'reason': f'Guard V2 Exit Signal (Conf: {prob:.2f} >= {self.EXIT_THRESHOLD})'
121
+ }
122
+ else:
123
+ return {
124
+ 'action': 'HOLD',
125
+ 'confidence': float(prob),
126
+ 'reason': f'Guard V2 Secure (Conf: {prob:.2f})'
127
+ }
128
+
129
+ except Exception as e:
130
+ # logger.error(f"Guard check failed for {symbol}: {e}")
131
+ # traceback.print_exc()
132
+ return {'action': 'ERROR', 'confidence': 0.0, 'reason': str(e)}