Riy777 commited on
Commit
8894213
·
verified ·
1 Parent(s): 061ad55

Update backtest_engine.py

Browse files
Files changed (1) hide show
  1. backtest_engine.py +120 -82
backtest_engine.py CHANGED
@@ -1,10 +1,10 @@
1
  # ============================================================
2
- # 🧪 backtest_engine.py (V40.0 - GEM-Architect: Full Grid & Guardians)
3
  # ============================================================
4
- # التحديثات الكبرى:
5
- # 1. Grid Search: توليد آلي لكل توليفات الأوزان والعتبات.
6
- # 2. Guardian Telemetry: تقرير مفصل عن تدخلات Hydra و Legacy.
7
- # 3. Stress Matrix: تحليل أعمق للمخاطر.
8
  # ============================================================
9
 
10
  import asyncio
@@ -12,7 +12,7 @@ import pandas as pd
12
  import numpy as np
13
  import time
14
  import logging
15
- import itertools # 👈 مكتبة التباديل والتوافيق
16
  from datetime import datetime
17
  from typing import Dict, Any, List
18
 
@@ -20,15 +20,23 @@ from ml_engine.processor import MLProcessor, SystemLimits
20
  from ml_engine.data_manager import DataManager
21
  from learning_hub.adaptive_hub import StrategyDNA
22
 
23
- # كتم الإشعارات الفرعية
24
  logging.getLogger('ml_engine.patterns').setLevel(logging.WARNING)
25
 
26
  class VirtualPortfolio:
27
  def __init__(self, initial_capital=1000.0):
28
  self.capital = initial_capital
29
  self.active_trades = {}
30
- self.stats = {"max_win_usd": 0.0, "max_loss_usd": 0.0, "max_drawdown_pct": 0.0}
31
- self.guardian_log = {'hydra_crash': 0, 'hydra_giveback': 0, 'legacy_panic': 0, 'tp_hit': 0, 'sl_hit': 0}
 
 
 
 
 
 
 
 
32
  self.MAX_SLOTS_MAP = {'BULL': 6, 'BEAR': 3, 'RANGE': 5, 'DEAD': 2}
33
 
34
  def can_open_trade(self, regime):
@@ -43,10 +51,9 @@ class BacktestSimulator:
43
  self.dm = data_manager
44
  self.proc = processor
45
  self.history_cache = {}
46
- self.DAYS_TO_FETCH = 14
47
  self.CHUNK_LIMIT = 1000
48
 
49
- # السلة الكاملة
50
  self.TARGET_COINS = [
51
  'BTC/USDT', 'ETH/USDT', 'BNB/USDT', 'SOL/USDT', 'XRP/USDT',
52
  'AVAX/USDT', 'ADA/USDT', 'LINK/USDT', 'NEAR/USDT', 'RUNE/USDT', 'INJ/USDT',
@@ -54,7 +61,7 @@ class BacktestSimulator:
54
  'XLM/USDT', 'TRX/USDT', 'LTC/USDT'
55
  ]
56
 
57
- print("🧪 [Backtest Engine V40.0] Full Grid & Guardian System Initialized.")
58
 
59
  # ==========================================================================
60
  # 1. Data Loading
@@ -66,8 +73,10 @@ class BacktestSimulator:
66
 
67
  loaded_count = 0
68
  for sym in self.TARGET_COINS:
 
69
  all_candles = []
70
  current_since = start_time_ms
 
71
  while current_since < end_time_ms:
72
  try:
73
  candles = await self.dm.exchange.fetch_ohlcv(sym, '1m', since=current_since, limit=self.CHUNK_LIMIT)
@@ -89,6 +98,9 @@ class BacktestSimulator:
89
  mask = (df.index >= pd.to_datetime(start_time_ms, unit='ms'))
90
  self.history_cache[sym] = df.loc[mask]
91
  loaded_count += 1
 
 
 
92
 
