GoshawkVortexAI commited on
Commit
fafa9aa
·
verified ·
1 Parent(s): 99329ac

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -354
app.py DELETED
@@ -1,354 +0,0 @@
1
- import warnings
2
- warnings.filterwarnings("ignore")
3
-
4
- from datetime import datetime, timezone
5
- import numpy as np
6
- import pandas as pd
7
- import yfinance as yf
8
- import gradio as gr
9
- import plotly.graph_objects as go
10
-
11
- from sklearn.pipeline import Pipeline
12
- from sklearn.preprocessing import StandardScaler
13
- from sklearn.impute import SimpleImputer
14
- from sklearn.neighbors import KNeighborsClassifier, NearestNeighbors
15
- from sklearn.metrics import accuracy_score, balanced_accuracy_score, confusion_matrix
16
-
17
- APP_TITLE = "BTCUSD KNN Daily Risk Engine"
18
-
19
- def rsi(series, period=14):
20
- delta = series.diff()
21
- gain = delta.clip(lower=0).ewm(alpha=1 / period, adjust=False).mean()
22
- loss = (-delta.clip(upper=0)).ewm(alpha=1 / period, adjust=False).mean()
23
- rs = gain / loss.replace(0, np.nan)
24
- return 100 - (100 / (1 + rs))
25
-
26
- def atr(df, period=14):
27
- prev_close = df["Close"].shift(1)
28
- tr = pd.concat([
29
- df["High"] - df["Low"],
30
- (df["High"] - prev_close).abs(),
31
- (df["Low"] - prev_close).abs()
32
- ], axis=1).max(axis=1)
33
- return tr.ewm(alpha=1 / period, adjust=False).mean()
34
-
35
- def download_data(period):
36
- df = yf.download("BTC-USD", period=period, interval="1d",
37
- auto_adjust=True, progress=False)
38
- if df is None or df.empty:
39
- raise ValueError("Yahoo Finance veri döndürmedi. Daha sonra tekrar deneyin.")
40
- if isinstance(df.columns, pd.MultiIndex):
41
- df.columns = df.columns.get_level_values(0)
42
- needed = ["Open", "High", "Low", "Close", "Volume"]
43
- df = df[needed].copy().dropna()
44
- df.index = pd.to_datetime(df.index)
45
- return df
46
-
47
- def make_features(df):
48
- x = pd.DataFrame(index=df.index)
49
- close = df["Close"]
50
- ret = close.pct_change()
51
- for n in [1, 2, 3, 5, 10, 20]:
52
- x[f"ret_{n}"] = close.pct_change(n)
53
- x["rsi_14"] = rsi(close, 14) / 100.0
54
- a = atr(df, 14)
55
- x["atr_pct"] = a / close
56
- x["range_pct"] = (df["High"] - df["Low"]) / close
57
- x["body_pct"] = (df["Close"] - df["Open"]) / df["Open"]
58
- for n in [5, 10, 20, 50]:
59
- ema = close.ewm(span=n, adjust=False).mean()
60
- x[f"ema_gap_{n}"] = close / ema - 1
61
- ema12 = close.ewm(span=12, adjust=False).mean()
62
- ema26 = close.ewm(span=26, adjust=False).mean()
63
- macd = ema12 - ema26
64
- signal = macd.ewm(span=9, adjust=False).mean()
65
- x["macd_hist_pct"] = (macd - signal) / close
66
- x["volatility_10"] = ret.rolling(10).std()
67
- x["volatility_20"] = ret.rolling(20).std()
68
- vol_mean = df["Volume"].rolling(20).mean()
69
- vol_std = df["Volume"].rolling(20).std()
70
- x["volume_z20"] = (df["Volume"] - vol_mean) / vol_std.replace(0, np.nan)
71
- x["volume_change"] = df["Volume"].pct_change()
72
- return x.replace([np.inf, -np.inf], np.nan), a
73
-
74
- def build_model(k):
75
- return Pipeline([
76
- ("imputer", SimpleImputer(strategy="median")),
77
- ("scaler", StandardScaler()),
78
- ("knn", KNeighborsClassifier(
79
- n_neighbors=k, weights="distance", metric="minkowski", p=2
80
- ))
81
- ])
82
-
83
- def fmt_pct(v):
84
- return f"{v * 100:.2f}%"
85
-
86
- def run_engine(period, k, train_window, threshold_atr, atr_stop,
87
- reward_risk, equity, risk_pct, max_leverage,
88
- contract_size, fee_pct, slippage_pct, use_latest):
89
- try:
90
- df = download_data(period)
91
- if len(df) < 180:
92
- raise ValueError("Yeterli günlük veri yok. En az 180 mum gerekli.")
93
-
94
- # Yahoo'nun son günlük mumu henüz kapanmamış olabilir.
95
- if not use_latest and len(df) > 2:
96
- df = df.iloc[:-1].copy()
97
-
98
- X, atr_series = make_features(df)
99
- next_ret = df["Close"].shift(-1) / df["Close"] - 1
100
- next_atr_pct = atr_series / df["Close"]
101
- band = threshold_atr * next_atr_pct
102
-
103
- # Üç sınıf: -1 aşağı, 0 nötr, +1 yukarı.
104
- y = pd.Series(
105
- np.where(next_ret > band, 1, np.where(next_ret < -band, -1, 0)),
106
- index=df.index
107
- )
108
-
109
- data = X.copy()
110
- data["target"] = y
111
- data["future_return"] = next_ret
112
- data = data.replace([np.inf, -np.inf], np.nan)
113
- feature_cols = list(X.columns)
114
-
115
- # Son satırın ileriye dönük hedefi bilinmez; yalnızca eğitimden çıkarılır.
116
- trainable = data.dropna(subset=["target", "future_return"])
117
- trainable = trainable.dropna(subset=feature_cols, how="all")
118
- if len(trainable) < max(100, int(k) + 30):
119
- raise ValueError("KNN eğitimi için yeterli temiz örnek bulunamadı.")
120
-
121
- # Son kapanmış mumun özellikleriyle tahmin.
122
- current_x = X.iloc[[-1]]
123
- if current_x.isna().all(axis=1).iloc[0]:
124
- raise ValueError("Son mum için özellik üretilemedi.")
125
-
126
- window = min(int(train_window), len(trainable))
127
- train = trainable.iloc[-window:]
128
- if len(train) <= int(k):
129
- raise ValueError("Komşu sayısı eğitim örneklerinden küçük olmalı.")
130
-
131
- model = build_model(int(k))
132
- model.fit(train[feature_cols], train["target"].astype(int))
133
- probs = model.predict_proba(current_x[feature_cols])[0]
134
- classes = model.named_steps["knn"].classes_
135
- prob_map = {int(c): float(p) for c, p in zip(classes, probs)}
136
- p_down = prob_map.get(-1, 0.0)
137
- p_flat = prob_map.get(0, 0.0)
138
- p_up = prob_map.get(1, 0.0)
139
-
140
- # Yakın geçmiş örnekleri: aynı özellik uzayında en yakın K gözlem.
141
- transformed_train = model.named_steps["scaler"].transform(
142
- model.named_steps["imputer"].transform(train[feature_cols])
143
- )
144
- transformed_now = model.named_steps["scaler"].transform(
145
- model.named_steps["imputer"].transform(current_x[feature_cols])
146
- )
147
- nn = NearestNeighbors(n_neighbors=int(k), metric="euclidean")
148
- nn.fit(transformed_train)
149
- distances, indices = nn.kneighbors(transformed_now)
150
- neighbors = train.iloc[indices[0]].copy()
151
- neighbors["distance"] = distances[0]
152
- mean_neighbor_return = float(neighbors["future_return"].mean())
153
- median_neighbor_return = float(neighbors["future_return"].median())
154
-
155
- # Chronological holdout sanity check: train on past, test on later samples.
156
- eval_n = min(120, max(30, len(trainable) // 5))
157
- if len(trainable) > eval_n + 100:
158
- hist_train = trainable.iloc[:-eval_n]
159
- hist_test = trainable.iloc[-eval_n:]
160
- eval_model = build_model(int(k))
161
- eval_model.fit(hist_train[feature_cols], hist_train["target"].astype(int))
162
- pred = eval_model.predict(hist_test[feature_cols])
163
- acc = accuracy_score(hist_test["target"].astype(int), pred)
164
- bacc = balanced_accuracy_score(hist_test["target"].astype(int), pred)
165
- eval_text = (
166
- f"Son {eval_n} örneklik kronolojik holdout — "
167
- f"Accuracy: {acc:.3f} | Balanced accuracy: {bacc:.3f}. "
168
- "Bu sonuç gelecekteki performans garantisi değildir."
169
- )
170
- else:
171
- eval_text = "Holdout değerlendirmesi için yeterli geçmiş örnek yok."
172
-
173
- entry = float(df["Close"].iloc[-1])
174
- current_atr = float(atr_series.iloc[-1])
175
- if not np.isfinite(current_atr) or current_atr <= 0:
176
- raise ValueError("ATR hesaplanamadı.")
177
-
178
- # Basit karar filtresi; nötr sınıf yüksekse işlem açma.
179
- if p_up > p_down and p_up >= 0.45 and p_flat < 0.55:
180
- side = "LONG"
181
- stop = entry - atr_stop * current_atr
182
- target = entry + reward_risk * (entry - stop)
183
- confidence = p_up
184
- elif p_down > p_up and p_down >= 0.45 and p_flat < 0.55:
185
- side = "SHORT"
186
- stop = entry + atr_stop * current_atr
187
- target = entry - reward_risk * (stop - entry)
188
- confidence = p_down
189
- else:
190
- side = "WAIT / NO TRADE"
191
- stop = np.nan
192
- target = np.nan
193
- confidence = max(p_up, p_down)
194
-
195
- risk_cash = float(equity) * float(risk_pct) / 100.0
196
- stop_distance = abs(entry - stop) if np.isfinite(stop) else np.nan
197
-
198
- # fee_pct ve slippage_pct her yön için varsayılır; yaklaşık round-trip maliyet.
199
- round_trip_cost_rate = 2 * (float(fee_pct) + float(slippage_pct)) / 100.0
200
- if side != "WAIT / NO TRADE":
201
- stop_pct = stop_distance / entry
202
- cost_per_btc = stop_distance + entry * round_trip_cost_rate
203
- btc_qty = risk_cash / cost_per_btc if cost_per_btc > 0 else 0.0
204
- notional = btc_qty * entry
205
- leverage_used = notional / float(equity) if equity > 0 else np.nan
206
- if leverage_used > float(max_leverage):
207
- btc_qty = (float(equity) * float(max_leverage)) / entry
208
- notional = btc_qty * entry
209
- effective_risk = btc_qty * cost_per_btc
210
- sizing_note = (
211
- f"Kaldıraç sınırı nedeniyle miktar kısıldı. "
212
- f"Gerçekleşen yaklaşık stop riski: {effective_risk:.2f} "
213
- f"({effective_risk / equity * 100:.2f}%)."
214
- )
215
- else:
216
- effective_risk = btc_qty * cost_per_btc
217
- sizing_note = "Pozisyon miktarı risk bütçesine göre hesaplandı."
218
- lots = btc_qty / float(contract_size)
219
- margin_est = notional / float(max_leverage)
220
- else:
221
- btc_qty = notional = lots = margin_est = 0.0
222
- effective_risk = 0.0
223
- sizing_note = "Model filtresi yeterli yönsel avantaj bulamadı; işlem açma."
224
-
225
- # Fiyat grafiği ve ATR seviyeleri.
226
- plot_df = df.tail(120)
227
- fig = go.Figure()
228
- fig.add_trace(go.Candlestick(
229
- x=plot_df.index, open=plot_df["Open"], high=plot_df["High"],
230
- low=plot_df["Low"], close=plot_df["Close"], name="BTC-USD"
231
- ))
232
- if np.isfinite(stop):
233
- fig.add_hline(y=stop, line_dash="dash", annotation_text="Stop")
234
- fig.add_hline(y=target, line_dash="dash", annotation_text="Take profit")
235
- fig.update_layout(
236
- title="BTC-USD — Daily candles (last 120)",
237
- xaxis_title="Date", yaxis_title="USD",
238
- height=520, xaxis_rangeslider_visible=False
239
- )
240
-
241
- neighbor_view = neighbors[["target", "future_return", "distance"]].copy()
242
- neighbor_view["target"] = neighbor_view["target"].map(
243
- {-1: "DOWN", 0: "FLAT", 1: "UP"}
244
- )
245
- neighbor_view["future_return"] = neighbor_view["future_return"].map(fmt_pct)
246
- neighbor_view["distance"] = neighbor_view["distance"].map(lambda z: f"{z:.3f}")
247
- neighbor_view.index = neighbor_view.index.strftime("%Y-%m-%d")
248
- neighbor_view = neighbor_view.reset_index().rename(columns={
249
- "index": "Neighbor date", "target": "Historical class",
250
- "future_return": "Next-day return", "distance": "Distance"
251
- })
252
-
253
- report = f"""
254
- ## {side}
255
-
256
- **Son kullanılan mum:** {df.index[-1].date()}
257
- **Kapanış / referans giriş:** ${entry:,.2f}
258
-
259
- ### KNN sınıf olasılıkları
260
- - Yukarı: **{p_up:.1%}**
261
- - Nötr: **{p_flat:.1%}**
262
- - Aşağı: **{p_down:.1%}**
263
- - Seçilen yönün olasılığı: **{confidence:.1%}**
264
-
265
- ### Plan seviyeleri
266
- - Stop-loss: **{('$' + format(stop, ',.2f')) if np.isfinite(stop) else '—'}**
267
- - Take-profit: **{('$' + format(target, ',.2f')) if np.isfinite(target) else '—'}**
268
- - ATR(14): **${current_atr:,.2f}**
269
- - Planlanan R:R: **1 : {reward_risk:.2f}**
270
-
271
- ### Pozisyon boyutu
272
- - Hesap özsermayesi: **${equity:,.2f}**
273
- - Risk bütçesi: **${risk_cash:,.2f} ({risk_pct:.2f}%)**
274
- - Tahmini BTC miktarı: **{btc_qty:.6f} BTC**
275
- - Tahmini lot: **{lots:.6f} lot** (1 lot = {contract_size} BTC)
276
- - Nominal pozisyon: **${notional:,.2f}**
277
- - Tahmini teminat (@ max leverage): **${margin_est:,.2f}**
278
- - Tahmini stop riski + maliyet: **${effective_risk:,.2f}**
279
- - {sizing_note}
280
-
281
- ### Komşu örnekler
282
- - En yakın K örneğin ortalama ertesi gün getirisi: **{fmt_pct(mean_neighbor_return)}**
283
- - Medyan ertesi gün getirisi: **{fmt_pct(median_neighbor_return)}**
284
-
285
- ### Model kontrolü
286
- {eval_text}
287
- """
288
-
289
- notes = (
290
- "Önemli: Bu bir araştırma/prototip karar destek aracıdır; yatırım tavsiyesi veya "
291
- "kârlılık garantisi değildir. KNN olasılıkları kalibre edilmiş gerçek olasılıklar "
292
- "olarak yorumlanmamalıdır. Günlük BTC-USD verisi Yahoo Finance'tan gelir; "
293
- "broker CFD fiyatı, spread, swap, funding, minimum lot, lot sözleşmesi ve "
294
- "marjin kuralları farklı olabilir. Emir vermeden önce broker şartlarıyla "
295
- "miktarı yeniden doğrulayın. Stop emirlerinde gap/slippage nedeniyle kayıp "
296
- "hesaplanandan yüksek olabilir. SHORT işlemlerde ayrıca borçlanma/funding "
297
- "maliyetleri bulunabilir."
298
- )
299
- return report, fig, neighbor_view, notes
300
-
301
- except Exception as e:
302
- return f"## Hata\n{type(e).__name__}: {e}", None, pd.DataFrame(), (
303
- "Veri bağlantısını, parametreleri ve internet erişimini kontrol edin."
304
- )
305
-
306
- with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as demo:
307
- gr.Markdown(
308
- "# BTCUSD KNN — 1 Günlük Risk & Pozisyon Motoru\n"
309
- "KNN benzer geçmiş günleri kullanarak yön sınıfı tahmini üretir; ATR tabanlı "
310
- "SL/TP ve risk bütçesine göre BTC miktarı hesaplar."
311
- )
312
- with gr.Row():
313
- with gr.Column(scale=1):
314
- period = gr.Dropdown(
315
- ["2y", "5y", "max"], value="5y", label="Geçmiş veri aralığı"
316
- )
317
- k = gr.Slider(3, 31, value=9, step=2,
318
- label="K komşu sayısı")
319
- train_window = gr.Slider(200, 1500, value=750, step=50,
320
- label="Eğitim penceresi (gün)")
321
- threshold_atr = gr.Slider(0.0, 1.0, value=0.25, step=0.05,
322
- label="Sınıf eşiği (ATR oranı)")
323
- atr_stop = gr.Slider(0.5, 5.0, value=2.0, step=0.1,
324
- label="Stop mesafesi (ATR)")
325
- reward_risk = gr.Slider(0.5, 5.0, value=2.0, step=0.1,
326
- label="Risk / ödül oranı")
327
- use_latest = gr.Checkbox(
328
- value=False, label="Son günlük mumu kullan (kapanmamış olabilir)"
329
- )
330
- with gr.Column(scale=1):
331
- equity = gr.Number(value=10000, label="Hesap özsermayesi (USD)")
332
- risk_pct = gr.Slider(0.1, 3.0, value=0.5, step=0.1,
333
- label="İşlem başına risk (%)")
334
- max_leverage = gr.Slider(1, 20, value=3, step=1,
335
- label="Azami kaldıraç (pozisyon limiti)")
336
- contract_size = gr.Number(value=1.0, label="1 lot kaç BTC?")
337
- fee_pct = gr.Number(value=0.05, label="Tek yön komisyon (%)")
338
- slippage_pct = gr.Number(value=0.03, label="Tek yön kayma varsayımı (%)")
339
- run = gr.Button("Analiz et", variant="primary")
340
-
341
- result = gr.Markdown()
342
- chart = gr.Plot(label="BTCUSD fiyat ve risk seviyeleri")
343
- neighbors = gr.Dataframe(label="KNN en yakın geçmiş örnekleri", interactive=False)
344
- disclaimer = gr.Markdown()
345
- run.click(
346
- fn=run_engine,
347
- inputs=[period, k, train_window, threshold_atr, atr_stop, reward_risk,
348
- equity, risk_pct, max_leverage, contract_size, fee_pct,
349
- slippage_pct, use_latest],
350
- outputs=[result, chart, neighbors, disclaimer]
351
- )
352
-
353
- if __name__ == "__main__":
354
- demo.launch(server_name="0.0.0.0", server_port=7860)