Riy777 commited on
Commit
2ec3ab9
·
verified ·
1 Parent(s): cda2b97

Update backtest_engine.py

Browse files
Files changed (1) hide show
  1. backtest_engine.py +22 -39
backtest_engine.py CHANGED
@@ -1,5 +1,5 @@
1
  # ============================================================
2
- # 🧪 backtest_engine.py (V85.0 - GEM-Architect: Full Audit)
3
  # ============================================================
4
 
5
  import asyncio
@@ -17,7 +17,6 @@ from typing import Dict, Any, List
17
  try:
18
  from ml_engine.processor import MLProcessor, SystemLimits
19
  from ml_engine.data_manager import DataManager
20
- # ✅ استيراد كامل للهب والاستراتيجية
21
  from learning_hub.adaptive_hub import StrategyDNA, AdaptiveHub
22
  from r2 import R2Service
23
  except ImportError:
@@ -36,7 +35,6 @@ class HeavyDutyBacktester:
36
  self.TRADING_FEES = 0.001
37
  self.MAX_SLOTS = 4
38
 
39
- # القائمة الكاملة (50 عملة)
40
  self.TARGET_COINS = [
41
  'SOL/USDT', 'XRP/USDT', 'DOGE/USDT', 'ADA/USDT', 'AVAX/USDT',
42
  'LINK/USDT', 'TON/USDT', 'INJ/USDT', 'APT/USDT', 'OP/USDT',
@@ -54,7 +52,7 @@ class HeavyDutyBacktester:
54
  self.force_end_date = None
55
 
56
  if not os.path.exists(CACHE_DIR): os.makedirs(CACHE_DIR)
57
- print(f"🧪 [Backtest V85.0] Full Audit Mode (Detailed Stats).")
58
 
59
  def set_date_range(self, start_str, end_str):
60
  self.force_start_date = start_str
@@ -65,7 +63,7 @@ class HeavyDutyBacktester:
65
  return df[['timestamp', 'open', 'high', 'low', 'close', 'volume']].values.tolist()
66
 
67
  # ==============================================================
68
- # 🧱 Core Logic: Single Coin Processor (Safe Scope)
69
  # ==============================================================
70
  async def _process_single_coin_task(self, sym, start_time_ms, end_time_ms):
71
  safe_sym = sym.replace('/', '_')
@@ -85,7 +83,6 @@ class HeavyDutyBacktester:
85
 
86
  try:
87
  current_since = start_time_ms
88
- fetch_count = 0
89
 
90
  while current_since < end_time_ms:
91
  try:
@@ -94,7 +91,7 @@ class HeavyDutyBacktester:
94
  timeout=10.0
95
  )
96
  except:
97
- print(f" ⚠️ [{sym}] Retry...", flush=True)
98
  await asyncio.sleep(1)
99
  continue
100
 
@@ -105,10 +102,8 @@ class HeavyDutyBacktester:
105
 
106
  all_candles_1m.extend(batch)
107
  current_since = last_ts + 1
108
- fetch_count += 1
109
 
110
- if fetch_count % 5 == 0:
111
- print(f" -> [{sym}] Fetched {len(all_candles_1m)} candles...", flush=True)
112
 
113
  await asyncio.sleep(0.01)
114
  if current_since >= end_time_ms: break
@@ -116,10 +111,11 @@ class HeavyDutyBacktester:
116
  all_candles_1m = [c for c in all_candles_1m if c[0] <= end_time_ms]
117
 
118
  if not all_candles_1m:
119
- print(f" [{sym}] No data.")
120
  return False
121
 
122
- print(f" [{sym}] Downloaded {len(all_candles_1m)} candles. Processing...", flush=True)
 
123
 