93
  print(f"✅ Data Load Complete. Cached {loaded_count}/{len(self.TARGET_COINS)} coins.")
94
 
@@ -176,27 +188,23 @@ class BacktestSimulator:
176
  return None
177
 
178
  # ==========================================================================
179
- # 4. Simulation Loop (With Guardian Telemetry)
180
  # ==========================================================================
181
- async def run_simulation(self, regime_name, weights, l1_thresh):
182
  SystemLimits.CURRENT_REGIME = regime_name
183
  self.portfolio = VirtualPortfolio()
184
- trades_log = []
185
 
186
- if not self.history_cache: return {'final_capital': 0, 'win_rate': 0, 'trades': 0}
187
  ref_symbol = list(self.history_cache.keys())[0]
188
  full_index = self.history_cache[ref_symbol].index
189
-
190
  start_idx = 6000
191
  end_idx = len(full_index) - 1
192
  current_idx = start_idx
193
 
194
- # print(f" ▶️ Sim...", end="", flush=True)
195
-
196
  while current_idx < end_idx:
197
  current_time = full_index[current_idx]
198
 
199
- # --- أ. إدارة الصفقات (وتفعيل الحراس) ---
200
  active_symbols = list(self.portfolio.active_trades.keys())
201
  for sym in active_symbols:
202
  trade = self.portfolio.active_trades[sym]
@@ -205,11 +213,13 @@ class BacktestSimulator:
205
  current_price = self.history_cache[sym].iloc[sym_idx]['close']
206
  except: continue
207
 
208
- # تحديث القمم والقيعان للصفقة
209
  if current_price > trade['highest_price']: trade['highest_price'] = current_price
210
  if current_price < trade.get('lowest_price', trade['entry_price']): trade['lowest_price'] = current_price
211
 
212
- # جلب Snapshot للحراس
 
 
 
213
  snapshot = self.get_market_snapshot(sym, sym_idx)
214
  if not snapshot: continue
215
 
@@ -220,39 +230,52 @@ class BacktestSimulator:
220
  'time_in_trade_mins': (current_idx - trade['entry_idx'])
221
  }
222
 
223
- # 🛡️ 1. Hydra Guardian (The 3 Heads)
224
  if self.proc.guardian_hydra:
 
 
 
 
 
225
  hydra_res = self.proc.guardian_hydra.analyze_position(sym, snapshot['1m'], snapshot['5m'], snapshot['15m'], trade_ctx)
226
  if hydra_res['action'] in ['EXIT_HARD', 'EXIT_SOFT']:
227
- exit_reason = f"Hydra_{hydra_res['reason']}" # سيحتوي على Crash/Giveback
228
 
229
- # 🛡️ 2. Legacy Guardian (V2/V3)
230
  if not exit_reason and self.proc.guardian_legacy:
231
- # تمرير None لدفتر الطلبات (غير موجود في الباكتست)
 
 
 
 
 
 
232
  legacy_res = self.proc.guardian_legacy.analyze_position(
233
  snapshot['1m'], snapshot['5m'], snapshot['15m'], trade['entry_price'], order_book=None
234
  )
235
  if legacy_res['action'] == 'EXIT_HARD':
236
- exit_reason = "Legacy_Panic"
237
 
238
- # 🛑 3. Hard TP/SL
239
  if not exit_reason:
240
- if current_price >= trade['tp']: exit_reason = "TP_Hit"
241
- elif current_price <= trade['sl']: exit_reason = "SL_Hit"
242
 
243
- # تنفيذ الخروج وتسجيل السبب
244
  if exit_reason:
245
  pnl_pct = (current_price - trade['entry_price']) / trade['entry_price']
246
  pnl_usd = trade['size'] * pnl_pct
247
  self.portfolio.capital += (trade['size'] + pnl_usd)
248
  trades_log.append(pnl_pct)
249
 
250
- # 📝 تسجيل من هو البطل؟
251
  if 'Crash' in exit_reason: self.portfolio.guardian_log['hydra_crash'] += 1
