Riy777 commited on
Commit
79a9e95
·
1 Parent(s): b23db77

Update data_manager.py

Browse files
Files changed (1) hide show
  1. data_manager.py +181 -166
data_manager.py CHANGED
@@ -5,7 +5,7 @@ import httpx
5
  import traceback
6
  import time
7
  from datetime import datetime
8
- import ccxt # استخدام ccxt العادي بدلاً من pro
9
  import numpy as np
10
  import logging
11
  from typing import List, Dict, Any
@@ -18,10 +18,6 @@ class DataManager:
18
  self.contracts_db = contracts_db or {}
19
  self.whale_monitor = whale_monitor
20
 
21
- # إعدادات الأداء المحسنة
22
- self.batch_size = 25 # حجم دفعة معقول
23
- self.cache_duration = 300
24
-
25
  try:
26
  self.exchange = ccxt.kucoin({
27
  'sandbox': False,
@@ -29,7 +25,7 @@ class DataManager:
29
  'timeout': 30000,
30
  'verbose': False,
31
  })
32
- print("✅ تم تهيئة اتصال KuCoin بنجاح (CCXT Standard)")
33
  except Exception as e:
34
  print(f"❌ فشل تهيئة اتصال KuCoin: {e}")
35
  self.exchange = None
@@ -37,13 +33,11 @@ class DataManager:
37
  self.http_client = None
38
  self.market_cache = {}
39
  self.last_market_load = None
40
- self.symbol_cache = {}
41
- self.cache_timestamp = {}
42
 
43
  async def initialize(self):
44
  self.http_client = httpx.AsyncClient(timeout=30.0)
45
  await self._load_markets()
46
- print("✅ DataManager initialized - Focused on Top 200 Symbols")
47
 
48
  async def _load_markets(self):
49
  try:
@@ -51,7 +45,7 @@ class DataManager:
51
  return
52
 
53
  print("🔄 جلب أحدث بيانات الأسواق من KuCoin...")
54
- self.exchange.load_markets() # sync call instead of await
55
  self.market_cache = self.exchange.markets
56
  self.last_market_load = datetime.now()
57
  print(f"✅ تم تحميل {len(self.market_cache)} سوق من KuCoin")
@@ -62,7 +56,6 @@ class DataManager:
62
  async def close(self):
63
  if self.http_client:
64
  await self.http_client.aclose()
65
- # لا داعي لـ close في ccxt العادي
66
 
67
  async def get_market_context_async(self):
68
  """جلب سياق السوق الأساسي فقط"""
@@ -165,12 +158,12 @@ class DataManager:
165
  try:
166
  prices = {'bitcoin': None, 'ethereum': None}
167
 
168
- btc_ticker = self.exchange.fetch_ticker('BTC/USDT') # sync call
169
  btc_price = float(btc_ticker.get('last', 0)) if btc_ticker.get('last') else None
170
  if btc_price and btc_price > 0:
171
  prices['bitcoin'] = btc_price
172
 
173
- eth_ticker = self.exchange.fetch_ticker('ETH/USDT') # sync call
174
  eth_price = float(eth_ticker.get('last', 0)) if eth_ticker.get('last') else None
175
  if eth_price and eth_price > 0:
176
  prices['ethereum'] = eth_price
@@ -215,216 +208,226 @@ class DataManager:
215
 
216
  async def layer1_rapid_screening(self) -> List[Dict[str, Any]]:
217
  """
218
- الطبقة 1: فحص سريع لأفضل 200 عملة بناءً على مؤشرات هامة
219
  """
