GoshawkVortexAI commited on
Commit
6269fce
Β·
verified Β·
1 Parent(s): 904b4e1

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +600 -0
app.py ADDED
@@ -0,0 +1,600 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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)