Riy777 commited on
Commit
079f572
·
1 Parent(s): f9978e7

Create indicators.py

Browse files
Files changed (1) hide show
  1. ml_engine/indicators.py +290 -0
ml_engine/indicators.py ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ml_engine/indicators.py
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'],
11
+ 'volatility': ['bbands', 'atr', 'keltner', 'donchian', 'rvi'],
12
+ 'volume': ['vwap', 'obv', 'mfi', 'volume_profile', 'ad', 'volume_oscillator'],
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:
19
+ return {}
20
+
21
+ indicators = {}
22
+
23
+ try:
24
+ indicators.update(self._calculate_trend_indicators(dataframe))
25
+ indicators.update(self._calculate_momentum_indicators(dataframe))
26
+ indicators.update(self._calculate_volatility_indicators(dataframe))
27
+ indicators.update(self._calculate_volume_indicators(dataframe, timeframe))
28
+ indicators.update(self._calculate_cycle_indicators(dataframe))
29
+ except Exception as e:
30
+ print(f"⚠️ خطأ في حساب المؤشرات لـ {timeframe}: {e}")
31
+
32
+ return indicators
33
+
34
+ def _calculate_trend_indicators(self, dataframe):
35
+ """حساب مؤشرات الاتجاه"""
36
+ trend = {}
37
+
38
+ try:
39
+ # التحقق من وجود البيانات الأساسية
40
+ if dataframe is None or dataframe.empty or 'close' not in dataframe.columns:
41
+ return {}
42
+
43
+ # المتوسطات المتحركة
44
+ if len(dataframe) >= 9:
45
+ ema_9 = ta.ema(dataframe['close'], length=9)
46
+ if ema_9 is not None and not ema_9.empty and not pd.isna(ema_9.iloc[-1]):
47
+ trend['ema_9'] = float(ema_9.iloc[-1])
48
+
49
+ if len(dataframe) >= 21:
50
+ ema_21 = ta.ema(dataframe['close'], length=21)
51
+ if ema_21 is not None and not ema_21.empty and not pd.isna(ema_21.iloc[-1]):
52
+ trend['ema_21'] = float(ema_21.iloc[-1])
53
+
54
+ if len(dataframe) >= 50:
55
+ ema_50 = ta.ema(dataframe['close'], length=50)
56
+ if ema_50 is not None and not ema_50.empty and not pd.isna(ema_50.iloc[-1]):
57
+ trend['ema_50'] = float(ema_50.iloc[-1])
58
+
59
+ if len(dataframe) >= 200:
60
+ ema_200 = ta.ema(dataframe['close'], length=200)
61
+ if ema_200 is not None and not ema_200.empty and not pd.isna(ema_200.iloc[-1]):
62
+ trend['ema_200'] = float(ema_200.iloc[-1])
63
+
64
+ # إيشيموكو
65
+ if len(dataframe) >= 26:
66
+ try:
67
+ ichimoku = ta.ichimoku(dataframe['high'], dataframe['low'], dataframe['close'])
68
+ if ichimoku is not None and len(ichimoku) > 0:
69
+ # التحقق من أن ichimoku ليس None وأنه يحتوي على بيانات
70
+ conversion_line = ichimoku[0].get('ITS_9') if ichimoku[0] is not None else None
71
+ base_line = ichimoku[0].get('IKS_26') if ichimoku[0] is not None else None
72
+
73
+ if conversion_line is not None and not conversion_line.empty and not pd.isna(conversion_line.iloc[-1]):
74
+ trend['ichimoku_conversion'] = float(conversion_line.iloc[-1])
75
+ if base_line is not None and not base_line.empty and not pd.isna(base_line.iloc[-1]):
76
+ trend['ichimoku_base'] = float(base_line.iloc[-1])
77
+ except Exception as ichimoku_error:
78
+ print(f"⚠️ خطأ في حساب إيشيموكو: {ichimoku_error}")
79
+
80
+ # ADX - قوة الاتجاه
81
+ if len(dataframe) >= 14:
82
+ try:
83
+ adx_result = ta.adx(dataframe['high'], dataframe['low'], dataframe['close'], length=14)
84
+ if adx_result is not None and not adx_result.empty:
85
+ adx_value = adx_result.get('ADX_14')
86
+ if adx_value is not None and not adx_value.empty and not pd.isna(adx_value.iloc[-1]):
87
+ trend['adx'] = float(adx_value.iloc[-1])
88
+ except Exception as adx_error:
89
+ print(f"⚠️ خطأ في حساب ADX: {adx_error}")
90
+
91
+ except Exception as e:
92
+ print(f"⚠️ خطأ في حساب مؤشرات الاتجاه: {e}")
93
+
94
+ return {key: value for key, value in trend.items() if value is not None and not np.isnan(value)}
95
+
96
+ def _calculate_momentum_indicators(self, dataframe):
97
+ """حساب مؤشرات الزخم"""
98
+ momentum = {}
99
+
100
+ try:
101
+ # التحقق من وجود البيانات الأساسية
102
+ if dataframe is None or dataframe.empty or 'close' not in dataframe.columns:
103
+ return {}
104
+
105
+ # RSI
106
+ if len(dataframe) >= 14:
107
+ rsi = ta.rsi(dataframe['close'], length=14)
108
+ if rsi is not None and not rsi.empty and not pd.isna(rsi.iloc[-1]):
109
+ momentum['rsi'] = float(rsi.iloc[-1])
110
+
111
+ # MACD
112
+ if len(dataframe) >= 26:
113
+ macd = ta.macd(dataframe['close'])
114
+ if macd is not None and not macd.empty:
115
+ macd_hist = macd.get('MACDh_12_26_9')
116
+ macd_line = macd.get('MACD_12_26_9')
117
+
118
+ if macd_hist is not None and not macd_hist.empty and not pd.isna(macd_hist.iloc[-1]):
119
+ momentum['macd_hist'] = float(macd_hist.iloc[-1])
120
+ if macd_line is not None and not macd_line.empty and not pd.isna(macd_line.iloc[-1]):
121
+ momentum['macd_line'] = float(macd_line.iloc[-1])
122
+
123
+ # ستوكاستك RSI
124
+ if len(dataframe) >= 14:
125
+ stoch_rsi = ta.stochrsi(dataframe['close'], length=14)
126
+ if stoch_rsi is not None and not stoch_rsi.empty:
127
+ stoch_k = stoch_rsi.get('STOCHRSIk_14_14_3_3')
128
+ if stoch_k is not None and not stoch_k.empty and not pd.isna(stoch_k.iloc[-1]):
129
+ momentum['stoch_rsi_k'] = float(stoch_k.iloc[-1])
130
+
131
+ # ويليامز %R
132
+ if len(dataframe) >= 14:
133
+ williams = ta.willr(dataframe['high'], dataframe['low'], dataframe['close'], length=14)
134
+ if williams is not None and not williams.empty and not pd.isna(williams.iloc[-1]):
135
+ momentum['williams_r'] = float(williams.iloc[-1])
136
+
137
+ except Exception as e:
138
+ print(f"⚠️ خطأ في حساب مؤشرات الزخم: {e}")
139
+
140
+ return {key: value for key, value in momentum.items() if value is not None and not np.isnan(value)}
141
+
142
+ def _calculate_volatility_indicators(self, dataframe):
143
+ """حساب مؤشرات التقلب"""
144
+ volatility = {}
145
+
146
+ try:
147
+ # التحقق من وجود البيانات الأساسية
148
+ if dataframe is None or dataframe.empty or 'close' not in dataframe.columns:
149
+ return {}
150
+
151
+ # بولينجر باندز
152
+ if len(dataframe) >= 20:
153
+ bollinger_bands = ta.bbands(dataframe['close'], length=20, std=2)
154
+ if bollinger_bands is not None and not bollinger_bands.empty:
155
+ bb_lower = bollinger_bands.get('BBL_20_2.0')
156
+ bb_upper = bollinger_bands.get('BBU_20_2.0')
157
+ bb_middle = bollinger_bands.get('BBM_20_2.0')
158
+
159
+ if bb_lower is not None and not bb_lower.empty and not pd.isna(bb_lower.iloc[-1]):
160
+ volatility['bb_lower'] = float(bb_lower.iloc[-1])
161
+ if bb_upper is not None and not bb_upper.empty and not pd.isna(bb_upper.iloc[-1]):
162
+ volatility['bb_upper'] = float(bb_upper.iloc[-1])
163
+ if bb_middle is not None and not bb_middle.empty and not pd.isna(bb_middle.iloc[-1]):
164
+ volatility['bb_middle'] = float(bb_middle.iloc[-1])
165
+
166
+ # متوسط المدى الحقيقي (ATR)
167
+ if len(dataframe) >= 14:
168
+ average_true_range = ta.atr(dataframe['high'], dataframe['low'], dataframe['close'], length=14)
169
+ if average_true_range is not None and not average_true_range.empty and not pd.isna(average_true_range.iloc[-1]):
170
+ atr_value = float(average_true_range.iloc[-1])
171
+ volatility['atr'] = atr_value
172
+ current_close = dataframe['close'].iloc[-1] if not dataframe['close'].empty else 0
173
+ if atr_value and current_close > 0:
174
+ volatility['atr_percent'] = (atr_value / current_close) * 100
175
+
176
+ except Exception as e:
177
+ print(f"⚠️ خطأ في حساب مؤشرات التقلب: {e}")
178
+
179
+ return {key: value for key, value in volatility.items() if value is not None and not np.isnan(value)}
180
+
181
+ def _calculate_volume_indicators(self, dataframe, timeframe):
182
+ """حساب مؤشرات الحجم"""
183
+ volume = {}
184
+
185
+ try:
186
+ # التحقق من وجود البيانات الأساسية
187
+ if dataframe is None or dataframe.empty or 'close' not in dataframe.columns or 'volume' not in dataframe.columns:
188
+ return {}
189
+
190
+ # VWAP - إصلاح المشكلة هنا
191
+ if len(dataframe) >= 1:
192
+ try:
193
+ # إنشاء نسخة من البيانات مع DatetimeIndex مرتب
194
+ df_vwap = dataframe.copy()
195
+
196
+ # تحويل timestamp إلى datetime وضبطه كـ index
197
+ if not isinstance(df_vwap.index, pd.DatetimeIndex):
198
+ if 'timestamp' in df_vwap.columns:
199
+ df_vwap['timestamp'] = pd.to_datetime(df_vwap['timestamp'], unit='ms')
200
+ df_vwap.set_index('timestamp', inplace=True)
201
+
202
+ # التأكد من أن الفهرس مرتب
203
+ df_vwap.sort_index(inplace=True)
204
+
205
+ # حساب VWAP
206
+ volume_weighted_average_price = ta.vwap(
207
+ high=df_vwap['high'],
208
+ low=df_vwap['low'],
209
+ close=df_vwap['close'],
210
+ volume=df_vwap['volume']
211
+ )
212
+
213
+ 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]):
214
+ volume['vwap'] = float(volume_weighted_average_price.iloc[-1])
215
+
216
+ except Exception as vwap_error:
217
+ print(f"⚠️ خطأ في حساب VWAP لـ {timeframe}: {vwap_error}")
218
+ # استخدام بديل لـ VWAP في حالة الخطأ
219
+ if len(dataframe) >= 20:
220
+ try:
221
+ typical_price = (dataframe['high'] + dataframe['low'] + dataframe['close']) / 3
222
+ vwap_simple = (typical_price * dataframe['volume']).sum() / dataframe['volume'].sum()
223
+ if not np.isnan(vwap_simple):
224
+ volume['vwap'] = float(vwap_simple)
225
+ except Exception as simple_vwap_error:
226
+ print(f"⚠️ خطأ في حساب VWAP البديل: {simple_vwap_error}")
227
+
228
+ # OBV
229
+ try:
230
+ on_balance_volume = ta.obv(dataframe['close'], dataframe['volume'])
231
+ if on_balance_volume is not None and not on_balance_volume.empty and not pd.isna(on_balance_volume.iloc[-1]):
232
+ volume['obv'] = float(on_balance_volume.iloc[-1])
233
+ except Exception as obv_error:
234
+ print(f"⚠️ خطأ في حساب OBV: {obv_error}")
235
+
236
+ # MFI
237
+ if len(dataframe) >= 14:
238
+ try:
239
+ money_flow_index = ta.mfi(dataframe['high'], dataframe['low'], dataframe['close'], dataframe['volume'], length=14)
240
+ if money_flow_index is not None and not money_flow_index.empty and not pd.isna(money_flow_index.iloc[-1]):
241
+ volume['mfi'] = float(money_flow_index.iloc[-1])
242
+ except Exception as mfi_error:
243
+ print(f"⚠️ خطأ في حساب MFI: {mfi_error}")
244
+
245
+ # نسبة الحجم
246
+ if len(dataframe) >= 20:
247
+ try:
248
+ volume_avg_20 = float(dataframe['volume'].tail(20).mean())
249
+ current_volume = float(dataframe['volume'].iloc[-1]) if not dataframe['volume'].empty else 0
250
+ if volume_avg_20 and volume_avg_20 > 0 and current_volume > 0:
251
+ volume_ratio = current_volume / volume_avg_20
252
+ if not np.isnan(volume_ratio):
253
+ volume['volume_ratio'] = volume_ratio
254
+ except Exception as volume_error:
255
+ print(f"⚠️ خطأ في حساب نسبة الحجم: {volume_error}")
256
+
257
+ except Exception as e:
258
+ print(f"⚠️ خطأ في حساب مؤشرات الحجم: {e}")
259
+
260
+ return {key: value for key, value in volume.items() if value is not None and not np.isnan(value)}
261
+
262
+ def _calculate_cycle_indicators(self, dataframe):
263
+ """حساب مؤشرات الدورة"""
264
+ cycle = {}
265
+
266
+ try:
267
+ # التحقق من وجود البيانات الأساسية
268
+ if dataframe is None or dataframe.empty or 'close' not in dataframe.columns:
269
+ return {}
270
+
271
+ # هول موفينج افريج
272
+ if len(dataframe) >= 9:
273
+ hull_moving_average = ta.hma(dataframe['close'], length=9)
274
+ if hull_moving_average is not None and not hull_moving_average.empty and not pd.isna(hull_moving_average.iloc[-1]):
275
+ cycle['hull_ma'] = float(hull_moving_average.iloc[-1])
276
+
277
+ # سوبرتريند
278
+ if len(dataframe) >= 10:
279
+ supertrend = ta.supertrend(dataframe['high'], dataframe['low'], dataframe['close'], length=10, multiplier=3)
280
+ if supertrend is not None and not supertrend.empty:
281
+ supertrend_value = supertrend.get('SUPERT_10_3.0')
282
+ if supertrend_value is not None and not supertrend_value.empty and not pd.isna(supertrend_value.iloc[-1]):
283
+ cycle['supertrend'] = float(supertrend_value.iloc[-1])
284
+
285
+ except Exception as e:
286
+ print(f"⚠️ خطأ في حساب مؤشرات الدورة: {e}")
287
+
288
+ return {key: value for key, value in cycle.items() if value is not None and not np.isnan(value)}
289
+
290
+ print("✅ ML Module: Technical Indicators loaded")