Riy777 commited on
Commit
75763fd
·
verified ·
1 Parent(s): 738e54b

Update trade_manager.py

Browse files
Files changed (1) hide show
  1. trade_manager.py +101 -278
trade_manager.py CHANGED
@@ -1,6 +1,6 @@
1
- # trade_manager.py (V22.5 - GEM-Architect: Real-Time Hard Limits Fix)
 
2
  import asyncio
3
- import json
4
  import uuid
5
  import time
6
  import traceback
@@ -8,70 +8,56 @@ from datetime import datetime
8
  from typing import List, Dict, Any
9
 
10
  class TradeManager:
11
- def __init__(self, r2_service, data_manager, titan_engine, pattern_engine, guard_engine=None, sniper_engine=None, deep_steward=None):
 
 
 
12
  self.r2 = r2_service
13
  self.data_manager = data_manager
14
- self.titan = titan_engine
15
- self.pattern_engine = pattern_engine
16
-
17
- # ⚠️ GuardEngine (Old V1) - معطل تماماً
18
- self.guard = guard_engine
19
-
20
- self.sniper = sniper_engine
21
 
22
- # [ 🧠 ] Hybrid Deep Steward (V2 Radar + V3 Sniper)
23
- self.deep_steward = deep_steward
24
 
25
  self.open_positions = {}
26
  self.watchlist = {}
27
  self.sentry_tasks = {}
28
  self.running = True
29
 
30
- # [ 🧠 IQ Stats ] مخزن الإحصائيات
31
  self.ai_stats = {
32
  "hybrid": {"total": 0, "good": 0, "saved": 0.0, "missed": 0.0},
33
  "v2": {"total": 0, "good": 0, "saved": 0.0, "missed": 0.0},
34
  "v3": {"total": 0, "good": 0, "saved": 0.0, "missed": 0.0}
35
  }
36
 
37
- self.ds_stats = self.ai_stats["hybrid"]
38
-
39
  self.execution_lock = asyncio.Lock()
40
 
41
- print(f"🛡️ [TradeManager V22.5] Initialized. Real-Time Hard Limits Enabled.")
42
 
43
  async def initialize_sentry_exchanges(self):
44
- print("🛡️ [TradeManager] Initializing and syncing state with R2...")
45
  await self.sync_internal_state_with_r2()
46
 
47
  async def sync_internal_state_with_r2(self):
48
  try:
49
  open_trades_list = await self.r2.get_open_trades_async()
50
  self.open_positions = {trade['symbol']: trade for trade in open_trades_list}
51
- print(f" -> [Sync] تم استعادة {len(self.open_positions)} صفقة مفتوحة من R2.")
52
  except Exception as e:
53
- print(f"❌ [TradeManager] فشل فادح في مزامنة R2 (get_open_trades_async): {e}")
54
  self.open_positions = {}
55
 
56
  # ==============================================================================
57
- # 🎯 دوال الفرز والتنفيذ (L4 Sniper Logic)
58
  # ==============================================================================
59
  async def select_and_execute_best_signal(self, oracle_approved_signals: List[Dict[str, Any]]):
60
  if len(self.open_positions) > 0:
61
- print(f"⛔ [TradeManager] تم إلغاء الفرز. توجد صفقة مفتوحة بالفعل.")
62
  return
63
 
64
- if self.sniper and not self.sniper.initialized:
65
- try:
66
- print(" -> [Lazy Load] 🎯 تهيئة SniperEngine V3 (Batch Select) عند الطلب...")
67
- await self.sniper.initialize()
68
- except Exception as e:
69
- print(f"❌ [Lazy Load] فشل فادح في تهيئة SniperEngine: {e}")
70
- self.sniper = None
71
-
72
- if not self.sniper or not self.sniper.initialized:
73
- print("⚠️ [TradeManager] SniperEngine V3 غير جاهز للفرز. تم الإلغاء.")
74
- return
75
 
76
  sniper_candidates = []
77
 
@@ -79,93 +65,61 @@ class TradeManager:
79
  symbol = signal['symbol']
80
 
81
  if symbol in self.open_positions or symbol in self.watchlist:
82
- print(f" -> [L4 Skip] {symbol} موجودة مسبقاً في الصفقات أو المراقبة.")
83
  continue
84
 
85
- print(f" -> [L4 Check] {symbol} التحقق من L4 (Sniper)...")
86
  ohlcv_1m = await self.data_manager.get_latest_ohlcv(symbol, '1m', 600)
87
 
88
- if not ohlcv_1m or len(ohlcv_1m) < self.sniper.LOOKBACK_WINDOW:
89
- print(f" -> [L4 Skip] {symbol} بيانات 1m غير كافية للقناص ({len(ohlcv_1m)} < {self.sniper.LOOKBACK_WINDOW}).")
90
- continue
91
-
92
- sniper_result = await self.sniper.check_entry_signal_async(ohlcv_1m)
93
 
94
  if sniper_result['signal'] == 'BUY':
