Riy777 commited on
Commit
e51f1a7
·
verified ·
1 Parent(s): ac465ec

Update ml_engine/guardian_hydra.py

Browse files
Files changed (1) hide show
  1. ml_engine/guardian_hydra.py +42 -24
ml_engine/guardian_hydra.py CHANGED
@@ -8,17 +8,21 @@ from collections import deque, defaultdict
8
  import traceback
9
  import sys
10
 
 
 
 
11
  class GuardianHydra:
12
  """
13
- GuardianHydra V1.4 (Configurable Verbosity)
14
- - Added set_silent_mode() to suppress logs during Backtesting.
 
15
  """
16
  def __init__(self, model_dir):
17
  self.model_dir = model_dir
18
  self.initialized = False
19
  self.models = {}
20
  self.feature_cols = []
21
- self.verbose = True # ✅ Default to True for Live System
22
 
23
  self.smoothing_buffer = defaultdict(lambda: {
24
  'crash': deque(maxlen=3),
@@ -27,11 +31,10 @@ class GuardianHydra:
27
  })
28
 
29
  self.ATR_PERIOD = 14
30
- # ✅ Silent check
31
  if self.verbose: print("🐲 [Hydra X-RAY] Instance Created. Waiting for data...")
32
 
33
  def set_silent_mode(self, silent=True):
34
- """ Control Logging Output (True = No Logs, False = X-RAY Logs) """
35
  self.verbose = not silent
36
 
37
  def initialize(self):
@@ -50,7 +53,7 @@ class GuardianHydra:
50
  self.feature_cols = joblib.load(feat_path)
51
  if self.verbose: print(f"✅ Features List Loaded ({len(self.feature_cols)} items)")
52
 
53
- # 2. Load Models (RAW)
54
  heads = ['crash', 'giveback', 'stagnation']
55
  for h in heads:
56
  model_path = os.path.join(self.model_dir, f"hydra_head_{h}_raw.json")
@@ -58,10 +61,27 @@ class GuardianHydra:
58
  if self.verbose: print(f"❌ Model missing: {model_path}")
59
  return False
60
 
 
61
  clf = xgb.XGBClassifier()
