Riy777 commited on
Commit
eb23359
·
verified ·
1 Parent(s): b61c69b

Update ml_engine/data_manager.py

Browse files
Files changed (1) hide show
  1. ml_engine/data_manager.py +50 -52
ml_engine/data_manager.py CHANGED
@@ -1,6 +1,6 @@
1
  # ============================================================
2
  # 📂 ml_engine/data_manager.py
3
- # (V60.3 - GEM-Architect: Critical Data Fix & Full Integration)
4
  # ============================================================
5
 
6
  import asyncio
@@ -12,13 +12,13 @@ import pandas as pd
12
  import numpy as np
13
  from typing import List, Dict, Any
14
 
15
- # محاولة استيراد حدود النظام (اختياري للربط مع باقي النظام)
16
  try:
17
  from ml_engine.processor import SystemLimits
18
  except ImportError:
19
  SystemLimits = None
20
 
21
- # إعدادات التسجيل لتقليل الضوضاء
22
  logging.getLogger("httpx").setLevel(logging.WARNING)
23
  logging.getLogger("ccxt").setLevel(logging.WARNING)
24
 
@@ -27,9 +27,8 @@ class DataManager:
27
  self.contracts_db = contracts_db or {}
28
  self.whale_monitor = whale_monitor
29
  self.r2_service = r2_service
30
- self.adaptive_hub_ref = None # مرجع لملف التعلم
31
 
