Riy777 commited on
Commit
bb3d23b
·
1 Parent(s): 28fa18b

Update whale_news_data.py

Browse files
Files changed (1) hide show
  1. whale_news_data.py +26 -184
whale_news_data.py CHANGED
@@ -8,10 +8,20 @@ from datetime import datetime, timedelta
8
  from collections import defaultdict, deque
9
  import ccxt.pro as ccxt
10
  import numpy as np
 
 
 
 
 
11
 
12
  class EnhancedWhaleMonitor:
13
  def __init__(self, contracts_db=None, r2_service=None):
14
- self.http_client = httpx.AsyncClient(timeout=15.0, limits=httpx.Limits(max_connections=50, max_keepalive_connections=10))
 
 
 
 
 
15
 
16
  self.moralis_key = os.getenv("MORALIS_KEY")
17
  self.etherscan_key = os.getenv("ETHERSCAN_KEY")
@@ -99,8 +109,8 @@ class EnhancedWhaleMonitor:
99
  self.price_cache = {}
100
  self.last_scan_time = {}
101
 
102
- self.contract_cache = {} # كاش جديد للعقود
103
- self.symbol_networks = {} # تتبع الشبكات المناسبة للرموز
104
 
105
  self.pattern_performance = {}
106
  self.pattern_success_rates = {}
@@ -108,7 +118,6 @@ class EnhancedWhaleMonitor:
108
  if self.r2_service:
109
  asyncio.create_task(self._load_pattern_performance())
110
 
111
- # تحميل العقود من R2 إذا كان متوفراً
112
  if self.r2_service:
113
  asyncio.create_task(self._load_contracts_from_r2())
114
 
@@ -159,7 +168,6 @@ class EnhancedWhaleMonitor:
159
  response = self.r2_service.s3_client.get_object(Bucket="trading", Key=key)
160
  contracts_data = json.loads(response['Body'].read())
161
 
162
- # تحديث قاعدة البيانات المحلية
163
  self.contracts_db.update(contracts_data)
164
  print(f"✅ تم تحميل {len(contracts_data)} عقد من R2")
165
 
@@ -195,7 +203,6 @@ class EnhancedWhaleMonitor:
195
 
196
  async def _load_pattern_performance(self):
197
  if not self.r2_service:
198
- print("⚠️ R2 Service غير متوفر لتحميل بيانات الأنماط")
199
  return
200
 
201
  try:
@@ -204,15 +211,12 @@ class EnhancedWhaleMonitor:
204
  data = json.loads(response['Body'].read())
205
  self.pattern_performance = data.get('pattern_performance', {})
206
  self.pattern_success_rates = data.get('pattern_success_rates', {})
207
- print(f"✅ تم تحميل بيانات أداء الأنماط: {len(self.pattern_performance)} نمط")
208
  except Exception as e:
209
- print(f"⚠️ لم يتم العثور على بيانات أداء الأنماط: {e}")
210
  self.pattern_performance = {}
211
  self.pattern_success_rates = {}
212
 
213
  async def _save_pattern_performance(self):
214
  if not self.r2_service:
215
- print("⚠️ R2 Service غير متوفر لحفظ بيانات الأنماط")
216
  return
217
 
218
  try:
@@ -228,7 +232,6 @@ class EnhancedWhaleMonitor:
228
  self.r2_service.s3_client.put_object(
229
  Bucket="trading", Key=key, Body=data_json, ContentType="application/json"
230
  )
231
- print(f"✅ تم حفظ بيانات أداء الأنماط: {len(self.pattern_performance)} نمط")
232
  except Exception as e:
233
  print(f"❌ فشل حفظ بيانات أداء الأنماط: {e}")
234
 
@@ -262,7 +265,6 @@ class EnhancedWhaleMonitor:
262
  self.address_categories['unknown'].add(address_lower)
263
  return 'unknown'
264
  except Exception as e:
265
- print(f"❌ خطأ في تصنيف العنوان: {e}")
266
  return 'unknown'
267
 
268
  def _detect_exchange_pattern(self, transactions):
@@ -300,7 +302,6 @@ class EnhancedWhaleMonitor:
300
  address_lower in self.address_categories['exchange'] or
301
  self.address_labels.get(address_lower) in ['cex', 'suspected_cex'])
302
  except Exception as e:
303
- print(f"❌ خطأ في التحقق من عنوان التبادل: {e}")
304
  return False
305
 
306
  async def _update_netflow_metrics(self, network, token_symbol, from_address, to_address, value_usd, transaction_hash):
@@ -330,7 +331,7 @@ class EnhancedWhaleMonitor:
330
  self.netflow_data[network][token_symbol]['netflow'].append(current_netflow)
331
 
332
  except Exception as e:
333
- print(f"❌ خطأ في تحديث مقاييس صافي التدفق: {e}")
334
 
335
  def _initialize_token_metrics(self, network, token_symbol):
336
  self.netflow_data[network][token_symbol] = {
@@ -370,7 +371,6 @@ class EnhancedWhaleMonitor:
370
  return zscore
371
 
372
  except Exception as e:
373
- print(f"❌ خطأ في حساب Z-score: {e}")
374
  return 0
375
 
376
  def _generate_netflow_signal(self, network, token_symbol):
@@ -445,7 +445,6 @@ class EnhancedWhaleMonitor:
445
  return signal
446
 
447
  except Exception as e:
448
- print(f"❌ خطأ في توليد إشارة التداول: {e}")
449
  return None
450
 
451
  async def _scan_single_evm_network(self, network):
@@ -454,17 +453,14 @@ class EnhancedWhaleMonitor:
454
 
455
  try:
456
  if not self.data_manager:
457
- print(f"⚠️ DataManager غير متوفر لمسح شبكة {network}")
458
  return [], []
459
 
460
  price_usd = await self.data_manager.get_native_coin_price(network)
461
  if price_usd is None:
462
- print(f"⚠️ لم يتم الحصول على سعر لـ {network}")
463
  return [], []
464
 
465
  latest_block_hex = await self._call_rpc_async(network, 'eth_blockNumber')
466
  if not latest_block_hex:
467
- print(f"⚠️ فشل الحصول على أحدث كتلة لـ {network}")
468
  return [], []
469
 
470
  latest_block = int(latest_block_hex, 16)
@@ -522,23 +518,19 @@ class EnhancedWhaleMonitor:
522
  })
