Riy777 commited on
Commit
fa36606
·
verified ·
1 Parent(s): 27827ed

Update learning_engine.py

Browse files
Files changed (1) hide show
  1. 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, "market_performance": market_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
- print("Strategy update forced successfully")
 
435
 
436
- print("Enhanced self-learning system loaded - ready for continuous learning and adaptation")
 
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)")