File size: 29,391 Bytes
41921e2
f5a7217
 
 
41921e2
53cf6c0
 
 
 
 
 
 
41921e2
 
53cf6c0
 
 
 
 
 
 
f5a7217
 
53cf6c0
 
 
41921e2
 
53cf6c0
41921e2
53cf6c0
f5a7217
53cf6c0
 
 
 
 
f5a7217
 
53cf6c0
 
 
41921e2
 
53cf6c0
 
f5a7217
53cf6c0
 
 
f5a7217
53cf6c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f5a7217
53cf6c0
f5a7217
53cf6c0
 
 
 
f5a7217
 
53cf6c0
 
 
f5a7217
 
53cf6c0
 
f5a7217
 
53cf6c0
 
f5a7217
 
 
53cf6c0
 
41921e2
 
53cf6c0
 
 
 
f5a7217
53cf6c0
 
 
 
 
 
 
f5a7217
53cf6c0
f5a7217
53cf6c0
f5a7217
53cf6c0
 
 
 
 
 
 
 
 
 
 
 
 
 
f5a7217
53cf6c0
f5a7217
53cf6c0
f5a7217
53cf6c0
41921e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53cf6c0
 
 
f5a7217
53cf6c0
 
f5a7217
53cf6c0
f5a7217
53cf6c0
 
 
 
 
 
 
 
 
 
 
f5a7217
53cf6c0
 
f5a7217
53cf6c0
 
f5a7217
53cf6c0
 
 
 
 
 
41921e2
 
 
 
53cf6c0
 
 
 
 
 
 
 
41921e2
53cf6c0
 
 
 
 
 
 
 
 
f5a7217
53cf6c0
 
 
41921e2
 
53cf6c0
41921e2
53cf6c0
f5a7217
53cf6c0
 
 
41921e2
 
 
53cf6c0
 
 
 
41921e2
53cf6c0
 
f5a7217
 
53cf6c0
 
 
 
 
 
f5a7217
53cf6c0
 
 
f5a7217
53cf6c0
 
 
 
f5a7217
41921e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53cf6c0
 
41921e2
53cf6c0
 
 
 
 
 
 
f5a7217
 
53cf6c0
 
 
 
 
 
f5a7217
53cf6c0
 
 
 
f5a7217
53cf6c0
 
 
 
 
 
 
f5a7217
53cf6c0
 
 
 
 
 
41921e2
f5a7217
53cf6c0
 
f5a7217
53cf6c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f5a7217
 
53cf6c0
 
 
f5a7217
53cf6c0
 
 
41921e2
f5a7217
53cf6c0
 
 
 
 
 
 
 
 
f5a7217
 
41921e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53cf6c0
 
 
f5a7217
53cf6c0
f5a7217
53cf6c0
 
f5a7217
53cf6c0
 
 
 
 
f5a7217
53cf6c0
f5a7217
 
53cf6c0
 
 
f5a7217
 
53cf6c0
 
 
 
 
 
 
 
 
 
 
 
 
f5a7217
 
53cf6c0
 
41921e2
 
 
 
 
 
 
 
 
 
 
53cf6c0
 
 
 
 
 
f5a7217
53cf6c0
 
 
 
f5a7217
 
41921e2
 
 
53cf6c0
 
 
 
 
f5a7217
 
53cf6c0
 
 
 
f5a7217
53cf6c0
 
f5a7217
53cf6c0
 
 
 
f5a7217
 
53cf6c0
 
 
 
f5a7217
53cf6c0
 
 
 
f5a7217
53cf6c0
 
 
f5a7217
53cf6c0
 
 
 
 
f5a7217
53cf6c0
 
41921e2
53cf6c0
 
 
 
 
f5a7217
53cf6c0
f5a7217
53cf6c0
41921e2
 
 
 
 
 
 
 
 
 
53cf6c0
41921e2
53cf6c0
 
 
f5a7217
53cf6c0
f5a7217
53cf6c0
 
 
f5a7217
53cf6c0
f5a7217
53cf6c0
 
41921e2
53cf6c0
 
 
41921e2
 
53cf6c0
41921e2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
# learning_engine (37).py (محدث بالكامل مع تعلم ملف الخروج)
import os, json, asyncio
from datetime import datetime
from helpers import normalize_weights, calculate_market_volatility, should_update_weights
import numpy as np # نحتاج numpy لحساب المتوسطات

