Riy777 commited on
Commit
afa0eeb
·
1 Parent(s): 392404b

Update data_manager.py

Browse files
Files changed (1) hide show
  1. data_manager.py +98 -109
data_manager.py CHANGED
@@ -280,18 +280,29 @@ class DataManager:
280
  if i + self.batch_size < len(usdt_symbols):
281
  await asyncio.sleep(0.1) # تقليل وقت الانتظار
282
 
 
 
 
 
 
 
283
  # ترتيب المرشحين حسب قوة الأساسيات
284
  candidates.sort(key=lambda x: x.get('layer1_score', 0), reverse=True)
285
 
286
- # نأخذ أفضل 80-180 مرشح للطبقة 2
287
- target_count = min(max(80, len(candidates) // 5), 180)
 
 
 
 
 
288
  final_candidates = candidates[:target_count]
289
 
290
- print(f"✅ تم اختيار {len(final_candidates)} عملة من الطبقة 1")
291
 
292
- # عرض أفضل 5 مرشحين
293
- print(" 🏆 أفضل 5 مرشحين من الطبقة 1:")
294
- for i, candidate in enumerate(final_candidates[:5]):
295
  score = candidate.get('layer1_score', 0)
296
  volume = candidate.get('dollar_volume', 0)
297
  change = candidate.get('price_change_24h', 0)
@@ -306,13 +317,7 @@ class DataManager:
306
  # استخدام asyncio.gather للمعالجة المتوازية
307
  tasks = []
308
  for symbol in symbols_batch:
309
- # التحقق من التخزين المؤقت أولاً
310
- cache_key = f"ticker_{symbol}"
311
- if (cache_key in self.symbol_cache and
312
- time.time() - self.cache_timestamp.get(cache_key, 0) < self.cache_duration):
313
- tasks.append(asyncio.create_task(self._process_cached_symbol(symbol)))
314
- else:
315
- tasks.append(asyncio.create_task(self._process_symbol_optimized(symbol)))
316
 
317
  # انتظار اكتمال جميع المهام
318
  results = await asyncio.gather(*tasks, return_exceptions=True)
@@ -324,16 +329,6 @@ class DataManager:
324
 
325
  return candidates
326
 
327
- async def _process_cached_symbol(self, symbol: str):
328
- """معالجة الرمز من التخزين المؤقت"""
329
- cache_key = f"ticker_{symbol}"
330
- cached_data = self.symbol_cache.get(cache_key)
331
- if cached_data and self._validate_cached_data(cached_data):
332
- return cached_data
333
- else:
334
- # إذا كانت البيانات المخزنة غير صالحة، معالجة جديدة
335
- return await self._process_symbol_optimized(symbol)
336
-
337
  async def _process_symbol_optimized(self, symbol: str):
338
  """معالجة رمز واحد بشكل محسن"""
339
  try:
@@ -353,7 +348,7 @@ class DataManager:
353
  high_24h = ticker.get('high', 0)
354
  low_24h = ticker.get('low', 0)
355
 
356
- # فحص سريع للمعايير الأساسية
357
  if not self._quick_validation(current_price, dollar_volume, high_24h, low_24h):
358
  return None
359
 
@@ -362,7 +357,8 @@ class DataManager:
362
  dollar_volume, price_change_24h, current_price, high_24h, low_24h
363
  )
364
 
365
- if layer1_score >= 0.3:
 
366
  candidate_data = {
367
  'symbol': symbol,
368
  'current_price': current_price,
@@ -375,25 +371,18 @@ class DataManager:
375
  'reasons': self._generate_fast_reasons(dollar_volume, price_change_24h)
376
  }
377
 
378
- # تخزين في الذاكرة المؤقتة
379
- cache_key = f"ticker_{symbol}"
380
- self.symbol_cache[cache_key] = candidate_data
381
- self.cache_timestamp[cache_key] = time.time()
382
-
383
  return candidate_data
384
  else:
385
  return None
386
 
387
  except (asyncio.TimeoutError, Exception) as e:
388
- # إصلاح الخطأ: است��دال continue بـ return None
389
- if "rate limit" not in str(e).lower():
390
- return None
391
  return None
392
 
393
  def _quick_validation(self, current_price, dollar_volume, high_24h, low_24h):
394
- """تحقق سريع من المعايير الأساسية"""
395
  return all([
396
- dollar_volume >= 1000000, # حجم تداول لا يقل عن 1M دولار
397
  current_price > 0.00000001, # أي سعر مقبول
398
  current_price <= 100000, # حد أقصى معقول
399
  high_24h > 0, # بيانات سعر صالحة
@@ -404,20 +393,20 @@ class DataManager:
404
  def _calculate_fast_layer1_score(self, dollar_volume, price_change, current_price, high_24h, low_24h):
405
  """حساب سريع لدرجة الطبقة 1"""
406
  # حساب مبسط للحجم (بدون تعقيد)
407
- volume_score = min(dollar_volume / 5000000, 1.0) # تطبيع إلى 5M
408
 
409
  # حساب مبكر للزخم
410
- if price_change >= 15:
411
  momentum_score = 0.9
412
- elif price_change >= 8:
413
  momentum_score = 0.7
414
- elif price_change >= 3:
415
  momentum_score = 0.5
416
- elif price_change <= -15:
417
  momentum_score = 0.8 # فرصة شراء في الانخفاض
418
- elif price_change <= -8:
419
  momentum_score = 0.6
420
- elif price_change <= -3:
421
  momentum_score = 0.4
422
  else:
423
  momentum_score = 0.3
@@ -425,9 +414,9 @@ class DataManager:
425
  # حساب موقع السعر بشكل مبسط
426
  if high_24h != low_24h:
427
  position = (current_price - low_24h) / (high_24h - low_24h)
428
- if position < 0.3:
429
  position_score = 0.8
430
- elif position > 0.7:
431
  position_score = 0.6
432
  else:
433
  position_score = 0.5
@@ -441,75 +430,79 @@ class DataManager:
441
  """توليد أسباب سريعة"""
442
  reasons = []
443
 
444
- if dollar_volume >= 5000000:
445
  reasons.append('very_high_volume')
446
- elif dollar_volume >= 2000000:
447
  reasons.append('high_volume')
448
  else:
449
  reasons.append('good_liquidity')
450
 
451
- if price_change >= 8:
452
  reasons.append('strong_positive_momentum')
453
- elif price_change >= 3:
454
  reasons.append('positive_momentum')
455
- elif price_change <= -8:
456
  reasons.append('oversold_opportunity')
457
- elif price_change <= -3:
458
  reasons.append('dip_opportunity')
459
 
460
  return reasons
461
 
462
- def _validate_cached_data(self, cached_data):
463
- """التحقق من صحة البيانات المخزنة"""
464
- if not cached_data:
465
- return False
466
-
467
- # التحقق من عمر البيانات
468
- cache_key = f"ticker_{cached_data['symbol']}"
469
- cache_time = self.cache_timestamp.get(cache_key, 0)
470
- if time.time() - cache_time > self.cache_duration:
471
- return False
472
-
473
- # التحقق من صحة البيانات
474
- required_fields = ['symbol', 'current_price', 'dollar_volume', 'layer1_score']
475
- return all(field in cached_data for field in required_fields)
476
-
477
  async def get_ohlcv_data_for_symbols(self, symbols: List[str]) -> List[Dict[str, Any]]:
478
  """
479
- جلب بيانات OHLCV كاملة للرموز المحددة بشكل متواز
480
  """
481
  results = []
482
 
483
  print(f"📊 جلب بيانات OHLCV لـ {len(symbols)} عملة...")
484
 
485
- # استخدام المهام المتوازية لجلب البيانات
486
  tasks = []
487
  for symbol in symbols:
488
- task = asyncio.create_task(self._fetch_ohlcv_for_symbol(symbol))
489
  tasks.append(task)
490
 
491
- # معالجة النتائج مع تحديد مهلة
492
- for task in asyncio.as_completed(tasks, timeout=30):
493
- try:
494
- result = await task
495
- if result:
496
- results.append(result)
497
- except (asyncio.TimeoutError, Exception) as e:
498
  continue
 
 
 
 
 
 
499
 
500
- print(f"✅ تم تجميع بيانات OHLCV لـ {len(results)} عملة")
501
  return results
502
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503
  async def _fetch_ohlcv_for_symbol(self, symbol: str):
504
  """جلب بيانات OHLCV لرمز واحد"""
505
  try:
506
  ohlcv_data = {}
 
507
  timeframes = [
508
- ('5m', 50), # تقليل عدد الشموع
509
- ('15m', 50),
510
- ('1h', 50),
511
- ('4h', 50),
512
- ('1d', 30), # تقليل للبيانات اليومية
513
  ]
514
 
515
  has_sufficient_data = True
@@ -517,35 +510,41 @@ class DataManager:
517
  try:
518
  ohlcv = await asyncio.wait_for(
519
  self.exchange.fetch_ohlcv(symbol, timeframe, limit=limit),
520
- timeout=5
521
  )
522
- if ohlcv and len(ohlcv) >= 15: # تقليل الحد الأدنى
523
  ohlcv_data[timeframe] = ohlcv
524
  else:
525
  has_sufficient_data = False
526
  break
527
- except (asyncio.TimeoutError, Exception):
 
528
  has_sufficient_data = False
529
  break
530
 
531
- if has_sufficient_data:
532
  # جلب السعر الحالي بشكل منفصل
533
- ticker = await asyncio.wait_for(
534
- self.exchange.fetch_ticker(symbol),
535
- timeout=3
536
- )
537
- current_price = ticker.get('last', 0) if ticker else 0
538
-
539
- return {
540
- 'symbol': symbol,
541
- 'ohlcv': ohlcv_data,
542
- 'current_price': current_price,
543
- 'timestamp': datetime.now().isoformat()
544
- }
 
 
 
 
545
  else:
546
  return None
547
 
548
  except Exception as symbol_error:
 
549
  return None
550
 
551
  async def get_latest_price_async(self, symbol):
@@ -554,24 +553,14 @@ class DataManager:
554
  if not self.exchange:
555
  return None
556
 
557
- # التحقق من التخزين المؤقت أولاً
558
- cache_key = f"price_{symbol}"
559
- if (cache_key in self.symbol_cache and
560
- time.time() - self.cache_timestamp.get(cache_key, 0) < 10): # تخزين الأسعار لمدة 10 ثوان
561
- return self.symbol_cache[cache_key].get('current_price')
562
-
563
  ticker = await asyncio.wait_for(
564
  self.exchange.fetch_ticker(symbol),
565
- timeout=3
566
  )
567
  current_price = ticker.get('last')
568
 
569
  if current_price:
570
- price = float(current_price)
571
- # تحديث التخزين المؤقت
572
- self.symbol_cache[cache_key] = {'current_price': price}
573
- self.cache_timestamp[cache_key] = time.time()
574
- return price
575
  else:
576
  return None
577
 
 
280
  if i + self.batch_size < len(usdt_symbols):
281
  await asyncio.sleep(0.1) # تقليل وقت الانتظار
282
 
283
+ print(f"📊 تم جمع {len(candidates)} مرشح مؤهل من الطبقة 1")
284
+
285
+ if not candidates:
286
+ print("❌ لم يتم العثور على أي مرشح مؤهل")
287
+ return []
288
+
289
  # ترتيب المرشحين حسب قوة الأساسيات
290
  candidates.sort(key=lambda x: x.get('layer1_score', 0), reverse=True)
291
 
292
+ # إصلاح الخطأ: تحديد عدد المرشحين بشكل صحيح
293
+ target_count = min(max(80, len(candidates) // 2), 180, len(candidates))
294
+
295
+ # إذا كان لدينا عدد قليل من المرشحين، نأخذ نسبة أكبر
296
+ if len(candidates) < 100:
297
+ target_count = min(len(candidates), 50) # تأخذ على الأقل 50 مرشح إذا كان العدد الإجمالي قليل
298
+
299
  final_candidates = candidates[:target_count]
300
 
301
+ print(f"✅ تم اختيار {len(final_candidates)} عملة من أصل {len(candidates)} مرشح للطبقة 2")
302
 
303
+ # عرض أفضل 10 مرشحين
304
+ print(" 🏆 أفضل 10 مرشحين من الطبقة 1:")
305
+ for i, candidate in enumerate(final_candidates[:10]):
306
  score = candidate.get('layer1_score', 0)
307
  volume = candidate.get('dollar_volume', 0)
308
  change = candidate.get('price_change_24h', 0)
 
317
  # استخدام asyncio.gather للمعالجة المتوازية
318
  tasks = []
319
  for symbol in symbols_batch:
320
+ tasks.append(asyncio.create_task(self._process_symbol_optimized(symbol)))
 
 
 
 
 
 
321
 
322
  # انتظار اكتمال جميع المهام
323
  results = await asyncio.gather(*tasks, return_exceptions=True)
 
329
 
330
  return candidates
331
 
 
 
 
 
 
 
 
 
 
 
332
  async def _process_symbol_optimized(self, symbol: str):
333
  """معالجة رمز واحد بشكل محسن"""
334
  try:
 
348
  high_24h = ticker.get('high', 0)
349
  low_24h = ticker.get('low', 0)
350
 
351
+ # فحص سريع للمعايير الأساسية - تخفيف الشروط
352
  if not self._quick_validation(current_price, dollar_volume, high_24h, low_24h):
353
  return None
354
 
 
357
  dollar_volume, price_change_24h, current_price, high_24h, low_24h
358
  )
359
 
360
+ # تخفيف عتبة القبول - تقليل من 0.3 إلى 0.1
361
+ if layer1_score >= 0.1: # كان 0.3
362
  candidate_data = {
363
  'symbol': symbol,
364
  'current_price': current_price,
 
371
  'reasons': self._generate_fast_reasons(dollar_volume, price_change_24h)
372
  }
373
 
 
 
 
 
 
374
  return candidate_data
375
  else:
376
  return None
377
 
378
  except (asyncio.TimeoutError, Exception) as e:
379
+ # تجاهل الأخطاء والمتابعة
 
 
380
  return None
381
 
382
  def _quick_validation(self, current_price, dollar_volume, high_24h, low_24h):
383
+ """تحقق سريع من المعايير الأساسية - تخفيف الشروط"""
384
  return all([
385
+ dollar_volume >= 500000, # تخفيف من 1M إلى 500K دولار
386
  current_price > 0.00000001, # أي سعر مقبول
387
  current_price <= 100000, # حد أقصى معقول
388
  high_24h > 0, # بيانات سعر صالحة
 
393
  def _calculate_fast_layer1_score(self, dollar_volume, price_change, current_price, high_24h, low_24h):
394
  """حساب سريع لدرجة الطبقة 1"""
395
  # حساب مبسط للحجم (بدون تعقيد)
396
+ volume_score = min(dollar_volume / 2000000, 1.0) # تخفيف من 5M إلى 2M
397
 
398
  # حساب مبكر للزخم
399
+ if price_change >= 10: # تخفيف من 15 إلى 10
400
  momentum_score = 0.9
401
+ elif price_change >= 5: # تخفيف من 8 إلى 5
402
  momentum_score = 0.7
403
+ elif price_change >= 2: # تخفيف من 3 إلى 2
404
  momentum_score = 0.5
405
+ elif price_change <= -10: # تخفيف من -15 إلى -10
406
  momentum_score = 0.8 # فرصة شراء في الانخفاض
407
+ elif price_change <= -5: # تخفيف من -8 إلى -5
408
  momentum_score = 0.6
409
+ elif price_change <= -2: # تخفيف من -3 إلى -2
410
  momentum_score = 0.4
411
  else:
412
  momentum_score = 0.3
 
414
  # حساب موقع السعر بشكل مبسط
415
  if high_24h != low_24h:
416
  position = (current_price - low_24h) / (high_24h - low_24h)
417
+ if position < 0.2: # كان 0.3
418
  position_score = 0.8
419
+ elif position > 0.8: # كان 0.7
420
  position_score = 0.6
421
  else:
422
  position_score = 0.5
 
430
  """توليد أسباب سريعة"""
431
  reasons = []
432
 
433
+ if dollar_volume >= 2000000: # تخفيف من 5M إلى 2M
434
  reasons.append('very_high_volume')
435
+ elif dollar_volume >= 1000000: # تخفيف من 2M إلى 1M
436
  reasons.append('high_volume')
437
  else:
438
  reasons.append('good_liquidity')
439
 
440
+ if price_change >= 5: # تخفيف من 8 إلى 5
441
  reasons.append('strong_positive_momentum')
442
+ elif price_change >= 2: # تخفيف من 3 إلى 2
443
  reasons.append('positive_momentum')
444
+ elif price_change <= -5: # تخفيف من -8 إلى -5
445
  reasons.append('oversold_opportunity')
446
+ elif price_change <= -2: # تخفيف من -3 إلى -2
447
  reasons.append('dip_opportunity')
448
 
449
  return reasons
450
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
451
  async def get_ohlcv_data_for_symbols(self, symbols: List[str]) -> List[Dict[str, Any]]:
452
  """
453
+ جلب بيانات OHLCV كاملة للرموز المحددة بشكل متواز ومحسن
454
  """
455
  results = []
456
 
457
  print(f"📊 جلب بيانات OHLCV لـ {len(symbols)} عملة...")
458
 
459
+ # استخدام المهام المتوازية لجلب البيانات مع إعادة المحاولة
460
  tasks = []
461
  for symbol in symbols:
462
+ task = asyncio.create_task(self._fetch_ohlcv_with_retry(symbol))
463
  tasks.append(task)
464
 
465
+ # جمع النتائج مع معالجة الأخطاء
466
+ completed_tasks = await asyncio.gather(*tasks, return_exceptions=True)
467
+
468
+ for result in completed_tasks:
469
+ if isinstance(result, Exception) or result is None:
 
 
470
  continue
471
+ results.append(result)
472
+
473
+ print(f"✅ تم تجميع بيانات OHLCV لـ {len(results)} عملة من أصل {len(symbols)}")
474
+
475
+ if len(results) < len(symbols):
476
+ print(f"⚠️ فشل جلب بيانات {len(symbols) - len(results)} عملة")
477
 
 
478
  return results
479
 
480
+ async def _fetch_ohlcv_with_retry(self, symbol: str, max_retries: int = 3):
481
+ """جلب بيانات OHLCV مع إعادة المحاولة"""
482
+ for attempt in range(max_retries):
483
+ try:
484
+ result = await self._fetch_ohlcv_for_symbol(symbol)
485
+ if result:
486
+ return result
487
+ else:
488
+ await asyncio.sleep(1) # انتظار قبل إعادة المحاولة
489
+ except Exception as e:
490
+ if attempt < max_retries - 1:
491
+ await asyncio.sleep(1)
492
+ continue
493
+ else:
494
+ print(f"❌ فشل جلب بيانات {symbol} بعد {max_retries} محاولات: {e}")
495
+ return None
496
+
497
  async def _fetch_ohlcv_for_symbol(self, symbol: str):
498
  """جلب بيانات OHLCV لرمز واحد"""
499
  try:
500
  ohlcv_data = {}
501
+ # تقليل عدد الإطارات الزمنية لتسريع العملية
502
  timeframes = [
503
+ ('1h', 50), # إطار ساعة واحد فقط للبيانات الأساسية
504
+ ('4h', 30), # إطار 4 ساعات
505
+ ('1d', 20), # إطار يومي
 
 
506
  ]
507
 
508
  has_sufficient_data = True
 
510
  try:
511
  ohlcv = await asyncio.wait_for(
512
  self.exchange.fetch_ohlcv(symbol, timeframe, limit=limit),
513
+ timeout=10 # زيادة المهلة
514
  )
515
+ if ohlcv and len(ohlcv) >= 10: # تقليل الحد الأدنى
516
  ohlcv_data[timeframe] = ohlcv
517
  else:
518
  has_sufficient_data = False
519
  break
520
+ except (asyncio.TimeoutError, Exception) as e:
521
+ print(f"⚠️ خطأ في جلب بيانات {timeframe} لـ {symbol}: {e}")
522
  has_sufficient_data = False
523
  break
524
 
525
+ if has_sufficient_data and ohlcv_data: # التأكد من وجود بيانات
526
  # جلب السعر الحالي بشكل منفصل
527
+ try:
528
+ ticker = await asyncio.wait_for(
529
+ self.exchange.fetch_ticker(symbol),
530
+ timeout=5
531
+ )
532
+ current_price = ticker.get('last', 0) if ticker else 0
533
+
534
+ return {
535
+ 'symbol': symbol,
536
+ 'ohlcv': ohlcv_data,
537
+ 'current_price': current_price,
538
+ 'timestamp': datetime.now().isoformat()
539
+ }
540
+ except Exception as price_error:
541
+ print(f"⚠️ خطأ في جلب السعر لـ {symbol}: {price_error}")
542
+ return None
543
  else:
544
  return None
545
 
546
  except Exception as symbol_error:
547
+ print(f"⚠️ خطأ عام في جلب بيانات {symbol}: {symbol_error}")
548
  return None
549
 
550
  async def get_latest_price_async(self, symbol):
 
553
  if not self.exchange:
554
  return None
555
 
 
 
 
 
 
 
556
  ticker = await asyncio.wait_for(
557
  self.exchange.fetch_ticker(symbol),
558
+ timeout=5
559
  )
560
  current_price = ticker.get('last')
561
 
562
  if current_price:
563
+ return float(current_price)
 
 
 
 
564
  else:
565
  return None
566