GoshawkVortexAI commited on
Commit
5e6d13f
·
verified ·
1 Parent(s): e1e3b82

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -21
app.py CHANGED
@@ -29,6 +29,7 @@ RR_GRID = [1.0, 1.25, 1.5, 2.0, 2.5, 3.0, 4.0]
29
  CLASSES = [-1, 0, 1]
30
  SIDE_MODES = ["Long + Short", "Sadece Long", "Sadece Short"]
31
  IND_MODES = ["Kapalı", "Onay filtresi (KNN + ST/UT)", "Sadece indikatör"]
 
32
  LDC_MODES = ["Kapalı", "Onay filtresi (Lorentzian)", "Sadece Lorentzian"]
33
  VP_MODES = ["Kapalı", "Onay filtresi (POC / Value Area)", "KNN özelliği + onay filtresi"]
34
 
@@ -405,13 +406,23 @@ def calibrate_current(raw_cal, y_cal, raw_cur, classes):
405
 
406
 
407
  # ---------------------------------------------------------------- bariyer / R
 
 
 
 
408
  def barrier_trade(A, i, side, sl_atr, rr, h):
409
  """(getiri, çıkış_pozisyonu, neden) döndürür. Aynı mumda SL+TP varsa SL kabul edilir."""
410
  entry, av = A["c"][i], A["a"][i]
411
  if not np.isfinite(av) or av <= 0 or not np.isfinite(entry):
412
  return None
413
- sd = sl_atr*av
414
- td = sd*rr
 
 
 
 
 
 
415
  end = min(i+h, len(A["c"])-1)
416
  for j in range(i+1, end+1):
417
  hi, lo = A["h"][j], A["l"][j]
@@ -434,7 +445,7 @@ def optimize_barriers(A, pos, regimes_arr, side, cost, current_regime, h):
434
  else:
435
  used = str(current_regime)
436
  results = []
437
- for sl in SL_GRID:
438
  for rr in RR_GRID:
439
  vals = []
440
  for i in sel:
@@ -542,7 +553,7 @@ TRADE_COLS = ["entry_date", "exit_date", "side", "entry_price", "exit_reason",
542
 
543
  # ---------------------------------------------------------------- grafikler
544
  def price_figure(df, ticker, trades_df, trade_ok, stop, target, ind=None, vp=None, vp_prof=None,
545
- ldc=None):
546
  w = df.tail(150)
547
  sub = vp is not None and vp_prof is not None
548
  if sub:
@@ -595,6 +606,16 @@ def price_figure(df, ticker, trades_df, trade_ok, stop, target, ind=None, vp=Non
595
  fig.add_trace(go.Scatter(x=w.index[m_], y=w[ycol].to_numpy()[m_]*off, mode="markers",
596
  name=nm, marker=dict(symbol="diamond", size=8, color=col,
597
  line=dict(width=1, color="white"))), **kw)
 
 
 
 
 
 
 
 
 
 
598
  if len(trades_df):
599
  t = trades_df[trades_df.entry_date.isin(w.index)]
600
  for side, sym, nm in [("LONG", "triangle-up", "OOS long"),
@@ -678,7 +699,8 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
678
  skip_overlap, whole_units, ind_mode, st_period, st_mult, ut_key, ut_period,
679
  vp_mode, vp_window, vp_bins, vp_va, vp_ext,
680
  ldc_mode, ldc_k, ldc_back, ldc_regime, ldc_kern_lb, ldc_kern_rw,
681
- ldc_use_vol, ldc_use_regime, ldc_use_adx, ldc_kernel, ldc_exact):
 
682
  try:
683
  ticker = str(ticker).strip().upper()
684
  h = int(horizon)
@@ -733,17 +755,51 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
733
  ind_confirm = ind_mode == IND_MODES[1]
734
  ind_now = int(ind_arr[-1])
735
 
736
- # --- Lorentzian Classification (ML + kernel), tamamen Python'da
737
- ldc_on = ldc_mode != LDC_MODES[0]
738
- ldc_only = ldc_mode == LDC_MODES[2]
739
- ldc_confirm = ldc_mode == LDC_MODES[1]
 
 
 
 
740
  ind_only = ind_only and not ldc_only # iki "Sadece" modu birlikteyse Lorentzian öncelikli
 
741
  LD = ldc_classify(df, ldc_k, ldc_back, ldc_regime, ldc_kern_lb, ldc_kern_rw,
742
  use_vol=bool(ldc_use_vol), use_regime=bool(ldc_use_regime),
743
  use_adx=bool(ldc_use_adx), use_kernel=bool(ldc_kernel),
744
- exact=bool(ldc_exact)) if ldc_on else None
745
  ldc_arr = LD["state"] if LD else np.zeros(len(df), dtype=int)
746
  ldc_now = int(ldc_arr[-1])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
747
 
748
  # --- K seçimi, kalibrasyon, güncel olasılık
749
  best_k, k_scores = tune_k(dev_X, dev_y, h)
@@ -770,6 +826,8 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
770
  side = ind_now
771
  if ldc_only and ldc_now != 0 and allow[ldc_now]:
772
  side = ldc_now
 
 
773
  p_side, p_opp = (p_up, p_down) if side == 1 else (p_down, p_up)
774
 
775
  imp, scaler = cal_model.named_steps["imputer"], cal_model.named_steps["scale"]
@@ -780,6 +838,8 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
780
  agreement = float((ind_arr[-10:] == side).mean())
781
  if ldc_only:
782
  agreement = float((ldc_arr[-10:] == side).mean())
 
 
783
 
784
  # --- yön bazlı TP/SL optimizasyonu (yalnızca geliştirme verisi)
785
  current_regime = str(regimes_all.iloc[-1])
@@ -792,6 +852,8 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
792
  f_ = [i for i in f_ if ind_arr[i] == s_]
793
  if ldc_on:
794
  f_ = [i for i in f_ if ldc_arr[i] == s_]
 
 
795
  if vp_on:
796
  f_ = [i for i in f_ if vp_arr[i] == s_]
797
  return f_ if len(f_) >= 35 else dev_pos
@@ -815,6 +877,10 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
815
  oos_pred = ldc_arr[oos_pos_arr]
816
  oos_bacc = float(balanced_accuracy_score(oos_y, oos_pred))
817
  oos_acc = float(accuracy_score(oos_y, oos_pred))
 
 
 
 
818
  if ind_only: # indikatör yönü OOS'ta tahmin yerine geçer
819
  oos_pred = ind_arr[oos_pos_arr]
820
  oos_bacc = float(balanced_accuracy_score(oos_y, oos_pred))
@@ -831,6 +897,8 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
831
  continue
832
  if ldc_confirm and ldc_arr[i] != pred:
833
  continue
 
 
834
  if skip_overlap and i <= busy:
835
  continue
836
  sl_p, rr_p = params[pred]
@@ -839,7 +907,7 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
839
  continue
840
  ret, j, why = t
841
  net = ret-cost
842
- r = net/max(sl_p*A["a"][i]/A["c"][i], 1e-12)
843
  rows.append((df.index[i], df.index[j], "LONG" if pred == 1 else "SHORT",
844
  A["c"][i], why, net*100, r, reg_arr[i]))
845
  busy = j
@@ -857,7 +925,17 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
857
 
858
  # --- güncel seviyeler ve pozisyon
859
  entry, cur_atr = float(df.Close.iloc[-1]), float(atr_all.iloc[-1])
860
- stop_d, target_d = sl*cur_atr, sl*cur_atr*rr
 
 
 
 
 
 
 
 
 
 
861
  stop = entry-stop_d if side == 1 else entry+stop_d
862
  target = entry+target_d if side == 1 else entry-target_d
863
 
@@ -887,7 +965,7 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
887
  ]
888
  dname = {1: "LONG ↑", -1: "SHORT ↓", 0: "belirsiz"}
889
  ind_check = ("İndikatör yönü (ST + UT aynı)", dname[ind_now], "yönle aynı", ind_now == side)
890
- if ind_only or ldc_only:
891
  keep = ("Yön izni", "OOS balanced acc.", "OOS işlem sayısı", "OOS expectancy")
892
  checks = [c for c in checks if c[0] in keep]
893
  if ind_only or ind_confirm:
@@ -895,6 +973,15 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
895
  if ldc_on:
896
  checks.insert(1, ("Lorentzian yönü (ML + kernel)", dname[ldc_now], "yönle aynı",
897
  ldc_now == side))
 
 
 
 
 
 
 
 
 
898
  if vp_on:
899
  checks.insert(1, ("Volume Profile (POC/VA konumu)", vp_names[int(vp_arr[-1])],
900
  "yönle aynı", int(vp_arr[-1]) == side))
@@ -964,6 +1051,23 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
964
  f"({int(ldc_kern_lb)}, {float(ldc_kern_rw):g}) · rejim eşiği {float(ldc_regime):g}.")
965
  else:
966
  ldc_md, ldc_note = "_Mod kapalı._", ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
967
  k_text = " | ".join(f"K={k}: {s:.3f}" for s, k in sorted(k_scores, reverse=True)) or "—"
968
  overlap_note = ("tek pozisyon (çakışma yok)" if skip_overlap
969
  else "çakışan sinyaller bağımsız işlem sayıldı")
@@ -988,6 +1092,9 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
988
  ## İndikatörler — mod: {ind_mode}