class LearningEngine:
    def __init__(self, r2_service, data_manager):
        self.r2_service = r2_service
        self.data_manager = data_manager
        self.weights = {}
        self.performance_history = []
        self.strategy_effectiveness = {} # 🔴 لتعلم استراتيجيات الدخول
        self.exit_profile_effectiveness = {} # 🔴 جديد: لتعلم (الدخول + الخروج)
        self.market_patterns = {}
        self.risk_profiles = {}
        self.initialized = False
        self.initialization_lock = asyncio.Lock()
        
    async def initialize(self):
        async with self.initialization_lock:
            if self.initialized: return
            print("Initializing learning system...")
            try:
                await self.load_weights_from_r2()
                await self.load_performance_history()
                # 🔴 جديد: تحميل أداء ملفات الخروج
                await self.load_exit_profile_effectiveness()
                self.initialized = True
                print("Learning system ready (with Exit Profile learning)")
            except Exception as e:
                print(f"Weights loading failed: {e}")
                await self.initialize_default_weights()
                self.initialized = True

    async def initialize_enhanced(self):
        async with self.initialization_lock:
            if self.initialized: return
            print("Enhanced learning system initialization...")
            try:
                await self.load_weights_from_r2()
                await self.load_performance_history()
                # 🔴 جديد: تحميل أداء ملفات الخروج
                await self.load_exit_profile_effectiveness()
                await self.fix_weights_structure()
                if not self.performance_history:
                    print("Starting learning from scratch")
                    await self.initialize_default_weights()
                self.initialized = True
            except Exception as e:
                print(f"Enhanced initialization failed: {e}")
                await self.initialize_default_weights()
                self.initialized = True
    
    async def fix_weights_structure(self):
        try:
            key = "learning_engine_weights.json"
            response = self.r2_service.s3_client.get_object(Bucket="trading", Key=key)
            current_data = json.loads(response['Body'].read())
            
            if 'strategy_weights' in current_data and 'last_updated' not in current_data:
                fixed_data = {
                    "weights": current_data,
                    "last_updated": datetime.now().isoformat(),
                    "version": "2.0",
                    "performance_metrics": await self.calculate_performance_metrics()
                }
                data_json = json.dumps(fixed_data, indent=2, ensure_ascii=False).encode('utf-8')
                self.r2_service.s3_client.put_object(
                    Bucket="trading", Key=key, Body=data_json, ContentType="application/json"
                )
                print("Weights structure fixed")
        except Exception as e:
            print(f"Weights structure fix failed: {e}")
    
    async def initialize_default_weights(self):
        self.weights = {
            "strategy_weights": {
                "trend_following": 0.18, "mean_reversion": 0.15, "breakout_momentum": 0.22,
                "volume_spike": 0.12, "whale_tracking": 0.15, "pattern_recognition": 0.10,
                "hybrid_ai": 0.08
            },
            "technical_weights": {
                "rsi": 0.15, "macd": 0.18, "ema_cross": 0.12, "bollinger_bands": 0.10,
                "volume_analysis": 0.15, "support_resistance": 0.12, "market_sentiment": 0.18
            },
            "risk_parameters": {
                "max_position_size": 0.1, "max_daily_loss": 0.02, "stop_loss_base": 0.02,
                "risk_reward_ratio": 2.0, "volatility_adjustment": 1.0
            },
            "market_condition_weights": {
                "bull_market": {"trend_following": 0.25, "breakout_momentum": 0.20, "whale_tracking": 0.15},
                "bear_market": {"mean_reversion": 0.25, "pattern_recognition": 0.20, "hybrid_ai": 0.15},
                "sideways_market": {"mean_reversion": 0.30, "volume_spike": 0.20, "pattern_recognition": 0.15}
            }
        }
        # 🔴 جديد: تهيئة افتراضية لملفات الخروج
        self.exit_profile_effectiveness = {}
    
    async def load_weights_from_r2(self):
        try:
            key = "learning_engine_weights.json"
            response = self.r2_service.s3_client.get_object(Bucket="trading", Key=key)
            weights_data = json.loads(response['Body'].read())
            
            if isinstance(weights_data, dict):
                if 'weights' in weights_data:
                    self.weights = weights_data['weights']
                else:
                    self.weights = weights_data
                print(f"Weights loaded from R2")
            else:
                raise ValueError("Invalid weights structure")
        except Exception as e:
            print(f"Weights loading failed: {e}")
            await self.initialize_default_weights()
            await self.save_weights_to_r2()
    
    async def save_weights_to_r2(self):
        try:
            key = "learning_engine_weights.json"
            weights_data = {
                "weights": self.weights,
                "last_updated": datetime.now().isoformat(),
                "version": "2.0",
                "performance_metrics": await self.calculate_performance_metrics()
            }
            data_json = json.dumps(weights_data, indent=2, ensure_ascii=False).encode('utf-8')
            self.r2_service.s3_client.put_object(
                Bucket="trading", Key=key, Body=data_json, ContentType="application/json"
            )
            print("Weights saved to R2")
        except Exception as e:
            print(f"Weights saving failed: {e}")
    
    # 🔴 جديد: تحميل وحفظ أداء ملف الخروج
    async def load_exit_profile_effectiveness(self):
        try:
            key = "learning_exit_profile_effectiveness.json"
            response = self.r2_service.s3_client.get_object(Bucket="trading", Key=key)
            data = json.loads(response['Body'].read())
            self.exit_profile_effectiveness = data.get("effectiveness", {})
            print(f"Exit profile effectiveness loaded - {len(self.exit_profile_effectiveness)} combinations")
        except Exception as e:
            print(f"Exit profile effectiveness loading failed: {e}")
            self.exit_profile_effectiveness = {}

    async def save_exit_profile_effectiveness(self):
        try:
            key = "learning_exit_profile_effectiveness.json"
            data = {
                "effectiveness": self.exit_profile_effectiveness,
                "last_updated": datetime.now().isoformat()
            }
            data_json = json.dumps(data, indent=2, ensure_ascii=False).encode('utf-8')
            self.r2_service.s3_client.put_object(
                Bucket="trading", Key=key, Body=data_json, ContentType="application/json"
            )
        except Exception as e:
            print(f"Exit profile effectiveness saving failed: {e}")

    async def load_performance_history(self):
        try:
            key = "learning_performance_history.json"
            response = self.r2_service.s3_client.get_object(Bucket="trading", Key=key)
            history_data = json.loads(response['Body'].read())
            self.performance_history = history_data.get("history", [])
            print(f"Performance history loaded - {len(self.performance_history)} records")
        except Exception as e:
            print(f"Performance history loading failed: {e}")
            self.performance_history = []
    
    async def save_performance_history(self):
        try:
            key = "learning_performance_history.json"
            history_data = {
                "history": self.performance_history[-1000:],
                "last_updated": datetime.now().isoformat()
            }
            data_json = json.dumps(history_data, indent=2, ensure_ascii=False).encode('utf-8')
            self.r2_service.s3_client.put_object(
                Bucket="trading", Key=key, Body=data_json, ContentType="application/json"
            )
        except Exception as e:
            print(f"Performance history saving failed: {e}")
    
    async def analyze_trade_outcome(self, trade_data, outcome):
        if not self.initialized: await self.initialize()
        try:
            strategy = trade_data.get('strategy', 'unknown')
            if strategy == 'unknown':
                decision_data = trade_data.get('decision_data', {})
                strategy = decision_data.get('strategy', 'unknown')
            
            # 🔴 جديد: استخراج ملف الخروج
            decision_data = trade_data.get('decision_data', {})
            exit_profile = decision_data.get('exit_profile', 'unknown')
            
            market_context = await self.get_current_market_conditions()
            
            analysis_entry = {
                "timestamp": datetime.now().isoformat(),
                "trade_data": trade_data,
                "outcome": outcome,
                "market_conditions": market_context,
                "strategy_used": strategy,
                "exit_profile_used": exit_profile, # 🔴 جديد
                "symbol": trade_data.get('symbol', 'unknown'),
                "pnl_usd": trade_data.get('pnl_usd', 0),
                "pnl_percent": trade_data.get('pnl_percent', 0)
            }
            
            self.performance_history.append(analysis_entry)
            await self.update_strategy_effectiveness(analysis_entry)
            await self.update_market_patterns(analysis_entry)
            
            if should_update_weights(len(self.performance_history)):
                await self.adapt_weights_based_on_performance()
                await self.save_weights_to_r2()
                await self.save_performance_history()
                # 🔴 جديد: حفظ أداء ملف الخروج
                await self.save_exit_profile_effectiveness()
            
            print(f"Trade analyzed {trade_data.get('symbol')} - Strategy: {strategy} - Exit: {exit_profile} - Outcome: {outcome}")
        except Exception as e:
            print(f"Trade outcome analysis failed: {e}")
    
    async def update_strategy_effectiveness(self, analysis_entry):
        strategy = analysis_entry['strategy_used']
        exit_profile = analysis_entry['exit_profile_used'] # 🔴 جديد
        combined_key = f"{strategy}_{exit_profile}" # 🔴 جديد
        
        outcome = analysis_entry['outcome']
        market_condition = analysis_entry['market_conditions']['current_trend']
        pnl_percent = analysis_entry.get('pnl_percent', 0)
        
        # --- 1. تحديث أداء استراتيجية الدخول (كما كان) ---
        if strategy not in self.strategy_effectiveness:
            self.strategy_effectiveness[strategy] = {
                "total_trades": 0, "successful_trades": 0, "total_profit": 0,
                "total_pnl_percent": 0, "market_conditions": {}
            }
        
        self.strategy_effectiveness[strategy]["total_trades"] += 1
        self.strategy_effectiveness[strategy]["total_pnl_percent"] += pnl_percent
        
        is_success = outcome in ["SUCCESS", "CLOSED_BY_REANALYSIS", "CLOSED_BY_MONITOR"] and pnl_percent > 0
        if is_success: self.strategy_effectiveness[strategy]["successful_trades"] += 1
        
        if market_condition not in self.strategy_effectiveness[strategy]["market_conditions"]:
            self.strategy_effectiveness[strategy]["market_conditions"][market_condition] = {
                "trades": 0, "successes": 0, "total_pnl": 0
            }
        
        self.strategy_effectiveness[strategy]["market_conditions"][market_condition]["trades"] += 1
        self.strategy_effectiveness[strategy]["market_conditions"][market_condition]["total_pnl"] += pnl_percent
        if is_success: self.strategy_effectiveness[strategy]["market_conditions"][market_condition]["successes"] += 1
        
        # --- 2. 🔴 جديد: تحديث أداء مزيج (الدخول + الخروج) ---
        if combined_key not in self.exit_profile_effectiveness:
            self.exit_profile_effectiveness[combined_key] = {
                "total_trades": 0, "successful_trades": 0, 
                "total_pnl_percent": 0, "pnl_list": [] # لتتبع المتوسط والانحراف
            }
        
        self.exit_profile_effectiveness[combined_key]["total_trades"] += 1
        self.exit_profile_effectiveness[combined_key]["total_pnl_percent"] += pnl_percent
        self.exit_profile_effectiveness[combined_key]["pnl_list"].append(pnl_percent)
        # الحفاظ على آخر 100 نتيجة فقط
        if len(self.exit_profile_effectiveness[combined_key]["pnl_list"]) > 100:
            self.exit_profile_effectiveness[combined_key]["pnl_list"] = self.exit_profile_effectiveness[combined_key]["pnl_list"][-100:]
            
        if is_success:
            self.exit_profile_effectiveness[combined_key]["successful_trades"] += 1

    
    async def update_market_patterns(self, analysis_entry):
        # ... (هذه الدالة تبقى كما هي، لا تحتاج تعديل)
        market_condition = analysis_entry['market_conditions']['current_trend']
        symbol = analysis_entry['symbol']
        outcome = analysis_entry['outcome']
        pnl_percent = analysis_entry.get('pnl_percent', 0)
        
        if market_condition not in self.market_patterns:
            self.market_patterns[market_condition] = {
                "total_trades": 0, "successful_trades": 0, "total_pnl_percent": 0,
                "best_performing_strategies": {}, "best_performing_symbols": {}
            }
        
        self.market_patterns[market_condition]["total_trades"] += 1
        self.market_patterns[market_condition]["total_pnl_percent"] += pnl_percent
        
        is_success = outcome in ["SUCCESS", "CLOSED_BY_REANALYSIS", "CLOSED_BY_MONITOR"] and pnl_percent > 0
        if is_success: self.market_patterns[market_condition]["successful_trades"] += 1
        
        strategy = analysis_entry['strategy_used']
        if strategy not in self.market_patterns[market_condition]["best_performing_strategies"]:
            self.market_patterns[market_condition]["best_performing_strategies"][strategy] = {
                "count": 0, "total_pnl": 0
            }
        
        self.market_patterns[market_condition]["best_performing_strategies"][strategy]["count"] += 1
        self.market_patterns[market_condition]["best_performing_strategies"][strategy]["total_pnl"] += pnl_percent
        
        if symbol not in self.market_patterns[market_condition]["best_performing_symbols"]:
            self.market_patterns[market_condition]["best_performing_symbols"][symbol] = {
                "count": 0, "total_pnl": 0
            }
        
        self.market_patterns[market_condition]["best_performing_symbols"][symbol]["count"] += 1
        self.market_patterns[market_condition]["best_performing_symbols"][symbol]["total_pnl"] += pnl_percent
    
    async def adapt_weights_based_on_performance(self):
        # ... (هذه الدالة تبقى كما هي، لتعديل أوزان *الدخول* فقط)
        print("Updating weights based on performance...")
        try:
            if not self.strategy_effectiveness:
                print("Insufficient performance data, using gradual adjustment")
                await self.gradual_weights_adjustment()
                return

            total_performance = 0
            strategy_performance = {}
            
            for strategy, data in self.strategy_effectiveness.items():
                if data["total_trades"] > 0:
                    success_rate = data["successful_trades"] / data["total_trades"]
                    avg_pnl = data["total_pnl_percent"] / data["total_trades"]
                    composite_performance = (success_rate * 0.7) + (min(avg_pnl, 10) / 10 * 0.3)
                    strategy_performance[strategy] = composite_performance
                    total_performance += composite_performance
            
            if total_performance > 0 and strategy_performance:
                for strategy, performance in strategy_performance.items():
                    current_weight = self.weights["strategy_weights"].get(strategy, 0.1)
                    new_weight = current_weight * 0.7 + (performance * 0.3)
                    self.weights["strategy_weights"][strategy] = new_weight
                
                normalize_weights(self.weights["strategy_weights"])
                print("Weights updated based on real performance")
            else:
                await self.gradual_weights_adjustment()
        except Exception as e:
            print(f"Weights update failed: {e}")
            await self.gradual_weights_adjustment()

    async def gradual_weights_adjustment(self):
        # ... (هذه الدالة تبقى كما هي)
        print("Gradual weights adjustment...")
        if self.market_patterns:
            for market_condition, data in self.market_patterns.items():
                if data.get("total_trades", 0) > 0:
                    best_strategy = max(data["best_performing_strategies"].items(), 
                                      key=lambda x: x[1]["total_pnl"])[0] if data["best_performing_strategies"] else None
                    if best_strategy:
                        current_weight = self.weights["strategy_weights"].get(best_strategy, 0.1)
                        self.weights["strategy_weights"][best_strategy] = min(current_weight * 1.1, 0.3)
        
        normalize_weights(self.weights["strategy_weights"])
        print("Gradual weights adjustment completed")
        
    # 🔴 جديد: دالة التغذية الراجعة لـ LLM
    async def get_best_exit_profile(self, entry_strategy: str) -> str:
        """
        يجد أفضل ملف خروج (Exit Profile) لاستراتيجية دخول معينة
        بناءً على متوسط الربح/الخسارة (avg_pnl_percent).
        """
        if not self.initialized or not self.exit_profile_effectiveness:
            return "unknown"
            
        relevant_profiles = {}
        
        for combined_key, data in self.exit_profile_effectiveness.items():
            if combined_key.startswith(f"{entry_strategy}_"):
                # يتطلب 3 صفقات على الأقل لاعتباره
                if data.get("total_trades", 0) >= 3:
                    exit_profile_name = combined_key.replace(f"{entry_strategy}_", "", 1)
                    
                    # استخدام متوسط الربح/الخسارة كمقياس أساسي
                    avg_pnl = data["total_pnl_percent"] / data["total_trades"]
                    
                    # استخدام مقياس مركب (مثل Sharpe ratio المبسط)
                    # pnl_std_dev = np.std(data["pnl_list"]) if len(data["pnl_list"]) > 1 else 0
                    # risk_adjusted_return = avg_pnl / (pnl_std_dev + 1e-6) # +1e-6 لمنع القسمة على صفر
                    
                    relevant_profiles[exit_profile_name] = avg_pnl # استخدام avg_pnl
        
        if not relevant_profiles:
            return "unknown" # لا توجد بيانات كافية
            
        # إرجاع اسم ملف الخروج صاحب أعلى متوسط ربح
        best_profile = max(relevant_profiles, key=relevant_profiles.get)
        print(f"🧠 Learning Feedback: Best exit for '{entry_strategy}' is '{best_profile}' (Avg PnL: {relevant_profiles[best_profile]:.2f}%)")
        return best_profile

    async def get_current_market_conditions(self):
        try:
            if not self.data_manager: raise ValueError("DataManager unavailable")
            market_context = await self.data_manager.get_market_context_async()
            if not market_context: raise ValueError("Market context fetch failed")
            return {
                "current_trend": market_context.get('market_trend', 'sideways_market'),
                "volatility": calculate_market_volatility(market_context),
                "market_sentiment": market_context.get('btc_sentiment', 'NEUTRAL'),
                "whale_activity": market_context.get('general_whale_activity', {}).get('sentiment', 'NEUTRAL'),
                "fear_greed_index": market_context.get('fear_and_greed_index', 50)
            }
        except Exception as e:
            print(f"Market conditions fetch failed: {e}")
            return {
                "current_trend": "sideways_market", "volatility": "medium",
                "market_sentiment": "neutral", "whale_activity": "low", "fear_greed_index": 50
            }
    
    async def calculate_performance_metrics(self):
        if not self.performance_history: return {"status": "No performance data yet"}
        recent_trades = self.performance_history[-50:]
        total_trades = len(recent_trades)
        successful_trades = sum(1 for trade in recent_trades 
                              if trade['outcome'] in ["SUCCESS", "CLOSED_BY_REANALYSIS", "CLOSED_BY_MONITOR"] and trade.get('pnl_percent', 0) > 0)
        success_rate = successful_trades / total_trades if total_trades > 0 else 0
        total_pnl = sum(trade.get('pnl_percent', 0) for trade in recent_trades)
        avg_pnl = total_pnl / total_trades if total_trades > 0 else 0
        
        strategy_performance = {}
        for strategy, data in self.strategy_effectiveness.items():
            if data["total_trades"] > 0:
                strategy_success_rate = data["successful_trades"] / data["total_trades"]
                strategy_avg_pnl = data["total_pnl_percent"] / data["total_trades"]
                strategy_performance[strategy] = {
                    "success_rate": strategy_success_rate, "avg_pnl_percent": strategy_avg_pnl,
                    "total_trades": data["total_trades"], "successful_trades": data["successful_trades"]
                }
        
        # 🔴 جديد: إضافة إحصائيات أداء ملف الخروج
        exit_profile_performance = {}
        for combined_key, data in self.exit_profile_effectiveness.items():
            if data["total_trades"] > 0:
                profile_success_rate = data["successful_trades"] / data["total_trades"]
                profile_avg_pnl = data["total_pnl_percent"] / data["total_trades"]
                exit_profile_performance[combined_key] = {
                    "success_rate": profile_success_rate, "avg_pnl_percent": profile_avg_pnl,
                    "total_trades": data["total_trades"]
                }

        market_performance = {}
        for condition, data in self.market_patterns.items():
            if data["total_trades"] > 0:
                market_success_rate = data["successful_trades"] / data["total_trades"]
                market_avg_pnl = data["total_pnl_percent"] / data["total_trades"]
                market_performance[condition] = {
                    "success_rate": market_success_rate, "avg_pnl_percent": market_avg_pnl,
                    "total_trades": data["total_trades"]
                }
        
        return {
            "overall_success_rate": success_rate, "overall_avg_pnl_percent": avg_pnl,
            "total_analyzed_trades": len(self.performance_history), "recent_trades_analyzed": total_trades,
            "strategy_performance": strategy_performance, 
            "exit_profile_performance": exit_profile_performance, # 🔴 جديد
            "market_performance": market_performance,
            "last_updated": datetime.now().isoformat()
        }
    
    async def get_optimized_strategy_weights(self, market_condition):
        try:
            if not self.initialized: return await self.get_default_strategy_weights()
            if (not self.weights or "strategy_weights" not in self.weights or not self.weights["strategy_weights"]):
                return await self.get_default_strategy_weights()
            base_weights = self.weights["strategy_weights"].copy()
            if not any(weight > 0 for weight in base_weights.values()):
                return await self.get_default_strategy_weights()
            print(f"Using learned weights: {base_weights}")
            return base_weights
        except Exception as e:
            print(f"Optimized weights calculation failed: {e}")
            return await self.get_default_strategy_weights()
    
    async def get_default_strategy_weights(self):
        return {
            "trend_following": 0.18, "mean_reversion": 0.15, "breakout_momentum": 0.22,
            "volume_spike": 0.12, "whale_tracking": 0.15, "pattern_recognition": 0.10,
            "hybrid_ai": 0.08
        }
    
    async def get_risk_parameters(self, symbol_volatility):
        if not self.weights or "risk_parameters" not in self.weights: await self.initialize_default_weights()
        risk_params = self.weights.get("risk_parameters", {}).copy()
        if symbol_volatility == "HIGH":
            risk_params["stop_loss_base"] *= 1.5
            risk_params["max_position_size"] *= 0.7
            risk_params["risk_reward_ratio"] = 1.5
        elif symbol_volatility == "LOW":
            risk_params["stop_loss_base"] *= 0.7
            risk_params["max_position_size"] *= 1.2
            risk_params["risk_reward_ratio"] = 2.5
        return risk_params
    
    async def suggest_improvements(self):
        improvements = []
        if not self.performance_history:
            improvements.append("Start collecting performance data from first trades")
            return improvements
        
        # ... (التحليل الأساسي يبقى كما هو)
        for strategy, data in self.strategy_effectiveness.items():
            if data["total_trades"] >= 3:
                success_rate = data["successful_trades"] / data["total_trades"]
                avg_pnl = data["total_pnl_percent"] / data["total_trades"]
                if success_rate < 0.3 and avg_pnl < 0:
                    improvements.append(f"Strategy {strategy} poor performance ({success_rate:.1%} success, {avg_pnl:+.1f}% average) - suggest reducing usage")
                elif success_rate > 0.6 and avg_pnl > 2:
                    improvements.append(f"Strategy {strategy} excellent performance ({success_rate:.1%} success, {avg_pnl:+.1f}% average) - suggest increasing usage")
        
        # 🔴 جديد: اقتراح تحسينات بناءً على ملفات الخروج
        for combined_key, data in self.exit_profile_effectiveness.items():
            if data["total_trades"] >= 5: # يتطلب 5 صفقات للمزيج
                success_rate = data["successful_trades"] / data["total_trades"]
                avg_pnl = data["total_pnl_percent"] / data["total_trades"]
                if success_rate < 0.3 and avg_pnl < -0.5:
                    improvements.append(f"Exit Combo '{combined_key}' is failing ({success_rate:.1%} success, {avg_pnl:+.1f}% avg). AVOID.")
                elif success_rate > 0.7 and avg_pnl > 1.5:
                     improvements.append(f"Exit Combo '{combined_key}' is performing well ({success_rate:.1%} success, {avg_pnl:+.1f}% avg). PRIORITIZE.")

        for market_condition, data in self.market_patterns.items():
             # ... (التحليل الأساسي يبقى كما هو)
            if data["total_trades"] >= 5:
                success_rate = data["successful_trades"] / data["total_trades"]
                if success_rate < 0.4:
                    improvements.append(f"Poor performance in {market_condition} market ({success_rate:.1%} success) - needs strategy review")
        
        if not improvements: improvements.append("No suggested improvements currently - continue data collection")
        return improvements

    async def force_strategy_learning(self):
        print("Forcing strategy update from current data...")
        if not self.performance_history:
            print("No performance data to learn from")
            return
        for entry in self.performance_history:
            await self.update_strategy_effectiveness(entry) # 🔴 هذا سيحدث الآن كلا القاموسين
            await self.update_market_patterns(entry)
        await self.adapt_weights_based_on_performance()
        await self.save_weights_to_r2()
        await self.save_exit_profile_effectiveness() # 🔴 جديد
        print("Strategy update forced successfully (including exit profiles)")

print("Enhanced self-learning system loaded - V2 (with Exit Profile Learning)")