GoshawkVortexAI commited on
Commit
e1e3b82
·
verified ·
1 Parent(s): 074a0ae

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +212 -8
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
  VP_MODES = ["Kapalı", "Onay filtresi (POC / Value Area)", "KNN özelliği + onay filtresi"]
33
 
34
  _CACHE = {}
@@ -216,6 +217,129 @@ def vp_signal(df, atr, vp, ext_atr):
216
  return np.where(ok_l, 1, np.where(ok_s, -1, 0)).astype(int)
217
 
218
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  def regime_labels(features, ref_vol):
220
  # Volatilite kantilleri yalnızca geliştirme dönemi verisinden alınır (sızıntı yok).
221
  q1, q2 = ref_vol.dropna().quantile([0.33, 0.67])
@@ -417,7 +541,8 @@ TRADE_COLS = ["entry_date", "exit_date", "side", "entry_price", "exit_reason",
417
 
418
 
419
  # ---------------------------------------------------------------- grafikler
420
- def price_figure(df, ticker, trades_df, trade_ok, stop, target, ind=None, vp=None, vp_prof=None):
 
421
  w = df.tail(150)
422
  sub = vp is not None and vp_prof is not None
423
  if sub:
@@ -455,6 +580,21 @@ def price_figure(df, ticker, trades_df, trade_ok, stop, target, ind=None, vp=Non
455
  marker_color=colors, name="Volume Profile", showlegend=False,
456
  hoverinfo="skip"), row=1, col=2)
457
  fig.update_xaxes(showticklabels=False, row=1, col=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  if len(trades_df):
459
  t = trades_df[trades_df.entry_date.isin(w.index)]
460
  for side, sym, nm in [("LONG", "triangle-up", "OOS long"),
@@ -536,7 +676,9 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
536
  max_leverage, fee, slip, train_window,
537
  p_min, p_gap, flat_max, agree_min, bacc_min, min_trades,
538
  skip_overlap, whole_units, ind_mode, st_period, st_mult, ut_key, ut_period,
539
- vp_mode, vp_window, vp_bins, vp_va, vp_ext):
 
 
540
  try:
541
  ticker = str(ticker).strip().upper()
542
  h = int(horizon)
@@ -591,6 +733,18 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
591
  ind_confirm = ind_mode == IND_MODES[1]
592
  ind_now = int(ind_arr[-1])
593
 
 
 
 
 
 
 
 
 
 
 
 
 
594
  # --- K seçimi, kalibrasyon, güncel olasılık
595
  best_k, k_scores = tune_k(dev_X, dev_y, h)
596
  cal_n = min(120, max(45, int(len(dev_X)*0.20)))
@@ -614,6 +768,8 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
614
  side = 1 if p_up >= p_down else -1
615
  if ind_only and ind_now != 0 and allow[ind_now]:
616
  side = ind_now
 
 
617
  p_side, p_opp = (p_up, p_down) if side == 1 else (p_down, p_up)
618
 
619
  imp, scaler = cal_model.named_steps["imputer"], cal_model.named_steps["scale"]
@@ -622,6 +778,8 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
622
  agreement = float((fit_y.iloc[idx[0]].to_numpy() == side).mean())
623
  if ind_only: # indikatör modunda: son 10 mumda yönün sürekliliği
624
  agreement = float((ind_arr[-10:] == side).mean())
 
 
625
 
626
  # --- yön bazlı TP/SL optimizasyonu (yalnızca geliştirme verisi)
627
  current_regime = str(regimes_all.iloc[-1])
@@ -632,6 +790,8 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
632
  f_ = list(dev_pos)
633
  if ind_only or ind_confirm:
634
  f_ = [i for i in f_ if ind_arr[i] == s_]
 
 
635
  if vp_on:
636
  f_ = [i for i in f_ if vp_arr[i] == s_]
637
  return f_ if len(f_) >= 35 else dev_pos
@@ -651,6 +811,10 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
651
  oos_bacc = float(balanced_accuracy_score(oos_y, oos_pred))
652
  oos_acc = float(accuracy_score(oos_y, oos_pred))
653
  oos_pos_arr = pos_of(oos_X.index)
 
 
 
 
654
  if ind_only: # indikatör yönü OOS'ta tahmin yerine geçer
655
  oos_pred = ind_arr[oos_pos_arr]
656
  oos_bacc = float(balanced_accuracy_score(oos_y, oos_pred))
@@ -665,6 +829,8 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
665
  continue
666
  if vp_on and vp_arr[i] != pred:
667
  continue
 
 
668
  if skip_overlap and i <= busy:
669
  continue
670
  sl_p, rr_p = params[pred]
@@ -721,12 +887,14 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
721
  ]
