Riy777 commited on
Commit
e173390
·
1 Parent(s): eced413

Update ml_engine/indicators.py

Browse files
Files changed (1) hide show
  1. ml_engine/indicators.py +92 -66
ml_engine/indicators.py CHANGED
@@ -1,4 +1,4 @@
1
- # ml_engine/indicators.py (V10.2 - Bug FIX)
2
  import pandas as pd
3
  import pandas_ta as ta
4
  import numpy as np
@@ -24,15 +24,28 @@ class AdvancedTechnicalAnalyzer:
24
  'cycle': ['hull_ma', 'supertrend', 'zigzag', 'fisher_transform']
25
  }
26
 
27
- # 🔴 --- (V10.2 - تم إصلاح الأخطاء هنا) --- 🔴
28
  def calculate_v9_smart_features(self, dataframe: pd.DataFrame) -> Dict[str, float]:
29
  """
30
- (محدث V10.2) - (إصلاح أخطاء 'hurst' و 'atr_normalized_return')
 
31
  """
32
  if dataframe.empty or dataframe is None or len(dataframe) < 100:
33
  return {}
34
 
35
- features = {}
 
 
 
 
 
 
 
 
 
 
 
 
36
  try:
37
  # --- جلب البيانات الأساسية (Series) ---
38
  close = dataframe['close']
@@ -49,84 +62,97 @@ class AdvancedTechnicalAnalyzer:
49
  obv_series = ta.obv(close, volume)
50
 
51
  # --- 2. ميزات "نسب السعر" (Price Ratios) ---
52
- ema_50 = ta.ema(close, length=50).iloc[-1]
53
- ema_200 = ta.ema(close, length=200).iloc[-1]
54
- if ema_50 and ema_50 > 0: features['price_to_ema_50'] = (current_price / ema_50) - 1
55
- if ema_200 and ema_200 > 0: features['price_to_ema_200'] = (current_price / ema_200) - 1
56
- min_100 = low.tail(100).min(); max_100 = high.tail(100).max()
57
- if min_100 and min_100 > 0: features['price_to_min_100'] = (current_price / min_100) - 1
58
- if max_100 and max_100 > 0: features['price_to_max_100'] = (current_price / max_100) - 1
 
 
 
 
59
 
60
  # --- 3. ميزات "الميل" (Slope) ---
61
- ema_14 = ta.ema(close, length=14).iloc[-1]
62
- if ema_14 and ema_50: features['slope_14_50'] = (ema_14 - ema_50) / 14
63
- if adx_data is not None and not adx_data.empty:
64
- adx_series = adx_data['ADX_14']
65
- if adx_series is not None and not adx_series.empty:
66
- adx_ema_5 = ta.ema(adx_series, length=5).iloc[-1]; adx_ema_15 = ta.ema(adx_series, length=15).iloc[-1]
67
- if adx_ema_5 and adx_ema_15: features['adx_slope'] = (adx_ema_5 - adx_ema_15) / 5
68
 
69
  # --- 4. ميزات "الحجم" (Volume) و "السيولة" ---
70
- vol_ma_50 = volume.tail(50).mean(); vol_std_50 = volume.tail(50).std()
71
- if vol_std_50 and vol_std_50 > 0: features['volume_zscore_50'] = (volume.iloc[-1] - vol_ma_50) / vol_std_50
72
- vwap = ta.vwap(high, low, close, volume).iloc[-1]
73
- if vwap and vwap > 0: features['vwap_gap'] = (current_price - vwap) / vwap
74
- cmf = ta.cmf(high, low, close, volume, length=20)
75
- if cmf is not None and not cmf.empty: features['cmf_20'] = cmf.iloc[-1]
76
- vroc = ta.roc(volume, length=12)
77
- if vroc is not None and not vroc.empty: features['vroc_12'] = vroc.iloc[-1]
78
- if obv_series is not None and not obv_series.empty:
79
- obv_ema_10 = ta.ema(obv_series, length=10).iloc[-1]; obv_ema_30 = ta.ema(obv_series, length=30).iloc[-1]
80
- if obv_ema_10 and obv_ema_30: features['obv_slope'] = (obv_ema_10 - obv_ema_30) / 10
 
 
81
 
82
  # --- 5. ميزات "تجميعية" (Aggregative) ---
