Spaces:
Paused
Paused
Update trade_manager.py
Browse files- trade_manager.py +44 -30
trade_manager.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# trade_manager.py (
|
| 2 |
import asyncio
|
| 3 |
import json
|
| 4 |
import uuid
|
|
@@ -22,7 +22,7 @@ class TradeManager:
|
|
| 22 |
|
| 23 |
self.execution_lock = asyncio.Lock()
|
| 24 |
|
| 25 |
-
print(f"🛡️ [TradeManager
|
| 26 |
if self.guard:
|
| 27 |
print(f" -> Guard V2 (Exit Protector) CREATED.")
|
| 28 |
else:
|
|
@@ -46,7 +46,7 @@ class TradeManager:
|
|
| 46 |
self.open_positions = {}
|
| 47 |
|
| 48 |
# ==============================================================================
|
| 49 |
-
# 🎯 دال
|
| 50 |
# ==============================================================================
|
| 51 |
async def select_and_execute_best_signal(self, oracle_approved_signals: List[Dict[str, Any]]):
|
| 52 |
if len(self.open_positions) > 0:
|
|
@@ -126,7 +126,7 @@ class TradeManager:
|
|
| 126 |
await self.select_and_execute_best_signal([signal_data])
|
| 127 |
|
| 128 |
# ==============================================================================
|
| 129 |
-
# 🎯 تنفيذ الدخول
|
| 130 |
# ==============================================================================
|
| 131 |
async def _execute_entry_from_signal(self, symbol, signal_data):
|
| 132 |
try:
|
|
@@ -194,7 +194,6 @@ class TradeManager:
|
|
| 194 |
|
| 195 |
self.sentry_tasks[symbol] = asyncio.create_task(self._guardian_loop(symbol))
|
| 196 |
|
| 197 |
-
# [GEM-FIX] استخدام تنسيق 8 خانات في السجلات
|
| 198 |
print(f"✅ [ENTRY EXECUTED] {symbol} | Price: {current_price:.8f} | TP: {tp_price:.8f} | SL: {sl_price:.8f}")
|
| 199 |
print(f" -> L2 Score: {new_trade['l1_score']:.2f}, L4 Conf: {new_trade['l2_sniper_confidence']:.2f}")
|
| 200 |
|
|
@@ -203,9 +202,10 @@ class TradeManager:
|
|
| 203 |
traceback.print_exc()
|
| 204 |
|
| 205 |
# ==============================================================================
|
| 206 |
-
# Watchlist Functions
|
| 207 |
# ==============================================================================
|
| 208 |
async def _add_to_watchlist(self, symbol, signal_data):
|
|
|
|
| 209 |
if symbol not in self.open_positions and symbol not in self.watchlist:
|
| 210 |
if self.open_positions:
|
| 211 |
print(f"👀 [Watchlist] {symbol} تم تجاهله (توجد صفقة أخرى مفتوحة).")
|
|
@@ -215,6 +215,7 @@ class TradeManager:
|
|
| 215 |
print(f"👀 [Watchlist] {symbol} تمت إضافته للمراقبة (L1 Score: {signal_data['enhanced_final_score']:.2f})")
|
| 216 |
|
| 217 |
async def _find_signal_in_watchlist(self):
|
|
|
|
| 218 |
if not self.watchlist:
|
| 219 |
return
|
| 220 |
|
|
@@ -250,10 +251,10 @@ class TradeManager:
|
|
| 250 |
await self.select_and_execute_best_signal(signals_from_watchlist)
|
| 251 |
|
| 252 |
# ==============================================================================
|
| 253 |
-
# دوال حارس الخروج (Sentry)
|
| 254 |
# ==============================================================================
|
| 255 |
async def _guardian_loop(self, symbol: str):
|
| 256 |
-
print(f"🛡️ [Sentry Activated] بدء الحراسة لـ {symbol}.")
|
| 257 |
|
| 258 |
while self.running and symbol in self.open_positions:
|
| 259 |
try:
|
|
@@ -268,6 +269,9 @@ class TradeManager:
|
|
| 268 |
print(f"⚠️ [Sentry {symbol}] فشل جلب السعر، إعادة المحاولة...")
|
| 269 |
continue
|
| 270 |
|
|
|
|
|
|
|
|
|
|
| 271 |
if current_price >= trade['tp_price']:
|
| 272 |
print(f"✅ [Sentry EXIT] {symbol} (TP Hit) at {current_price:.8f}")
|
| 273 |
async with self.execution_lock:
|
|
@@ -280,29 +284,31 @@ class TradeManager:
|
|
| 280 |
await self._execute_exit(symbol, current_price, "SL_HIT")
|
| 281 |
break
|
| 282 |
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
exit_check = await self.guard.check_exit_signal_async(ohlcv_5m)
|
| 296 |
|
| 297 |
-
if
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 302 |
else:
|
|
|
|
| 303 |
pass
|
| 304 |
-
else:
|
| 305 |
-
print(f"⚠️ [Guard V2 Skip] {symbol} بيانات 5m غير كافية للحارس.")
|
| 306 |
|
| 307 |
self.open_positions[symbol]['last_update'] = datetime.now().isoformat()
|
| 308 |
|
|
@@ -316,7 +322,7 @@ class TradeManager:
|
|
| 316 |
|
| 317 |
async def _execute_exit(self, symbol, price, reason):
|
| 318 |
if symbol not in self.open_positions:
|
| 319 |
-
print(f"⚠️ [Exit ERROR] {symbol} غير موجودة في الصفقات المفتوحة
|
| 320 |
return
|
| 321 |
|
| 322 |
try:
|
|
@@ -341,9 +347,18 @@ class TradeManager:
|
|
| 341 |
except Exception as e:
|
| 342 |
print(f"❌ [TradeManager] فشل فادح أثناء تنفيذ الخروج لـ {symbol}: {e}")
|
| 343 |
traceback.print_exc()
|
|
|
|
| 344 |
if symbol not in self.open_positions:
|
| 345 |
self.open_positions[symbol] = trade
|
| 346 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 347 |
async def update_trade_targets(self, symbol, new_tp=None, new_sl=None, reason="MANUAL"):
|
| 348 |
if symbol in self.open_positions:
|
| 349 |
trade = self.open_positions[symbol]
|
|
@@ -371,6 +386,5 @@ class TradeManager:
|
|
| 371 |
self.running = False
|
| 372 |
for sym, task in self.sentry_tasks.items():
|
| 373 |
task.cancel()
|
| 374 |
-
|
| 375 |
await asyncio.sleep(1)
|
| 376 |
print("🛑 [TradeManager] All sentries stopped.")
|
|
|
|
| 1 |
+
# trade_manager.py (V16.2 - GEM-Architect: Full Restoration + Active Mgmt Fixes)
|
| 2 |
import asyncio
|
| 3 |
import json
|
| 4 |
import uuid
|
|
|
|
| 22 |
|
| 23 |
self.execution_lock = asyncio.Lock()
|
| 24 |
|
| 25 |
+
print(f"🛡️ [TradeManager V16.2] Sentry Module Initialized (Full Stack).")
|
| 26 |
if self.guard:
|
| 27 |
print(f" -> Guard V2 (Exit Protector) CREATED.")
|
| 28 |
else:
|
|
|
|
| 46 |
self.open_positions = {}
|
| 47 |
|
| 48 |
# ==============================================================================
|
| 49 |
+
# 🎯 دوال الفرز والتنفيذ (L4 Sniper Logic)
|
| 50 |
# ==============================================================================
|
| 51 |
async def select_and_execute_best_signal(self, oracle_approved_signals: List[Dict[str, Any]]):
|
| 52 |
if len(self.open_positions) > 0:
|
|
|
|
| 126 |
await self.select_and_execute_best_signal([signal_data])
|
| 127 |
|
| 128 |
# ==============================================================================
|
| 129 |
+
# 🎯 تنفيذ الدخول
|
| 130 |
# ==============================================================================
|
| 131 |
async def _execute_entry_from_signal(self, symbol, signal_data):
|
| 132 |
try:
|
|
|
|
| 194 |
|
| 195 |
self.sentry_tasks[symbol] = asyncio.create_task(self._guardian_loop(symbol))
|
| 196 |
|
|
|
|
| 197 |
print(f"✅ [ENTRY EXECUTED] {symbol} | Price: {current_price:.8f} | TP: {tp_price:.8f} | SL: {sl_price:.8f}")
|
| 198 |
print(f" -> L2 Score: {new_trade['l1_score']:.2f}, L4 Conf: {new_trade['l2_sniper_confidence']:.2f}")
|
| 199 |
|
|
|
|
| 202 |
traceback.print_exc()
|
| 203 |
|
| 204 |
# ==============================================================================
|
| 205 |
+
# 👁️ Watchlist Functions (تم استعادتها بالكامل)
|
| 206 |
# ==============================================================================
|
| 207 |
async def _add_to_watchlist(self, symbol, signal_data):
|
| 208 |
+
"""إضافة عملة لقائمة المراقبة إذا لم يكن الوقت مناسباً بعد"""
|
| 209 |
if symbol not in self.open_positions and symbol not in self.watchlist:
|
| 210 |
if self.open_positions:
|
| 211 |
print(f"👀 [Watchlist] {symbol} تم تجاهله (توجد صفقة أخرى مفتوحة).")
|
|
|
|
| 215 |
print(f"👀 [Watchlist] {symbol} تمت إضافته للمراقبة (L1 Score: {signal_data['enhanced_final_score']:.2f})")
|
| 216 |
|
| 217 |
async def _find_signal_in_watchlist(self):
|
| 218 |
+
"""فحص دوري لقائمة المراقبة لمعرفة ما إذا تحقق شرط القناص"""
|
| 219 |
if not self.watchlist:
|
| 220 |
return
|
| 221 |
|
|
|
|
| 251 |
await self.select_and_execute_best_signal(signals_from_watchlist)
|
| 252 |
|
| 253 |
# ==============================================================================
|
| 254 |
+
# 🛡️ دوال حارس الخروج (Sentry)
|
| 255 |
# ==============================================================================
|
| 256 |
async def _guardian_loop(self, symbol: str):
|
| 257 |
+
print(f"🛡️ [Sentry Activated] بدء الحراسة لـ {symbol} (فحص كل 60 ثانية).")
|
| 258 |
|
| 259 |
while self.running and symbol in self.open_positions:
|
| 260 |
try:
|
|
|
|
| 269 |
print(f"⚠️ [Sentry {symbol}] فشل جلب السعر، إعادة المحاولة...")
|
| 270 |
continue
|
| 271 |
|
| 272 |
+
# [Log Stamp] تأكيد حياة الحارس في السجلات
|
| 273 |
+
# print(f" 🛡️ [Sentry Check] {symbol} Price: {current_price:.8f} | TP: {trade['tp_price']:.8f} | SL: {trade['sl_price']:.8f}")
|
| 274 |
+
|
| 275 |
if current_price >= trade['tp_price']:
|
| 276 |
print(f"✅ [Sentry EXIT] {symbol} (TP Hit) at {current_price:.8f}")
|
| 277 |
async with self.execution_lock:
|
|
|
|
| 284 |
await self._execute_exit(symbol, current_price, "SL_HIT")
|
| 285 |
break
|
| 286 |
|
| 287 |
+
# [L2 Guard Integration]
|
| 288 |
+
if self.guard:
|
| 289 |
+
if not self.guard.initialized:
|
| 290 |
+
try:
|
| 291 |
+
print(f" -> [Lazy Load] 🛡️ تهيئة GuardEngine V2 لـ {symbol}...")
|
| 292 |
+
await self.guard.initialize()
|
| 293 |
+
except Exception as e:
|
| 294 |
+
print(f"❌ [Lazy Load] فشل تهيئة GuardEngine: {e}")
|
| 295 |
+
self.guard = None
|
| 296 |
+
|
| 297 |
+
if self.guard and self.guard.initialized:
|
| 298 |
+
ohlcv_5m = await self.data_manager.get_latest_ohlcv(symbol, '5m', 250)
|
|
|
|
| 299 |
|
| 300 |
+
if len(ohlcv_5m) >= 200:
|
| 301 |
+
# [GEM-Architect Fix] استخدام الدالة Async الجديدة
|
| 302 |
+
exit_check = await self.guard.check_exit_signal_async(ohlcv_5m)
|
| 303 |
+
|
| 304 |
+
if exit_check['action'] == 'EXIT_NOW':
|
| 305 |
+
print(f"🛡️ [Guard V2 SIGNAL] {symbol} أمر بالخروج (Conf: {exit_check['confidence']:.2f})")
|
| 306 |
+
async with self.execution_lock:
|
| 307 |
+
await self._execute_exit(symbol, current_price, "GUARD_V2_SIGNAL")
|
| 308 |
+
break
|
| 309 |
else:
|
| 310 |
+
# print(f"⚠️ [Guard V2 Skip] {symbol} بيانات 5m غير كافية.")
|
| 311 |
pass
|
|
|
|
|
|
|
| 312 |
|
| 313 |
self.open_positions[symbol]['last_update'] = datetime.now().isoformat()
|
| 314 |
|
|
|
|
| 322 |
|
| 323 |
async def _execute_exit(self, symbol, price, reason):
|
| 324 |
if symbol not in self.open_positions:
|
| 325 |
+
print(f"⚠️ [Exit ERROR] {symbol} غير موجودة في الصفقات المفتوحة.")
|
| 326 |
return
|
| 327 |
|
| 328 |
try:
|
|
|
|
| 347 |
except Exception as e:
|
| 348 |
print(f"❌ [TradeManager] فشل فادح أثناء تنفيذ الخروج لـ {symbol}: {e}")
|
| 349 |
traceback.print_exc()
|
| 350 |
+
# إعادة الصفقة للقائمة في حال الفشل لضمان عدم ضياعها
|
| 351 |
if symbol not in self.open_positions:
|
| 352 |
self.open_positions[symbol] = trade
|
| 353 |
|
| 354 |
+
# [GEM-Architect Fix] دالة للخروج القسري من الإدارة (app.py)
|
| 355 |
+
async def force_exit_by_manager(self, symbol, reason):
|
| 356 |
+
"""يسمح لنظام الإدارة الذكي بإجبار الخروج عند تغير التحليل"""
|
| 357 |
+
print(f"⚠️ [Manager Force Exit] طلب خروج إداري لـ {symbol} بسبب: {reason}")
|
| 358 |
+
current_price = await self.data_manager.get_latest_price_async(symbol)
|
| 359 |
+
async with self.execution_lock:
|
| 360 |
+
await self._execute_exit(symbol, current_price, reason)
|
| 361 |
+
|
| 362 |
async def update_trade_targets(self, symbol, new_tp=None, new_sl=None, reason="MANUAL"):
|
| 363 |
if symbol in self.open_positions:
|
| 364 |
trade = self.open_positions[symbol]
|
|
|
|
| 386 |
self.running = False
|
| 387 |
for sym, task in self.sentry_tasks.items():
|
| 388 |
task.cancel()
|
|
|
|
| 389 |
await asyncio.sleep(1)
|
| 390 |
print("🛑 [TradeManager] All sentries stopped.")
|