989
  {ind_md}
990
 
 
 
 
991
  ## Lorentzian Classification — mod: {ldc_mode}
992
  {ldc_md}
993
 
@@ -998,16 +1105,16 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
998
 
999
  {vp_note}
1000
 
1001
- ## TP / SL ({'LONG' if side == 1 else 'SHORT'} için optimize)
1002
  | Parametre | Değer |
1003
  |---|---:|
1004
- | SL | {sl:.2f} ATR |
1005
- | TP | {rr:.2f}R |
1006
  | Stop-loss | {fmt_p(stop)} |
1007
  | Take-profit | {fmt_p(target)} |
1008
  | ATR(14) | {fmt_p(cur_atr)} |
1009
 
1010
- TP/SL optimizasyon rejimi: {regime_used}. Yeterli rejim örneği yoksa tüm geliştirme dönemine geri dönülür.
1011
 
1012
  ## OOS backtest ({overlap_note})
1013
  {oos_md}
@@ -1034,6 +1141,8 @@ TP/SL optimizasyon rejimi: {regime_used}. Yeterli rejim örneği yoksa tüm geli
1034
  """
1035
  top_df = pd.DataFrame(top, columns=["score", "SL_ATR", "TP_R", "samples",
1036
  "mean_net_return", "win_rate"])
 
 
1037
  if not top_df.empty:
1038
  top_df["score"] = top_df.score.map(lambda v: f"{v:.5f}")
1039
  top_df["mean_net_return"] = top_df.mean_net_return.map(lambda v: f"{v:.3%}")
@@ -1047,8 +1156,8 @@ TP/SL optimizasyon rejimi: {regime_used}. Yeterli rejim örneği yoksa tüm geli
1047
 
1048
  price_fig = price_figure(df, ticker, trades_df, trade_ok, stop, target,
1049
  ind=(st_line, st_dir, ut_stop),
1050
- vp=vp if vp_on else None, vp_prof=lp,
1051
- ldc=LD)
1052
  eq_fig = equity_figure(curve, dds) if len(R) else None
1053
  pf_fig = pf_gauge(stats["pf"], stats["n"]) if stats else None
1054
  mc_fig = mc_figure(mc) if mc else None
@@ -1064,7 +1173,7 @@ TP/SL optimizasyon rejimi: {regime_used}. Yeterli rejim örneği yoksa tüm geli
1064
  "seri korelasyonunu ve rejim değişimini tam modellemez. Pozisyon hesabı spot miktar "
1065
  "varsayar; CFD lot sözleşmesi, spread, funding, swap, komisyon, minimum lot, marjin ve "
1066
  "broker fiyatı farklı olabilir. Gap ve kayma kaybı planlanan riskin üstüne çıkarabilir. "
1067
- "Supertrend ve UT Bot, TradingView formüllerinin Python portudur; ATR başlangıcı ve veri kaynağı yüzünden TV değerlerinden küçük sapmalar olabilir. Lorentzian Classification, jdehorty'nin TradingView göstergesinin Python portudur (ANN komşu seçimi, filtreler ve kernel regresyon); Pine kaynağıyla birebir aynı sonuç vermeyebilir ve yalnızca günlük mumda çalışır. Volume Profile, günlük OHLCV'den (her mumun hacmi high–low aralığına eşit dağıtılarak) yaklaşık hesaplanır; TradingView VPVR'nin alt-zaman dilimi verisiyle birebir aynı olmaz. Canlı hesap öncesi paper trading ve broker bazlı doğrulama zorunludur."
1068
  )
1069
  return (report, prob_figure(p_down, p_flat, p_up), price_fig, eq_fig, pf_fig, mc_fig,
1070
  top_df, csv_path, disclaimer)
@@ -1092,6 +1201,9 @@ with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
1092
  ind_mode = gr.Radio(IND_MODES, value="Kapalı", label="İndikatör modu (Supertrend + UT Bot)")
1093
  vp_mode = gr.Radio(VP_MODES, value="Kapalı", label="Volume Profile modu")
1094
  ldc_mode = gr.Radio(LDC_MODES, value="Kapalı", label="Lorentzian Classification modu")
 
 
 
1095
  train_window = gr.Slider(300, 1500, value=900, step=50, label="Maksimum eğitim penceresi")
1096
  with gr.Column():
1097
  equity = gr.Number(value=10000, label="Hesap büyüklüğü (USD)")
@@ -1114,6 +1226,11 @@ with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
1114
  st_mult = gr.Slider(1.0, 6.0, value=3.0, step=0.1, label="Supertrend çarpanı")
1115
  ut_key = gr.Slider(0.5, 4.0, value=1.0, step=0.1, label="UT Bot key value")
1116
  ut_period = gr.Slider(5, 30, value=10, step=1, label="UT Bot ATR periyodu")
 
 
 
 
 
1117
  with gr.Row():
1118
  ldc_k = gr.Slider(1, 30, value=8, step=1, label="Lorentzian komşu sayısı")
1119
  ldc_back = gr.Slider(300, 3000, value=2000, step=100, label="Lorentzian maks. geçmiş mum")
@@ -1162,7 +1279,8 @@ with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
1162
  skip_overlap, whole_units, ind_mode, st_period, st_mult, ut_key, ut_period,
1163
  vp_mode, vp_window, vp_bins, vp_va, vp_ext,
1164
  ldc_mode, ldc_k, ldc_back, ldc_regime, ldc_kern_lb, ldc_kern_rw,
1165
- ldc_use_vol, ldc_use_regime, ldc_use_adx, ldc_kernel, ldc_exact],
 
1166
  outputs=[output, prob_plot, chart, equity_plot, pf_plot, mc_plot, optimization,
1167
  csv_file, disclaimer],
1168
  )
 
29
  CLASSES = [-1, 0, 1]
30
  SIDE_MODES = ["Long + Short", "Sadece Long", "Sadece Short"]
31
  IND_MODES = ["Kapalı", "Onay filtresi (KNN + ST/UT)", "Sadece indikatör"]
32
+ COMBO_MODES = ["Kapalı", "Onay filtresi (KNN + birleşik)", "Sadece birleşik sinyal"]
33
  LDC_MODES = ["Kapalı", "Onay filtresi (Lorentzian)", "Sadece Lorentzian"]
34
  VP_MODES = ["Kapalı", "Onay filtresi (POC / Value Area)", "KNN özelliği + onay filtresi"]
35
 
 
406
 
407
 
408
  # ---------------------------------------------------------------- bariyer / R
409
+ def stop_dist(A, i, side, sl_atr):
410
+ return A["ind_sd"][side][i] if "ind_sd" in A else sl_atr*A["a"][i]
411
+
412
+
413
  def barrier_trade(A, i, side, sl_atr, rr, h):
414
  """(getiri, çıkış_pozisyonu, neden) döndürür. Aynı mumda SL+TP varsa SL kabul edilir."""
415
  entry, av = A["c"][i], A["a"][i]
416
  if not np.isfinite(av) or av <= 0 or not np.isfinite(entry):
417
  return None
418
+ if "ind_sd" in A: # SL/TP indikatör seviyelerinden (ST / UT / Volume Profile)
419
+ sd = A["ind_sd"][side][i]
420
+ if not np.isfinite(sd) or sd <= 0:
421
+ return None
422
+ td = min(sd*rr, A["ind_cap"][side][i])
423
+ else:
424
+ sd = sl_atr*av
425
+ td = sd*rr
426
  end = min(i+h, len(A["c"])-1)
427
  for j in range(i+1, end+1):
428
  hi, lo = A["h"][j], A["l"][j]
 
445
  else:
446
  used = str(current_regime)
447
  results = []
448
+ for sl in ([1.0] if "ind_sd" in A else SL_GRID):
449
  for rr in RR_GRID:
450
  vals = []
451
  for i in sel:
 
553
 
554
  # ---------------------------------------------------------------- grafikler
555
  def price_figure(df, ticker, trades_df, trade_ok, stop, target, ind=None, vp=None, vp_prof=None,
556
+ ldc=None, combo=None):
557
  w = df.tail(150)
558
  sub = vp is not None and vp_prof is not None
559
  if sub:
 
606
  fig.add_trace(go.Scatter(x=w.index[m_], y=w[ycol].to_numpy()[m_]*off, mode="markers",
607
  name=nm, marker=dict(symbol="diamond", size=8, color=col,
608
  line=dict(width=1, color="white"))), **kw)
609
+ if combo is not None:
610
+ cs = np.asarray(combo)[-150:]
611
+ pv = np.r_[0, cs[:-1]]
612
+ for d, nm, col, ycol, off in [(1, "Birleşik LONG", "#f59e0b", "Low", 0.985),
613
+ (-1, "Birleşik SHORT", "#7c3aed", "High", 1.015)]:
614
+ m_ = (cs == d) & (pv != d)
615
+ if m_.any():
616
+ fig.add_trace(go.Scatter(x=w.index[m_], y=w[ycol].to_numpy()[m_]*off, mode="markers",
617
+ name=nm, marker=dict(symbol="star", size=12, color=col,
618
+ line=dict(width=1, color="white"))), **kw)
619
  if len(trades_df):
620
  t = trades_df[trades_df.entry_date.isin(w.index)]
621
  for side, sym, nm in [("LONG", "triangle-up", "OOS long"),
 
699
  skip_overlap, whole_units, ind_mode, st_period, st_mult, ut_key, ut_period,
700
  vp_mode, vp_window, vp_bins, vp_va, vp_ext,
701
  ldc_mode, ldc_k, ldc_back, ldc_regime, ldc_kern_lb, ldc_kern_rw,
702
+ ldc_use_vol, ldc_use_regime, ldc_use_adx, ldc_kernel, ldc_exact,
703
+ combo_mode, combo_votes, ind_tpsl, tpsl_smin, tpsl_smax, tpsl_minrr):
704
  try:
705
  ticker = str(ticker).strip().upper()
706
  h = int(horizon)
 
755
  ind_confirm = ind_mode == IND_MODES[1]
756
  ind_now = int(ind_arr[-1])
757
 
758
+ # --- Lorentzian Classification (ML + kernel) ve birleşik sinyal (oylama)
759
+ combo_on = combo_mode != COMBO_MODES[0]
760
+ combo_only = combo_mode == COMBO_MODES[2]
761
+ ldc_on = ldc_mode != LDC_MODES[0] and not combo_only
762
+ ldc_only = ldc_mode == LDC_MODES[2] and not combo_only
763
+ ldc_confirm = ldc_mode == LDC_MODES[1] and not combo_only
764
+ if combo_only: # oylar zaten birleşik sinyale girer; tekil filtreler çift sayılmasın
765
+ ind_only = ind_confirm = vp_on = False
766
  ind_only = ind_only and not ldc_only # iki "Sadece" modu birlikteyse Lorentzian öncelikli
767
+ need_ldc = ldc_mode != LDC_MODES[0] or combo_on
768
  LD = ldc_classify(df, ldc_k, ldc_back, ldc_regime, ldc_kern_lb, ldc_kern_rw,
769
  use_vol=bool(ldc_use_vol), use_regime=bool(ldc_use_regime),
770
  use_adx=bool(ldc_use_adx), use_kernel=bool(ldc_kernel),
771
+ exact=bool(ldc_exact)) if need_ldc else None
772
  ldc_arr = LD["state"] if LD else np.zeros(len(df), dtype=int)
773
  ldc_now = int(ldc_arr[-1])
774
+ vp_now = int(vp_arr[-1])
775
+ votes = np.vstack([ind_arr, ldc_arr, vp_arr]) # ST+UT, Lorentzian, Volume Profile
776
+ n_long, n_short = (votes == 1).sum(axis=0), (votes == -1).sum(axis=0)
777
+ mv = int(combo_votes)
778
+ combo_arr = np.where((n_long >= mv) & (n_short == 0), 1,
779
+ np.where((n_short >= mv) & (n_long == 0), -1, 0)).astype(int)
780
+ combo_now = int(combo_arr[-1])
781
+
782
+ # --- indikatör bazlı SL/TP: en yakın ST / UT / VP seviyesi = invalidasyon (SL),
783
+ # önündeki Value Area / POC seviyesi >= 1 ATR uzaktaysa TP üst sınırı
784
+ ind_tpsl = bool(ind_tpsl)
785
+ if ind_tpsl:
786
+ c_, a_ = A["c"], A["a"]
787
+ vpo, vpl, vph = (vp[k].to_numpy(float) for k in ("poc", "val", "vah"))
788
+
789
+ def nearest(levels, sign): # sign=+1: seviye fiyatın altında, -1: üstünde
790
+ d = np.full(len(c_), np.inf)
791
+ for lv in levels:
792
+ dd = sign*(c_-lv)
793
+ ok = np.isfinite(dd) & (dd > 0)
794
+ d = np.where(ok & (dd < d), dd, d)
795
+ return d
796
+ smin, smax = float(tpsl_smin), float(tpsl_smax)
797
+ sd_of = lambda d: np.clip(np.where(np.isfinite(d), d+0.1*a_, 1.5*a_), smin*a_, smax*a_)
798
+ cap_of = lambda d: np.where(d >= 1.0*a_, d, np.inf)
799
+ A["ind_sd"] = {1: sd_of(nearest([st_line, ut_stop, vpl], 1)),
800
+ -1: sd_of(nearest([st_line, ut_stop, vph], -1))}
801
+ A["ind_cap"] = {1: cap_of(nearest([vpo, vph], -1)),
802
+ -1: cap_of(nearest([vpo, vpl], 1))}
803
 
804
  # --- K seçimi, kalibrasyon, güncel olasılık
805
  best_k, k_scores = tune_k(dev_X, dev_y, h)
 
826
  side = ind_now
827
  if ldc_only and ldc_now != 0 and allow[ldc_now]:
828
  side = ldc_now
829
+ if combo_only and combo_now != 0 and allow[combo_now]:
830
+ side = combo_now
831
  p_side, p_opp = (p_up, p_down) if side == 1 else (p_down, p_up)
832
 
833
  imp, scaler = cal_model.named_steps["imputer"], cal_model.named_steps["scale"]
 
838
  agreement = float((ind_arr[-10:] == side).mean())
839
  if ldc_only:
840
  agreement = float((ldc_arr[-10:] == side).mean())
841
+ if combo_only:
842
+ agreement = float((combo_arr[-10:] == side).mean())
843
 
844
  # --- yön bazlı TP/SL optimizasyonu (yalnızca geliştirme verisi)
845
  current_regime = str(regimes_all.iloc[-1])
 
852
  f_ = [i for i in f_ if ind_arr[i] == s_]
853
  if ldc_on:
854
  f_ = [i for i in f_ if ldc_arr[i] == s_]
855
+ if combo_on:
856
+ f_ = [i for i in f_ if combo_arr[i] == s_]
857
  if vp_on:
858
  f_ = [i for i in f_ if vp_arr[i] == s_]
859
  return f_ if len(f_) >= 35 else dev_pos
 
877
  oos_pred = ldc_arr[oos_pos_arr]
878
  oos_bacc = float(balanced_accuracy_score(oos_y, oos_pred))
879
  oos_acc = float(accuracy_score(oos_y, oos_pred))
880
+ if combo_only: # birleşik sinyal OOS'ta tahmin yerine geçer
881
+ oos_pred = combo_arr[oos_pos_arr]
882
+ oos_bacc = float(balanced_accuracy_score(oos_y, oos_pred))
883
+ oos_acc = float(accuracy_score(oos_y, oos_pred))
884
  if ind_only: # indikatör yönü OOS'ta tahmin yerine geçer
885
  oos_pred = ind_arr[oos_pos_arr]
886
  oos_bacc = float(balanced_accuracy_score(oos_y, oos_pred))
 
897
  continue
898
  if ldc_confirm and ldc_arr[i] != pred:
899
  continue
900
+ if combo_on and combo_arr[i] != pred:
901
+ continue
902
  if skip_overlap and i <= busy:
903
  continue
904
  sl_p, rr_p = params[pred]
 
907
  continue
908
  ret, j, why = t
909
  net = ret-cost
910
+ r = net/max(stop_dist(A, i, pred, sl_p)/A["c"][i], 1e-12)
911
  rows.append((df.index[i], df.index[j], "LONG" if pred == 1 else "SHORT",
912
  A["c"][i], why, net*100, r, reg_arr[i]))
913
  busy = j
 
925
 
926
  # --- güncel seviyeler ve pozisyon
927
  entry, cur_atr = float(df.Close.iloc[-1]), float(atr_all.iloc[-1])
928
+ if ind_tpsl:
929
+ stop_d = float(A["ind_sd"][side][-1])
930
+ target_d = float(min(stop_d*rr, A["ind_cap"][side][-1]))
931
+ cl_ = float(A["c"][-1])
932
+ cands = {"Supertrend": float(st_line[-1]), "UT trailing stop": float(ut_stop[-1]),
933
+ "VP " + ("VAL" if side == 1 else "VAH"):
934
+ float((vp.val if side == 1 else vp.vah).iloc[-1])}
935
+ valid = {k_: side*(cl_-v_) for k_, v_ in cands.items() if np.isfinite(v_) and side*(cl_-v_) > 0}
936
+ sl_name = min(valid, key=valid.get) if valid else "ATR varsayılan (seviye yok)"
937
+ else:
938
+ stop_d, target_d = sl*cur_atr, sl*cur_atr*rr
939
  stop = entry-stop_d if side == 1 else entry+stop_d
940
  target = entry+target_d if side == 1 else entry-target_d
941
 
 
965
  ]
966
  dname = {1: "LONG ↑", -1: "SHORT ↓", 0: "belirsiz"}
967
  ind_check = ("İndikatör yönü (ST + UT aynı)", dname[ind_now], "yönle aynı", ind_now == side)
968
+ if ind_only or ldc_only or combo_only:
969
  keep = ("Yön izni", "OOS balanced acc.", "OOS işlem sayısı", "OOS expectancy")
970
  checks = [c for c in checks if c[0] in keep]
971
  if ind_only or ind_confirm:
 
973
  if ldc_on:
974
  checks.insert(1, ("Lorentzian yönü (ML + kernel)", dname[ldc_now], "yönle aynı",
975
  ldc_now == side))
976
+ if combo_on:
977
+ nv = int(sum(1 for v_ in (ind_now, ldc_now, vp_now) if v_ == side))
978
+ no_ = int(sum(1 for v_ in (ind_now, ldc_now, vp_now) if v_ == -side))
979
+ checks.insert(1, ("Birleşik sinyal (ST+UT · Lorentzian · VP)", f"{nv}/3 oy, karşı {no_}",
980
+ f"≥ {mv} oy, karşı oy yok", combo_now == side))
981
+ if ind_tpsl:
982
+ rr_now = target_d/stop_d if stop_d > 0 else 0.0
983
+ checks.append(("İndikatör R:R (TP/SL)", f"{rr_now:.2f}", f"≥ {float(tpsl_minrr):g}",
984
+ rr_now >= float(tpsl_minrr)))
985
  if vp_on:
986
  checks.insert(1, ("Volume Profile (POC/VA konumu)", vp_names[int(vp_arr[-1])],
987
  "yönle aynı", int(vp_arr[-1]) == side))
 
1051
  f"({int(ldc_kern_lb)}, {float(ldc_kern_rw):g}) · rejim eşiği {float(ldc_regime):g}.")
1052
  else:
1053
  ldc_md, ldc_note = "_Mod kapalı._", ""
1054
+ if combo_on:
1055
+ combo_md = md_table(["Kaynak", "Oy"], [
1056
+ ("Supertrend + UT Bot", dname[ind_now]), ("Lorentzian (ML + kernel)", dname[ldc_now]),
1057
+ ("Volume Profile (POC/VA)", dname[vp_now]),
1058
+ ("**Birleşik sinyal**", f"**{dname[combo_now]}** (en az {mv} oy, karşı oy yok)")])
1059
+ else:
1060
+ combo_md = "_Mod kapalı._"
1061
+ if ind_tpsl:
1062
+ capped = target_d < stop_d*rr-1e-12
1063
+ tp_title = "indikatörlerden türetildi"
1064
+ tpsl_note = (f"SL: en yakın invalidasyon seviyesi — **{sl_name}** (+0,1 ATR tampon, "
1065
+ f"{float(tpsl_smin):g}–{float(tpsl_smax):g} ATR aralığına sıkıştırılır). "
1066
+ f"TP: {rr:.2f}R katı"
1067
+ + (", önündeki Value Area/POC seviyesinde sınırlandı" if capped else "")
1068
+ + ". Optimize edilen tek parametre R katıdır.\n\n")
1069
+ else:
1070
+ tp_title, tpsl_note = "optimize", ""
1071
  k_text = " | ".join(f"K={k}: {s:.3f}" for s, k in sorted(k_scores, reverse=True)) or "—"
1072
  overlap_note = ("tek pozisyon (çakışma yok)" if skip_overlap
1073
  else "çakışan sinyaller bağımsız işlem sayıldı")
 
1092
  ## İndikatörler — mod: {ind_mode}
1093
  {ind_md}
1094
 
1095
+ ## Birleşik sinyal — mod: {combo_mode}
1096
+ {combo_md}
1097
+
1098
  ## Lorentzian Classification — mod: {ldc_mode}
1099
  {ldc_md}
1100
 
 
1105
 
1106
  {vp_note}
1107
 
1108
+ ## TP / SL ({'LONG' if side == 1 else 'SHORT'} için {tp_title})
1109
  | Parametre | Değer |
1110
  |---|---:|
1111
+ | SL | {stop_d/cur_atr:.2f} ATR |
1112
+ | TP | {target_d/stop_d:.2f}R |
1113
  | Stop-loss | {fmt_p(stop)} |
1114
  | Take-profit | {fmt_p(target)} |
1115
  | ATR(14) | {fmt_p(cur_atr)} |
1116
 
1117
+ {tpsl_note}TP/SL optimizasyon rejimi: {regime_used}. Yeterli rejim örneği yoksa tüm geliştirme dönemine geri dönülür.
1118
 
1119
  ## OOS backtest ({overlap_note})
1120
  {oos_md}
 
1141
  """
