Update learning_engine.py
Browse files- learning_engine.py +134 -22
learning_engine.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
|
|
| 1 |
import os, json, asyncio
|
| 2 |
from datetime import datetime
|
| 3 |
from helpers import normalize_weights, calculate_market_volatility, should_update_weights
|
|
|
|
| 4 |
|
| 5 |
class LearningEngine:
|
| 6 |
def __init__(self, r2_service, data_manager):
|
|
@@ -8,7 +10,8 @@ class LearningEngine:
|
|
| 8 |
self.data_manager = data_manager
|
| 9 |
self.weights = {}
|
| 10 |
self.performance_history = []
|
| 11 |
-
self.strategy_effectiveness = {}
|
|
|
|
| 12 |
self.market_patterns = {}
|
| 13 |
self.risk_profiles = {}
|
| 14 |
self.initialized = False
|
|
@@ -21,8 +24,10 @@ class LearningEngine:
|
|
| 21 |
try:
|
| 22 |
await self.load_weights_from_r2()
|
| 23 |
await self.load_performance_history()
|
|
|
|
|
|
|
| 24 |
self.initialized = True
|
| 25 |
-
print("Learning system ready")
|
| 26 |
except Exception as e:
|
| 27 |
print(f"Weights loading failed: {e}")
|
| 28 |
await self.initialize_default_weights()
|
|
@@ -35,6 +40,8 @@ class LearningEngine:
|
|
| 35 |
try:
|
| 36 |
await self.load_weights_from_r2()
|
| 37 |
await self.load_performance_history()
|
|
|
|
|
|
|
| 38 |
await self.fix_weights_structure()
|
| 39 |
if not self.performance_history:
|
| 40 |
print("Starting learning from scratch")
|
|
@@ -87,6 +94,8 @@ class LearningEngine:
|
|
| 87 |
"sideways_market": {"mean_reversion": 0.30, "volume_spike": 0.20, "pattern_recognition": 0.15}
|
| 88 |
}
|
| 89 |
}
|
|
|
|
|
|
|
| 90 |
|
| 91 |
async def load_weights_from_r2(self):
|
| 92 |
try:
|
|
@@ -124,6 +133,32 @@ class LearningEngine:
|
|
| 124 |
except Exception as e:
|
| 125 |
print(f"Weights saving failed: {e}")
|
| 126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
async def load_performance_history(self):
|
| 128 |
try:
|
| 129 |
key = "learning_performance_history.json"
|
|
@@ -157,6 +192,10 @@ class LearningEngine:
|
|
| 157 |
decision_data = trade_data.get('decision_data', {})
|
| 158 |
strategy = decision_data.get('strategy', 'unknown')
|
| 159 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
market_context = await self.get_current_market_conditions()
|
| 161 |
|
| 162 |
analysis_entry = {
|
|
@@ -165,6 +204,7 @@ class LearningEngine:
|
|
| 165 |
"outcome": outcome,
|
| 166 |
"market_conditions": market_context,
|
| 167 |
"strategy_used": strategy,
|
|
|
|
| 168 |
"symbol": trade_data.get('symbol', 'unknown'),
|
| 169 |
"pnl_usd": trade_data.get('pnl_usd', 0),
|
| 170 |
"pnl_percent": trade_data.get('pnl_percent', 0)
|
|
@@ -178,17 +218,23 @@ class LearningEngine:
|
|
| 178 |
await self.adapt_weights_based_on_performance()
|
| 179 |
await self.save_weights_to_r2()
|
| 180 |
await self.save_performance_history()
|
|
|
|
|
|
|
| 181 |
|
| 182 |
-
print(f"Trade analyzed {trade_data.get('symbol')} - Strategy: {strategy} - Outcome: {outcome}")
|
| 183 |
except Exception as e:
|
| 184 |
print(f"Trade outcome analysis failed: {e}")
|
| 185 |
|
| 186 |
async def update_strategy_effectiveness(self, analysis_entry):
|
| 187 |
strategy = analysis_entry['strategy_used']
|
|
|
|
|
|
|
|
|
|
| 188 |
outcome = analysis_entry['outcome']
|
| 189 |
market_condition = analysis_entry['market_conditions']['current_trend']
|
| 190 |
pnl_percent = analysis_entry.get('pnl_percent', 0)
|
| 191 |
|
|
|
|
| 192 |
if strategy not in self.strategy_effectiveness:
|
| 193 |
self.strategy_effectiveness[strategy] = {
|
| 194 |
"total_trades": 0, "successful_trades": 0, "total_profit": 0,
|
|
@@ -209,8 +255,27 @@ class LearningEngine:
|
|
| 209 |
self.strategy_effectiveness[strategy]["market_conditions"][market_condition]["trades"] += 1
|
| 210 |
self.strategy_effectiveness[strategy]["market_conditions"][market_condition]["total_pnl"] += pnl_percent
|
| 211 |
if is_success: self.strategy_effectiveness[strategy]["market_conditions"][market_condition]["successes"] += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
|
| 213 |
async def update_market_patterns(self, analysis_entry):
|
|
|
|
| 214 |
market_condition = analysis_entry['market_conditions']['current_trend']
|
| 215 |
symbol = analysis_entry['symbol']
|
| 216 |
outcome = analysis_entry['outcome']
|
|
@@ -246,6 +311,7 @@ class LearningEngine:
|
|
| 246 |
self.market_patterns[market_condition]["best_performing_symbols"][symbol]["total_pnl"] += pnl_percent
|
| 247 |
|
| 248 |
async def adapt_weights_based_on_performance(self):
|
|
|
|
| 249 |
print("Updating weights based on performance...")
|
| 250 |
try:
|
| 251 |
if not self.strategy_effectiveness:
|
|
@@ -279,6 +345,7 @@ class LearningEngine:
|
|
| 279 |
await self.gradual_weights_adjustment()
|
| 280 |
|
| 281 |
async def gradual_weights_adjustment(self):
|
|
|
|
| 282 |
print("Gradual weights adjustment...")
|
| 283 |
if self.market_patterns:
|
| 284 |
for market_condition, data in self.market_patterns.items():
|
|
@@ -291,6 +358,40 @@ class LearningEngine:
|
|
| 291 |
|
| 292 |
normalize_weights(self.weights["strategy_weights"])
|
| 293 |
print("Gradual weights adjustment completed")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
|
| 295 |
async def get_current_market_conditions(self):
|
| 296 |
try:
|
|
@@ -331,6 +432,17 @@ class LearningEngine:
|
|
| 331 |
"total_trades": data["total_trades"], "successful_trades": data["successful_trades"]
|
| 332 |
}
|
| 333 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 334 |
market_performance = {}
|
| 335 |
for condition, data in self.market_patterns.items():
|
| 336 |
if data["total_trades"] > 0:
|
|
@@ -344,7 +456,9 @@ class LearningEngine:
|
|
| 344 |
return {
|
| 345 |
"overall_success_rate": success_rate, "overall_avg_pnl_percent": avg_pnl,
|
| 346 |
"total_analyzed_trades": len(self.performance_history), "recent_trades_analyzed": total_trades,
|
| 347 |
-
"strategy_performance": strategy_performance,
|
|
|
|
|
|
|
| 348 |
"last_updated": datetime.now().isoformat()
|
| 349 |
}
|
| 350 |
|
|
@@ -388,6 +502,7 @@ class LearningEngine:
|
|
| 388 |
improvements.append("Start collecting performance data from first trades")
|
| 389 |
return improvements
|
| 390 |
|
|
|
|
| 391 |
for strategy, data in self.strategy_effectiveness.items():
|
| 392 |
if data["total_trades"] >= 3:
|
| 393 |
success_rate = data["successful_trades"] / data["total_trades"]
|
|
@@ -396,27 +511,23 @@ class LearningEngine:
|
|
| 396 |
improvements.append(f"Strategy {strategy} poor performance ({success_rate:.1%} success, {avg_pnl:+.1f}% average) - suggest reducing usage")
|
| 397 |
elif success_rate > 0.6 and avg_pnl > 2:
|
| 398 |
improvements.append(f"Strategy {strategy} excellent performance ({success_rate:.1%} success, {avg_pnl:+.1f}% average) - suggest increasing usage")
|
| 399 |
-
elif success_rate > 0.7:
|
| 400 |
-
improvements.append(f"Strategy {strategy} high success ({success_rate:.1%}) - focus on trade quality")
|
| 401 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 402 |
for market_condition, data in self.market_patterns.items():
|
|
|
|
| 403 |
if data["total_trades"] >= 5:
|
| 404 |
success_rate = data["successful_trades"] / data["total_trades"]
|
| 405 |
-
avg_pnl = data["total_pnl_percent"] / data["total_trades"]
|
| 406 |
if success_rate < 0.4:
|
| 407 |
improvements.append(f"Poor performance in {market_condition} market ({success_rate:.1%} success) - needs strategy review")
|
| 408 |
-
|
| 409 |
-
best_strategy = None
|
| 410 |
-
best_performance = -100
|
| 411 |
-
for strategy, stats in data["best_performing_strategies"].items():
|
| 412 |
-
if stats["count"] >= 2:
|
| 413 |
-
strategy_avg_pnl = stats["total_pnl"] / stats["count"]
|
| 414 |
-
if strategy_avg_pnl > best_performance:
|
| 415 |
-
best_performance = strategy_avg_pnl
|
| 416 |
-
best_strategy = strategy
|
| 417 |
-
|
| 418 |
-
if best_strategy and best_performance > 1:
|
| 419 |
-
improvements.append(f"Best strategy in {market_condition}: {best_strategy} ({best_performance:+.1f}% average profit)")
|
| 420 |
|
| 421 |
if not improvements: improvements.append("No suggested improvements currently - continue data collection")
|
| 422 |
return improvements
|
|
@@ -427,10 +538,11 @@ class LearningEngine:
|
|
| 427 |
print("No performance data to learn from")
|
| 428 |
return
|
| 429 |
for entry in self.performance_history:
|
| 430 |
-
await self.update_strategy_effectiveness(entry)
|
| 431 |
await self.update_market_patterns(entry)
|
| 432 |
await self.adapt_weights_based_on_performance()
|
| 433 |
await self.save_weights_to_r2()
|
| 434 |
-
|
|
|
|
| 435 |
|
| 436 |
-
print("Enhanced self-learning system loaded -
|
|
|
|
| 1 |
+
# learning_engine (37).py (محدث بالكامل مع تعلم ملف الخروج)
|
| 2 |
import os, json, asyncio
|
| 3 |
from datetime import datetime
|
| 4 |
from helpers import normalize_weights, calculate_market_volatility, should_update_weights
|
| 5 |
+
import numpy as np # نحتاج numpy لحساب المتوسطات
|
| 6 |
|
| 7 |
class LearningEngine:
|
| 8 |
def __init__(self, r2_service, data_manager):
|
|
|
|
| 10 |
self.data_manager = data_manager
|
| 11 |
self.weights = {}
|
| 12 |
self.performance_history = []
|
| 13 |
+
self.strategy_effectiveness = {} # 🔴 لتعلم استراتيجيات الدخول
|
| 14 |
+
self.exit_profile_effectiveness = {} # 🔴 جديد: لتعلم (الدخول + الخروج)
|
| 15 |
self.market_patterns = {}
|
| 16 |
self.risk_profiles = {}
|
| 17 |
self.initialized = False
|
|
|
|
| 24 |
try:
|
| 25 |
await self.load_weights_from_r2()
|
| 26 |
await self.load_performance_history()
|
| 27 |
+
# 🔴 جديد: تحميل أداء ملفات الخروج
|
| 28 |
+
await self.load_exit_profile_effectiveness()
|
| 29 |
self.initialized = True
|
| 30 |
+
print("Learning system ready (with Exit Profile learning)")
|
| 31 |
except Exception as e:
|
| 32 |
print(f"Weights loading failed: {e}")
|
| 33 |
await self.initialize_default_weights()
|
|
|
|
| 40 |
try:
|
| 41 |
await self.load_weights_from_r2()
|
| 42 |
await self.load_performance_history()
|
| 43 |
+
# 🔴 جديد: تحميل أداء ملفات الخروج
|
| 44 |
+
await self.load_exit_profile_effectiveness()
|
| 45 |
await self.fix_weights_structure()
|
| 46 |
if not self.performance_history:
|
| 47 |
print("Starting learning from scratch")
|
|
|
|
| 94 |
"sideways_market": {"mean_reversion": 0.30, "volume_spike": 0.20, "pattern_recognition": 0.15}
|
| 95 |
}
|
| 96 |
}
|
| 97 |
+
# 🔴 جديد: تهيئة افتراضية لملفات الخروج
|
| 98 |
+
self.exit_profile_effectiveness = {}
|
| 99 |
|
| 100 |
async def load_weights_from_r2(self):
|
| 101 |
try:
|
|
|
|
| 133 |
except Exception as e:
|
| 134 |
print(f"Weights saving failed: {e}")
|
| 135 |
|
| 136 |
+
# 🔴 جديد: تحميل وحفظ أداء ملف الخروج
|
| 137 |
+
async def load_exit_profile_effectiveness(self):
|
| 138 |
+
try:
|
| 139 |
+
key = "learning_exit_profile_effectiveness.json"
|
| 140 |
+
response = self.r2_service.s3_client.get_object(Bucket="trading", Key=key)
|
| 141 |
+
data = json.loads(response['Body'].read())
|
| 142 |
+
self.exit_profile_effectiveness = data.get("effectiveness", {})
|
| 143 |
+
print(f"Exit profile effectiveness loaded - {len(self.exit_profile_effectiveness)} combinations")
|
| 144 |
+
except Exception as e:
|
| 145 |
+
print(f"Exit profile effectiveness loading failed: {e}")
|
| 146 |
+
self.exit_profile_effectiveness = {}
|
| 147 |
+
|
| 148 |
+
async def save_exit_profile_effectiveness(self):
|
| 149 |
+
try:
|
| 150 |
+
key = "learning_exit_profile_effectiveness.json"
|
| 151 |
+
data = {
|
| 152 |
+
"effectiveness": self.exit_profile_effectiveness,
|
| 153 |
+
"last_updated": datetime.now().isoformat()
|
| 154 |
+
}
|
| 155 |
+
data_json = json.dumps(data, indent=2, ensure_ascii=False).encode('utf-8')
|
| 156 |
+
self.r2_service.s3_client.put_object(
|
| 157 |
+
Bucket="trading", Key=key, Body=data_json, ContentType="application/json"
|
| 158 |
+
)
|
| 159 |
+
except Exception as e:
|
| 160 |
+
print(f"Exit profile effectiveness saving failed: {e}")
|
| 161 |
+
|
| 162 |
async def load_performance_history(self):
|
| 163 |
try:
|
| 164 |
key = "learning_performance_history.json"
|
|
|
|
| 192 |
decision_data = trade_data.get('decision_data', {})
|
| 193 |
strategy = decision_data.get('strategy', 'unknown')
|
| 194 |
|
| 195 |
+
# 🔴 جديد: استخراج ملف الخروج
|
| 196 |
+
decision_data = trade_data.get('decision_data', {})
|
| 197 |
+
exit_profile = decision_data.get('exit_profile', 'unknown')
|
| 198 |
+
|
| 199 |
market_context = await self.get_current_market_conditions()
|
| 200 |
|
| 201 |
analysis_entry = {
|
|
|
|
| 204 |
"outcome": outcome,
|
| 205 |
"market_conditions": market_context,
|
| 206 |
"strategy_used": strategy,
|
| 207 |
+
"exit_profile_used": exit_profile, # 🔴 جديد
|
| 208 |
"symbol": trade_data.get('symbol', 'unknown'),
|
| 209 |
"pnl_usd": trade_data.get('pnl_usd', 0),
|
| 210 |
"pnl_percent": trade_data.get('pnl_percent', 0)
|
|
|
|
| 218 |
await self.adapt_weights_based_on_performance()
|
| 219 |
await self.save_weights_to_r2()
|
| 220 |
await self.save_performance_history()
|
| 221 |
+
# 🔴 جديد: حفظ أداء ملف الخروج
|
| 222 |
+
await self.save_exit_profile_effectiveness()
|
| 223 |
|
| 224 |
+
print(f"Trade analyzed {trade_data.get('symbol')} - Strategy: {strategy} - Exit: {exit_profile} - Outcome: {outcome}")
|
| 225 |
except Exception as e:
|
| 226 |
print(f"Trade outcome analysis failed: {e}")
|
| 227 |
|
| 228 |
async def update_strategy_effectiveness(self, analysis_entry):
|
| 229 |
strategy = analysis_entry['strategy_used']
|
| 230 |
+
exit_profile = analysis_entry['exit_profile_used'] # 🔴 جديد
|
| 231 |
+
combined_key = f"{strategy}_{exit_profile}" # 🔴 جديد
|
| 232 |
+
|
| 233 |
outcome = analysis_entry['outcome']
|
| 234 |
market_condition = analysis_entry['market_conditions']['current_trend']
|
| 235 |
pnl_percent = analysis_entry.get('pnl_percent', 0)
|
| 236 |
|
| 237 |
+
# --- 1. تحديث أداء استراتيجية الدخول (كما كان) ---
|
| 238 |
if strategy not in self.strategy_effectiveness:
|
| 239 |
self.strategy_effectiveness[strategy] = {
|
| 240 |
"total_trades": 0, "successful_trades": 0, "total_profit": 0,
|
|
|
|
| 255 |
self.strategy_effectiveness[strategy]["market_conditions"][market_condition]["trades"] += 1
|
| 256 |
self.strategy_effectiveness[strategy]["market_conditions"][market_condition]["total_pnl"] += pnl_percent
|
| 257 |
if is_success: self.strategy_effectiveness[strategy]["market_conditions"][market_condition]["successes"] += 1
|
| 258 |
+
|
| 259 |
+
# --- 2. 🔴 جديد: تحديث أداء مزيج (الدخول + الخروج) ---
|
| 260 |
+
if combined_key not in self.exit_profile_effectiveness:
|
| 261 |
+
self.exit_profile_effectiveness[combined_key] = {
|
| 262 |
+
"total_trades": 0, "successful_trades": 0,
|
| 263 |
+
"total_pnl_percent": 0, "pnl_list": [] # لتتبع المتوسط والانحراف
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
self.exit_profile_effectiveness[combined_key]["total_trades"] += 1
|
| 267 |
+
self.exit_profile_effectiveness[combined_key]["total_pnl_percent"] += pnl_percent
|
| 268 |
+
self.exit_profile_effectiveness[combined_key]["pnl_list"].append(pnl_percent)
|
| 269 |
+
# الحفاظ على آخر 100 نتيجة فقط
|
| 270 |
+
if len(self.exit_profile_effectiveness[combined_key]["pnl_list"]) > 100:
|
| 271 |
+
self.exit_profile_effectiveness[combined_key]["pnl_list"] = self.exit_profile_effectiveness[combined_key]["pnl_list"][-100:]
|
| 272 |
+
|
| 273 |
+
if is_success:
|
| 274 |
+
self.exit_profile_effectiveness[combined_key]["successful_trades"] += 1
|
| 275 |
+
|
| 276 |
|
| 277 |
async def update_market_patterns(self, analysis_entry):
|
| 278 |
+
# ... (هذه الدالة تبقى كما هي، لا تحتاج تعديل)
|
| 279 |
market_condition = analysis_entry['market_conditions']['current_trend']
|
| 280 |
symbol = analysis_entry['symbol']
|
| 281 |
outcome = analysis_entry['outcome']
|
|
|
|
| 311 |
self.market_patterns[market_condition]["best_performing_symbols"][symbol]["total_pnl"] += pnl_percent
|
| 312 |
|
| 313 |
async def adapt_weights_based_on_performance(self):
|
| 314 |
+
# ... (هذه الدالة تبقى كما هي، لتعديل أوزان *الدخول* فقط)
|
| 315 |
print("Updating weights based on performance...")
|
| 316 |
try:
|
| 317 |
if not self.strategy_effectiveness:
|
|
|
|
| 345 |
await self.gradual_weights_adjustment()
|
| 346 |
|
| 347 |
async def gradual_weights_adjustment(self):
|
| 348 |
+
# ... (هذه الدالة تبقى كما هي)
|
| 349 |
print("Gradual weights adjustment...")
|
| 350 |
if self.market_patterns:
|
| 351 |
for market_condition, data in self.market_patterns.items():
|
|
|
|
| 358 |
|
| 359 |
normalize_weights(self.weights["strategy_weights"])
|
| 360 |
print("Gradual weights adjustment completed")
|
| 361 |
+
|
| 362 |
+
# 🔴 جديد: دالة التغذية الراجعة لـ LLM
|
| 363 |
+
async def get_best_exit_profile(self, entry_strategy: str) -> str:
|
| 364 |
+
"""
|
| 365 |
+
يجد أفضل ملف خروج (Exit Profile) لاستراتيجية دخول معينة
|
| 366 |
+
بناءً على متوسط الربح/الخسارة (avg_pnl_percent).
|
| 367 |
+
"""
|
| 368 |
+
if not self.initialized or not self.exit_profile_effectiveness:
|
| 369 |
+
return "unknown"
|
| 370 |
+
|
| 371 |
+
relevant_profiles = {}
|
| 372 |
+
|
| 373 |
+
for combined_key, data in self.exit_profile_effectiveness.items():
|
| 374 |
+
if combined_key.startswith(f"{entry_strategy}_"):
|
| 375 |
+
# يتطلب 3 صفقات على الأقل لاعتباره
|
| 376 |
+
if data.get("total_trades", 0) >= 3:
|
| 377 |
+
exit_profile_name = combined_key.replace(f"{entry_strategy}_", "", 1)
|
| 378 |
+
|
| 379 |
+
# استخدام متوسط الربح/الخسارة كمقياس أساسي
|
| 380 |
+
avg_pnl = data["total_pnl_percent"] / data["total_trades"]
|
| 381 |
+
|
| 382 |
+
# استخدام مقياس مركب (مثل Sharpe ratio المبسط)
|
| 383 |
+
# pnl_std_dev = np.std(data["pnl_list"]) if len(data["pnl_list"]) > 1 else 0
|
| 384 |
+
# risk_adjusted_return = avg_pnl / (pnl_std_dev + 1e-6) # +1e-6 لمنع القسمة على صفر
|
| 385 |
+
|
| 386 |
+
relevant_profiles[exit_profile_name] = avg_pnl # استخدام avg_pnl
|
| 387 |
+
|
| 388 |
+
if not relevant_profiles:
|
| 389 |
+
return "unknown" # لا توجد بيانات كافية
|
| 390 |
+
|
| 391 |
+
# إرجاع اسم ملف الخروج صاحب أعلى متوسط ربح
|
| 392 |
+
best_profile = max(relevant_profiles, key=relevant_profiles.get)
|
| 393 |
+
print(f"🧠 Learning Feedback: Best exit for '{entry_strategy}' is '{best_profile}' (Avg PnL: {relevant_profiles[best_profile]:.2f}%)")
|
| 394 |
+
return best_profile
|
| 395 |
|
| 396 |
async def get_current_market_conditions(self):
|
| 397 |
try:
|
|
|
|
| 432 |
"total_trades": data["total_trades"], "successful_trades": data["successful_trades"]
|
| 433 |
}
|
| 434 |
|
| 435 |
+
# 🔴 جديد: إضافة إحصائيات أداء ملف الخروج
|
| 436 |
+
exit_profile_performance = {}
|
| 437 |
+
for combined_key, data in self.exit_profile_effectiveness.items():
|
| 438 |
+
if data["total_trades"] > 0:
|
| 439 |
+
profile_success_rate = data["successful_trades"] / data["total_trades"]
|
| 440 |
+
profile_avg_pnl = data["total_pnl_percent"] / data["total_trades"]
|
| 441 |
+
exit_profile_performance[combined_key] = {
|
| 442 |
+
"success_rate": profile_success_rate, "avg_pnl_percent": profile_avg_pnl,
|
| 443 |
+
"total_trades": data["total_trades"]
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
market_performance = {}
|
| 447 |
for condition, data in self.market_patterns.items():
|
| 448 |
if data["total_trades"] > 0:
|
|
|
|
| 456 |
return {
|
| 457 |
"overall_success_rate": success_rate, "overall_avg_pnl_percent": avg_pnl,
|
| 458 |
"total_analyzed_trades": len(self.performance_history), "recent_trades_analyzed": total_trades,
|
| 459 |
+
"strategy_performance": strategy_performance,
|
| 460 |
+
"exit_profile_performance": exit_profile_performance, # 🔴 جديد
|
| 461 |
+
"market_performance": market_performance,
|
| 462 |
"last_updated": datetime.now().isoformat()
|
| 463 |
}
|
| 464 |
|
|
|
|
| 502 |
improvements.append("Start collecting performance data from first trades")
|
| 503 |
return improvements
|
| 504 |
|
| 505 |
+
# ... (التحليل الأساسي يبقى كما هو)
|
| 506 |
for strategy, data in self.strategy_effectiveness.items():
|
| 507 |
if data["total_trades"] >= 3:
|
| 508 |
success_rate = data["successful_trades"] / data["total_trades"]
|
|
|
|
| 511 |
improvements.append(f"Strategy {strategy} poor performance ({success_rate:.1%} success, {avg_pnl:+.1f}% average) - suggest reducing usage")
|
| 512 |
elif success_rate > 0.6 and avg_pnl > 2:
|
| 513 |
improvements.append(f"Strategy {strategy} excellent performance ({success_rate:.1%} success, {avg_pnl:+.1f}% average) - suggest increasing usage")
|
|
|
|
|
|
|
| 514 |
|
| 515 |
+
# 🔴 جديد: اقتراح تحسينات بناءً على ملفات الخروج
|
| 516 |
+
for combined_key, data in self.exit_profile_effectiveness.items():
|
| 517 |
+
if data["total_trades"] >= 5: # يتطلب 5 صفقات للمزيج
|
| 518 |
+
success_rate = data["successful_trades"] / data["total_trades"]
|
| 519 |
+
avg_pnl = data["total_pnl_percent"] / data["total_trades"]
|
| 520 |
+
if success_rate < 0.3 and avg_pnl < -0.5:
|
| 521 |
+
improvements.append(f"Exit Combo '{combined_key}' is failing ({success_rate:.1%} success, {avg_pnl:+.1f}% avg). AVOID.")
|
| 522 |
+
elif success_rate > 0.7 and avg_pnl > 1.5:
|
| 523 |
+
improvements.append(f"Exit Combo '{combined_key}' is performing well ({success_rate:.1%} success, {avg_pnl:+.1f}% avg). PRIORITIZE.")
|
| 524 |
+
|
| 525 |
for market_condition, data in self.market_patterns.items():
|
| 526 |
+
# ... (التحليل الأساسي يبقى كما هو)
|
| 527 |
if data["total_trades"] >= 5:
|
| 528 |
success_rate = data["successful_trades"] / data["total_trades"]
|
|
|
|
| 529 |
if success_rate < 0.4:
|
| 530 |
improvements.append(f"Poor performance in {market_condition} market ({success_rate:.1%} success) - needs strategy review")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 531 |
|
| 532 |
if not improvements: improvements.append("No suggested improvements currently - continue data collection")
|
| 533 |
return improvements
|
|
|
|
| 538 |
print("No performance data to learn from")
|
| 539 |
return
|
| 540 |
for entry in self.performance_history:
|
| 541 |
+
await self.update_strategy_effectiveness(entry) # 🔴 هذا سيحدث الآن كلا القاموسين
|
| 542 |
await self.update_market_patterns(entry)
|
| 543 |
await self.adapt_weights_based_on_performance()
|
| 544 |
await self.save_weights_to_r2()
|
| 545 |
+
await self.save_exit_profile_effectiveness() # 🔴 جديد
|
| 546 |
+
print("Strategy update forced successfully (including exit profiles)")
|
| 547 |
|
| 548 |
+
print("Enhanced self-learning system loaded - V2 (with Exit Profile Learning)")
|