95
  confidence = sniper_result['confidence_prob']
96
- threshold = sniper_result.get('threshold', self.sniper.threshold)
97
- print(f" -> [L4 PASS] {symbol} (Conf: {confidence:.2f} >= {threshold:.2f}). أضيف للفرز النهائي.")
98
 
99
  signal['l2_sniper_result'] = sniper_result
100
  signal['sniper_confidence'] = confidence
101
  sniper_candidates.append(signal)
102
  else:
103
- confidence = sniper_result.get('confidence_prob', 0.0)
104
- threshold = sniper_result.get('threshold', self.sniper.threshold)
105
- print(f" -> [L4 REJECT] {symbol} (Conf: {confidence:.2f} < {threshold:.2f}).")
106
 
107
  if not sniper_candidates:
108
- print(" -> [L4 Result] القناص رفض جميع الإشارات المعتمدة من العقل. لا يوجد تنفيذ.")
109
  return
110
 
 
111
  sniper_candidates.sort(key=lambda x: (x['sniper_confidence'], x['final_total_score']), reverse=True)
112
-
113
  best_signal = sniper_candidates[0]
114
 
115
- print(f" 🔥 [L4 WINNER] {best_signal['symbol']} (Sniper: {best_signal['sniper_confidence']:.2f}, L2: {best_signal['final_total_score']:.2f})")
116
 
117
- if len(sniper_candidates) > 1:
118
- for i, loser in enumerate(sniper_candidates[1:]):
119
- print(f" -> (خسرت أمامها: {i+2}. {loser['symbol']} (Sniper: {loser['sniper_confidence']:.2f}, L2: {loser['final_total_score']:.2f}))")
120
-
121
  async with self.execution_lock:
122
- if len(self.open_positions) > 0:
123
- print(f"⛔ [TradeManager] تم إلغاء التنفيذ في اللحظة الأخيرة. توجد صفقة مفتوحة.")
124
- return
125
-
126
- if best_signal['symbol'] in self.open_positions:
127
- print(f" -> [L4 EXEC SKIP] {best_signal['symbol']} تم فتحها بواسطة عملية أخرى للتو.")
128
- return
129
-
130
- await self._execute_entry_from_signal(best_signal['symbol'], best_signal)
131
 
132
  # ==============================================================================
133
- # 🎯 تنفيذ الدخول (Entry Execution)
134
  # ==============================================================================
135
  async def _execute_entry_from_signal(self, symbol, signal_data):
136
  try:
137
- if len(self.open_positions) > 0:
138
- print(f"⛔ [Entry BLOCKED] لا يمكن فتح {symbol}، توجد صفقة مفتوحة بالفعل.")
139
- return
140
-
141
  trade_id = str(uuid.uuid4())
142
  current_price = float(signal_data.get('current_price', 0.0))
143
-
144
  if current_price <= 0.0:
145
  current_price = await self.data_manager.get_latest_price_async(symbol)
146
- if current_price <= 0.0:
147
- print(f"⚠️ [Entry ERROR] {symbol} السعر 0، لا يمكن التنفيذ.")
148
- return
149
 
150
  l2_result = signal_data.get('l2_sniper_result', {})
151
- l2_confidence = l2_result.get('confidence_prob', 0.0)
152
- l2_threshold = l2_result.get('threshold', 0.0)
153
-
154
- tp_price = signal_data.get('tp_price')
155
- sl_price = signal_data.get('sl_price')
156
 
157
- if not tp_price or not sl_price:
158
- print(f" -> [Entry Info] {symbol} لم يوفر العقل أهدافاً، جاري الحساب الوهمي.")
159
  atr_mock = current_price * 0.02
160
  tp_price = current_price + (atr_mock * 2.0)
161
  sl_price = current_price - (atr_mock * 1.0)
162
-
163
- tp_price = float(tp_price)
164
- sl_price = float(sl_price)
165
-
166
- if tp_price <= current_price or sl_price >= current_price:
167
- print(f"⚠️ [Entry ERROR] {symbol} أهداف TP/SL غير صالحة. إلغاء.")
168
- return
169
 
170
  new_trade = {
171
  'id': trade_id,
@@ -178,100 +132,41 @@ class TradeManager:
178
  'last_update': datetime.now().isoformat(),
179
 
180
  'l1_score': float(signal_data.get('final_total_score', 0.0)),
181
- 'l1_components': signal_data.get('components', {}),
182
- 'l2_sniper_confidence': float(l2_confidence),
183
- 'l2_sniper_threshold': float(l2_threshold),
184
- 'l3_oracle_tp': float(signal_data.get('tp_price', 0.0) or 0.0),
185
- 'l3_oracle_sl': float(signal_data.get('sl_price', 0.0) or 0.0),
186
  }
187
 
188
  self.open_positions[symbol] = new_trade
 
189
 
