GoshawkVortexAI commited on
Commit
10c29cc
·
verified ·
1 Parent(s): 6adbc65

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -600
app.py DELETED
@@ -1,600 +0,0 @@
1
- import subprocess
2
- import sys
3
-
4
- def install(pkg):
5
- subprocess.check_call([sys.executable, "-m", "pip", "install", pkg, "-q"])
6
-
7
- packages = [
8
- "gradio==4.44.0",
9
- "requests",
10
- "pandas",
11
- "numpy",
12
- "plotly",
13
- "xgboost",
14
- "scikit-learn",
15
- "ta",
16
- ]
17
-
18
- for pkg in packages:
19
- try:
20
- install(pkg)
21
- except Exception as e:
22
- print(f"Warning: could not install {pkg}: {e}")
23
-
24
- import gradio as gr
25
- import requests
26
- import pandas as pd
27
- import numpy as np
28
- import plotly.graph_objects as go
29
- from plotly.subplots import make_subplots
30
- import json
31
- import warnings
32
- warnings.filterwarnings("ignore")
33
-
34
- try:
35
- import ta
36
- TA_AVAILABLE = True
37
- except ImportError:
38
- TA_AVAILABLE = False
39
-
40
- try:
41
- from xgboost import XGBClassifier
42
- XGB_AVAILABLE = True
43
- except ImportError:
44
- XGB_AVAILABLE = False
45
-
46
- from sklearn.preprocessing import StandardScaler
47
- from sklearn.model_selection import train_test_split
48
-
49
- # ─────────────────────────────────────────────
50
- # DATA FETCHING
51
- # ─────────────────────────────────────────────
52
-
53
- SYMBOLS = [
54
- "BTCUSDT", "ETHUSDT", "SOLUSDT", "BNBUSDT", "XRPUSDT",
55
- "ADAUSDT", "DOGEUSDT", "AVAXUSDT", "DOTUSDT", "MATICUSDT",
56
- "LINKUSDT", "LTCUSDT", "UNIUSDT", "ATOMUSDT", "NEARUSDT",
57
- ]
58
-
59
- INTERVALS = ["5m", "15m", "1h", "4h", "1d"]
60
-
61
- def fetch_klines(symbol: str, interval: str, limit: int = 300) -> pd.DataFrame:
62
- url = "https://api.binance.com/api/v3/klines"
63
- params = {"symbol": symbol, "interval": interval, "limit": limit}
64
- try:
65
- r = requests.get(url, params=params, timeout=10)
66
- r.raise_for_status()
67
- raw = r.json()
68
- except Exception as e:
69
- raise RuntimeError(f"Binance API hatası: {e}")
70
-
71
- df = pd.DataFrame(raw, columns=[
72
- "open_time","open","high","low","close","volume",
73
- "close_time","quote_vol","trades","taker_buy_base",
74
- "taker_buy_quote","ignore"
75
- ])
76
- for col in ["open","high","low","close","volume"]:
77
- df[col] = df[col].astype(float)
78
- df["open_time"] = pd.to_datetime(df["open_time"], unit="ms")
79
- df.set_index("open_time", inplace=True)
80
- return df[["open","high","low","close","volume"]]
81
-
82
- # ─────────────────────────────────────────────
83
- # INDICATORS
84
- # ─────────────────────────────────────────────
85
-
86
- def compute_ema(series: pd.Series, period: int) -> pd.Series:
87
- return series.ewm(span=period, adjust=False).mean()
88
-
89
- def compute_rsi(series: pd.Series, period: int = 14) -> pd.Series:
90
- delta = series.diff()
91
- gain = delta.clip(lower=0).rolling(period).mean()
92
- loss = (-delta.clip(upper=0)).rolling(period).mean()
93
- rs = gain / loss.replace(0, np.nan)
94
- return 100 - (100 / (1 + rs))
95
-
96
- def compute_macd(series: pd.Series):
97
- fast = series.ewm(span=12, adjust=False).mean()
98
- slow = series.ewm(span=26, adjust=False).mean()
99
- macd_line = fast - slow
100
- signal_line = macd_line.ewm(span=9, adjust=False).mean()
101
- histogram = macd_line - signal_line
102
- return macd_line, signal_line, histogram
103
-
104
- def compute_atr(df: pd.DataFrame, period: int = 14) -> pd.Series:
105
- h_l = df["high"] - df["low"]
106
- h_pc = (df["high"] - df["close"].shift()).abs()
107
- l_pc = (df["low"] - df["close"].shift()).abs()
108
- tr = pd.concat([h_l, h_pc, l_pc], axis=1).max(axis=1)
109
- return tr.rolling(period).mean()
110
-
111
- def compute_vwap(df: pd.DataFrame) -> pd.Series:
112
- tp = (df["high"] + df["low"] + df["close"]) / 3
113
- cum_tp_vol = (tp * df["volume"]).cumsum()
114
- cum_vol = df["volume"].cumsum()
115
- return cum_tp_vol / cum_vol
116
-
117
- def add_indicators(df: pd.DataFrame) -> pd.DataFrame:
118
- df = df.copy()
119
- df["ema20"] = compute_ema(df["close"], 20)
120
- df["ema50"] = compute_ema(df["close"], 50)
121
- df["ema200"] = compute_ema(df["close"], 200)
122
- df["rsi"] = compute_rsi(df["close"], 14)
123
- df["macd"], df["macd_signal"], df["macd_hist"] = compute_macd(df["close"])
124
- df["atr"] = compute_atr(df, 14)
125
- df["vwap"] = compute_vwap(df)
126
-
127
- # Volume Profile (approximate: rolling 20-bar avg)
128
- df["vol_ma20"] = df["volume"].rolling(20).mean()
129
- df["vol_ratio"] = df["volume"] / df["vol_ma20"].replace(0, np.nan)
130
-
131
- return df.dropna()
132
-
133
- # ─────────────────────────────────────────────
134
- # SIGNAL LOGIC
135
- # ─────────────────────────────────────────────
136
-
137
- def generate_signal(df: pd.DataFrame):
138
- """Returns (signal, confidence_tech, sl, tp, rr) on last row."""
139
- last = df.iloc[-1]
140
- prev = df.iloc[-2]
141
-
142
- buy_conditions = [
143
- last["ema20"] > last["ema50"],
144
- last["ema50"] > last["ema200"],
145
- last["rsi"] > 50,
146
- (last["macd"] > last["macd_signal"]) and (prev["macd"] <= prev["macd_signal"]),
147
- last["close"] > last["vwap"],
148
- ]
149
- sell_conditions = [
150
- last["ema20"] < last["ema50"],
151
- last["ema50"] < last["ema200"],
152
- last["rsi"] < 50,
153
- (last["macd"] < last["macd_signal"]) and (prev["macd"] >= prev["macd_signal"]),
154
- last["close"] < last["vwap"],
155
- ]
156
-
157
- buy_score = sum(buy_conditions)
158
- sell_score = sum(sell_conditions)
159
-
160
- atr = last["atr"]
161
- price = last["close"]
162
-
163
- if buy_score >= 3:
164
- signal = "AL 📈"
165
- sl = round(price - 1.5 * atr, 4)
166
- tp = round(price + 3.0 * atr, 4)
167
- tech_conf = int(buy_score / 5 * 100)
168
- elif sell_score >= 3:
169
- signal = "SAT 📉"
170
- sl = round(price + 1.5 * atr, 4)
171
- tp = round(price - 3.0 * atr, 4)
172
- tech_conf = int(sell_score / 5 * 100)
173
- else:
174
- signal = "BEKLE ⏳"
175
- sl = round(price - 1.5 * atr, 4)
176
- tp = round(price + 1.5 * atr, 4)
177
- tech_conf = 30
178
-
179
- rr = round(abs(tp - price) / abs(sl - price), 2) if abs(sl - price) > 0 else 0
180
- return signal, tech_conf, sl, tp, rr
181
-
182
- # ─────────────────────────────────────────────
183
- # AI MODEL
184
- # ─────────────────────────────────────────────
185
-
186
- def build_features(df: pd.DataFrame) -> pd.DataFrame:
187
- d = df.copy()
188
- d["ret1"] = d["close"].pct_change(1)
189
- d["ret3"] = d["close"].pct_change(3)
190
- d["ret5"] = d["close"].pct_change(5)
191
- d["ema20_50_cross"] = (d["ema20"] - d["ema50"]) / d["close"]
192
- d["ema50_200_cross"] = (d["ema50"] - d["ema200"]) / d["close"]
193
- d["rsi_norm"] = d["rsi"] / 100
194
- d["macd_norm"] = d["macd"] / d["close"]
195
- d["macd_hist_norm"] = d["macd_hist"] / d["close"]
196
- d["vwap_dist"] = (d["close"] - d["vwap"]) / d["close"]
197
- d["atr_norm"] = d["atr"] / d["close"]
198
- d["vol_ratio_feat"] = d["vol_ratio"].clip(0, 5)
199
- return d.dropna()
200
-
201
- FEATURE_COLS = [
202
- "ret1","ret3","ret5",
203
- "ema20_50_cross","ema50_200_cross",
204
- "rsi_norm","macd_norm","macd_hist_norm",
205
- "vwap_dist","atr_norm","vol_ratio_feat"
206
- ]
207
-
208
- def train_ai(df: pd.DataFrame):
209
- feat_df = build_features(df)
210
- if len(feat_df) < 60:
211
- return None, None, 50
212
-
213
- feat_df["target"] = (feat_df["close"].shift(-3) > feat_df["close"]).astype(int)
214
- feat_df = feat_df.dropna()
215
-
216
- X = feat_df[FEATURE_COLS].values
217
- y = feat_df["target"].values
218
-
219
- if len(X) < 40:
220
- return None, None, 50
221
-
222
- scaler = StandardScaler()
223
- X_scaled = scaler.fit_transform(X)
224
-
225
- split = int(len(X_scaled) * 0.8)
226
- X_train, X_test = X_scaled[:split], X_scaled[split:]
227
- y_train, y_test = y[:split], y[split:]
228
-
229
- if not XGB_AVAILABLE:
230
- return None, scaler, 50
231
-
232
- try:
233
- model = XGBClassifier(
234
- n_estimators=50,
235
- max_depth=3,
236
- learning_rate=0.1,
237
- use_label_encoder=False,
238
- eval_metric="logloss",
239
- verbosity=0,
240
- n_jobs=1,
241
- )
242
- model.fit(X_train, y_train)
243
-
244
- last_feat = build_features(df.tail(50)).tail(1)[FEATURE_COLS].values
245
- last_scaled = scaler.transform(last_feat)
246
- prob = model.predict_proba(last_scaled)[0][1]
247
- ai_conf = int(prob * 100)
248
- return model, scaler, ai_conf
249
- except Exception:
250
- return None, None, 50
251
-
252
- # ─────────────────────────────────────────────
253
- # CHART
254
- # ─────────────────────────────────────────────
255
-
256
- def build_chart(df: pd.DataFrame, symbol: str, signal: str, sl: float, tp: float) -> go.Figure:
257
- plot_df = df.tail(120).copy()
258
-
259
- fig = make_subplots(
260
- rows=3, cols=1,
261
- shared_xaxes=True,
262
- row_heights=[0.6, 0.2, 0.2],
263
- vertical_spacing=0.03,
264
- subplot_titles=["", "RSI", "MACD"]
265
- )
266
-
267
- # Candlestick
268
- fig.add_trace(go.Candlestick(
269
- x=plot_df.index,
270
- open=plot_df["open"], high=plot_df["high"],
271
- low=plot_df["low"], close=plot_df["close"],
272
- name="Fiyat",
273
- increasing_line_color="#00e676",
274
- decreasing_line_color="#ff5252",
275
- increasing_fillcolor="#00e676",
276
- decreasing_fillcolor="#ff5252",
277
- ), row=1, col=1)
278
-
279
- # EMAs
280
- for period, color, width in [(20,"#64b5f6",1.5),(50,"#ffb74d",1.5),(200,"#ce93d8",2)]:
281
- fig.add_trace(go.Scatter(
282
- x=plot_df.index, y=plot_df[f"ema{period}"],
283
- name=f"EMA{period}", line=dict(color=color, width=width)
284
- ), row=1, col=1)
285
-
286
- # VWAP
287
- fig.add_trace(go.Scatter(
288
- x=plot_df.index, y=plot_df["vwap"],
289
- name="VWAP", line=dict(color="#f48fb1", width=1.5, dash="dot")
290
- ), row=1, col=1)
291
-
292
- # Signal arrows on last bar
293
- last_idx = plot_df.index[-1]
294
- last_close = plot_df["close"].iloc[-1]
295
-
296
- if "AL" in signal:
297
- fig.add_annotation(
298
- x=last_idx, y=last_close * 0.995,
299
- text="▲ AL", showarrow=False,
300
- font=dict(color="#00e676", size=16, family="monospace"),
301
- row=1, col=1
302
- )
303
- elif "SAT" in signal:
304
- fig.add_annotation(
305
- x=last_idx, y=last_close * 1.005,
306
- text="▼ SAT", showarrow=False,
307
- font=dict(color="#ff5252", size=16, family="monospace"),
308
- row=1, col=1
309
- )
310
-
311
- # SL / TP horizontal lines
312
- fig.add_hline(y=sl, line_dash="dash", line_color="#ff5252",
313
- annotation_text=f"SL: {sl:,.4f}", row=1, col=1)
314
- fig.add_hline(y=tp, line_dash="dash", line_color="#00e676",
315
- annotation_text=f"TP: {tp:,.4f}", row=1, col=1)
316
-
317
- # RSI
318
- fig.add_trace(go.Scatter(
319
- x=plot_df.index, y=plot_df["rsi"],
320
- name="RSI", line=dict(color="#80cbc4", width=1.5)
321
- ), row=2, col=1)
322
- fig.add_hline(y=70, line_dash="dot", line_color="#ff5252", row=2, col=1)
323
- fig.add_hline(y=30, line_dash="dot", line_color="#00e676", row=2, col=1)
324
- fig.add_hline(y=50, line_dash="dot", line_color="#888888", row=2, col=1)
325
-
326
- # MACD
327
- colors = ["#00e676" if v >= 0 else "#ff5252" for v in plot_df["macd_hist"]]
328
- fig.add_trace(go.Bar(
329
- x=plot_df.index, y=plot_df["macd_hist"],
330
- name="MACD Hist", marker_color=colors, opacity=0.7
331
- ), row=3, col=1)
332
- fig.add_trace(go.Scatter(
333
- x=plot_df.index, y=plot_df["macd"],
334
- name="MACD", line=dict(color="#64b5f6", width=1.2)
335
- ), row=3, col=1)
336
- fig.add_trace(go.Scatter(
337
- x=plot_df.index, y=plot_df["macd_signal"],
338
- name="Sinyal", line=dict(color="#ffb74d", width=1.2)
339
- ), row=3, col=1)
340
-
341
- fig.update_layout(
342
- title=dict(
343
- text=f"<b>{symbol}</b> — Trading Analizi",
344
- font=dict(color="#e0e0e0", size=18, family="'Courier New', monospace")
345
- ),
346
- paper_bgcolor="#0d0d0d",
347
- plot_bgcolor="#111111",
348
- font=dict(color="#b0b0b0", family="'Courier New', monospace"),
349
- xaxis_rangeslider_visible=False,
350
- legend=dict(
351
- bgcolor="rgba(20,20,20,0.8)",
352
- bordercolor="#333",
353
- borderwidth=1,
354
- font=dict(size=10)
355
- ),
356
- height=750,
357
- margin=dict(l=50, r=50, t=60, b=20),
358
- )
359
- for i in range(1, 4):
360
- fig.update_xaxes(
361
- gridcolor="#1e1e1e", zeroline=False,
362
- showspikes=True, spikecolor="#444", row=i, col=1
363
- )
364
- fig.update_yaxes(
365
- gridcolor="#1e1e1e", zeroline=False,
366
- showspikes=True, spikecolor="#444", row=i, col=1
367
- )
368
-
369
- return fig
370
-
371
- # ─────────────────────────────────────────────
372
- # MAIN ANALYSIS
373
- # ─────────────────────────────────────────────
374
-
375
- def analyze(symbol: str, interval: str):
376
- try:
377
- df_raw = fetch_klines(symbol, interval, limit=300)
378
- except Exception as e:
379
- return None, f"❌ Veri alınamadı: {e}", "", "", "", "", "", ""
380
-
381
- df = add_indicators(df_raw)
382
-
383
- if len(df) < 50:
384
- return None, "❌ Yeterli veri yok.", "", "", "", "", "", ""
385
-
386
- signal, tech_conf, sl, tp, rr = generate_signal(df)
387
- _, _, ai_conf = train_ai(df)
388
-
389
- # Combined confidence
390
- final_conf = int(0.5 * tech_conf + 0.5 * ai_conf)
391
-
392
- # Direction
393
- if "AL" in signal:
394
- direction = "🟢 YUKARI"
395
- direction_color = "#00e676"
396
- elif "SAT" in signal:
397
- direction = "🔴 AŞAĞI"
398
- direction_color = "#ff5252"
399
- else:
400
- direction = "🟡 YATAY"
401
- direction_color = "#ffb74d"
402
-
403
- price = df["close"].iloc[-1]
404
- rsi_val = df["rsi"].iloc[-1]
405
- atr_val = df["atr"].iloc[-1]
406
-
407
- fig = build_chart(df, symbol, signal, sl, tp)
408
-
409
- signal_md = f"""
410
- <div style="
411
- background: linear-gradient(135deg, #0d1117 0%, #161b22 100%);
412
- border: 1px solid #30363d;
413
- border-radius: 12px;
414
- padding: 20px;
415
- font-family: 'Courier New', monospace;
416
- color: #e6edf3;
417
- ">
418
- <h2 style="margin:0 0 16px 0; color:#58a6ff; font-size:1.1em; letter-spacing:2px;">
419
- ⚡ SİNYAL ANALİZİ — {symbol} / {interval}
420
- </h2>
421
- <table style="width:100%; border-collapse:collapse;">
422
- <tr>
423
- <td style="padding:8px 12px; color:#8b949e; width:40%;">📌 Son Sinyal</td>
424
- <td style="padding:8px 12px; font-size:1.2em; font-weight:bold;">{signal}</td>
425
- </tr>
426
- <tr style="background:rgba(255,255,255,0.03);">
427
- <td style="padding:8px 12px; color:#8b949e;">📊 Güven Skoru</td>
428
- <td style="padding:8px 12px;">
429
- <div style="background:#21262d; border-radius:6px; overflow:hidden; height:20px; width:100%;">
430
- <div style="background: linear-gradient(90deg, #238636, #56d364); width:{final_conf}%; height:100%; display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:bold;">{final_conf}%</div>
431
- </div>
432
- </td>
433
- </tr>
434
- <tr>
435
- <td style="padding:8px 12px; color:#8b949e;">🎯 Teknik Skor</td>
436
- <td style="padding:8px 12px;">{tech_conf}% &nbsp; | &nbsp; 🤖 AI Skoru: {ai_conf}%</td>
437
- </tr>
438
- <tr style="background:rgba(255,255,255,0.03);">
439
- <td style="padding:8px 12px; color:#8b949e;">📈 Beklenen Yön</td>
440
- <td style="padding:8px 12px; color:{direction_color}; font-weight:bold;">{direction}</td>
441
- </tr>
442
- <tr>
443
- <td style="padding:8px 12px; color:#8b949e;">💰 Güncel Fiyat</td>
444
- <td style="padding:8px 12px;">${price:,.4f}</td>
445
- </tr>
446
- <tr style="background:rgba(255,255,255,0.03);">
447
- <td style="padding:8px 12px; color:#ff5252;">🛑 Stop Loss</td>
448
- <td style="padding:8px 12px; color:#ff5252; font-weight:bold;">${sl:,.4f}</td>
449
- </tr>
450
- <tr>
451
- <td style="padding:8px 12px; color:#00e676;">✅ Take Profit</td>
452
- <td style="padding:8px 12px; color:#00e676; font-weight:bold;">${tp:,.4f}</td>
453
- </tr>
454
- <tr style="background:rgba(255,255,255,0.03);">
455
- <td style="padding:8px 12px; color:#8b949e;">⚖️ Risk/Ödül</td>
456
- <td style="padding:8px 12px;">{rr}x</td>
457
- </tr>
458
- <tr>
459
- <td style="padding:8px 12px; color:#8b949e;">📉 RSI (14)</td>
460
- <td style="padding:8px 12px;">{rsi_val:.1f}</td>
461
- </tr>
462
- <tr style="background:rgba(255,255,255,0.03);">
463
- <td style="padding:8px 12px; color:#8b949e;">📏 ATR (14)</td>
464
- <td style="padding:8px 12px;">${atr_val:,.4f}</td>
465
- </tr>
466
- </table>
467
- <p style="margin:16px 0 0 0; font-size:0.75em; color:#484f58; text-align:center;">
468
- ⚠️ Bu uygulama eğitim amaçlıdır. Finansal tavsiye değildir. Her zaman kendi araştırmanızı yapın.
469
- </p>
470
- </div>
471
- """
472
-
473
- return fig, signal_md
474
-
475
- # ─────────────────────────────────────────────
476
- # GRADIO UI
477
- # ─────────────────────────────────────────────
478
-
479
- CSS = """
480
- body, .gradio-container {
481
- background: #0a0a0f !important;
482
- font-family: 'Courier New', monospace !important;
483
- }
484
- .gr-button {
485
- background: linear-gradient(135deg, #1a1a2e, #16213e) !important;
486
- border: 1px solid #0f3460 !important;
487
- color: #e0e0e0 !important;
488
- font-family: 'Courier New', monospace !important;
489
- letter-spacing: 1px !important;
490
- transition: all 0.2s !important;
491
- }
492
- .gr-button:hover {
493
- background: linear-gradient(135deg, #0f3460, #533483) !important;
494
- border-color: #533483 !important;
495
- box-shadow: 0 0 12px rgba(83,52,131,0.5) !important;
496
- }
497
- .gr-button.primary {
498
- background: linear-gradient(135deg, #0f3460, #533483) !important;
499
- border-color: #7b68ee !important;
500
- font-weight: bold !important;
501
- }
502
- .gr-dropdown, .gr-textbox, select, input {
503
- background: #111 !important;
504
- border: 1px solid #333 !important;
505
- color: #e0e0e0 !important;
506
- font-family: 'Courier New', monospace !important;
507
- }
508
- .gradio-container h1, .gradio-container h2, .gradio-container h3 {
509
- font-family: 'Courier New', monospace !important;
510
- }
511
- """
512
-
513
- HEADER_HTML = """
514
- <div style="
515
- background: linear-gradient(135deg, #0d0d1a 0%, #0a0a0f 50%, #1a0a1a 100%);
516
- border: 1px solid #1e1e3f;
517
- border-radius: 16px;
518
- padding: 28px 32px;
519
- text-align: center;
520
- font-family: 'Courier New', monospace;
521
- margin-bottom: 8px;
522
- position: relative;
523
- overflow: hidden;
524
- ">
525
- <div style="
526
- position: absolute; top: 0; left: 0; right: 0; height: 2px;
527
- background: linear-gradient(90deg, transparent, #7b68ee, #00e5ff, #7b68ee, transparent);
528
- "></div>
529
- <h1 style="
530
- margin: 0 0 6px 0;
531
- font-size: 2em;
532
- letter-spacing: 4px;
533
- background: linear-gradient(90deg, #7b68ee, #00e5ff, #7b68ee);
534
- -webkit-background-clip: text;
535
- -webkit-text-fill-color: transparent;
536
- background-clip: text;
537
- text-transform: uppercase;
538
- ">⚡ CRYPTO SIGNAL PRO</h1>
539
- <p style="margin:0; color:#555; letter-spacing:3px; font-size:0.75em; text-transform:uppercase;">
540
- AI-Powered Technical Analysis &amp; Trading Signals
541
- </p>
542
- <div style="
543
- display: flex; justify-content: center; gap: 24px; margin-top: 16px;
544
- font-size: 0.7em; color: #444; letter-spacing: 2px;
545
- ">
546
- <span>EMA · RSI · MACD</span>
547
- <span style="color:#333;">|</span>
548
- <span>VWAP · ATR · Volume</span>
549
- <span style="color:#333;">|</span>
550
- <span>XGBoost AI</span>
551
- </div>
552
- </div>
553
- """
554
-
555
- def run_analysis(symbol, interval):
556
- fig, signal_md = analyze(symbol, interval)
557
- if fig is None:
558
- return None, signal_md
559
- return fig, signal_md
560
-
561
- with gr.Blocks(css=CSS, title="⚡ Crypto Signal Pro") as demo:
562
- gr.HTML(HEADER_HTML)
563
-
564
- with gr.Row():
565
- sym_dd = gr.Dropdown(
566
- choices=SYMBOLS,
567
- value="BTCUSDT",
568
- label="📊 Parite",
569
- interactive=True,
570
- )
571
- int_dd = gr.Dropdown(
572
- choices=INTERVALS,
573
- value="1h",
574
- label="⏱ Zaman Dilimi",
575
- interactive=True,
576
- )
577
- analyze_btn = gr.Button("🔍 ANALİZ ET", variant="primary", scale=1)
578
-
579
- chart_out = gr.Plot(label="Grafik", elem_id="chart-area")
580
- signal_out = gr.HTML(label="Sinyal Özeti")
581
-
582
- analyze_btn.click(
583
- fn=run_analysis,
584
- inputs=[sym_dd, int_dd],
585
- outputs=[chart_out, signal_out],
586
- )
587
-
588
- gr.HTML("""
589
- <div style="
590
- text-align:center; padding:16px;
591
- color:#2a2a2a; font-size:0.7em;
592
- font-family:'Courier New',monospace; letter-spacing:1px;
593
- ">
594
- CRYPTO SIGNAL PRO · Binance API · XGBoost AI · Plotly Charts<br>
595
- ⚠️ Yatırım tavsiyesi değildir — DYOR
596
- </div>
597
- """)
598
-
599
- if __name__ == "__main__":
600
- demo.launch(server_name="0.0.0.0", server_port=7860)