Update data_manager.py
Browse files- data_manager.py +52 -37
data_manager.py
CHANGED
|
@@ -607,7 +607,7 @@ class DataManager:
|
|
| 607 |
print(" 📈 الإطارات الزمنية: 5m, 15m, 1h, 4h, 1d, 1w")
|
| 608 |
|
| 609 |
# تقسيم الرموز إلى دفعات لتجنب rate limits
|
| 610 |
-
batch_size =
|
| 611 |
batches = [symbols[i:i + batch_size] for i in range(0, len(symbols), batch_size)]
|
| 612 |
|
| 613 |
all_results = []
|
|
@@ -633,17 +633,17 @@ class DataManager:
|
|
| 633 |
elif result is not None:
|
| 634 |
all_results.append(result)
|
| 635 |
successful_count += 1
|
| 636 |
-
print(f" ✅ تم جلب بيانات {symbol}")
|
| 637 |
else:
|
| 638 |
-
print(f" ❌ فشل جلب بيانات {symbol}: لا توجد بيانات")
|
| 639 |
-
|
| 640 |
print(f" ✅ اكتملت الدفعة {batch_num + 1}: {successful_count}/{len(batch)} ناجحة")
|
| 641 |
|
| 642 |
# انتظار قصير بين الدفعات لتجنب rate limits
|
| 643 |
if batch_num < len(batches) - 1:
|
| 644 |
-
await asyncio.sleep(
|
| 645 |
|
| 646 |
-
print(f"✅ تم تجميع بيانات OHLCV كاملة لـ {len(all_results)} عملة")
|
| 647 |
return all_results
|
| 648 |
|
| 649 |
async def _fetch_complete_ohlcv_parallel(self, symbol: str) -> Dict[str, Any]:
|
|
@@ -651,45 +651,46 @@ class DataManager:
|
|
| 651 |
try:
|
| 652 |
ohlcv_data = {}
|
| 653 |
|
| 654 |
-
#
|
| 655 |
timeframes = [
|
| 656 |
-
('5m', 200),
|
| 657 |
-
('15m', 200),
|
| 658 |
-
('1h', 200),
|
| 659 |
-
('4h', 200),
|
| 660 |
-
('1d', 200),
|
| 661 |
-
('1w', 200),
|
| 662 |
]
|
| 663 |
|
| 664 |
# إنشاء مهام لجميع الإطارات الزمنية بشكل متوازي
|
| 665 |
timeframe_tasks = []
|
| 666 |
for timeframe, limit in timeframes:
|
| 667 |
-
task = asyncio.create_task(self.
|
| 668 |
timeframe_tasks.append(task)
|
| 669 |
|
| 670 |
# انتظار جميع المهام
|
| 671 |
timeframe_results = await asyncio.gather(*timeframe_tasks, return_exceptions=True)
|
| 672 |
|
| 673 |
-
|
|
|
|
|
|
|
| 674 |
|
| 675 |
# معالجة النتائج
|
| 676 |
for i, (timeframe, limit) in enumerate(timeframes):
|
| 677 |
result = timeframe_results[i]
|
| 678 |
-
if isinstance(result, Exception) or result is None:
|
| 679 |
-
print(f" ⚠️ فشل جلب بيانات {timeframe} لـ {symbol}")
|
| 680 |
-
has_sufficient_data = False
|
| 681 |
-
break
|
| 682 |
|
| 683 |
-
|
| 684 |
-
|
|
|
|
|
|
|
|
|
|
| 685 |
ohlcv_data[timeframe] = result
|
|
|
|
| 686 |
print(f" ✅ {symbol} - {timeframe}: {len(result)} شمعة")
|
| 687 |
else:
|
| 688 |
-
print(f" ⚠️ {symbol} - {timeframe}: بيانات
|
| 689 |
-
has_sufficient_data = False
|
| 690 |
-
break
|
| 691 |
|
| 692 |
-
|
|
|
|
| 693 |
try:
|
| 694 |
ticker = self.exchange.fetch_ticker(symbol)
|
| 695 |
current_price = ticker.get('last', 0) if ticker else 0
|
|
@@ -699,32 +700,46 @@ class DataManager:
|
|
| 699 |
'ohlcv': ohlcv_data,
|
| 700 |
'current_price': current_price,
|
| 701 |
'timestamp': datetime.now().isoformat(),
|
| 702 |
-
'candles_count': {tf: len(data) for tf, data in ohlcv_data.items()}
|
|
|
|
| 703 |
}
|
| 704 |
|
| 705 |
-
print(f" ✅ اكتمل جلب بيانات {symbol}: {result_data['candles_count']}")
|
| 706 |
return result_data
|
| 707 |
|
| 708 |
except Exception as price_error:
|
| 709 |
print(f" ❌ خطأ في جلب سعر {symbol}: {price_error}")
|
| 710 |
return None
|
| 711 |
else:
|
| 712 |
-
print(f" ❌ بيانات غير كافية لـ {symbol}")
|
| 713 |
return None
|
| 714 |
|
| 715 |
except Exception as e:
|
| 716 |
print(f" ❌ خطأ عام في جلب بيانات {symbol}: {e}")
|
| 717 |
return None
|
| 718 |
|
| 719 |
-
async def
|
| 720 |
-
"""جلب بيانات إطار زمني واحد"""
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 728 |
|
| 729 |
async def get_latest_price_async(self, symbol):
|
| 730 |
"""جلب السعر الحالي لعملة محددة"""
|
|
|
|
| 607 |
print(" 📈 الإطارات الزمنية: 5m, 15m, 1h, 4h, 1d, 1w")
|
| 608 |
|
| 609 |
# تقسيم الرموز إلى دفعات لتجنب rate limits
|
| 610 |
+
batch_size = 15 # تقليل حجم الدفعة لتحسين الاستقرار
|
| 611 |
batches = [symbols[i:i + batch_size] for i in range(0, len(symbols), batch_size)]
|
| 612 |
|
| 613 |
all_results = []
|
|
|
|
| 633 |
elif result is not None:
|
| 634 |
all_results.append(result)
|
| 635 |
successful_count += 1
|
| 636 |
+
print(f" ✅ تم جلب بيانات {symbol} ({result.get('successful_timeframes', 0)}/6 أطر)")
|
| 637 |
else:
|
| 638 |
+
print(f" ❌ فشل جلب بيانات {symbol}: لا توجد بيانات كافية")
|
| 639 |
+
|
| 640 |
print(f" ✅ اكتملت الدفعة {batch_num + 1}: {successful_count}/{len(batch)} ناجحة")
|
| 641 |
|
| 642 |
# انتظار قصير بين الدفعات لتجنب rate limits
|
| 643 |
if batch_num < len(batches) - 1:
|
| 644 |
+
await asyncio.sleep(1) # زيادة وقت الانتظار
|
| 645 |
|
| 646 |
+
print(f"✅ تم تجميع بيانات OHLCV كاملة لـ {len(all_results)} عملة من أصل {len(symbols)}")
|
| 647 |
return all_results
|
| 648 |
|
| 649 |
async def _fetch_complete_ohlcv_parallel(self, symbol: str) -> Dict[str, Any]:
|
|
|
|
| 651 |
try:
|
| 652 |
ohlcv_data = {}
|
| 653 |
|
| 654 |
+
# جلب 200 شمعة لكل إطار زمني مع تحسين التعامل مع الأخطاء
|
| 655 |
timeframes = [
|
| 656 |
+
('5m', 200),
|
| 657 |
+
('15m', 200),
|
| 658 |
+
('1h', 200),
|
| 659 |
+
('4h', 200),
|
| 660 |
+
('1d', 200),
|
| 661 |
+
('1w', 200),
|
| 662 |
]
|
| 663 |
|
| 664 |
# إنشاء مهام لجميع الإطارات الزمنية بشكل متوازي
|
| 665 |
timeframe_tasks = []
|
| 666 |
for timeframe, limit in timeframes:
|
| 667 |
+
task = asyncio.create_task(self._fetch_single_timeframe_improved(symbol, timeframe, limit))
|
| 668 |
timeframe_tasks.append(task)
|
| 669 |
|
| 670 |
# انتظار جميع المهام
|
| 671 |
timeframe_results = await asyncio.gather(*timeframe_tasks, return_exceptions=True)
|
| 672 |
|
| 673 |
+
# تحسين: قبول البيانات حتى لو كانت غير مكتملة
|
| 674 |
+
successful_timeframes = 0
|
| 675 |
+
min_required_timeframes = 3 # على الأقل 3 أطر زمنية
|
| 676 |
|
| 677 |
# معالجة النتائج
|
| 678 |
for i, (timeframe, limit) in enumerate(timeframes):
|
| 679 |
result = timeframe_results[i]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 680 |
|
| 681 |
+
if isinstance(result, Exception):
|
| 682 |
+
print(f" ⚠️ فشل جلب بيانات {timeframe} لـ {symbol}: {result}")
|
| 683 |
+
continue
|
| 684 |
+
|
| 685 |
+
if result and len(result) >= 10: # تخفيف الشرط من 50 إلى 10 شموع
|
| 686 |
ohlcv_data[timeframe] = result
|
| 687 |
+
successful_timeframes += 1
|
| 688 |
print(f" ✅ {symbol} - {timeframe}: {len(result)} شمعة")
|
| 689 |
else:
|
| 690 |
+
print(f" ⚠️ {symbol} - {timeframe}: بيانات محدودة ({len(result) if result else 0} شمعة)")
|
|
|
|
|
|
|
| 691 |
|
| 692 |
+
# تحسين: قبول العملة إذا كان لديها عدد كافٍ من الأطر الزمنية
|
| 693 |
+
if successful_timeframes >= min_required_timeframes and ohlcv_data:
|
| 694 |
try:
|
| 695 |
ticker = self.exchange.fetch_ticker(symbol)
|
| 696 |
current_price = ticker.get('last', 0) if ticker else 0
|
|
|
|
| 700 |
'ohlcv': ohlcv_data,
|
| 701 |
'current_price': current_price,
|
| 702 |
'timestamp': datetime.now().isoformat(),
|
| 703 |
+
'candles_count': {tf: len(data) for tf, data in ohlcv_data.items()},
|
| 704 |
+
'successful_timeframes': successful_timeframes
|
| 705 |
}
|
| 706 |
|
| 707 |
+
print(f" ✅ اكتمل جلب بيانات {symbol}: {result_data['candles_count']} (نجح {successful_timeframes}/6)")
|
| 708 |
return result_data
|
| 709 |
|
| 710 |
except Exception as price_error:
|
| 711 |
print(f" ❌ خطأ في جلب سعر {symbol}: {price_error}")
|
| 712 |
return None
|
| 713 |
else:
|
| 714 |
+
print(f" ❌ بيانات غير كافية لـ {symbol}: {successful_timeframes} أطر ناجحة فقط (المطلوب: {min_required_timeframes})")
|
| 715 |
return None
|
| 716 |
|
| 717 |
except Exception as e:
|
| 718 |
print(f" ❌ خطأ عام في جلب بيانات {symbol}: {e}")
|
| 719 |
return None
|
| 720 |
|
| 721 |
+
async def _fetch_single_timeframe_improved(self, symbol: str, timeframe: str, limit: int):
|
| 722 |
+
"""جلب بيانات إطار زمني واحد مع تحسين التعامل مع الأخطاء"""
|
| 723 |
+
max_retries = 3
|
| 724 |
+
retry_delay = 2
|
| 725 |
+
|
| 726 |
+
for attempt in range(max_retries):
|
| 727 |
+
try:
|
| 728 |
+
ohlcv_data = self.exchange.fetch_ohlcv(symbol, timeframe, limit=limit)
|
| 729 |
+
|
| 730 |
+
if ohlcv_data and len(ohlcv_data) > 0:
|
| 731 |
+
print(f" 📊 {symbol} - {timeframe}: {len(ohlcv_data)} شمعة (المحاولة {attempt + 1})")
|
| 732 |
+
return ohlcv_data
|
| 733 |
+
else:
|
| 734 |
+
print(f" ⚠️ {symbol} - {timeframe}: لا توجد بيانات (المحاولة {attempt + 1})")
|
| 735 |
+
return []
|
| 736 |
+
|
| 737 |
+
except Exception as e:
|
| 738 |
+
print(f" ❌ فشل جلب {timeframe} لـ {symbol} (المحاولة {attempt + 1}): {e}")
|
| 739 |
+
if attempt < max_retries - 1:
|
| 740 |
+
await asyncio.sleep(retry_delay * (attempt + 1))
|
| 741 |
+
else:
|
| 742 |
+
return []
|
| 743 |
|
| 744 |
async def get_latest_price_async(self, symbol):
|
| 745 |
"""جلب السعر الحالي لعملة محددة"""
|