252
  elif 'Giveback' in exit_reason: self.portfolio.guardian_log['hydra_giveback'] += 1
253
- elif 'Legacy' in exit_reason: self.portfolio.guardian_log['legacy_panic'] += 1
254
- elif 'TP' in exit_reason: self.portfolio.guardian_log['tp_hit'] += 1
255
- elif 'SL' in exit_reason: self.portfolio.guardian_log['sl_hit'] += 1
 
 
 
 
256
 
257
  del self.portfolio.active_trades[sym]
258
 
@@ -281,82 +304,96 @@ class BacktestSimulator:
281
  current_idx += 1
282
 
283
  wins = len([p for p in trades_log if p > 0])
284
- total = len(trades_log)
285
- wr = (wins/total*100) if total > 0 else 0.0
286
 
287
  return {
288
  'final_capital': self.portfolio.capital,
289
  'win_rate': wr,
290
- 'trades': total,
291
- 'guards': self.portfolio.guardian_log
 
 
 
292
  }
293
 
294
  # ==========================================================================
295
- # 5. Grid Search Manager (توليد آلي)
296
  # ==========================================================================
297
  async def optimize_dna(self):
298
  best_dna = {}
299
- regimes = ['RANGE'] # للسرعة
300
 
301
- # 🎲 توليد الاحتمالات (Grid Search Generation)
302
- # نولد أوزان بحيث يكون مجموعها 1.0 تقريباً
303
- # Titan, Pattern, Sniper, MC (الثابت 0.1)
304
- # سنغير Titan و Pattern و Sniper
305
-
306
- possible_weights = []
307
- # توليد مبسط لتفادي الانفجار الحسابي
308
- # (Titan, Patterns, Sniper)
309
- combos = [
310
- (0.3, 0.3, 0.3), # Balanced
311
- (0.5, 0.2, 0.2), # Trend Focus
312
- (0.2, 0.5, 0.2), # Pattern Focus
313
- (0.2, 0.2, 0.5), # Sniper Focus
314
- (0.4, 0.4, 0.1), # Tech Focus
315
  ]
316
 
317
- possible_thresholds = [0.50, 0.60] # تجربتين للعتبة
 
 
 
 
 
 
 
 
 
 
 
318
 
319
  for regime in regimes:
320
- print(f"\n🧪 Optimizing {regime} (Grid Search: {len(combos)*len(possible_thresholds)} combinations)...")
321
- print("-" * 100)
322
- print(f"{'WEIGHTS (Ti/Pat/Sn)':<25} | {'THR':<4} | {'CAPITAL':<9} | {'WR%':<5} | {'TRDS':<4} | {'GUARDS (Crsh/Gvbk/Leg/TP/SL)'}")
323
- print("-" * 100)
 
 
324
 
325
  best_score = -9999
326
  best_config = None
327
 
328
- for w in combos:
329
- weights = {'titan': w[0], 'patterns': w[1], 'sniper': w[2], 'mc': 0.1}
330
- for thresh in possible_thresholds:
331
-
332
- res = await self.run_simulation(regime, weights, thresh)
333
-
334
- g = res['guards']
335
- guard_str = f"{g['hydra_crash']}/{g['hydra_giveback']}/{g['legacy_panic']}/{g['tp_hit']}/{g['sl_hit']}"
336
- w_str = f"{w[0]}/{w[1]}/{w[2]}"
337
-
338
- print(f"{w_str:<25} | {thresh:<4} | ${res['final_capital']:.1f} | {res['win_rate']:.1f}% | {res['trades']:<4} | {guard_str}")
339
-
340
- if res['final_capital'] > best_score:
341
- best_score = res['final_capital']
342
- best_config = {'w': weights, 'th': thresh, 'guards': g}
343
 
344
  if best_config:
345
  best_dna[regime] = {
346
  "model_weights": best_config['w'],
347
  "ob_settings": {"wall_ratio_limit": 0.4, "imbalance_thresh": 0.5},
348
- "filters": {"l1_min_score": best_config['th'] * 100, "l3_conf_thresh": 0.65}
 
 
 
 
 
 
 
349
  }
350
- g = best_config['guards']
351
- print("-" * 100)
352
- print(f"🏆 WINNER ({regime}): Weights={best_config['w']} | Thresh={best_config['th']}")
353
- print(f"🛡️ Guardian Report: Hydra Saved: {g['hydra_crash']+g['hydra_giveback']} | Legacy Saved: {g['legacy_panic']}")
354
- print("=" * 100)
 
355
 
356
  return best_dna
357
 
358
  async def run_strategic_optimization_task():
359
- print("\n🧪 [STRATEGIC BACKTEST V40.0] Full Grid & Guardian Telemetry...")
360
  from r2 import R2Service
361
  r2 = R2Service()
362
  dm = DataManager(None, None, r2)
@@ -376,6 +413,7 @@ async def run_strategic_optimization_task():
376
  if reg in hub.strategies:
377
  hub.strategies[reg].model_weights.update(data['model_weights'])
378
  hub.strategies[reg].filters = data['filters']
 
379
 
380
  await hub._save_state_to_r2()
381
  await dm.close()
 
1
  # ============================================================
2
+ # 🧪 backtest_engine.py (V42.1 - GEM-Architect: Exact Threshold Mapping)
3
  # ============================================================
4
+ # التحديثات:
5
+ # 1. مطابقة تامة لمتغيرات processor.py (Hydra Crash/Giveback, Legacy V2/V3).
6
+ # 2. توسيع الشبكة لتشمل هذه المتغيرات الدقيقة.
7
+ # 3. تقرير يفصل أي "رأس" من رؤوس الحراس كان الأنشط.
8
  # ============================================================
9
 
10
  import asyncio
 
12
  import numpy as np
13
  import time
14
  import logging
15
+ import itertools
16
  from datetime import datetime
17
  from typing import Dict, Any, List
18
 
 
20
  from ml_engine.data_manager import DataManager
21
  from learning_hub.adaptive_hub import StrategyDNA
22
 
23
+ # كتم الضوضاء
24
  logging.getLogger('ml_engine.patterns').setLevel(logging.WARNING)
25
 
26
  class VirtualPortfolio:
27
  def __init__(self, initial_capital=1000.0):
28
  self.capital = initial_capital
29
  self.active_trades = {}
30
+ self.stats = {
31
+ "max_win_usd": 0.0, "max_loss_usd": 0.0,
32
+ "max_drawdown_pct": 0.0, "max_runup_pct": 0.0
33
+ }
34
+ # تفصيل أدق للحراس
35
+ self.guardian_log = {
36
+ 'hydra_crash': 0, 'hydra_giveback': 0, 'hydra_stag': 0,
37
+ 'legacy_v2': 0, 'legacy_v3': 0,
38
+ 'tp': 0, 'sl': 0
39
+ }
40
  self.MAX_SLOTS_MAP = {'BULL': 6, 'BEAR': 3, 'RANGE': 5, 'DEAD': 2}
41
 
42
  def can_open_trade(self, regime):
 
51
  self.dm = data_manager
52
  self.proc = processor
53
  self.history_cache = {}
54
+ self.DAYS_TO_FETCH = 7
55
  self.CHUNK_LIMIT = 1000
56
 
 
57
  self.TARGET_COINS = [
58
  'BTC/USDT', 'ETH/USDT', 'BNB/USDT', 'SOL/USDT', 'XRP/USDT',
59
  'AVAX/USDT', 'ADA/USDT', 'LINK/USDT', 'NEAR/USDT', 'RUNE/USDT', 'INJ/USDT',
 
61
  'XLM/USDT', 'TRX/USDT', 'LTC/USDT'
62
  ]
63
 
64
+ print("🧪 [Backtest Engine V42.1] Exact Threshold Grid Initialized.")
65
 
