GoshawkVortexAI commited on
Commit
60ab4aa
·
verified ·
1 Parent(s): 6d785c6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -25
app.py CHANGED
@@ -477,8 +477,27 @@ def _models():
477
  }
478
 
479
 
480
- def _fit_predict(Xtr, ytr, Xte, w=None):
481
- """Ensemble: HGB + ExtraTrees + Logistic -> olasılık ortalaması."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
482
  ps = []
483
  for name, m in _models().items():
484
  if name == "lr":
@@ -508,7 +527,25 @@ def _backtest(p, fwd, horizon, thr, fee):
508
  "hit": float((tr > 0).mean()), "pf": float(gp / gl) if gl > 0 else np.inf}
509
 
510
 
511
- def predict(df: pd.DataFrame, horizon: int, fee: float = 0.0006, n_folds: int = 5, ext=None):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
512
  feats, atr = make_features(df)
513
  n_ext = 0
514
  if ext is not None:
@@ -543,24 +580,20 @@ def predict(df: pd.DataFrame, horizon: int, fee: float = 0.0006, n_folds: int =
543
  # ve büyük hareketlere daha fazla ağırlık ver.
544
  W = np.clip(np.abs(F) / (TM + 1e-12), 0.05, 3.0)
545
 
546
- # --- Purged walk-forward (expanding window) ---
547
- n = len(X)
548
- start = int(n * 0.4)
549
- edges = np.linspace(start, n, n_folds + 1).astype(int)
550
- oos_p, oos_idx = [], []
551
- for k in range(n_folds):
552
- tr_end, te0, te1 = edges[k] - horizon, edges[k], edges[k + 1]
553
- if tr_end < 80:
554
- continue
555
- p = _fit_predict(X.iloc[:tr_end], Y.iloc[:tr_end], X.iloc[te0:te1], W[:tr_end])
556
- oos_p.append(p)
557
- oos_idx.extend(range(te0, te1))
558
- if not oos_p:
559
- raise ValueError("Walk-forward için yeterli veri yok. Mum sayısını artır.")
560
- oos_p = np.concatenate(oos_p)
561
- oos_idx = np.array(oos_idx)
562
  yo, fo = Y.values[oos_idx], F[oos_idx]
563
 
 
 
 
 
 
 
 
 
 
 
564
  acc = float(((oos_p > 0.5).astype(int) == yo).mean())
565
  base = float(max(yo.mean(), 1 - yo.mean()))
566
  try:
@@ -576,7 +609,7 @@ def predict(df: pd.DataFrame, horizon: int, fee: float = 0.0006, n_folds: int =
576
  best = {"thr": thr, **r}
577
 
578
  # Son model: tüm veriyle, canlı tahmin
579
- final_p = _fit_predict(X, Y, feats.iloc[[-1]][cols].ffill().fillna(0), W)
580
  p_up = float(final_p[0])
581
 
582
  price, a = float(close.iloc[-1]), float(atr.iloc[-1])
@@ -586,7 +619,7 @@ def predict(df: pd.DataFrame, horizon: int, fee: float = 0.0006, n_folds: int =
586
  "p_up": p_up, "acc": acc, "baseline": base, "auc": auc, "price": price, "atr": a,
587
  "center": center, "low": center - move, "high": center + move,
588
  "thr": best["thr"], "bt": best, "n_oos": len(oos_p), "fee": fee,
589
- "n_ext": n_ext, "n_feat": len(cols),
590
  }
591
 
592
 
@@ -631,7 +664,7 @@ def _root(e):
631
  return f"{type(e).__name__}: {e}"
632
 
633
 
634
- def run(symbol, timeframe, exchange, horizon, limit, use_deriv=True):
635
  try:
636
  ohlcv, deep, ind, extra = asyncio.run(run_async(symbol, timeframe, exchange, horizon, limit))
637
  df = to_df(ohlcv)
@@ -642,7 +675,7 @@ def run(symbol, timeframe, exchange, horizon, limit, use_deriv=True):
642
  ext = indicator_features(ind, df)
643
  if dfeat is not None:
644
  ext = dfeat if ext is None else pd.concat([ext, dfeat], axis=1)
645
- res = predict(df, int(horizon), ext=ext)
646
  except BaseException as e: # noqa: BLE001
647
  import traceback
648
  traceback.print_exc()
@@ -662,7 +695,8 @@ def run(symbol, timeframe, exchange, horizon, limit, use_deriv=True):
662
  | OOS AUC / doğruluk | {res['auc']:.3f} / {res['acc']:.1%} (baseline {res['baseline']:.1%}) |
663
  | OOS işlem sayısı | {bt['n']} (hit {bt['hit']:.1%}, PF {bt['pf']:.2f}) |
664
  | Ort. net getiri / işlem | {bt['mean']:.3%} (t = {bt['t']:.2f}, ücret {res['fee']:.2%}/işlem) |
665
- | Özellik sayısı | {res['n_feat']} (Tickscope göstergesi: {res['n_ext']}) |
 
666
  | Model edge | {edge} |
667
 
668
  *Walk-forward (purged) out-of-sample sonuçlar. Eşik OOS'ta seçildiği için hafif iyimser olabilir. Eğitim/araştırma amaçlıdır; yatırım tavsiyesi değildir.*"""
