Riy777 commited on
Commit
3ce5528
·
verified ·
1 Parent(s): 706140f

Update smart_portfolio.py

Browse files
Files changed (1) hide show
  1. smart_portfolio.py +14 -11
smart_portfolio.py CHANGED
@@ -1,5 +1,5 @@
1
  # ==============================================================================
2
- # 💼 smart_portfolio.py (V37.0 - GEM-Architect: Grade-Based Sizing)
3
  # ==============================================================================
4
 
5
  import asyncio
@@ -46,7 +46,7 @@ class SmartPortfolio:
46
  "halt_reason": None
47
  }
48
 
49
- print("💼 [SmartPortfolio V37.0] Grade-Based Sizing System Initialized.")
50
 
51
  async def initialize(self):
52
  await self._sync_state_from_r2()
@@ -76,11 +76,12 @@ class SmartPortfolio:
76
  await asyncio.sleep(60)
77
 
78
  # ==============================================================================
79
- # 🧠 Core Logic: Entry Approval (Grade-Based)
80
  # ==============================================================================
81
  async def request_entry_approval(self, signal_data: Dict[str, Any], open_positions_count: int) -> Tuple[bool, Dict[str, Any]]:
82
  """
83
  تطلب الموافقة وتحدد الحجم بناءً على جودة الحوكمة (Grade).
 
84
  """
85
  async with self.capital_lock:
86
  # 1. Circuit Breaker
@@ -106,12 +107,13 @@ class SmartPortfolio:
106
  return False, {"reason": f"Governance Rejected (Score: {gov_score})"}
107
 
108
  # 4. Regime-Based Slots
109
- regime = getattr(SystemLimits, 'CURRENT_REGIME', 'RANGE')
 
110
 
111
  if regime == "BULL": max_slots = 6
112
  elif regime == "BEAR": max_slots = 3
113
  elif regime == "DEAD": max_slots = 2
114
- else: max_slots = 4
115
 
116
  if current_cap < self.MIN_CAPITAL_FOR_SPLIT: max_slots = min(max_slots, 2)
117
 
@@ -126,9 +128,6 @@ class SmartPortfolio:
126
  return False, {"reason": f"Insufficient Free Capital (${free_capital:.2f})"}
127
 
128
  # ✅ 6. Position Sizing (Grade Logic)
129
- # القاعدة: الحصة الكاملة = الكابيتال / عدد الخانات.
130
- # الجودة تحدد كم نأخذ من هذه الحصة.
131
-
132
  target_slot_size = 0.0
133
  if current_cap >= self.MIN_CAPITAL_FOR_SPLIT:
134
  target_slot_size = current_cap / max_slots
@@ -151,17 +150,21 @@ class SmartPortfolio:
151
  if free_capital >= 5.0: final_size_usd = 5.0
152
  else: return False, {"reason": "Calculated size too small"}
153
 
154
- # 7. Dynamic TP Selection
 
155
  entry_price = float(signal_data.get('sniper_entry_price') or signal_data.get('current_price'))
156
  tp_map = signal_data.get('tp_map', {})
157
 
158
  if regime == "BULL" and gov_grade in ["STRONG", "ULTRA"]:
 
159
  selected_tp = tp_map.get('TP3') or tp_map.get('TP4')
160
  target_label = "TP3/4 (Bull Run)"
161
- elif regime == "BEAR":
 
162
  selected_tp = tp_map.get('TP1')
163
- target_label = "TP1 (Scalp)"
164
  else:
 
165
  selected_tp = tp_map.get('TP2')
166
  target_label = "TP2"
167
 
 
1
  # ==============================================================================
2
+ # 💼 smart_portfolio.py (V37.2 - GEM-Architect: Regime-Aware Targeting)
3
  # ==============================================================================
4
 
5
  import asyncio
 
46
  "halt_reason": None
47
  }
48
 
49
+ print("💼 [SmartPortfolio V37.2] Regime-Aware Sizing & Targeting Initialized.")
50
 
51
  async def initialize(self):
52
  await self._sync_state_from_r2()
 
76
  await asyncio.sleep(60)
77
 
78
  # ==============================================================================
79
+ # 🧠 Core Logic: Entry Approval (Grade-Based + Regime-Aware TP)
80
  # ==============================================================================
81
  async def request_entry_approval(self, signal_data: Dict[str, Any], open_positions_count: int) -> Tuple[bool, Dict[str, Any]]:
82
  """
83
  تطلب الموافقة وتحدد الحجم بناءً على جودة الحوكمة (Grade).
84
+ وتحدد الهدف (TP) بناءً على الريجيم الحالي (Context).
85
  """
86
  async with self.capital_lock:
87
  # 1. Circuit Breaker
 
107
  return False, {"reason": f"Governance Rejected (Score: {gov_score})"}
108
 
109
  # 4. Regime-Based Slots
110
+ # محاولة استخراج الريجيم من الإشارة نفسها (الأدق) أو العودة للنظام العام
111
+ regime = signal_data.get('asset_regime', getattr(SystemLimits, 'CURRENT_REGIME', 'RANGE'))
112
 
113
  if regime == "BULL": max_slots = 6
114
  elif regime == "BEAR": max_slots = 3
115
  elif regime == "DEAD": max_slots = 2
116
+ else: max_slots = 4 # RANGE
117
 
118
  if current_cap < self.MIN_CAPITAL_FOR_SPLIT: max_slots = min(max_slots, 2)
119
 
 
128
  return False, {"reason": f"Insufficient Free Capital (${free_capital:.2f})"}
129
 
130
  # ✅ 6. Position Sizing (Grade Logic)
 
 
 
131
  target_slot_size = 0.0
132
  if current_cap >= self.MIN_CAPITAL_FOR_SPLIT:
133
  target_slot_size = current_cap / max_slots
 
150
  if free_capital >= 5.0: final_size_usd = 5.0
151
  else: return False, {"reason": "Calculated size too small"}
152
 
153
+ # 7. Dynamic TP Selection (The Fix)
154
+ # إصلاح المنطق: في أسواق Range/Dead/Bear، نلتزم بـ TP1 لضمان الخروج بربح.
155
  entry_price = float(signal_data.get('sniper_entry_price') or signal_data.get('current_price'))
156
  tp_map = signal_data.get('tp_map', {})
157
 
158
  if regime == "BULL" and gov_grade in ["STRONG", "ULTRA"]:
159
+ # فقط في البول رن القوي نستهدف الأهداف البعيدة
160
  selected_tp = tp_map.get('TP3') or tp_map.get('TP4')
161
  target_label = "TP3/4 (Bull Run)"
162
+ elif regime in ["RANGE", "DEAD", "BEAR"]:
163
+ # في الأسواق العرضية والميتة والهابطة، نأخذ أول هدف ونخرج
164
  selected_tp = tp_map.get('TP1')
165
+ target_label = f"TP1 ({regime} Scalp)"
166
  else:
167
+ # الحالة الطبيعية
168
  selected_tp = tp_map.get('TP2')
169
  target_label = "TP2"
170