Riy777 commited on
Commit
66bf018
·
1 Parent(s): 5acd124

Update ml_engine/indicators.py

Browse files
Files changed (1) hide show
  1. ml_engine/indicators.py +133 -20
ml_engine/indicators.py CHANGED
@@ -1,10 +1,12 @@
1
- # ml_engine/indicators.py (V5.3 - Fixed VWAP DatetimeIndex Bug)
2
  import pandas as pd
3
  import pandas_ta as ta
4
  import numpy as np
 
5
 
6
  class AdvancedTechnicalAnalyzer:
7
  def __init__(self):
 
8
  self.indicators_config = {
9
  'trend': ['ema_9', 'ema_21', 'ema_50', 'ema_200', 'ichimoku', 'adx', 'parabolic_sar', 'dmi'],
10
  'momentum': ['rsi', 'stoch_rsi', 'macd', 'williams_r', 'cci', 'awesome_oscillator', 'momentum'],
@@ -13,6 +15,116 @@ class AdvancedTechnicalAnalyzer:
13
  'cycle': ['hull_ma', 'supertrend', 'zigzag', 'fisher_transform']
14
  }
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  def calculate_all_indicators(self, dataframe, timeframe):
17
  """حساب جميع المؤشرات الفنية للإطار الزمني المحدد"""
18
  if dataframe.empty or dataframe is None:
@@ -84,7 +196,8 @@ class AdvancedTechnicalAnalyzer:
84
  pass
85
 
86
  except Exception as e:
87
- print(f"⚠️ خطأ في حساب مؤشرات الاتجاه: {e}")
 
88
 
89
  return {key: value for key, value in trend.items() if value is not None and not np.isnan(value)}
90
 
@@ -125,7 +238,8 @@ class AdvancedTechnicalAnalyzer:
125
  momentum['williams_r'] = float(williams.iloc[-1])
126
 
127
  except Exception as e:
128
- print(f"⚠️ خطأ في حساب مؤشرات الزخم: {e}")
 
129
 
130
  return {key: value for key, value in momentum.items() if value is not None and not np.isnan(value)}
131
 
@@ -161,9 +275,9 @@ class AdvancedTechnicalAnalyzer:
161
  volatility['atr_percent'] = (atr_value / current_close) * 100
162
 
163
  except Exception as e:
164
- print(f"⚠️ خطأ في حساب مؤشرات التقلب: {e}")
 
165
 
166
- # (إصلاح V5.2: إعادة 'volatility' بدلاً من 'volume')
167
  return {key: value for key, value in volatility.items() if value is not None and not np.isnan(value)}
168
 
169
  def _calculate_volume_indicators(self, dataframe, timeframe):
@@ -182,32 +296,29 @@ class AdvancedTechnicalAnalyzer:
182
  if 'timestamp' in df_vwap.columns:
183
  df_vwap['timestamp'] = pd.to_datetime(df_vwap['timestamp'], unit='ms')
184
  df_vwap.set_index('timestamp', inplace=True)
 
 
 
185
  else:
186
  raise ValueError("DataFrame needs 'timestamp' column or DatetimeIndex")
187
 
188
  df_vwap.sort_index(inplace=True)
189
 
190
- # 🔴 --- START OF CHANGE (V5.3 - FIX) --- 🔴
191
- # (إصلاح: إزالة reset_index() للحفاظ على DatetimeIndex لـ ta.vwap)
192
- # df_vwap_reset = df_vwap.reset_index() # <-- هذا السطر يسبب المشكلة
193
-
194
  volume_weighted_average_price = ta.vwap(
195
- high=df_vwap['high'], # (استخدام df_vwap مباشرة)
196
- low=df_vwap['low'], # (استخدام df_vwap مباشرة)
197
- close=df_vwap['close'], # (استخدام df_vwap مباشرة)
198
- volume=df_vwap['volume'] # (استخدام df_vwap مباشرة)
199
  )
200
- # 🔴 --- END OF CHANGE --- 🔴
201
 
202
  if volume_weighted_average_price is not None and not volume_weighted_average_price.empty and not pd.isna(volume_weighted_average_price.iloc[-1]):