66
  # ==========================================================================
67
  # 1. Data Loading
 
73
 
74
  loaded_count = 0
75
  for sym in self.TARGET_COINS:
76
+ print(f" ⬇️ {sym:<10}", end="", flush=True)
77
  all_candles = []
78
  current_since = start_time_ms
79
+
80
  while current_since < end_time_ms:
81
  try:
82
  candles = await self.dm.exchange.fetch_ohlcv(sym, '1m', since=current_since, limit=self.CHUNK_LIMIT)
 
98
  mask = (df.index >= pd.to_datetime(start_time_ms, unit='ms'))
99
  self.history_cache[sym] = df.loc[mask]
100
  loaded_count += 1
101
+ print(f" ✅ ({len(self.history_cache[sym])})")
102
+ else:
103
+ print(" ⚠️ No Data")
104
 
105
  print(f"✅ Data Load Complete. Cached {loaded_count}/{len(self.TARGET_COINS)} coins.")
106
 
 
188
  return None
189
 
190
  # ==========================================================================
191
+ # 4. Simulation Loop (Exact Threshold Injection)
192
  # ==========================================================================
193
+ async def run_simulation(self, regime_name, weights, l1_thresh, hydra_crash, hydra_giveback, legacy_v2, legacy_v3):
194
  SystemLimits.CURRENT_REGIME = regime_name
195
  self.portfolio = VirtualPortfolio()
196
+ trades_log = []
197
 
 
198
  ref_symbol = list(self.history_cache.keys())[0]
199
  full_index = self.history_cache[ref_symbol].index
 
200
  start_idx = 6000
201
  end_idx = len(full_index) - 1
202
  current_idx = start_idx
203
 
 
 
204
  while current_idx < end_idx:
205
  current_time = full_index[current_idx]
206
 
207
+ # --- أ. الحراس ---
208
  active_symbols = list(self.portfolio.active_trades.keys())
209
  for sym in active_symbols:
210
  trade = self.portfolio.active_trades[sym]
 
213
  current_price = self.history_cache[sym].iloc[sym_idx]['close']
214
  except: continue
215
 
 
216
  if current_price > trade['highest_price']: trade['highest_price'] = current_price
217
  if current_price < trade.get('lowest_price', trade['entry_price']): trade['lowest_price'] = current_price
218
 
219
+ # Max DD
220
+ dd = (trade['lowest_price'] - trade['entry_price']) / trade['entry_price']
221
+ if dd < self.portfolio.stats['max_drawdown_pct']: self.portfolio.stats['max_drawdown_pct'] = dd
222
+
223
  snapshot = self.get_market_snapshot(sym, sym_idx)
224
  if not snapshot: continue
225
 
 
230
  'time_in_trade_mins': (current_idx - trade['entry_idx'])
231
  }
232
 
233
+ # 🛡️ 1. Hydra (Exact Thresholds)
234
  if self.proc.guardian_hydra:
235
+ # حقن المتغيرات الدقيقة
236
+ SystemLimits.HYDRA_CRASH_THRESH = hydra_crash
237
+ SystemLimits.HYDRA_GIVEBACK_THRESH = hydra_giveback
238
+ SystemLimits.HYDRA_STAGNATION_THRESH = 0.50 # ثابت حالياً
239
+
240
  hydra_res = self.proc.guardian_hydra.analyze_position(sym, snapshot['1m'], snapshot['5m'], snapshot['15m'], trade_ctx)
241
  if hydra_res['action'] in ['EXIT_HARD', 'EXIT_SOFT']:
242
+ exit_reason = f"Hydra_{hydra_res.get('reason','Unknown')}"
243
 
244
+ # 🛡️ 2. Legacy (Exact Thresholds)
245
  if not exit_reason and self.proc.guardian_legacy:
246
+ # حقن المتغيرات الدقيقة
247
+ self.proc.guardian_legacy.configure_thresholds(
248
+ v2_panic=legacy_v2,
249
+ v3_hard=legacy_v3,
250
+ v3_soft=legacy_v3-0.1, # مشتق منطقي
251
+ v3_ultra=0.99
252
+ )
253
  legacy_res = self.proc.guardian_legacy.analyze_position(
254
  snapshot['1m'], snapshot['5m'], snapshot['15m'], trade['entry_price'], order_book=None
255
  )
256
  if legacy_res['action'] == 'EXIT_HARD':
257
+ exit_reason = f"Legacy_{legacy_res.get('reason','Unknown')}"
258
 
 
259
  if not exit_reason:
260
+ if current_price >= trade['tp']: exit_reason = "TP"
261
+ elif current_price <= trade['sl']: exit_reason = "SL"
262
 
 
263
  if exit_reason:
264
  pnl_pct = (current_price - trade['entry_price']) / trade['entry_price']
265
  pnl_usd = trade['size'] * pnl_pct
266
  self.portfolio.capital += (trade['size'] + pnl_usd)
267
  trades_log.append(pnl_pct)
268
 
269
+ # تسجيل دقيق للسبب
270
  if 'Crash' in exit_reason: self.portfolio.guardian_log['hydra_crash'] += 1
271
  elif 'Giveback' in exit_reason: self.portfolio.guardian_log['hydra_giveback'] += 1
272
+ elif 'V2' in exit_reason: self.portfolio.guardian_log['legacy_v2'] += 1
273
+ elif 'V3' in exit_reason: self.portfolio.guardian_log['legacy_v3'] += 1
274
+ elif 'TP' in exit_reason: self.portfolio.guardian_log['tp'] += 1
275
+ elif 'SL' in exit_reason: self.portfolio.guardian_log['sl'] += 1
276
+
277
+ if pnl_usd > self.portfolio.stats['max_win_usd']: self.portfolio.stats['max_win_usd'] = pnl_usd
278
+ if pnl_usd < self.portfolio.stats['max_loss_usd']: self.portfolio.stats['max_loss_usd'] = pnl_usd
279
 
280
  del self.portfolio.active_trades[sym]
281
 
 
304
  current_idx += 1
305
 
306
  wins = len([p for p in trades_log if p > 0])
307
+ losses = len(trades_log) - wins
308
+ wr = (wins/len(trades_log)*100) if len(trades_log) > 0 else 0.0
309
 
310
  return {
311
  'final_capital': self.portfolio.capital,
312
  'win_rate': wr,
313
+ 'trades_count': len(trades_log),
314
+ 'wins': wins,
315
+ 'losses': losses,
316
+ 'guards': self.portfolio.guardian_log,
317
+ 'stats': self.portfolio.stats
318
  }
319
 
320
  # ==========================================================================
321
+ # 5. Master Grid Search (Expanded)
322
  # ==========================================================================
323
  async def optimize_dna(self):
324
  best_dna = {}
325
+ regimes = ['RANGE']
326
 
327
+ # 1. متغيرات الأوزان
328
+ weight_opts = [
329
+ {'titan': 0.3, 'patterns': 0.3, 'sniper': 0.3, 'mc': 0.1}, # Balanced
330
+ {'titan': 0.5, 'patterns': 0.2, 'sniper': 0.2, 'mc': 0.1}, # Trend
 
 
 
 
 
 
 
 
 
 
331
  ]
332
 
333
+ # 2. متغيرات العتبات (Entry)
334
+ entry_thresh_opts = [0.55, 0.60]
335
+
336
+ # 3. متغيرات Hydra (Crash/Giveback)
337
+ hydra_crash_opts = [0.60, 0.70] # هل نجزع عند 60% أم 70%؟
338
+ hydra_give_opts = [0.65, 0.75]
339
+
340
+ # 4. متغيرات Legacy (V2/V3)
341
+ legacy_v2_opts = [0.95, 0.98] # V2 Panic
342
+ legacy_v3_opts = [0.95] # V3 Hard (نثبته لتقليل الاحتمالات قليلاً)
343
+
344
+ # Grid Size: 2 * 2 * 2 * 2 * 2 * 1 = 32 Combination
345
 
