Riy777 commited on
Commit
00bb5c9
·
1 Parent(s): 014b082

Update data_manager.py

Browse files
Files changed (1) hide show
  1. data_manager.py +9 -1080
data_manager.py CHANGED
@@ -1,1073 +1,14 @@
1
- # data_manager.py - الإصدار المحسن مع تحليل صافي التدفق الذكي
2
- import os, asyncio, httpx, json, traceback, backoff, re, time, math
3
- from datetime import datetime, timedelta
4
- from functools import wraps
5
- from collections import defaultdict, deque
 
6
  import ccxt.pro as ccxt
7
- from ccxt.base.errors import RateLimitExceeded, DDoSProtection, NetworkError
8
- import pandas as pd
9
- import numpy as np
10
  from state import MARKET_STATE_OK
11
 
12
- # --- 🐋 نظام تتبع الحيتان المحسن مع تحليل صافي التدفق ---
13
- class EnhancedWhaleMonitor:
14
- def __init__(self, contracts_db=None):
15
- self.http_client = httpx.AsyncClient(timeout=15.0, limits=httpx.Limits(max_connections=50, max_keepalive_connections=10))
16
-
17
- # 🔑 استخدام مفاتيح API من متغيرات البيئة فقط
18
- self.moralis_key = os.getenv("MORALIS_KEY")
19
- self.etherscan_key = os.getenv("ETHERSCAN_KEY")
20
- self.infura_key = os.getenv("INFURA_KEY")
21
-
22
- self.whale_threshold_usd = 100000
23
- self.contracts_db = contracts_db or {}
24
-
25
- # قاعدة بيانات العناوين المصنفة ديناميكياً
26
- self.address_labels = {}
27
- self._initialize_dynamic_labels()
28
-
29
- # تخزين بيانات صافي التدفق
30
- self.netflow_data = {
31
- 'ethereum': defaultdict(lambda: {
32
- 'inflow': deque(maxlen=288),
33
- 'outflow': deque(maxlen=288),
34
- 'netflow': deque(maxlen=288),
35
- 'timestamps': deque(maxlen=288),
36
- 'volume_24h': 0
37
- }),
38
- 'bsc': defaultdict(lambda: {
39
- 'inflow': deque(maxlen=288),
40
- 'outflow': deque(maxlen=288),
41
- 'netflow': deque(maxlen=288),
42
- 'timestamps': deque(maxlen=288),
43
- 'volume_24h': 0
44
- })
45
- }
46
-
47
- # إحصائيات استخدام APIs
48
- self.api_usage_stats = {
49
- 'etherscan': {
50
- 'requests_today': 0,
51
- 'requests_per_second': 0,
52
- 'last_request_time': time.time(),
53
- 'last_reset': datetime.now().date()
54
- },
55
- 'infura': {
56
- 'requests_today': 0,
57
- 'requests_per_second': 0,
58
- 'last_request_time': time.time(),
59
- 'last_reset': datetime.now().date()
60
- }
61
- }
62
-
63
- # مصادر RPC متعددة
64
- self.rpc_endpoints = {
65
- 'ethereum': [
66
- 'https://rpc.ankr.com/eth',
67
- 'https://cloudflare-eth.com',
68
- 'https://eth.llamarpc.com'
69
- ],
70
- 'bsc': [
71
- 'https://bsc-dataseed.binance.org/',
72
- 'https://bsc-dataseed1.defibit.io/',
73
- 'https://bsc-dataseed1.ninicoin.io/'
74
- ]
75
- }
76
-
77
- # إضافة Infura إذا كان المفتاح متوفرًا
78
- if self.infura_key:
79
- infura_endpoint = f"https://mainnet.infura.io/v3/{self.infura_key}"
80
- self.rpc_endpoints['ethereum'].insert(0, infura_endpoint)
81
- print(f"✅ تم تكوين Infura بنجاح - الشبكة: Ethereum")
82
-
83
- self.current_rpc_index = {network: 0 for network in self.rpc_endpoints.keys()}
84
- self.rpc_failures = {network: 0 for network in self.rpc_endpoints.keys()}
85
-
86
- self.price_cache = {}
87
- self.last_scan_time = {}
88
-
89
- # رموز KuCoin للعملات
90
- self.kucoin_symbols = {
91
- 'ethereum': 'ETH',
92
- 'bsc': 'BNB'
93
- }
94
-
95
- print("🎯 نظام تتبع الحيتان المحسن - تحليل صافي التدفق الذكي مفعل")
96
-
97
- def _initialize_dynamic_labels(self):
98
- """تهيئة التصنيفات الديناميكية للعناوين"""
99
- # فئات التصنيف
100
- self.address_categories = {
101
- 'exchange': set(),
102
- 'cex': set(),
103
- 'dex': set(),
104
- 'institution': set(),
105
- 'whale': set(),
106
- 'contract': set(),
107
- 'unknown': set()
108
- }
109
-
110
- # أنماط العناوين للمنصات المركزية
111
- self.exchange_patterns = {
112
- 'binance': ['0x3f5ce5fbfe3e9af3971dd833d26ba9b5c936f0be', '0xd551234ae421e3bcba99a0da6d736074f22192ff'],
113
- 'coinbase': ['0x71660c4005ba85c37ccec55d0c4493e66fe775d3', '0x503828976d22510aad0201ac7ec88293211d23da'],
114
- 'kraken': ['0x2910543af39aba0cd09dbb2d50200b3e800a63d2', '0xa160cdab225685da1d56aa342ad8841c3b53f291'],
115
- 'kucoin': ['0x2b5634c42055806a59e9107ed44d43c426e58258', '0x689c56aef474df92d44a1b70850f808488f9769c']
116
- }
117
-
118
- # تحميل العناوين الأولية
119
- self._load_initial_exchange_addresses()
120
-
121
- def _load_initial_exchange_addresses(self):
122
- """تحميل عناوين المنصات المعروفة مبدئياً"""
123
- for exchange, addresses in self.exchange_patterns.items():
124
- for address in addresses:
125
- self.address_labels[address.lower()] = 'cex'
126
- self.address_categories['cex'].add(address.lower())
127
- self.address_categories['exchange'].add(address.lower())
128
-
129
- def _classify_address_dynamic(self, address, transaction_history=None):
130
- """تصنيف ديناميكي للعناوين بناءً على الأنماط السلوكية"""
131
- address_lower = address.lower()
132
-
133
- # التحقق من العناوين المصنفة مسبقاً
134
- if address_lower in self.address_labels:
135
- return self.address_labels[address_lower]
136
-
137
- # تصنيف بناءً على أنماط المعاملات
138
- if transaction_history:
139
- if self._detect_exchange_pattern(transaction_history):
140
- self.address_labels[address_lower] = 'suspected_cex'
141
- self.address_categories['cex'].add(address_lower)
142
- return 'suspected_cex'
143
-
144
- if self._detect_whale_pattern(transaction_history):
145
- self.address_labels[address_lower] = 'suspected_whale'
146
- self.address_categories['whale'].add(address_lower)
147
- return 'suspected_whale'
148
-
149
- if self._detect_contract_pattern(transaction_history):
150
- self.address_labels[address_lower] = 'contract_user'
151
- self.address_categories['contract'].add(address_lower)
152
- return 'contract_user'
153
-
154
- # إذا لم يتم التصنيف، نضيفه للمجهول
155
- self.address_labels[address_lower] = 'unknown'
156
- self.address_categories['unknown'].add(address_lower)
157
- return 'unknown'
158
-
159
- def _detect_exchange_pattern(self, transactions):
160
- """اكتشاف نمط المنصات"""
161
- if len(transactions) < 10:
162
- return False
163
-
164
- unique_senders = set()
165
- unique_receivers = set()
166
-
167
- for tx in transactions[-20:]:
168
- if 'from' in tx:
169
- unique_senders.add(tx['from'])
170
- if 'to' in tx:
171
- unique_receivers.add(tx['to'])
172
-
173
- if len(unique_senders) > 15 and len(unique_receivers) < 5:
174
- return True
175
-
176
- return False
177
-
178
- def _detect_whale_pattern(self, transactions):
179
- """اكتشاف نمط الحيتان"""
180
- large_txs = [tx for tx in transactions if tx.get('value_usd', 0) > 100000]
181
- return len(large_txs) >= 3
182
-
183
- def _detect_contract_pattern(self, transactions):
184
- """اكتشاف نمط العقود"""
185
- contract_interactions = [tx for tx in transactions if tx.get('to', '') and len(tx.get('to', '')) == 42 and tx.get('input', '0x') != '0x']
186
- return len(contract_interactions) > len(transactions) * 0.7
187
-
188
- def _is_exchange_address(self, address):
189
- """التحقق إذا كان العنوان ينتمي لمنصة"""
190
- address_lower = address.lower()
191
- return (address_lower in self.address_categories['cex'] or
192
- address_lower in self.address_categories['exchange'] or
193
- self.address_labels.get(address_lower) in ['cex', 'suspected_cex'])
194
-
195
- async def _update_netflow_metrics(self, network, token_symbol, from_address, to_address, value_usd, transaction_hash):
196
- """تحديث مقاييس صافي التدفق مع التصنيف الذكي"""
197
- try:
198
- # تصنيف العناوين
199
- from_label = self._classify_address_dynamic(from_address)
200
- to_label = self._classify_address_dynamic(to_address)
201
-
202
- # تحديث التدفق الداخل إلى المنصات
203
- if self._is_exchange_address(to_address):
204
- if token_symbol not in self.netflow_data[network]:
205
- self._initialize_token_metrics(network, token_symbol)
206
-
207
- self.netflow_data[network][token_symbol]['inflow'].append(value_usd)
208
- self.netflow_data[network][token_symbol]['timestamps'].append(datetime.now())
209
-
210
- print(f"📥 تدفق إلى منصة: {value_usd:,.0f} USD ({token_symbol})")
211
-
212
- # تحديث التدفق الخارج من المنصات
213
- if self._is_exchange_address(from_address):
214
- if token_symbol not in self.netflow_data[network]:
215
- self._initialize_token_metrics(network, token_symbol)
216
-
217
- self.netflow_data[network][token_symbol]['outflow'].append(value_usd)
218
- self.netflow_data[network][token_symbol]['timestamps'].append(datetime.now())
219
-
220
- print(f"📤 تدفق من منصة: {value_usd:,.0f} USD ({token_symbol})")
221
-
222
- # حساب صافي التدفق الحالي
223
- if token_symbol in self.netflow_data[network]:
224
- current_inflow = sum(list(self.netflow_data[network][token_symbol]['inflow'])[-12:])
225
- current_outflow = sum(list(self.netflow_data[network][token_symbol]['outflow'])[-12:])
226
- current_netflow = current_inflow - current_outflow
227
-
228
- self.netflow_data[network][token_symbol]['netflow'].append(current_netflow)
229
-
230
- except Exception as e:
231
- print(f"⚠️ خطأ في تحديث مقاييس صافي التدفق: {e}")
232
-
233
- def _initialize_token_metrics(self, network, token_symbol):
234
- """تهيئة مقاييس الرمز المميز"""
235
- self.netflow_data[network][token_symbol] = {
236
- 'inflow': deque(maxlen=288),
237
- 'outflow': deque(maxlen=288),
238
- 'netflow': deque(maxlen=288),
239
- 'timestamps': deque(maxlen=288),
240
- 'volume_24h': 0
241
- }
242
-
243
- def _calculate_netflow_zscore(self, network, token_symbol, window_hours=24):
244
- """حساب Z-score لصافي التدفق"""
245
- try:
246
- if token_symbol not in self.netflow_data[network]:
247
- return 0
248
-
249
- data = self.netflow_data[network][token_symbol]
250
- netflow_values = list(data['netflow'])
251
-
252
- if len(netflow_values) < 10:
253
- return 0
254
-
255
- window_size = min(len(netflow_values), window_hours * 12)
256
- recent_values = netflow_values[-window_size:]
257
-
258
- if len(recent_values) < 5:
259
- return 0
260
-
261
- mean_val = np.mean(recent_values)
262
- std_val = np.std(recent_values)
263
-
264
- if std_val == 0:
265
- return 0
266
-
267
- current_netflow = recent_values[-1] if recent_values else 0
268
- zscore = (current_netflow - mean_val) / std_val
269
-
270
- return zscore
271
-
272
- except Exception as e:
273
- print(f"⚠️ خطأ في حساب Z-score: {e}")
274
- return 0
275
-
276
- def _generate_netflow_signal(self, network, token_symbol):
277
- """توليد إشارات تداول بناءً على صافي التدفق"""
278
- try:
279
- if token_symbol not in self.netflow_data[network]:
280
- return None
281
-
282
- data = self.netflow_data[network][token_symbol]
283
- netflow_values = list(data['netflow'])
284
-
285
- if len(netflow_values) < 12:
286
- return None
287
-
288
- recent_inflow = sum(list(data['inflow'])[-12:])
289
- recent_outflow = sum(list(data['outflow'])[-12:])
290
- recent_netflow = recent_inflow - recent_outflow
291
-
292
- zscore = self._calculate_netflow_zscore(network, token_symbol)
293
-
294
- signal = {
295
- 'symbol': token_symbol,
296
- 'network': network,
297
- 'netflow_1h': recent_netflow,
298
- 'inflow_1h': recent_inflow,
299
- 'outflow_1h': recent_outflow,
300
- 'z_score': zscore,
301
- 'timestamp': datetime.now().isoformat()
302
- }
303
-
304
- if recent_netflow < -500000 and zscore < -2.5:
305
- signal.update({
306
- 'action': 'STRONG_SELL',
307
- 'confidence': min(0.95, abs(zscore) / 3),
308
- 'reason': f'تدفق بيعي قوي: ${abs(recent_netflow):,.0f} إلى المنصات',
309
- 'critical_alert': abs(recent_netflow) > 1000000
310
- })
311
- return signal
312
-
313
- elif recent_netflow < -100000 and zscore < -1.5:
314
- signal.update({
315
- 'action': 'SELL',
316
- 'confidence': min(0.8, abs(zscore) / 2),
317
- 'reason': f'تدفق بيعي: ${abs(recent_netflow):,.0f} إلى المنصات',
318
- 'critical_alert': False
319
- })
320
- return signal
321
-
322
- elif recent_netflow > 500000 and zscore > 2.5:
323
- signal.update({
324
- 'action': 'STRONG_BUY',
325
- 'confidence': min(0.95, zscore / 3),
326
- 'reason': f'تدفق شرائي قوي: ${recent_netflow:,.0f} من المنصات',
327
- 'critical_alert': recent_netflow > 1000000
328
- })
329
- return signal
330
-
331
- elif recent_netflow > 100000 and zscore > 1.5:
332
- signal.update({
333
- 'action': 'BUY',
334
- 'confidence': min(0.8, zscore / 2),
335
- 'reason': f'تدفق شرائي: ${recent_netflow:,.0f} من المنصات',
336
- 'critical_alert': False
337
- })
338
- return signal
339
-
340
- signal.update({
341
- 'action': 'HOLD',
342
- 'confidence': 0.5,
343
- 'reason': f'تدفق متوازن: ${recent_netflow:,.0f}',
344
- 'critical_alert': False
345
- })
346
- return signal
347
-
348
- except Exception as e:
349
- print(f"⚠️ خطأ في توليد إشارة التداول: {e}")
350
- return None
351
-
352
- async def _scan_single_evm_network(self, network):
353
- """مسح شبكة EVM واحدة مع تحليل صافي التدفق"""
354
- whale_alerts = []
355
- trading_signals = []
356
-
357
- try:
358
- price_usd = await self._get_native_coin_price(network)
359
- if price_usd is None:
360
- print(f"⚠️ سعر {network} غير متوفر، تخطي المسح")
361
- return [], []
362
-
363
- latest_block_hex = await self._call_rpc_async(network, 'eth_blockNumber')
364
- if not latest_block_hex:
365
- return [], []
366
-
367
- latest_block = int(latest_block_hex, 16)
368
- blocks_to_scan = 15
369
- scanned_blocks = 0
370
-
371
- for block_offset in range(blocks_to_scan):
372
- block_number = latest_block - block_offset
373
- if block_number < 0:
374
- break
375
-
376
- block_data = await self._call_rpc_async(network, 'eth_getBlockByNumber', [hex(block_number), True])
377
- if not block_data or 'transactions' not in block_data:
378
- continue
379
-
380
- scanned_blocks += 1
381
-
382
- block_timestamp_hex = block_data.get('timestamp', '0x0')
383
- block_timestamp = int(block_timestamp_hex, 16)
384
- block_time = datetime.fromtimestamp(block_timestamp)
385
- time_ago = datetime.now() - block_time
386
-
387
- for tx in block_data.get('transactions', []):
388
- value_wei = int(tx.get('value', '0x0'), 16)
389
- if value_wei > 0:
390
- value_native = value_wei / 1e18
391
- value_usd = value_native * price_usd
392
-
393
- if value_usd >= self.whale_threshold_usd:
394
- from_address = tx.get('from', '')
395
- to_address = tx.get('to', '')
396
- tx_hash = tx.get('hash', '')
397
-
398
- await self._update_netflow_metrics(network, 'NATIVE', from_address, to_address, value_usd, tx_hash)
399
-
400
- from_label = self._classify_address_dynamic(from_address)
401
- to_label = self._classify_address_dynamic(to_address)
402
-
403
- whale_alerts.append({
404
- 'network': network,
405
- 'value_usd': value_usd,
406
- 'from': from_address,
407
- 'to': to_address,
408
- 'from_label': from_label,
409
- 'to_label': to_label,
410
- 'hash': tx_hash,
411
- 'block_number': block_number,
412
- 'timestamp': block_timestamp,
413
- 'human_time': block_time.isoformat(),
414
- 'minutes_ago': time_ago.total_seconds() / 60,
415
- 'transaction_type': 'native_transfer',
416
- 'flow_direction': 'TO_EXCHANGE' if self._is_exchange_address(to_address) else
417
- 'FROM_EXCHANGE' if self._is_exchange_address(from_address) else 'UNKNOWN'
418
- })
419
-
420
- if block_offset % 3 == 0:
421
- await asyncio.sleep(0.1)
422
-
423
- signal = self._generate_netflow_signal(network, 'NATIVE')
424
- if signal:
425
- trading_signals.append(signal)
426
-
427
- print(f"✅ مسح {network}: {scanned_blocks} كتل، {len(whale_alerts)} تنبيهات، {len(trading_signals)} إشارات")
428
-
429
- except Exception as e:
430
- print(f"⚠️ خطأ في مسح شبكة {network}: {e}")
431
-
432
- return whale_alerts, trading_signals
433
-
434
- async def get_general_whale_activity(self):
435
- """الوظيفة الرئيسية لمراقبة الحيتان"""
436
- print("🌊 بدء مراقبة الحيتان وتحليل صافي التدفق...")
437
-
438
- try:
439
- tasks = []
440
- networks_to_scan = ['ethereum', 'bsc']
441
- for network in networks_to_scan:
442
- tasks.append(self._scan_single_evm_network(network))
443
-
444
- results = await asyncio.gather(*tasks, return_exceptions=True)
445
-
446
- all_alerts = []
447
- all_signals = []
448
- successful_networks = 0
449
-
450
- for res in results:
451
- if isinstance(res, tuple) and len(res) == 2:
452
- alerts, signals = res
453
- all_alerts.extend(alerts)
454
- all_signals.extend(signals)
455
- successful_networks += 1
456
-
457
- all_alerts.sort(key=lambda x: x['timestamp'], reverse=True)
458
-
459
- total_volume = sum(alert['value_usd'] for alert in all_alerts)
460
- alert_count = len(all_alerts)
461
-
462
- exchange_inflow = sum(alert['value_usd'] for alert in all_alerts
463
- if alert['flow_direction'] == 'TO_EXCHANGE')
464
- exchange_outflow = sum(alert['value_usd'] for alert in all_alerts
465
- if alert['flow_direction'] == 'FROM_EXCHANGE')
466
- net_exchange_flow = exchange_inflow - exchange_outflow
467
-
468
- critical_signals = [s for s in all_signals if s.get('critical_alert', False)]
469
-
470
- if not all_alerts:
471
- return {
472
- 'data_available': False,
473
- 'description': 'غير متوفر - لم يتم اكتشاف نشاط حيتان كبير',
474
- 'critical_alert': False,
475
- 'sentiment': 'UNKNOWN',
476
- 'total_volume_usd': 0,
477
- 'transaction_count': 0,
478
- 'data_quality': 'HIGH',
479
- 'networks_scanned': successful_networks,
480
- 'trading_signals': all_signals,
481
- 'netflow_analysis': {
482
- 'inflow_to_exchanges': 0,
483
- 'outflow_from_exchanges': 0,
484
- 'net_flow': 0,
485
- 'flow_direction': 'BALANCED'
486
- }
487
- }
488
-
489
- latest_alert = all_alerts[0] if all_alerts else None
490
- latest_time_info = f"آخر نشاط منذ {latest_alert['minutes_ago']:.1f} دقيقة" if latest_alert else ""
491
-
492
- if net_exchange_flow < -1000000:
493
- sentiment = 'BEARISH'
494
- flow_description = f"ضغط بيعي قوي: ${abs(net_exchange_flow):,.0f} إلى المنصات"
495
- market_impact = "HIGH"
496
- elif net_exchange_flow < -500000:
497
- sentiment = 'SLIGHTLY_BEARISH'
498
- flow_description = f"ضغط بيعي: ${abs(net_exchange_flow):,.0f} إلى المنصات"
499
- market_impact = "MEDIUM"
500
- elif net_exchange_flow > 1000000:
501
- sentiment = 'BULLISH'
502
- flow_description = f"تراكم شرائي قوي: ${net_exchange_flow:,.0f} من المنصات"
503
- market_impact = "HIGH"
504
- elif net_exchange_flow > 500000:
505
- sentiment = 'SLIGHTLY_BULLISH'
506
- flow_description = f"تراكم شرائي: ${net_exchange_flow:,.0f} من المنصات"
507
- market_impact = "MEDIUM"
508
- else:
509
- sentiment = 'NEUTRAL'
510
- flow_description = f"تدفق متوازن: ${net_exchange_flow:,.0f} صافي"
511
- market_impact = "LOW"
512
-
513
- critical_alert = (
514
- total_volume > 10_000_000 or
515
- any(tx['value_usd'] > 5_000_000 for tx in all_alerts) or
516
- abs(net_exchange_flow) > 5_000_000 or
517
- len(critical_signals) > 0
518
- )
519
-
520
- description = f"تم اكتشاف {alert_count} معاملة حوت بإجمالي ${total_volume:,.0f} عبر {successful_networks} شبكات. {flow_description}. {latest_time_info}"
521
-
522
- return {
523
- 'data_available': True,
524
- 'description': description,
525
- 'critical_alert': critical_alert,
526
- 'sentiment': sentiment,
527
- 'market_impact': market_impact,
528
- 'total_volume_usd': total_volume,
529
- 'transaction_count': alert_count,
530
- 'netflow_analysis': {
531
- 'inflow_to_exchanges': exchange_inflow,
532
- 'outflow_from_exchanges': exchange_outflow,
533
- 'net_flow': net_exchange_flow,
534
- 'flow_direction': 'TO_EXCHANGES' if net_exchange_flow < 0 else 'FROM_EXCHANGES',
535
- 'market_impact': market_impact
536
- },
537
- 'recent_alerts': all_alerts[:10],
538
- 'latest_activity': latest_alert['human_time'] if latest_alert else None,
539
- 'trading_signals': all_signals,
540
- 'critical_signals_count': len(critical_signals),
541
- 'address_classification_stats': {
542
- 'total_classified': len(self.address_labels),
543
- 'exchange_addresses': len(self.address_categories['cex']),
544
- 'whale_addresses': len(self.address_categories['whale']),
545
- 'unknown_addresses': len(self.address_categories['unknown'])
546
- },
547
- 'data_quality': 'HIGH',
548
- 'networks_scanned': successful_networks
549
- }
550
-
551
- except Exception as e:
552
- print(f"❌ فشل مراقبة الحيتان العامة: {e}")
553
- return {
554
- 'data_available': False,
555
- 'description': f'غير متوفر - فشل في مراقبة الحيتان: {str(e)}',
556
- 'critical_alert': False,
557
- 'sentiment': 'UNKNOWN',
558
- 'total_volume_usd': 0,
559
- 'transaction_count': 0,
560
- 'data_quality': 'LOW',
561
- 'error': str(e),
562
- 'trading_signals': []
563
- }
564
-
565
- async def _get_native_coin_price(self, network):
566
- """جلب الأسعار من مصادر حقيقية"""
567
- now = time.time()
568
- cache_key = f"{network}_price"
569
-
570
- if cache_key in self.price_cache and (now - self.price_cache[cache_key]['timestamp']) < 300:
571
- return self.price_cache[cache_key]['price']
572
-
573
- symbol = self.kucoin_symbols.get(network)
574
- if not symbol:
575
- return await self._get_price_from_coingecko_fallback(network)
576
-
577
- try:
578
- price = await self._get_price_from_kucoin(symbol)
579
- if price and price > 0:
580
- self.price_cache[cache_key] = {'price': price, 'timestamp': now, 'source': 'kucoin'}
581
- return price
582
-
583
- price = await self._get_price_from_coingecko_fallback(network)
584
- if price and price > 0:
585
- self.price_cache[cache_key] = {'price': price, 'timestamp': now, 'source': 'coingecko'}
586
- return price
587
-
588
- return None
589
-
590
- except Exception as e:
591
- print(f"⚠️ فشل جلب سعر {network}: {e}")
592
- return None
593
-
594
- async def _get_price_from_kucoin(self, symbol):
595
- """جلب السعر من KuCoin"""
596
- try:
597
- exchange = ccxt.kucoin({
598
- 'sandbox': False,
599
- 'enableRateLimit': True
600
- })
601
-
602
- trading_symbol = f"{symbol}/USDT"
603
- try:
604
- ticker = await exchange.fetch_ticker(trading_symbol)
605
- price = ticker.get('last')
606
- if price and price > 0:
607
- print(f"✅ سعر {symbol} من KuCoin: ${price:.2f}")
608
- await exchange.close()
609
- return float(price)
610
- except Exception as e:
611
- print(f"⚠️ رمز التداول {trading_symbol} غير مدعوم في KuCoin: {e}")
612
-
613
- await exchange.close()
614
- return None
615
-
616
- except Exception as e:
617
- print(f"⚠️ فشل جلب السعر من KuCoin لـ {symbol}: {e}")
618
- return None
619
-
620
- async def _get_price_from_coingecko_fallback(self, network):
621
- """الاحتياطي: جلب السعر من CoinGecko"""
622
- coin_map = {
623
- 'ethereum': 'ethereum',
624
- 'bsc': 'binancecoin'
625
- }
626
-
627
- coin_id = coin_map.get(network)
628
- if not coin_id:
629
- return None
630
-
631
- try:
632
- await asyncio.sleep(0.5)
633
- url = f"https://api.coingecko.com/api/v3/simple/price?ids={coin_id}&vs_currencies=usd"
634
- response = await self.http_client.get(url)
635
- response.raise_for_status()
636
- price = response.json().get(coin_id, {}).get('usd', 0)
637
- if price > 0:
638
- print(f"✅ سعر {network} من CoinGecko: ${price:.2f}")
639
- return price
640
- return None
641
- except Exception as e:
642
- print(f"⚠️ فشل جلب سعر {network} من CoinGecko: {e}")
643
- return None
644
-
645
- async def _call_rpc_async(self, network, method, params=[]):
646
- """اتصال RPC غير متزامن"""
647
- max_retries = 2
648
-
649
- for attempt in range(max_retries):
650
- endpoint = self._get_next_rpc_endpoint(network)
651
- if not endpoint:
652
- print(f"❌ لا توجد نقاط نهاية RPC متاحة لـ {network}")
653
- return None
654
-
655
- try:
656
- if 'infura' in endpoint and self.infura_key:
657
- self._update_api_usage_stats('infura')
658
-
659
- if await self._api_rate_limit_delay('infura'):
660
- continue
661
-
662
- payload = {"jsonrpc": "2.0", "method": method, "params": params, "id": 1}
663
-
664
- timeout = 25.0 if method == 'eth_getBlockByNumber' else 12.0
665
-
666
- async with httpx.AsyncClient(timeout=timeout) as client:
667
- response = await client.post(endpoint, json=payload)
668
-
669
- if response.status_code == 401:
670
- print(f"🔐 خطأ مصادقة في {endpoint}")
671
- self.rpc_failures[network] += 1
672
- continue
673
- elif response.status_code == 429:
674
- print(f"⏳ Rate limit على {endpoint}")
675
- await asyncio.sleep(2 * (attempt + 1))
676
- continue
677
-
678
- response.raise_for_status()
679
- result = response.json().get('result')
680
-
681
- self.rpc_failures[network] = 0
682
- return result
683
-
684
- except httpx.HTTPStatusError as e:
685
- if e.response.status_code == 429:
686
- print(f"⚠️ Rate limit على {endpoint} لـ {network}")
687
- self.rpc_failures[network] += 1
688
- await asyncio.sleep(3 * (attempt + 1))
689
- continue
690
- elif e.response.status_code == 401:
691
- print(f"🔐 خطأ مصادقة في {endpoint}")
692
- self.rpc_failures[network] += 1
693
- continue
694
- else:
695
- print(f"⚠️ خطأ HTTP {e.response.status_code} في {endpoint}")
696
- self.rpc_failures[network] += 1
697
-
698
- except Exception as e:
699
- print(f"⚠️ فشل اتصال RPC لـ {network}: {e}")
700
- self.rpc_failures[network] += 1
701
-
702
- if attempt < max_retries - 1:
703
- await asyncio.sleep(1 * (attempt + 1))
704
-
705
- print(f"❌ فشل جميع محاولات RPC لـ {network}")
706
- return None
707
-
708
- def _get_next_rpc_endpoint(self, network):
709
- """الحصول على عنوان RPC التالي"""
710
- if network not in self.rpc_endpoints:
711
- return None
712
-
713
- endpoints = self.rpc_endpoints[network]
714
- if not endpoints:
715
- return None
716
-
717
- index = self.current_rpc_index[network]
718
- endpoint = endpoints[index]
719
- self.current_rpc_index[network] = (index + 1) % len(endpoints)
720
-
721
- return endpoint
722
-
723
- def _update_api_usage_stats(self, api_name):
724
- """تحديث إحصائيات استخدام API"""
725
- now = datetime.now()
726
- current_date = now.date()
727
-
728
- stats = self.api_usage_stats[api_name]
729
-
730
- if current_date != stats['last_reset']:
731
- stats['requests_today'] = 0
732
- stats['last_reset'] = current_date
733
-
734
- current_time = time.time()
735
- time_diff = current_time - stats['last_request_time']
736
-
737
- if time_diff < 1.0:
738
- stats['requests_per_second'] += 1
739
- else:
740
- stats['requests_per_second'] = 1
741
- stats['last_request_time'] = current_time
742
-
743
- stats['requests_today'] += 1
744
-
745
- if api_name == 'etherscan':
746
- if stats['requests_today'] > 90000:
747
- print(f"🚨 تحذير: طلبات {api_name} اليومية تقترب من الحد")
748
- if stats['requests_per_second'] > 4:
749
- print(f"🚨 تحذير: طلبات {api_name} في الثانية تقترب من الحد")
750
-
751
- elif api_name == 'infura':
752
- if stats['requests_today'] > 2500000:
753
- print(f"🚨 تحذير: طلبات {api_name} اليومية تقترب من الحد")
754
- if stats['requests_per_second'] > 450:
755
- print(f"🚨 تحذير: طلبات {api_name} في الثانية تقترب من الحد")
756
-
757
- async def _api_rate_limit_delay(self, api_name):
758
- """تأخير ذكي لتجنب تجاوز حدود API"""
759
- stats = self.api_usage_stats[api_name]
760
-
761
- if api_name == 'etherscan':
762
- if stats['requests_per_second'] > 4:
763
- delay = 0.2 * (stats['requests_per_second'] - 4)
764
- print(f"⏳ تأخير {delay:.2f} ثانية لـ {api_name}")
765
- await asyncio.sleep(delay)
766
-
767
- if stats['requests_today'] > 95000:
768
- print(f"🚨 تجاوز الحد اليومي لطلبات {api_name}")
769
- return True
770
-
771
- elif api_name == 'infura':
772
- if stats['requests_per_second'] > 400:
773
- delay = 0.1 * (stats['requests_per_second'] - 400)
774
- print(f"⏳ تأخير {delay:.2f} ثانية لـ {api_name}")
775
- await asyncio.sleep(delay)
776
-
777
- if stats['requests_today'] > 2800000:
778
- print(f"🚨 تجاوز الحد اليومي لطلبات {api_name}")
779
- return True
780
-
781
- return False
782
-
783
- async def get_symbol_specific_whale_data(self, symbol, contract_address=None):
784
- """جلب بيانات الحيتان الخاصة بعملة محددة"""
785
- try:
786
- base_symbol = symbol.split("/")[0] if '/' in symbol else symbol
787
-
788
- if not contract_address:
789
- contract_address = await self._find_contract_address(base_symbol)
790
-
791
- if not contract_address:
792
- return await self._scan_networks_for_symbol(symbol, base_symbol)
793
-
794
- print(f"🔍 جلب بيانات الحيتان لـ {symbol}")
795
-
796
- api_data = await self._get_combined_api_data(contract_address)
797
-
798
- if api_data:
799
- enriched_data = await self._enrich_api_data_with_timing(api_data)
800
- return self._analyze_symbol_specific_data(enriched_data, symbol)
801
- else:
802
- return await self._scan_networks_for_symbol(symbol, base_symbol)
803
-
804
- except Exception as e:
805
- print(f"❌ فشل جلب بيانات الحيتان لـ {symbol}: {e}")
806
- return {
807
- 'data_available': False,
808
- 'description': f'غير متوفر - خطأ في جلب بيانات الحيتان',
809
- 'total_volume': 0,
810
- 'transfer_count': 0,
811
- 'source': 'error'
812
- }
813
-
814
- async def _get_combined_api_data(self, contract_address):
815
- """جلب البيانات المجمعة من مصادر API"""
816
- tasks = []
817
-
818
- if self.moralis_key:
819
- tasks.append(self._get_moralis_token_data(contract_address))
820
- if self.etherscan_key:
821
- tasks.append(self._get_etherscan_token_data_v2(contract_address))
822
-
823
- if not tasks:
824
- return []
825
-
826
- results = await asyncio.gather(*tasks, return_exceptions=True)
827
-
828
- all_transfers = []
829
- for res in results:
830
- if isinstance(res, list):
831
- all_transfers.extend(res)
832
-
833
- return all_transfers
834
-
835
- async def _get_etherscan_token_data_v2(self, contract_address):
836
- """جلب بيانات Etherscan"""
837
- if not self.etherscan_key:
838
- return []
839
-
840
- try:
841
- self._update_api_usage_stats('etherscan')
842
-
843
- if await self._api_rate_limit_delay('etherscan'):
844
- print("⚠️ تجاوز حدود Etherscan، تخطي الطلب")
845
- return []
846
-
847
- params = {
848
- "module": "account",
849
- "action": "tokentx",
850
- "contractaddress": contract_address,
851
- "page": 1,
852
- "offset": 10,
853
- "sort": "desc",
854
- "apikey": self.etherscan_key
855
- }
856
-
857
- base_url = "https://api.etherscan.io/api"
858
-
859
- print(f"🔍 جلب بيانات Etherscan للعقد: {contract_address[:10]}...")
860
-
861
- async with httpx.AsyncClient(timeout=10.0) as client:
862
- response = await client.get(base_url, params=params)
863
-
864
- if response.status_code == 429:
865
- print("⏳ تجاوز حد معدل Etherscan")
866
- await asyncio.sleep(2)
867
- return []
868
-
869
- response.raise_for_status()
870
- data = response.json()
871
-
872
- if data.get('status') == '1' and data.get('message') == 'OK':
873
- result = data.get('result', [])
874
- print(f"✅ بيانات Etherscan: {len(result)} تحويل")
875
- return result
876
- else:
877
- error_message = data.get('message', 'Unknown error')
878
- print(f"⚠️ خطأ في استجابة Etherscan: {error_message}")
879
- return []
880
-
881
- except httpx.HTTPStatusError as e:
882
- print(f"⚠️ خطأ HTTP في Etherscan API: {e.response.status_code}")
883
- return []
884
- except Exception as e:
885
- print(f"⚠️ فشل جلب بيانات Etherscan: {e}")
886
- return []
887
-
888
- async def _get_moralis_token_data(self, contract_address):
889
- """جلب بيانات Moralis"""
890
- if not self.moralis_key:
891
- return []
892
-
893
- try:
894
- response = await self.http_client.get(
895
- f"https://deep-index.moralis.io/api/v2/erc20/{contract_address}/transfers",
896
- headers={"X-API-Key": self.moralis_key},
897
- params={"chain": "eth", "limit": 10}
898
- )
899
-
900
- if response.status_code == 200:
901
- result = response.json().get('result', [])
902
- print(f"✅ بيانات Moralis: {len(result)} تحويل")
903
- return result
904
- else:
905
- print(f"⚠️ خطأ Moralis API: {response.status_code}")
906
- return []
907
-
908
- except Exception as e:
909
- print(f"⚠️ Moralis API error: {e}")
910
- return []
911
-
912
- async def _enrich_api_data_with_timing(self, api_data):
913
- """إثرا�� بيانات API بتوقيتات إضافية"""
914
- enriched_data = []
915
- for transfer in api_data:
916
- try:
917
- if 'timeStamp' in transfer:
918
- timestamp = int(transfer['timeStamp'])
919
- elif 'block_timestamp' in transfer:
920
- timestamp = int(transfer['block_timestamp'])
921
- else:
922
- timestamp = int(time.time())
923
-
924
- transfer_time = datetime.fromtimestamp(timestamp)
925
- time_ago = datetime.now() - transfer_time
926
-
927
- enriched_transfer = {
928
- **transfer,
929
- 'human_time': transfer_time.isoformat(),
930
- 'minutes_ago': time_ago.total_seconds() / 60,
931
- 'timestamp': timestamp
932
- }
933
- enriched_data.append(enriched_transfer)
934
-
935
- except Exception as e:
936
- print(f"⚠️ خطأ في إثراء بيانات التحويل: {e}")
937
- continue
938
-
939
- return enriched_data
940
-
941
- def _analyze_symbol_specific_data(self, enriched_data, symbol):
942
- """تحليل بيانات الرمز المحدد"""
943
- if not enriched_data:
944
- return {
945
- 'data_available': False,
946
- 'description': f'غير متوفر - لا توجد بيانات تحويل لـ {symbol}',
947
- 'total_volume': 0,
948
- 'transfer_count': 0,
949
- 'source': 'no_data'
950
- }
951
-
952
- try:
953
- volumes = []
954
- large_transfers = []
955
-
956
- for transfer in enriched_data:
957
- value = float(transfer.get('value', 0))
958
- volumes.append(value)
959
-
960
- if value > 10000:
961
- large_transfers.append(transfer)
962
-
963
- total_volume = sum(volumes)
964
- transfer_count = len(volumes)
965
- avg_volume = total_volume / transfer_count if transfer_count > 0 else 0
966
-
967
- latest_transfer = max(enriched_data, key=lambda x: x['timestamp'])
968
- oldest_transfer = min(enriched_data, key=lambda x: x['timestamp'])
969
- time_range_hours = (latest_transfer['timestamp'] - oldest_transfer['timestamp']) / 3600
970
-
971
- if len(large_transfers) > 5:
972
- activity_level = 'HIGH'
973
- description = f"نشاط حيتان مرتفع لـ {symbol}: {len(large_transfers)} تحويل كبير"
974
- elif len(large_transfers) > 2:
975
- activity_level = 'MEDIUM'
976
- description = f"نشاط حيتان متوسط لـ {symbol}: {len(large_transfers)} تحويل كبير"
977
- else:
978
- activity_level = 'LOW'
979
- description = f"نشاط حيتان منخفض لـ {symbol}: {len(large_transfers)} تحويل كبير"
980
-
981
- return {
982
- 'data_available': True,
983
- 'description': description,
984
- 'total_volume': total_volume,
985
- 'transfer_count': transfer_count,
986
- 'average_volume': avg_volume,
987
- 'large_transfers_count': len(large_transfers),
988
- 'activity_level': activity_level,
989
- 'latest_transfer_time': latest_transfer['human_time'],
990
- 'time_range_hours': time_range_hours,
991
- 'source': 'api_combined',
992
- 'recent_large_transfers': large_transfers[:5]
993
- }
994
-
995
- except Exception as e:
996
- print(f"❌ خطأ في تحليل بيانات {symbol}: {e}")
997
- return {
998
- 'data_available': False,
999
- 'description': f'غير متوفر - خطأ في تحليل البيانات',
1000
- 'total_volume': 0,
1001
- 'transfer_count': 0,
1002
- 'source': 'error'
1003
- }
1004
-
1005
- async def _find_contract_address(self, symbol):
1006
- """البحث عن عنوان العقد للرمز المحدد"""
1007
- symbol_lower = symbol.lower()
1008
- for key, address in self.contracts_db.items():
1009
- if symbol_lower in key.lower():
1010
- return address
1011
-
1012
- print(f"🔍 لم يتم العثور على عقد لـ {symbol} في قاعدة البيانات")
1013
- return None
1014
-
1015
- async def _scan_networks_for_symbol(self, symbol, base_symbol):
1016
- """مسح الشبكات للعثور على الرمز"""
1017
- print(f"🔍 مسح الشبكات للعثور على {symbol}...")
1018
-
1019
- networks_to_scan = ['ethereum', 'bsc']
1020
-
1021
- for network in networks_to_scan:
1022
- try:
1023
- price = await self._get_native_coin_price(network)
1024
- if price:
1025
- print(f"✅ تم العثور على {symbol} على شبكة {network} بسعر ${price:.2f}")
1026
- return {
1027
- 'data_available': True,
1028
- 'description': f'تم اكتشاف {symbol} على شبكة {network}',
1029
- 'network': network,
1030
- 'price_usd': price,
1031
- 'source': 'network_scan'
1032
- }
1033
- except Exception as e:
1034
- print(f"⚠️ فشل مسح {network} لـ {symbol}: {e}")
1035
- continue
1036
-
1037
- return {
1038
- 'data_available': False,
1039
- 'description': f'غير متوفر - لم يتم العثور على {symbol} على أي شبكة',
1040
- 'source': 'not_found'
1041
- }
1042
-
1043
- def get_api_usage_stats(self):
1044
- """الحصول على إحصائيات استخدام APIs"""
1045
- stats = {}
1046
-
1047
- for api_name, api_stats in self.api_usage_stats.items():
1048
- if api_name == 'etherscan':
1049
- daily_limit = 100000
1050
- per_second_limit = 5
1051
- elif api_name == 'infura':
1052
- daily_limit = 3000000
1053
- per_second_limit = 500
1054
- else:
1055
- continue
1056
-
1057
- stats[api_name] = {
1058
- 'requests_today': api_stats['requests_today'],
1059
- 'requests_per_second': api_stats['requests_per_second'],
1060
- 'daily_limit_remaining': daily_limit - api_stats['requests_today'],
1061
- 'usage_percentage': (api_stats['requests_today'] / daily_limit) * 100,
1062
- 'per_second_usage_percentage': (api_stats['requests_per_second'] / per_second_limit) * 100,
1063
- 'last_reset': api_stats['last_reset'].isoformat(),
1064
- 'api_available': getattr(self, f'{api_name}_key') is not None
1065
- }
1066
-
1067
- return stats
1068
-
1069
- # إنشاء نسخة عالمية
1070
- whale_monitor_global = EnhancedWhaleMonitor()
1071
 