190
- if self.watchlist:
191
- print(f" -> [Watchlist] مسح {len(self.watchlist)} عنصر من قائمة المراقبة.")
192
- self.watchlist.clear()
193
-
194
- # ============================================================
195
- # 🕒 تسجيل وقت أول صفقة
196
- # ============================================================
197
  portfolio = await self.r2.get_portfolio_state_async()
198
  if portfolio.get('first_trade_timestamp') is None:
199
  portfolio['first_trade_timestamp'] = new_trade['entry_time']
200
  await self.r2.save_portfolio_state_async(portfolio)
201
-
202
  await self.r2.save_open_trades_async(list(self.open_positions.values()))
203
 
204
- if symbol in self.sentry_tasks:
205
- self.sentry_tasks[symbol].cancel()
206
-
207
  self.sentry_tasks[symbol] = asyncio.create_task(self._guardian_loop(symbol))
208
 
209
- print(f"✅ [ENTRY EXECUTED] {symbol} | Price: {current_price:.8f} | TP: {tp_price:.8f} | SL: {sl_price:.8f}")
210
 
211
  except Exception as e:
212
- print(f"❌ [TradeManager] فشل فادح أثناء تنفيذ الدخول لـ {symbol}: {e}")
213
  traceback.print_exc()
214
 
215
  # ==============================================================================
216
- # 👁️ Watchlist Functions
217
- # ==============================================================================
218
- async def _add_to_watchlist(self, symbol, signal_data):
219
- if symbol not in self.open_positions and symbol not in self.watchlist:
220
- if self.open_positions:
221
- print(f"👀 [Watchlist] {symbol} تم تجاهله (توجد صفقة أخرى مفتوحة).")
222
- return
223
-
224
- self.watchlist[symbol] = signal_data
225
- print(f"👀 [Watchlist] {symbol} تمت إضافته للمراقبة (L1 Score: {signal_data['enhanced_final_score']:.2f})")
226
-
227
- async def _find_signal_in_watchlist(self):
228
- if not self.watchlist:
229
- return
230
-
231
- if self.open_positions:
232
- print(" -> [Watchlist] تم تخطي البحث (توجد صفقة مفتوحة). مسح المراقب...")
233
- self.watchlist.clear()
234
- return
235
-
236
- if self.sniper and not self.sniper.initialized:
237
- try:
238
- print(" -> [Lazy Load] 🎯 تهيئة SniperEngine V3 (Watchlist) عند الطلب...")
239
- await self.sniper.initialize()
240
- except Exception as e:
241
- print(f"❌ [Lazy Load] فشل فادح في تهيئة SniperEngine (Watchlist): {e}")
242
- self.sniper = None
243
-
244
- if not self.sniper or not self.sniper.initialized:
245
- return
246
-
247
- watchlist_symbols = list(self.watchlist.keys())
248
- if not watchlist_symbols:
249
- return
250
-
251
- print(f" -> [Watchlist] فحص {len(watchlist_symbols)} عملة في قائمة المراقبة لـ L4...")
252
-
253
- signals_from_watchlist = []
254
- for symbol in watchlist_symbols:
255
- signal_data = self.watchlist.get(symbol)
256
- if not signal_data: continue
257
- signals_from_watchlist.append(signal_data)
258
-
259
- if signals_from_watchlist:
260
- await self.select_and_execute_best_signal(signals_from_watchlist)
261
-
262
- # ==============================================================================
263
- # 🛡️ دوال حا��س الخروج (Hybrid Sentry) - [CRITICAL FIX: Real-Time Checks]
264
  # ==============================================================================
265
  async def _guardian_loop(self, symbol: str):
266
- print(f"🛡️ [Sentry Activated] بدء الحراسة لـ {symbol} (وضع الاستجابة الفورية).")
267
-
268
  last_ai_check_time = 0
269
 
270
  while self.running and symbol in self.open_positions:
271
  try:
272
- # [FAST LANE] المسار السريع: فحص الحدود الصارمة كل 2 ثانية
273
- # هذا يضمن عدم تفويت الهدف إذا تحرك السعر بسرعة
274
- await asyncio.sleep(2)
275
 
276
  trade = self.open_positions.get(symbol)
277
  if not trade: break
@@ -279,61 +174,48 @@ class TradeManager:
279
  current_price = await self.data_manager.get_latest_price_async(symbol)
280
  if current_price == 0.0: continue
281
 
282
- # 1. فحص الحدود الصارمة (Hard Limits) - أولوية قصوى
283
  if current_price >= trade['tp_price']:
284
- print(f"✅ [Sentry FAST] {symbol} (Target Hit) at {current_price:.8f}")
285
  async with self.execution_lock:
286
  await self._execute_exit(symbol, current_price, "TP_HIT_HARD")
287
  break
288
-
289
  if current_price <= trade['sl_price']:
290
- print(f"🛑 [Sentry FAST] {symbol} (Stop Loss Hit) at {current_price:.8f}")
291
  async with self.execution_lock:
292
  await self._execute_exit(symbol, current_price, "SL_HIT_HARD")
293
  break
294
 