722
  dname = {1: "LONG ↑", -1: "SHORT ↓", 0: "belirsiz"}
723
  ind_check = ("İndikatör yönü (ST + UT aynı)", dname[ind_now], "yönle aynı", ind_now == side)
724
- if ind_only:
725
  keep = ("Yön izni", "OOS balanced acc.", "OOS işlem sayısı", "OOS expectancy")
726
  checks = [c for c in checks if c[0] in keep]
 
727
  checks.insert(1, ind_check)
728
- elif ind_confirm:
729
- checks.insert(1, ind_check)
 
730
  if vp_on:
731
  checks.insert(1, ("Volume Profile (POC/VA konumu)", vp_names[int(vp_arr[-1])],
732
  "yönle aynı", int(vp_arr[-1]) == side))
@@ -782,6 +950,20 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
782
  f"uzama sınırı {float(vp_ext):g} ATR."
783
  + (" Hacim verisi yok → zaman bazlı profil kullanıldı." if vp_no_vol else "")
784
  + (" Mod Kapalı: yalnızca bilgi amaçlı." if not vp_on else ""))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
785
  k_text = " | ".join(f"K={k}: {s:.3f}" for s, k in sorted(k_scores, reverse=True)) or "—"
786
  overlap_note = ("tek pozisyon (çakışma yok)" if skip_overlap
787
  else "çakışan sinyaller bağımsız işlem sayıldı")
@@ -806,6 +988,11 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
806
  ## İndikatörler — mod: {ind_mode}
807
  {ind_md}
808
 
 
 
 
 
 
809
  ## Volume Profile — mod: {vp_mode}
810
  {vp_md}
811
 
@@ -860,7 +1047,8 @@ TP/SL optimizasyon rejimi: {regime_used}. Yeterli rejim örneği yoksa tüm geli
860
 
861
  price_fig = price_figure(df, ticker, trades_df, trade_ok, stop, target,
862
  ind=(st_line, st_dir, ut_stop),
863
- vp=vp if vp_on else None, vp_prof=lp)
 
864
  eq_fig = equity_figure(curve, dds) if len(R) else None
865
  pf_fig = pf_gauge(stats["pf"], stats["n"]) if stats else None
866
  mc_fig = mc_figure(mc) if mc else None
@@ -876,7 +1064,7 @@ TP/SL optimizasyon rejimi: {regime_used}. Yeterli rejim örneği yoksa tüm geli
876
  "seri korelasyonunu ve rejim değişimini tam modellemez. Pozisyon hesabı spot miktar "
877
  "varsayar; CFD lot sözleşmesi, spread, funding, swap, komisyon, minimum lot, marjin ve "
878
  "broker fiyatı farklı olabilir. Gap ve kayma kaybı planlanan riskin üstüne çıkarabilir. "
879
- "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. 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."
880
  )
881
  return (report, prob_figure(p_down, p_flat, p_up), price_fig, eq_fig, pf_fig, mc_fig,
882
  top_df, csv_path, disclaimer)
@@ -903,6 +1091,7 @@ with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
903
  side_mode = gr.Radio(SIDE_MODES, value="Long + Short", label="İzin verilen yön")
904
  ind_mode = gr.Radio(IND_MODES, value="Kapalı", label="İndikatör modu (Supertrend + UT Bot)")