@@ -695,12 +729,13 @@ with gr.Blocks(title="Tickscope Tahmin") as demo:
695
  horizon = gr.Slider(1, 24, value=4, step=1, label="Tahmin ufku (bar)")
696
  limit = gr.Slider(300, 20000, value=5000, step=100, label="Mum sayısı (1000 üstü sayfalanır)")
697
  use_deriv = gr.Checkbox(True, label="Türev verisi (LiquidVision MCP: funding/OI) — mumları geçmişin kapsadığı aralığa kırpabilir")
 
698
  btn = gr.Button("Tahmin et", variant="primary")
699
  out_md = gr.Markdown()
700
  out_plot = gr.Plot()
701
  with gr.Accordion("Tickscope ham çıktı (deep_analyze / indicators)", open=False):
702
  out_raw = gr.Code(language="json")
703
- btn.click(run, [symbol, timeframe, exchange, horizon, limit, use_deriv], [out_md, out_plot, out_raw])
704
 
705
  if __name__ == "__main__":
706
  demo.launch()
 
477
  }
478
 
479
 
480
+ def _select(Xtr, ftr, k, thr=0.95):
481
+ """Yalnızca EĞİTİM verisiyle: |Spearman IC| sırasına göre, birbirine çok benzeyenleri (>thr) eleyerek k özellik seç."""
482
+ if k <= 0 or Xtr.shape[1] <= k:
483
+ return list(Xtr.columns)
484
+ ic = Xtr.rank().corrwith(pd.Series(np.asarray(ftr), index=Xtr.index).rank()).abs().fillna(0)
485
+ ic = ic.sort_values(ascending=False)
486
+ corr = Xtr.corr().abs().fillna(0)
487
+ keep = []
488
+ for c in ic.index:
489
+ if all(corr.at[c, o] < thr for o in keep):
490
+ keep.append(c)
491
+ if len(keep) >= k:
492
+ break
493
+ return keep
494
+
495
+
496
+ def _fit_predict(Xtr, ytr, Xte, w=None, ftr=None, k=0):
497
+ """Ensemble: HGB + ExtraTrees + Logistic -> olasılık ortalaması (k>0 ise fold-içi özellik seçimi)."""
498
+ if k and ftr is not None:
499
+ sel = _select(Xtr, ftr, k)
500
+ Xtr, Xte = Xtr[sel], Xte[sel]
501
  ps = []
502
  for name, m in _models().items():
503
  if name == "lr":
 
527
  "hit": float((tr > 0).mean()), "pf": float(gp / gl) if gl > 0 else np.inf}
528
 
529
 
530
+ def _walk(X, Y, F, W, horizon, n_folds, k):
531
+ """Purged expanding-window walk-forward; OOS olasılıkları ve satır indeksleri."""
532
+ n = len(X)
533
+ edges = np.linspace(int(n * 0.4), n, n_folds + 1).astype(int)
534
+ oos_p, oos_idx = [], []
535
+ for j in range(n_folds):
536
+ tr_end, te0, te1 = edges[j] - horizon, edges[j], edges[j + 1]
537
+ if tr_end < 80:
538
+ continue
539
+ oos_p.append(_fit_predict(X.iloc[:tr_end], Y.iloc[:tr_end], X.iloc[te0:te1],
540
+ W[:tr_end], F[:tr_end], k))
541
+ oos_idx.extend(range(te0, te1))
542
+ if not oos_p:
543
+ raise ValueError("Walk-forward için yeterli veri yok. Mum sayısını artır.")
544
+ return np.concatenate(oos_p), np.array(oos_idx)
545
+
546
+
547
+ def predict(df: pd.DataFrame, horizon: int, fee: float = 0.0006, n_folds: int = 5, ext=None,
548
+ max_feat: int = 40):
549
  feats, atr = make_features(df)
550
  n_ext = 0
551
  if ext is not None:
 
580
  # ve büyük hareketlere daha fazla ağırlık ver.
581
  W = np.clip(np.abs(F) / (TM + 1e-12), 0.05, 3.0)
582
 
