Spaces:
Paused
Paused
Update trade_manager.py
Browse files- trade_manager.py +9 -36
trade_manager.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# trade_manager.py (V15.
|
| 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 V15.
|
| 26 |
if self.guard:
|
| 27 |
print(f" -> Guard V2 (Exit Protector) CREATED.")
|
| 28 |
else:
|
|
@@ -39,7 +39,6 @@ class TradeManager:
|
|
| 39 |
async def sync_internal_state_with_r2(self):
|
| 40 |
try:
|
| 41 |
open_trades_list = await self.r2.get_open_trades_async()
|
| 42 |
-
# تحويل القائمة إلى قاموس مع تنظيف البيانات
|
| 43 |
self.open_positions = {trade['symbol']: trade for trade in open_trades_list}
|
| 44 |
print(f" -> [Sync] تم استعادة {len(self.open_positions)} صفقة مفتوحة من R2.")
|
| 45 |
except Exception as e:
|
|
@@ -50,13 +49,6 @@ class TradeManager:
|
|
| 50 |
# 🎯 دالة الفرز والتنفيذ
|
| 51 |
# ==============================================================================
|
| 52 |
async def select_and_execute_best_signal(self, oracle_approved_signals: List[Dict[str, Any]]):
|
| 53 |
-
"""
|
| 54 |
-
1. يفحص جميع الإشارات المعتمدة من العقل باستخدام القناص.
|
| 55 |
-
2. يفرزها وينفذ الأفضل.
|
| 56 |
-
3. يتحقق من عدم وجود صفقات مفتوحة قبل البدء.
|
| 57 |
-
"""
|
| 58 |
-
|
| 59 |
-
# [GEM-FIX] تحقق سريع قبل بدء معالجة القناص
|
| 60 |
if len(self.open_positions) > 0:
|
| 61 |
print(f"⛔ [TradeManager] تم إلغاء الفرز. توجد صفقة مفتوحة بالفعل.")
|
| 62 |
return
|
|
@@ -119,7 +111,6 @@ class TradeManager:
|
|
| 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 |
-
# [GEM-FIX] تحقق مزدوج داخل القفل
|
| 123 |
if len(self.open_positions) > 0:
|
| 124 |
print(f"⛔ [TradeManager] تم إلغاء التنفيذ في اللحظة الأخيرة. توجد صفقة مفتوحة.")
|
| 125 |
return
|
|
@@ -131,22 +122,14 @@ class TradeManager:
|
|
| 131 |
await self._execute_entry_from_signal(best_signal['symbol'], best_signal)
|
| 132 |
|
| 133 |
async def _handle_new_signal(self, symbol, signal_data):
|
| 134 |
-
"""
|
| 135 |
-
(Legacy) معالج الإشارات القديم.
|
| 136 |
-
"""
|
| 137 |
print(f"⚠️ [TradeManager] _handle_new_signal (Legacy) called for {symbol}. Redirecting to Batch Select Logic...")
|
| 138 |
await self.select_and_execute_best_signal([signal_data])
|
| 139 |
|
| 140 |
# ==============================================================================
|
| 141 |
-
# 🎯 تنفيذ الدخول (المعدل)
|
| 142 |
# ==============================================================================
|
| 143 |
async def _execute_entry_from_signal(self, symbol, signal_data):
|
| 144 |
-
"""
|
| 145 |
-
تنفيذ عملية الدخول (وهمي حالياً) مع قفل صارم.
|
| 146 |
-
"""
|
| 147 |
-
# ملاحظة: يجب استدعاء هذه الدالة داخل execution_lock من الدالة الأم، ولكن للسلامة نتحقق هنا أيضاً
|
| 148 |
try:
|
| 149 |
-
# [GEM-FIX] قفل صارم جداً
|
| 150 |
if len(self.open_positions) > 0:
|
| 151 |
print(f"⛔ [Entry BLOCKED] لا يمكن فتح {symbol}، توجد صفقة مفتوحة بالفعل.")
|
| 152 |
return
|
|
@@ -154,9 +137,7 @@ class TradeManager:
|
|
| 154 |
trade_id = str(uuid.uuid4())
|
| 155 |
current_price = float(signal_data.get('current_price', 0.0))
|
| 156 |
|
| 157 |
-
# [GEM-FIX] معالجة السعر الصفري
|
| 158 |
if current_price <= 0.0:
|
| 159 |
-
# محاولة طارئة
|
| 160 |
current_price = await self.data_manager.get_latest_price_async(symbol)
|
| 161 |
if current_price <= 0.0:
|
| 162 |
print(f"⚠️ [Entry ERROR] {symbol} السعر 0، لا يمكن التنفيذ.")
|
|
@@ -175,7 +156,6 @@ class TradeManager:
|
|
| 175 |
tp_price = current_price + (atr_mock * 2.0)
|
| 176 |
sl_price = current_price - (atr_mock * 1.0)
|
| 177 |
|
| 178 |
-
# [GEM-FIX] ضمان أن القيم Float
|
| 179 |
tp_price = float(tp_price)
|
| 180 |
sl_price = float(sl_price)
|
| 181 |
|
|
@@ -201,23 +181,21 @@ class TradeManager:
|
|
| 201 |
'l3_oracle_sl': float(signal_data.get('sl_price', 0.0) or 0.0),
|
| 202 |
}
|
| 203 |
|
| 204 |
-
# 1. تحديث الحالة الداخلية
|
| 205 |
self.open_positions[symbol] = new_trade
|
| 206 |
|
| 207 |
if self.watchlist:
|
| 208 |
-
print(f" -> [Watchlist] مسح {len(self.watchlist)} عنصر من قائمة
|
| 209 |
self.watchlist.clear()
|
| 210 |
|
| 211 |
-
# 2. حفظ في R2
|
| 212 |
await self.r2.save_open_trades_async(list(self.open_positions.values()))
|
| 213 |
|
| 214 |
-
# 3. بدء حارس الخروج
|
| 215 |
if symbol in self.sentry_tasks:
|
| 216 |
self.sentry_tasks[symbol].cancel()
|
| 217 |
|
| 218 |
self.sentry_tasks[symbol] = asyncio.create_task(self._guardian_loop(symbol))
|
| 219 |
|
| 220 |
-
|
|
|
|
| 221 |
print(f" -> L2 Score: {new_trade['l1_score']:.2f}, L4 Conf: {new_trade['l2_sniper_confidence']:.2f}")
|
| 222 |
|
| 223 |
except Exception as e:
|
|
@@ -291,13 +269,13 @@ class TradeManager:
|
|
| 291 |
continue
|
| 292 |
|
| 293 |
if current_price >= trade['tp_price']:
|
| 294 |
-
print(f"✅ [Sentry EXIT] {symbol} (TP Hit) at {current_price}")
|
| 295 |
async with self.execution_lock:
|
| 296 |
await self._execute_exit(symbol, current_price, "TP_HIT")
|
| 297 |
break
|
| 298 |
|
| 299 |
if current_price <= trade['sl_price']:
|
| 300 |
-
print(f"🛑 [Sentry EXIT] {symbol} (SL Hit) at {current_price}")
|
| 301 |
async with self.execution_lock:
|
| 302 |
await self._execute_exit(symbol, current_price, "SL_HIT")
|
| 303 |
break
|
|
@@ -352,9 +330,6 @@ class TradeManager:
|
|
| 352 |
profit = (price - trade['entry_price']) / trade['entry_price']
|
| 353 |
trade['profit_pct'] = profit * 100
|
| 354 |
|
| 355 |
-
# await self.r2.archive_closed_trade_async(trade)
|
| 356 |
-
print(" -> [Info] تم تخطي archive_closed_trade_async (غير موجودة في r2.py)")
|
| 357 |
-
|
| 358 |
await self.r2.save_open_trades_async(list(self.open_positions.values()))
|
| 359 |
|
| 360 |
print(f"✅ [EXIT EXECUTED] {symbol} | Reason: {reason} | PnL: {trade['profit_pct']:.2f}%")
|
|
@@ -381,19 +356,17 @@ class TradeManager:
|
|
| 381 |
self.open_positions[symbol] = trade
|
| 382 |
await self.r2.save_open_trades_async(list(self.open_positions.values()))
|
| 383 |
|
| 384 |
-
print(f"🎯 [Targets Updated] {symbol} | TP: {old_tp:.
|
| 385 |
else:
|
| 386 |
print(f"⚠️ [Target Update Failed] {symbol} is not currently open.")
|
| 387 |
|
| 388 |
async def start_sentry_loops(self):
|
| 389 |
-
"""بدء أو استئناف جميع مهام الحراسة"""
|
| 390 |
for symbol in list(self.open_positions.keys()):
|
| 391 |
if symbol not in self.sentry_tasks or self.sentry_tasks[symbol].done():
|
| 392 |
print(f"🛡️ [Sentry Restart] Activating guardian for existing trade: {symbol}")
|
| 393 |
self.sentry_tasks[symbol] = asyncio.create_task(self._guardian_loop(symbol))
|
| 394 |
|
| 395 |
async def stop_sentry_loops(self):
|
| 396 |
-
"""إيقاف نظيف لجميع المهام الخلفية"""
|
| 397 |
print("🛑 [TradeManager] Stopping all sentry loops...")
|
| 398 |
self.running = False
|
| 399 |
for sym, task in self.sentry_tasks.items():
|
|
|
|
| 1 |
+
# trade_manager.py (V15.6 - GEM-Architect Fix: Precision Logging)
|
| 2 |
import asyncio
|
| 3 |
import json
|
| 4 |
import uuid
|
|
|
|
| 22 |
|
| 23 |
self.execution_lock = asyncio.Lock()
|
| 24 |
|
| 25 |
+
print(f"🛡️ [TradeManager V15.6] Sentry Module Initialized (Precision Logs).")
|
| 26 |
if self.guard:
|
| 27 |
print(f" -> Guard V2 (Exit Protector) CREATED.")
|
| 28 |
else:
|
|
|
|
| 39 |
async def sync_internal_state_with_r2(self):
|
| 40 |
try:
|
| 41 |
open_trades_list = await self.r2.get_open_trades_async()
|
|
|
|
| 42 |
self.open_positions = {trade['symbol']: trade for trade in open_trades_list}
|
| 43 |
print(f" -> [Sync] تم استعادة {len(self.open_positions)} صفقة مفتوحة من R2.")
|
| 44 |
except Exception as e:
|
|
|
|
| 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:
|
| 53 |
print(f"⛔ [TradeManager] تم إلغاء الفرز. توجد صفقة مفتوحة بالفعل.")
|
| 54 |
return
|
|
|
|
| 111 |
print(f" -> (خسرت أمامها: {i+2}. {loser['symbol']} (Sniper: {loser['sniper_confidence']:.2f}, L2: {loser['final_total_score']:.2f}))")
|
| 112 |
|
| 113 |
async with self.execution_lock:
|
|
|
|
| 114 |
if len(self.open_positions) > 0:
|
| 115 |
print(f"⛔ [TradeManager] تم إلغاء التنفيذ في اللحظة الأخيرة. توجد صفقة مفتوحة.")
|
| 116 |
return
|
|
|
|
| 122 |
await self._execute_entry_from_signal(best_signal['symbol'], best_signal)
|
| 123 |
|
| 124 |
async def _handle_new_signal(self, symbol, signal_data):
|
|
|
|
|
|
|
|
|
|
| 125 |
print(f"⚠️ [TradeManager] _handle_new_signal (Legacy) called for {symbol}. Redirecting to Batch Select Logic...")
|
| 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:
|
|
|
|
| 133 |
if len(self.open_positions) > 0:
|
| 134 |
print(f"⛔ [Entry BLOCKED] لا يمكن فتح {symbol}، توجد صفقة مفتوحة بالفعل.")
|
| 135 |
return
|
|
|
|
| 137 |
trade_id = str(uuid.uuid4())
|
| 138 |
current_price = float(signal_data.get('current_price', 0.0))
|
| 139 |
|
|
|
|
| 140 |
if current_price <= 0.0:
|
|
|
|
| 141 |
current_price = await self.data_manager.get_latest_price_async(symbol)
|
| 142 |
if current_price <= 0.0:
|
| 143 |
print(f"⚠️ [Entry ERROR] {symbol} السعر 0، لا يمكن التنفيذ.")
|
|
|
|
| 156 |
tp_price = current_price + (atr_mock * 2.0)
|
| 157 |
sl_price = current_price - (atr_mock * 1.0)
|
| 158 |
|
|
|
|
| 159 |
tp_price = float(tp_price)
|
| 160 |
sl_price = float(sl_price)
|
| 161 |
|
|
|
|
| 181 |
'l3_oracle_sl': float(signal_data.get('sl_price', 0.0) or 0.0),
|
| 182 |
}
|
| 183 |
|
|
|
|
| 184 |
self.open_positions[symbol] = new_trade
|
| 185 |
|
| 186 |
if self.watchlist:
|
| 187 |
+
print(f" -> [Watchlist] مسح {len(self.watchlist)} عنصر من قائمة المراقبة.")
|
| 188 |
self.watchlist.clear()
|
| 189 |
|
|
|
|
| 190 |
await self.r2.save_open_trades_async(list(self.open_positions.values()))
|
| 191 |
|
|
|
|
| 192 |
if symbol in self.sentry_tasks:
|
| 193 |
self.sentry_tasks[symbol].cancel()
|
| 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 |
|
| 201 |
except Exception as e:
|
|
|
|
| 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:
|
| 274 |
await self._execute_exit(symbol, current_price, "TP_HIT")
|
| 275 |
break
|
| 276 |
|
| 277 |
if current_price <= trade['sl_price']:
|
| 278 |
+
print(f"🛑 [Sentry EXIT] {symbol} (SL Hit) at {current_price:.8f}")
|
| 279 |
async with self.execution_lock:
|
| 280 |
await self._execute_exit(symbol, current_price, "SL_HIT")
|
| 281 |
break
|
|
|
|
| 330 |
profit = (price - trade['entry_price']) / trade['entry_price']
|
| 331 |
trade['profit_pct'] = profit * 100
|
| 332 |
|
|
|
|
|
|
|
|
|
|
| 333 |
await self.r2.save_open_trades_async(list(self.open_positions.values()))
|
| 334 |
|
| 335 |
print(f"✅ [EXIT EXECUTED] {symbol} | Reason: {reason} | PnL: {trade['profit_pct']:.2f}%")
|
|
|
|
| 356 |
self.open_positions[symbol] = trade
|
| 357 |
await self.r2.save_open_trades_async(list(self.open_positions.values()))
|
| 358 |
|
| 359 |
+
print(f"🎯 [Targets Updated] {symbol} | TP: {old_tp:.8f}->{trade['tp_price']:.8f} | SL: {old_sl:.8f}->{trade['sl_price']:.8f} | Reason: {reason}")
|
| 360 |
else:
|
| 361 |
print(f"⚠️ [Target Update Failed] {symbol} is not currently open.")
|
| 362 |
|
| 363 |
async def start_sentry_loops(self):
|
|
|
|
| 364 |
for symbol in list(self.open_positions.keys()):
|
| 365 |
if symbol not in self.sentry_tasks or self.sentry_tasks[symbol].done():
|
| 366 |
print(f"🛡️ [Sentry Restart] Activating guardian for existing trade: {symbol}")
|
| 367 |
self.sentry_tasks[symbol] = asyncio.create_task(self._guardian_loop(symbol))
|
| 368 |
|
| 369 |
async def stop_sentry_loops(self):
|
|
|
|
| 370 |
print("🛑 [TradeManager] Stopping all sentry loops...")
|
| 371 |
self.running = False
|
| 372 |
for sym, task in self.sentry_tasks.items():
|