523
  whale_transactions_found += 1
524
 
525
- if block_offset % 3 == 0:
526
- await asyncio.sleep(0.1)
527
 
528
  signal = self._generate_netflow_signal(network, 'NATIVE')
529
  if signal:
530
  trading_signals.append(signal)
531
 
532
- print(f"✅ تم مسح {scanned_blocks} كتلة في {network} - تم العثور على {whale_transactions_found} معاملة حوت")
533
  return whale_alerts, trading_signals
534
 
535
  except Exception as e:
536
- print(f"❌ خطأ في مسح شبكة {network}: {e}")
537
  return [], []
538
 
539
  async def get_general_whale_activity(self):
540
  try:
541
- print("🔍 بدء مسح نشاط الحيتان العام...")
542
  tasks = []
543
  networks_to_scan = ['ethereum', 'bsc']
544
  for network in networks_to_scan:
@@ -556,9 +548,8 @@ class EnhancedWhaleMonitor:
556
  all_alerts.extend(alerts)
557
  all_signals.extend(signals)
558
  successful_networks += 1
559
- print(f"✅ شبكة {networks_to_scan[i]} تمت معالجتها بنجاح")
560
  else:
561
- print(f"❌ فشل معالجة شبكة {networks_to_scan[i]}: {res}")
562
 
563
  all_alerts.sort(key=lambda x: x['timestamp'], reverse=True)
564
 
@@ -591,13 +582,11 @@ class EnhancedWhaleMonitor:
591
  'flow_direction': 'BALANCED'
592
  }
593
  }
594
- print("ℹ️ لم يتم اكتشاف أي نشاط حيتان كبير")
595
  return result
596
 
597
  latest_alert = all_alerts[0] if all_alerts else None
598
  latest_time_info = f"آخر نشاط منذ {latest_alert['minutes_ago']:.1f} دقيقة" if latest_alert else ""
599
 
600
- # تحديد flow_direction بشكل آمن
601
  flow_direction = 'BALANCED'
602
  if net_exchange_flow < 0:
603
  flow_direction = 'TO_EXCHANGES'
@@ -668,8 +657,6 @@ class EnhancedWhaleMonitor:
668
 
669
  except Exception as e:
670
  print(f"❌ فشل مراقبة الحيتان العامة: {e}")
671
- import traceback
672
- traceback.print_exc()
673
  return {
674
  'data_available': False,
675
  'description': f'غير متوفر - فشل في مراقبة الحيتان: {str(e)}',
@@ -683,12 +670,11 @@ class EnhancedWhaleMonitor:
683
  }
684
 
685
  async def _call_rpc_async(self, network, method, params=[]):
686
- max_retries = 3
687
 
688
  for attempt in range(max_retries):
689
  endpoint = self._get_next_rpc_endpoint(network)
690
  if not endpoint:
691
- print(f"❌ لا توجد نقاط نهاية متاحة لـ {network}")
692
  return None
693
 
694
  try:
@@ -700,18 +686,16 @@ class EnhancedWhaleMonitor:
700
 
701
  payload = {"jsonrpc": "2.0", "method": method, "params": params, "id": 1}
702
 
703
- timeout = 25.0 if method == 'eth_getBlockByNumber' else 12.0
704
 
705
  async with httpx.AsyncClient(timeout=timeout) as client:
706
  response = await client.post(endpoint, json=payload)
707
 
708
  if response.status_code == 401:
709
- print(f"❌ خطأ في المصادقة لنقطة النهاية {endpoint}")
710
  self._remove_rpc_endpoint(network, endpoint)
711
  continue
712
  elif response.status_code == 429:
713
- print(f"⏰ تجاوز حد المعدل لنقطة النهاية {endpoint}")
714
- await asyncio.sleep(2 * (attempt + 1))
715
  continue
716
 
717
  response.raise_for_status()
@@ -720,27 +704,12 @@ class EnhancedWhaleMonitor:
720
  self.rpc_failures[network] = 0
721
  return result
722
 
723
- except httpx.HTTPStatusError as e:
724
- if e.response.status_code == 429:
725
- self.rpc_failures[network] += 1
726
- await asyncio.sleep(3 * (attempt + 1))
727
- continue
728
- elif e.response.status_code == 401:
729
- self.rpc_failures[network] += 1
730
- self._remove_rpc_endpoint(network, endpoint)
731
- continue
732
- else:
733
- self.rpc_failures[network] += 1
734
- print(f"❌ خطأ HTTP في RPC {network}: {e}")
735
-
736
  except Exception as e:
737
  self.rpc_failures[network] += 1
738
- print(f"❌ خطأ عام في RPC {network}: {e}")
739
 
740
  if attempt < max_retries - 1:
741
- await asyncio.sleep(1 * (attempt + 1))
742
 
743
- print(f"❌ فشل جميع محاولات RPC لـ {network}")
744
  return None
745
 
746
  def _get_next_rpc_endpoint(self, network):
@@ -760,7 +729,6 @@ class EnhancedWhaleMonitor:
760
  def _remove_rpc_endpoint(self, network, endpoint):
761
  if network in self.rpc_endpoints and endpoint in self.rpc_endpoints[network]:
762
  self.rpc_endpoints[network].remove(endpoint)
763
- print(f"⚠️ تمت إزالة نقطة RPC {endpoint} من {network} بسبب الفشل")
764
 
765
  if self.current_rpc_index[network] >= len(self.rpc_endpoints[network]):
