GoshawkVortexAI commited on
Commit
0c1454f
Β·
verified Β·
1 Parent(s): d87d9c5

Upload 2 files

Browse files
Files changed (2) hide show
  1. app-2.py +568 -0
  2. requirements-27.txt +6 -0
app-2.py ADDED
@@ -0,0 +1,568 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ╔══════════════════════════════════════════════════════════╗
2
+ # β•‘ CRYPTO SIGNAL PRO β€” OKX Edition β•‘
3
+ # β•‘ OKX REST API Β· XGBoost AI Β· CanlΔ± Otomatik Analiz β•‘
4
+ # β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
5
+
6
+ import subprocess, sys, warnings
7
+ warnings.filterwarnings("ignore")
8
+
9
+ def _pip(pkg):
10
+ subprocess.check_call([sys.executable,"-m","pip","install",pkg,"-q"],
11
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
12
+
13
+ for _p in ["requests","pandas","numpy","plotly","xgboost","scikit-learn"]:
14
+ try: _pip(_p)
15
+ except: pass
16
+
17
+ import gradio as gr
18
+ import requests, time, traceback
19
+ import pandas as pd
20
+ import numpy as np
21
+ import plotly.graph_objects as go
22
+ from plotly.subplots import make_subplots
23
+ from datetime import datetime, timezone
24
+
25
+ try:
26
+ from xgboost import XGBClassifier
27
+ XGB_OK = True
28
+ except ImportError:
29
+ XGB_OK = False
30
+
31
+ from sklearn.preprocessing import StandardScaler
32
+
33
+ # ──────────────────────────────────────────────────────────
34
+ # OKX REST API
35
+ # ──────────────────────────────────────────────────────────
36
+ OKX_BASE = "https://www.okx.com"
37
+
38
+ # OKX instId formatΔ±: BTC-USDT (tire ile)
39
+ # KullanΔ±cΔ±ya gΓΆsterilecek etiket: BTCUSDT (tirensiz)
40
+ SYMBOLS_LABEL = [
41
+ "BTCUSDT","ETHUSDT","SOLUSDT","BNBUSDT","XRPUSDT",
42
+ "ADAUSDT","DOGEUSDT","AVAXUSDT","DOTUSDT","LINKUSDT",
43
+ "LTCUSDT","UNIUSDT","ATOMUSDT","NEARUSDT","OPUSDT",
44
+ "ARBUSDT","INJUSDT","TIAUSDT","SUIUSDT","APTUSDT",
45
+ ]
46
+ def _to_instid(label: str) -> str:
47
+ """BTCUSDT β†’ BTC-USDT"""
48
+ base = label.replace("USDT","")
49
+ return f"{base}-USDT"
50
+
51
+ # OKX bar formatlarΔ±
52
+ INTERVALS = ["5m","15m","1H","4H","1D"]
53
+ _OKX_BAR = {"5m":"5m","15m":"15m","1H":"1H","4H":"4H","1D":"1D"}
54
+
55
+ def fetch_okx(label: str, interval: str, limit: int = 300) -> pd.DataFrame:
56
+ """OKX /api/v5/market/candles β†’ OHLCV DataFrame"""
57
+ inst = _to_instid(label)
58
+ bar = _OKX_BAR.get(interval, interval)
59
+ url = f"{OKX_BASE}/api/v5/market/candles"
60
+ params = {"instId": inst, "bar": bar, "limit": min(limit, 300)}
61
+ r = requests.get(url, params=params, timeout=12)
62
+ r.raise_for_status()
63
+ data = r.json()
64
+ if data.get("code") != "0":
65
+ raise RuntimeError(f"OKX hata: {data.get('msg','bilinmeyen')}")
66
+ raw = data["data"] # liste: [[ts,o,h,l,c,vol,volCcy,volCcyQuote,confirm],...]
67
+ if not raw:
68
+ raise RuntimeError("OKX boş veri dândürdü.")
69
+ df = pd.DataFrame(raw, columns=["ts","open","high","low","close","vol","volCcy","volCcyQ","confirm"])
70
+ for c in ["open","high","low","close","vol"]:
71
+ df[c] = df[c].astype(float)
72
+ df["ts"] = pd.to_datetime(df["ts"].astype(np.int64), unit="ms", utc=True)
73
+ df = df.sort_values("ts").set_index("ts")
74
+ df.index.name = "open_time"
75
+ return df[["open","high","low","close"]].rename(columns={"vol":"volume"}).assign(
76
+ volume=df["vol"])
77
+
78
+ def fetch_ticker(label: str) -> dict:
79
+ """Anlık ticker: bid/ask/last/24h değişim"""
80
+ inst = _to_instid(label)
81
+ r = requests.get(f"{OKX_BASE}/api/v5/market/ticker",
82
+ params={"instId": inst}, timeout=8)
83
+ r.raise_for_status()
84
+ d = r.json()
85
+ if d.get("code") != "0" or not d["data"]:
86
+ return {}
87
+ t = d["data"][0]
88
+ return {
89
+ "last": float(t.get("last",0)),
90
+ "bid": float(t.get("bidPx",0)),
91
+ "ask": float(t.get("askPx",0)),
92
+ "chg24": float(t.get("chgUtc8",0) or t.get("sodUtc8",0) or 0),
93
+ "vol24": float(t.get("vol24h",0)),
94
+ "high24": float(t.get("high24h",0)),
95
+ "low24": float(t.get("low24h",0)),
96
+ }
97
+
98
+ # ──────────────────────────────────────────────────────────
99
+ # TEKNΔ°K GΓ–STERGELer
100
+ # ──────────────────────────────────────────────────────────
101
+ def ema(s,n): return s.ewm(span=n,adjust=False).mean()
102
+ def rsi(s,n=14):
103
+ d=s.diff(); g=d.clip(lower=0).rolling(n).mean()
104
+ l=(-d.clip(upper=0)).rolling(n).mean()
105
+ return 100-(100/(1+g/l.replace(0,np.nan)))
106
+ def macd(s):
107
+ ml=s.ewm(span=12,adjust=False).mean()-s.ewm(span=26,adjust=False).mean()
108
+ sig=ml.ewm(span=9,adjust=False).mean(); return ml,sig,ml-sig
109
+ def atr(df,n=14):
110
+ tr=pd.concat([df.high-df.low,
111
+ (df.high-df.close.shift()).abs(),
112
+ (df.low -df.close.shift()).abs()],axis=1).max(axis=1)
113
+ return tr.rolling(n).mean()
114
+ def vwap(df):
115
+ tp=(df.high+df.low+df.close)/3
116
+ return (tp*df.volume).cumsum()/df.volume.cumsum()
117
+
118
+ def add_indicators(df):
119
+ df=df.copy()
120
+ df["ema20"] =ema(df.close,20)
121
+ df["ema50"] =ema(df.close,50)
122
+ df["ema200"]=ema(df.close,200)
123
+ df["rsi"] =rsi(df.close)
124
+ df["macd"],df["macd_sig"],df["macd_hist"]=macd(df.close)
125
+ df["atr"] =atr(df)
126
+ df["vwap"] =vwap(df)
127
+ df["vol_ma"]=df.volume.rolling(20).mean()
128
+ df["vol_ratio"]=df.volume/df.vol_ma.replace(0,np.nan)
129
+ return df.dropna()
130
+
131
+ # ──────────────────────────────────────────────────────────
132
+ # SİNYAL MANTIĞI
133
+ # ──────────────────────────────────────────────────────────
134
+ def generate_signal(df):
135
+ l,p=df.iloc[-1],df.iloc[-2]
136
+ bc=[l.ema20>l.ema50, l.ema50>l.ema200, l.rsi>50,
137
+ bool((l.macd>l.macd_sig) and (p.macd<=p.macd_sig)),
138
+ l.close>l.vwap]
139
+ sc=[l.ema20<l.ema50, l.ema50<l.ema200, l.rsi<50,
140
+ bool((l.macd<l.macd_sig) and (p.macd>=p.macd_sig)),
141
+ l.close<l.vwap]
142
+ bs,ss=sum(bc),sum(sc)
143
+ px,at=l.close,l.atr
144
+ if bs>=3:
145
+ sig="AL πŸ“ˆ"; conf=int(bs/5*100)
146
+ sl=round(px-1.5*at,6); tp=round(px+3.0*at,6)
147
+ elif ss>=3:
148
+ sig="SAT πŸ“‰"; conf=int(ss/5*100)
149
+ sl=round(px+1.5*at,6); tp=round(px-3.0*at,6)
150
+ else:
151
+ sig="BEKLE ⏳"; conf=30
152
+ sl=round(px-1.5*at,6); tp=round(px+1.5*at,6)
153
+ rr=round(abs(tp-px)/abs(sl-px),2) if abs(sl-px)>0 else 0
154
+ cond_txt=(
155
+ f"EMA20>50:{'βœ…' if bc[0] else '❌'} "
156
+ f"EMA50>200:{'βœ…' if bc[1] else '❌'} "
157
+ f"RSI>50:{'βœ…' if bc[2] else '❌'} "
158
+ f"MACDβœ—:{'βœ…' if bc[3] else '❌'} "
159
+ f"Fiyat>VWAP:{'βœ…' if bc[4] else '❌'}"
160
+ )
161
+ return sig,conf,sl,tp,rr,cond_txt
162
+
163
+ # ──────────────────────────────────────────────────────────
164
+ # AI (XGBoost)
165
+ # ──────────────────────────────────────────────────────────
166
+ FCOLS=["r1","r3","r5","e2050","e50200","rsi_n","macd_n","mhist_n","vwap_d","atr_n","volr"]
167
+
168
+ def featurize(df):
169
+ d=df.copy()
170
+ d["r1"]=d.close.pct_change(1); d["r3"]=d.close.pct_change(3); d["r5"]=d.close.pct_change(5)
171
+ d["e2050"] =(d.ema20-d.ema50)/d.close
172
+ d["e50200"]=(d.ema50-d.ema200)/d.close
173
+ d["rsi_n"] =d.rsi/100
174
+ d["macd_n"]=d.macd/d.close
175
+ d["mhist_n"]=d.macd_hist/d.close
176
+ d["vwap_d"]=(d.close-d.vwap)/d.close
177
+ d["atr_n"] =d.atr/d.close
178
+ d["volr"] =d.vol_ratio.clip(0,5)
179
+ return d.dropna()
180
+
181
+ def train_ai(df):
182
+ if not XGB_OK: return 50
183
+ fd=featurize(df)
184
+ if len(fd)<60: return 50
185
+ fd=fd.copy(); fd["tgt"]=(fd.close.shift(-3)>fd.close).astype(int)
186
+ fd=fd.dropna()
187
+ if len(fd)<40: return 50
188
+ X=fd[FCOLS].values; y=fd["tgt"].values
189
+ sc=StandardScaler(); Xs=sc.fit_transform(X)
190
+ sp=int(len(Xs)*0.8)
191
+ try:
192
+ m=XGBClassifier(n_estimators=60,max_depth=3,learning_rate=0.1,
193
+ eval_metric="logloss",verbosity=0,n_jobs=1)
194
+ m.fit(Xs[:sp],y[:sp])
195
+ lf=featurize(df.tail(60)).tail(1)[FCOLS].values
196
+ prob=m.predict_proba(sc.transform(lf))[0][1]
197
+ return int(prob*100)
198
+ except:
199
+ return 50
200
+
201
+ # ──────────────────────────────────────────────────────────
202
+ # GRAFΔ°K
203
+ # ──────────────────────────────────────────────────────────
204
+ def build_chart(df, label, interval, signal, sl, tp, ticker):
205
+ p=df.tail(150).copy()
206
+ fig=make_subplots(
207
+ rows=4,cols=1,shared_xaxes=True,
208
+ row_heights=[0.52,0.16,0.16,0.16],
209
+ vertical_spacing=0.02,
210
+ subplot_titles=["","RSI","MACD","Volume"],
211
+ )
212
+
213
+ # ── Mum grafiği
214
+ fig.add_trace(go.Candlestick(
215
+ x=p.index,open=p.open,high=p.high,low=p.low,close=p.close,
216
+ name="Fiyat",
217
+ increasing_line_color="#00e676", decreasing_line_color="#ff5252",
218
+ increasing_fillcolor="#00c85388",decreasing_fillcolor="#ff525288",
219
+ line_width=1,
220
+ ),row=1,col=1)
221
+
222
+ # ── EMAs
223
+ for n,c,w,dash in [
224
+ (20,"#64b5f6",1.5,"solid"),
225
+ (50,"#ffb74d",1.5,"solid"),
226
+ (200,"#ce93d8",2.0,"dot"),
227
+ ]:
228
+ fig.add_trace(go.Scatter(x=p.index,y=p[f"ema{n}"],name=f"EMA{n}",
229
+ line=dict(color=c,width=w,dash=dash),opacity=0.85),row=1,col=1)
230
+
231
+ # ── VWAP
232
+ fig.add_trace(go.Scatter(x=p.index,y=p.vwap,name="VWAP",
233
+ line=dict(color="#f06292",width=1.4,dash="dashdot"),opacity=0.8),row=1,col=1)
234
+
235
+ # ── SL / TP Γ§izgileri
236
+ fig.add_hline(y=sl,line_dash="dash",line_color="#ff525299",line_width=1.2,
237
+ annotation_text=f"SL {sl:,.4f}",annotation_font_color="#ff5252",
238
+ annotation_position="right",row=1,col=1)
239
+ fig.add_hline(y=tp,line_dash="dash",line_color="#00e67699",line_width=1.2,
240
+ annotation_text=f"TP {tp:,.4f}",annotation_font_color="#00e676",
241
+ annotation_position="right",row=1,col=1)
242
+
243
+ # ── Sinyal oku (son barda)
244
+ li,lc=p.index[-1],p.close.iloc[-1]
245
+ if "AL" in signal:
246
+ fig.add_trace(go.Scatter(x=[li],y=[lc*0.992],mode="markers+text",
247
+ marker=dict(symbol="triangle-up",size=18,color="#00e676"),
248
+ text=["AL"],textposition="bottom center",
249
+ textfont=dict(color="#00e676",size=11),showlegend=False),row=1,col=1)
250
+ elif "SAT" in signal:
251
+ fig.add_trace(go.Scatter(x=[li],y=[lc*1.008],mode="markers+text",
252
+ marker=dict(symbol="triangle-down",size=18,color="#ff5252"),
253
+ text=["SAT"],textposition="top center",
254
+ textfont=dict(color="#ff5252",size=11),showlegend=False),row=1,col=1)
255
+
256
+ # ── RSI
257
+ fig.add_trace(go.Scatter(x=p.index,y=p.rsi,name="RSI",
258
+ line=dict(color="#80cbc4",width=1.4),fill="tozeroy",
259
+ fillcolor="rgba(128,203,196,0.06)"),row=2,col=1)
260
+ for yv,c in [(70,"#ff525266"),(50,"#55555566"),(30,"#00e67666")]:
261
+ fig.add_hline(y=yv,line_dash="dot",line_color=c,line_width=0.8,row=2,col=1)
262
+
263
+ # ── MACD histogram + Γ§izgiler
264
+ clrs=["#00c853aa" if v>=0 else "#ff1744aa" for v in p.macd_hist]
265
+ fig.add_trace(go.Bar(x=p.index,y=p.macd_hist,name="Hist",
266
+ marker_color=clrs,showlegend=False),row=3,col=1)
267
+ fig.add_trace(go.Scatter(x=p.index,y=p.macd,name="MACD",
268
+ line=dict(color="#64b5f6",width=1.2)),row=3,col=1)
269
+ fig.add_trace(go.Scatter(x=p.index,y=p.macd_sig,name="Signal",
270
+ line=dict(color="#ffb74d",width=1.2)),row=3,col=1)
271
+
272
+ # ── Volume
273
+ vcols=["#00c85366" if c>=o else "#ff525266"
274
+ for c,o in zip(p.close,p.open)]
275
+ fig.add_trace(go.Bar(x=p.index,y=p.volume,name="Vol",
276
+ marker_color=vcols,showlegend=False),row=4,col=1)
277
+ fig.add_trace(go.Scatter(x=p.index,y=p.vol_ma,name="Vol MA",
278
+ line=dict(color="#ffcc0299",width=1.2)),row=4,col=1)
279
+
280
+ # ── Son fiyat annotation
281
+ price_str=f"${lc:,.4f}"
282
+ fig.add_annotation(x=1,y=lc,xref="paper",yref="y",
283
+ text=f" {price_str} ",showarrow=False,
284
+ font=dict(color="#fff",size=11,family="Courier New"),
285
+ bgcolor="#1565c0",bordercolor="#42a5f5",borderwidth=1,
286
+ xanchor="left",yanchor="middle")
287
+
288
+ # ── BaşlΔ±k
289
+ chg = ticker.get("chg24",0)
290
+ chg_col="#00e676" if chg>=0 else "#ff5252"
291
+ chg_sym="β–²" if chg>=0 else "β–Ό"
292
+ title_txt=(f"<b>{label}</b> <span style='font-size:13px;color:{chg_col}'>"
293
+ f"{chg_sym} {abs(chg):.2f}%</span> "
294
+ f"<span style='font-size:11px;color:#666'>{interval} Β· OKX</span>")
295
+
296
+ fig.update_layout(
297
+ title=dict(text=title_txt,font=dict(color="#e0e0e0",size=15,
298
+ family="'Courier New',monospace"),x=0.01,xanchor="left"),
299
+ paper_bgcolor="#0b0b10",plot_bgcolor="#0f0f16",
300
+ font=dict(color="#9e9e9e",family="'Courier New',monospace",size=10),
301
+ xaxis_rangeslider_visible=False,
302
+ height=800,
303
+ legend=dict(bgcolor="rgba(15,15,22,0.85)",bordercolor="#222",
304
+ borderwidth=1,font=dict(size=9),x=0.01,y=0.99,
305
+ xanchor="left",yanchor="top"),
306
+ margin=dict(l=55,r=80,t=55,b=15),
307
+ hoverlabel=dict(bgcolor="#1a1a2e",bordercolor="#333",
308
+ font_color="#e0e0e0",font_family="Courier New"),
309
+ )
310
+ for i in range(1,5):
311
+ fig.update_xaxes(gridcolor="#191924",zeroline=False,
312
+ showspikes=True,spikecolor="#444",
313
+ spikethickness=1,row=i,col=1)
314
+ fig.update_yaxes(gridcolor="#191924",zeroline=False,
315
+ showspikes=True,spikecolor="#444",row=i,col=1)
316
+ return fig
317
+
318
+ # ──────────────────────────────────────────────────────────
319
+ # PANEL HTML
320
+ # ──────────────────────────────────────────────────────────
321
+ def build_panel(label,interval,signal,tech_conf,ai_conf,sl,tp,rr,
322
+ cond_txt,ticker,df):
323
+ final=int(0.5*tech_conf+0.5*ai_conf)
324
+ price=df.close.iloc[-1]
325
+ rsi_v=df.rsi.iloc[-1]
326
+ atr_v=df.atr.iloc[-1]
327
+ ema20=df.ema20.iloc[-1]; ema50=df.ema50.iloc[-1]; ema200=df.ema200.iloc[-1]
328
+ vwap_v=df.vwap.iloc[-1]
329
+ now=datetime.now(timezone.utc).strftime("%H:%M:%S UTC")
330
+
331
+ if "AL" in signal: dir_txt,dir_col,bg="🟒 YUKARI","#00e676","rgba(0,200,83,0.08)"
332
+ elif "SAT" in signal: dir_txt,dir_col,bg="πŸ”΄ AŞAĞI","#ff5252","rgba(255,82,82,0.08)"
333
+ else: dir_txt,dir_col,bg="🟑 YATAY","#ffb74d","rgba(255,183,77,0.08)"
334
+
335
+ bar_col=("#238636" if final>=65 else "#f0883e" if final>=40 else "#da3633")
336
+ chg=ticker.get("chg24",0); chg_col="#00e676" if chg>=0 else "#ff5252"
337
+ h24=ticker.get("high24",0); l24=ticker.get("low24",0)
338
+ vol24=ticker.get("vol24",0)
339
+
340
+ def row(label,val,extra="",bg_tr=""):
341
+ bg_style=f"background:{bg_tr};" if bg_tr else ""
342
+ return (f'<tr style="{bg_style}">'
343
+ f'<td style="padding:7px 10px;color:#6e7681;font-size:.85em">{label}</td>'
344
+ f'<td style="padding:7px 10px;font-size:.9em">{val}</td>'
345
+ f'{"<td style=padding:7px_10px;font-size:.8em;color:#555>"+extra+"</td>" if extra else ""}'
346
+ f'</tr>')
347
+
348
+ html=f"""
349
+ <div style="background:linear-gradient(160deg,#0d1117 0%,#161b22 100%);
350
+ border:1px solid #21262d;border-radius:14px;padding:18px 16px;
351
+ font-family:'Courier New',monospace;color:#e6edf3;min-width:260px;">
352
+
353
+ <!-- Header -->
354
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;">
355
+ <div>
356
+ <span style="font-size:1.1em;font-weight:bold;color:#58a6ff">{label}</span>
357
+ <span style="margin-left:8px;font-size:.75em;color:#444;letter-spacing:1px">{interval} Β· OKX</span>
358
+ </div>
359
+ <div style="font-size:.7em;color:#30363d">{now}</div>
360
+ </div>
361
+
362
+ <!-- BΓΌyΓΌk sinyal kutusu -->
363
+ <div style="background:{bg};border:1px solid {dir_col}33;border-radius:10px;
364
+ padding:14px;text-align:center;margin-bottom:14px;">
365
+ <div style="font-size:1.6em;font-weight:bold;letter-spacing:2px">{signal}</div>
366
+ <div style="font-size:1.1em;color:{dir_col};margin-top:4px">{dir_txt}</div>
367
+ </div>
368
+
369
+ <!-- Güven çubuğu -->
370
+ <div style="margin-bottom:14px">
371
+ <div style="display:flex;justify-content:space-between;font-size:.75em;
372
+ color:#8b949e;margin-bottom:4px">
373
+ <span>GΓΌven Skoru</span><span style="color:#e6edf3;font-weight:bold">{final}%</span>
374
+ </div>
375
+ <div style="background:#21262d;border-radius:6px;overflow:hidden;height:10px">
376
+ <div style="background:linear-gradient(90deg,{bar_col},{bar_col}bb);
377
+ width:{final}%;height:100%;border-radius:6px;
378
+ box-shadow:0 0 8px {bar_col}66"></div>
379
+ </div>
380
+ <div style="display:flex;justify-content:space-between;font-size:.7em;
381
+ color:#484f58;margin-top:3px">
382
+ <span>πŸ”¬ Teknik: {tech_conf}%</span><span>πŸ€– AI: {ai_conf}%</span>
383
+ </div>
384
+ </div>
385
+
386
+ <!-- Tablo -->
387
+ <table style="width:100%;border-collapse:collapse;font-size:.88em">
388
+ {row("πŸ’° GΓΌncel Fiyat", f'<b>${price:,.6g}</b>')}
389
+ {row("24h Değişim", f'<span style="color:{chg_col}">{"β–²" if chg>=0 else "β–Ό"} {abs(chg):.2f}%</span>',
390
+ bg_tr="rgba(255,255,255,.025)")}
391
+ {row("24h Yüksek / Düşük", f'<span style="color:#00e676">{h24:,.6g}</span> / <span style="color:#ff5252">{l24:,.6g}</span>')}
392
+ {row("πŸ›‘ Stop Loss", f'<b style="color:#ff5252">${sl:,.6g}</b>',
393
+ bg_tr="rgba(255,82,82,.04)")}
394
+ {row("βœ… Take Profit", f'<b style="color:#00e676">${tp:,.6g}</b>',
395
+ bg_tr="rgba(0,200,83,.04)")}
396
+ {row("βš–οΈ Risk/Γ–dΓΌl", f'<b>{rr}x</b>')}
397
+ {row("πŸ“‰ RSI (14)", f'{rsi_v:.1f}', bg_tr="rgba(255,255,255,.025)")}
398
+ {row("πŸ“ ATR (14)", f'${atr_v:,.6g}')}
399
+ {row("EMA 20/50/200", f'{ema20:,.6g} / {ema50:,.6g} / {ema200:,.6g}',
400
+ bg_tr="rgba(255,255,255,.025)")}
401
+ {row("VWAP", f'${vwap_v:,.6g}')}
402
+ {row("24h Hacim", f'{vol24:,.0f}')}
403
+ </table>
404
+
405
+ <!-- Koşullar -->
406
+ <div style="margin-top:12px;padding:10px;background:#0d1117;border-radius:8px;
407
+ border:1px solid #1c2128;font-size:.72em;color:#8b949e;line-height:1.8">
408
+ <div style="color:#444;margin-bottom:4px;letter-spacing:1px">SİNYAL KOŞULLARI</div>
409
+ {cond_txt.replace(" ","&nbsp;&nbsp;")}
410
+ </div>
411
+
412
+ <p style="margin:12px 0 0;font-size:.65em;color:#30363d;text-align:center;letter-spacing:.5px">
413
+ ⚠️ Eğitim amaΓ§lΔ±dΔ±r β€” finansal tavsiye değildir. DYOR.
414
+ </p>
415
+ </div>"""
416
+ return html
417
+
418
+ # ──────────────────────────────────────────────────────────
419
+ # ANA ANALΔ°Z FONKSΔ°YONU
420
+ # ──────────────────────────────────────────────────────────
421
+ def analyze(label, interval):
422
+ # 1. Veri Γ§ek
423
+ try:
424
+ df_raw=fetch_okx(label, interval, limit=300)
425
+ except Exception as e:
426
+ err=f"<div style='color:#ff5252;font-family:monospace;padding:20px'>❌ OKX veri hatası:<br>{e}</div>"
427
+ return None, err
428
+
429
+ # 2. GΓΆstergeler
430
+ df=add_indicators(df_raw)
431
+ if len(df)<50:
432
+ return None,"<div style='color:#ff5252;font-family:monospace;padding:20px'>❌ Yeterli veri yok.</div>"
433
+
434
+ # 3. Sinyal
435
+ sig,tech_conf,sl,tp,rr,cond_txt=generate_signal(df)
436
+
437
+ # 4. AI
438
+ ai_conf=train_ai(df)
439
+
440
+ # 5. Ticker
441
+ try:
442
+ ticker=fetch_ticker(label)
443
+ except:
444
+ ticker={}
445
+
446
+ # 6. Grafik & Panel
447
+ fig=build_chart(df,label,interval,sig,sl,tp,ticker)
448
+ panel=build_panel(label,interval,sig,tech_conf,ai_conf,sl,tp,rr,cond_txt,ticker,df)
449
+ return fig, panel
450
+
451
+ # ──────────────────────────────────────────────────────────
452
+ # GRADIO UI
453
+ # ──────────────────────────────────────────────────────────
454
+ CSS="""
455
+ body,.gradio-container{background:#07070d !important;}
456
+ footer{display:none !important;}
457
+ .gr-button.primary{
458
+ background:linear-gradient(135deg,#1565c0,#4a148c) !important;
459
+ border:1px solid #42a5f566 !important;color:#fff !important;
460
+ font-family:'Courier New',monospace !important;letter-spacing:1px !important;
461
+ transition:all .2s !important;
462
+ }
463
+ .gr-button.primary:hover{
464
+ background:linear-gradient(135deg,#1976d2,#6a1b9a) !important;
465
+ box-shadow:0 0 16px #42a5f544 !important;
466
+ }
467
+ .gr-button{
468
+ background:#0f0f1a !important;border:1px solid #1e1e3f !important;
469
+ color:#8b949e !important;font-family:'Courier New',monospace !important;
470
+ }
471
+ select,input{background:#0d1117 !important;border:1px solid #21262d !important;
472
+ color:#e6edf3 !important;font-family:'Courier New',monospace !important;}
473
+ """
474
+
475
+ HEADER="""
476
+ <div style="background:linear-gradient(135deg,#07070d,#0d0d1a,#070712);
477
+ border:1px solid #1c1c3a;border-radius:16px;padding:24px 28px;
478
+ text-align:center;font-family:'Courier New',monospace;
479
+ margin-bottom:6px;position:relative;overflow:hidden;">
480
+ <div style="position:absolute;top:0;left:0;right:0;height:2px;
481
+ background:linear-gradient(90deg,transparent,#3d5afe,#00e5ff,#7c4dff,transparent)"></div>
482
+ <div style="position:absolute;bottom:0;left:0;right:0;height:1px;
483
+ background:linear-gradient(90deg,transparent,#1c2a4a,transparent)"></div>
484
+ <h1 style="margin:0 0 4px;font-size:1.75em;letter-spacing:5px;
485
+ background:linear-gradient(90deg,#3d5afe,#00e5ff,#7c4dff);
486
+ -webkit-background-clip:text;-webkit-text-fill-color:transparent;
487
+ background-clip:text;text-transform:uppercase;font-weight:900">
488
+ ⚑ CRYPTO SIGNAL PRO
489
+ </h1>
490
+ <p style="margin:0;color:#2a3550;letter-spacing:3px;font-size:.68em;text-transform:uppercase">
491
+ OKX REST API Β· XGBoost AI Β· CanlΔ± Otomatik Analiz
492
+ </p>
493
+ <div style="display:flex;justify-content:center;gap:18px;margin-top:10px;
494
+ font-size:.65em;color:#1c2a4a;letter-spacing:2px">
495
+ <span>EMA 20/50/200</span><span>Β·</span><span>RSI Β· MACD</span>
496
+ <span>Β·</span><span>VWAP Β· ATR</span><span>Β·</span><span>Volume Profile</span>
497
+ </div>
498
+ </div>"""
499
+
500
+ STATUS_TMPL="""
501
+ <div style="display:flex;align-items:center;gap:10px;padding:8px 14px;
502
+ background:#0d1117;border:1px solid #21262d;border-radius:8px;
503
+ font-family:'Courier New',monospace;font-size:.78em;color:#8b949e;">
504
+ <span style="width:8px;height:8px;border-radius:50%;background:{col};
505
+ box-shadow:0 0 6px {col};display:inline-block"></span>
506
+ {msg}
507
+ </div>"""
508
+
509
+ def make_status(msg,ok=True):
510
+ return STATUS_TMPL.format(col="#00e676" if ok else "#ff5252",msg=msg)
511
+
512
+ # Refresh count (hafΔ±za iΓ§in state)
513
+ _refresh_count = {"n": 0}
514
+
515
+ def run_and_status(label, interval):
516
+ _refresh_count["n"] += 1
517
+ n = _refresh_count["n"]
518
+ fig, panel = analyze(label, interval)
519
+ now = datetime.now(timezone.utc).strftime("%H:%M:%S UTC")
520
+ if fig is None:
521
+ st = make_status(f"#{n} · {now} ❌ Hata",ok=False)
522
+ else:
523
+ st = make_status(f"#{n} Β· {now} βœ… {label} / {interval} gΓΌncellendi")
524
+ return fig, panel, st
525
+
526
+ with gr.Blocks(css=CSS, title="⚑ Crypto Signal Pro · OKX") as demo:
527
+ gr.HTML(HEADER)
528
+
529
+ with gr.Row(equal_height=True):
530
+ sym = gr.Dropdown(choices=SYMBOLS_LABEL, value="BTCUSDT",
531
+ label="πŸ“Š Parite", scale=3, interactive=True)
532
+ ivl = gr.Dropdown(choices=INTERVALS, value="1H",
533
+ label="⏱ Zaman Dilimi", scale=2, interactive=True)
534
+ auto_cb = gr.Checkbox(value=True, label="πŸ”„ Otomatik Yenile", scale=1)
535
+ btn = gr.Button("πŸ” ANALΔ°Z ET", variant="primary", scale=2)
536
+
537
+ status_box = gr.HTML(make_status("HazΔ±r β€” Analiz Et butonuna bas veya otomatik yenilemeyi bekle."))
538
+
539
+ with gr.Row():
540
+ chart_out = gr.Plot(label="CanlΔ± Grafik", scale=3)
541
+ panel_out = gr.HTML(label="Sinyal Paneli", scale=1)
542
+
543
+ # Manuel buton
544
+ btn.click(fn=run_and_status,
545
+ inputs=[sym, ivl],
546
+ outputs=[chart_out, panel_out, status_box])
547
+
548
+ # Otomatik yenileme β€” gr.Timer (Gradio 4.x+)
549
+ # Her 30 saniyede bir tetiklenir; checkbox kapalΔ±ysa atlar
550
+ def auto_refresh(label, interval, enabled):
551
+ if not enabled:
552
+ return gr.update(), gr.update(), gr.update()
553
+ return run_and_status(label, interval)
554
+
555
+ timer = gr.Timer(value=30) # 30 sn
556
+ timer.tick(fn=auto_refresh,
557
+ inputs=[sym, ivl, auto_cb],
558
+ outputs=[chart_out, panel_out, status_box])
559
+
560
+ gr.HTML("""
561
+ <div style="text-align:center;padding:10px;color:#1c2a4a;
562
+ font-size:.62em;font-family:'Courier New',monospace;letter-spacing:1px">
563
+ CRYPTO SIGNAL PRO Β· OKX REST API Β· XGBoost AI Β· Plotly Β· Gradio<br>
564
+ ⚠️ YatΔ±rΔ±m tavsiyesi değildir β€” DYOR
565
+ </div>""")
566
+
567
+ if __name__ == "__main__":
568
+ demo.launch(server_name="0.0.0.0", server_port=7860)
requirements-27.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ requests
2
+ pandas
3
+ numpy
4
+ plotly
5
+ xgboost
6
+ scikit-learn