295
- # 🐌 [SLOW LANE] المسار البطيء: فحص الذكاء الاصطناعي كل 60 ثانية
296
  if time.time() - last_ai_check_time > 60:
297
- if self.deep_steward and self.deep_steward.initialized:
298
- # جلب البيانات اللازمة (تم تثبيت الحد على 300)
299
- task1 = self.data_manager.get_latest_ohlcv(symbol, '1m', 300)
300
- task5 = self.data_manager.get_latest_ohlcv(symbol, '5m', 200)
301
- task15 = self.data_manager.get_latest_ohlcv(symbol, '15m', 100)
 
 
 
 
302
 
303
- d1, d5, d15 = await asyncio.gather(task1, task5, task15)
 
304
 
305
- if d1 and d5 and d15 and len(d1) >= 200:
306
- decision = self.deep_steward.analyze_position(d1, d5, d15, trade['entry_price'])
307
- action = decision.get('action', 'HOLD')
308
- scores = decision.get('scores', {})
309
-
310
- if action == 'EXIT_HARD':
311
- print(f"🤖 [Hybrid Guardian] 🚨 خروج طارئ! {decision['reason']}")
312
- async with self.execution_lock:
313
- await self._execute_exit(symbol, current_price, "AI_HARD_EXIT", ai_scores=scores)
314
- break
315
-
316
- elif action == 'EXIT_SOFT':
317
- print(f"🤖 [Hybrid Guardian] ⚠️ تحذير خروج! {decision['reason']}")
318
- async with self.execution_lock:
319
- await self._execute_exit(symbol, current_price, "AI_SOFT_EXIT", ai_scores=scores)
320
- break
321
- else:
322
- # لو البيانات ناقصة، ننتظر الدورة القادمة
323
- pass
324
 
325
  last_ai_check_time = time.time()
326
  self.open_positions[symbol]['last_update'] = datetime.now().isoformat()
327
 
328
  except asyncio.CancelledError:
329
- print(f"🛡️ [Sentry STOP] تم إيقاف الحارس لـ {symbol}.")
330
  break
331
  except Exception as e:
332
- print(f"❌ [Sentry ERROR] فشل مؤقت لـ {symbol}: {e}")
333
- await asyncio.sleep(5) # انتظار قصير عند الخطأ
334
 
335
  # ==============================================================================
336
- # 👻 المراقب الشبحي (Ghost Monitor)
337
  # ==============================================================================
338
  def _launch_post_exit_analysis(self, symbol, exit_price, exit_time, position_size_usd, ai_scores=None):
339
  asyncio.create_task(self._analyze_after_exit_task(symbol, exit_price, exit_time, position_size_usd, ai_scores))
@@ -348,146 +230,87 @@ class TradeManager:
348
  self.ai_stats[key]["missed"] += abs(usd_impact)
349
 
350
  async def _analyze_after_exit_task(self, symbol, exit_price, exit_time, position_size_usd, ai_scores):
351
- await asyncio.sleep(900)
352
-
353
  try:
354
- current_price = await self.data_manager.get_latest_price_async(symbol)
355
- if current_price == 0: return
356
 
357
- change_pct = (current_price - exit_price) / exit_price
358
  usd_impact = change_pct * position_size_usd
359
  is_good_exit = change_pct < 0
360
 
361
- # 1. تحديث الهجين
362
  self._update_specific_stat("hybrid", is_good_exit, usd_impact)
363
 
364
- # 2. تحديث المكونات
365
  if ai_scores:
366
- v2_score = ai_scores.get('v2', 0.0)
367
- v3_score = ai_scores.get('v3', 0.0)
368
-
369
- if v2_score >= 0.60: # V2 ساهم
370
- self._update_specific_stat("v2", is_good_exit, usd_impact)
371
-
372
- if v3_score >= 0.75: # V3 ساهم
373
- self._update_specific_stat("v3", is_good_exit, usd_impact)
374
-
375
- audit_record = {
376
- "symbol": symbol,
377
- "exit_time": exit_time,
378
- "exit_price": exit_price,
379
- "price_15m_later": current_price,
380
- "change_15m_pct": change_pct * 100,
381
- "usd_impact": usd_impact,
382
- "verdict": "SUCCESS (Saved Loss)" if is_good_exit else "MISS (Lost Profit)",
383
- "ai_scores": ai_scores if ai_scores else {},
384
- "timestamp": datetime.now().isoformat()
385
  }
386
-
387
- await self.r2.append_deep_steward_audit(audit_record)
388
- print(f"👻 [Ghost Monitor] {symbol}: {audit_record['verdict']} | Impact: ${usd_impact:.2f}")
389
 
390
  except Exception as e:
391
- print(f"⚠️ [Ghost Error] {symbol}: {e}")
392
 
393
  # ==============================================================================
394
- # 🔴 دالة الخروج المحاسبية (Accounting Exit Logic)
395
  # ==============================================================================
396
  async def _execute_exit(self, symbol, price, reason, ai_scores=None):