1142
  top_df = pd.DataFrame(top, columns=["score", "SL_ATR", "TP_R", "samples",
1143
  "mean_net_return", "win_rate"])
1144
+ if ind_tpsl and not top_df.empty:
1145
+ top_df["SL_ATR"] = "indikatör"
1146
  if not top_df.empty:
1147
  top_df["score"] = top_df.score.map(lambda v: f"{v:.5f}")
1148
  top_df["mean_net_return"] = top_df.mean_net_return.map(lambda v: f"{v:.3%}")
 
1156
 
1157
  price_fig = price_figure(df, ticker, trades_df, trade_ok, stop, target,
1158
  ind=(st_line, st_dir, ut_stop),
1159
+ vp=vp if (vp_on or combo_on) else None, vp_prof=lp,
1160
+ ldc=LD, combo=combo_arr if combo_on else None)
1161
  eq_fig = equity_figure(curve, dds) if len(R) else None
1162
  pf_fig = pf_gauge(stats["pf"], stats["n"]) if stats else None
1163
  mc_fig = mc_figure(mc) if mc else None
 
1173
  "seri korelasyonunu ve rejim değişimini tam modellemez. Pozisyon hesabı spot miktar "
1174
  "varsayar; CFD lot sözleşmesi, spread, funding, swap, komisyon, minimum lot, marjin ve "