905
  vp_mode = gr.Radio(VP_MODES, value="Kapalı", label="Volume Profile modu")
 
906
  train_window = gr.Slider(300, 1500, value=900, step=50, label="Maksimum eğitim penceresi")
907
  with gr.Column():
908
  equity = gr.Number(value=10000, label="Hesap büyüklüğü (USD)")
@@ -925,6 +1114,19 @@ with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
925
  st_mult = gr.Slider(1.0, 6.0, value=3.0, step=0.1, label="Supertrend çarpanı")
926
  ut_key = gr.Slider(0.5, 4.0, value=1.0, step=0.1, label="UT Bot key value")
927
  ut_period = gr.Slider(5, 30, value=10, step=1, label="UT Bot ATR periyodu")
 
 
 
 
 
 
 
 
 
 
 
 
 
928
  with gr.Row():
929
  vp_window = gr.Slider(20, 250, value=60, step=5, label="Volume Profile penceresi (mum)")
930
  vp_bins = gr.Slider(12, 60, value=24, step=2, label="Fiyat kutusu sayısı")
@@ -958,7 +1160,9 @@ with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
958
  max_leverage, fee, slip, train_window,
959
  p_min, p_gap, flat_max, agree_min, bacc_min, min_trades,
960
  skip_overlap, whole_units, ind_mode, st_period, st_mult, ut_key, ut_period,
961
- vp_mode, vp_window, vp_bins, vp_va, vp_ext],
 
 
962
  outputs=[output, prob_plot, chart, equity_plot, pf_plot, mc_plot, optimization,
963
  csv_file, disclaimer],
964
  )
 
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
 
35
  _CACHE = {}
 
217
  return np.where(ok_l, 1, np.where(ok_s, -1, 0)).astype(int)
218
 
219
 