1072
  class DataManager:
1073
  def __init__(self, contracts_db):
@@ -1087,7 +28,7 @@ class DataManager:
1087
  self._whale_data_cache = {}
1088
  self.http_client = None
1089
  self.fetch_stats = {'successful_fetches': 0, 'failed_fetches': 0, 'rate_limit_hits': 0}
1090
- self.whale_monitor = EnhancedWhaleMonitor(contracts_db)
1091
  self.price_cache = {}
1092
 
1093
  async def initialize(self):
@@ -1111,7 +52,6 @@ class DataManager:
1111
  await self.exchange.close()
1112
 
1113
  async def get_sentiment_safe_async(self):
1114
- """جلب بيانات المشاعر من مصادر حقيقية"""
1115
  max_retries = 2
1116
  for attempt in range(max_retries):
1117
  try:
@@ -1139,7 +79,6 @@ class DataManager:
1139
  return None
1140
 
1141
  async def get_market_context_async(self):
1142
- """جلب سياق السوق من مصادر حقيقية"""
1143
  max_retries = 2
1144
  for attempt in range(max_retries):
1145
  try:
@@ -1216,7 +155,6 @@ class DataManager:
1216
  return self._get_minimal_market_context()
1217
 
1218
  def _analyze_advanced_trading_signals(self, whale_activity, sentiment_data):
