Riy777 commited on
Commit
d1993c5
·
verified ·
1 Parent(s): 554b04f

Update backtest_engine.py

Browse files
Files changed (1) hide show
  1. backtest_engine.py +67 -59
backtest_engine.py CHANGED
@@ -285,68 +285,42 @@ class HeavyDutyBacktester:
285
  l = df["low"].astype(np.float64)
286
  v = df["volume"].astype(np.float64) if "volume" in df.columns else pd.Series(np.zeros(len(df)), index=df.index)
287
 
288
- # ✅ [GEM-FIX] Calculate Slope for Oracle (prevents missing feature warning)
289
- try:
290
- df['slope'] = ta.slope(c, length=7).fillna(0)
291
- except:
292
- df['slope'] = 0.0
293
-
294
- # [GEM-FIX] Calculate MFI for Titan (prevents missing feature warning)
295
- try:
296
- df['MFI'] = ta.mfi(h, l, c, v, length=14).fillna(50)
297
- except:
298
- df['MFI'] = 50.0
299
-
300
- # EMAs
301
- for span in [9, 20, 21, 50, 200]:
302
- df[f"ema{span}"] = c.ewm(span=span, adjust=False).mean()
303
-
304
- # BBANDS
305
- if len(df) < 30:
306
- df["lower_bb"] = c
307
- df["upper_bb"] = c
308
- df["bb_width"] = 0.0
309
- df["bb_pct"] = 0.5
310
- else:
311
- bb = ta.bbands(c, length=20, std=2.0)
312
- if bb is None or (isinstance(bb, pd.DataFrame) and bb.shape[1] < 3):
313
- lower, upper, width, pct = self._safe_bbands(c, 20, 2.0)
314
- df["lower_bb"], df["upper_bb"], df["bb_width"], df["bb_pct"] = lower, upper, width, pct
315
- else:
316
- if isinstance(bb, pd.DataFrame):
317
- col_lower = [x for x in bb.columns if "BBL" in x]
318
- col_upper = [x for x in bb.columns if "BBU" in x]
319
- col_width = [x for x in bb.columns if "BBB" in x]
320
- col_pct = [x for x in bb.columns if "BBP" in x]
321
- if col_lower and col_upper:
322
- df["lower_bb"] = bb[col_lower[0]]
323
- df["upper_bb"] = bb[col_upper[0]]
324
- else:
325
- lower, upper, width, pct = self._safe_bbands(c, 20, 2.0)
326
- df["lower_bb"], df["upper_bb"] = lower, upper
327
- df["bb_width"] = bb[col_width[0]] if col_width else (df["upper_bb"] - df["lower_bb"]) / (c.abs() + 1e-12)
328
- df["bb_pct"] = bb[col_pct[0]] if col_pct else (c - df["lower_bb"]) / ((df["upper_bb"] - df["lower_bb"]) + 1e-12)
329
- else:
330
- lower, upper, width, pct = self._safe_bbands(c, 20, 2.0)
331
- df["lower_bb"], df["upper_bb"], df["bb_width"], df["bb_pct"] = lower, upper, width, pct
332
 
333
- # MACD
334
- macd = ta.macd(c)
335
- if macd is not None and isinstance(macd, pd.DataFrame) and macd.shape[1] >= 3:
336
- df["MACD"] = macd.iloc[:, 0]
337
- df["MACD_h"] = macd.iloc[:, 1]
338
- df["MACD_s"] = macd.iloc[:, 2]
339
- else:
340
- df["MACD"] = 0.0
341
- df["MACD_h"] = 0.0
342
- df["MACD_s"] = 0.0
343
 
344
- # Core
 
345
  df["RSI"] = ta.rsi(c, length=14).fillna(50)
 
 
346
  df["ATR"] = ta.atr(h, l, c, length=14).fillna(0)
 
 
 
 
 
 
 
347
 
 
348
  adx_df = ta.adx(h, l, c, length=14)
349
- df["ADX"] = adx_df.iloc[:, 0].fillna(0) if (adx_df is not None and isinstance(adx_df, pd.DataFrame) and adx_df.shape[1] >= 1) else 0.0
 
 
 
 
 
 
 
350
 
351
  try:
352
  df["CHOP"] = ta.chop(h, l, c, length=14).fillna(50)
@@ -358,19 +332,53 @@ class HeavyDutyBacktester:
358
  except:
359
  df["vwap"] = c
360
 
361
- # ✅ FIX: Add CCI (Titan expects features like 5m_CCI)
362
  try:
363
  df["CCI"] = ta.cci(h, l, c, length=20).fillna(0)
364
  except:
365
  df["CCI"] = 0.0
366
 
367
- # Derived
 
 
 
 
368
  df["EMA_9_dist"] = (c / (df["ema9"] + 1e-12)) - 1
369
  df["EMA_21_dist"] = (c / (df["ema21"] + 1e-12)) - 1
370
  df["EMA_50_dist"] = (c / (df["ema50"] + 1e-12)) - 1
371
  df["EMA_200_dist"] = (c / (df["ema200"] + 1e-12)) - 1
372
  df["VWAP_dist"] = (c / (df["vwap"] + 1e-12)) - 1
373
- df["ATR_pct"] = (df["ATR"] / (c + 1e-12)) * 100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
 
375
  mean_vol = v.rolling(50).mean() + 1e-9