220
+ # ------------------------------------------- Lorentzian Classification (jdehorty) portu
221
+ def adx_wilder(df, n=14):
222
+ h, l, c = df.High, df.Low, df.Close
223
+ up, dn = h.diff(), -l.diff()
224
+ plus = pd.Series(np.where((up > dn) & (up > 0), up, 0.0), index=df.index)
225
+ minus = pd.Series(np.where((dn > up) & (dn > 0), dn, 0.0), index=df.index)
226
+ tr = pd.concat([(h-l), (h-c.shift(1)).abs(), (l-c.shift(1)).abs()], axis=1).max(axis=1)
227
+ a = 1/n
228
+ atr = tr.ewm(alpha=a, adjust=False).mean()
229
+ pdi = 100*plus.ewm(alpha=a, adjust=False).mean()/atr
230
+ mdi = 100*minus.ewm(alpha=a, adjust=False).mean()/atr
231
+ dx = 100*(pdi-mdi).abs()/(pdi+mdi).replace(0, np.nan)
232
+ return dx.ewm(alpha=a, adjust=False).mean().to_numpy(float)
233
+
234
+
235
+ def _norm01(x):
236
+ """Geçmiş min/max'a göre 0-1 ölçekleme (TV 'normalize'); yalnızca geçmişe bakar."""
237
+ s = pd.Series(x)
238
+ lo, hi = s.cummin(), s.cummax()
239
+ return ((s-lo)/(hi-lo).replace(0, np.nan)).to_numpy(float)
240
+
241
+
242
+ def _ldc_features(df):
243
+ src = (df.High+df.Low+df.Close)/3
244
+ ema = lambda s, n: s.ewm(span=max(int(n), 1), adjust=False).mean()
245
+ rsi = lambda n: ema(calc_rsi(src, n)/100, 1).to_numpy(float)
246
+ e1 = ema(src, 10)
247
+ e2 = ema((src-e1).abs(), 10)
248
+ wt1 = ema((src-e1)/(0.015*e2).replace(0, np.nan), 11)
249
+ wt = _norm01((wt1-wt1.rolling(4).mean()).to_numpy(float))
250
+ ma = src.rolling(20).mean()
251
+ md = src.rolling(20).apply(lambda a: np.abs(a-a.mean()).mean(), raw=True)
252
+ cci = _norm01(((src-ma)/(0.015*md.replace(0, np.nan))).to_numpy(float))
253
+ adx = adx_wilder(df, 20)/100
254
+ # varsayılan öznitelikler: RSI(14,1), WT(10,11), CCI(20,1), ADX(20,2), RSI(9,1)
255
+ return np.column_stack([rsi(14), wt, cci, adx, rsi(9)]), src.to_numpy(float)
256
+
257
+
258
+ def ldc_classify(df, k=8, max_back=2000, regime_thr=-0.1, kern_lb=8, kern_rw=8.0, x0=25,
259
+ use_vol=True, use_regime=True, use_adx=False, adx_thr=20, use_kernel=True, exact=True):
260
+ """Machine Learning: Lorentzian Classification (jdehorty) Python portu.
261
+ Lorentzian mesafe = sum(log(1+|x-y|)); exact=True: gerçek k-NN, False: Pine'ın yaklaşık-NN döngüsü;
262
+ etiket = 4 bar sonraki yön. Filtreler: volatilite, rejim (Kalman eğimi), ADX; kernel:
263
+ Nadaraya-Watson rational quadratic. Her mum yalnızca kendisine kadarki veriyi kullanır.
264
+ state: +1 / -1 (ML sinyali + kernel eğimi aynı yönde), 0 onay yok."""
265
+ n = len(df)
266
+ F, s = _ldc_features(df)
267
+ y = np.full(n, np.nan)
268
+ y[:-4] = np.sign(s[4:]-s[:-4])
269
+ ok_f = np.isfinite(F).all(axis=1)
270
+ cand = ok_f & np.isfinite(y) & (np.arange(n) % 4 != 0)
271
+ kk = int(k)
272
+ cut = int(np.floor(kk*0.75+0.5))
273
+ pred = np.zeros(n)
274
+ for t in range(60, n):
275
+ if not ok_f[t]:
276
+ continue
277
+ hi_j = t-4 # etiketi t'de bilinen son örnek
278
+ lo_j = max(0, hi_j-int(max_back)+1)
279
+ sel = np.flatnonzero(cand[lo_j:hi_j+1]) + lo_j
280
+ if len(sel) < kk:
281
+ continue
282
+ D = np.log1p(np.abs(F[sel]-F[t])).sum(axis=1)
283
+ if exact: # gerçek k en yakın komşu (Lorentzian mesafe)
284
+ nn_ = np.argpartition(D, kk-1)[:kk]
285
+ pred[t] = y[sel][nn_].sum()
286
+ continue
287
+ last, dist, pr = -1.0, [], [] # Pine'ın kronolojik yaklaşık-NN döngüsü
288
+ for d, yv in zip(D.tolist(), y[sel].tolist()):
289
+ if d >= last:
290
+ dist.append(d)
291
+ pr.append(yv)
292
+ if len(dist) > kk:
293
+ last = dist[cut]
294
+ dist.pop(0)
295
+ pr.pop(0)
296
+ pred[t] = sum(pr)
297
+
298
+ # --- filtreler
299
+ f_vol = (calc_atr(df, 1).to_numpy(float) > calc_atr(df, 10).to_numpy(float)) if use_vol \
300
+ else np.ones(n, bool)
301
+ f_reg = np.ones(n, bool)
302
+ if use_regime:
303
+ o4 = ((df.Open+df.High+df.Low+df.Close)/4).to_numpy(float)
304
+ hl = (df.High-df.Low).to_numpy(float)
305
+ v1 = v2 = kl = 0.0
306
+ klmf = np.zeros(n)
307
+ for i in range(n):
308
+ v1 = 0.2*(o4[i]-(o4[i-1] if i else o4[i]))+0.8*v1
309
+ v2 = 0.1*hl[i]+0.8*v2
310
+ om = abs(v1/v2) if v2 else 0.0
311
+ al = (-om**2+np.sqrt(om**4+16*om**2))/8
312
+ kl = al*o4[i]+(1-al)*kl
313
+ klmf[i] = kl
314
+ slope = pd.Series(np.abs(np.diff(klmf, prepend=klmf[0])))
315
+ ema_s = slope.ewm(span=200, adjust=False).mean()
316
+ f_reg = (((slope-ema_s)/ema_s.replace(0, np.nan)) >= float(regime_thr)).fillna(False).to_numpy(bool)
317
+ f_adx = (adx_wilder(df, 14) > float(adx_thr)) if use_adx else np.ones(n, bool)
318
+ filt = f_vol & f_reg & f_adx
319
+
320
+ sig = np.zeros(n, dtype=int)
321
+ for t in range(1, n):
322
+ sig[t] = 1 if (pred[t] > 0 and filt[t]) else -1 if (pred[t] < 0 and filt[t]) else sig[t-1]
323
+
324
+ # --- kernel regresyon (rational quadratic), yalnızca geçmiş barlar
325
+ L = int(kern_lb)+int(x0)
326
+ i_ = np.arange(L+1)
327
+ w = (1+i_**2/(float(kern_lb)**2*2*float(kern_rw)))**(-float(kern_rw))
328
+ yhat = np.full(n, np.nan)
329
+ for t in range(n):
330
+ m = min(L+1, t+1)
331
+ yhat[t] = (w[:m]*s[t-np.arange(m)]).sum()/w[:m].sum()
332
+ bull = np.r_[False, yhat[1:] > yhat[:-1]]
333
+ bear = np.r_[False, yhat[1:] < yhat[:-1]]
334
+ if use_kernel:
335
+ state = np.where((sig == 1) & bull, 1, np.where((sig == -1) & bear, -1, 0)).astype(int)
336
+ else:
337
+ state = sig.copy()
338
+ state[:60] = 0
339
+ return {"state": state, "signal": sig, "pred": pred, "yhat": yhat,
340
+ "vol": f_vol, "reg": f_reg, "adx": f_adx}
341
+
342
+
343
  def regime_labels(features, ref_vol):