1219
- """تحليل إشارات التداول المتقدمة"""
1220
  if not whale_activity or not whale_activity.get('data_available'):
1221
  return {
1222
  'action': 'HOLD',
@@ -1281,7 +219,6 @@ class DataManager:
1281
  }
1282
 
1283
  def _assess_market_risk(self, whale_activity, sentiment_data):
1284
- """تقييم مخاطر السوق"""
1285
  risk_factors = []
1286
  risk_score = 0
1287
 
@@ -1314,7 +251,6 @@ class DataManager:
1314
  return {'level': 'LOW', 'score': risk_score, 'factors': risk_factors}
1315
 
1316
  def _get_btc_sentiment(self, bitcoin_price):
1317
- """تحديد اتجاه البيتكوين"""
1318
  if bitcoin_price is None:
1319
  return 'UNKNOWN'
1320
  elif bitcoin_price > 60000:
@@ -1325,7 +261,6 @@ class DataManager:
1325
  return 'NEUTRAL'
1326
 
1327
  async def _get_prices_with_fallback(self):
1328
- """جلب الأسعار من مصادر حقيقية"""
1329
  try:
1330
  prices = await self._get_prices_from_kucoin_safe()
1331
  if prices.get('bitcoin') and prices.get('ethereum'):
@@ -1342,7 +277,6 @@ class DataManager:
1342
  return {'bitcoin': None, 'ethereum': None}
