Spaces:
Sleeping
Sleeping
Delete app.py
Browse files
app.py
DELETED
|
@@ -1,382 +0,0 @@
|
|
| 1 |
-
import warnings
|
| 2 |
-
warnings.filterwarnings("ignore")
|
| 3 |
-
|
| 4 |
-
import numpy as np
|
| 5 |
-
import pandas as pd
|
| 6 |
-
import yfinance as yf
|
| 7 |
-
import gradio as gr
|
| 8 |
-
import plotly.graph_objects as go
|
| 9 |
-
|
| 10 |
-
from sklearn.impute import SimpleImputer
|
| 11 |
-
from sklearn.preprocessing import StandardScaler
|
| 12 |
-
from sklearn.pipeline import Pipeline
|
| 13 |
-
from sklearn.neighbors import KNeighborsClassifier, NearestNeighbors
|
| 14 |
-
from sklearn.metrics import balanced_accuracy_score
|
| 15 |
-
|
| 16 |
-
APP_TITLE = "Goshawk Adaptive BTCUSD Engine"
|
| 17 |
-
HORIZON = 5
|
| 18 |
-
FEE_DEFAULT = 0.05
|
| 19 |
-
SLIPPAGE_DEFAULT = 0.03
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
def download_btc(period="5y"):
|
| 23 |
-
df = yf.download("BTC-USD", period=period, interval="1d",
|
| 24 |
-
auto_adjust=True, progress=False)
|
| 25 |
-
if df is None or df.empty:
|
| 26 |
-
raise ValueError("BTC verisi alınamadı. İnternet/veri sağlayıcısını kontrol edin.")
|
| 27 |
-
if isinstance(df.columns, pd.MultiIndex):
|
| 28 |
-
df.columns = df.columns.get_level_values(0)
|
| 29 |
-
df = df[["Open", "High", "Low", "Close", "Volume"]].dropna().copy()
|
| 30 |
-
df.index = pd.to_datetime(df.index)
|
| 31 |
-
return df
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
def calc_atr(df, n=14):
|
| 35 |
-
pc = df.Close.shift(1)
|
| 36 |
-
tr = pd.concat([(df.High-df.Low), (df.High-pc).abs(),
|
| 37 |
-
(df.Low-pc).abs()], axis=1).max(axis=1)
|
| 38 |
-
return tr.ewm(alpha=1/n, adjust=False).mean()
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
def rsi(s, n=14):
|
| 42 |
-
d = s.diff()
|
| 43 |
-
up = d.clip(lower=0).ewm(alpha=1/n, adjust=False).mean()
|
| 44 |
-
dn = (-d.clip(upper=0)).ewm(alpha=1/n, adjust=False).mean()
|
| 45 |
-
rs = up / dn.replace(0, np.nan)
|
| 46 |
-
return 100 - 100/(1+rs)
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
def feature_engineering(df):
|
| 50 |
-
c, v = df.Close, df.Volume
|
| 51 |
-
x = pd.DataFrame(index=df.index)
|
| 52 |
-
for n in [1, 2, 3, 5, 10, 20, 50]:
|
| 53 |
-
x[f"return_{n}"] = c.pct_change(n)
|
| 54 |
-
for n in [5, 10, 20, 50]:
|
| 55 |
-
ema = c.ewm(span=n, adjust=False).mean()
|
| 56 |
-
x[f"ema_distance_{n}"] = c/ema - 1
|
| 57 |
-
x["rsi"] = rsi(c)/100
|
| 58 |
-
atr = calc_atr(df)
|
| 59 |
-
x["atr_pct"] = atr/c
|
| 60 |
-
x["range_pct"] = (df.High-df.Low)/c
|
| 61 |
-
x["body_pct"] = (df.Close-df.Open)/df.Open
|
| 62 |
-
x["volatility_10"] = c.pct_change().rolling(10).std()
|
| 63 |
-
x["volatility_20"] = c.pct_change().rolling(20).std()
|
| 64 |
-
x["volume_z"] = (v-v.rolling(20).mean())/v.rolling(20).std().replace(0, np.nan)
|
| 65 |
-
x["volume_return"] = v.pct_change()
|
| 66 |
-
macd = c.ewm(span=12, adjust=False).mean()-c.ewm(span=26, adjust=False).mean()
|
| 67 |
-
x["macd_pct"] = macd/c
|
| 68 |
-
return x.replace([np.inf, -np.inf], np.nan), atr
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
def make_labels(df, atr, horizon=HORIZON, threshold=0.20):
|
| 72 |
-
# Label is based only on the close-to-close forward return; features are lagged/current.
|
| 73 |
-
fwd = df.Close.shift(-horizon)/df.Close - 1
|
| 74 |
-
band = threshold*(atr/df.Close)*np.sqrt(horizon)
|
| 75 |
-
y = np.where(fwd > band, 1, np.where(fwd < -band, -1, 0))
|
| 76 |
-
return pd.Series(y, index=df.index), fwd
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
def build_pipeline(k):
|
| 80 |
-
return Pipeline([
|
| 81 |
-
("imputer", SimpleImputer(strategy="median")),
|
| 82 |
-
("scale", StandardScaler()),
|
| 83 |
-
("knn", KNeighborsClassifier(n_neighbors=k, weights="distance"))
|
| 84 |
-
])
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
def barrier_outcome(df, start_i, side, stop_atr, target_atr, horizon=HORIZON):
|
| 88 |
-
entry = float(df.Close.iloc[start_i])
|
| 89 |
-
atr = float(calc_atr(df).iloc[start_i])
|
| 90 |
-
if not np.isfinite(atr) or atr <= 0:
|
| 91 |
-
return None
|
| 92 |
-
if side == 1:
|
| 93 |
-
stop, target = entry-stop_atr*atr, entry+target_atr*atr
|
| 94 |
-
else:
|
| 95 |
-
stop, target = entry+stop_atr*atr, entry-target_atr*atr
|
| 96 |
-
end = min(start_i+horizon, len(df)-1)
|
| 97 |
-
for j in range(start_i+1, end+1):
|
| 98 |
-
hi, lo = float(df.High.iloc[j]), float(df.Low.iloc[j])
|
| 99 |
-
if side == 1:
|
| 100 |
-
hit_sl, hit_tp = lo <= stop, hi >= target
|
| 101 |
-
else:
|
| 102 |
-
hit_sl, hit_tp = hi >= stop, lo <= target
|
| 103 |
-
# Conservative assumption if both barriers are touched in one daily candle.
|
| 104 |
-
if hit_sl and hit_tp:
|
| 105 |
-
return -stop_atr*atr/entry
|
| 106 |
-
if hit_sl:
|
| 107 |
-
return -stop_atr*atr/entry
|
| 108 |
-
if hit_tp:
|
| 109 |
-
return target_atr*atr/entry
|
| 110 |
-
final = float(df.Close.iloc[end])
|
| 111 |
-
return side*(final-entry)/entry
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
def optimize_barriers(df, train_end, side, fee_pct, slip_pct):
|
| 115 |
-
# Select SL/TP from matured historical examples only.
|
| 116 |
-
sl_grid = [0.8, 1.0, 1.2, 1.5, 1.8, 2.0, 2.5, 3.0]
|
| 117 |
-
rr_grid = [1.0, 1.25, 1.5, 2.0, 2.5, 3.0, 4.0]
|
| 118 |
-
first = max(60, train_end-450)
|
| 119 |
-
candidates = []
|
| 120 |
-
cost = 2*(fee_pct+slip_pct)/100
|
| 121 |
-
for sl in sl_grid:
|
| 122 |
-
for rr in rr_grid:
|
| 123 |
-
outcomes = []
|
| 124 |
-
for i in range(first, train_end):
|
| 125 |
-
# Only use examples whose full forward horizon is inside training history.
|
| 126 |
-
if i+HORIZON >= train_end:
|
| 127 |
-
continue
|
| 128 |
-
r = barrier_outcome(df, i, side, sl, sl*rr)
|
| 129 |
-
if r is not None:
|
| 130 |
-
outcomes.append(r-cost)
|
| 131 |
-
if len(outcomes) < 35:
|
| 132 |
-
continue
|
| 133 |
-
arr = np.asarray(outcomes)
|
| 134 |
-
# Penalize unstable settings; maximize average net return per trade.
|
| 135 |
-
score = arr.mean() - 0.25*arr.std()/np.sqrt(len(arr))
|
| 136 |
-
candidates.append((score, sl, rr, len(arr), arr.mean(), (arr > 0).mean()))
|
| 137 |
-
if not candidates:
|
| 138 |
-
return 1.5, 2.0, None
|
| 139 |
-
best = max(candidates, key=lambda z: z[0])
|
| 140 |
-
return best[1], best[2], best
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
def regime_name(row):
|
| 144 |
-
if row["volatility_20"] > 0.045:
|
| 145 |
-
vol = "Yüksek volatilite"
|
| 146 |
-
elif row["volatility_20"] < 0.018:
|
| 147 |
-
vol = "Düşük volatilite"
|
| 148 |
-
else:
|
| 149 |
-
vol = "Orta volatilite"
|
| 150 |
-
if row["ema_distance_20"] > 0.025:
|
| 151 |
-
trend = "Yukarı trend"
|
| 152 |
-
elif row["ema_distance_20"] < -0.025:
|
| 153 |
-
trend = "Aşağı trend"
|
| 154 |
-
else:
|
| 155 |
-
trend = "Yatay / kararsız"
|
| 156 |
-
return f"{trend} · {vol}"
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
def run_engine(period, equity, max_risk, min_risk, max_leverage,
|
| 160 |
-
fee_pct, slip_pct, train_window, k):
|
| 161 |
-
try:
|
| 162 |
-
df = download_btc(period)
|
| 163 |
-
if len(df) < 300:
|
| 164 |
-
raise ValueError("En az 300 günlük mum gerekli.")
|
| 165 |
-
# Ignore today's unfinished daily candle by default.
|
| 166 |
-
df = df.iloc[:-1].copy()
|
| 167 |
-
X, atr = feature_engineering(df)
|
| 168 |
-
y, fwd = make_labels(df, atr)
|
| 169 |
-
data = X.copy()
|
| 170 |
-
data["target"] = y
|
| 171 |
-
data["future"] = fwd
|
| 172 |
-
valid = data.dropna(subset=["target", "future"])
|
| 173 |
-
valid = valid.dropna(subset=list(X.columns), how="all")
|
| 174 |
-
if len(valid) < 180:
|
| 175 |
-
raise ValueError("Model eğitimi için yeterli temiz örnek yok.")
|
| 176 |
-
|
| 177 |
-
# Latest known candle's feature row; training labels are already matured.
|
| 178 |
-
current_x = X.iloc[[-1]]
|
| 179 |
-
train_end = len(valid)
|
| 180 |
-
window = min(int(train_window), train_end-HORIZON-1)
|
| 181 |
-
train = valid.iloc[-window:]
|
| 182 |
-
if len(train) <= int(k):
|
| 183 |
-
raise ValueError("K komşu sayısı eğitim örneklerinden küçük.")
|
| 184 |
-
|
| 185 |
-
model = build_pipeline(int(k))
|
| 186 |
-
model.fit(train[X.columns], train.target.astype(int))
|
| 187 |
-
probs = model.predict_proba(current_x[X.columns])[0]
|
| 188 |
-
classes = model.named_steps["knn"].classes_
|
| 189 |
-
p = {int(c): float(v) for c, v in zip(classes, probs)}
|
| 190 |
-
p_long, p_short, p_flat = p.get(1, 0), p.get(-1, 0), p.get(0, 0)
|
| 191 |
-
direction = 1 if p_long >= p_short else -1
|
| 192 |
-
direction_prob = max(p_long, p_short)
|
| 193 |
-
edge = abs(p_long-p_short)
|
| 194 |
-
|
| 195 |
-
# KNN neighborhood agreement and chronological holdout score.
|
| 196 |
-
imputer, scaler = model.named_steps["imputer"], model.named_steps["scale"]
|
| 197 |
-
z_train = scaler.transform(imputer.transform(train[X.columns]))
|
| 198 |
-
z_now = scaler.transform(imputer.transform(current_x[X.columns]))
|
| 199 |
-
nn = NearestNeighbors(n_neighbors=int(k)).fit(z_train)
|
| 200 |
-
distances, indices = nn.kneighbors(z_now)
|
| 201 |
-
analogs = train.iloc[indices[0]]
|
| 202 |
-
agreement = float((analogs.target.astype(int) == direction).mean())
|
| 203 |
-
|
| 204 |
-
test_n = min(90, max(30, len(valid)//6))
|
| 205 |
-
hist_train = valid.iloc[:-test_n]
|
| 206 |
-
hist_test = valid.iloc[-test_n:]
|
| 207 |
-
eval_model = build_pipeline(int(k))
|
| 208 |
-
eval_model.fit(hist_train[X.columns], hist_train.target.astype(int))
|
| 209 |
-
pred = eval_model.predict(hist_test[X.columns])
|
| 210 |
-
holdout_bacc = balanced_accuracy_score(hist_test.target.astype(int), pred)
|
| 211 |
-
|
| 212 |
-
sl_mult, rr_mult, opt_stats = optimize_barriers(
|
| 213 |
-
df, len(df)-HORIZON, direction, float(fee_pct), float(slip_pct)
|
| 214 |
-
)
|
| 215 |
-
entry = float(df.Close.iloc[-1])
|
| 216 |
-
current_atr = float(atr.iloc[-1])
|
| 217 |
-
stop_dist = sl_mult*current_atr
|
| 218 |
-
tp_dist = stop_dist*rr_mult
|
| 219 |
-
if direction == 1:
|
| 220 |
-
stop, target = entry-stop_dist, entry+tp_dist
|
| 221 |
-
else:
|
| 222 |
-
stop, target = entry+stop_dist, entry-tp_dist
|
| 223 |
-
|
| 224 |
-
# Adaptive risk: base on model edge, neighbor agreement, validation quality,
|
| 225 |
-
# and current drawdown proxy (recent 30-day peak-to-trough close drawdown).
|
| 226 |
-
close = df.Close
|
| 227 |
-
recent = close.tail(30)
|
| 228 |
-
dd = float(recent.iloc[-1]/recent.cummax().iloc[-1]-1)
|
| 229 |
-
quality = np.clip((holdout_bacc-0.33)/0.20, 0, 1)
|
| 230 |
-
conviction = np.clip((direction_prob-0.34)/0.35, 0, 1)
|
| 231 |
-
neighbor_quality = np.clip((agreement-0.33)/0.50, 0, 1)
|
| 232 |
-
risk_factor = 0.20 + 0.35*quality + 0.25*conviction + 0.20*neighbor_quality
|
| 233 |
-
if dd < -0.12:
|
| 234 |
-
risk_factor *= 0.35
|
| 235 |
-
elif dd < -0.07:
|
| 236 |
-
risk_factor *= 0.60
|
| 237 |
-
risk_pct = float(min_risk) + (float(max_risk)-float(min_risk))*risk_factor
|
| 238 |
-
risk_pct = float(np.clip(risk_pct, min_risk, max_risk))
|
| 239 |
-
|
| 240 |
-
# No trade when evidence is weak or validation is poor.
|
| 241 |
-
trade_ok = (
|
| 242 |
-
direction_prob >= 0.43 and edge >= 0.12 and agreement >= 0.55
|
| 243 |
-
and holdout_bacc >= 0.36 and p_flat < 0.60
|
| 244 |
-
)
|
| 245 |
-
risk_cash = float(equity)*risk_pct/100
|
| 246 |
-
cost_rate = 2*(float(fee_pct)+float(slip_pct))/100
|
| 247 |
-
cost_per_btc = stop_dist + entry*cost_rate
|
| 248 |
-
btc_qty = risk_cash/cost_per_btc if cost_per_btc > 0 else 0
|
| 249 |
-
notional = btc_qty*entry
|
| 250 |
-
max_notional = float(equity)*float(max_leverage)
|
| 251 |
-
leverage_limited = notional > max_notional
|
| 252 |
-
if leverage_limited:
|
| 253 |
-
btc_qty = max_notional/entry
|
| 254 |
-
notional = btc_qty*entry
|
| 255 |
-
actual_risk = btc_qty*cost_per_btc
|
| 256 |
-
lot_size_btc = 1.0 # Change to broker's contract specification.
|
| 257 |
-
lots = btc_qty/lot_size_btc
|
| 258 |
-
margin = notional/max(float(max_leverage), 1)
|
| 259 |
-
|
| 260 |
-
if not trade_ok:
|
| 261 |
-
signal = "WAIT — İŞLEM AÇMA"
|
| 262 |
-
btc_qty = notional = lots = margin = actual_risk = 0.0
|
| 263 |
-
else:
|
| 264 |
-
signal = "LONG" if direction == 1 else "SHORT"
|
| 265 |
-
|
| 266 |
-
if opt_stats:
|
| 267 |
-
opt_text = (
|
| 268 |
-
f"Optimizasyon örnek sayısı: {opt_stats[3]} · "
|
| 269 |
-
f"Geçmiş ortalama net getiri/işlem: {opt_stats[4]*100:.3f}% · "
|
| 270 |
-
f"Geçmiş pozitif sonuç oranı: {opt_stats[5]*100:.1f}%"
|
| 271 |
-
)
|
| 272 |
-
else:
|
| 273 |
-
opt_text = "TP/SL optimizasyonu için yeterli olgunlaşmış örnek bulunamadı."
|
| 274 |
-
|
| 275 |
-
report = f"""
|
| 276 |
-
# {signal}
|
| 277 |
-
|
| 278 |
-
**Referans tarih:** {df.index[-1].date()} · **Referans fiyat:** ${entry:,.2f}
|
| 279 |
-
|
| 280 |
-
## Modelin öğrendikleri
|
| 281 |
-
| Ölçüm | Sonuç |
|
| 282 |
-
|---|---:|
|
| 283 |
-
| P(up) | {p_long:.1%} |
|
| 284 |
-
| P(flat) | {p_flat:.1%} |
|
| 285 |
-
| P(down) | {p_short:.1%} |
|
| 286 |
-
| En yakın komşu uyumu | {agreement:.1%} |
|
| 287 |
-
| Kronolojik holdout balanced accuracy | {holdout_bacc:.3f} |
|
| 288 |
-
| Piyasa rejimi | {regime_name(X.iloc[-1])} |
|
| 289 |
-
|
| 290 |
-
## Otomatik TP / SL
|
| 291 |
-
| Parametre | Değer |
|
| 292 |
-
|---|---:|
|
| 293 |
-
| Stop mesafesi | {sl_mult:.2f} ATR |
|
| 294 |
-
| Hedef mesafesi | {rr_mult:.2f}R |
|
| 295 |
-
| Stop-loss | ${stop:,.2f} |
|
| 296 |
-
| Take-profit | ${target:,.2f} |
|
| 297 |
-
| ATR(14) | ${current_atr:,.2f} |
|
| 298 |
-
| TP/SL geçmiş optimizasyonu | {opt_text} |
|
| 299 |
-
|
| 300 |
-
## Adaptif pozisyon ve risk
|
| 301 |
-
| Parametre | Değer |
|
| 302 |
-
|---|---:|
|
| 303 |
-
| Hesap büyüklüğü | ${equity:,.2f} |
|
| 304 |
-
| Öğrenilmiş risk | {risk_pct:.2f}% |
|
| 305 |
-
| Risk bütçesi | ${risk_cash:,.2f} |
|
| 306 |
-
| BTC miktarı | {btc_qty:.6f} |
|
| 307 |
-
| Nominal pozisyon | ${notional:,.2f} |
|
| 308 |
-
| Tahmini teminat | ${margin:,.2f} |
|
| 309 |
-
| Tahmini stop kaybı + maliyet | ${actual_risk:,.2f} |
|
| 310 |
-
| Son 30 günlük kapanış DD | {dd:.2%} |
|
| 311 |
-
| Kaldıraç sınırı uygulandı mı? | {"Evet" if leverage_limited else "Hayır"} |
|
| 312 |
-
|
| 313 |
-
Risk yüzdesi model kalitesi, komşu uyumu ve yakın dönem drawdown'a göre seçildi.
|
| 314 |
-
"""
|
| 315 |
-
|
| 316 |
-
fig = go.Figure(data=[go.Candlestick(
|
| 317 |
-
x=df.index[-120:], open=df.Open.tail(120), high=df.High.tail(120),
|
| 318 |
-
low=df.Low.tail(120), close=df.Close.tail(120), name="BTCUSD"
|
| 319 |
-
)])
|
| 320 |
-
if trade_ok:
|
| 321 |
-
fig.add_hline(y=stop, line_dash="dash", annotation_text="SL")
|
| 322 |
-
fig.add_hline(y=target, line_dash="dash", annotation_text="TP")
|
| 323 |
-
fig.update_layout(title="BTCUSD Daily", height=520,
|
| 324 |
-
xaxis_rangeslider_visible=False)
|
| 325 |
-
|
| 326 |
-
neighbor_table = analogs[["target", "future"]].copy()
|
| 327 |
-
neighbor_table["target"] = neighbor_table.target.map({-1:"DOWN",0:"FLAT",1:"UP"})
|
| 328 |
-
neighbor_table["future"] = neighbor_table.future.map(lambda z: f"{z:.2%}")
|
| 329 |
-
neighbor_table.index = neighbor_table.index.strftime("%Y-%m-%d")
|
| 330 |
-
neighbor_table = neighbor_table.reset_index().rename(
|
| 331 |
-
columns={"index":"Tarih","target":"Sınıf","future":"5 günlük getiri"}
|
| 332 |
-
)
|
| 333 |
-
disclaimer = (
|
| 334 |
-
"**Araştırma prototipi — otomatik emir göndermez.** Model her çalıştırmada "
|
| 335 |
-
"indirilen geçmiş veriyi yeniden eğitir; canlı öğrenme/online learning değildir. "
|
| 336 |
-
"TP/SL seçimi geçmiş örneklerde optimize edilir ve overfitting riski taşır. "
|
| 337 |
-
"KNN skorları kalibre edilmiş olasılık değildir. Günlük OHLC mumlarında aynı "
|
| 338 |
-
"gün TP ve SL birlikte görülürse muhafazakâr olarak SL varsayılır. Yahoo BTC-USD "
|
| 339 |
-
"verisi broker CFD fiyatı değildir. Lot büyüklüğü, komisyon, spread, funding, "
|
| 340 |
-
"swap, marjin ve minimum miktarı broker şartlarına göre doğrulayın. Gerçek "
|
| 341 |
-
"hesapta kullanmadan önce out-of-sample walk-forward, paper trading ve stres "
|
| 342 |
-
"testleri zorunludur."
|
| 343 |
-
)
|
| 344 |
-
return report, fig, neighbor_table, disclaimer
|
| 345 |
-
|
| 346 |
-
except Exception as exc:
|
| 347 |
-
return f"# Hata\n{type(exc).__name__}: {exc}", None, pd.DataFrame(), \
|
| 348 |
-
"Veri bağlantısını ve parametreleri kontrol edin."
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
with gr.Blocks(title=APP_TITLE, theme=gr.themes.Soft()) as app:
|
| 352 |
-
gr.Markdown(
|
| 353 |
-
"# GOSHAWK — Adaptive BTCUSD KNN Risk Engine\n"
|
| 354 |
-
"Günlük veride KNN yön tahmini, geçmiş bariyer sonuçlarından adaptif TP/SL "
|
| 355 |
-
"seçimi ve model kalitesine göre dinamik risk/pozisyon boyutlandırma."
|
| 356 |
-
)
|
| 357 |
-
with gr.Row():
|
| 358 |
-
with gr.Column():
|
| 359 |
-
period = gr.Dropdown(["2y", "5y", "max"], value="5y", label="Veri geçmişi")
|
| 360 |
-
train_window = gr.Slider(250, 1500, value=900, step=50, label="Eğitim penceresi")
|
| 361 |
-
k = gr.Slider(3, 31, value=9, step=2, label="KNN komşu sayısı")
|
| 362 |
-
equity = gr.Number(value=10000, label="Hesap büyüklüğü (USD)")
|
| 363 |
-
with gr.Column():
|
| 364 |
-
min_risk = gr.Slider(0.1, 0.5, value=0.1, step=0.05, label="Minimum risk (%)")
|
| 365 |
-
max_risk = gr.Slider(0.5, 2.0, value=0.75, step=0.05, label="Maksimum risk (%)")
|
| 366 |
-
max_leverage = gr.Slider(1, 10, value=3, step=1, label="Azami kaldıraç")
|
| 367 |
-
fee_pct = gr.Number(value=FEE_DEFAULT, label="Tek yön komisyon (%)")
|
| 368 |
-
slip_pct = gr.Number(value=SLIPPAGE_DEFAULT, label="Tek yön slippage (%)")
|
| 369 |
-
run = gr.Button("Veriyi öğren ve analiz et", variant="primary")
|
| 370 |
-
output = gr.Markdown()
|
| 371 |
-
chart = gr.Plot()
|
| 372 |
-
neighbors = gr.Dataframe(label="En yakın geçmiş piyasa örnekleri", interactive=False)
|
| 373 |
-
disclaimer = gr.Markdown()
|
| 374 |
-
run.click(
|
| 375 |
-
run_engine,
|
| 376 |
-
inputs=[period, equity, max_risk, min_risk, max_leverage,
|
| 377 |
-
fee_pct, slip_pct, train_window, k],
|
| 378 |
-
outputs=[output, chart, neighbors, disclaimer]
|
| 379 |
-
)
|
| 380 |
-
|
| 381 |
-
if __name__ == "__main__":
|
| 382 |
-
app.launch(server_name="0.0.0.0", server_port=7860)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|