Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -28,6 +28,7 @@ SL_GRID = [0.8, 1.0, 1.2, 1.5, 1.8, 2.0, 2.5, 3.0]
|
|
| 28 |
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 |
|
| 32 |
_CACHE = {}
|
| 33 |
CACHE_TTL = 600 # saniye; Yahoo'yu gereksiz yere tekrar çağırmamak için
|
|
@@ -91,6 +92,53 @@ def make_features(df):
|
|
| 91 |
return x.replace([np.inf, -np.inf], np.nan), atr
|
| 92 |
|
| 93 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
def regime_labels(features, ref_vol):
|
| 95 |
# Volatilite kantilleri yalnızca geliştirme dönemi verisinden alınır (sızıntı yok).
|
| 96 |
q1, q2 = ref_vol.dropna().quantile([0.33, 0.67])
|
|
@@ -292,7 +340,7 @@ TRADE_COLS = ["entry_date", "exit_date", "side", "entry_price", "exit_reason",
|
|
| 292 |
|
| 293 |
|
| 294 |
# ---------------------------------------------------------------- grafikler
|
| 295 |
-
def price_figure(df, ticker, trades_df, trade_ok, stop, target):
|
| 296 |
w = df.tail(150)
|
| 297 |
fig = go.Figure([go.Candlestick(x=w.index, open=w.Open, high=w.High, low=w.Low,
|
| 298 |
close=w.Close, name=ticker)])
|
|
@@ -300,6 +348,13 @@ def price_figure(df, ticker, trades_df, trade_ok, stop, target):
|
|
| 300 |
ema = df.Close.ewm(span=n, adjust=False).mean().tail(150)
|
| 301 |
fig.add_trace(go.Scatter(x=w.index, y=ema, mode="lines", name=f"EMA{n}",
|
| 302 |
line=dict(width=1.2, color=col)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 303 |
if len(trades_df):
|
| 304 |
t = trades_df[trades_df.entry_date.isin(w.index)]
|
| 305 |
for side, sym, nm in [("LONG", "triangle-up", "OOS long"),
|
|
@@ -379,8 +434,7 @@ def mc_figure(mc):
|
|
| 379 |
def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
|
| 380 |
max_leverage, fee, slip, train_window,
|
| 381 |
p_min, p_gap, flat_max, agree_min, bacc_min, min_trades,
|
| 382 |
-
skip_overlap, whole_units):
|
| 383 |
-
empty = (None, None, None, None, None, pd.DataFrame(), None)
|
| 384 |
try:
|
| 385 |
ticker = str(ticker).strip().upper()
|
| 386 |
h = int(horizon)
|
|
@@ -419,6 +473,14 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
|
|
| 419 |
"c": df.Close.to_numpy(float), "a": atr_all.to_numpy(float)}
|
| 420 |
pos_of = lambda idx: df.index.get_indexer(idx)
|
| 421 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 422 |
# --- K seçimi, kalibrasyon, güncel olasılık
|
| 423 |
best_k, k_scores = tune_k(dev_X, dev_y, h)
|
| 424 |
cal_n = min(120, max(45, int(len(dev_X)*0.20)))
|
|
@@ -440,21 +502,32 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
|
|
| 440 |
side = -1
|
| 441 |
else:
|
| 442 |
side = 1 if p_up >= p_down else -1
|
|
|
|
|
|
|
| 443 |
p_side, p_opp = (p_up, p_down) if side == 1 else (p_down, p_up)
|
| 444 |
|
| 445 |
imp, scaler = cal_model.named_steps["imputer"], cal_model.named_steps["scale"]
|
| 446 |
nn = NearestNeighbors(n_neighbors=best_k).fit(scaler.transform(imp.transform(fit_X)))
|
| 447 |
_, idx = nn.kneighbors(scaler.transform(imp.transform(current_x)))
|
| 448 |
agreement = float((fit_y.iloc[idx[0]].to_numpy() == side).mean())
|
|
|
|
|
|
|
| 449 |
|
| 450 |
# --- yön bazlı TP/SL optimizasyonu (yalnızca geliştirme verisi)
|
| 451 |
current_regime = str(regimes_all.iloc[-1])
|
| 452 |
dev_pos = pos_of(dev_X.index)
|
| 453 |
params, top, regime_used = {}, [], "—"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 454 |
for s in (1, -1):
|
| 455 |
if allow[s]:
|
| 456 |
sl_s, rr_s, top_s, used_s = optimize_barriers(
|
| 457 |
-
A,
|
| 458 |
params[s] = (sl_s, rr_s)
|
| 459 |
if s == side:
|
| 460 |
top, regime_used = top_s, used_s
|
|
@@ -466,12 +539,19 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
|
|
| 466 |
oos_pred = pipe(best_k).fit(dev_X, dev_y).predict(oos_X)
|
| 467 |
oos_bacc = float(balanced_accuracy_score(oos_y, oos_pred))
|
| 468 |
oos_acc = float(accuracy_score(oos_y, oos_pred))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
|
| 470 |
rows, busy = [], -1
|
| 471 |
-
for i, pred in zip(
|
| 472 |
pred = int(pred)
|
| 473 |
if pred == 0 or not allow[pred]:
|
| 474 |
continue
|
|
|
|
|
|
|
| 475 |
if skip_overlap and i <= busy:
|
| 476 |
continue
|
| 477 |
sl_p, rr_p = params[pred]
|
|
@@ -526,6 +606,14 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
|
|
| 526 |
("OOS işlem sayısı", f"{len(R)}", f"≥ {int(min_trades)}", len(R) >= int(min_trades)),
|
| 527 |
("OOS expectancy", f"{expectancy_r:.3f}R", "> 0", expectancy_r > 0),
|
| 528 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 529 |
trade_ok = all(c[3] for c in checks)
|
| 530 |
if trade_ok:
|
| 531 |
signal = "LONG" if side == 1 else "SHORT"
|
|
@@ -560,6 +648,10 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
|
|
| 560 |
f"%5 kuyruk max DD: {mc['dd95']:.2%} · "
|
| 561 |
f"%50 sermaye altına inme frekansı: {mc['ruin']:.1%}"
|
| 562 |
if mc else "Monte Carlo için yeterli OOS işlem yok.")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 563 |
k_text = " | ".join(f"K={k}: {s:.3f}" for s, k in sorted(k_scores, reverse=True)) or "—"
|
| 564 |
overlap_note = ("tek pozisyon (çakışma yok)" if skip_overlap
|
| 565 |
else "çakışan sinyaller bağımsız işlem sayıldı")
|
|
@@ -581,6 +673,9 @@ def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
|
|
| 581 |
|
| 582 |
**K seçim skorları:** {k_text}
|
| 583 |
|
|
|
|
|
|
|
|
|
|
| 584 |
## TP / SL ({'LONG' if side == 1 else 'SHORT'} için optimize)
|
| 585 |
| Parametre | Değer |
|
| 586 |
|---|---:|
|
|
@@ -628,7 +723,8 @@ TP/SL optimizasyon rejimi: {regime_used}. Yeterli rejim örneği yoksa tüm geli
|
|
| 628 |
csv_path = os.path.join(tempfile.gettempdir(), f"goshawk_{safe}_oos_trades.csv")
|
| 629 |
trades_df.to_csv(csv_path, index=False)
|
| 630 |
|
| 631 |
-
price_fig = price_figure(df, ticker, trades_df, trade_ok, stop, target
|
|
|
|
| 632 |
eq_fig = equity_figure(curve, dds) if len(R) else None
|
| 633 |
pf_fig = pf_gauge(stats["pf"], stats["n"]) if stats else None
|
| 634 |
mc_fig = mc_figure(mc) if mc else None
|
|
@@ -644,14 +740,15 @@ TP/SL optimizasyon rejimi: {regime_used}. Yeterli rejim örneği yoksa tüm geli
|
|
| 644 |
"seri korelasyonunu ve rejim değişimini tam modellemez. Pozisyon hesabı spot miktar "
|
| 645 |
"varsayar; CFD lot sözleşmesi, spread, funding, swap, komisyon, minimum lot, marjin ve "
|
| 646 |
"broker fiyatı farklı olabilir. Gap ve kayma kaybı planlanan riskin üstüne çıkarabilir. "
|
| 647 |
-
"Canlı hesap öncesi paper trading ve broker bazlı doğrulama zorunludur."
|
| 648 |
)
|
| 649 |
return (report, prob_figure(p_down, p_flat, p_up), price_fig, eq_fig, pf_fig, mc_fig,
|
| 650 |
top_df, csv_path, disclaimer)
|
| 651 |
|
| 652 |
except Exception as exc:
|
| 653 |
-
return (f"# Hata\n{type(exc).__name__}: {exc}",
|
| 654 |
-
|
|
|
|
| 655 |
|
| 656 |
|
| 657 |
# ---------------------------------------------------------------- arayüz
|
|
@@ -668,6 +765,7 @@ with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
|
|
| 668 |
period = gr.Dropdown(["2y", "5y", "10y", "max"], value="5y", label="Veri geçmişi")
|
| 669 |
horizon = gr.Dropdown([3, 5, 10], value=5, label="Tahmin ufku (gün)")
|
| 670 |
side_mode = gr.Radio(SIDE_MODES, value="Long + Short", label="İzin verilen yön")
|
|
|
|
| 671 |
train_window = gr.Slider(300, 1500, value=900, step=50, label="Maksimum eğitim penceresi")
|
| 672 |
with gr.Column():
|
| 673 |
equity = gr.Number(value=10000, label="Hesap büyüklüğü (USD)")
|
|
@@ -685,6 +783,11 @@ with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
|
|
| 685 |
agree_min = gr.Slider(0.30, 0.90, value=0.55, step=0.01, label="Min. komşu uyumu")
|
| 686 |
bacc_min = gr.Slider(0.30, 0.60, value=0.36, step=0.01, label="Min. OOS balanced acc.")
|
| 687 |
min_trades = gr.Slider(5, 50, value=15, step=1, label="Min. OOS işlem sayısı")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 688 |
with gr.Row():
|
| 689 |
skip_overlap = gr.Checkbox(value=False, label="Açık pozisyon varken yeni sinyali atla (tek pozisyon)")
|
| 690 |
whole_units = gr.Checkbox(value=False, label="Miktarı tam sayıya yuvarla (hisse)")
|
|
@@ -712,11 +815,10 @@ with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
|
|
| 712 |
inputs=[ticker, period, horizon, side_mode, equity, min_risk, max_risk,
|
| 713 |
max_leverage, fee, slip, train_window,
|
| 714 |
p_min, p_gap, flat_max, agree_min, bacc_min, min_trades,
|
| 715 |
-
skip_overlap, whole_units],
|
| 716 |
outputs=[output, prob_plot, chart, equity_plot, pf_plot, mc_plot, optimization,
|
| 717 |
csv_file, disclaimer],
|
| 718 |
)
|
| 719 |
|
| 720 |
if __name__ == "__main__":
|
| 721 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|
| 722 |
-
0
|
|
|
|
| 28 |
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 |
|
| 33 |
_CACHE = {}
|
| 34 |
CACHE_TTL = 600 # saniye; Yahoo'yu gereksiz yere tekrar çağırmamak için
|
|
|
|
| 92 |
return x.replace([np.inf, -np.inf], np.nan), atr
|
| 93 |
|
| 94 |
|
| 95 |
+
def supertrend(df, period=10, mult=3.0):
|
| 96 |
+
"""TradingView ta.supertrend portu. dir: +1 yükseliş, -1 düşüş."""
|
| 97 |
+
atr = calc_atr(df, period).to_numpy(float)
|
| 98 |
+
h, l, c = df.High.to_numpy(float), df.Low.to_numpy(float), df.Close.to_numpy(float)
|
| 99 |
+
hl2 = (h+l)/2
|
| 100 |
+
n = len(c)
|
| 101 |
+
up, dn = hl2-mult*atr, hl2+mult*atr
|
| 102 |
+
trend = np.ones(n, dtype=int)
|
| 103 |
+
for i in range(1, n):
|
| 104 |
+
if c[i-1] > up[i-1]:
|
| 105 |
+
up[i] = max(up[i], up[i-1])
|
| 106 |
+
if c[i-1] < dn[i-1]:
|
| 107 |
+
dn[i] = min(dn[i], dn[i-1])
|
| 108 |
+
trend[i] = trend[i-1]
|
| 109 |
+
if trend[i-1] == -1 and c[i] > dn[i-1]:
|
| 110 |
+
trend[i] = 1
|
| 111 |
+
elif trend[i-1] == 1 and c[i] < up[i-1]:
|
| 112 |
+
trend[i] = -1
|
| 113 |
+
return trend, np.where(trend == 1, up, dn)
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def ut_bot(df, key=1.0, period=10):
|
| 117 |
+
"""UT Bot Alerts (QuantNomad) portu. pos: +1 al, -1 sat, 0 henüz sinyal yok."""
|
| 118 |
+
c = df.Close.to_numpy(float)
|
| 119 |
+
nloss = key*calc_atr(df, period).to_numpy(float)
|
| 120 |
+
n = len(c)
|
| 121 |
+
stop, pos = np.zeros(n), np.zeros(n, dtype=int)
|
| 122 |
+
stop[0] = c[0]-nloss[0]
|
| 123 |
+
for i in range(1, n):
|
| 124 |
+
prev = stop[i-1]
|
| 125 |
+
if c[i] > prev and c[i-1] > prev:
|
| 126 |
+
stop[i] = max(prev, c[i]-nloss[i])
|
| 127 |
+
elif c[i] < prev and c[i-1] < prev:
|
| 128 |
+
stop[i] = min(prev, c[i]+nloss[i])
|
| 129 |
+
elif c[i] > prev:
|
| 130 |
+
stop[i] = c[i]-nloss[i]
|
| 131 |
+
else:
|
| 132 |
+
stop[i] = c[i]+nloss[i]
|
| 133 |
+
if c[i-1] < prev and c[i] > prev:
|
| 134 |
+
pos[i] = 1
|
| 135 |
+
elif c[i-1] > prev and c[i] < prev:
|
| 136 |
+
pos[i] = -1
|
| 137 |
+
else:
|
| 138 |
+
pos[i] = pos[i-1]
|
| 139 |
+
return pos, stop
|
| 140 |
+
|
| 141 |
+
|
| 142 |
def regime_labels(features, ref_vol):
|
| 143 |
# Volatilite kantilleri yalnızca geliştirme dönemi verisinden alınır (sızıntı yok).
|
| 144 |
q1, q2 = ref_vol.dropna().quantile([0.33, 0.67])
|
|
|
|
| 340 |
|
| 341 |
|
| 342 |
# ---------------------------------------------------------------- grafikler
|
| 343 |
+
def price_figure(df, ticker, trades_df, trade_ok, stop, target, ind=None):
|
| 344 |
w = df.tail(150)
|
| 345 |
fig = go.Figure([go.Candlestick(x=w.index, open=w.Open, high=w.High, low=w.Low,
|
| 346 |
close=w.Close, name=ticker)])
|
|
|
|
| 348 |
ema = df.Close.ewm(span=n, adjust=False).mean().tail(150)
|
| 349 |
fig.add_trace(go.Scatter(x=w.index, y=ema, mode="lines", name=f"EMA{n}",
|
| 350 |
line=dict(width=1.2, color=col)))
|
| 351 |
+
if ind is not None:
|
| 352 |
+
st_line, st_dir, ut_stop = (np.asarray(a)[-150:] for a in ind)
|
| 353 |
+
for d, col, nm in [(1, "#16a34a", "Supertrend ↑"), (-1, "#dc2626", "Supertrend ↓")]:
|
| 354 |
+
fig.add_trace(go.Scatter(x=w.index, y=np.where(st_dir == d, st_line, np.nan),
|
| 355 |
+
mode="lines", name=nm, line=dict(width=1.5, color=col)))
|
| 356 |
+
fig.add_trace(go.Scatter(x=w.index, y=ut_stop, mode="lines", name="UT trailing stop",
|
| 357 |
+
line=dict(width=1, dash="dot", color="#9333ea")))
|
| 358 |
if len(trades_df):
|
| 359 |
t = trades_df[trades_df.entry_date.isin(w.index)]
|
| 360 |
for side, sym, nm in [("LONG", "triangle-up", "OOS long"),
|
|
|
|
| 434 |
def run_engine(ticker, period, horizon, side_mode, equity, min_risk, max_risk,
|
| 435 |
max_leverage, fee, slip, train_window,
|
| 436 |
p_min, p_gap, flat_max, agree_min, bacc_min, min_trades,
|
| 437 |
+
skip_overlap, whole_units, ind_mode, st_period, st_mult, ut_key, ut_period):
|
|
|
|
| 438 |
try:
|
| 439 |
ticker = str(ticker).strip().upper()
|
| 440 |
h = int(horizon)
|
|
|
|
| 473 |
"c": df.Close.to_numpy(float), "a": atr_all.to_numpy(float)}
|
| 474 |
pos_of = lambda idx: df.index.get_indexer(idx)
|
| 475 |
|
| 476 |
+
# --- indikatörler (Supertrend + UT Bot), tamamen Python'da
|
| 477 |
+
st_dir, st_line = supertrend(df, int(st_period), float(st_mult))
|
| 478 |
+
ut_pos, ut_stop = ut_bot(df, float(ut_key), int(ut_period))
|
| 479 |
+
ind_arr = np.where((st_dir == ut_pos) & (ut_pos != 0), ut_pos, 0).astype(int)
|
| 480 |
+
ind_only = ind_mode == "Sadece indikatör"
|
| 481 |
+
ind_confirm = ind_mode == IND_MODES[1]
|
| 482 |
+
ind_now = int(ind_arr[-1])
|
| 483 |
+
|
| 484 |
# --- K seçimi, kalibrasyon, güncel olasılık
|
| 485 |
best_k, k_scores = tune_k(dev_X, dev_y, h)
|
| 486 |
cal_n = min(120, max(45, int(len(dev_X)*0.20)))
|
|
|
|
| 502 |
side = -1
|
| 503 |
else:
|
| 504 |
side = 1 if p_up >= p_down else -1
|
| 505 |
+
if ind_only and ind_now != 0 and allow[ind_now]:
|
| 506 |
+
side = ind_now
|
| 507 |
p_side, p_opp = (p_up, p_down) if side == 1 else (p_down, p_up)
|
| 508 |
|
| 509 |
imp, scaler = cal_model.named_steps["imputer"], cal_model.named_steps["scale"]
|
| 510 |
nn = NearestNeighbors(n_neighbors=best_k).fit(scaler.transform(imp.transform(fit_X)))
|
| 511 |
_, idx = nn.kneighbors(scaler.transform(imp.transform(current_x)))
|
| 512 |
agreement = float((fit_y.iloc[idx[0]].to_numpy() == side).mean())
|
| 513 |
+
if ind_only: # indikatör modunda: son 10 mumda yönün sürekliliği
|
| 514 |
+
agreement = float((ind_arr[-10:] == side).mean())
|
| 515 |
|
| 516 |
# --- yön bazlı TP/SL optimizasyonu (yalnızca geliştirme verisi)
|
| 517 |
current_regime = str(regimes_all.iloc[-1])
|
| 518 |
dev_pos = pos_of(dev_X.index)
|
| 519 |
params, top, regime_used = {}, [], "—"
|
| 520 |
+
|
| 521 |
+
def opt_pos(s_):
|
| 522 |
+
if ind_only or ind_confirm:
|
| 523 |
+
f_ = [i for i in dev_pos if ind_arr[i] == s_]
|
| 524 |
+
if len(f_) >= 35:
|
| 525 |
+
return f_
|
| 526 |
+
return dev_pos
|
| 527 |
for s in (1, -1):
|
| 528 |
if allow[s]:
|
| 529 |
sl_s, rr_s, top_s, used_s = optimize_barriers(
|
| 530 |
+
A, opt_pos(s), reg_arr, s, cost, current_regime, h)
|
| 531 |
params[s] = (sl_s, rr_s)
|
| 532 |
if s == side:
|
| 533 |
top, regime_used = top_s, used_s
|
|
|
|
| 539 |
oos_pred = pipe(best_k).fit(dev_X, dev_y).predict(oos_X)
|
| 540 |
oos_bacc = float(balanced_accuracy_score(oos_y, oos_pred))
|
| 541 |
oos_acc = float(accuracy_score(oos_y, oos_pred))
|
| 542 |
+
oos_pos_arr = pos_of(oos_X.index)
|
| 543 |
+
if ind_only: # indikatör yönü OOS'ta tahmin yerine geçer
|
| 544 |
+
oos_pred = ind_arr[oos_pos_arr]
|
| 545 |
+
oos_bacc = float(balanced_accuracy_score(oos_y, oos_pred))
|
| 546 |
+
oos_acc = float(accuracy_score(oos_y, oos_pred))
|
| 547 |
|
| 548 |
rows, busy = [], -1
|
| 549 |
+
for i, pred in zip(oos_pos_arr, oos_pred):
|
| 550 |
pred = int(pred)
|
| 551 |
if pred == 0 or not allow[pred]:
|
| 552 |
continue
|
| 553 |
+
if ind_confirm and ind_arr[i] != pred:
|
| 554 |
+
continue
|
| 555 |
if skip_overlap and i <= busy:
|
| 556 |
continue
|
| 557 |
sl_p, rr_p = params[pred]
|
|
|
|
| 606 |
("OOS işlem sayısı", f"{len(R)}", f"≥ {int(min_trades)}", len(R) >= int(min_trades)),
|
| 607 |
("OOS expectancy", f"{expectancy_r:.3f}R", "> 0", expectancy_r > 0),
|
| 608 |
]
|
| 609 |
+
dname = {1: "LONG ↑", -1: "SHORT ↓", 0: "belirsiz"}
|
| 610 |
+
ind_check = ("İndikatör yönü (ST + UT aynı)", dname[ind_now], "yönle aynı", ind_now == side)
|
| 611 |
+
if ind_only:
|
| 612 |
+
keep = ("Yön izni", "OOS balanced acc.", "OOS işlem sayısı", "OOS expectancy")
|
| 613 |
+
checks = [c for c in checks if c[0] in keep]
|
| 614 |
+
checks.insert(1, ind_check)
|
| 615 |
+
elif ind_confirm:
|
| 616 |
+
checks.insert(1, ind_check)
|
| 617 |
trade_ok = all(c[3] for c in checks)
|
| 618 |
if trade_ok:
|
| 619 |
signal = "LONG" if side == 1 else "SHORT"
|
|
|
|
| 648 |
f"%5 kuyruk max DD: {mc['dd95']:.2%} · "
|
| 649 |
f"%50 sermaye altına inme frekansı: {mc['ruin']:.1%}"
|
| 650 |
if mc else "Monte Carlo için yeterli OOS işlem yok.")
|
| 651 |
+
ind_md = md_table(["İndikatör", "Yön", "Seviye"], [
|
| 652 |
+
(f"Supertrend ({int(st_period)}, {float(st_mult):g})", dname[int(st_dir[-1])], fmt_p(float(st_line[-1]))),
|
| 653 |
+
(f"UT Bot ({float(ut_key):g}, {int(ut_period)})", dname[int(ut_pos[-1])], fmt_p(float(ut_stop[-1]))),
|
| 654 |
+
("Bileşik (ikisi aynı yönde)", dname[ind_now], "—")])
|
| 655 |
k_text = " | ".join(f"K={k}: {s:.3f}" for s, k in sorted(k_scores, reverse=True)) or "—"
|
| 656 |
overlap_note = ("tek pozisyon (çakışma yok)" if skip_overlap
|
| 657 |
else "çakışan sinyaller bağımsız işlem sayıldı")
|
|
|
|
| 673 |
|
| 674 |
**K seçim skorları:** {k_text}
|
| 675 |
|
| 676 |
+
## İndikatörler — mod: {ind_mode}
|
| 677 |
+
{ind_md}
|
| 678 |
+
|
| 679 |
## TP / SL ({'LONG' if side == 1 else 'SHORT'} için optimize)
|
| 680 |
| Parametre | Değer |
|
| 681 |
|---|---:|
|
|
|
|
| 723 |
csv_path = os.path.join(tempfile.gettempdir(), f"goshawk_{safe}_oos_trades.csv")
|
| 724 |
trades_df.to_csv(csv_path, index=False)
|
| 725 |
|
| 726 |
+
price_fig = price_figure(df, ticker, trades_df, trade_ok, stop, target,
|
| 727 |
+
ind=(st_line, st_dir, ut_stop))
|
| 728 |
eq_fig = equity_figure(curve, dds) if len(R) else None
|
| 729 |
pf_fig = pf_gauge(stats["pf"], stats["n"]) if stats else None
|
| 730 |
mc_fig = mc_figure(mc) if mc else None
|
|
|
|
| 740 |
"seri korelasyonunu ve rejim değişimini tam modellemez. Pozisyon hesabı spot miktar "
|
| 741 |
"varsayar; CFD lot sözleşmesi, spread, funding, swap, komisyon, minimum lot, marjin ve "
|
| 742 |
"broker fiyatı farklı olabilir. Gap ve kayma kaybı planlanan riskin üstüne çıkarabilir. "
|
| 743 |
+
"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. Canlı hesap öncesi paper trading ve broker bazlı doğrulama zorunludur."
|
| 744 |
)
|
| 745 |
return (report, prob_figure(p_down, p_flat, p_up), price_fig, eq_fig, pf_fig, mc_fig,
|
| 746 |
top_df, csv_path, disclaimer)
|
| 747 |
|
| 748 |
except Exception as exc:
|
| 749 |
+
return (f"# Hata\n{type(exc).__name__}: {exc}", None, None, None, None, None,
|
| 750 |
+
pd.DataFrame(), None,
|
| 751 |
+
"Veri bağlantısını ve parametreleri kontrol edin.")
|
| 752 |
|
| 753 |
|
| 754 |
# ---------------------------------------------------------------- arayüz
|
|
|
|
| 765 |
period = gr.Dropdown(["2y", "5y", "10y", "max"], value="5y", label="Veri geçmişi")
|
| 766 |
horizon = gr.Dropdown([3, 5, 10], value=5, label="Tahmin ufku (gün)")
|
| 767 |
side_mode = gr.Radio(SIDE_MODES, value="Long + Short", label="İzin verilen yön")
|
| 768 |
+
ind_mode = gr.Radio(IND_MODES, value="Kapalı", label="İndikatör modu (Supertrend + UT Bot)")
|
| 769 |
train_window = gr.Slider(300, 1500, value=900, step=50, label="Maksimum eğitim penceresi")
|
| 770 |
with gr.Column():
|
| 771 |
equity = gr.Number(value=10000, label="Hesap büyüklüğü (USD)")
|
|
|
|
| 783 |
agree_min = gr.Slider(0.30, 0.90, value=0.55, step=0.01, label="Min. komşu uyumu")
|
| 784 |
bacc_min = gr.Slider(0.30, 0.60, value=0.36, step=0.01, label="Min. OOS balanced acc.")
|
| 785 |
min_trades = gr.Slider(5, 50, value=15, step=1, label="Min. OOS işlem sayısı")
|
| 786 |
+
with gr.Row():
|
| 787 |
+
st_period = gr.Slider(5, 30, value=10, step=1, label="Supertrend ATR periyodu")
|
| 788 |
+
st_mult = gr.Slider(1.0, 6.0, value=3.0, step=0.1, label="Supertrend çarpanı")
|
| 789 |
+
ut_key = gr.Slider(0.5, 4.0, value=1.0, step=0.1, label="UT Bot key value")
|
| 790 |
+
ut_period = gr.Slider(5, 30, value=10, step=1, label="UT Bot ATR periyodu")
|
| 791 |
with gr.Row():
|
| 792 |
skip_overlap = gr.Checkbox(value=False, label="Açık pozisyon varken yeni sinyali atla (tek pozisyon)")
|
| 793 |
whole_units = gr.Checkbox(value=False, label="Miktarı tam sayıya yuvarla (hisse)")
|
|
|
|
| 815 |
inputs=[ticker, period, horizon, side_mode, equity, min_risk, max_risk,
|
| 816 |
max_leverage, fee, slip, train_window,
|
| 817 |
p_min, p_gap, flat_max, agree_min, bacc_min, min_trades,
|
| 818 |
+
skip_overlap, whole_units, ind_mode, st_period, st_mult, ut_key, ut_period],
|
| 819 |
outputs=[output, prob_plot, chart, equity_plot, pf_plot, mc_plot, optimization,
|
| 820 |
csv_file, disclaimer],
|
| 821 |
)
|
| 822 |
|
| 823 |
if __name__ == "__main__":
|
| 824 |
demo.launch(server_name="0.0.0.0", server_port=7860)
|
|
|