Riy777 commited on
Commit
2c0f90a
·
verified ·
1 Parent(s): afadb83

Update backtest_engine.py

Browse files
Files changed (1) hide show
  1. backtest_engine.py +109 -88
backtest_engine.py CHANGED
@@ -1,5 +1,5 @@
1
  # ============================================================
2
- # 🧪 backtest_engine.py (V76.0 - GEM-Architect: Aggressive Force)
3
  # ============================================================
4
 
5
  import asyncio
@@ -11,6 +11,7 @@ import itertools
11
  import os
12
  import gc
13
  import concurrent.futures
 
14
  from typing import Dict, Any, List
15
 
16
  try:
@@ -28,17 +29,35 @@ class HeavyDutyBacktester:
28
  def __init__(self, data_manager, processor):
29
  self.dm = data_manager
30
  self.proc = processor
31
- self.GRID_DENSITY = 10 # كثافة عالية للدقة
32
- self.BACKTEST_DAYS = 30 # شهر كامل
33
 
34
  # 💰 إعدادات التوأم الرقمي
35
  self.INITIAL_CAPITAL = 10.0
36
  self.TRADING_FEES = 0.001
37
  self.MAX_SLOTS = 4
38
 
39
- self.TARGET_COINS = [ 'SOL/USDT', 'XRP/USDT', 'DOGE/USDT', 'ADA/USDT', 'AVAX/USDT', 'LINK/USDT', 'TON/USDT', 'INJ/USDT', 'APT/USDT', 'OP/USDT', 'ARB/USDT', 'SUI/USDT', 'SEI/USDT', 'TIA/USDT', 'MATIC/USDT', 'PEPE/USDT', 'NEAR/USDT', 'RUNE/USDT', 'PYTH/USDT', 'WIF/USDT' ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  if not os.path.exists(CACHE_DIR): os.makedirs(CACHE_DIR)
41
- print(f"🧪 [Backtest V76.0] Aggressive Force Mode (Max Thresh 0.55).")
 
 
 
 
42
 
43
  # ==============================================================
44
  # 🛠️ Helpers
@@ -52,15 +71,15 @@ class HeavyDutyBacktester:
52
  # ==============================================================
53
  async def _process_single_coin_task(self, sym, start_time_ms, end_time_ms):
54
  safe_sym = sym.replace('/', '_')
55
- scores_file = f"{CACHE_DIR}/{safe_sym}_fullstack_scores.pkl"
 
56
 
57
  if os.path.exists(scores_file):
58
- print(f" 📂 {sym} scores ready. Skipping.")
59
  return True
60
 
61
  print(f" ⚙️ Simulating {sym}...", end="", flush=True)
62
 
63
- # تهيئة المتغيرات لتجنب أخطاء النطاق
64
  all_candles_1m = []
65
  df_1m = None
66
  frames = {}
@@ -184,27 +203,31 @@ class HeavyDutyBacktester:
184
  # PHASE 1: Main Loop
185
  # ==============================================================
186
  async def generate_truth_data(self):
187
- print(f"\n🚜 [Phase 1] Processing Logic Tree + Titan ({self.BACKTEST_DAYS} Days)...")
188
- end_time_ms = int(time.time() * 1000)
189
- start_time_ms = end_time_ms - (self.BACKTEST_DAYS * 24 * 60 * 60 * 1000)
 
 
 
 
 
190
 
191
  chunk_size = 4
192
  chunks = [self.TARGET_COINS[i:i + chunk_size] for i in range(0, len(self.TARGET_COINS), chunk_size)]
193
 
194
  for chunk_idx, chunk in enumerate(chunks):
195
- print(f"\n--- 📦 Processing Batch {chunk_idx + 1}/{len(chunks)} ---")
196
  for sym in chunk:
197
  try:
198
  await asyncio.wait_for(
199
  self._process_single_coin_task(sym, start_time_ms, end_time_ms),
200
- timeout=180.0
201
  )
202
  except asyncio.TimeoutError:
203
- print(f" 💀 [WATCHDOG] Killed {sym}. Moving on...")
204
  gc.collect()
205
-
206
  gc.collect()
207
- await asyncio.sleep(2.0)
208
 
209
  # ==============================================================
210
  # PHASE 2: Portfolio Digital Twin Engine
@@ -234,7 +257,7 @@ class HeavyDutyBacktester:
234
  entry_thresh = config['thresh']
235
 
236
  for ts, group in grouped_by_time:
237
- # 1. Exit Logic
238
  active_symbols = list(wallet["positions"].keys())
239
  current_prices = {row['symbol']: row['close'] for _, row in group.iterrows()}
240
 
@@ -254,7 +277,7 @@ class HeavyDutyBacktester:
254
  del wallet["positions"][sym]
255
  wallet["trades_history"].append({'pnl': net_pnl})
256
 
257
- # 2. Entry Logic
258
  if len(wallet["positions"]) < max_slots:
259
  free_capital = wallet["balance"] - wallet["allocated"]
260
  slots_left = max_slots - len(wallet["positions"])
@@ -287,116 +310,88 @@ class HeavyDutyBacktester:
287
 
288
  if wallet["balance"] < 1.0 and len(wallet["positions"]) == 0: break
289
 
290
- # Analytics
291
  trades = wallet["trades_history"]
292
  if trades:
293
  net_profit = wallet["balance"] - initial_capital
294
  pnls = [t['pnl'] for t in trades]
295
  wins = [p for p in pnls if p > 0]
296
  losses = [p for p in pnls if p <= 0]
 
 
297
 
298
- win_count = len(wins); loss_count = len(losses)
299
- total_trades = len(trades)
300
- win_rate = (win_count / total_trades) * 100 if total_trades > 0 else 0
301
- max_single_win = max(pnls) if pnls else 0.0
302
- max_single_loss = min(pnls) if pnls else 0.0
303
-
304
- current_win_streak = 0; max_win_streak = 0
305
- current_loss_streak = 0; max_loss_streak = 0
306
- for p in pnls:
307
- if p > 0:
308
- current_win_streak += 1; current_loss_streak = 0
309
- if current_win_streak > max_win_streak: max_win_streak = current_win_streak
310
- else:
311
- current_loss_streak += 1; current_win_streak = 0
312
- if current_loss_streak > max_loss_streak: max_loss_streak = current_loss_streak
313
-
314
  results.append({
315
  'config': config,
316
  'final_balance': wallet["balance"],
317
  'net_profit': net_profit,
318
- 'total_trades': total_trades,
319
- 'win_count': win_count, 'loss_count': loss_count,
320
  'win_rate': win_rate,
321
- 'max_single_win': max_single_win, 'max_single_loss': max_single_loss,
322
- 'max_win_streak': max_win_streak, 'max_loss_streak': max_loss_streak
323
  })
324
  else:
325
- results.append({
326
- 'config': config, 'final_balance': initial_capital, 'net_profit': 0.0,
327
- 'total_trades': 0, 'win_count': 0, 'loss_count': 0, 'win_rate': 0.0,
328
- 'max_single_win': 0.0, 'max_single_loss': 0.0, 'max_win_streak': 0, 'max_loss_streak': 0
329
- })
330
 
331
  return results
332
 
333
- async def run_optimization(self):
334
- # Ensure directory
335
- if not os.path.exists(CACHE_DIR): os.makedirs(CACHE_DIR)
336
-
337
  await self.generate_truth_data()
338
 
339
- score_files = [os.path.join(CACHE_DIR, f) for f in os.listdir(CACHE_DIR) if f.endswith(f'_fullstack_scores.pkl')]
340
- if not score_files:
341
- print("❌ No Full-Stack signals found.")
 
 
 
 
 
 
 
 
 
 
342
  return None
343
 
344
- print(f"\n🧩 [Phase 2] Running Aggressive Force Simulation...")
345
  print(f" 💰 Start Capital: ${self.INITIAL_CAPITAL}")
346
 
347
  w_titan_range = np.linspace(0.4, 0.9, num=self.GRID_DENSITY)
348
  w_struct_range = np.linspace(0.1, 0.6, num=self.GRID_DENSITY)
349
-
350
- # 🔥🔥🔥 The Force: Forced Aggression (0.20 to 0.55) 🔥🔥🔥
351
- thresh_range = np.linspace(0.20, 0.55, num=self.GRID_DENSITY)
352
 
353
  combinations = []
354
  for wt, ws, th in itertools.product(w_titan_range, w_struct_range, thresh_range):
355
  if 0.9 <= (wt + ws) <= 1.1:
356
  combinations.append({'w_titan': round(wt, 2), 'w_struct': round(ws, 2), 'thresh': round(th, 2)})
357
 
358
- print(f" 📊 Simulating {len(combinations):,} scenarios...")
359
-
360
  final_results = []
361
  batch_size = max(20, len(combinations) // (os.cpu_count() * 2))
362
  batches = [combinations[i:i+batch_size] for i in range(0, len(combinations), batch_size)]
363
 
364
  with concurrent.futures.ProcessPoolExecutor() as executor:
365
- futures = [executor.submit(self._worker_optimize, batch, score_files,
366
  self.INITIAL_CAPITAL, self.TRADING_FEES, self.MAX_SLOTS)
367
  for batch in batches]
368
  for future in concurrent.futures.as_completed(futures):
369
  try: final_results.extend(future.result())
370
  except Exception as e: print(f"Grid Error: {e}")
371
 
372
- if not final_results:
373
- print("⚠️ No profitable config found.")
374
- return None
375
 
376
  best = sorted(final_results, key=lambda x: x['final_balance'], reverse=True)[0]
377
 
378
  print("\n" + "="*60)
379
- print(f"🏆 CHAMPION AGGRESSIVE REPORT ({self.BACKTEST_DAYS} Days):")
380
- print(f" 💰 Final Balance: ${best['final_balance']:,.2f}")
381
- print(f" 🚀 Net PnL: ${best['net_profit']:,.2f}")
382
- print("-" * 60)
383
- print(f" 📊 Total Trades: {best['total_trades']}")
384
- print(f" ✅ Winning Trades: {best['win_count']}")
385
- print(f" ❌ Losing Trades: {best['loss_count']}")
386
- print(f" 📈 Win Rate: {best['win_rate']:.1f}%")
387
- print("-" * 60)
388
- print(f" 🟢 Max Single Win: ${best['max_single_win']:.2f}")
389
- print(f" 🔴 Max Single Loss: ${best['max_single_loss']:.2f}")
390
- print(f" 🔥 Max Win Streak: {best['max_win_streak']} trades")
391
- print(f" 🧊 Max Loss Streak: {best['max_loss_streak']} trades")
392
- print("-" * 60)
393
  print(f" ⚙️ Config: Titan={best['config']['w_titan']} | Struct={best['config']['w_struct']} | Thresh={best['config']['thresh']}")
394
  print("="*60)
395
 
396
  return best['config']
397
 
398
  async def run_strategic_optimization_task():
399
- print("\n🧪 [STRATEGIC BACKTEST] Starting Aggressive Force Optimization...")
400
  r2 = R2Service()
401
  dm = DataManager(None, None, r2)
402
  proc = MLProcessor(dm)
@@ -405,25 +400,51 @@ async def run_strategic_optimization_task():
405
  await proc.initialize()
406
 
407
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408
  optimizer = HeavyDutyBacktester(dm, proc)
409
- best_config = await optimizer.run_optimization()
410
 
411
- if best_config:
412
- from learning_hub.adaptive_hub import AdaptiveHub
413
- hub = AdaptiveHub(r2)
414
- await hub.initialize()
415
 
416
- target_regime = "RANGE"
417
- if target_regime in hub.strategies:
418
- print(f"💉 Injecting DNA into {target_regime}...")
419
- st = hub.strategies[target_regime]
 
 
 
420
  st.model_weights['titan'] = best_config['w_titan']
421
  st.model_weights['structure'] = best_config['w_struct']
422
  st.filters['l1_min_score'] = best_config['thresh']
 
 
 
 
 
423
 
424
- await hub._save_state_to_r2()
425
- hub._inject_current_parameters()
426
- print(f"✅ [System] DNA Updated Successfully.")
427
  finally:
428
  await dm.close()
429
 
 
1
  # ============================================================
2
+ # 🧪 backtest_engine.py (V81.0 - GEM-Architect: The Time Lord)
3
  # ============================================================
4
 
5
  import asyncio
 
11
  import os
12
  import gc
13
  import concurrent.futures
14
+ from datetime import datetime, timezone
15
  from typing import Dict, Any, List
16
 
17
  try:
 
29
  def __init__(self, data_manager, processor):
30
  self.dm = data_manager
31
  self.proc = processor
32
+ self.GRID_DENSITY = 10 # كثافة متوازنة للسرعة والدقة
 
33
 
34
  # 💰 إعدادات التوأم الرقمي
35
  self.INITIAL_CAPITAL = 10.0
36
  self.TRADING_FEES = 0.001
37
  self.MAX_SLOTS = 4
38
 
39
+ self.TARGET_COINS = [
40
+ 'SOL/USDT', 'XRP/USDT', 'DOGE/USDT', 'ADA/USDT', 'AVAX/USDT',
41
+ 'LINK/USDT', 'TON/USDT', 'INJ/USDT', 'APT/USDT', 'OP/USDT',
42
+ 'ARB/USDT', 'SUI/USDT', 'SEI/USDT', 'TIA/USDT', 'BEST/USDT',
43
+ 'NEAR/USDT', 'RUNE/USDT', 'PYTH/USDT', 'WIF/USDT', 'PEPE/USDT',
44
+ 'SHIB/USDT', 'TRX/USDT', 'DOT/USDT', 'UNI/USDT', 'ONDO/USDT',
45
+ 'ENA/USDT', 'HBAR/USDT', 'XLM/USDT', 'TAO/USDT', 'ZK/USDT',
46
+ 'ZRO/USDT', 'KCS/USDT', 'ICP/USDT', 'SAND/USDT', 'AXS/USDT',
47
+ 'APE/USDT', 'GMT/USDT', 'CHZ/USDT', 'CFX/USDT', 'LDO/USDT',
48
+ 'FET/USDT', 'JTO/USDT', 'STRK/USDT', 'BLUR/USDT', 'ALT/USDT',
49
+ 'JUP/USDT', 'PENDLE/USDT', 'ETHFI/USDT', 'MEME/USDT', 'ATOM/USDT'
50
+ ]
51
+
52
+ self.force_start_date = None
53
+ self.force_end_date = None
54
+
55
  if not os.path.exists(CACHE_DIR): os.makedirs(CACHE_DIR)
56
+ print(f"🧪 [Backtest V81.0] Time Lord Mode Ready.")
57
+
58
+ def set_date_range(self, start_str, end_str):
59
+ self.force_start_date = start_str
60
+ self.force_end_date = end_str
61
 
62
  # ==============================================================
63
  # 🛠️ Helpers
 
71
  # ==============================================================
72
  async def _process_single_coin_task(self, sym, start_time_ms, end_time_ms):
73
  safe_sym = sym.replace('/', '_')
74
+ period_suffix = f"{start_time_ms}_{end_time_ms}"
75
+ scores_file = f"{CACHE_DIR}/{safe_sym}_{period_suffix}_scores.pkl"
76
 
77
  if os.path.exists(scores_file):
78
+ # print(f" 📂 {sym} ready.")
79
  return True
80
 
81
  print(f" ⚙️ Simulating {sym}...", end="", flush=True)
82
 
 
83
  all_candles_1m = []
84
  df_1m = None
85
  frames = {}
 
203
  # PHASE 1: Main Loop
204
  # ==============================================================
205
  async def generate_truth_data(self):
206
+ if self.force_start_date and self.force_end_date:
207
+ dt_start = datetime.strptime(self.force_start_date, "%Y-%m-%d").replace(tzinfo=timezone.utc)
208
+ dt_end = datetime.strptime(self.force_end_date, "%Y-%m-%d").replace(tzinfo=timezone.utc)
209
+ start_time_ms = int(dt_start.timestamp() * 1000)
210
+ end_time_ms = int(dt_end.timestamp() * 1000)
211
+ print(f"\n🚜 [Phase 1] Processing Era: {self.force_start_date} -> {self.force_end_date}")
212
+ else:
213
+ return
214
 
215
  chunk_size = 4
216
  chunks = [self.TARGET_COINS[i:i + chunk_size] for i in range(0, len(self.TARGET_COINS), chunk_size)]
217
 
218
  for chunk_idx, chunk in enumerate(chunks):
219
+ # print(f"--- Processing Batch {chunk_idx + 1}/{len(chunks)} ---")
220
  for sym in chunk:
221
  try:
222
  await asyncio.wait_for(
223
  self._process_single_coin_task(sym, start_time_ms, end_time_ms),
224
+ timeout=300.0
225
  )
226
  except asyncio.TimeoutError:
227
+ print(f" 💀 Killed {sym}. Moving on...")
228
  gc.collect()
 
229
  gc.collect()
230
+ await asyncio.sleep(1.0)
231
 
232
  # ==============================================================
233
  # PHASE 2: Portfolio Digital Twin Engine
 
257
  entry_thresh = config['thresh']
258
 
259
  for ts, group in grouped_by_time:
260
+ # Exit
261
  active_symbols = list(wallet["positions"].keys())
262
  current_prices = {row['symbol']: row['close'] for _, row in group.iterrows()}
263
 
 
277
  del wallet["positions"][sym]
278
  wallet["trades_history"].append({'pnl': net_pnl})
279
 
280
+ # Entry
281
  if len(wallet["positions"]) < max_slots:
282
  free_capital = wallet["balance"] - wallet["allocated"]
283
  slots_left = max_slots - len(wallet["positions"])
 
310
 
311
  if wallet["balance"] < 1.0 and len(wallet["positions"]) == 0: break
312
 
 
313
  trades = wallet["trades_history"]
314
  if trades:
315
  net_profit = wallet["balance"] - initial_capital
316
  pnls = [t['pnl'] for t in trades]
317
  wins = [p for p in pnls if p > 0]
318
  losses = [p for p in pnls if p <= 0]
319
+ win_rate = (len(wins) / len(trades)) * 100
320
+ max_dd = 0 # Simplified for speed
321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  results.append({
323
  'config': config,
324
  'final_balance': wallet["balance"],
325
  'net_profit': net_profit,
326
+ 'total_trades': len(trades),
 
327
  'win_rate': win_rate,
328
+ 'max_drawdown': max_dd
 
329
  })
330
  else:
331
+ results.append({'config': config, 'final_balance': initial_capital, 'net_profit': 0.0, 'total_trades': 0, 'win_rate': 0.0, 'max_drawdown': 0})
 
 
 
 
332
 
333
  return results
334
 
335
+ async def run_optimization(self, target_regime="RANGE"):
 
 
 
336
  await self.generate_truth_data()
337
 
338
+ # فلترة الملفات حسب الفترة الزمنية الحالية فقط
339
+ # نستخدم التواريخ في اسم الملف لضمان العزل
340
+ start_ts = int(datetime.strptime(self.force_start_date, "%Y-%m-%d").replace(tzinfo=timezone.utc).timestamp() * 1000)
341
+ end_ts = int(datetime.strptime(self.force_end_date, "%Y-%m-%d").replace(tzinfo=timezone.utc).timestamp() * 1000)
342
+ period_id = f"{start_ts}_{end_ts}"
343
+
344
+ current_period_files = []
345
+ for f in os.listdir(CACHE_DIR):
346
+ if f.endswith('_scores.pkl') and period_id in f:
347
+ current_period_files.append(os.path.join(CACHE_DIR, f))
348
+
349
+ if not current_period_files:
350
+ print(f"❌ No signals for {target_regime} ({self.force_start_date}).")
351
  return None
352
 
353
+ print(f"\n🧩 [Phase 2] Optimizing for {target_regime}...")
354
  print(f" 💰 Start Capital: ${self.INITIAL_CAPITAL}")
355
 
356
  w_titan_range = np.linspace(0.4, 0.9, num=self.GRID_DENSITY)
357
  w_struct_range = np.linspace(0.1, 0.6, num=self.GRID_DENSITY)
358
+ # نستخدم طيف واسع جداً (0.20 - 0.85) لنغطي كل الحالات
359
+ thresh_range = np.linspace(0.20, 0.85, num=self.GRID_DENSITY)
 
360
 
361
  combinations = []
362
  for wt, ws, th in itertools.product(w_titan_range, w_struct_range, thresh_range):
363
  if 0.9 <= (wt + ws) <= 1.1:
364
  combinations.append({'w_titan': round(wt, 2), 'w_struct': round(ws, 2), 'thresh': round(th, 2)})
365
 
 
 
366
  final_results = []
367
  batch_size = max(20, len(combinations) // (os.cpu_count() * 2))
368
  batches = [combinations[i:i+batch_size] for i in range(0, len(combinations), batch_size)]
369
 
370
  with concurrent.futures.ProcessPoolExecutor() as executor:
371
+ futures = [executor.submit(self._worker_optimize, batch, current_period_files,
372
  self.INITIAL_CAPITAL, self.TRADING_FEES, self.MAX_SLOTS)
373
  for batch in batches]
374
  for future in concurrent.futures.as_completed(futures):
375
  try: final_results.extend(future.result())
376
  except Exception as e: print(f"Grid Error: {e}")
377
 
378
+ if not final_results: return None
 
 
379
 
380
  best = sorted(final_results, key=lambda x: x['final_balance'], reverse=True)[0]
381
 
382
  print("\n" + "="*60)
383
+ print(f"🏆 CHAMPION REPORT [{target_regime}]:")
384
+ print(f" 📅 Period: {self.force_start_date} -> {self.force_end_date}")
385
+ print(f" 💰 Final Balance: ${best['final_balance']:,.2f}")
386
+ print(f" 🚀 Net PnL: ${best['net_profit']:,.2f}")
387
+ print(f" 📈 Win Rate: {best['win_rate']:.1f}%")
 
 
 
 
 
 
 
 
 
388
  print(f" ⚙️ Config: Titan={best['config']['w_titan']} | Struct={best['config']['w_struct']} | Thresh={best['config']['thresh']}")
389
  print("="*60)
390
 
391
  return best['config']
392
 
393
  async def run_strategic_optimization_task():
394
+ print("\n🧪 [STRATEGIC BACKTEST] Time Lord Initiated...")
395
  r2 = R2Service()
396
  dm = DataManager(None, None, r2)
397
  proc = MLProcessor(dm)
 
400
  await proc.initialize()
401
 
402
  try:
403
+ hub = AdaptiveHub(r2)
404
+ await hub.initialize()
405
+
406
+ # 🔥🔥🔥 خريطة السيناريوهات الشاملة (The Master Plan) 🔥🔥🔥
407
+ # التواريخ التي حددتها أنت بدقة
408
+ scenarios = [
409
+ # 1. BULL SCENARIOS (أقوى موجات الصعود)
410
+ # سنستخدم "موجة اعتماد ETF" كمعيار للبول رن
411
+ {"regime": "BULL", "start": "2024-01-01", "end": "2024-03-30"},
412
+
413
+ # 2. BEAR SCENARIOS (أقوى موجات الهبوط)
414
+ # سنستخدم "التصحيح العنيف" كمعيار للهبوط
415
+ {"regime": "BEAR", "start": "2023-08-01", "end": "2023-09-15"},
416
+
417
+ # 3. DEAD SCENARIOS (الركود القاتل)
418
+ # سنستخدم "يونيو 2023" كمعيار للموت السريري
419
+ {"regime": "DEAD", "start": "2023-06-01", "end": "2023-08-01"},
420
+
421
+ # 4. RANGE SCENARIOS (التذبذب الممل)
422
+ # سنستخدم "يوليو 2024" كمعيار للعرضية
423
+ {"regime": "RANGE", "start": "2024-07-01", "end": "2024-09-30"}
424
+ ]
425
+
426
  optimizer = HeavyDutyBacktester(dm, proc)
 
427
 
428
+ for scen in scenarios:
429
+ target = scen["regime"]
430
+ optimizer.set_date_range(scen["start"], scen["end"])
 
431
 
432
+ # تشغيل التحسين لهذه الحقبة
433
+ best_config = await optimizer.run_optimization(target_regime=target)
434
+
435
+ # حفظ النتائج فوراً في الذاكرة
436
+ if best_config and target in hub.strategies:
437
+ print(f"💉 Injecting Optimized DNA into {target}...")
438
+ st = hub.strategies[target]
439
  st.model_weights['titan'] = best_config['w_titan']
440
  st.model_weights['structure'] = best_config['w_struct']
441
  st.filters['l1_min_score'] = best_config['thresh']
442
+
443
+ # بعد انتهاء كل السيناريوهات، نحفظ الملف النهائي
444
+ await hub._save_state_to_r2()
445
+ hub._inject_current_parameters() # تفعيل الحالة الحالية
446
+ print(f"✅ [System] ALL DNA Updated & Saved Successfully.")
447
 
 
 
 
448
  finally:
449
  await dm.close()
450