1175
  "broker fiyatı farklı olabilir. Gap ve kayma kaybı planlanan riskin üstüne çıkarabilir. "
1176
+ "Supertrend ve UT Bot, TradingView formüllerinin Python portudur; ATR başlangıcı ve veri kaynağı yüzünden TV değerlerinden küçük sapmalar olabilir. Birleşik sinyal; ST+UT, Lorentzian ve Volume Profile oylarının birleşimidir. İndikatör bazlı TP/SL, en yakın ST/UT/VP seviyesini invalidasyon sayar ve ATR aralığına sıkıştırır. Lorentzian Classification, jdehorty'nin TradingView göstergesinin Python portudur (ANN komşu seçimi, filtreler ve kernel regresyon); Pine kaynağıyla birebir aynı sonuç vermeyebilir ve yalnızca günlük mumda çalışır. Volume Profile, günlük OHLCV'den (her mumun hacmi high–low aralığına eşit dağıtılarak) yaklaşık hesaplanır; TradingView VPVR'nin alt-zaman dilimi verisiyle birebir aynı olmaz. Canlı hesap öncesi paper trading ve broker bazlı doğrulama zorunludur."
1177
  )
1178
  return (report, prob_figure(p_down, p_flat, p_up), price_fig, eq_fig, pf_fig, mc_fig,
1179
  top_df, csv_path, disclaimer)
 