766
  self.current_rpc_index[network] = 0
@@ -803,68 +771,53 @@ class EnhancedWhaleMonitor:
803
  if api_name == 'etherscan':
804
  if stats['requests_per_second'] > 4:
805
  delay = 0.2 * (stats['requests_per_second'] - 4)
806
- print(f"⏰ تأخير {delay:.2f} ثانية لتجنب حد المعدل لـ {api_name}")
807
  await asyncio.sleep(delay)
808
 
809
  if stats['requests_today'] > 95000:
810
- print(f"🚨 تجاوز الحد اليومي لـ {api_name}")
811
  return True
812
 
813
  elif api_name == 'infura':
814
  if stats['requests_per_second'] > 90:
815
  delay = 0.1 * (stats['requests_per_second'] - 90)
816
- print(f"⏰ تأخير {delay:.2f} ثانية لتجنب حد المعدل لـ {api_name}")
817
  await asyncio.sleep(delay)
818
 
819
  if stats['requests_today'] > 99000:
820
- print(f"🚨 تجاوز الحد اليومي لـ {api_name}")
821
  return True
822
 
823
  elif api_name == 'moralis':
824
  if stats['requests_per_second'] > 4:
825
  delay = 0.2 * (stats['requests_per_second'] - 4)
826
- print(f"⏰ تأخير {delay:.2f} ثانية لتجنب حد المعدل لـ {api_name}")
827
  await asyncio.sleep(delay)
828
 
829
  if stats['requests_today'] > 95000:
830
- print(f"🚨 تجاوز الحد اليومي لـ {api_name}")
831
  return True
832
 
833
  return False
834
 
835
  async def _find_contract_address_enhanced(self, symbol):
836
- """بحث محسن عن عنوان العقد باستخدام مصادر متعددة"""
837
  base_symbol = symbol.split("/")[0] if '/' in symbol else symbol
838
  symbol_lower = base_symbol.lower()
839
 
840
- # البحث في الكاش أولاً
841
  if symbol_lower in self.contract_cache:
842
  return self.contract_cache[symbol_lower]
843
 
844
- # البحث في قاعدة البيانات المحلية
845
  for key, address in self.contracts_db.items():
846
  if symbol_lower in key.lower():
847
  self.contract_cache[symbol_lower] = address
848
- print(f"✅ تم العثور على عنوان العقد لـ {symbol} في قاعدة البيانات: {address}")
849
  return address
850
 
851
- # البحث عبر CoinGecko
852
  coingecko_address = await self._find_contract_via_coingecko(base_symbol)
853
  if coingecko_address:
854
  self.contract_cache[symbol_lower] = coingecko_address
855
- # حفظ في قاعدة البيانات للمستقبل
856
  self.contracts_db[symbol_lower] = coingecko_address
857
  if self.r2_service:
858
  await self._save_contracts_to_r2()
859
  return coingecko_address
860
 
861
- print(f"⚠️ لم يتم العثور على عنوان عقد لـ {symbol} في أي مصدر")
862
  return None
863
 
864
  async def _find_contract_via_coingecko(self, symbol):
865
- """البحث عن عنوان العقد عبر CoinGecko API"""
866
  try:
867
- # البحث عن ID العملة أولاً
868
  search_url = f"https://api.coingecko.com/api/v3/search?query={symbol}"
869
  async with httpx.AsyncClient(timeout=15) as client:
870
  response = await client.get(search_url)
@@ -877,31 +830,24 @@ class EnhancedWhaleMonitor:
877
  if not coins:
878
  return None
879
 
880
- # أخذ أفضل نتيجة مطابقة
881
  best_coin = coins[0]
882
  coin_id = best_coin.get('id')
883
 
884
  if not coin_id:
885
  return None
886
 
887
- # جلب تفاصيل العملة
888
  detail_url = f"https://api.coingecko.com/api/v3/coins/{coin_id}"
889
  detail_response = await client.get(detail_url)
890
  if detail_response.status_code != 200:
891
  return None
892
 
893
  detail_data = detail_response.json()
894
-
895
- # البحث عن عناوين العقود في المنصات المختلفة
896
  platforms = detail_data.get('platforms', {})
897
 
898
- # إعطاء الأولوية لـ Ethereum ثم BSC ثم Polygon
899
  for platform in ['ethereum', 'binance-smart-chain', 'polygon-pos']:
900
  if platform in platforms and platforms[platform]:
901
  address = platforms[platform]