1343
 
1344
  async def _get_prices_from_kucoin_safe(self):
1345
- """جلب الأسعار من KuCoin"""
1346
  if not self.exchange:
1347
  return {'bitcoin': None, 'ethereum': None}
1348
 
@@ -1376,7 +310,6 @@ class DataManager:
1376
  return {'bitcoin': None, 'ethereum': None}
1377
 
1378
  async def _get_prices_from_coingecko(self):
1379
- """جلب الأسعار من CoinGecko"""
1380
  try:
1381
  await asyncio.sleep(0.5)
1382
  url = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum&vs_currencies=usd"
@@ -1401,7 +334,6 @@ class DataManager:
1401
  return {'bitcoin': None, 'ethereum': None}
1402
 
1403
  def _get_minimal_market_context(self):
1404
- """إرجاع سياق سوق أساسي"""
1405
  return {
1406
  'timestamp': datetime.now().isoformat(),
1407
  'data_available': False,
@@ -1424,7 +356,6 @@ class DataManager:
1424
  }
1425
 
1426
  def _determine_market_trend(self, bitcoin_price, sentiment_data, whale_activity):
1427
- """تحديد اتجاه السوق"""
1428
  try:
1429
  if bitcoin_price is None:
1430
  return "UNKNOWN"
@@ -1474,7 +405,6 @@ class DataManager:
1474
  return "UNKNOWN"