1201
  ind_mode = gr.Radio(IND_MODES, value="Kapalı", label="İndikatör modu (Supertrend + UT Bot)")
1202
  vp_mode = gr.Radio(VP_MODES, value="Kapalı", label="Volume Profile modu")
1203
  ldc_mode = gr.Radio(LDC_MODES, value="Kapalı", label="Lorentzian Classification modu")
1204
+ combo_mode = gr.Radio(COMBO_MODES, value=COMBO_MODES[2],
1205
+ label="Birleşik sinyal (ST+UT · Lorentzian · Volume Profile oylaması)")
1206
+ ind_tpsl = gr.Checkbox(value=True, label="TP/SL'i indikatörlerden türet (ST / UT / VP seviyeleri)")
1207
  train_window = gr.Slider(300, 1500, value=900, step=50, label="Maksimum eğitim penceresi")
1208
  with gr.Column():
1209
  equity = gr.Number(value=10000, label="Hesap büyüklüğü (USD)")
 
1226
  st_mult = gr.Slider(1.0, 6.0, value=3.0, step=0.1, label="Supertrend çarpanı")
1227
  ut_key = gr.Slider(0.5, 4.0, value=1.0, step=0.1, label="UT Bot key value")
1228
  ut_period = gr.Slider(5, 30, value=10, step=1, label="UT Bot ATR periyodu")