902
- if address and len(address) == 42: # تأكيد أن العنوان صالح
903
- print(f"✅ تم العثور على عنوان {symbol} على {platform}: {address}")
904
- # تحديد الشبكة المناسبة للرمز
905
  network_map = {
906
  'ethereum': 'ethereum',
907
  'binance-smart-chain': 'bsc',
@@ -913,51 +859,40 @@ class EnhancedWhaleMonitor:
913
  return None
914
 
915
  except Exception as e:
916
- print(f"❌ فشل البحث عن عقد {symbol} عبر CoinGecko: {e}")
917
  return None
918
 
919
  async def _save_contracts_to_r2(self):
920
- """حفظ قاعدة بيانات العقود إلى R2"""
921
  try:
922
  key = "contracts_database.json"
923
  data_json = json.dumps(self.contracts_db, indent=2).encode('utf-8')
924
  self.r2_service.s3_client.put_object(
925
  Bucket="trading", Key=key, Body=data_json, ContentType="application/json"
926
  )
927
- print(f"✅ تم حفظ {len(self.contracts_db)} عقد في R2")
928
  except Exception as e:
929
- print(f"❌ فشل حفظ العقود في R2: {e}")
930
 
931
  async def get_symbol_specific_whale_data(self, symbol, contract_address=None):
932
  try:
933
- print(f"🔍 جلب بيانات الحيتان لـ {symbol}...")
934
  base_symbol = symbol.split("/")[0] if '/' in symbol else symbol
935
 
936
- # البحث عن عنوان العقد إذا لم يتم توفيره
937
  if not contract_address:
938
  contract_address = await self._find_contract_address_enhanced(base_symbol)
939
 
940
  if not contract_address:
941
- print(f"⚠️ لم يتم العثور على عنوان عقد لـ {symbol}")
942
  return await self._scan_networks_for_symbol(symbol, base_symbol)
943
 
944
- # تحديد الشبكة المناسبة للبحث
945
  network = self.symbol_networks.get(base_symbol, 'ethereum')
946
- print(f"🔍 البحث في شبكة {network} للرمز {symbol}")
947
 
948
  api_data = await self._get_combined_api_data(contract_address, network)
949
 
950
  if api_data:
951
  enriched_data = await self._enrich_api_data_with_timing(api_data)
952
  result = self._analyze_symbol_specific_data(enriched_data, symbol)
953
- print(f"✅ تم تحليل بيانات الحيتان لـ {symbol}: {result.get('transfer_count', 0)} تحويل")
954
  return result
955
  else:
956
- print(f"⚠️ لا توجد بيانات API لـ {symbol}")
957
  return await self._scan_networks_for_symbol(symbol, base_symbol)
958
 
959
  except Exception as e:
960
- print(f"❌ فشل جلب بيانات الحيتان لـ {symbol}: {e}")
961
  return {
962
  'data_available': False,
963
  'description': f'غير متوفر - خطأ في جلب بيانات الحيتان',
@@ -969,7 +904,6 @@ class EnhancedWhaleMonitor:
969
  async def _get_combined_api_data(self, contract_address, network='ethereum'):
970
  tasks = []
971
 
972
- # ��ستخدام APIs المتاحة فقط
973
  if self.moralis_key and self._is_valid_moralis_key():
974
  tasks.append(self._get_moralis_token_data(contract_address, network))
975
 
@@ -977,7 +911,6 @@ class EnhancedWhaleMonitor:
977
  tasks.append(self._get_etherscan_token_data_v2(contract_address))
978
 
979
  if not tasks:
980
- print("⚠️ لا توجد مفاتيح API متاحة لجلب بيانات الرموز")
981
  return await self._get_rpc_token_data(contract_address, network)
982
 
983
  results = await asyncio.gather(*tasks, return_exceptions=True)
@@ -988,25 +921,19 @@ class EnhancedWhaleMonitor:
988
  all_transfers.extend(res)
989
 
990
  if not all_transfers:
991
- print("⚠️ فشل جميع APIs، استخدام RPC كبديل")
992
  return await self._get_rpc_token_data(contract_address, network)
993
 
994
- print(f"✅ تم جمع {len(all_transfers)} تحويل من APIs")
995
  return all_transfers
996
 
997
  def _is_valid_moralis_key(self):
998
- """التحقق من أن مفتاح Moralis صالح"""
999
  if not self.moralis_key:
1000
  return False
1001
  return len(self.moralis_key) >= 20
1002
 
1003
  async def _get_rpc_token_data(self, contract_address, network='ethereum'):
1004
  try:
1005
- print(f"🔍 استخدام RPC لجلب بيانات العقد {contract_address} على شبكة {network}")
1006
-
1007
  endpoint = self._get_next_rpc_endpoint(network)
1008
  if not endpoint:
1009
- print(f"❌ لا توجد نقاط RPC متاحة لـ {network}")
1010
  return []
1011
 
1012
  transfers = []
@@ -1023,8 +950,7 @@ class EnhancedWhaleMonitor:
1023
 
1024
  latest_block = int(result, 16)
1025
 
1026
- # مسح آخر 50 كتلة
1027
- for block_offset in range(50):
1028
  block_number = latest_block - block_offset
1029
  if block_number < 0:
1030
  break
@@ -1050,16 +976,13 @@ class EnhancedWhaleMonitor:
1050
  'blockNumber': str(block_number)
1051
  })
1052
 
1053
- print(f"✅ تم جمع {len(transfers)} تحويل من RPC")
1054
  return transfers
1055
 
1056
  except Exception as e:
1057
- print(f"❌ فشل جلب بيانات RPC: {e}")
1058
  return []
1059
 
1060
  async def _get_etherscan_token_data_v2(self, contract_address):
1061
  if not self.etherscan_key:
1062
- print("⚠️ مفتاح Etherscan غير متوفر")
1063
  return []
1064
 
1065
  try:
@@ -1083,38 +1006,26 @@ class EnhancedWhaleMonitor:
1083
  response = await client.get(base_url, params=params)
1084
 
1085
  if response.status_code == 429:
1086
- print("⏰ تجاوز حد المعدل في Etherscan")
1087
  await asyncio.sleep(2)
1088
  return []
1089
  elif response.status_code == 401:
1090
- print("❌ خطأ في مصادقة Etherscan - المفتاح غير صالح")
1091
  return []
1092
  elif response.status_code >= 500:
1093
- print(f"❌ خطأ في خادم Etherscan: {response.status_code}")
1094
  return []
1095
 
1096
  response.raise_for_status()
1097
  data = response.json()
1098
 
1099
  if data.get('status') == '1' and data.get('message') == 'OK':
1100
- result = data.get('result', [])
1101
- print(f"✅ تم جلب {len(result)} تحويل من Etherscan")
1102
- return result
1103
  else:
1104
- error_msg = data.get('result', data.get('message', 'Unknown error'))
1105
- print(f"⚠️ استجابة غير متوقعة من Etherscan: {error_msg}")
1106
  return []
1107
 
1108
- except httpx.HTTPStatusError as e:
1109
- print(f"❌ خطأ HTTP في Etherscan: {e}")
1110
- return []
1111
  except Exception as e:
1112
- print(f"❌ خطأ عام في Etherscan: {e}")
1113
  return []
1114
 
1115
  async def _get_moralis_token_data(self, contract_address, network='ethereum'):
