Spaces:
Sleeping
Sleeping
Delete knn_calibrate.py
Browse files- knn_calibrate.py +0 -128
knn_calibrate.py
DELETED
|
@@ -1,128 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
KNN KALİBRASYON — walk-forward (seçim / test ayrımlı) parametre taraması.
|
| 3 |
-
|
| 4 |
-
Kullanım (app.py ile aynı klasörde, internet gerekir):
|
| 5 |
-
python knn_calibrate.py # BTC-USDT 1H, son 4000 bar
|
| 6 |
-
python knn_calibrate.py BTC-USDT 1H 6000
|
| 7 |
-
|
| 8 |
-
Mantık:
|
| 9 |
-
1) OKX history-candles ile uzun geçmiş indirilir (yalnızca kapanmış mumlar).
|
| 10 |
-
2) Parametre ızgarası: K, edge eşiği, ileri bar, SL/TP (ATR) çarpanları.
|
| 11 |
-
3) Skor aralığının İLK %60'ı = SEÇİM, SON %40'ı = TEST (hiç görülmemiş veri).
|
| 12 |
-
Parametreler yalnızca seçim dilimindeki sonuca göre sıralanır; TEST dilimi sadece raporlanır.
|
| 13 |
-
4) Her satırda "başa baş win rate" gösterilir: SL/(SL+TP). Win rate bunun üstünde değilse yüksek win rate kâr demek DEĞİLDİR.
|
| 14 |
-
"""
|
| 15 |
-
import itertools
|
| 16 |
-
import os
|
| 17 |
-
import sys
|
| 18 |
-
import time
|
| 19 |
-
|
| 20 |
-
os.environ["APP_NO_LAUNCH"] = "1"
|
| 21 |
-
import numpy as np
|
| 22 |
-
import pandas as pd
|
| 23 |
-
|
| 24 |
-
import app
|
| 25 |
-
|
| 26 |
-
GRID_K = (9, 15, 25)
|
| 27 |
-
GRID_EDGE = (0.15, 0.30, 0.50)
|
| 28 |
-
GRID_FWD = (3, 5, 8)
|
| 29 |
-
GRID_SLTP = ((1.5, 2.5), (2.0, 2.0), (2.5, 1.5), (3.0, 1.0)) # (SL, TP) ATR
|
| 30 |
-
MIN_TRADES = 20 # seçim diliminde en az bu kadar işlem yoksa satır sıralamaya girmez
|
| 31 |
-
SPLIT = 0.60
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
def fetch_history(inst_id="BTC-USDT", bar="1H", total=4000):
|
| 35 |
-
rows, after = [], None
|
| 36 |
-
while len(rows) < total:
|
| 37 |
-
p = {"instId": inst_id, "bar": bar, "limit": 100}
|
| 38 |
-
if after:
|
| 39 |
-
p["after"] = after
|
| 40 |
-
raw = app._get("/api/v5/market/history-candles", p)
|
| 41 |
-
if not raw:
|
| 42 |
-
break
|
| 43 |
-
rows += raw
|
| 44 |
-
after = raw[-1][0] # en eski mumun zamanı -> bir sonraki sayfa daha eskiyi getirir
|
| 45 |
-
time.sleep(0.12)
|
| 46 |
-
cols = ["ts", "o", "h", "l", "c", "vol", "volCcy", "volCcyQuote", "confirm"]
|
| 47 |
-
df = pd.DataFrame(rows, columns=cols).drop_duplicates("ts")
|
| 48 |
-
for c in ["o", "h", "l", "c", "vol"]:
|
| 49 |
-
df[c] = df[c].astype(float)
|
| 50 |
-
df["confirm"] = df["confirm"].astype(int)
|
| 51 |
-
df["ts"] = pd.to_datetime(df["ts"].astype(np.int64), unit="ms")
|
| 52 |
-
df = df[df["confirm"] == 1].sort_values("ts").reset_index(drop=True)
|
| 53 |
-
return df.tail(total).reset_index(drop=True)
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
def _stats(trades, sl, tp):
|
| 57 |
-
if not trades:
|
| 58 |
-
return None
|
| 59 |
-
pnl = np.array([t["pnl"] for t in trades])
|
| 60 |
-
r = np.array([t["r"] for t in trades])
|
| 61 |
-
gl = abs(pnl[pnl <= 0].sum())
|
| 62 |
-
return {"n": len(trades), "wr": float((pnl > 0).mean()),
|
| 63 |
-
"pf": float(pnl[pnl > 0].sum() / gl) if gl > 0 else float("inf"),
|
| 64 |
-
"exp_r": float(r.mean()), "be_wr": sl / (sl + tp)}
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
def run(df):
|
| 68 |
-
n = len(df)
|
| 69 |
-
results = []
|
| 70 |
-
for fwd in GRID_FWD:
|
| 71 |
-
app.KNN_FORWARD = fwd
|
| 72 |
-
for K, edge in itertools.product(GRID_K, GRID_EDGE):
|
| 73 |
-
app.KNN_K = K
|
| 74 |
-
app.KNN_MIN_EDGE = edge
|
| 75 |
-
app.KNN_TIERS = (edge, min(edge + 0.15, 0.85), min(edge + 0.35, 0.90), min(edge + 0.55, 0.95))
|
| 76 |
-
ind = app.compute_indicators(df)
|
| 77 |
-
ind["_arr"]["knn_y"] = app.knn_labels(df, ind, forward=fwd)
|
| 78 |
-
start = app.WARMUP_BARS + app.KNN_MIN_POOL + fwd
|
| 79 |
-
scores = [app._score_at(ind, i) for i in range(start, n)]
|
| 80 |
-
cut = start + int((n - start) * SPLIT)
|
| 81 |
-
for sl, tp in GRID_SLTP:
|
| 82 |
-
app.SL_ATR, app.TP_ATR = sl, tp
|
| 83 |
-
trades = app.simulate_trades(df, ind, start, scores)
|
| 84 |
-
sel = _stats([t for t in trades if t["signal_i"] < cut], sl, tp)
|
| 85 |
-
tst = _stats([t for t in trades if t["signal_i"] >= cut], sl, tp)
|
| 86 |
-
results.append({"K": K, "edge": edge, "fwd": fwd, "sl": sl, "tp": tp, "sel": sel, "test": tst})
|
| 87 |
-
return results
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
def _row(r):
|
| 91 |
-
f = lambda s: " — " if not s else f"n={s['n']:<3d} WR=%{s['wr'] * 100:4.1f} PF={min(s['pf'], 99):4.2f} R={s['exp_r']:+.2f}"
|
| 92 |
-
return (f"K={r['K']:<2d} edge={r['edge']:.2f} fwd={r['fwd']} SL/TP={r['sl']}/{r['tp']} (başa baş WR %{r['sel']['be_wr'] * 100:.0f}) | "
|
| 93 |
-
f"SEÇİM {f(r['sel'])} | TEST {f(r['test'])}")
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
def report(results):
|
| 97 |
-
ok = [r for r in results if r["sel"] and r["sel"]["n"] >= MIN_TRADES]
|
| 98 |
-
print(f"\nToplam kombinasyon: {len(results)} · seçim diliminde ≥{MIN_TRADES} işlemli: {len(ok)}")
|
| 99 |
-
if not ok:
|
| 100 |
-
print("Yeterli işlem üreten kombinasyon yok — daha çok bar indirin.")
|
| 101 |
-
return
|
| 102 |
-
print("\n── Seçim diliminde PROFIT FACTOR'e göre ilk 5 (test dilimi hiç görülmedi) ──")
|
| 103 |
-
for r in sorted(ok, key=lambda r: -r["sel"]["pf"])[:5]:
|
| 104 |
-
print(" ", _row(r))
|
| 105 |
-
hi = [r for r in ok if r["sel"]["pf"] >= 1.0]
|
| 106 |
-
print("\n── Seçimde PF ≥ 1 olanlar içinde WIN RATE'e göre ilk 5 ──")
|
| 107 |
-
for r in sorted(hi, key=lambda r: -r["sel"]["wr"])[:5]:
|
| 108 |
-
print(" ", _row(r))
|
| 109 |
-
tests = [r for r in ok if r["test"] and r["test"]["n"] >= 10]
|
| 110 |
-
best = max(tests, key=lambda r: r["test"]["wr"], default=None)
|
| 111 |
-
print("\n── DÜRÜST ÖZET ──")
|
| 112 |
-
if best:
|
| 113 |
-
print(f"Test diliminde (≥10 işlem) görülen en yüksek win rate: %{best['test']['wr'] * 100:.1f} (bu satır test sonucuna bakılarak seçildi → iyimser)")
|
| 114 |
-
top = sorted(ok, key=lambda r: -r["sel"]["pf"])[0]
|
| 115 |
-
if top["test"]:
|
| 116 |
-
t = top["test"]
|
| 117 |
-
print(f"Seçimde en iyi parametrenin TEST sonucu: WR %{t['wr'] * 100:.1f}, PF {min(t['pf'], 99):.2f}, ort. R {t['exp_r']:+.2f} ({t['n']} işlem)")
|
| 118 |
-
print("→ %80 hedefi tutuyorsa hem test win rate'i hem PF > 1 olmalı; yalnızca win rate yüksek ama PF < 1 ise parametre zarar ettiriyor demektir.")
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
if __name__ == "__main__":
|
| 122 |
-
inst = sys.argv[1] if len(sys.argv) > 1 else "BTC-USDT"
|
| 123 |
-
bar = sys.argv[2] if len(sys.argv) > 2 else "1H"
|
| 124 |
-
total = int(sys.argv[3]) if len(sys.argv) > 3 else 4000
|
| 125 |
-
print(f"{inst} {bar} için {total} bar indiriliyor...")
|
| 126 |
-
data = fetch_history(inst, bar, total)
|
| 127 |
-
print(f"{len(data)} bar: {data['ts'].iloc[0]} → {data['ts'].iloc[-1]}")
|
| 128 |
-
report(run(data))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|