83
- if rsi_series is not None and not rsi_series.empty:
84
- features['rsi_14'] = rsi_series.iloc[-1]; features['rsi_mean_10'] = rsi_series.tail(10).mean(); features['rsi_std_10'] = rsi_series.tail(10).std()
85
- if mfi_series is not None and not mfi_series.empty:
86
- features['mfi_14'] = mfi_series.iloc[-1]; features['mfi_mean_10'] = mfi_series.tail(10).mean()
87
- if adx_data is not None and not adx_data.empty:
88
- adx_val = adx_data['ADX_14'].iloc[-1]
89
- if adx_val is not None: features['adx_14'] = adx_val
 
 
90
 
91
- # 🔴 --- (V10.2 - إصلاح 'atr_val') --- 🔴
92
- atr_val = None # (تعريف المتغير أولاً)
93
- if atr_series is not None and not atr_series.empty:
94
- atr_val = atr_series.iloc[-1]
95
- if atr_val and current_price > 0: features['atr_percent'] = (atr_val / current_price) * 100
96
- vol_of_vol_series = ta.atr(atr_series, length=10) # (Vol-of-Vol)
97
- if vol_of_vol_series is not None and not vol_of_vol_series.empty: features['vol_of_vol'] = vol_of_vol_series.iloc[-1]
98
-
99
- last_return = close.pct_change().iloc[-1]
100
- if atr_val and atr_val > 0:
101
- features['atr_normalized_return'] = last_return / atr_val
102
- else:
103
- features['atr_normalized_return'] = 0.0 # (قيمة افتراضية إذا فشل ATR)
104
 
105
- # 🔴 --- (V10.2 - إصلاح 'hurst') --- 🔴
106
- if HURST_AVAILABLE:
107
- try:
 
 
 
 
 
 
108
  hurst_series = close.tail(100).to_numpy()
109
  H, c, data = compute_Hc(hurst_series, kind='price', simplified=True)
110
  features['hurst'] = H
111
- except Exception:
112
- features['hurst'] = 0.5 # (محايد إذا فشلت المكتبة)
113
- else:
114
- features['hurst'] = 0.5 # (محايد إذا لم يتم تثبيت المكتبة)
115
 
116
- ppo_data = ta.ppo(close, fast=12, slow=26, signal=9)
117
- if ppo_data is not None and not ppo_data.empty:
118
- features['ppo_hist'] = ppo_data['PPOh_12_26_9'].iloc[-1]
119
- features['ppo_line'] = ppo_data['PPO_12_26_9'].iloc[-1]
 
 
120
 
121
  except Exception as e:
122
- # print(f"⚠️ خطأ في حساب ميزات V9.8 الذكية: {e}");
 
123
  pass
124
 
125
- final_features = {};
126
  for key, value in features.items():
127
- if value is not None and np.isfinite(value): final_features[key] = float(value)
128
- else: final_features[key] = 0.0
129
- return final_features
 
 
 
130
 
131
  # -----------------------------------------------------------------
132
  # --- (الدوال القديمة تبقى كما هي للاستخدامات الأخرى مثل Sentry 1m) ---
@@ -285,4 +311,4 @@ class AdvancedTechnicalAnalyzer:
285
  except Exception as e: pass;
286
  return {key: value for key, value in cycle.items() if value is not None and not np.isnan(value)};
287
 
288
- print("✅ ML Module: Technical Indicators loaded (V10.2 - Bug FIX)")
 
1
+ # ml_engine/indicators.py (V10.2 - Anti-Fragile FIX)
2
  import pandas as pd
3
  import pandas_ta as ta
4
  import numpy as np
 
24
  'cycle': ['hull_ma', 'supertrend', 'zigzag', 'fisher_transform']
25
  }
26
 
27
+ # 🔴 --- START OF UPDATED FUNCTION (V10.2 - Anti-Fragile) --- 🔴
28
  def calculate_v9_smart_features(self, dataframe: pd.DataFrame) -> Dict[str, float]:
29
  """
30
+ (محدث V10.2) - (إصلاح خطأ "الميزات المفقودة" بشكل نهائي)
31
+ - استخدام "قالب الميزات" لضمان إرجاع جميع الميزات دائماً.
32
  """
33
  if dataframe.empty or dataframe is None or len(dataframe) < 100:
34
  return {}
35
 
36
+ # --- (V10.2) الخطوة 1: تعريف "قالب الميزات" بالقيم الافتراضية ---
37
+ # (هذه هي جميع الميزات التي تدرب عليها نموذج V9.8)
38
+ features = {
39
+ 'price_to_ema_50': 0.0, 'price_to_ema_200': 0.0, 'price_to_min_100': 0.0,
40
+ 'price_to_max_100': 0.0, 'slope_14_50': 0.0, 'adx_slope': 0.0,
41
+ 'volume_zscore_50': 0.0, 'vwap_gap': 0.0, 'cmf_20': 0.0, 'vroc_12': 0.0,
42
+ 'obv_slope': 0.0, 'rsi_14': 50.0, 'rsi_mean_10': 50.0, 'rsi_std_10': 0.0,
43
+ 'mfi_14': 50.0, 'mfi_mean_10': 50.0, 'adx_14': 20.0, 'atr_percent': 0.0,
44
+ 'vol_of_vol': 0.0, 'atr_normalized_return': 0.0, 'hurst': 0.5,
45
+ 'ppo_hist': 0.0, 'ppo_line': 0.0
46
+ # (ميزات مونت كارلو ستضاف لاحقاً في data_manager)
47
+ }
48
+
49
  try:
50
  # --- جلب البيانات الأساسية (Series) ---
51
  close = dataframe['close']
 
62
  obv_series = ta.obv(close, volume)
63
 
64
  # --- 2. ميزات "نسب السعر" (Price Ratios) ---
65
+ try:
66
+ ema_50 = ta.ema(close, length=50).iloc[-1]
67
+ ema_200 = ta.ema(close, length=200).iloc[-1]
68
+ if ema_50 and ema_50 > 0: features['price_to_ema_50'] = (current_price / ema_50) - 1
69
+ if ema_200 and ema_200 > 0: features['price_to_ema_200'] = (current_price / ema_200) - 1
70
+ min_100 = low.tail(100).min(); max_100 = high.tail(100).max()
71
+ if min_100 and min_100 > 0: features['price_to_min_100'] = (current_price / min_100) - 1
72
+ if max_100 and max_100 > 0: features['price_to_max_100'] = (current_price / max_100) - 1
73
+ ema_14 = ta.ema(close, length=14).iloc[-1]
74
+ if ema_14 and ema_50: features['slope_14_50'] = (ema_14 - ema_50) / 14
75
+ except Exception: pass # (فشل هذا الجزء، ستبقى القيم الافتراضية)
76
 
77
  # --- 3. ميزات "الميل" (Slope) ---
78
+ try:
79
+ if adx_data is not None and not adx_data.empty:
80
+ adx_series = adx_data['ADX_14']
81
+ if adx_series is not None and not adx_series.empty:
82
+ adx_ema_5 = ta.ema(adx_series, length=5).iloc[-1]; adx_ema_15 = ta.ema(adx_series, length=15).iloc[-1]
83
+ if adx_ema_5 and adx_ema_15: features['adx_slope'] = (adx_ema_5 - adx_ema_15) / 5
84
+ except Exception: pass # (فشل هذا الجزء، ستبقى القيم الافتراضية)
85
 
86
  # --- 4. ميزات "الحجم" (Volume) و "السيولة" ---
87
+ try:
88
+ vol_ma_50 = volume.tail(50).mean(); vol_std_50 = volume.tail(50).std()
89
+ if vol_std_50 and vol_std_50 > 0: features['volume_zscore_50'] = (volume.iloc[-1] - vol_ma_50) / vol_std_50
90
+ vwap = ta.vwap(high, low, close, volume).iloc[-1]
91
+ if vwap and vwap > 0: features['vwap_gap'] = (current_price - vwap) / vwap
92
+ cmf = ta.cmf(high, low, close, volume, length=20)
93
+ if cmf is not None and not cmf.empty: features['cmf_20'] = cmf.iloc[-1]
94
+ vroc = ta.roc(volume, length=12)
95
+ if vroc is not None and not vroc.empty: features['vroc_12'] = vroc.iloc[-1]
96
+ if obv_series is not None and not obv_series.empty:
97
+ obv_ema_10 = ta.ema(obv_series, length=10).iloc[-1]; obv_ema_30 = ta.ema(obv_series, length=30).iloc[-1]
98
+ if obv_ema_10 and obv_ema_30: features['obv_slope'] = (obv_ema_10 - obv_ema_30) / 10
99
+ except Exception: pass # (فشل هذا الجزء، ستبقى القيم الافتراضية)
100
 