1475
 
1476
  def get_performance_stats(self):
1477
- """الحصول على إحصائيات الأداء"""
1478
  total_attempts = self.fetch_stats['successful_fetches'] + self.fetch_stats['failed_fetches']
1479
  success_rate = (self.fetch_stats['successful_fetches'] / total_attempts * 100) if total_attempts > 0 else 0
1480
 
@@ -1494,7 +424,6 @@ class DataManager:
1494
  return stats
1495
 
1496
  async def get_symbol_specific_whale_data(self, symbol, contract_address=None):
1497
- """جلب بيانات الحيتان الخاصة بعملة محددة"""
1498
  return await self.whale_monitor.get_symbol_specific_whale_data(symbol, contract_address)
1499
 
1500
  print("✅ Enhanced Data Manager Loaded - جميع البيانات حقيقية")
 
1
+ import os
2
+ import asyncio
3
+ import httpx
4
+ import traceback
5
+ import time
6
+ from datetime import datetime
7
  import ccxt.pro as ccxt
 
 
 
8
  from state import MARKET_STATE_OK
9
 
10
+ from whale_news_data import whale_monitor_global
11
+ from helpers import safe_float_conversion
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  class DataManager:
14
  def __init__(self, contracts_db):
 
28
  self._whale_data_cache = {}