1229
+ with gr.Row():
1230
+ combo_votes = gr.Slider(1, 3, value=2, step=1, label="Birleşik sinyal: min. aynı yön oyu (karşı oy yok)")
1231
+ tpsl_smin = gr.Slider(0.3, 2.0, value=0.8, step=0.1, label="İndikatör SL alt sınır (ATR)")
1232
+ tpsl_smax = gr.Slider(1.5, 6.0, value=3.0, step=0.1, label="İndikatör SL üst sınır (ATR)")
1233
+ tpsl_minrr = gr.Slider(0.5, 3.0, value=1.0, step=0.1, label="Min. R:R (kapı)")
1234
  with gr.Row():
1235
  ldc_k = gr.Slider(1, 30, value=8, step=1, label="Lorentzian komşu sayısı")
1236
  ldc_back = gr.Slider(300, 3000, value=2000, step=100, label="Lorentzian maks. geçmiş mum")
 
1279
  skip_overlap, whole_units, ind_mode, st_period, st_mult, ut_key, ut_period,
1280
  vp_mode, vp_window, vp_bins, vp_va, vp_ext,
1281
  ldc_mode, ldc_k, ldc_back, ldc_regime, ldc_kern_lb, ldc_kern_rw,
1282
+ ldc_use_vol, ldc_use_regime, ldc_use_adx, ldc_kernel, ldc_exact,
1283
+ combo_mode, combo_votes, ind_tpsl, tpsl_smin, tpsl_smax, tpsl_minrr],
1284
  outputs=[output, prob_plot, chart, equity_plot, pf_plot, mc_plot, optimization,
1285
  csv_file, disclaimer],
1286
  )