203
  volume['vwap'] = float(volume_weighted_average_price.iloc[-1])
204
 
205
  except Exception as vwap_error:
206
- # (تم تعديل الشرط لطباعة الخطأ إذا لم يكن التحذير المتوقع)
207
  if "VWAP requires an ordered DatetimeIndex" not in str(vwap_error) and "Index" not in str(vwap_error):
208
- print(f"⚠️ خطأ في حساب VWAP لـ {timeframe}: {vwap_error}")
 
209
 
210
- # (محاولة حساب احتياطي بسيط إذا فشل الحساب المعتمد على الفهرس)
211
  if len(dataframe) >= 20:
212
  try:
213
  typical_price = (dataframe['high'] + dataframe['low'] + dataframe['close']) / 3
@@ -244,7 +355,8 @@ class AdvancedTechnicalAnalyzer:
244
  pass
245
 
246
  except Exception as e:
247
- print(f"⚠️ خطأ في حساب مؤشرات الحجم: {e}")
 
248
 
249
  return {key: value for key, value in volume.items() if value is not None and not np.isnan(value)}
250
 
@@ -269,8 +381,9 @@ class AdvancedTechnicalAnalyzer:
269
  cycle['supertrend'] = float(supertrend_value.iloc[-1])
270
 
271
  except Exception as e:
272
- print(f"⚠️ خطأ في حساب مؤشرات الدورة: {e}")
 
273
 
274
  return {key: value for key, value in cycle.items() if value is not None and not np.isnan(value)}
275
 
276
- print("✅ ML Module: Technical Indicators loaded (V5.3 - VWAP DatetimeIndex Fix)")
 
1
+ # ml_engine/indicators.py (V9.1 - Smart Feature Engineering)
2
  import pandas as pd
3
  import pandas_ta as ta
4
  import numpy as np
5
+ from typing import Dict
6
 
7
  class AdvancedTechnicalAnalyzer:
8
  def __init__(self):
9
+ # (هذا الكونفيغ سيبقى للاستخدامات القديمة مثل الحارس 1m)
10
  self.indicators_config = {
11
  'trend': ['ema_9', 'ema_21', 'ema_50', 'ema_200', 'ichimoku', 'adx', 'parabolic_sar', 'dmi'],
12
  'momentum': ['rsi', 'stoch_rsi', 'macd', 'williams_r', 'cci', 'awesome_oscillator', 'momentum'],
 
15
  'cycle': ['hull_ma', 'supertrend', 'zigzag', 'fisher_transform']
16
  }
17
 