397
- if symbol not in self.open_positions:
398
- print(f"⚠️ [Exit ERROR] {symbol} غير موجودة في الصفقات المفتوحة.")
399
- return
400
 
401
  try:
402
  trade = self.open_positions.pop(symbol)
403
- entry_price = float(trade['entry_price'])
404
- exit_price = float(price)
405
-
406
- raw_profit_pct = (exit_price - entry_price) / entry_price
407
- profit_pct_display = raw_profit_pct * 100
408
 
409
- trade['status'] = 'CLOSED'
410
- trade['exit_price'] = exit_price
411
- trade['exit_time'] = datetime.now().isoformat()
412
- trade['exit_reason'] = reason
413
- trade['profit_pct'] = profit_pct_display
414
 
415
  portfolio = await self.r2.get_portfolio_state_async()
416
- current_capital = float(portfolio.get('current_capital_usd', 100.0))
 
 
417
 
418
- pnl_usd = current_capital * raw_profit_pct
419
- new_capital = current_capital + pnl_usd
420
-
421
- portfolio['current_capital_usd'] = new_capital
422
  portfolio['total_trades'] = portfolio.get('total_trades', 0) + 1
423
-
424
  if pnl_usd >= 0:
425
  portfolio['winning_trades'] = portfolio.get('winning_trades', 0) + 1
426
- portfolio['total_profit_usd'] = portfolio.get('total_profit_usd', 0.0) + pnl_usd
427
  trade['result'] = 'WIN'
428
  else:
429
  portfolio['losing_trades'] = portfolio.get('losing_trades', 0) + 1
430
- portfolio['total_loss_usd'] = portfolio.get('total_loss_usd', 0.0) + abs(pnl_usd)
431
  trade['result'] = 'LOSS'
432
 
433
- total_t = portfolio['total_trades']
434
- if total_t > 0:
435
- portfolio['win_rate'] = (portfolio['winning_trades'] / total_t) * 100
436
-
437
- trade['pnl_usd'] = pnl_usd
438
-
439
  await self.r2.save_portfolio_state_async(portfolio)
440
  await self.r2.save_open_trades_async(list(self.open_positions.values()))
441
  await self.r2.append_to_closed_trades_history(trade)
442
 
443
- print(f"✅ [EXIT EXECUTED] {symbol} | Reason: {reason} | PnL: {profit_pct_display:.2f}% (${pnl_usd:.2f}) | New Cap: ${new_capital:.2f}")
444
 
445
  if "AI_" in reason:
446
- self._launch_post_exit_analysis(symbol, exit_price, trade['exit_time'], current_capital, ai_scores)
447
 
448
  if symbol in self.sentry_tasks:
449
  self.sentry_tasks[symbol].cancel()
450
  del self.sentry_tasks[symbol]
451
 
452
  except Exception as e:
453
- print(f"❌ [TradeManager] فشل فادح أثناء تنفيذ الخروج لـ {symbol}: {e}")
454
- traceback.print_exc()
455
- if symbol not in self.open_positions:
456
- self.open_positions[symbol] = trade
457
 
458
  async def force_exit_by_manager(self, symbol, reason):
459
- print(f"⚠️ [Manager Force Exit] طلب خروج إداري لـ {symbol} بسبب: {reason}")
460
- current_price = await self.data_manager.get_latest_price_async(symbol)
461
  async with self.execution_lock:
462
- await self._execute_exit(symbol, current_price, reason)
463
-
464
- async def update_trade_targets(self, symbol, new_tp=None, new_sl=None, reason="MANUAL"):
465
- if symbol in self.open_positions:
466
- trade = self.open_positions[symbol]
467
- old_tp = trade['tp_price']
468
- old_sl = trade['sl_price']
469
-
470
- if new_tp is not None: trade['tp_price'] = float(new_tp)
471
- if new_sl is not None: trade['sl_price'] = float(new_sl)
472
-
473
- self.open_positions[symbol] = trade
474
- await self.r2.save_open_trades_async(list(self.open_positions.values()))
475
-
476
- print(f"🎯 [Targets Updated] {symbol} | TP: {old_tp:.8f}->{trade['tp_price']:.8f} | SL: {old_sl:.8f}->{trade['sl_price']:.8f} | Reason: {reason}")
477
- else:
478
- print(f"⚠️ [Target Update Failed] {symbol} is not currently open.")
479
 
480
  async def start_sentry_loops(self):
481
  for symbol in list(self.open_positions.keys()):
482
  if symbol not in self.sentry_tasks or self.sentry_tasks[symbol].done():
483
- print(f"🛡️ [Sentry Restart] Activating guardian for existing trade: {symbol}")
484
  self.sentry_tasks[symbol] = asyncio.create_task(self._guardian_loop(symbol))
485
 
486
  async def stop_sentry_loops(self):
487
- print("🛑 [TradeManager] Stopping all sentry loops...")
488
  self.running = False
489
- for sym, task in self.sentry_tasks.items():
490
- task.cancel()
491
-
492
- await asyncio.sleep(1)
493
- print("🛑 [TradeManager] All sentries stopped.")
 
