Spaces:
Sleeping
Sleeping
Update app.py
Browse files
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 |
-
|
| 414 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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)
|
| 737 |
-
|
| 738 |
-
|
| 739 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 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(
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 1002 |
| Parametre | Değer |
|
| 1003 |
|---|---:|
|
| 1004 |
-
| SL | {
|
| 1005 |
-
| TP | {
|
| 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 |
)
|