29
  self.http_client = None
30
  self.fetch_stats = {'successful_fetches': 0, 'failed_fetches': 0, 'rate_limit_hits': 0}
31
+ self.whale_monitor = whale_monitor_global
32
  self.price_cache = {}
33
 
34
  async def initialize(self):
 
52
  await self.exchange.close()
53
 
54
  async def get_sentiment_safe_async(self):
 
55
  max_retries = 2
56
  for attempt in range(max_retries):
57
  try:
 
79
  return None
80
 
81
  async def get_market_context_async(self):
 
82
  max_retries = 2
83
  for attempt in range(max_retries):
84
  try:
 
155
  return self._get_minimal_market_context()
156
 
157
  def _analyze_advanced_trading_signals(self, whale_activity, sentiment_data):
 
158
  if not whale_activity or not whale_activity.get('data_available'):
159
  return {
160
  'action': 'HOLD',
 
219
  }
220
 
221
  def _assess_market_risk(self, whale_activity, sentiment_data):
 
222
  risk_factors = []
223
  risk_score = 0
224
 
 
251
  return {'level': 'LOW', 'score': risk_score, 'factors': risk_factors}
252
 
253
  def _get_btc_sentiment(self, bitcoin_price):
 
254
  if bitcoin_price is None:
255
  return 'UNKNOWN'