18
+ # 🔴 --- START OF NEW FUNCTION (V9.1) --- 🔴
19
+ def calculate_v9_smart_features(self, dataframe: pd.DataFrame) -> Dict[str, float]:
20
+ """
21
+ (جديد V9.1) - (العقل الحسابي لنموذج الرانكر V9.1)
22
+ حساب "الميزات الذكية" المتقدمة المستوحاة من خطة GPT (للكاشف المصغر V9.1).
23
+ هذه الدالة مصممة لتغذية نموذج ML (مثل LightGBM) ببيانات غنية.
24
+ """
25
+ if dataframe.empty or dataframe is None or len(dataframe) < 100:
26
+ # (نحتاج 100 شمعة على الأقل لحساب الميزات الطويلة المدى مثل min(100))
27
+ # (ملاحظة: data_manager V9.1 سيطلب 200 شمعة لضمان عمل ema_200)
28
+ return {}
29
+
30
+ features = {}
31
+ try:
32
+ # --- جلب البيانات الأساسية (Series) ---
33
+ close = dataframe['close']
34
+ high = dataframe['high']
35
+ low = dataframe['low']
36
+ volume = dataframe['volume']
37
+ current_price = close.iloc[-1]
38
+
39
+ # --- 1. حساب مؤشرات السلسلة الكاملة (Series) ---
40
+ rsi_series = ta.rsi(close, length=14)
41
+ mfi_series = ta.mfi(high, low, close, volume, length=14)
42
+ atr_series = ta.atr(high, low, close, length=14)
43
+ adx_data = ta.adx(high, low, close, length=14)
44
+
45
+ # --- 2. ميزات "نسب السعر" (Price Ratios) - (لتحديد "القاع") ---
46
+ # (نسبة السعر إلى المتوسطات المتحركة)
47
+ ema_50 = ta.ema(close, length=50).iloc[-1]
48
+ ema_200 = ta.ema(close, length=200).iloc[-1]
49
+ if ema_50 and ema_50 > 0:
50
+ features['price_to_ema_50'] = (current_price / ema_50) - 1
51
+ if ema_200 and ema_200 > 0:
52
+ features['price_to_ema_200'] = (current_price / ema_200) - 1
53
+
54
+ # (نسبة السعر إلى أدنى/أعلى سعر)
55
+ min_100 = low.tail(100).min()
56
+ max_100 = high.tail(100).max()
57
+ if min_100 and min_100 > 0:
58
+ features['price_to_min_100'] = (current_price / min_100) - 1
59
+ if max_100 and max_100 > 0:
60
+ features['price_to_max_100'] = (current_price / max_100) - 1
61
+
62
+ # --- 3. ميزات "الميل" (Slope) - (لتحديد "تراكم الزخم") ---
63
+ ema_14 = ta.ema(close, length=14).iloc[-1]
64
+ if ema_14 and ema_50:
65
+ features['slope_14_50'] = (ema_14 - ema_50) / 14
66
+
67
+ # --- 4. ميزات "الحجم" (Volume) و "السيولة" ---
68
+ # (Z-Score للحجم)
69
+ vol_ma_50 = volume.tail(50).mean()
70
+ vol_std_50 = volume.tail(50).std()
71
+ if vol_std_50 and vol_std_50 > 0:
72
+ features['volume_zscore_50'] = (volume.iloc[-1] - vol_ma_50) / vol_std_50
73
+
74
+ # (فجوة VWAP)
75
+ vwap = ta.vwap(high, low, close, volume).iloc[-1]
76
+ if vwap and vwap > 0:
77
+ features['vwap_gap'] = (current_price - vwap) / vwap
78
+
79
+ # --- 5. ميزات "تجميعية" (Aggregative) - (لفهم السياق) ---
80
+ # (إحصائيات RSI)
81
+ if rsi_series is not None:
82
+ features['rsi_14'] = rsi_series.iloc[-1]
83
+ features['rsi_mean_10'] = rsi_series.tail(10).mean()
84
+ features['rsi_std_10'] = rsi_series.tail(10).std()
85
+
86
+ # (إحصائيات MFI)
87
+ if mfi_series is not None:
88
+ features['mfi_14'] = mfi_series.iloc[-1]
89
+ features['mfi_mean_10'] = mfi_series.tail(10).mean()
90
+
91
+ # (مؤشر ADX)
92
+ if adx_data is not None:
93
+ features['adx_14'] = adx_data['ADX_14'].iloc[-1]
94
+
95
+ # --- 6. ميزات "التقلب" (Volatility) ---
96
+ # (ATR كنسبة مئوية)
97
+ if atr_series is not None:
98
+ atr_val = atr_series.iloc[-1]
99
+ if atr_val and current_price > 0:
100
+ features['atr_percent'] = (atr_val / current_price) * 100
101
+
102
+ # (تطبيع العائد بالتقلب)
103
+ last_return = close.pct_change().iloc[-1]
104
+ if atr_val and atr_val > 0:
105
+ features['atr_normalized_return'] = last_return / atr_val
106
+
107
+ except Exception as e:
108
+ # (في التداول الحي، من الأفضل تسجيل الخطأ بدلاً من طباعته فقط)
109
+ # print(f"⚠️ خطأ في حساب ميزات V9.1 الذكية: {e}")
110
+ return {}
111
+
112
+ # (تنظيف: إزالة NaN أو Inf وضمان أن القيم أرقام عشرية)
113
+ final_features = {}
114
+ for key, value in features.items():
115
+ if value is not None and np.isfinite(value):
116
+ final_features[key] = float(value)
117
+ else:
118
+ final_features[key] = 0.0 # (استبدال القيم غير الصالحة بـ 0.0)
119
+
120
+ return final_features
121
+ # 🔴 --- END OF NEW FUNCTION (V9.1) --- 🔴
122
+
123
+
124
+ # -----------------------------------------------------------------
125
+ # --- (الدوال القديمة تبقى كما هي للاستخدامات الأخرى مثل Sentry 1m) ---
126
+ # -----------------------------------------------------------------
127
+
128
  def calculate_all_indicators(self, dataframe, timeframe):