124
  df_1m = pd.DataFrame(all_candles_1m, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
125
  cols = ['open', 'high', 'low', 'close', 'volume']
@@ -242,7 +238,7 @@ class HeavyDutyBacktester:
242
  await asyncio.sleep(1.0)
243
 
244
  # ==============================================================
245
- # PHASE 2: Portfolio Digital Twin Engine (Full Audit Stats)
246
  # ==============================================================
247
  @staticmethod
248
  def _worker_optimize(combinations_batch, scores_files, initial_capital, fees_pct, max_slots):
@@ -267,7 +263,7 @@ class HeavyDutyBacktester:
267
  w_struct = config['w_struct']
268
  entry_thresh = config['thresh']
269
 
270
- # تتبع الـ Drawdown
271
  peak_balance = initial_capital
272
  max_drawdown = 0.0
273
 
@@ -275,7 +271,7 @@ class HeavyDutyBacktester:
275
  active_symbols = list(wallet["positions"].keys())
276
  current_prices = {row['symbol']: row['close'] for _, row in group.iterrows()}
277
 
278
- # 1. Check Exits
279
  for sym in active_symbols:
280
  if sym in current_prices:
281
  curr_p = current_prices[sym]
@@ -292,15 +288,12 @@ class HeavyDutyBacktester:
292
  del wallet["positions"][sym]
293
  wallet["trades_history"].append({'pnl': net_pnl})
294
 
295
- # تحديث قمة الرصيد وحساب Drawdown
296
- current_total_equity = wallet["balance"] # نتجاهل العائم للسرعة، نحسب المحقق فقط
297
- if current_total_equity > peak_balance:
298
- peak_balance = current_total_equity
299
-
300
  dd = (peak_balance - current_total_equity) / peak_balance
301
  if dd > max_drawdown: max_drawdown = dd
302
 
303
- # 2. Check Entries
304
  if len(wallet["positions"]) < max_slots:
305
  free_capital = wallet["balance"] - wallet["allocated"]
306
  slots_left = max_slots - len(wallet["positions"])
@@ -333,7 +326,6 @@ class HeavyDutyBacktester:
333
 
334
  if wallet["balance"] < 1.0 and len(wallet["positions"]) == 0: break
335
 
336
- # 🔥🔥🔥 حساب الإحصائيات التفصيلية الكاملة 🔥🔥🔥
337
  trades = wallet["trades_history"]
338
  if trades:
339
  net_profit = wallet["balance"] - initial_capital
@@ -341,26 +333,20 @@ class HeavyDutyBacktester:
341
  wins = [p for p in pnls if p > 0]
342
  losses = [p for p in pnls if p <= 0]
343
 
 
344
  total_trades = len(trades)
345
- win_count = len(wins)
346
- loss_count = len(losses)
347
  win_rate = (win_count / total_trades) * 100 if total_trades > 0 else 0
348
-
349
  max_single_win = max(pnls) if pnls else 0.0
350
  max_single_loss = min(pnls) if pnls else 0.0
351
 
352
- # حساب السلاسل المتتالية
353
  current_win_streak = 0; max_win_streak = 0
354
  current_loss_streak = 0; max_loss_streak = 0
355
-
356
  for p in pnls:
357
  if p > 0:
358
- current_win_streak += 1
359
- current_loss_streak = 0
360
  if current_win_streak > max_win_streak: max_win_streak = current_win_streak
361
  else:
362
- current_loss_streak += 1
363
- current_win_streak = 0
364
  if current_loss_streak > max_loss_streak: max_loss_streak = current_loss_streak
365
 
366
  results.append({
@@ -368,14 +354,11 @@ class HeavyDutyBacktester:
368
  'final_balance': wallet["balance"],
369
  'net_profit': net_profit,
370
  'total_trades': total_trades,
371
- 'win_count': win_count,
372
- 'loss_count': loss_count,
373
  'win_rate': win_rate,
374
- 'max_single_win': max_single_win,
375
- 'max_single_loss': max_single_loss,
376
- 'max_win_streak': max_win_streak,
377
- 'max_loss_streak': max_loss_streak,
378
- 'max_drawdown': max_drawdown * 100 # كنسبة مئوية
379
  })
380
  else:
381
  results.append({
@@ -431,7 +414,7 @@ class HeavyDutyBacktester:
431
 
432
  best = sorted(final_results, key=lambda x: x['final_balance'], reverse=True)[0]
433
 
434
- # 🔥🔥🔥 The Full Audit Report 🔥🔥🔥
435
  print("\n" + "="*60)
436
  print(f"🏆 CHAMPION REPORT [{target_regime}]:")
437
  print(f" 📅 Period: {self.force_start_date} -> {self.force_end_date}")
 
1
  # ============================================================
2
+ # 🧪 backtest_engine.py (V85.1 - GEM-Architect: Silent Fetcher)
3
  # ============================================================
4
 
5
  import asyncio
 
17
  try:
18
  from ml_engine.processor import MLProcessor, SystemLimits
19
  from ml_engine.data_manager import DataManager
 
20
  from learning_hub.adaptive_hub import StrategyDNA, AdaptiveHub
21
  from r2 import R2Service
22
  except ImportError:
 
35
  self.TRADING_FEES = 0.001
36
  self.MAX_SLOTS = 4
37
 
 
38
  self.TARGET_COINS = [
39
  'SOL/USDT', 'XRP/USDT', 'DOGE/USDT', 'ADA/USDT', 'AVAX/USDT',
40
  'LINK/USDT', 'TON/USDT', 'INJ/USDT', 'APT/USDT', 'OP/USDT',
 
52
  self.force_end_date = None
53
 
54
  if not os.path.exists(CACHE_DIR): os.makedirs(CACHE_DIR)
55
+ print(f"🧪 [Backtest V85.1] Silent Fetcher Mode (Clean Logs).")
56
 
57
  def set_date_range(self, start_str, end_str):
58
  self.force_start_date = start_str
 
63
  return df[['timestamp', 'open', 'high', 'low', 'close', 'volume']].values.tolist()
64
 
65
  # ==============================================================
66
+ # 🧱 Core Logic: Single Coin Processor
67
  # ==============================================================
68
  async def _process_single_coin_task(self, sym, start_time_ms, end_time_ms):
69
  safe_sym = sym.replace('/', '_')
 
83
 
84
  try:
85
  current_since = start_time_ms
 
86
 
87
  while current_since < end_time_ms:
88
  try:
 
91
  timeout=10.0
92
  )
93
  except:
94
+ # صامت عند إعادة المحاولة
95
  await asyncio.sleep(1)
96
  continue
97
 
 
102
 
103
  all_candles_1m.extend(batch)
104
  current_since = last_ts + 1
 
105
 
106
+ # 🔇 [Removed] Intermediate print logic here
 
107
 
108
  await asyncio.sleep(0.01)
109
  if current_since >= end_time_ms: break
 
111
  all_candles_1m = [c for c in all_candles_1m if c[0] <= end_time_ms]
112
 
113
  if not all_candles_1m:
114
+ print(f" ❌ No data.")
115
  return False
116
 
117
+ # طباعة واحدة عند الانتهاء
118
+ print(f" ✅ Downloaded {len(all_candles_1m)} candles. Processing...", flush=True)
119
 
120
  df_1m = pd.DataFrame(all_candles_1m, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
121
  cols = ['open', 'high', 'low', 'close', 'volume']
 
238
  await asyncio.sleep(1.0)
239
 
240
  # ==============================================================
241
+ # PHASE 2: Portfolio Digital Twin Engine
242
  # ==============================================================
243
  @staticmethod
244
  def _worker_optimize(combinations_batch, scores_files, initial_capital, fees_pct, max_slots):
 
263
  w_struct = config['w_struct']
264
  entry_thresh = config['thresh']
265
 
266
+ # Tracking Drawdown
267
  peak_balance = initial_capital
268
  max_drawdown = 0.0
269
 
 
271
  active_symbols = list(wallet["positions"].keys())
272
  current_prices = {row['symbol']: row['close'] for _, row in group.iterrows()}
273
 
274
+ # Check Exits
275
  for sym in active_symbols:
276
  if sym in current_prices:
277
  curr_p = current_prices[sym]
 
288
  del wallet["positions"][sym]
289
  wallet["trades_history"].append({'pnl': net_pnl})
290
 
291
+ current_total_equity = wallet["balance"]
292
+ if current_total_equity > peak_balance: peak_balance = current_total_equity
 
 
 
293
  dd = (peak_balance - current_total_equity) / peak_balance
294
  if dd > max_drawdown: max_drawdown = dd
295
 
296
+ # Check Entries
297
  if len(wallet["positions"]) < max_slots:
298
  free_capital = wallet["balance"] - wallet["allocated"]
299
  slots_left = max_slots - len(wallet["positions"])
 
326
 
327
  if wallet["balance"] < 1.0 and len(wallet["positions"]) == 0: break
328
 
 
329
  trades = wallet["trades_history"]
330
  if trades:
331
  net_profit = wallet["balance"] - initial_capital
 
333
  wins = [p for p in pnls if p > 0]
334
  losses = [p for p in pnls if p <= 0]
335
 
336
+ win_count = len(wins); loss_count = len(losses)
337
  total_trades = len(trades)
 
 
338
  win_rate = (win_count / total_trades) * 100 if total_trades > 0 else 0
 
339
  max_single_win = max(pnls) if pnls else 0.0
340
  max_single_loss = min(pnls) if pnls else 0.0
341
 
 
342
  current_win_streak = 0; max_win_streak = 0
343
  current_loss_streak = 0; max_loss_streak = 0
 
344
  for p in pnls:
345
  if p > 0:
346
+ current_win_streak += 1; current_loss_streak = 0
 
347
  if current_win_streak > max_win_streak: max_win_streak = current_win_streak
348
  else:
349
+ current_loss_streak += 1; current_win_streak = 0
 
350
  if current_loss_streak > max_loss_streak: max_loss_streak = current_loss_streak
351
 
352
  results.append({
 
354
  'final_balance': wallet["balance"],
355
  'net_profit': net_profit,
356
  'total_trades': total_trades,
357
+ 'win_count': win_count, 'loss_count': loss_count,
 
358
  'win_rate': win_rate,
359
+ 'max_single_win': max_single_win, 'max_single_loss': max_single_loss,
360
+ 'max_win_streak': max_win_streak, 'max_loss_streak': max_loss_streak,
361
+ 'max_drawdown': max_drawdown * 100
 
 
362
  })
363
  else:
364
  results.append({
 
414
 
415
  best = sorted(final_results, key=lambda x: x['final_balance'], reverse=True)[0]
416
 
417
+ # 🔥🔥🔥 Full Report 🔥🔥🔥
418
  print("\n" + "="*60)
419
  print(f"🏆 CHAMPION REPORT [{target_regime}]:")
420
  print(f" 📅 Period: {self.force_start_date} -> {self.force_end_date}")