Spaces:
Paused
Paused
Update trade_manager.py
Browse files- trade_manager.py +36 -32
trade_manager.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
# ============================================================
|
| 2 |
-
# 🛡️ trade_manager.py (V37.
|
| 3 |
# ============================================================
|
| 4 |
|
| 5 |
import asyncio
|
|
@@ -12,7 +12,7 @@ from typing import List, Dict, Any
|
|
| 12 |
# استيراد المكونات الأساسية
|
| 13 |
from smart_portfolio import SmartPortfolio
|
| 14 |
from ml_engine.processor import SystemLimits
|
| 15 |
-
# ✅ استيراد محرك الحوكمة الجديد
|
| 16 |
from governance_engine import GovernanceEngine
|
| 17 |
|
| 18 |
class TradeManager:
|
|
@@ -45,7 +45,7 @@ class TradeManager:
|
|
| 45 |
}
|
| 46 |
|
| 47 |
self.execution_lock = asyncio.Lock()
|
| 48 |
-
print(f"🛡️ [TradeManager V37.
|
| 49 |
|
| 50 |
async def initialize_sentry_exchanges(self):
|
| 51 |
"""تهيئة المحفظة واستعادة الحالة"""
|
|
@@ -112,7 +112,7 @@ class TradeManager:
|
|
| 112 |
print(f" -> ⚠️ [Skip] {symbol}: Insufficient 1m data.")
|
| 113 |
continue
|
| 114 |
|
| 115 |
-
# فحص Sniper
|
| 116 |
sniper_result = await self.processor.check_sniper_entry(ohlcv_1m, order_book)
|
| 117 |
sniper_signal = sniper_result.get('signal', 'WAIT')
|
| 118 |
final_conf = sniper_result.get('confidence_prob', 0.0)
|
|
@@ -147,7 +147,6 @@ class TradeManager:
|
|
| 147 |
"""تنفيذ الدخول الفعلي مع فحص الحوكمة وإدارة المحفظة"""
|
| 148 |
try:
|
| 149 |
# 🏛️ الخطوة 1: استشارة مجلس الحوكمة (Governance Layer)
|
| 150 |
-
# نحتاج إلى تجميع البيانات المطلوبة للحوكمة (خاصة فريم 15 دقيقة)
|
| 151 |
print(f" 🏛️ [Governance] Convening Senate for {symbol}...")
|
| 152 |
|
| 153 |
t15_task = self.data_manager.get_latest_ohlcv(symbol, '15m', 200)
|
|
@@ -167,12 +166,12 @@ class TradeManager:
|
|
| 167 |
|
| 168 |
print(f" ✅ [Governance PASS] Grade: {gov_decision['grade']} | Score: {gov_decision['governance_score']:.1f}")
|
| 169 |
|
| 170 |
-
# دمج نتائج الحوكمة في بيانات الإشارة
|
| 171 |
signal_data['governance_grade'] = gov_decision['grade']
|
| 172 |
signal_data['governance_score'] = gov_decision['governance_score']
|
| 173 |
signal_data['governance_details'] = gov_decision['components']
|
| 174 |
|
| 175 |
-
# 💰 الخطوة 2: طلب الموافقة من المحفظة الذكية
|
| 176 |
is_approved, plan = await self.smart_portfolio.request_entry_approval(signal_data, len(self.open_positions))
|
| 177 |
|
| 178 |
if not is_approved:
|
|
@@ -196,6 +195,7 @@ class TradeManager:
|
|
| 196 |
'oracle_conf': signal_data.get('confidence', 0),
|
| 197 |
'governance_grade': gov_decision['grade'], # تسجيل الجودة
|
| 198 |
'governance_score': gov_decision['governance_score'],
|
|
|
|
| 199 |
'system_confidence': system_conf,
|
| 200 |
'market_mood': market_mood,
|
| 201 |
'regime_at_entry': getattr(SystemLimits, 'CURRENT_REGIME', 'UNKNOWN')
|
|
@@ -213,13 +213,8 @@ class TradeManager:
|
|
| 213 |
'last_update': datetime.now().isoformat(),
|
| 214 |
'last_oracle_check': datetime.now().isoformat(),
|
| 215 |
'strategy': 'OracleV4_Governance_Hydra',
|
| 216 |
-
'initial_oracle_strength': float(signal_data.get('strength', 0.5)),
|
| 217 |
-
'initial_oracle_class': signal_data.get('target_class', 'TP2'),
|
| 218 |
-
'oracle_tp_map': signal_data.get('tp_map', {}),
|
| 219 |
'entry_capital': approved_size_usd,
|
| 220 |
'entry_fee_usd': entry_fee_usd,
|
| 221 |
-
'l1_score': float(signal_data.get('enhanced_final_score', 0.0)),
|
| 222 |
-
'target_class_int': 3,
|
| 223 |
'decision_data': decision_snapshot,
|
| 224 |
'highest_price': current_price
|
| 225 |
}
|
|
@@ -303,7 +298,7 @@ class TradeManager:
|
|
| 303 |
'volume_30m_usd': vol_30m_sum
|
| 304 |
}
|
| 305 |
|
| 306 |
-
# ✅ استدعاء الحراس
|
| 307 |
decision = self.processor.consult_dual_guardians(symbol, d1, d5, d15, context_data, order_book_snapshot=d_ob)
|
| 308 |
action = decision.get('action', 'HOLD')
|
| 309 |
reason = decision.get('reason', '')
|
|
@@ -322,7 +317,7 @@ class TradeManager:
|
|
| 322 |
last_ai_check_time = time.time()
|
| 323 |
self.open_positions[symbol]['last_update'] = datetime.now().isoformat()
|
| 324 |
|
| 325 |
-
# 3. إعادة فحص Oracle
|
| 326 |
last_oracle = datetime.fromisoformat(trade.get('last_oracle_check', datetime.now().isoformat()))
|
| 327 |
if (datetime.now() - last_oracle).total_seconds() > self.ORACLE_CHECK_INTERVAL:
|
| 328 |
self.open_positions[symbol]['last_oracle_check'] = datetime.now().isoformat()
|
|
@@ -351,7 +346,6 @@ class TradeManager:
|
|
| 351 |
await self.r2.save_open_trades_async(list(self.open_positions.values()))
|
| 352 |
|
| 353 |
async def _consult_oracle_strategy_update(self, symbol, trade):
|
| 354 |
-
"""إعادة استشارة Oracle أثناء الصفقة"""
|
| 355 |
try:
|
| 356 |
tasks = [self.data_manager.get_latest_ohlcv(symbol, tf, limit=100) for tf in ["15m", "1h", "4h"]]
|
| 357 |
results = await asyncio.gather(*tasks)
|
|
@@ -367,13 +361,6 @@ class TradeManager:
|
|
| 367 |
print(f"🚨 [Oracle] Outlook Bearish. Exiting {symbol}...")
|
| 368 |
await self.force_exit_by_manager(symbol, reason="Oracle_Bearish_Flip")
|
| 369 |
return
|
| 370 |
-
|
| 371 |
-
if oracle.get('strength', 0.5) < (trade.get('initial_oracle_strength', 0.5) * 0.6):
|
| 372 |
-
tp_map = trade.get('oracle_tp_map', {})
|
| 373 |
-
cons_tp = tp_map.get('TP1')
|
| 374 |
-
if cons_tp and cons_tp > curr_p and cons_tp < trade['tp_price']:
|
| 375 |
-
print(f"⚠️ [Oracle] Weakening. Lowering TP to {cons_tp}")
|
| 376 |
-
self.open_positions[symbol]['tp_price'] = cons_tp
|
| 377 |
except Exception: pass
|
| 378 |
|
| 379 |
def _launch_post_exit_analysis(self, symbol, exit_price, exit_time, position_size_usd, ai_scores=None, trade_obj=None):
|
|
@@ -398,10 +385,6 @@ class TradeManager:
|
|
| 398 |
is_good_exit = change_pct < 0
|
| 399 |
|
| 400 |
self._update_specific_stat("hybrid", is_good_exit, usd_impact)
|
| 401 |
-
if ai_scores:
|
| 402 |
-
if ai_scores.get('crash', 0) >= 0.60: self._update_specific_stat("crash", is_good_exit, usd_impact)
|
| 403 |
-
if ai_scores.get('giveback', 0) >= 0.70: self._update_specific_stat("giveback", is_good_exit, usd_impact)
|
| 404 |
-
if ai_scores.get('stagnation', 0) >= 0.50: self._update_specific_stat("stagnation", is_good_exit, usd_impact)
|
| 405 |
|
| 406 |
record = {"symbol": symbol, "exit_price": exit_price, "price_15m": curr, "usd_impact": usd_impact, "verdict": "SUCCESS" if is_good_exit else "MISS"}
|
| 407 |
await self.r2.append_deep_steward_audit(record)
|
|
@@ -415,7 +398,7 @@ class TradeManager:
|
|
| 415 |
entry_price = float(trade['entry_price']); exit_price = float(price)
|
| 416 |
entry_capital = float(trade.get('entry_capital', 100.0)); entry_fee = float(trade.get('entry_fee_usd', 0.0))
|
| 417 |
|
| 418 |
-
#
|
| 419 |
exit_val_gross = (exit_price / entry_price) * entry_capital
|
| 420 |
exit_fee = exit_val_gross * self.FEE_RATE
|
| 421 |
total_fees = entry_fee + exit_fee
|
|
@@ -424,7 +407,7 @@ class TradeManager:
|
|
| 424 |
true_net_pnl_usd = gross_pnl_usd - total_fees
|
| 425 |
true_net_pct = (true_net_pnl_usd / entry_capital) * 100
|
| 426 |
|
| 427 |
-
#
|
| 428 |
await self.smart_portfolio.register_closed_position(entry_capital, gross_pnl_usd, total_fees)
|
| 429 |
|
| 430 |
trade.update({
|
|
@@ -451,16 +434,37 @@ class TradeManager:
|
|
| 451 |
|
| 452 |
print(f"✅ [EXIT] {symbol} | Net PnL: {true_net_pct:.2f}% (${true_net_pnl_usd:.2f}) | {reason}")
|
| 453 |
|
| 454 |
-
|
| 455 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
# ==========================================================
|
| 457 |
# 🧠 THE TACTICAL LEARNING LINK
|
| 458 |
# ==========================================================
|
| 459 |
if self.learning_hub:
|
| 460 |
-
print(f"🎓 [Learning] Reporting trade outcome to AdaptiveHub...")
|
| 461 |
asyncio.create_task(self.learning_hub.register_trade_outcome(trade))
|
| 462 |
-
# ==========================================================
|
| 463 |
|
|
|
|
|
|
|
| 464 |
self.latest_guardian_log = f"✅ Closed {symbol} ({reason})"
|
| 465 |
if symbol in self.sentry_tasks: self.sentry_tasks[symbol].cancel(); del self.sentry_tasks[symbol]
|
| 466 |
|
|
|
|
| 1 |
# ============================================================
|
| 2 |
+
# 🛡️ trade_manager.py (V37.1 - GEM-Architect: Governance Data Loop)
|
| 3 |
# ============================================================
|
| 4 |
|
| 5 |
import asyncio
|
|
|
|
| 12 |
# استيراد المكونات الأساسية
|
| 13 |
from smart_portfolio import SmartPortfolio
|
| 14 |
from ml_engine.processor import SystemLimits
|
| 15 |
+
# ✅ استيراد محرك الحوكمة الجديد
|
| 16 |
from governance_engine import GovernanceEngine
|
| 17 |
|
| 18 |
class TradeManager:
|
|
|
|
| 45 |
}
|
| 46 |
|
| 47 |
self.execution_lock = asyncio.Lock()
|
| 48 |
+
print(f"🛡️ [TradeManager V37.1] Full System Online (Governance Learning Loop Active).")
|
| 49 |
|
| 50 |
async def initialize_sentry_exchanges(self):
|
| 51 |
"""تهيئة المحفظة واستعادة الحالة"""
|
|
|
|
| 112 |
print(f" -> ⚠️ [Skip] {symbol}: Insufficient 1m data.")
|
| 113 |
continue
|
| 114 |
|
| 115 |
+
# فحص Sniper
|
| 116 |
sniper_result = await self.processor.check_sniper_entry(ohlcv_1m, order_book)
|
| 117 |
sniper_signal = sniper_result.get('signal', 'WAIT')
|
| 118 |
final_conf = sniper_result.get('confidence_prob', 0.0)
|
|
|
|
| 147 |
"""تنفيذ الدخول الفعلي مع فحص الحوكمة وإدارة المحفظة"""
|
| 148 |
try:
|
| 149 |
# 🏛️ الخطوة 1: استشارة مجلس الحوكمة (Governance Layer)
|
|
|
|
| 150 |
print(f" 🏛️ [Governance] Convening Senate for {symbol}...")
|
| 151 |
|
| 152 |
t15_task = self.data_manager.get_latest_ohlcv(symbol, '15m', 200)
|
|
|
|
| 166 |
|
| 167 |
print(f" ✅ [Governance PASS] Grade: {gov_decision['grade']} | Score: {gov_decision['governance_score']:.1f}")
|
| 168 |
|
| 169 |
+
# دمج نتائج الحوكمة في بيانات الإشارة
|
| 170 |
signal_data['governance_grade'] = gov_decision['grade']
|
| 171 |
signal_data['governance_score'] = gov_decision['governance_score']
|
| 172 |
signal_data['governance_details'] = gov_decision['components']
|
| 173 |
|
| 174 |
+
# 💰 الخطوة 2: طلب الموافقة من المحفظة الذكية
|
| 175 |
is_approved, plan = await self.smart_portfolio.request_entry_approval(signal_data, len(self.open_positions))
|
| 176 |
|
| 177 |
if not is_approved:
|
|
|
|
| 195 |
'oracle_conf': signal_data.get('confidence', 0),
|
| 196 |
'governance_grade': gov_decision['grade'], # تسجيل الجودة
|
| 197 |
'governance_score': gov_decision['governance_score'],
|
| 198 |
+
'governance_details': gov_decision['components'], # تفاصيل الـ 156 مؤشر (مختصرة في المجالات)
|
| 199 |
'system_confidence': system_conf,
|
| 200 |
'market_mood': market_mood,
|
| 201 |
'regime_at_entry': getattr(SystemLimits, 'CURRENT_REGIME', 'UNKNOWN')
|
|
|
|
| 213 |
'last_update': datetime.now().isoformat(),
|
| 214 |
'last_oracle_check': datetime.now().isoformat(),
|
| 215 |
'strategy': 'OracleV4_Governance_Hydra',
|
|
|
|
|
|
|
|
|
|
| 216 |
'entry_capital': approved_size_usd,
|
| 217 |
'entry_fee_usd': entry_fee_usd,
|
|
|
|
|
|
|
| 218 |
'decision_data': decision_snapshot,
|
| 219 |
'highest_price': current_price
|
| 220 |
}
|
|
|
|
| 298 |
'volume_30m_usd': vol_30m_sum
|
| 299 |
}
|
| 300 |
|
| 301 |
+
# ✅ استدعاء الحراس
|
| 302 |
decision = self.processor.consult_dual_guardians(symbol, d1, d5, d15, context_data, order_book_snapshot=d_ob)
|
| 303 |
action = decision.get('action', 'HOLD')
|
| 304 |
reason = decision.get('reason', '')
|
|
|
|
| 317 |
last_ai_check_time = time.time()
|
| 318 |
self.open_positions[symbol]['last_update'] = datetime.now().isoformat()
|
| 319 |
|
| 320 |
+
# 3. إعادة فحص Oracle
|
| 321 |
last_oracle = datetime.fromisoformat(trade.get('last_oracle_check', datetime.now().isoformat()))
|
| 322 |
if (datetime.now() - last_oracle).total_seconds() > self.ORACLE_CHECK_INTERVAL:
|
| 323 |
self.open_positions[symbol]['last_oracle_check'] = datetime.now().isoformat()
|
|
|
|
| 346 |
await self.r2.save_open_trades_async(list(self.open_positions.values()))
|
| 347 |
|
| 348 |
async def _consult_oracle_strategy_update(self, symbol, trade):
|
|
|
|
| 349 |
try:
|
| 350 |
tasks = [self.data_manager.get_latest_ohlcv(symbol, tf, limit=100) for tf in ["15m", "1h", "4h"]]
|
| 351 |
results = await asyncio.gather(*tasks)
|
|
|
|
| 361 |
print(f"🚨 [Oracle] Outlook Bearish. Exiting {symbol}...")
|
| 362 |
await self.force_exit_by_manager(symbol, reason="Oracle_Bearish_Flip")
|
| 363 |
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 364 |
except Exception: pass
|
| 365 |
|
| 366 |
def _launch_post_exit_analysis(self, symbol, exit_price, exit_time, position_size_usd, ai_scores=None, trade_obj=None):
|
|
|
|
| 385 |
is_good_exit = change_pct < 0
|
| 386 |
|
| 387 |
self._update_specific_stat("hybrid", is_good_exit, usd_impact)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
|
| 389 |
record = {"symbol": symbol, "exit_price": exit_price, "price_15m": curr, "usd_impact": usd_impact, "verdict": "SUCCESS" if is_good_exit else "MISS"}
|
| 390 |
await self.r2.append_deep_steward_audit(record)
|
|
|
|
| 398 |
entry_price = float(trade['entry_price']); exit_price = float(price)
|
| 399 |
entry_capital = float(trade.get('entry_capital', 100.0)); entry_fee = float(trade.get('entry_fee_usd', 0.0))
|
| 400 |
|
| 401 |
+
# حساب الأرباح
|
| 402 |
exit_val_gross = (exit_price / entry_price) * entry_capital
|
| 403 |
exit_fee = exit_val_gross * self.FEE_RATE
|
| 404 |
total_fees = entry_fee + exit_fee
|
|
|
|
| 407 |
true_net_pnl_usd = gross_pnl_usd - total_fees
|
| 408 |
true_net_pct = (true_net_pnl_usd / entry_capital) * 100
|
| 409 |
|
| 410 |
+
# تحديث المحفظة
|
| 411 |
await self.smart_portfolio.register_closed_position(entry_capital, gross_pnl_usd, total_fees)
|
| 412 |
|
| 413 |
trade.update({
|
|
|
|
| 434 |
|
| 435 |
print(f"✅ [EXIT] {symbol} | Net PnL: {true_net_pct:.2f}% (${true_net_pnl_usd:.2f}) | {reason}")
|
| 436 |
|
| 437 |
+
# ==========================================================
|
| 438 |
+
# 🏛️ إرسال البيانات لملف تدريب الحوكمة (Governance Training Data)
|
| 439 |
+
# ==========================================================
|
| 440 |
+
try:
|
| 441 |
+
decision_data = trade.get('decision_data', {})
|
| 442 |
+
if 'governance_grade' in decision_data:
|
| 443 |
+
training_record = {
|
| 444 |
+
"symbol": symbol,
|
| 445 |
+
"entry_time": trade['entry_time'],
|
| 446 |
+
"exit_time": trade['exit_time'],
|
| 447 |
+
"governance_grade": decision_data['governance_grade'],
|
| 448 |
+
"governance_score": decision_data.get('governance_score', 0),
|
| 449 |
+
"governance_components": decision_data.get('governance_details', {}), # تفاصيل الـ 156 مؤشر
|
| 450 |
+
"entry_price": trade['entry_price'],
|
| 451 |
+
"exit_price": trade['exit_price'],
|
| 452 |
+
"profit_pct": true_net_pct,
|
| 453 |
+
"result": trade['result']
|
| 454 |
+
}
|
| 455 |
+
# إرسال إلى R2 في الخلفية
|
| 456 |
+
asyncio.create_task(self.r2.append_governance_training_data(training_record))
|
| 457 |
+
except Exception as ge:
|
| 458 |
+
print(f"⚠️ [Learning Error] Failed to save governance training data: {ge}")
|
| 459 |
+
|
| 460 |
# ==========================================================
|
| 461 |
# 🧠 THE TACTICAL LEARNING LINK
|
| 462 |
# ==========================================================
|
| 463 |
if self.learning_hub:
|
|
|
|
| 464 |
asyncio.create_task(self.learning_hub.register_trade_outcome(trade))
|
|
|
|
| 465 |
|
| 466 |
+
self._launch_post_exit_analysis(symbol, exit_price, trade.get('exit_time'), entry_capital, ai_scores, trade)
|
| 467 |
+
|
| 468 |
self.latest_guardian_log = f"✅ Closed {symbol} ({reason})"
|
| 469 |
if symbol in self.sentry_tasks: self.sentry_tasks[symbol].cancel(); del self.sentry_tasks[symbol]
|
| 470 |
|