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 |
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 |
-
|
| 729 |
-
checks.insert(1,
|
|
|
|
| 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 |
)
|