344
  # Volatilite kantilleri yalnızca geliştirme dönemi verisinden alınır (sızıntı yok).
345
  q1, q2 = ref_vol.dropna().quantile([0.33, 0.67])
 
541
 
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:
 
580
  marker_color=colors, name="Volume Profile", showlegend=False,
581
  hoverinfo="skip"), row=1, col=2)
582
  fig.update_xaxes(showticklabels=False, row=1, col=2)
583
+ if ldc is not None:
584
+ yh = np.asarray(ldc["yhat"])[-150:]
585
+ rising = np.r_[False, np.diff(yh) > 0]
586
+ for flag, col, nm in [(True, "#16a34a", "Lorentzian kernel ↑"), (False, "#dc2626", "Lorentzian kernel ↓")]:
587
+ fig.add_trace(go.Scatter(x=w.index, y=np.where(rising == flag, yh, np.nan), mode="lines",
588
+ name=nm, line=dict(width=2, color=col)), **kw)
589
+ st_ = np.asarray(ldc["state"])[-150:]
590
+ prev = np.r_[0, st_[:-1]]
591
+ for d, nm, col, ycol, off in [(1, "LDC long", "#15803d", "Low", 0.995),
592
+ (-1, "LDC short", "#b91c1c", "High", 1.005)]:
593
+ m_ = (st_ == d) & (prev != d)
594
+ if m_.any():
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"),
 
676
  max_leverage, fee, slip, train_window,
677
  p_min, p_gap, flat_max, agree_min, bacc_min, min_trades,
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
  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)
750
  cal_n = min(120, max(45, int(len(dev_X)*0.20)))
 
768
  side = 1 if p_up >= p_down else -1
769
  if ind_only and ind_now != 0 and allow[ind_now]:
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"]
 
778
  agreement = float((fit_y.iloc[idx[0]].to_numpy() == side).mean())