1
+ # trade_manager.py (V23.0 - GEM-Architect: Processor Integration)
2
+
3
  import asyncio
 
4
  import uuid
5
  import time
6
  import traceback
 
8
  from typing import List, Dict, Any
9
 
10
  class TradeManager:
11
+ def __init__(self, r2_service, data_manager, processor):
12
+ """
13
+ مدير الصفقات: يعتمد كلياً على 'processor' في القرارات الذكية.
14
+ """
15
  self.r2 = r2_service
16
  self.data_manager = data_manager
 
 
 
 
 
 
 
17
 
18
+ # 🧠 The Central Brain
19
+ self.processor = processor
20
 
21
  self.open_positions = {}
22
  self.watchlist = {}
23
  self.sentry_tasks = {}
24
  self.running = True
25
 
26
+ # [ 🧠 IQ Stats ]
27
  self.ai_stats = {
28
  "hybrid": {"total": 0, "good": 0, "saved": 0.0, "missed": 0.0},
29
  "v2": {"total": 0, "good": 0, "saved": 0.0, "missed": 0.0},
30
  "v3": {"total": 0, "good": 0, "saved": 0.0, "missed": 0.0}
31
  }
32
 
 
 
33
  self.execution_lock = asyncio.Lock()
34
 
35
+ print(f"🛡️ [TradeManager V23] Initialized with Central Processor.")
36
 
37
  async def initialize_sentry_exchanges(self):
38
+ print("🛡️ [TradeManager] Syncing state with R2...")
39
  await self.sync_internal_state_with_r2()
40
 
41
  async def sync_internal_state_with_r2(self):
42
  try:
43
  open_trades_list = await self.r2.get_open_trades_async()
44
  self.open_positions = {trade['symbol']: trade for trade in open_trades_list}
45
+ print(f" -> [Sync] Recovered {len(self.open_positions)} active trades.")
46
  except Exception as e:
47
+ print(f"❌ [TradeManager] R2 Sync Failed: {e}")
48
  self.open_positions = {}
49
 
50
  # ==============================================================================
51
+ # 🎯 L4 Sniper Logic (Via Processor)
52
  # ==============================================================================
53
  async def select_and_execute_best_signal(self, oracle_approved_signals: List[Dict[str, Any]]):
54
  if len(self.open_positions) > 0:
55
+ print(f"⛔ [TradeManager] Scan aborted. Max positions reached.")
56
  return
57
 
58
+ # نطلب من المعالج التأكد من أن القناص جاهز
59
+ if not self.processor.initialized:
60
+ await self.processor.initialize()
 
 
 
 
 
 
 
 
61
 
62
  sniper_candidates = []
63
 
 
65
  symbol = signal['symbol']
66
 
67
  if symbol in self.open_positions or symbol in self.watchlist:
 
68
  continue
69
 
70
+ # جلب البيانات
71
  ohlcv_1m = await self.data_manager.get_latest_ohlcv(symbol, '1m', 600)
72
 
73
+ # استشارة القناص عبر المعالج
74
+ sniper_result = await self.processor.check_sniper_entry(ohlcv_1m)
 
 
 
75
 
76
  if sniper_result['signal'] == 'BUY':
77
  confidence = sniper_result['confidence_prob']
78
+ threshold = sniper_result.get('threshold', 0.60)
79
+ print(f" -> [L4 PASS] {symbol} (Conf: {confidence:.2f}). Added to batch.")
80
 
81
  signal['l2_sniper_result'] = sniper_result
82
  signal['sniper_confidence'] = confidence
83
  sniper_candidates.append(signal)
84
  else:
85
+ print(f" -> [L4 REJECT] {symbol} (Conf: {sniper_result.get('confidence_prob',0):.2f})")
 
 
86
 
87
  if not sniper_candidates:
88
+ print(" -> [L4 Result] No candidates passed the Sniper check.")
89
  return
90
 
91
+ # ترتيب النتائج
92
  sniper_candidates.sort(key=lambda x: (x['sniper_confidence'], x['final_total_score']), reverse=True)
 
93
  best_signal = sniper_candidates[0]
94
 
95
+ print(f" 🔥 [L4 WINNER] {best_signal['symbol']} (Sniper: {best_signal['sniper_confidence']:.2f})")
96
 
97
+ # التنفيذ
 
 
 
98
  async with self.execution_lock:
99
+ if len(self.open_positions) == 0 and best_signal['symbol'] not in self.open_positions:
100
+ await self._execute_entry_from_signal(best_signal['symbol'], best_signal)
 
 
 
 
 
 
 
101
 
102
  # ==============================================================================
103
+ # 🎯 Entry Execution
104
  # ==============================================================================
105
  async def _execute_entry_from_signal(self, symbol, signal_data):
106
  try:
 
 
 
 
107
  trade_id = str(uuid.uuid4())
108
  current_price = float(signal_data.get('current_price', 0.0))
 