129
  """حساب جميع المؤشرات الفنية للإطار الزمني المحدد"""
130
  if dataframe.empty or dataframe is None:
 
196
  pass
197
 
198
  except Exception as e:
199
+ # print(f"⚠️ خطأ في حساب مؤشرات الاتجاه: {e}")
200
+ pass
201
 
202
  return {key: value for key, value in trend.items() if value is not None and not np.isnan(value)}
203
 
 
238
  momentum['williams_r'] = float(williams.iloc[-1])
239
 
240
  except Exception as e:
241
+ # print(f"⚠️ خطأ في حساب مؤشرات الزخم: {e}")
242
+ pass
243
 
244
  return {key: value for key, value in momentum.items() if value is not None and not np.isnan(value)}
245
 
 
275
  volatility['atr_percent'] = (atr_value / current_close) * 100
276
 
277
  except Exception as e:
278
+ # print(f"⚠️ خطأ في حساب مؤشرات التقلب: {e}")
279
+ pass
280
 
 
281
  return {key: value for key, value in volatility.items() if value is not None and not np.isnan(value)}
282
 
283
  def _calculate_volume_indicators(self, dataframe, timeframe):
 
296
  if 'timestamp' in df_vwap.columns:
297
  df_vwap['timestamp'] = pd.to_datetime(df_vwap['timestamp'], unit='ms')
298
  df_vwap.set_index('timestamp', inplace=True)
299
+ elif not df_vwap.index.is_numeric():
300
+ # (محاولة تحويل الفهرس إذا كان هو التايم ستامب)
301
+ df_vwap.index = pd.to_datetime(df_vwap.index, unit='ms')
302
  else:
303
  raise ValueError("DataFrame needs 'timestamp' column or DatetimeIndex")
304
 
305
  df_vwap.sort_index(inplace=True)
306
 
 
 
 
 
307
  volume_weighted_average_price = ta.vwap(
308
+ high=df_vwap['high'],
309
+ low=df_vwap['low'],
310
+ close=df_vwap['close'],
311
+ volume=df_vwap['volume']
312
  )
 
313
 
314
  if volume_weighted_average_price is not None and not volume_weighted_average_price.empty and not pd.isna(volume_weighted_average_price.iloc[-1]):
315
  volume['vwap'] = float(volume_weighted_average_price.iloc[-1])
316
 
317
  except Exception as vwap_error:
 
318
  if "VWAP requires an ordered DatetimeIndex" not in str(vwap_error) and "Index" not in str(vwap_error):
319
+ # print(f"⚠️ خطأ في حساب VWAP لـ {timeframe}: {vwap_error}")
320
+ pass
321
 
 
322
  if len(dataframe) >= 20:
323
  try:
324
  typical_price = (dataframe['high'] + dataframe['low'] + dataframe['close']) / 3
 
355
  pass
356
 
357
  except Exception as e:
358
+ # print(f"⚠️ خطأ في حساب مؤشرات الحجم: {e}")
359
+ pass
360
 
361
  return {key: value for key, value in volume.items() if value is not None and not np.isnan(value)}
362
 
 
381
  cycle['supertrend'] = float(supertrend_value.iloc[-1])
382
 
383
  except Exception as e:
384
+ # print(f"⚠️ خطأ في حساب مؤشرات الدورة: {e}")
385
+ pass
386
 
387
  return {key: value for key, value in cycle.items() if value is not None and not np.isnan(value)}
388
 
389
+ print("✅ ML Module: Technical Indicators loaded (V9.1 - Smart Features Enabled)")