346
  for regime in regimes:
347
+ print(f"\n🧪 Optimizing {regime} (Master Grid: 32 combos)...")
348
+ # رأس الجدول العريض جداً
349
+ header = f"{'W(Ti/Pat/Sn)':<15} | {'En-Th':<5} | {'H-Crsh':<6} | {'H-Giv':<5} | {'L-V2':<4} | {'CAPITAL':<9} | {'W/L':<7} | {'Guards(Cr/Gv/V2/V3)'}"
350
+ print("-" * len(header))
351
+ print(header)
352
+ print("-" * len(header))
353
 
354
  best_score = -9999
355
  best_config = None
356
 
357
+ # حلقة التوليفات الكبرى
358
+ for w, e_th, h_c, h_g, l_v2, l_v3 in itertools.product(weight_opts, entry_thresh_opts, hydra_crash_opts, hydra_give_opts, legacy_v2_opts, legacy_v3_opts):
359
+
360
+ res = await self.run_simulation(regime, w, e_th, h_c, h_g, l_v2, l_v3)
361
+
362
+ w_str = f"{w['titan']}/{w['patterns']}/{w['sniper']}"
363
+ wl_str = f"{res['wins']}/{res['losses']}"
364
+ g = res['guards']
365
+ g_str = f"{g['hydra_crash']}/{g['hydra_giveback']}/{g['legacy_v2']}/{g['legacy_v3']}"
366
+
367
+ print(f"{w_str:<15} | {e_th:<5} | {h_c:<6} | {h_g:<5} | {l_v2:<4} | ${res['final_capital']:.1f} | {wl_str:<7} | {g_str}")
368
+
369
+ if res['final_capital'] > best_score:
370
+ best_score = res['final_capital']
371
+ best_config = {'w': w, 'e_th': e_th, 'h_c': h_c, 'h_g': h_g, 'l_v2': l_v2, 'l_v3': l_v3, 'res': res}
372
 
373
  if best_config:
374
  best_dna[regime] = {
375
  "model_weights": best_config['w'],
376
  "ob_settings": {"wall_ratio_limit": 0.4, "imbalance_thresh": 0.5},
377
+ "filters": {"l1_min_score": best_config['e_th'] * 100, "l3_conf_thresh": 0.65},
378
+ # حفظ عتبات الحراس الدقيقة
379
+ "guard_settings": {
380
+ "hydra_crash": best_config['h_c'],
381
+ "hydra_giveback": best_config['h_g'],
382
+ "legacy_v2": best_config['l_v2'],
383
+ "legacy_v3": best_config['l_v3']
384
+ }
385
  }
386
+
387
+ s = best_config['res']['stats']
388
+ print("-" * len(header))
389
+ print(f"🏆 WINNER ({regime}): Profit=${(best_score-1000):.2f} | Max DD: {s['max_drawdown_pct']*100:.2f}%")
390
+ print(f" ⚙️ Config: H-Crash={best_config['h_c']}, H-Give={best_config['h_g']}, V2={best_config['l_v2']}")
391
+ print("=" * len(header))
392
 
393
  return best_dna
394
 
395
  async def run_strategic_optimization_task():
396
+ print("\n🧪 [STRATEGIC BACKTEST V42.1] Exact Threshold Grid...")
397
  from r2 import R2Service
398
  r2 = R2Service()
399
  dm = DataManager(None, None, r2)
 
413
  if reg in hub.strategies:
414
  hub.strategies[reg].model_weights.update(data['model_weights'])
415
  hub.strategies[reg].filters = data['filters']
416
+ # هنا سنحتاج لتحديث AdaptiveHub لاحقاً ليخزن guard_settings
417
 
418
  await hub._save_state_to_r2()
419
  await dm.close()