101
  # --- 5. ميزات "تجميعية" (Aggregative) ---
102
+ try:
103
+ if rsi_series is not None and not rsi_series.empty:
104
+ features['rsi_14'] = rsi_series.iloc[-1]; features['rsi_mean_10'] = rsi_series.tail(10).mean(); features['rsi_std_10'] = rsi_series.tail(10).std()
105
+ if mfi_series is not None and not mfi_series.empty:
106
+ features['mfi_14'] = mfi_series.iloc[-1]; features['mfi_mean_10'] = mfi_series.tail(10).mean()
107
+ if adx_data is not None and not adx_data.empty:
108
+ adx_val = adx_data['ADX_14'].iloc[-1]
109
+ if adx_val is not None: features['adx_14'] = adx_val
110
+ except Exception: pass # (فشل هذا الجزء، ستبقى القيم الافتراضية)
111
 
112
+ # --- 6. ميزات "التقلب" (Volatility) ---
113
+ try:
114
+ atr_val = None
115
+ if atr_series is not None and not atr_series.empty:
116
+ atr_val = atr_series.iloc[-1]
117
+ if atr_val and current_price > 0: features['atr_percent'] = (atr_val / current_price) * 100
118
+ vol_of_vol_series = ta.atr(atr_series, length=10) # (Vol-of-Vol)
119
+ if vol_of_vol_series is not None and not vol_of_vol_series.empty: features['vol_of_vol'] = vol_of_vol_series.iloc[-1]
 
 
 
 
 
120
 
121
+ last_return = close.pct_change().iloc[-1]
122
+ if atr_val and atr_val > 0:
123
+ features['atr_normalized_return'] = last_return / atr_val
124
+ # (لا نحتاج else، القيمة الافتراضية 0.0 موجودة)
125
+ except Exception: pass # (فشل هذا الجزء، ستبقى القيم الافتراضية)
126
+
127
+ # --- 7. ميزات النظام (Regime Features) ---
128
+ try:
129
+ if HURST_AVAILABLE:
130
  hurst_series = close.tail(100).to_numpy()
131
  H, c, data = compute_Hc(hurst_series, kind='price', simplified=True)
132
  features['hurst'] = H
133
+ # (لا نحتاج else، القيمة الافتراضية 0.5 موجودة)
134
+ except Exception: pass # (فشل هذا الجزء، ستبقى القيم الافتراضية)
 
 
135
 
136
+ try:
137
+ ppo_data = ta.ppo(close, fast=12, slow=26, signal=9)
138
+ if ppo_data is not None and not ppo_data.empty:
139
+ features['ppo_hist'] = ppo_data['PPOh_12_26_9'].iloc[-1]
140
+ features['ppo_line'] = ppo_data['PPO_12_26_9'].iloc[-1]
141
+ except Exception: pass # (فشل هذا الجزء، ستبقى القيم الافتراضية)
142
 
143
  except Exception as e:
144
+ # (فشل كبير، سنعيد القالب الافتراضي)
145
+ # print(f"⚠️ خطأ كارثي في حساب ميزات V9.8: {e}");
146
  pass
147
 
148
+ # (تنظيف نهائي للتأكد من عدم وجود NaN/Inf)
149
  for key, value in features.items():
150
+ if not np.isfinite(value):
151
+ features[key] = 0.0 # (إعادة التعيين إلى 0.0 إذا كان الحساب NaN)
152
+
153
+ return features
154
+ # 🔴 --- END OF UPDATED FUNCTION (V10.2) --- 🔴
155
+
156
 
157
  # -----------------------------------------------------------------
158
  # --- (الدوال القديمة تبقى كما هي للاستخدامات الأخرى مثل Sentry 1m) ---
 
311
  except Exception as e: pass;
312
  return {key: value for key, value in cycle.items() if value is not None and not np.isnan(value)};
313
 
314
+ print("✅ ML Module: Technical Indicators loaded (V10.2 - Anti-Fragile FIX)")