GoshawkVortexAI commited on
Commit
4fb38ec
·
verified ·
1 Parent(s): 6a8e809

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +444 -0
app.py ADDED
@@ -0,0 +1,444 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Kripto Arbitraj Tarayıcı - Gradio Uygulaması
3
+ Borsa fiyat farklarını tespit eder ve arbitraj fırsatlarını gösterir.
4
+ """
5
+
6
+ import gradio as gr
7
+ import requests
8
+ import pandas as pd
9
+ import time
10
+ from datetime import datetime
11
+
12
+ # ─────────────────────────────────────────────
13
+ # BORSA API FONKSİYONLARI
14
+ # ─────────────────────────────────────────────
15
+
16
+ BORSALAR = {
17
+ "Binance": "https://api.binance.com/api/v3/ticker/price?symbol={symbol}USDT",
18
+ "KuCoin": "https://api.kucoin.com/api/v1/market/orderbook/level1?symbol={symbol}-USDT",
19
+ "Bybit": "https://api.bybit.com/v5/market/tickers?category=spot&symbol={symbol}USDT",
20
+ "OKX": "https://www.okx.com/api/v5/market/ticker?instId={symbol}-USDT",
21
+ "Gate.io": "https://api.gateio.ws/api/v4/spot/tickers?currency_pair={symbol}_USDT",
22
+ }
23
+
24
+ DESTEKLENEN_COINLER = [
25
+ "BTC", "ETH", "BNB", "SOL", "XRP",
26
+ "ADA", "AVAX", "DOT", "MATIC", "LINK",
27
+ "LTC", "UNI", "ATOM", "NEAR", "APT",
28
+ ]
29
+
30
+
31
+ def binance_fiyat(symbol: str) -> float | None:
32
+ try:
33
+ r = requests.get(
34
+ f"https://api.binance.com/api/v3/ticker/price?symbol={symbol}USDT",
35
+ timeout=5
36
+ )
37
+ return float(r.json()["price"])
38
+ except Exception:
39
+ return None
40
+
41
+
42
+ def kucoin_fiyat(symbol: str) -> float | None:
43
+ try:
44
+ r = requests.get(
45
+ f"https://api.kucoin.com/api/v1/market/orderbook/level1?symbol={symbol}-USDT",
46
+ timeout=5
47
+ )
48
+ data = r.json()
49
+ price = data.get("data", {}).get("price")
50
+ return float(price) if price else None
51
+ except Exception:
52
+ return None
53
+
54
+
55
+ def bybit_fiyat(symbol: str) -> float | None:
56
+ try:
57
+ r = requests.get(
58
+ f"https://api.bybit.com/v5/market/tickers?category=spot&symbol={symbol}USDT",
59
+ timeout=5
60
+ )
61
+ items = r.json().get("result", {}).get("list", [])
62
+ if items:
63
+ return float(items[0]["lastPrice"])
64
+ return None
65
+ except Exception:
66
+ return None
67
+
68
+
69
+ def okx_fiyat(symbol: str) -> float | None:
70
+ try:
71
+ r = requests.get(
72
+ f"https://www.okx.com/api/v5/market/ticker?instId={symbol}-USDT",
73
+ timeout=5
74
+ )
75
+ data = r.json().get("data", [])
76
+ if data:
77
+ return float(data[0]["last"])
78
+ return None
79
+ except Exception:
80
+ return None
81
+
82
+
83
+ def gateio_fiyat(symbol: str) -> float | None:
84
+ try:
85
+ r = requests.get(
86
+ f"https://api.gateio.ws/api/v4/spot/tickers?currency_pair={symbol}_USDT",
87
+ timeout=5
88
+ )
89
+ data = r.json()
90
+ if data:
91
+ return float(data[0]["last"])
92
+ return None
93
+ except Exception:
94
+ return None
95
+
96
+
97
+ BORSA_FONKSIYONLARI = {
98
+ "Binance": binance_fiyat,
99
+ "KuCoin": kucoin_fiyat,
100
+ "Bybit": bybit_fiyat,
101
+ "OKX": okx_fiyat,
102
+ "Gate.io": gateio_fiyat,
103
+ }
104
+
105
+ # ─────────────────────────────────────────────
106
+ # ARBİTRAJ HESAPLAMA
107
+ # ─────────────────────────────────────────────
108
+
109
+ def fiyatlari_cek(coinler: list[str], borsalar: list[str]) -> dict:
110
+ """Seçili coin ve borsalar için fiyatları çeker."""
111
+ sonuclar = {}
112
+ for coin in coinler:
113
+ sonuclar[coin] = {}
114
+ for borsa in borsalar:
115
+ fn = BORSA_FONKSIYONLARI.get(borsa)
116
+ if fn:
117
+ sonuclar[coin][borsa] = fn(coin)
118
+ return sonuclar
119
+
120
+
121
+ def arbitraj_hesapla(
122
+ secili_coinler: list[str],
123
+ secili_borsalar: list[str],
124
+ min_fark: float,
125
+ islem_ucreti: float,
126
+ ) -> tuple[str, str, str]:
127
+ """
128
+ Arbitraj fırsatlarını hesaplar.
129
+ Döndürür: (durum_mesaji, fiyat_tablosu_html, firsat_tablosu_html)
130
+ """
131
+ if not secili_coinler:
132
+ return "⚠️ En az bir coin seçin.", "", ""
133
+ if len(secili_borsalar) < 2:
134
+ return "⚠️ En az iki borsa seçin.", "", ""
135
+
136
+ zaman = datetime.now().strftime("%H:%M:%S")
137
+ durum = f"🔄 Fiyatlar çekiliyor... ({zaman})"
138
+
139
+ fiyatlar = fiyatlari_cek(secili_coinler, secili_borsalar)
140
+
141
+ # ── Fiyat tablosu ──────────────────────────────
142
+ fiyat_satirlari = ""
143
+ for coin, borsa_fiyatlari in fiyatlar.items():
144
+ for borsa, fiyat in borsa_fiyatlari.items():
145
+ gosterim = f"${fiyat:,.4f}" if fiyat else "—"
146
+ fiyat_satirlari += f"<tr><td>{coin}</td><td>{borsa}</td><td>{gosterim}</td></tr>\n"
147
+
148
+ fiyat_tablosu = f"""
149
+ <div class="tablo-kap">
150
+ <h3 class="tablo-baslik">📊 Anlık Fiyatlar</h3>
151
+ <table class="arb-tablo">
152
+ <thead><tr><th>Coin</th><th>Borsa</th><th>Fiyat (USDT)</th></tr></thead>
153
+ <tbody>{fiyat_satirlari}</tbody>
154
+ </table>
155
+ </div>
156
+ """
157
+
158
+ # ── Arbitraj fırsatları ────────────────────────
159
+ firsatlar = []
160
+ for coin, borsa_fiyatlari in fiyatlar.items():
161
+ gecerli = {b: p for b, p in borsa_fiyatlari.items() if p is not None}
162
+ if len(gecerli) < 2:
163
+ continue
164
+ borsalar_list = list(gecerli.items())
165
+ for i in range(len(borsalar_list)):
166
+ for j in range(len(borsalar_list)):
167
+ if i == j:
168
+ continue
169
+ al_borsa, al_fiyat = borsalar_list[i]
170
+ sat_borsa, sat_fiyat = borsalar_list[j]
171
+ if sat_fiyat <= al_fiyat:
172
+ continue
173
+ brut_fark = (sat_fiyat - al_fiyat) / al_fiyat * 100
174
+ net_fark = brut_fark - (islem_ucreti * 2)
175
+ if net_fark >= min_fark:
176
+ firsatlar.append({
177
+ "coin": coin,
178
+ "al_borsa": al_borsa,
179
+ "al_fiyat": al_fiyat,
180
+ "sat_borsa": sat_borsa,
181
+ "sat_fiyat": sat_fiyat,
182
+ "brut_fark": brut_fark,
183
+ "net_fark": net_fark,
184
+ })
185
+
186
+ firsatlar.sort(key=lambda x: x["net_fark"], reverse=True)
187
+
188
+ if firsatlar:
189
+ firsat_satirlari = ""
190
+ for f in firsatlar:
191
+ seviye = "🟢" if f["net_fark"] >= 1.0 else "🟡"
192
+ firsat_satirlari += f"""
193
+ <tr>
194
+ <td><strong>{f['coin']}</strong></td>
195
+ <td style="color:#4ade80">{f['al_borsa']}<br><small>${f['al_fiyat']:,.4f}</small></td>
196
+ <td style="color:#f87171">{f['sat_borsa']}<br><small>${f['sat_fiyat']:,.4f}</small></td>
197
+ <td>{f['brut_fark']:.3f}%</td>
198
+ <td><strong>{seviye} {f['net_fark']:.3f}%</strong></td>
199
+ </tr>"""
200
+ firsat_html = f"""
201
+ <div class="tablo-kap firsat-kap">
202
+ <h3 class="tablo-baslik">⚡ Arbitraj Fırsatları ({len(firsatlar)} adet)</h3>
203
+ <table class="arb-tablo">
204
+ <thead><tr>
205
+ <th>Coin</th><th>Al (Borsa)</th><th>Sat (Borsa)</th>
206
+ <th>Brüt Fark</th><th>Net Fark</th>
207
+ </tr></thead>
208
+ <tbody>{firsat_satirlari}</tbody>
209
+ </table>
210
+ </div>"""
211
+ durum = f"✅ {len(firsatlar)} fırsat bulundu | Son güncelleme: {zaman}"
212
+ else:
213
+ firsat_html = """
214
+ <div class="tablo-kap bos-kap">
215
+ <p style="text-align:center;padding:2rem;color:#94a3b8;">
216
+ 😴 Eşik değerini karşılayan arbitraj fırsatı bulunamadı.<br>
217
+ <small>Min. net farkı düşürmeyi veya daha fazla borsa seçmeyi deneyin.</small>
218
+ </p>
219
+ </div>"""
220
+ durum = f"😴 Fırsat bulunamadı | Son güncelleme: {zaman}"
221
+
222
+ return durum, fiyat_tablosu, firsat_html
223
+
224
+
225
+ # ─────────────────────────────────────────────
226
+ # CSS & TEMA
227
+ # ─────────────────────────────────────────────
228
+
229
+ CSS = """
230
+ @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600&family=Space+Grotesk:wght@400;600;700&display=swap');
231
+
232
+ :root {
233
+ --bg: #0a0e1a;
234
+ --surface: #111827;
235
+ --border: #1e2d40;
236
+ --accent: #00d4ff;
237
+ --accent2: #7c3aed;
238
+ --green: #4ade80;
239
+ --red: #f87171;
240
+ --yellow: #fbbf24;
241
+ --text: #e2e8f0;
242
+ --muted: #64748b;
243
+ }
244
+
245
+ body, .gradio-container {
246
+ background: var(--bg) !important;
247
+ font-family: 'Space Grotesk', sans-serif !important;
248
+ color: var(--text) !important;
249
+ }
250
+
251
+ .baslik-blok {
252
+ background: linear-gradient(135deg, #0f172a 0%, #1a1040 50%, #0f172a 100%);
253
+ border: 1px solid var(--border);
254
+ border-radius: 12px;
255
+ padding: 1.5rem 2rem;
256
+ margin-bottom: 1rem;
257
+ position: relative;
258
+ overflow: hidden;
259
+ }
260
+ .baslik-blok::before {
261
+ content: '';
262
+ position: absolute;
263
+ top: 0; left: 0; right: 0;
264
+ height: 2px;
265
+ background: linear-gradient(90deg, var(--accent2), var(--accent), var(--green));
266
+ }
267
+ .baslik-blok h1 {
268
+ font-size: 1.8rem;
269
+ font-weight: 700;
270
+ background: linear-gradient(90deg, var(--accent), var(--green));
271
+ -webkit-background-clip: text;
272
+ -webkit-text-fill-color: transparent;
273
+ margin: 0 0 0.25rem 0;
274
+ }
275
+ .baslik-blok p {
276
+ color: var(--muted);
277
+ font-size: 0.85rem;
278
+ margin: 0;
279
+ font-family: 'IBM Plex Mono', monospace;
280
+ }
281
+
282
+ /* Tablo stili */
283
+ .tablo-kap { margin-top: 1rem; }
284
+ .tablo-baslik {
285
+ font-size: 1rem;
286
+ font-weight: 600;
287
+ color: var(--accent);
288
+ margin-bottom: 0.75rem;
289
+ font-family: 'IBM Plex Mono', monospace;
290
+ }
291
+ .arb-tablo {
292
+ width: 100%;
293
+ border-collapse: collapse;
294
+ font-size: 0.85rem;
295
+ font-family: 'IBM Plex Mono', monospace;
296
+ }
297
+ .arb-tablo th {
298
+ background: #1e2d40;
299
+ color: var(--accent);
300
+ padding: 0.6rem 1rem;
301
+ text-align: left;
302
+ font-weight: 600;
303
+ border-bottom: 1px solid var(--border);
304
+ }
305
+ .arb-tablo td {
306
+ padding: 0.55rem 1rem;
307
+ border-bottom: 1px solid #1a2535;
308
+ color: var(--text);
309
+ }
310
+ .arb-tablo tr:hover td { background: #141f2e; }
311
+ .firsat-kap .tablo-baslik { color: var(--green); }
312
+ .bos-kap { background: #0d1525; border-radius: 8px; border: 1px dashed var(--border); }
313
+
314
+ /* Durum çubuğu */
315
+ #durum-kutusu textarea {
316
+ background: #0d1a2a !important;
317
+ border: 1px solid var(--border) !important;
318
+ color: var(--accent) !important;
319
+ font-family: 'IBM Plex Mono', monospace !important;
320
+ font-size: 0.82rem !important;
321
+ }
322
+
323
+ /* Buton */
324
+ #tara-btn {
325
+ background: linear-gradient(135deg, var(--accent2), var(--accent)) !important;
326
+ border: none !important;
327
+ font-weight: 700 !important;
328
+ font-size: 1rem !important;
329
+ padding: 0.8rem !important;
330
+ border-radius: 8px !important;
331
+ color: white !important;
332
+ cursor: pointer !important;
333
+ transition: opacity 0.2s !important;
334
+ }
335
+ #tara-btn:hover { opacity: 0.85 !important; }
336
+
337
+ /* Panel */
338
+ .panel {
339
+ background: var(--surface) !important;
340
+ border: 1px solid var(--border) !important;
341
+ border-radius: 10px !important;
342
+ }
343
+
344
+ label { color: var(--muted) !important; font-size: 0.82rem !important; }
345
+
346
+ .gr-checkbox-group label, .gr-radio label { color: var(--text) !important; }
347
+
348
+ input[type=number], .gr-slider { accent-color: var(--accent) !important; }
349
+ """
350
+
351
+ # ─────────────────────────────────────────────
352
+ # GRADIO ARAYÜZÜ
353
+ # ─────────────────────────────────────────────
354
+
355
+ def uygulama_olustur():
356
+ with gr.Blocks(css=CSS, title="Kripto Arbitraj Tarayıcı") as demo:
357
+
358
+ gr.HTML("""
359
+ <div class="baslik-blok">
360
+ <h1>⚡ Kripto Arbitraj Tarayıcı</h1>
361
+ <p>Borsalar arası fiyat farklarını gerçek zamanlı tespit et • USDT çiftleri • Türkçe arayüz</p>
362
+ </div>
363
+ """)
364
+
365
+ with gr.Row():
366
+ # ── Sol panel: Ayarlar ──────────────────
367
+ with gr.Column(scale=1, elem_classes="panel"):
368
+ gr.Markdown("### 🎛️ Ayarlar")
369
+
370
+ secili_coinler = gr.CheckboxGroup(
371
+ choices=DESTEKLENEN_COINLER,
372
+ value=["BTC", "ETH", "SOL", "BNB"],
373
+ label="Coin Seçimi",
374
+ info="Taranacak kripto para birimleri",
375
+ )
376
+
377
+ secili_borsalar = gr.CheckboxGroup(
378
+ choices=list(BORSA_FONKSIYONLARI.keys()),
379
+ value=["Binance", "KuCoin", "Bybit"],
380
+ label="Borsa Seçimi",
381
+ info="En az 2 borsa seçin",
382
+ )
383
+
384
+ min_fark = gr.Slider(
385
+ minimum=0.0,
386
+ maximum=5.0,
387
+ value=0.3,
388
+ step=0.05,
389
+ label="Min. Net Fark (%)",
390
+ info="Bu değerin altındaki fırsatlar gizlenir",
391
+ )
392
+
393
+ islem_ucreti = gr.Slider(
394
+ minimum=0.0,
395
+ maximum=1.0,
396
+ value=0.1,
397
+ step=0.01,
398
+ label="İşlem Ücreti (% / borsa)",
399
+ info="Her iki taraf için toplam 2× uygulanır",
400
+ )
401
+
402
+ tara_btn = gr.Button(
403
+ "🚀 Tara",
404
+ variant="primary",
405
+ elem_id="tara-btn",
406
+ )
407
+
408
+ durum = gr.Textbox(
409
+ label="Durum",
410
+ interactive=False,
411
+ elem_id="durum-kutusu",
412
+ lines=2,
413
+ )
414
+
415
+ gr.Markdown("""
416
+ ---
417
+ **⚠️ Uyarı:** Bu araç yalnızca bilgi amaçlıdır.
418
+ Arbitraj işlemleri transfer süresi, likidite
419
+ ve ağ ücretlerinden etkilenebilir.
420
+ """)
421
+
422
+ # ── Sağ panel: Sonuçlar ─────────────────
423
+ with gr.Column(scale=3):
424
+ fiyat_html = gr.HTML(label="Fiyatlar")
425
+ firsat_html = gr.HTML(label="Fırsatlar")
426
+
427
+ # ── Bağlantılar ─────────────────────────────
428
+ tara_btn.click(
429
+ fn=arbitraj_hesapla,
430
+ inputs=[secili_coinler, secili_borsalar, min_fark, islem_ucreti],
431
+ outputs=[durum, fiyat_html, firsat_html],
432
+ )
433
+
434
+ return demo
435
+
436
+
437
+ if __name__ == "__main__":
438
+ app = uygulama_olustur()
439
+ app.launch(
440
+ server_name="0.0.0.0",
441
+ server_port=7860,
442
+ show_api=False,
443
+ share=False,
444
+ )