1116
  if not self.moralis_key or not self._is_valid_moralis_key():
1117
- print("⚠️ مفتاح Moralis غير متوفر أو غير صالح")
1118
  return []
1119
 
1120
  try:
@@ -1131,7 +1042,6 @@ class EnhancedWhaleMonitor:
1131
 
1132
  chain_id = chains.get(network)
1133
  if not chain_id:
1134
- print(f"⚠️ شبكة {network} غير مدعومة في Moralis")
1135
  return []
1136
 
1137
  all_transfers = []
@@ -1153,25 +1063,19 @@ class EnhancedWhaleMonitor:
1153
  if response.status_code == 200:
1154
  result = response.json().get('result', [])
1155
  all_transfers.extend(result)
1156
- print(f"✅ تم جلب {len(result)} تحويل من Moralis ({network})")
1157
  elif response.status_code == 401:
1158
- print(f"❌ خطأ في مصادقة Moralis - المفتاح غير صالح")
1159
  return []
1160
  elif response.status_code == 404:
1161
- print(f"⚠️ لم يتم العثور على بيانات للعقد {contract_address} على {network}")
1162
  return []
1163
  else:
1164
- print(f"⚠️ استجابة غير ناجحة من Moralis لـ {network}: {response.status_code}")
1165
  return []
1166
 
1167
  except Exception as chain_error:
1168
- print(f"❌ خطأ في Moralis لـ {network}: {chain_error}")
1169
  return []
1170
 
1171
  return all_transfers
1172
 
1173
  except Exception as e:
1174
- print(f"❌ خطأ عام في Moralis: {e}")
1175
  return []
1176
 
1177
  async def _enrich_api_data_with_timing(self, api_data):
@@ -1211,7 +1115,6 @@ class EnhancedWhaleMonitor:
1211
  enriched_data.append(enriched_transfer)
1212
 
1213
  except Exception as e:
1214
- print(f"⚠️ خطأ في توقيت البيانات: {e}")
1215
  continue
1216
 
1217
  return enriched_data
@@ -1232,11 +1135,11 @@ class EnhancedWhaleMonitor:
1232
 
1233
  for transfer in enriched_data:
1234
  value = float(transfer.get('value', 0))
1235
- if value > 1e15: # تحويل من wei إلى ether
1236
  value = value / 1e18
1237
  volumes.append(value)
1238
 
1239
- if value > 10000: # تحويل كبير
1240
  large_transfers.append(transfer)
1241
 
1242
  total_volume = sum(volumes)
@@ -1275,7 +1178,6 @@ class EnhancedWhaleMonitor:
1275
  }
1276
 
1277
  except Exception as e:
1278
- print(f"❌ خطأ في تحليل بيانات {symbol}: {e}")
1279
  return {
1280
  'data_available': False,
1281
  'description': f'غير متوفر - خطأ في تحليل البيانات',
@@ -1292,7 +1194,6 @@ class EnhancedWhaleMonitor:
1292
  if self.data_manager:
1293
  native_price = await self.data_manager.get_native_coin_price(network)
1294
  if native_price:
1295
- print(f"✅ تم اكتشاف {symbol} على شبكة {network} - سعر {network.upper()}: ${native_price:.2f}")
1296
  return {
1297
  'data_available': True,
1298
  'description': f'تم اكتشاف {symbol} على شبكة {network}',
@@ -1301,10 +1202,8 @@ class EnhancedWhaleMonitor:
1301
  'source': 'network_scan'
1302
  }
1303
  except Exception as e:
1304
- print(f"⚠️ فشل مسح شبكة {network} لـ {symbol}: {e}")
1305
  continue
1306
 
1307
- print(f"❌ لم يتم العثور على {symbol} على أي شبكة")
1308
  return {
1309
  'data_available': False,
1310
  'description': f'غير متوفر - لم يتم العثور على {symbol} على أي شبكة',
@@ -1401,66 +1300,9 @@ class EnhancedWhaleMonitor:
1401
  return signal
1402
 
1403
  except Exception as e:
1404
- print(f"❌ خطأ في توليد إشارة الحيتان: {e}")
1405
  return None
1406
 
1407
- async def track_pattern_outcome(self, symbol, pattern_analysis, success, profit_percent):
1408
- if not pattern_analysis:
1409
- return
1410
-
1411
- pattern_name = pattern_analysis.get('pattern_detected')
1412
- confidence = pattern_analysis.get('pattern_confidence', 0)
1413
-
1414
- if pattern_name not in ['no_clear_pattern', 'insufficient_data']:
1415
- if pattern_name not in self.pattern_performance:
1416
- self.pattern_performance[pattern_name] = {
1417
- 'total_trades': 0,
1418
- 'successful_trades': 0,
1419
- 'total_profit': 0,
1420
- 'total_confidence': 0,
1421
- 'last_updated': datetime.now().isoformat()
1422
- }
1423
-
1424
- stats = self.pattern_performance[pattern_name]
1425
- stats['total_trades'] += 1
1426
- stats['total_confidence'] += confidence
1427
- stats['last_updated'] = datetime.now().isoformat()
1428
-
1429
- if success:
1430
- stats['successful_trades'] += 1
1431
- stats['total_profit'] += profit_percent
1432
-
1433
- if stats['total_trades'] > 0:
1434
- self.pattern_success_rates[pattern_name] = {
1435
- 'success_rate': stats['successful_trades'] / stats['total_trades'],
1436
- 'avg_profit': stats['total_profit'] / stats['total_trades'],
1437
- 'total_trades': stats['total_trades'],
1438
- 'last_updated': datetime.now().isoformat()
1439
- }
1440
-
1441
- if stats['total_trades'] % 10 == 0:
1442
- await self._save_pattern_performance()
1443
-
1444
- print(f"✅ تم تحديث أداء النمط {pattern_name}: {stats['successful_trades']}/{stats['total_trades']} نجاح")
1445
-
1446
- def get_pattern_reliability(self, pattern_name):
1447
- if pattern_name in self.pattern_success_rates:
1448
- return self.pattern_success_rates[pattern_name]['success_rate']
1449
- return 0.5
1450
-
1451
- async def save_all_pattern_data(self):
1452
- await self._save_pattern_performance()
1453
-
1454
- def get_pattern_performance_summary(self):
1455
- return {
1456
- 'pattern_performance': self.pattern_performance,
1457
- 'pattern_success_rates': self.pattern_success_rates,
1458
- 'total_patterns_tracked': len(self.pattern_performance),
1459
- 'last_updated': datetime.now().isoformat()
1460
- }
1461
-
1462
  async def cleanup(self):
1463
  await self.http_client.aclose()
1464
- print("✅ تم تنظيف موارد EnhancedWhaleMonitor")
1465
 
1466
  print("✅ EnhancedWhaleMonitor loaded - Real-time whale activity monitoring ready")
 
8
  from collections import defaultdict, deque
9
  import ccxt.pro as ccxt
10
  import numpy as np
11
+ import logging
12
+
13
+ # تعطيل تسجيل HTTP المزعج
14
+ logging.getLogger("httpx").setLevel(logging.WARNING)
15
+ logging.getLogger("httpcore").setLevel(logging.WARNING)
16
 
17
  class EnhancedWhaleMonitor:
18
  def __init__(self, contracts_db=None, r2_service=None):
19
+ # تعطيل التسجيل التفصيلي لـ HTTP Client
20
+ self.http_client = httpx.AsyncClient(
21
+ timeout=15.0,
22
+ limits=httpx.Limits(max_connections=50, max_keepalive_connections=10),
23
+ follow_redirects=True
24
+ )
25
 
26
  self.moralis_key = os.getenv("MORALIS_KEY")
27
  self.etherscan_key = os.getenv("ETHERSCAN_KEY")
 
109
  self.price_cache = {}
110
  self.last_scan_time = {}
111
 
112
+ self.contract_cache = {}
113
+ self.symbol_networks = {}
114
 
115
  self.pattern_performance = {}
116
  self.pattern_success_rates = {}
 
118
  if self.r2_service:
119
  asyncio.create_task(self._load_pattern_performance())
120
 
 
121
  if self.r2_service:
122
  asyncio.create_task(self._load_contracts_from_r2())
123
 
 
168
  response = self.r2_service.s3_client.get_object(Bucket="trading", Key=key)
169
  contracts_data = json.loads(response['Body'].read())
170
 
 
171
  self.contracts_db.update(contracts_data)
172
  print(f"✅ تم تحميل {len(contracts_data)} عقد من R2")
173
 
 
203
 
204
  async def _load_pattern_performance(self):
205
  if not self.r2_service:
 
206
  return
207
 
208
  try:
 
211
  data = json.loads(response['Body'].read())
212
  self.pattern_performance = data.get('pattern_performance', {})
213
  self.pattern_success_rates = data.get('pattern_success_rates', {})
 
214
  except Exception as e:
 
215
  self.pattern_performance = {}
216
  self.pattern_success_rates = {}
217
 
218
  async def _save_pattern_performance(self):
219
  if not self.r2_service:
 
220
  return
221
 
222
  try:
 
232
  self.r2_service.s3_client.put_object(
233
  Bucket="trading", Key=key, Body=data_json, ContentType="application/json"
234
  )
 
235
  except Exception as e:
236
  print(f"❌ فشل حفظ بيانات أداء الأنماط: {e}")
237
 
 
265
  self.address_categories['unknown'].add(address_lower)
266
  return 'unknown'
267
  except Exception as e:
 
268
  return 'unknown'
269
 
270
  def _detect_exchange_pattern(self, transactions):
 
302
  address_lower in self.address_categories['exchange'] or
303
  self.address_labels.get(address_lower) in ['cex', 'suspected_cex'])
304
  except Exception as e:
 
305
  return False
306
 
307
  async def _update_netflow_metrics(self, network, token_symbol, from_address, to_address, value_usd, transaction_hash):
 
331
  self.netflow_data[network][token_symbol]['netflow'].append(current_netflow)
332
 
333
  except Exception as e:
334
+ pass
335
 
336
  def _initialize_token_metrics(self, network, token_symbol):
337
  self.netflow_data[network][token_symbol] = {
 
371
  return zscore
372
 
373
  except Exception as e:
 
374
  return 0
375
 
376
  def _generate_netflow_signal(self, network, token_symbol):
 
445
  return signal
446
 
447
  except Exception as e:
 
448
  return None
449
 
450
  async def _scan_single_evm_network(self, network):
 
453
 
454
  try:
455
  if not self.data_manager:
 
456
  return [], []
457
 
458
  price_usd = await self.data_manager.get_native_coin_price(network)
459
  if price_usd is None:
 
460
  return [], []
461
 
462
  latest_block_hex = await self._call_rpc_async(network, 'eth_blockNumber')
463
  if not latest_block_hex:
 
464
  return [], []
465
 
466
  latest_block = int(latest_block_hex, 16)
 
518
  })
519
  whale_transactions_found += 1
520
 
521
+ await asyncio.sleep(0.05)
 
522
 
523
  signal = self._generate_netflow_signal(network, 'NATIVE')
524
  if signal:
525
  trading_signals.append(signal)
526
 
 
527
  return whale_alerts, trading_signals
528
 
529
  except Exception as e:
 
530
  return [], []
531
 
532
  async def get_general_whale_activity(self):
533
  try:
 
534
  tasks = []
535
  networks_to_scan = ['ethereum', 'bsc']
536
  for network in networks_to_scan:
 
548
  all_alerts.extend(alerts)
549
  all_signals.extend(signals)
550
  successful_networks += 1
 
551
  else:
552
+ pass
553
 