109
  if current_price <= 0.0:
110
  current_price = await self.data_manager.get_latest_price_async(symbol)
 
 
 
111
 
112
  l2_result = signal_data.get('l2_sniper_result', {})
113
+
114
+ # الأهداف (من Oracle أو حساب تلقائي)
115
+ tp_price = float(signal_data.get('tp_price') or 0.0)
116
+ sl_price = float(signal_data.get('sl_price') or 0.0)
 
117
 
118
+ if tp_price <= 0 or sl_price <= 0:
119
+ # Fallback simple calculation
120
  atr_mock = current_price * 0.02
121
  tp_price = current_price + (atr_mock * 2.0)
122
  sl_price = current_price - (atr_mock * 1.0)
 
 
 
 
 
 
 
123
 
124
  new_trade = {
125
  'id': trade_id,
 
132
  'last_update': datetime.now().isoformat(),
133
 
134
  'l1_score': float(signal_data.get('final_total_score', 0.0)),
135
+ 'l2_sniper_confidence': float(l2_result.get('confidence_prob', 0.0)),
136
+ 'l3_oracle_tp': tp_price,
137
+ 'l3_oracle_sl': sl_price,
 
 
138
  }
139
 
140
  self.open_positions[symbol] = new_trade
141
+ if self.watchlist: self.watchlist.clear()
142
 
143
+ # حفظ في R2
 
 
 
 
 
 
144
  portfolio = await self.r2.get_portfolio_state_async()
145
  if portfolio.get('first_trade_timestamp') is None:
146
  portfolio['first_trade_timestamp'] = new_trade['entry_time']
147
  await self.r2.save_portfolio_state_async(portfolio)
 
148
  await self.r2.save_open_trades_async(list(self.open_positions.values()))
149
 
150
+ # تفعيل الحارس
151
+ if symbol in self.sentry_tasks: self.sentry_tasks[symbol].cancel()
 
152
  self.sentry_tasks[symbol] = asyncio.create_task(self._guardian_loop(symbol))
153
 
154
+ print(f"✅ [ENTRY] {symbol} @ {current_price} | TP: {tp_price} | SL: {sl_price}")
155
 
156
  except Exception as e:
157
+ print(f"❌ [Entry Error] {symbol}: {e}")
158
  traceback.print_exc()
159
 
160
  # ==============================================================================
161
+ # 🛡️ Hybrid Sentry (Via Processor)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  # ==============================================================================
163
  async def _guardian_loop(self, symbol: str):
164
+ print(f"🛡️ [Sentry] Guarding {symbol}...")
 
165
  last_ai_check_time = 0
166
 
167
  while self.running and symbol in self.open_positions:
168
  try:
169
+ await asyncio.sleep(2) # Fast tick
 
 
170
 
171
  trade = self.open_positions.get(symbol)
172
  if not trade: break
 
174
  current_price = await self.data_manager.get_latest_price_async(symbol)
175
  if current_price == 0.0: continue
176
 
177
+ # 1. Hard Limits
178
  if current_price >= trade['tp_price']:
 
179
  async with self.execution_lock:
180
  await self._execute_exit(symbol, current_price, "TP_HIT_HARD")
181
  break
 
182
  if current_price <= trade['sl_price']:
 
183
  async with self.execution_lock:
184
  await self._execute_exit(symbol, current_price, "SL_HIT_HARD")
185
  break
186
 
187
+ # 2. AI Check (Processor Consultation) every 60s
188
  if time.time() - last_ai_check_time > 60:
189
+ t1 = self.data_manager.get_latest_ohlcv(symbol, '1m', 300)
190
+ t5 = self.data_manager.get_latest_ohlcv(symbol, '5m', 200)
191
+ t15 = self.data_manager.get_latest_ohlcv(symbol, '15m', 100)
192
+
193
+ d1, d5, d15 = await asyncio.gather(t1, t5, t15)
194
+
195
+ if d1 and d5 and d15 and len(d1) >= 200:
196
+ # ⚡ استشارة المعالج هنا ⚡
197
+ decision = self.processor.consult_guardian(d1, d5, d15, trade['entry_price'])
198
 
199
+ action = decision.get('action', 'HOLD')
200
+ scores = decision.get('scores', {})
201
 
202
+ if action in ['EXIT_HARD', 'EXIT_SOFT']:
203
+ print(f"🤖 [Guardian] {action}: {decision.get('reason')}")
204
+ async with self.execution_lock:
205
+ await self._execute_exit(symbol, current_price, f"AI_{action}", ai_scores=scores)
206
+ break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
  last_ai_check_time = time.time()
209
  self.open_positions[symbol]['last_update'] = datetime.now().isoformat()
210
 
211
  except asyncio.CancelledError:
 
212
  break
213
  except Exception as e:
214
+ print(f"❌ [Sentry Error] {symbol}: {e}")
215
+ await asyncio.sleep(5)
216
 
217
  # ==============================================================================
218
+ # 👻 Ghost Monitor & Stats
219
  # ==============================================================================