583
+ # --- Purged walk-forward (expanding window), fold-içi özellik seçimiyle ---
584
+ oos_p, oos_idx = _walk(X, Y, F, W, horizon, n_folds, max_feat)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
585
  yo, fo = Y.values[oos_idx], F[oos_idx]
586
 
587
+ # Teşhis (ablation): yalnızca temel (fiyat/hacim) özelliklerle aynı test
588
+ base_cols = [c for c in cols if not c.startswith(("ts_", "dv_"))]
589
+ auc_base = None
590
+ if len(base_cols) < len(cols):
591
+ pb, ib = _walk(X[base_cols], Y, F, W, horizon, n_folds, max_feat)
592
+ try:
593
+ auc_base = float(roc_auc_score(Y.values[ib], pb))
594
+ except ValueError:
595
+ auc_base = 0.5
596
+
597
  acc = float(((oos_p > 0.5).astype(int) == yo).mean())
598
  base = float(max(yo.mean(), 1 - yo.mean()))
599
  try:
 
609
  best = {"thr": thr, **r}
610
 
611
  # Son model: tüm veriyle, canlı tahmin
612
+ final_p = _fit_predict(X, Y, feats.iloc[[-1]][cols].ffill().fillna(0), W, F, max_feat)
613
  p_up = float(final_p[0])
614
 
615
  price, a = float(close.iloc[-1]), float(atr.iloc[-1])
 
619
  "p_up": p_up, "acc": acc, "baseline": base, "auc": auc, "price": price, "atr": a,
620
  "center": center, "low": center - move, "high": center + move,
621
  "thr": best["thr"], "bt": best, "n_oos": len(oos_p), "fee": fee,
622
+ "n_ext": n_ext, "n_feat": len(cols), "auc_base": auc_base, "max_feat": max_feat,
623
  }
624
 
625
 
 
664
  return f"{type(e).__name__}: {e}"
665
 
666
 
667
+ def run(symbol, timeframe, exchange, horizon, limit, use_deriv=True, max_feat=40):
668
  try:
669
  ohlcv, deep, ind, extra = asyncio.run(run_async(symbol, timeframe, exchange, horizon, limit))
670
  df = to_df(ohlcv)
 
675
  ext = indicator_features(ind, df)
676
  if dfeat is not None:
677
  ext = dfeat if ext is None else pd.concat([ext, dfeat], axis=1)
678
+ res = predict(df, int(horizon), ext=ext, max_feat=int(max_feat))
679
  except BaseException as e: # noqa: BLE001
680
  import traceback
681
  traceback.print_exc()
 
695
  | OOS AUC / doğruluk | {res['auc']:.3f} / {res['acc']:.1%} (baseline {res['baseline']:.1%}) |
696
  | OOS işlem sayısı | {bt['n']} (hit {bt['hit']:.1%}, PF {bt['pf']:.2f}) |
697
  | Ort. net getiri / işlem | {bt['mean']:.3%} (t = {bt['t']:.2f}, ücret {res['fee']:.2%}/işlem) |
698
+ | Özellik sayısı | {res['n_feat']} (Tickscope/türev: {res['n_ext']}) → fold başına en fazla {res['max_feat']} seçilir |
699
+ | AUC yalnızca temel özelliklerle | {('%.3f' % res['auc_base']) if res['auc_base'] is not None else '—'} (ek veri kaynakları yardım ediyor mu?) |
700
  | Model edge | {edge} |
701
 
702
  *Walk-forward (purged) out-of-sample sonuçlar. Eşik OOS'ta seçildiği için hafif iyimser olabilir. Eğitim/araştırma amaçlıdır; yatırım tavsiyesi değildir.*"""
 
729
  horizon = gr.Slider(1, 24, value=4, step=1, label="Tahmin ufku (bar)")
730
  limit = gr.Slider(300, 20000, value=5000, step=100, label="Mum sayısı (1000 üstü sayfalanır)")
731
  use_deriv = gr.Checkbox(True, label="Türev verisi (LiquidVision MCP: funding/OI) — mumları geçmişin kapsadığı aralığa kırpabilir")
732
+ max_feat = gr.Slider(10, 150, value=40, step=5, label="Maks. özellik (fold içinde seçilir; az = daha az aşırı uyum)")
733
  btn = gr.Button("Tahmin et", variant="primary")
734
  out_md = gr.Markdown()
735
  out_plot = gr.Plot()
736
  with gr.Accordion("Tickscope ham çıktı (deep_analyze / indicators)", open=False):
737
  out_raw = gr.Code(language="json")
738
+ btn.click(run, [symbol, timeframe, exchange, horizon, limit, use_deriv, max_feat], [out_md, out_plot, out_raw])
739
 
740
  if __name__ == "__main__":
741
  demo.launch()