554
  all_alerts.sort(key=lambda x: x['timestamp'], reverse=True)
555
 
 
582
  'flow_direction': 'BALANCED'
583
  }
584
  }
 
585
  return result
586
 
587
  latest_alert = all_alerts[0] if all_alerts else None
588
  latest_time_info = f"آخر نشاط منذ {latest_alert['minutes_ago']:.1f} دقيقة" if latest_alert else ""
589
 
 
590
  flow_direction = 'BALANCED'
591
  if net_exchange_flow < 0:
592
  flow_direction = 'TO_EXCHANGES'
 
657
 
658
  except Exception as e:
659
  print(f"❌ فشل مراقبة الحيتان العامة: {e}")
 
 
660
  return {
661
  'data_available': False,
662
  'description': f'غير متوفر - فشل في مراقبة الحيتان: {str(e)}',
 
670
  }
671
 
672
  async def _call_rpc_async(self, network, method, params=[]):
673
+ max_retries = 2
674
 
675
  for attempt in range(max_retries):
676
  endpoint = self._get_next_rpc_endpoint(network)
677
  if not endpoint:
 
678
  return None
679
 
680
  try:
 
686
 
687
  payload = {"jsonrpc": "2.0", "method": method, "params": params, "id": 1}
688
 
689
+ timeout = 20.0
690
 
691
  async with httpx.AsyncClient(timeout=timeout) as client:
692
  response = await client.post(endpoint, json=payload)
693
 
694
  if response.status_code == 401:
 
695
  self._remove_rpc_endpoint(network, endpoint)
696
  continue
697
  elif response.status_code == 429:
698
+ await asyncio.sleep(1 * (attempt + 1))
 
699
  continue
700
 
701
  response.raise_for_status()
 
704
  self.rpc_failures[network] = 0
705
  return result
706
 
 
 
 
 
 
 
 
 
 
 
 
 
 
707
  except Exception as e:
708
  self.rpc_failures[network] += 1
 
709
 
710
  if attempt < max_retries - 1:
711
+ await asyncio.sleep(0.5)
712
 
 
713
  return None
714
 
715
  def _get_next_rpc_endpoint(self, network):
 
729
  def _remove_rpc_endpoint(self, network, endpoint):
730
  if network in self.rpc_endpoints and endpoint in self.rpc_endpoints[network]:
731
  self.rpc_endpoints[network].remove(endpoint)
 
732
 
733
  if self.current_rpc_index[network] >= len(self.rpc_endpoints[network]):
734
  self.current_rpc_index[network] = 0
 
771
  if api_name == 'etherscan':
772
  if stats['requests_per_second'] > 4:
773
  delay = 0.2 * (stats['requests_per_second'] - 4)
 
774
  await asyncio.sleep(delay)
775
 
776
  if stats['requests_today'] > 95000:
 
777
  return True
778
 
779
  elif api_name == 'infura':
780
  if stats['requests_per_second'] > 90:
781
  delay = 0.1 * (stats['requests_per_second'] - 90)
 
782
  await asyncio.sleep(delay)
783
 
784
  if stats['requests_today'] > 99000:
 
785
  return True
786
 
787
  elif api_name == 'moralis':
788
  if stats['requests_per_second'] > 4:
789
  delay = 0.2 * (stats['requests_per_second'] - 4)
 
790
  await asyncio.sleep(delay)
791
 
792
  if stats['requests_today'] > 95000:
 
793
  return True
794
 
795
  return False
796
 
797
  async def _find_contract_address_enhanced(self, symbol):
 
798
  base_symbol = symbol.split("/")[0] if '/' in symbol else symbol
799
  symbol_lower = base_symbol.lower()
800
 
 
801
  if symbol_lower in self.contract_cache:
802
  return self.contract_cache[symbol_lower]
803
 
 
804
  for key, address in self.contracts_db.items():
805
  if symbol_lower in key.lower():
806
  self.contract_cache[symbol_lower] = address
 
807
  return address
808
 
 
809
  coingecko_address = await self._find_contract_via_coingecko(base_symbol)
810
  if coingecko_address:
811
  self.contract_cache[symbol_lower] = coingecko_address
 
812
  self.contracts_db[symbol_lower] = coingecko_address
813
  if self.r2_service:
814
  await self._save_contracts_to_r2()
815
  return coingecko_address
816
 
 
817
  return None
818
 
819
  async def _find_contract_via_coingecko(self, symbol):
 
820
  try:
 
821
  search_url = f"https://api.coingecko.com/api/v3/search?query={symbol}"
822
  async with httpx.AsyncClient(timeout=15) as client:
823
  response = await client.get(search_url)
 
830
  if not coins:
831
  return None
832
 
 
833
  best_coin = coins[0]
834
  coin_id = best_coin.get('id')
835
 
836
  if not coin_id:
837
  return None
838
 
 
839
  detail_url = f"https://api.coingecko.com/api/v3/coins/{coin_id}"
840
  detail_response = await client.get(detail_url)
841
  if detail_response.status_code != 200:
842
  return None
843
 
844
  detail_data = detail_response.json()
 
 
845
  platforms = detail_data.get('platforms', {})
846
 
 
847
  for platform in ['ethereum', 'binance-smart-chain', 'polygon-pos']:
848
  if platform in platforms and platforms[platform]:
849
  address = platforms[platform]