32
- # إعداد منصة KuCoin
33
  self.exchange = ccxt.kucoin({
34
  'enableRateLimit': True,
35
  'timeout': 60000,
@@ -39,13 +38,13 @@ class DataManager:
39
  self.http_client = None
40
  self.market_cache = {}
41
 
42
- # قائمة العملات المحظورة (Stablecoins + Leveraged Tokens)
43
  self.BLACKLIST_TOKENS = [
44
  'USDT', 'USDC', 'DAI', 'TUSD', 'BUSD', 'FDUSD', 'EUR', 'PAX',
45
  'UP', 'DOWN', 'BEAR', 'BULL', '3S', '3L'
46
  ]
47
 
48
- print(f"📦 [DataManager V60.3] Critical Data Fix + Tuned Shield Active.")
49
 
50
  async def initialize(self):
51
  print(" > [DataManager] Starting initialization...")
@@ -74,53 +73,62 @@ class DataManager:
74
  return self.contracts_db
75
 
76
  # ==================================================================
77
- # 🧠 Layer 1: Screening + Diagnosis + Injection (The Pipeline)
78
  # ==================================================================
79
  async def layer1_rapid_screening(self, adaptive_hub_ref=None) -> List[Dict[str, Any]]:
80
  self.adaptive_hub_ref = adaptive_hub_ref
81
- print(f"🔍 [Layer 1] Initiating Robust Screening...")
82
 
83
- # 1. فلتر السيولة الأساسي (المصحح جذرياً)
84
  initial_candidates = await self._stage0_universe_filter()
85
-
86
  if not initial_candidates:
87
- print("⚠️ [Layer 1] CRITICAL: Stage 0 returned 0 candidates. Check Connection.")
88
  return []
89
 
90
- # 2. جلب البيانات الفنية (لأفضل 120 عملة لضمان التنوع)
91
  top_candidates = initial_candidates[:120]
92
  enriched_data = await self._fetch_technical_data_batch(top_candidates)
93
 
94
  final_list = []
95
 
96
  for item in enriched_data:
97
- # 3. تطبيق الفلتر الفني الصارم (Tuned Anti-FOMO)
98
  classification = self._apply_strict_logic_tree(item)
99
 
100
  if classification['type'] != 'NONE':
101
- # 4. التشخيص والحقن (Context Injection)
102
  regime_info = self._diagnose_asset_regime(item)
103
- item['asset_regime'] = regime_info['regime']
 
 
 
 
 
 
 
 
 
 
104
  item['asset_regime_conf'] = regime_info['conf']
105
 
106
- # حقن العتبات الديناميكية من ملف التعلم
107
  if self.adaptive_hub_ref:
108
- dynamic_config = self.adaptive_hub_ref.get_regime_config(regime_info['regime'])
109
  item['dynamic_limits'] = dynamic_config
110
 
111
  item['l1_sort_score'] = classification['score']
112
  item['strategy_tag'] = classification['type']
113
  final_list.append(item)
114
 
115
- # 5. الترتيب النهائي
116
  final_list.sort(key=lambda x: x['l1_sort_score'], reverse=True)
117
 
118
  selection = final_list[:50]
119
- print(f"✅ [Layer 1] Passed {len(selection)} candidates to Processor.")
120
  return selection
121
 
122
  # ==================================================================
123
- # 🔍 Stage 0: Universe Filter (FIXED: Force USD Calculation)
124
  # ==================================================================
125
  async def _stage0_universe_filter(self) -> List[Dict[str, Any]]:
126
  try:
@@ -128,38 +136,39 @@ class DataManager:
128
  tickers = await self.exchange.fetch_tickers()
129
  candidates = []
130
 
131
- # إحصائيات الرفض للتشخيص
 
 
132
  reject_stats = {"volume": 0, "change": 0, "blacklist": 0}
133
  debug_printed = False
134
 
135
  for symbol, ticker in tickers.items():
136
  if not symbol.endswith('/USDT'): continue
137
 
138
- # 1. Blacklist
139
  base_curr = symbol.split('/')[0]
140
  if any(bad in base_curr for bad in self.BLACKLIST_TOKENS):
141
  reject_stats["blacklist"] += 1
142
  continue
143
 
144
- # 2. 🔥 FORCE CALCULATED VOLUME (USD) - الإصلاح الجذري
145
- # نتجاهل quoteVolume القادم من المنصة إذا كان مشكوكاً فيه
146
  base_vol = float(ticker.get('baseVolume') or 0.0)
147
  last_price = float(ticker.get('last') or 0.0)
148
-
149
- # الحساب اليدوي: الحجم * السعر = السيولة بالدولار
150
  calc_quote_vol = base_vol * last_price
151
 
152
- # طباعة فحص BTC للتأكد من الإصلاح (مرة واحدة)
 
 
153
  if "BTC/USDT" in symbol and not debug_printed:
154
- print(f" 🐛 [DEBUG] BTC Fixed Vol: ${calc_quote_vol:,.0f} (Verified USD)")
155
  debug_printed = True
156
 
157
- # فلتر السيولة (500k)
158
- if calc_quote_vol < 500_000:
159
- reject_stats["volume"] += 1
160
- continue
 
161
 
162
- # فلتر التغير (20%) - مسموح للحركة القوية
163
  change_pct = ticker.get('percentage')
164
  if change_pct is None: change_pct = 0.0
165
 
@@ -169,7 +178,7 @@ class DataManager:
169
 
170
  candidates.append({
171
  'symbol': symbol,
172
- 'quote_volume': calc_quote_vol, # نستخدم القيمة المحسوبة
173
  'current_price': last_price,
174
  'change_24h': change_pct
175
  })
@@ -186,7 +195,7 @@ class DataManager:
186
  return []
187
 
188
  # ------------------------------------------------------------------
189
- # 🧭 The Diagnoser (يحدد حالة العملة لحقن العتبات)
190
  # ------------------------------------------------------------------
191
  def _diagnose_asset_regime(self, item: Dict[str, Any]) -> Dict[str, Any]:
192
  try:
@@ -216,7 +225,7 @@ class DataManager:
216
  except Exception: return {'regime': 'RANGE', 'conf': 0.0}
217
 
218
  # ------------------------------------------------------------------
219
- # 🛡️ The Logic Tree (TUNED Anti-FOMO)
220
  # ------------------------------------------------------------------
221
  def _apply_strict_logic_tree(self, data: Dict[str, Any]) -> Dict[str, Any]:
222
  try:
@@ -233,32 +242,21 @@ class DataManager:
233
  change_4h = ((curr_1h['close'] - close_4h_ago) / close_4h_ago) * 100
234
  except: change_4h = 0.0
235
 
236
- # 🔧 TUNED GATES (بوابات الأمان المخففة)
237
- # 1. السماح بحركة 12% في 4 ساعات
238
  if change_4h > 12.0: return {'type': 'NONE', 'score': 0}
239
-
240
- # 2. السماح بـ RSI حتى 75 (منطقة الزخم القوي)
241
  if curr_1h['rsi'] > 75: return {'type': 'NONE', 'score': 0}
242
-
243
- # 3. السماح بانحراف 2.2 ATR
244
  dev = (curr_1h['close'] - curr_1h['ema20']) / curr_1h['atr'] if curr_1h['atr'] > 0 else 0
245
  if dev > 2.2: return {'type': 'NONE', 'score': 0}
246
 
247
- # --- التصنيف ---
248
-
249
- # A. Breakout (اختراق آمن)
250
  is_bullish = (curr_1h['ema20'] > curr_1h['ema50']) or (curr_1h['close'] > curr_1h['ema20'])
251
-
252
- # وسعنا النطاق قليلاً ليقبل الزخم القوي
253
  if is_bullish and (45 <= curr_1h['rsi'] <= 75):
254
  vol_ma = df_15m['volume'].rolling(20).mean().iloc[-1]
255
-
256
- # خفضنا شرط الفوليوم لـ 1.2 لالتقاط البدايات
257
  if curr_15m['volume'] >= 1.2 * vol_ma:
258
  score = curr_15m['volume'] / vol_ma if vol_ma > 0 else 1.0
259
  return {'type': 'BREAKOUT', 'score': score}
260
 
261
- # B. Reversal (صيد القاع)
262
  if 20 <= curr_1h['rsi'] <= 40 and change_4h <= -2.0:
263
  score = (100 - curr_1h['rsi'])
264
  return {'type': 'REVERSAL', 'score': score}
@@ -313,4 +311,4 @@ class DataManager:
313
 
314
  async def get_order_book_snapshot(self, symbol, limit=20):
315
  try: return await self.exchange.fetch_order_book(symbol, limit)
316
- except: return {}
 
1
  # ============================================================
2
  # 📂 ml_engine/data_manager.py
3
+ # (V60.4 - GEM-Architect: Regime Gating + Robust Data)
4
  # ============================================================
5
 
6
  import asyncio
 
12
  import numpy as np
13
  from typing import List, Dict, Any
14
 
15
+ # محاولة استيراد حدود النظام
16
  try:
17
  from ml_engine.processor import SystemLimits
18
  except ImportError:
19
  SystemLimits = None
20
 
21
+ # تقليل ضوضاء السجلات
22
  logging.getLogger("httpx").setLevel(logging.WARNING)
23
  logging.getLogger("ccxt").setLevel(logging.WARNING)
24
 
 
27
  self.contracts_db = contracts_db or {}
28
  self.whale_monitor = whale_monitor
29
  self.r2_service = r2_service
30
+ self.adaptive_hub_ref = None
31
 
 
32
  self.exchange = ccxt.kucoin({
33
  'enableRateLimit': True,
34
  'timeout': 60000,
 
38
  self.http_client = None
39
  self.market_cache = {}
40
 
41
+ # القائمة السوداء
42
  self.BLACKLIST_TOKENS = [
43
  'USDT', 'USDC', 'DAI', 'TUSD', 'BUSD', 'FDUSD', 'EUR', 'PAX',
44
  'UP', 'DOWN', 'BEAR', 'BULL', '3S', '3L'
45
  ]
46
 
47
+ print(f"📦 [DataManager V60.4] Regime Gating (Range Protection) Active.")
48
 
49
  async def initialize(self):
50
  print(" > [DataManager] Starting initialization...")
 
73
  return self.contracts_db
74
 
75
  # ==================================================================
76
+ # 🧠 Layer 1: Screening + Diagnosis + Regime Gating
77
  # ==================================================================
78
  async def layer1_rapid_screening(self, adaptive_hub_ref=None) -> List[Dict[str, Any]]:
79
  self.adaptive_hub_ref = adaptive_hub_ref
80
+ print(f"🔍 [Layer 1] Screening with Regime Gating...")
81
 
82
+ # 1. فلتر السيولة
83
  initial_candidates = await self._stage0_universe_filter()
 
84
  if not initial_candidates:
85
+ print("⚠️ [Layer 1] Stage 0 returned 0 candidates.")
86
  return []
87
 
88
+ # 2. جلب البيانات الفنية
89
  top_candidates = initial_candidates[:120]
90
  enriched_data = await self._fetch_technical_data_batch(top_candidates)
91
 
92
  final_list = []
93
 
94
  for item in enriched_data:
95
+ # 3. التصنيف الفني (Breakout vs Reversal)
96
  classification = self._apply_strict_logic_tree(item)
97
 
98
  if classification['type'] != 'NONE':
99
+ # 4. التشخيص (Diagnosis)
100
  regime_info = self._diagnose_asset_regime(item)
101
+ current_regime = regime_info['regime']
102
+
103
+ # 🔥 5. Regime Gating (بوابة النظام - الحماية من المصيدة)
104
+ # إذا السوق عرضي (RANGE) أو ميت (DEAD)، نمنع الاختراقات (BREAKOUT)
105
+ # لأن الاختراقات تفشل في هذه الظروف وتصبح مصيدة ثيران.
106
+ if current_regime in ['RANGE', 'DEAD'] and classification['type'] == 'BREAKOUT':
107
+ # تخطي بصمت (حماية)
108
+ continue
109
+
110
+ # إذا مر من البوابة، نتابع
111
+ item['asset_regime'] = current_regime
112
  item['asset_regime_conf'] = regime_info['conf']
113
 
114
+ # حقن العتبات
115
  if self.adaptive_hub_ref:
116
+ dynamic_config = self.adaptive_hub_ref.get_regime_config(current_regime)
117
  item['dynamic_limits'] = dynamic_config
118
 
119
  item['l1_sort_score'] = classification['score']
120
  item['strategy_tag'] = classification['type']
121
  final_list.append(item)
122
 
123
+ # 6. الترتيب النهائي
124
  final_list.sort(key=lambda x: x['l1_sort_score'], reverse=True)
125
 
126
  selection = final_list[:50]
127
+ print(f"✅ [Layer 1] Passed {len(selection)} candidates (Safe Strategies Only).")
128
  return selection
129
 
130
  # ==================================================================
131
+ # 🔍 Stage 0: Universe Filter (Robust USD Calc)
132
  # ==================================================================
133
  async def _stage0_universe_filter(self) -> List[Dict[str, Any]]:
134
  try:
 
136
  tickers = await self.exchange.fetch_tickers()
137
  candidates = []
138
 
139
+ # القائمة السيادية (تمر دائماً)
140
+ SOVEREIGN_COINS = ['BTC/USDT', 'ETH/USDT', 'SOL/USDT', 'BNB/USDT', 'XRP/USDT']
141
+
142
  reject_stats = {"volume": 0, "change": 0, "blacklist": 0}
143
  debug_printed = False
144
 
145
  for symbol, ticker in tickers.items():
146
  if not symbol.endswith('/USDT'): continue
147
 
 
148
  base_curr = symbol.split('/')[0]
149
  if any(bad in base_curr for bad in self.BLACKLIST_TOKENS):
150
  reject_stats["blacklist"] += 1
151
  continue
152
 
153
+ # حساب الحجم يدوياً لضمان الدقة
 
154
  base_vol = float(ticker.get('baseVolume') or 0.0)
155
  last_price = float(ticker.get('last') or 0.0)
 
 
156
  calc_quote_vol = base_vol * last_price
157
 
158
+ is_sovereign = symbol in SOVEREIGN_COINS
159
+
160
+ # طباعة فحص BTC مرة واحدة
161
  if "BTC/USDT" in symbol and not debug_printed:
162
+ print(f" 🐛 [DEBUG] BTC Vol: ${calc_quote_vol:,.0f}")
163
  debug_printed = True
164
 
165
+ # فلتر السيولة (500k) - نتجاوزه للعملات السيادية
166
+ if not is_sovereign:
167
+ if calc_quote_vol < 500_000:
168
+ reject_stats["volume"] += 1
169
+ continue
170
 
171
+ # فلتر التغير (20%)
172
  change_pct = ticker.get('percentage')
173
  if change_pct is None: change_pct = 0.0
174
 
 
178
 
179
  candidates.append({
180
  'symbol': symbol,
181
+ 'quote_volume': calc_quote_vol,
182
  'current_price': last_price,
183
  'change_24h': change_pct
184
  })
 
195
  return []
196
 
197
  # ------------------------------------------------------------------
198
+ # 🧭 The Diagnoser
199
  # ------------------------------------------------------------------
200
  def _diagnose_asset_regime(self, item: Dict[str, Any]) -> Dict[str, Any]:
201
  try:
 
225
  except Exception: return {'regime': 'RANGE', 'conf': 0.0}
226
 
227
  # ------------------------------------------------------------------
228
+ # 🛡️ The Logic Tree (Anti-FOMO Tuned)
229
  # ------------------------------------------------------------------
230
  def _apply_strict_logic_tree(self, data: Dict[str, Any]) -> Dict[str, Any]:
231
  try:
 
242
  change_4h = ((curr_1h['close'] - close_4h_ago) / close_4h_ago) * 100
243
  except: change_4h = 0.0
244
 
245
+ # Gates
 
246
  if change_4h > 12.0: return {'type': 'NONE', 'score': 0}
 
 
247
  if curr_1h['rsi'] > 75: return {'type': 'NONE', 'score': 0}
 
 
248
  dev = (curr_1h['close'] - curr_1h['ema20']) / curr_1h['atr'] if curr_1h['atr'] > 0 else 0
249
  if dev > 2.2: return {'type': 'NONE', 'score': 0}
250
 
251
+ # A. Breakout
 
 
252
  is_bullish = (curr_1h['ema20'] > curr_1h['ema50']) or (curr_1h['close'] > curr_1h['ema20'])
 
 
253
  if is_bullish and (45 <= curr_1h['rsi'] <= 75):
254
  vol_ma = df_15m['volume'].rolling(20).mean().iloc[-1]
 
 
255
  if curr_15m['volume'] >= 1.2 * vol_ma:
256
  score = curr_15m['volume'] / vol_ma if vol_ma > 0 else 1.0
257
  return {'type': 'BREAKOUT', 'score': score}
258
 
259
+ # B. Reversal
260
  if 20 <= curr_1h['rsi'] <= 40 and change_4h <= -2.0:
261
  score = (100 - curr_1h['rsi'])
262
  return {'type': 'REVERSAL', 'score': score}
 
311
 
312
  async def get_order_book_snapshot(self, symbol, limit=20):
313
  try: return await self.exchange.fetch_order_book(symbol, limit)
314
+ except: return {}