220
- print("📊 الطبقة 1: فحص سريع لأفضل العملات بناءً على مؤشرات هامة...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
- # الحصول على جميع الرموز النشطة
 
 
 
 
223
  usdt_symbols = [
224
  symbol for symbol in self.market_cache.keys()
225
  if symbol.endswith('/USDT') and self.market_cache[symbol].get('active', False)
226
  ]
227
 
228
- print(f"🔍 تحليل {len(usdt_symbols)} عملة متاحة...")
229
-
230
- # جلب بيانات التداول لجميع الرموز وتقييمها
231
- all_symbols_data = []
232
 
233
- for i, symbol in enumerate(usdt_symbols):
 
234
  try:
235
- symbol_data = await self._get_symbol_trading_data(symbol)
236
- if symbol_data:
237
- all_symbols_data.append(symbol_data)
238
-
239
- if i % 50 == 0:
240
- print(f" 📈 معالجة {i}/{len(usdt_symbols)} عملة...")
241
-
242
- await asyncio.sleep(0.05) # وقت انتظار قصير جداً
 
 
 
243
 
 
 
 
 
 
 
 
 
 
 
 
244
  except Exception as e:
245
  continue
246
 
247
- print(f"✅ تم جمع بيانات {len(all_symbols_data)} عملة")
248
-
249
- if not all_symbols_data:
250
- return []
 
 
251
 
252
- # تصنيف العملات بناءً على مؤشرات هامة
253
- scored_symbols = []
254
 
255
- for symbol_data in all_symbols_data:
256
  try:
257
- score = self._calculate_comprehensive_score(symbol_data)
258
- if score > 0: # قبول العملات ذات الدرجة الإيجابية فقط
259
- symbol_data['layer1_score'] = score
260
- scored_symbols.append(symbol_data)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  except Exception as e:
262
  continue
263
 
264
- # ترتيب العملات حسب الدرجة (من الأعلى للأدنى)
265
- scored_symbols.sort(key=lambda x: x.get('layer1_score', 0), reverse=True)
266
-
267
- # أخذ أفضل 200 عملة فقط
268
- top_200 = scored_symbols[:200]
269
-
270
- print(f"🎯 تم اختيار أفضل {len(top_200)} عملة للطبقة 2")
271
-
272
- # عرض أفضل 15 عملة
273
- print("🏆 أفضل 15 عملة من الطبقة 1:")
274
- for i, symbol_data in enumerate(top_200[:15]):
275
- score = symbol_data.get('layer1_score', 0)
276
- volume = symbol_data.get('dollar_volume', 0)
277
- change = symbol_data.get('price_change_24h', 0)
278
- volatility = symbol_data.get('volatility_score', 0)
279
- print(f" {i+1:2d}. {symbol_data['symbol']}: {score:.3f} | ${volume:>8,.0f} | {change:>+6.1f}% | تقلب: {volatility:.3f}")
280
-
281
- return top_200
282
 
283
- async def _get_symbol_trading_data(self, symbol: str) -> Dict[str, Any]:
284
- """جلب بيانات التداول لرمز واحد"""
285
  try:
286
  ticker = self.exchange.fetch_ticker(symbol)
287
  if not ticker:
288
  return None
289
 
290
  current_price = ticker.get('last', 0)
291
- volume_24h = ticker.get('baseVolume', 0)
292
- dollar_volume = volume_24h * current_price
293
- price_change_24h = ticker.get('percentage', 0) or 0
294
  high_24h = ticker.get('high', 0)
295
  low_24h = ticker.get('low', 0)
296
  open_price = ticker.get('open', 0)
 
297
 
298
- # حساب مؤشرات إضافية هامة
299
- volatility = self._calculate_volatility_score(high_24h, low_24h, current_price)
300
- volume_trend = self._calculate_volume_trend(dollar_volume)
301
  price_strength = self._calculate_price_strength(current_price, open_price, price_change_24h)
 
302
 
303
  return {
304
- 'symbol': symbol,
305
- 'current_price': current_price,
306
- 'volume_24h': volume_24h,
307
- 'dollar_volume': dollar_volume,
308
  'price_change_24h': price_change_24h,
309
  'high_24h': high_24h,
310
  'low_24h': low_24h,
311
  'open_price': open_price,
312
- 'volatility_score': volatility,
313
- 'volume_trend': volume_trend,
314
  'price_strength': price_strength,
 
315
  'reasons': []
316
  }
317
 
318
  except Exception as e:
319
  return None
320
 
321
- def _calculate_comprehensive_score(self, symbol_data: Dict[str, Any]) -> float:
322
- """حساب درجة شاملة تعتمد على مؤشرات هامة للربحية"""
323
-
324
  dollar_volume = symbol_data.get('dollar_volume', 0)
325
  price_change = symbol_data.get('price_change_24h', 0)
326
- volatility = symbol_data.get('volatility_score', 0)
327
- volume_trend = symbol_data.get('volume_trend', 0)
328
  price_strength = symbol_data.get('price_strength', 0)
 
329
 
330
- # 1. السيولة والحجم (35%) - الأهم لتجنب العملات الميتة
331
- if dollar_volume < 100000: # أقل من 100K دولار - رفض
332
- return 0
333
-
334
- volume_score = 0
335
- if dollar_volume >= 10000000: # 10M+
336
- volume_score = 1.0
337
- elif dollar_volume >= 5000000: # 5M+
338
- volume_score = 0.9
339
- elif dollar_volume >= 2000000: # 2M+
340
- volume_score = 0.8
341
- elif dollar_volume >= 1000000: # 1M+
342
- volume_score = 0.7
343
- elif dollar_volume >= 500000: # 500K+
344
- volume_score = 0.6
345
- elif dollar_volume >= 250000: # 250K+
346
- volume_score = 0.5
347
- elif dollar_volume >= 100000: # 100K+
348
- volume_score = 0.4
349
 
350
- # 2. الزخم السعري (25%) - البحث عن حركة قوية
351
- momentum_score = 0
352
- if price_change >= 20: # +20%+ - قوي جداً
353
- momentum_score = 1.0
354
- elif price_change >= 15: # +15%+
355
- momentum_score = 0.9
356
- elif price_change >= 10: # +10%+
357
- momentum_score = 0.8
358
- elif price_change >= 5: # +5%+
359
- momentum_score = 0.7
360
- elif price_change >= 2: # +2%+
361
- momentum_score = 0.6
362
- elif price_change >= 0: # موجب
363
- momentum_score = 0.5
364
- elif price_change >= -5: # حتى -5% (فرصة شراء)
365
- momentum_score = 0.4
366
- elif price_change >= -10: # حتى -10%
367
- momentum_score = 0.3
368
- else: # أكثر من -10% - تجنب
369
- momentum_score = 0.1
370
 
371
- # 3. التقلب المناسب (20%) - ليس عالي جداً ولا منخفض جداً
372
- volatility_score = 0
373
- if 0.02 <= volatility <= 0.15: # تقلب مثالي 2%-15%
374
- volatility_score = 1.0
375
- elif 0.01 <= volatility <= 0.20: # مقبول 1%-20%
376
- volatility_score = 0.8
377
- elif volatility <= 0.01: # قليل جداً
378
- volatility_score = 0.3
379
- elif volatility > 0.20: # عالي جداً
380
- volatility_score = 0.2
381
 
382
- # 4. قوة السعر (20%) - مزيج من الاتجاه والقوة
383
  strength_score = price_strength
384
 
385
  # الدرجة النهائية
386
  final_score = (
387
- volume_score * 0.35 +
388
  momentum_score * 0.25 +
389
  volatility_score * 0.20 +
390
- strength_score * 0.20
391
  )
392
 
393
  # تحديث أسباب الترشيح
394
  reasons = []
395
  if volume_score >= 0.7:
396
- reasons.append('high_liquidity')
397
  if momentum_score >= 0.7:
398
  reasons.append('strong_momentum')
399
- if volatility_score >= 0.8:
400
- reasons.append('optimal_volatility')
401
- if strength_score >= 0.7:
402
- reasons.append('price_strength')
403
 
404
  symbol_data['reasons'] = reasons
405
 
406
  return final_score
407
 
408
- def _calculate_volatility_score(self, high_24h: float, low_24h: float, current_price: float) -> float:
409
- """حساب درجة التقلب"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  if current_price == 0:
411
  return 0
412
  return (high_24h - low_24h) / current_price
413
 
414
- def _calculate_volume_trend(self, dollar_volume: float) -> float:
415
- """حساب اتجاه الحجم"""
416
- if dollar_volume >= 10000000:
417
  return 1.0
418
- elif dollar_volume >= 5000000:
419
  return 0.8
420
- elif dollar_volume >= 1000000:
421
- return 0.6
422
- elif dollar_volume >= 500000:
423
  return 0.4
424
- elif dollar_volume >= 100000:
425
- return 0.2
426
  else:
427
- return 0.1
428
 
429
  def _calculate_price_strength(self, current_price: float, open_price: float, price_change: float) -> float:
430
  """حساب قوة السعر"""
@@ -433,13 +436,32 @@ class DataManager:
433
 
434
  # قوة السعر تعتمد على المسافة من سعر الافتتاح ونسبة التغير
435
  distance_from_open = abs(current_price - open_price) / open_price
436
- change_strength = min(abs(price_change) / 50, 1.0) # تطبيع قوة التغير
437
 
438
  return (distance_from_open * 0.6 + change_strength * 0.4)
439
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
440
  async def get_ohlcv_data_for_symbols(self, symbols: List[str]) -> List[Dict[str, Any]]:
441
  """
442
- جلب بيانات OHLCV كاملة للرموز المحددة مع جميع الإطارات الزمنية الـ6
443
  """
444
  results = []
445
 
@@ -456,7 +478,7 @@ class DataManager:
456
  print(f" ❌ ({i+1}/{len(symbols)}) فشل جلب بيانات {symbol}")
457
 
458
  # وقت انتظار لتجنب rate limits
459
- await asyncio.sleep(0.3)
460
 
461
  except Exception as symbol_error:
462
  print(f" ❌ ({i+1}/{len(symbols)}) خطأ في {symbol}: {symbol_error}")
@@ -466,41 +488,37 @@ class DataManager:
466
  return results
467
 
468
  async def _fetch_complete_ohlcv(self, symbol: str) -> Dict[str, Any]:
469
- """جلب بيانات OHLCV كاملة مع جميع الإطارات الزمنية الـ6"""
470
  try:
471
  ohlcv_data = {}
472
 
473
- # جميع الإطارات الزمنية الـ6 المطلوبة
474
  timeframes = [
475
- ('5m', 100), # 5 دقائق - 100 شمعة
476
- ('15m', 100), # 15 دقيقة - 100 شمعة
477
- ('1h', 100), # 1 ساعة - 100 شمعة
478
- ('4h', 100), # 4 ساعات - 100 شمعة
479
- ('1d', 100), # 1 يوم - 100 شمعة
480
- ('1w', 50), # 1 أسبوع - 50 شمعة
481
  ]
482
 
483
  has_sufficient_data = True
484
 
485
  for timeframe, limit in timeframes:
486
  try:
487
- # استخدام fetch_ohlcv العادي (ليس pro)
488
  ohlcv = self.exchange.fetch_ohlcv(symbol, timeframe, limit=limit)
489
 
490
- if ohlcv and len(ohlcv) >= 20: # تأكد من وجود بيانات كافية
491
  ohlcv_data[timeframe] = ohlcv
492
  else:
493
- print(f" ⚠️ بيانات غير كافية لـ {symbol} على {timeframe}")
494
  has_sufficient_data = False
495
  break
496
 
497
  except Exception as e:
498
- print(f" ⚠️ خطأ في {symbol} على {timeframe}: {e}")
499
  has_sufficient_data = False
500
  break
501
 
502
  if has_sufficient_data and ohlcv_data:
503
- # جلب السعر الحالي
504
  try:
505
  ticker = self.exchange.fetch_ticker(symbol)
506
  current_price = ticker.get('last', 0) if ticker else 0
@@ -512,13 +530,11 @@ class DataManager:
512
  'timestamp': datetime.now().isoformat()
513
  }
514
  except Exception as price_error:
515
- print(f" ⚠️ خطأ في جلب السعر لـ {symbol}: {price_error}")
516
  return None
517
  else:
518
  return None
519
 
520
  except Exception as e:
521
- print(f" ❌ خطأ عام في {symbol}: {e}")
522
  return None
523
 
524
  async def get_latest_price_async(self, symbol):
@@ -536,7 +552,6 @@ class DataManager:
536
  return None
537
 
538
  except Exception as e:
539
- print(f"❌ خطأ في جلب السعر لـ {symbol}: {e}")
540
  return None
541
 
542
  async def get_available_symbols(self):
@@ -574,4 +589,4 @@ class DataManager:
574
  print(f"❌ خطأ في التحقق من الرمز {symbol}: {e}")
575
  return False
576
 
577
- print("✅ DataManager loaded - CCXT Standard with Top 200 Symbols & Full OHLCV Timeframes")
 
5
  import traceback
6
  import time
7
  from datetime import datetime
8
+ import ccxt
9
  import numpy as np
10
  import logging
11
  from typing import List, Dict, Any
 
18
  self.contracts_db = contracts_db or {}
19
  self.whale_monitor = whale_monitor
20
 
 
 
 
 
21
  try:
22
  self.exchange = ccxt.kucoin({
23
  'sandbox': False,
 
25
  'timeout': 30000,
26
  'verbose': False,
27
  })
28
+ print("✅ تم تهيئة اتصال KuCoin بنجاح")
29
  except Exception as e:
30
  print(f"❌ فشل تهيئة اتصال KuCoin: {e}")
31
  self.exchange = None
 
33
  self.http_client = None
34
  self.market_cache = {}
35
  self.last_market_load = None
 
 
36
 
37
  async def initialize(self):
38
  self.http_client = httpx.AsyncClient(timeout=30.0)
39
  await self._load_markets()
40
+ print("✅ DataManager initialized - Top 200 by Volume Focus")
41
 
42
  async def _load_markets(self):
43
  try:
 
45
  return
46
 
47
  print("🔄 جلب أحدث بيانات الأسواق من KuCoin...")
48
+ self.exchange.load_markets()
49
  self.market_cache = self.exchange.markets
50
  self.last_market_load = datetime.now()
51
  print(f"✅ تم تحميل {len(self.market_cache)} سوق من KuCoin")
 
56
  async def close(self):
57
  if self.http_client:
58
  await self.http_client.aclose()
 
59
 
60
  async def get_market_context_async(self):
61
  """جلب سياق السوق الأساسي فقط"""
 
158
  try:
159
  prices = {'bitcoin': None, 'ethereum': None}
160
 
161
+ btc_ticker = self.exchange.fetch_ticker('BTC/USDT')
162
  btc_price = float(btc_ticker.get('last', 0)) if btc_ticker.get('last') else None
163
  if btc_price and btc_price > 0:
164
  prices['bitcoin'] = btc_price
165
 
166
+ eth_ticker = self.exchange.fetch_ticker('ETH/USDT')
167
  eth_price = float(eth_ticker.get('last', 0)) if eth_ticker.get('last') else None
168
  if eth_price and eth_price > 0:
169
  prices['ethereum'] = eth_price
 
208
 
209
  async def layer1_rapid_screening(self) -> List[Dict[str, Any]]:
210
  """
211
+ الطبقة 1: فحص سريع - المرحلة 1: جلب أفضل 200 عملة حسب الحجم فقط
212
  """
213
+ print("📊 الطبقة 1: جلب أفضل 200 عملة حسب حجم التداول...")
214
+
215
+ # المرحلة 1: جلب أحجام التداول لجميع العملات بسرعة
216
+ print(" 🔍 جلب أحجام التداول لجميع العملات...")
217
+ volume_data = await self._get_all_symbols_volume()
218
+
219
+ if not volume_data:
220
+ print("❌ فشل جلب بيانات الأحجام")
221
+ return []
222
+
223
+ # أخذ أفضل 200 عملة حسب الحجم فقط
224
+ volume_data.sort(key=lambda x: x['dollar_volume'], reverse=True)
225
+ top_200_by_volume = volume_data[:200]
226
+
227
+ print(f"✅ تم اختيار أفضل {len(top_200_by_volume)} عملة حسب الحجم")
228
+
229
+ # المرحلة 2: تطبيق المؤشرات الأخرى على الـ200 فقط
230
+ print(" 📈 تطبيق المؤشرات المتقدمة على أفضل 200 عملة...")
231
+ final_candidates = await self._apply_advanced_indicators(top_200_by_volume)
232
+
233
+ print(f"🎯 تم تحليل {len(final_candidates)} عملة للطبقة 2")
234
+
235
+ # عرض أفضل 15 عملة
236
+ print("🏆 أفضل 15 عملة من الطبقة 1:")
237
+ for i, candidate in enumerate(final_candidates[:15]):
238
+ score = candidate.get('layer1_score', 0)
239
+ volume = candidate.get('dollar_volume', 0)
240
+ change = candidate.get('price_change_24h', 0)
241
+ print(f" {i+1:2d}. {candidate['symbol']}: {score:.3f} | ${volume:>10,.0f} | {change:>+6.1f}%")
242
 
243
+ return final_candidates
244
+
245
+ async def _get_all_symbols_volume(self) -> List[Dict[str, Any]]:
246
+ """جلب أحجام التداول لجميع العملات بسرعة"""
247
+ volume_data = []
248
  usdt_symbols = [
249
  symbol for symbol in self.market_cache.keys()
250
  if symbol.endswith('/USDT') and self.market_cache[symbol].get('active', False)
251
  ]
252
 
253
+ print(f" 📊 معالجة {len(usdt_symbols)} عملة...")
 
 
 
254
 
255
+ processed = 0
256
+ for symbol in usdt_symbols:
257
  try:
258
+ ticker = self.exchange.fetch_ticker(symbol)
259
+ if not ticker:
260
+ continue
261
+
262
+ current_price = ticker.get('last', 0)
263
+ volume_24h = ticker.get('baseVolume', 0)
264
+ dollar_volume = volume_24h * current_price
265
+
266
+ # فلترة أولية: تجاهل العملات ذات الحجم المنخفض جداً
267
+ if dollar_volume < 50000: # أقل من 50K دولار
268
+ continue
269
 
270
+ volume_data.append({
271
+ 'symbol': symbol,
272
+ 'dollar_volume': dollar_volume,
273
+ 'current_price': current_price,
274
+ 'volume_24h': volume_24h
275
+ })
276
+
277
+ processed += 1
278
+ if processed % 100 == 0:
279
+ print(f" ✅ تم معالجة {processed} عملة...")
280
+
281
  except Exception as e:
282
  continue
283
 
284
+ print(f" ✅ تم جمع بيانات {len(volume_data)} عملة مؤهلة")
285
+ return volume_data
286
+
287
+ async def _apply_advanced_indicators(self, volume_data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
288
+ """تطبيق المؤشرات المتقدمة على أفضل العملات حسب الحجم"""
289
+ candidates = []
290
 
291
+ print(" 🔧 تطبيق مؤشرات الزخم والتقلب وقوة السعر...")
 
292
 
293
+ for i, symbol_data in enumerate(volume_data):
294
  try:
295
+ symbol = symbol_data['symbol']
296
+
297
+ # جلب بيانات إضافية للرمز
298
+ detailed_data = await self._get_detailed_symbol_data(symbol)
299
+ if not detailed_data:
300
+ continue
301
+
302
+ # دمج البيانات
303
+ symbol_data.update(detailed_data)
304
+
305
+ # حساب الدرجة النهائية
306
+ score = self._calculate_advanced_score(symbol_data)
307
+ symbol_data['layer1_score'] = score
308
+
309
+ candidates.append(symbol_data)
310
+
311
+ if (i + 1) % 50 == 0:
312
+ print(f" ✅ تم تحليل {i + 1}/{len(volume_data)} عملة")
313
+
314
  except Exception as e:
315
  continue
316
 
317
+ # ترتيب المرشحين حسب الدرجة النهائية
318
+ candidates.sort(key=lambda x: x.get('layer1_score', 0), reverse=True)
319
+ return candidates
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
 
321
+ async def _get_detailed_symbol_data(self, symbol: str) -> Dict[str, Any]:
322
+ """جلب بيانات تفصيلية للرمز"""
323
  try:
324
  ticker = self.exchange.fetch_ticker(symbol)
325
  if not ticker:
326
  return None
327
 
328
  current_price = ticker.get('last', 0)
 
 
 
329
  high_24h = ticker.get('high', 0)
330
  low_24h = ticker.get('low', 0)
331
  open_price = ticker.get('open', 0)
332
+ price_change_24h = ticker.get('percentage', 0) or 0
333
 
334
+ # حساب المؤشرات المتقدمة
335
+ volatility = self._calculate_volatility(high_24h, low_24h, current_price)
 
336
  price_strength = self._calculate_price_strength(current_price, open_price, price_change_24h)
337
+ momentum = self._calculate_momentum(price_change_24h)
338
 
339
  return {
 
 
 
 
340
  'price_change_24h': price_change_24h,
341
  'high_24h': high_24h,
342
  'low_24h': low_24h,
343
  'open_price': open_price,
344
+ 'volatility': volatility,
 
345
  'price_strength': price_strength,
346
+ 'momentum': momentum,
347
  'reasons': []
348
  }
349
 
350
  except Exception as e:
351
  return None
352
 
353
+ def _calculate_advanced_score(self, symbol_data: Dict[str, Any]) -> float:
354
+ """حساب درجة متقدمة تجمع بين الحجم والمؤشرات الأخرى"""
 
355
  dollar_volume = symbol_data.get('dollar_volume', 0)
356
  price_change = symbol_data.get('price_change_24h', 0)
357
+ volatility = symbol_data.get('volatility', 0)
 
358
  price_strength = symbol_data.get('price_strength', 0)
359
+ momentum = symbol_data.get('momentum', 0)
360
 
361
+ # 1. درجة الحجم (40%) - الأهم
362
+ volume_score = self._calculate_volume_score(dollar_volume)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
 
364
+ # 2. درجة الزخم (25%)
365
+ momentum_score = momentum
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
366
 
367
+ # 3. درجة التقلب (20%)
368
+ volatility_score = self._calculate_volatility_score(volatility)
 
 
 
 
 
 
 
 
369
 
370
+ # 4. درجة قوة السعر (15%)
371
  strength_score = price_strength
372
 
373
  # الدرجة النهائية
374
  final_score = (
375
+ volume_score * 0.40 +
376
  momentum_score * 0.25 +
377
  volatility_score * 0.20 +
378
+ strength_score * 0.15
379
  )
380
 
381
  # تحديث أسباب الترشيح
382
  reasons = []
383
  if volume_score >= 0.7:
384
+ reasons.append('high_volume')
385
  if momentum_score >= 0.7:
386
  reasons.append('strong_momentum')
387
+ if volatility_score >= 0.7:
388
+ reasons.append('good_volatility')
 
 
389
 
390
  symbol_data['reasons'] = reasons
391
 
392
  return final_score
393
 
394
+ def _calculate_volume_score(self, dollar_volume: float) -> float:
395
+ """حساب درجة الحجم"""
396
+ if dollar_volume >= 10000000: # 10M+
397
+ return 1.0
398
+ elif dollar_volume >= 5000000: # 5M+
399
+ return 0.9
400
+ elif dollar_volume >= 2000000: # 2M+
401
+ return 0.8
402
+ elif dollar_volume >= 1000000: # 1M+
403
+ return 0.7
404
+ elif dollar_volume >= 500000: # 500K+
405
+ return 0.6
406
+ elif dollar_volume >= 250000: # 250K+
407
+ return 0.5
408
+ elif dollar_volume >= 100000: # 100K+
409
+ return 0.4
410
+ else:
411
+ return 0.3
412
+
413
+ def _calculate_volatility(self, high_24h: float, low_24h: float, current_price: float) -> float:
414
+ """حساب التقلب"""
415
  if current_price == 0:
416
  return 0
417
  return (high_24h - low_24h) / current_price
418
 
419
+ def _calculate_volatility_score(self, volatility: float) -> float:
420
+ """حساب درجة التقلب"""
421
+ if 0.02 <= volatility <= 0.15: # تقلب مثالي 2%-15%
422
  return 1.0
423
+ elif 0.01 <= volatility <= 0.20: # مقبول 1%-20%
424
  return 0.8
425
+ elif volatility <= 0.01: # قليل جداً
 
 
426
  return 0.4
427
+ elif volatility > 0.20: # عالي جداً
428
+ return 0.3
429
  else:
430
+ return 0.5
431
 
432
  def _calculate_price_strength(self, current_price: float, open_price: float, price_change: float) -> float:
433
  """حساب قوة السعر"""
 
436
 
437
  # قوة السعر تعتمد على المسافة من سعر الافتتاح ونسبة التغير
438
  distance_from_open = abs(current_price - open_price) / open_price
439
+ change_strength = min(abs(price_change) / 50, 1.0)
440
 
441
  return (distance_from_open * 0.6 + change_strength * 0.4)
442
 
443
+ def _calculate_momentum(self, price_change: float) -> float:
444
+ """حساب الزخم"""
445
+ if price_change >= 15: # +15%+
446
+ return 1.0
447
+ elif price_change >= 10: # +10%+
448
+ return 0.9
449
+ elif price_change >= 5: # +5%+
450
+ return 0.8
451
+ elif price_change >= 2: # +2%+
452
+ return 0.7
453
+ elif price_change >= 0: # موجب
454
+ return 0.6
455
+ elif price_change >= -5: # حتى -5%
456
+ return 0.5
457
+ elif price_change >= -10: # حتى -10%
458
+ return 0.4
459
+ else: # أكثر من -10%
460
+ return 0.3
461
+
462
  async def get_ohlcv_data_for_symbols(self, symbols: List[str]) -> List[Dict[str, Any]]:
463
  """
464
+ جلب بيانات OHLCV كاملة للرموز المحددة مع جميع الإطارات الزمنية
465
  """
466
  results = []
467
 
 
478
  print(f" ❌ ({i+1}/{len(symbols)}) فشل جلب بيانات {symbol}")
479
 
480
  # وقت انتظار لتجنب rate limits
481
+ await asyncio.sleep(0.2)
482
 
483
  except Exception as symbol_error:
484
  print(f" ❌ ({i+1}/{len(symbols)}) خطأ في {symbol}: {symbol_error}")
 
488
  return results
489
 
490
  async def _fetch_complete_ohlcv(self, symbol: str) -> Dict[str, Any]:
491
+ """جلب بيانات OHLCV كاملة مع جميع الإطارات الزمنية"""
492
  try:
493
  ohlcv_data = {}
494
 
495
+ # جميع الإطارات الزمنية الـ6
496
  timeframes = [
497
+ ('5m', 100),
498
+ ('15m', 100),
499
+ ('1h', 100),
500
+ ('4h', 100),
501
+ ('1d', 100),
502
+ ('1w', 50),
503
  ]
504
 
505
  has_sufficient_data = True
506
 
507
  for timeframe, limit in timeframes:
508
  try:
 
509
  ohlcv = self.exchange.fetch_ohlcv(symbol, timeframe, limit=limit)
510
 
511
+ if ohlcv and len(ohlcv) >= 20:
512
  ohlcv_data[timeframe] = ohlcv
513
  else:
 
514
  has_sufficient_data = False
515
  break
516
 
517
  except Exception as e:
 
518
  has_sufficient_data = False
519
  break
520
 
521
  if has_sufficient_data and ohlcv_data:
 
522
  try:
523
  ticker = self.exchange.fetch_ticker(symbol)
524
  current_price = ticker.get('last', 0) if ticker else 0
 
530
  'timestamp': datetime.now().isoformat()
531
  }
532
  except Exception as price_error:
 
533
  return None
534
  else:
535
  return None
536
 
537
  except Exception as e:
 
538
  return None
539
 
540
  async def get_latest_price_async(self, symbol):
 
552
  return None
553
 
554
  except Exception as e:
 
555
  return None
556
 
557
  async def get_available_symbols(self):
 
589
  print(f"❌ خطأ في التحقق من الرمز {symbol}: {e}")
590
  return False
591
 
592
+ print("✅ DataManager loaded - Efficient Top 200 Volume-Based Screening")