256
  elif bitcoin_price > 60000:
 
261
  return 'NEUTRAL'
262
 
263
  async def _get_prices_with_fallback(self):
 
264
  try:
265
  prices = await self._get_prices_from_kucoin_safe()
266
  if prices.get('bitcoin') and prices.get('ethereum'):
 
277
  return {'bitcoin': None, 'ethereum': None}
278
 
279
  async def _get_prices_from_kucoin_safe(self):
 
280
  if not self.exchange:
281
  return {'bitcoin': None, 'ethereum': None}
282
 
 
310
  return {'bitcoin': None, 'ethereum': None}
311
 
312
  async def _get_prices_from_coingecko(self):
 
313
  try:
314
  await asyncio.sleep(0.5)
315
  url = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum&vs_currencies=usd"
 
334
  return {'bitcoin': None, 'ethereum': None}
335
 
336
  def _get_minimal_market_context(self):
 
337
  return {
338
  'timestamp': datetime.now().isoformat(),
339
  'data_available': False,
 
356
  }
357
 
358
  def _determine_market_trend(self, bitcoin_price, sentiment_data, whale_activity):
 
359
  try:
360
  if bitcoin_price is None:
361
  return "UNKNOWN"
 
405
  return "UNKNOWN"
406
 
407
  def get_performance_stats(self):
 
408
  total_attempts = self.fetch_stats['successful_fetches'] + self.fetch_stats['failed_fetches']
409
  success_rate = (self.fetch_stats['successful_fetches'] / total_attempts * 100) if total_attempts > 0 else 0
410
 
 
424
  return stats
425
 
426
  async def get_symbol_specific_whale_data(self, symbol, contract_address=None):
 
427
  return await self.whale_monitor.get_symbol_specific_whale_data(symbol, contract_address)
428
 
429
  print("✅ Enhanced Data Manager Loaded - جميع البيانات حقيقية")