376
  df["rel_vol"] = v / mean_vol
 
285
  l = df["low"].astype(np.float64)
286
  v = df["volume"].astype(np.float64) if "volume" in df.columns else pd.Series(np.zeros(len(df)), index=df.index)
287
 
288
+ # ----------------------------------------------------
289
+ # ✅ [GEM-FIX] جسر التوافق مع Oracle & Titan
290
+ # ----------------------------------------------------
291
+
292
+ # 1. Oracle: Slope
293
+ try: df['slope'] = ta.slope(c, length=7).fillna(0)
294
+ except: df['slope'] = 0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
 
296
+ # 2. Titan: MFI
297
+ try: df['MFI'] = ta.mfi(h, l, c, v, length=14).fillna(50)
298
+ except: df['MFI'] = 50.0
 
 
 
 
 
 
 
299
 
300
+ # 3. Oracle Mapping (LowerCase Aliases)
301
+ # يحسب المكتبة RSI، ونحن ننسخها إلى rsi لأن النموذج يطلبها صغيرة
302
  df["RSI"] = ta.rsi(c, length=14).fillna(50)
303
+ df["rsi"] = df["RSI"] # Alias for Oracle
304
+
305
  df["ATR"] = ta.atr(h, l, c, length=14).fillna(0)
306
+ df["ATR_pct"] = (df["ATR"] / (c + 1e-12)) * 100
307
+ df["atr_pct"] = df["ATR_pct"] # Alias for Oracle
308
+
309
+ # 4. Oracle: Volume Z-Score (vol_z)
310
+ vol_mean = v.rolling(20).mean()
311
+ vol_std = v.rolling(20).std()
312
+ df["vol_z"] = ((v - vol_mean) / (vol_std + 1e-9)).fillna(0) # For Oracle
313
 
314
+ # 5. Titan: Trend Strong (Approx for lower TFs, perfect for 1d)
315
  adx_df = ta.adx(h, l, c, length=14)
316
+ if adx_df is not None and not adx_df.empty:
317
+ df["ADX"] = adx_df.iloc[:, 0].fillna(0)
318
+ df["Trend_Strong"] = np.where(df["ADX"] > 25, 1, 0) # For Titan 1d
319
+ else:
320
+ df["ADX"] = 0.0
321
+ df["Trend_Strong"] = 0
322
+
323
+ # ----------------------------------------------------
324
 
325
  try:
326
  df["CHOP"] = ta.chop(h, l, c, length=14).fillna(50)
 
332
  except:
333
  df["vwap"] = c
334
 
 
335
  try:
336
  df["CCI"] = ta.cci(h, l, c, length=20).fillna(0)
337
  except:
338
  df["CCI"] = 0.0
339
 
340
+ # EMAs
341
+ for span in [9, 20, 21, 50, 200]:
342
+ df[f"ema{span}"] = c.ewm(span=span, adjust=False).mean()
343
+
344
+ # Derived Features
345
  df["EMA_9_dist"] = (c / (df["ema9"] + 1e-12)) - 1
346
  df["EMA_21_dist"] = (c / (df["ema21"] + 1e-12)) - 1
347
  df["EMA_50_dist"] = (c / (df["ema50"] + 1e-12)) - 1
348
  df["EMA_200_dist"] = (c / (df["ema200"] + 1e-12)) - 1
349
  df["VWAP_dist"] = (c / (df["vwap"] + 1e-12)) - 1
350
+
351
+ # BBANDS
352
+ if len(df) < 30:
353
+ df["lower_bb"] = c; df["upper_bb"] = c; df["bb_width"] = 0.0; df["bb_pct"] = 0.5
354
+ else:
355
+ bb = ta.bbands(c, length=20, std=2.0)
356
+ if bb is not None and isinstance(bb, pd.DataFrame):
357
+ col_w = [x for x in bb.columns if "BBB" in x]
358
+ col_p = [x for x in bb.columns if "BBP" in x]
359
+ col_l = [x for x in bb.columns if "BBL" in x]
360
+ col_u = [x for x in bb.columns if "BBU" in x]
361
+
362
+ df["bb_width"] = bb[col_w[0]] if col_w else 0.0
363
+ df["bb_pct"] = bb[col_p[0]] if col_p else 0.5
364
+ df["lower_bb"] = bb[col_l[0]] if col_l else c
365
+ df["upper_bb"] = bb[col_u[0]] if col_u else c
366
+
367
+ # Aliases for Titan
368
+ df["BB_w"] = df["bb_width"]
369
+ df["BB_p"] = df["bb_pct"]
370
+ else:
371
+ df["lower_bb"] = c; df["upper_bb"] = c; df["bb_width"] = 0.0; df["bb_pct"] = 0.5
372
+ df["BB_w"] = 0.0; df["BB_p"] = 0.5
373
+
374
+ # MACD
375
+ macd = ta.macd(c)
376
+ if macd is not None and not macd.empty:
377
+ df["MACD"] = macd.iloc[:, 0]
378
+ df["MACD_h"] = macd.iloc[:, 1]
379
+ df["MACD_s"] = macd.iloc[:, 2]
380
+ else:
381
+ df["MACD"] = 0.0; df["MACD_h"] = 0.0; df["MACD_s"] = 0.0
382
 
383
  mean_vol = v.rolling(50).mean() + 1e-9
384
  df["rel_vol"] = v / mean_vol