779
  if ind_only: # indikatör modunda: son 10 mumda yönün sürekliliği
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])
 
790
  f_ = list(dev_pos)
791
  if ind_only or ind_confirm:
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
 
811
  oos_bacc = float(balanced_accuracy_score(oos_y, oos_pred))
812
  oos_acc = float(accuracy_score(oos_y, oos_pred))
813
  oos_pos_arr = pos_of(oos_X.index)
814
+ if ldc_only: # Lorentzian yönü OOS'ta tahmin yerine geçer
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))
 
829
  continue
830
  if vp_on and vp_arr[i] != pred:
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]
 
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:
894
  checks.insert(1, ind_check)
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))
 
950
  f"uzama sınırı {float(vp_ext):g} ATR."
951
  + (" Hacim verisi yok → zaman bazlı profil kullanıldı." if vp_no_vol else "")
952
  + (" Mod Kapalı: yalnızca bilgi amaçlı." if not vp_on else ""))
953
+ if LD is not None:
954
+ fl = lambda on, arr: "kapalı" if not on else ("✅" if bool(arr[-1]) else "❌")
955
+ ldc_md = md_table(["Bileşen", "Değer"], [
956
+ ("Lorentzian yönü (ML + kernel)", dname[ldc_now]),
957
+ ("ML sinyali (filtreli)", dname[int(LD["signal"][-1])]),
958
+ ("ML tahmin skoru", f"{int(LD['pred'][-1]):+d} / ±{int(ldc_k)}"),
959
+ ("Kernel tahmini · eğim", f"{fmt_p(float(LD['yhat'][-1]))} · "
960
+ f"{'↑' if LD['yhat'][-1] > LD['yhat'][-2] else '↓'}"),
961
+ ("Volatilite / Rejim / ADX filtresi",
962
+ f"{fl(ldc_use_vol, LD['vol'])} / {fl(ldc_use_regime, LD['reg'])} / {fl(ldc_use_adx, LD['adx'])}")])
963
+ ldc_note = (f"{int(ldc_k)} komşu · en fazla {int(ldc_back)} geçmiş mum · kernel "
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
  ## İndikatörler — mod: {ind_mode}
989
  {ind_md}
990
 
991
+ ## Lorentzian Classification — mod: {ldc_mode}
992
+ {ldc_md}
993
+
994
+ {ldc_note}
995
+
996
  ## Volume Profile — mod: {vp_mode}
997
  {vp_md}
998
 
 
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
  "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)
 
1091
  side_mode = gr.Radio(SIDE_MODES, value="Long + Short", label="İzin verilen yön")
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
  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")
1120
+ ldc_regime = gr.Slider(-2.0, 2.0, value=-0.1, step=0.1, label="Rejim eşiği")
1121
+ with gr.Row():
1122
+ ldc_kern_lb = gr.Slider(3, 50, value=8, step=1, label="Kernel lookback")
1123
+ ldc_kern_rw = gr.Slider(0.25, 25, value=8, step=0.25, label="Kernel göreli ağırlık")
1124
+ with gr.Row():
1125
+ ldc_use_vol = gr.Checkbox(value=True, label="Volatilite filtresi")
1126
+ ldc_use_regime = gr.Checkbox(value=True, label="Rejim filtresi")
1127
+ ldc_use_adx = gr.Checkbox(value=False, label="ADX filtresi (eşik 20)")
1128
+ ldc_kernel = gr.Checkbox(value=True, label="Kernel ile onayla")
1129
+ ldc_exact = gr.Checkbox(value=True, label="Gerçek en yakın komşu (kapalı: Pine yaklaşık-NN)")
1130
  with gr.Row():
1131
  vp_window = gr.Slider(20, 250, value=60, step=5, label="Volume Profile penceresi (mum)")
1132
  vp_bins = gr.Slider(12, 60, value=24, step=2, label="Fiyat kutusu sayısı")
 
1160
  max_leverage, fee, slip, train_window,
1161
  p_min, p_gap, flat_max, agree_min, bacc_min, min_trades,
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
  )