850
+ if address and len(address) == 42:
 
 
851
  network_map = {
852
  'ethereum': 'ethereum',
853
  'binance-smart-chain': 'bsc',
 
859
  return None
860
 
861
  except Exception as e:
 
862
  return None
863
 
864
  async def _save_contracts_to_r2(self):
 
865
  try:
866
  key = "contracts_database.json"
867
  data_json = json.dumps(self.contracts_db, indent=2).encode('utf-8')
868
  self.r2_service.s3_client.put_object(
869
  Bucket="trading", Key=key, Body=data_json, ContentType="application/json"
870
  )
 
871
  except Exception as e:
872
+ pass
873
 
874
  async def get_symbol_specific_whale_data(self, symbol, contract_address=None):
875
  try:
 
876
  base_symbol = symbol.split("/")[0] if '/' in symbol else symbol
877
 
 
878
  if not contract_address:
879
  contract_address = await self._find_contract_address_enhanced(base_symbol)
880
 
881
  if not contract_address:
 
882
  return await self._scan_networks_for_symbol(symbol, base_symbol)
883
 
 
884
  network = self.symbol_networks.get(base_symbol, 'ethereum')
 
885
 
886
  api_data = await self._get_combined_api_data(contract_address, network)
887
 
888
  if api_data:
889
  enriched_data = await self._enrich_api_data_with_timing(api_data)
890
  result = self._analyze_symbol_specific_data(enriched_data, symbol)
 
891
  return result
892
  else:
 
893
  return await self._scan_networks_for_symbol(symbol, base_symbol)
894
 
895
  except Exception as e:
 
896
  return {
897
  'data_available': False,
898
  'description': f'غير متوفر - خطأ في جلب بيانات الحيتان',
 
904
  async def _get_combined_api_data(self, contract_address, network='ethereum'):
905
  tasks = []
906
 
 
907
  if self.moralis_key and self._is_valid_moralis_key():
908
  tasks.append(self._get_moralis_token_data(contract_address, network))
909
 
 
911
  tasks.append(self._get_etherscan_token_data_v2(contract_address))
912
 
913
  if not tasks:
 
914
  return await self._get_rpc_token_data(contract_address, network)
915
 
916
  results = await asyncio.gather(*tasks, return_exceptions=True)
 
921
  all_transfers.extend(res)
922
 
923
  if not all_transfers:
 
924
  return await self._get_rpc_token_data(contract_address, network)
925
 
 
926
  return all_transfers
927
 
928
  def _is_valid_moralis_key(self):
 
929
  if not self.moralis_key:
930
  return False
931
  return len(self.moralis_key) >= 20
932
 
933
  async def _get_rpc_token_data(self, contract_address, network='ethereum'):
934
  try:
 
 
935
  endpoint = self._get_next_rpc_endpoint(network)
936
  if not endpoint:
 
937
  return []
938
 
939
  transfers = []
 
950
 
951
  latest_block = int(result, 16)
952
 
953
+ for block_offset in range(20):
 
954
  block_number = latest_block - block_offset
955
  if block_number < 0:
956
  break
 
976
  'blockNumber': str(block_number)
977
  })
978
 
 
979
  return transfers
980
 
981
  except Exception as e:
 
982
  return []
983
 
984
  async def _get_etherscan_token_data_v2(self, contract_address):
985
  if not self.etherscan_key:
 
986
  return []
987
 
988
  try:
 
1006
  response = await client.get(base_url, params=params)
1007
 
1008
  if response.status_code == 429:
 
1009
  await asyncio.sleep(2)
1010
  return []
1011
  elif response.status_code == 401:
 
1012
  return []
1013
  elif response.status_code >= 500:
 
1014
  return []
1015
 
1016
  response.raise_for_status()
1017
  data = response.json()
1018
 
1019
  if data.get('status') == '1' and data.get('message') == 'OK':
1020
+ return data.get('result', [])
 
 
1021
  else:
 
 
1022
  return []
1023
 
 
 
 
1024
  except Exception as e:
 
1025
  return []
1026
 
1027
  async def _get_moralis_token_data(self, contract_address, network='ethereum'):
1028
  if not self.moralis_key or not self._is_valid_moralis_key():
 
1029
  return []
1030
 
1031
  try:
 
1042
 
1043
  chain_id = chains.get(network)
1044
  if not chain_id:
 
1045
  return []
1046
 
1047
  all_transfers = []
 
1063
  if response.status_code == 200:
1064
  result = response.json().get('result', [])
1065
  all_transfers.extend(result)
 
1066
  elif response.status_code == 401:
 
1067
  return []
1068
  elif response.status_code == 404:
 
1069
  return []
1070
  else:
 
1071
  return []
1072
 
1073
  except Exception as chain_error:
 
1074
  return []
1075
 
1076
  return all_transfers
1077
 
1078
  except Exception as e:
 
1079
  return []
1080
 
1081
  async def _enrich_api_data_with_timing(self, api_data):
 
1115
  enriched_data.append(enriched_transfer)
1116
 
1117
  except Exception as e:
 
1118
  continue
1119
 
1120
  return enriched_data
 
1135
 
1136
  for transfer in enriched_data:
1137
  value = float(transfer.get('value', 0))
1138
+ if value > 1e15:
1139
  value = value / 1e18
1140
  volumes.append(value)
1141
 
1142
+ if value > 10000:
1143
  large_transfers.append(transfer)
1144
 
1145
  total_volume = sum(volumes)
 
1178
  }
1179
 
1180
  except Exception as e:
 
1181
  return {
1182
  'data_available': False,
1183
  'description': f'غير متوفر - خطأ في تحليل البيانات',
 
1194
  if self.data_manager:
1195
  native_price = await self.data_manager.get_native_coin_price(network)
1196
  if native_price:
 
1197
  return {
1198
  'data_available': True,
1199
  'description': f'تم اكتشاف {symbol} على شبكة {network}',
 
1202
  'source': 'network_scan'
1203
  }
1204
  except Exception as e:
 
1205
  continue
1206
 
 
1207
  return {
1208
  'data_available': False,
1209
  'description': f'غير متوفر - لم يتم العثور على {symbol} على أي شبكة',
 
1300
  return signal
1301
 
1302
  except Exception as e:
 
1303
  return None
1304
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1305
  async def cleanup(self):
1306
  await self.http_client.aclose()
 
1307
 
1308
  print("✅ EnhancedWhaleMonitor loaded - Real-time whale activity monitoring ready")