220
  def _launch_post_exit_analysis(self, symbol, exit_price, exit_time, position_size_usd, ai_scores=None):
221
  asyncio.create_task(self._analyze_after_exit_task(symbol, exit_price, exit_time, position_size_usd, ai_scores))
 
230
  self.ai_stats[key]["missed"] += abs(usd_impact)
231
 
232
  async def _analyze_after_exit_task(self, symbol, exit_price, exit_time, position_size_usd, ai_scores):
233
+ await asyncio.sleep(900) # 15 min wait
 
234
  try:
235
+ curr = await self.data_manager.get_latest_price_async(symbol)
236
+ if curr == 0: return
237
 
238
+ change_pct = (curr - exit_price) / exit_price
239
  usd_impact = change_pct * position_size_usd
240
  is_good_exit = change_pct < 0
241
 
 
242
  self._update_specific_stat("hybrid", is_good_exit, usd_impact)
243
 
 
244
  if ai_scores:
245
+ if ai_scores.get('v2', 0) >= 0.60: self._update_specific_stat("v2", is_good_exit, usd_impact)
246
+ if ai_scores.get('v3', 0) >= 0.75: self._update_specific_stat("v3", is_good_exit, usd_impact)
247
+
248
+ record = {
249
+ "symbol": symbol, "exit_price": exit_price, "price_15m": curr,
250
+ "usd_impact": usd_impact, "verdict": "SUCCESS" if is_good_exit else "MISS"
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  }
252
+ await self.r2.append_deep_steward_audit(record)
 
 
253
 
254
  except Exception as e:
255
+ print(f"⚠️ [Ghost Error] {e}")
256
 
257
  # ==============================================================================
258
+ # 🔴 Exit & Force Exit
259
  # ==============================================================================
260
  async def _execute_exit(self, symbol, price, reason, ai_scores=None):
261
+ if symbol not in self.open_positions: return
 
 
262
 
263
  try:
264
  trade = self.open_positions.pop(symbol)
265
+ entry = float(trade['entry_price'])
266
+ exit_p = float(price)
267
+ profit_pct = ((exit_p - entry) / entry)
 
 
268
 
269
+ trade.update({'status': 'CLOSED', 'exit_price': exit_p, 'exit_reason': reason, 'profit_pct': profit_pct*100})
 
 
 
 
270
 
271
  portfolio = await self.r2.get_portfolio_state_async()
272
+ curr_cap = float(portfolio.get('current_capital_usd', 100.0))
273
+ pnl_usd = curr_cap * profit_pct
274
+ new_cap = curr_cap + pnl_usd
275
 
276
+ portfolio['current_capital_usd'] = new_cap
 
 
 
277
  portfolio['total_trades'] = portfolio.get('total_trades', 0) + 1
 
278
  if pnl_usd >= 0:
279
  portfolio['winning_trades'] = portfolio.get('winning_trades', 0) + 1
280
+ portfolio['total_profit_usd'] = portfolio.get('total_profit_usd', 0) + pnl_usd
281
  trade['result'] = 'WIN'
282
  else:
283
  portfolio['losing_trades'] = portfolio.get('losing_trades', 0) + 1
284
+ portfolio['total_loss_usd'] = portfolio.get('total_loss_usd', 0) + abs(pnl_usd)
285
  trade['result'] = 'LOSS'
286
 
 
 
 
 
 
 
287
  await self.r2.save_portfolio_state_async(portfolio)
288
  await self.r2.save_open_trades_async(list(self.open_positions.values()))
289
  await self.r2.append_to_closed_trades_history(trade)
290
 
291
+ print(f"✅ [EXIT] {symbol} | PnL: {trade['profit_pct']:.2f}% | Cap: ${new_cap:.2f}")
292
 
293
  if "AI_" in reason:
294
+ self._launch_post_exit_analysis(symbol, exit_p, trade.get('exit_time'), curr_cap, ai_scores)
295
 
296
  if symbol in self.sentry_tasks:
297
  self.sentry_tasks[symbol].cancel()
298
  del self.sentry_tasks[symbol]
299
 
300
  except Exception as e:
301
+ print(f"❌ [Exit Error] {e}")
302
+ self.open_positions[symbol] = trade # استعادة في حال الخطأ
 
 
303
 
304
  async def force_exit_by_manager(self, symbol, reason):
305
+ p = await self.data_manager.get_latest_price_async(symbol)
 
306
  async with self.execution_lock:
307
+ await self._execute_exit(symbol, p, reason)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
 
309
  async def start_sentry_loops(self):
310
  for symbol in list(self.open_positions.keys()):
311
  if symbol not in self.sentry_tasks or self.sentry_tasks[symbol].done():
 
312
  self.sentry_tasks[symbol] = asyncio.create_task(self._guardian_loop(symbol))
313
 
314
  async def stop_sentry_loops(self):
 
315
  self.running = False
316
+ for task in self.sentry_tasks.values(): task.cancel()