GoshawkVortexAI commited on
Commit
5a9c9df
·
verified ·
1 Parent(s): 2d5bce4

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +0 -0
  2. knn_calibrate.py +128 -0
app.py ADDED
The diff for this file is too large to render. See raw diff
 
knn_calibrate.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.30, 0.50, 0.70)
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.2, 0.90), min(edge + 0.4, 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))