62
- clf.load_model(model_path)
63
- self.models[h] = clf
64
- if self.verbose: print(f"✅ Loaded Head: {h}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
  self.initialized = True
67
  if self.verbose: print(f"✅ [Hydra X-RAY] System Ready.")
@@ -81,10 +101,7 @@ class GuardianHydra:
81
 
82
  df_1m = pd.DataFrame(ohlcv_1m, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
83
 
84
- # [DIAGNOSTIC 1] Print Input Sample
85
  last_close = df_1m['close'].iloc[-1]
86
- if self.verbose:
87
- print(f"🔍 [Input Check] Last Close: {last_close} | Candles: {len(df_1m)}")
88
 
89
  if len(df_1m) < 50:
90
  if self.verbose: print(f"⚠️ [X-RAY] Not enough history: {len(df_1m)} < 50")
@@ -94,14 +111,9 @@ class GuardianHydra:
94
  df_1m['atr'] = ta.atr(df_1m['high'], df_1m['low'], df_1m['close'], length=self.ATR_PERIOD)
95
  df_1m['rsi'] = ta.rsi(df_1m['close'], length=14)
96
 
97
- # [DIAGNOSTIC 2] Check Indicators
98
  last_rsi = df_1m['rsi'].iloc[-1]
99
  last_atr = df_1m['atr'].iloc[-1]
100
 
101
- if (pd.isna(last_rsi) or pd.isna(last_atr)) and self.verbose:
102
- print(f"⚠️ [X-RAY] Indicators are NaN! RSI: {last_rsi}, ATR: {last_atr}")
103
-
104
- # ... rest of calculations ...
105
  bb = ta.bbands(df_1m['close'], length=20, std=2)
106
  if bb is not None:
107
  w_col = [c for c in bb.columns if 'BBB' in c]
@@ -126,7 +138,7 @@ class GuardianHydra:
126
 
127
  # Trade Context
128
  entry_price = float(trade_context.get('entry_price', 0.0))
129
- if entry_price == 0: entry_price = last_close # Fallback
130
 
131
  atr_val = last_atr if last_atr > 0 else (entry_price * 0.01)
132
  sl_dist_unit = 1.5 * atr_val
@@ -168,9 +180,6 @@ class GuardianHydra:
168
  vector[col] = 0.0
169
 
170
  if vector.isnull().values.any():
171
- if self.verbose:
172
- print("⚠️ [X-RAY] Final Vector contains NaNs! Model will fail or output 0.")
173
- print(vector.iloc[0].to_dict())
174
  vector = vector.fillna(0)
175
 
176
  return vector[self.feature_cols].astype(float)
@@ -189,7 +198,6 @@ class GuardianHydra:
189
  features = self._engineer_features(ohlcv_1m, ohlcv_5m, ohlcv_15m, trade_data)
190
 
191
  if features is None:
192
- if self.verbose: print(f"🚫 [X-RAY] {symbol}: Feature Engineering Failed.")
193
  return {'action': 'HOLD', 'reason': 'Feat Fail'}
194
 
195
  probs = {}
@@ -197,8 +205,18 @@ class GuardianHydra:
197
 
198
  for h in ['crash', 'giveback', 'stagnation']:
199
  try:
200
- full_pred = self.models[h].predict_proba(features)
201
- raw_prob = full_pred[0][1]
 
 
 
 
 
 
 
 
 
 
202
  probs[h] = raw_prob
203
 
204
  if raw_prob > 0.0 and self.verbose:
 
8
  import traceback
9
  import sys
10
 
11
+ # ✅ GEM-FIX: استيراد Mixin لضمان التوافق (احتياطي)
12
+ from sklearn.base import ClassifierMixin
13
+
14
  class GuardianHydra:
15
  """
16
+ GuardianHydra V1.5 (Production Fix)
17
+ - Fixed: `_estimator_type` undefined error during load_model.
18
+ - Added: Manual type injection for XGBClassifier.
19
  """
20
  def __init__(self, model_dir):
21
  self.model_dir = model_dir
22
  self.initialized = False
23
  self.models = {}
24
  self.feature_cols = []
25
+ self.verbose = True
26
 
27
  self.smoothing_buffer = defaultdict(lambda: {
28
  'crash': deque(maxlen=3),
 
31
  })
32
 
33
  self.ATR_PERIOD = 14
 
34
  if self.verbose: print("🐲 [Hydra X-RAY] Instance Created. Waiting for data...")
35
 
36
  def set_silent_mode(self, silent=True):
37
+ """ Control Logging Output """
38
  self.verbose = not silent
39
 
40
  def initialize(self):
 
53
  self.feature_cols = joblib.load(feat_path)
54
  if self.verbose: print(f"✅ Features List Loaded ({len(self.feature_cols)} items)")
55
 
56
+ # 2. Load Models (RAW with Type Injection)
57
  heads = ['crash', 'giveback', 'stagnation']
58
  for h in heads:
59
  model_path = os.path.join(self.model_dir, f"hydra_head_{h}_raw.json")
 
61
  if self.verbose: print(f"❌ Model missing: {model_path}")
62
  return False
63
 
64
+ # ✅ إنشاء الكائن
65
  clf = xgb.XGBClassifier()
66
+
67
+ # =========================================================
68
+ # 💉 GEM-ARCHITECT PATCH: FORCE ESTIMATOR TYPE
69
+ # =========================================================
70
+ # هذا السطر يخبر XGBoost قسراً أن هذا الكائن هو Classifier
71
+ # لتجاوز فحص validate_loader الداخلي الذي يسبب الخطأ
72
+ clf._estimator_type = "classifier"
73
+ # =========================================================
74
+
75
+ try:
76
+ clf.load_model(model_path)
77
+ self.models[h] = clf
78
+ if self.verbose: print(f"✅ Loaded Head: {h}")
79
+ except Exception as load_err:
80
+ if self.verbose: print(f"⚠️ Failed to load {h} with XGBClassifier. Trying raw Booster...")
81
+ # Fallback to raw booster if classifier wrapper fails completely
82
+ bst = xgb.Booster()
83
+ bst.load_model(model_path)
84
+ self.models[h] = bst # Note: Prediction logic handles this differently usually, but we keep clf flow first.
85
 
86
  self.initialized = True
87
  if self.verbose: print(f"✅ [Hydra X-RAY] System Ready.")
 
101
 
102
  df_1m = pd.DataFrame(ohlcv_1m, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
103
 
 
104
  last_close = df_1m['close'].iloc[-1]
 
 
105
 
106
  if len(df_1m) < 50:
107
  if self.verbose: print(f"⚠️ [X-RAY] Not enough history: {len(df_1m)} < 50")
 
111
  df_1m['atr'] = ta.atr(df_1m['high'], df_1m['low'], df_1m['close'], length=self.ATR_PERIOD)
112
  df_1m['rsi'] = ta.rsi(df_1m['close'], length=14)
113
 
 
114
  last_rsi = df_1m['rsi'].iloc[-1]
115
  last_atr = df_1m['atr'].iloc[-1]
116
 
 
 
 
 
117
  bb = ta.bbands(df_1m['close'], length=20, std=2)
118
  if bb is not None:
119
  w_col = [c for c in bb.columns if 'BBB' in c]
 
138
 
139
  # Trade Context
140
  entry_price = float(trade_context.get('entry_price', 0.0))
141
+ if entry_price == 0: entry_price = last_close
142
 
143
  atr_val = last_atr if last_atr > 0 else (entry_price * 0.01)
144
  sl_dist_unit = 1.5 * atr_val
 
180
  vector[col] = 0.0
181
 
182
  if vector.isnull().values.any():
 
 
 
183
  vector = vector.fillna(0)
184
 
185
  return vector[self.feature_cols].astype(float)
 
198
  features = self._engineer_features(ohlcv_1m, ohlcv_5m, ohlcv_15m, trade_data)
199
 
200
  if features is None:
 
201
  return {'action': 'HOLD', 'reason': 'Feat Fail'}
202
 
203
  probs = {}
 
205
 
206
  for h in ['crash', 'giveback', 'stagnation']:
207
  try:
208
+ model = self.models[h]
209
+ # Check if it's a Raw Booster or Sklearn Wrapper
210
+ if isinstance(model, xgb.Booster):
211
+ # For raw booster, we need DMatrix
212
+ dtest = xgb.DMatrix(features)
213
+ # Booster returns raw probability directly for binary classification
214
+ raw_prob = model.predict(dtest)[0]
215
+ else:
216
+ # Sklearn Wrapper
217
+ full_pred = model.predict_proba(features)
218
+ raw_prob = full_pred[0][1]
219
+
220
  probs[h] = raw_prob
221
 
222
  if raw_prob > 0.0 and self.verbose: