GoshawkVortexAI commited on
Commit
8bfd54f
·
verified ·
1 Parent(s): 92e88cb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +94 -173
app.py CHANGED
@@ -1,5 +1,5 @@
1
  import os
2
- import time
3
  import requests
4
  import numpy as np
5
  import pandas as pd
@@ -9,81 +9,38 @@ from sklearn.neighbors import KNeighborsClassifier
9
  from sklearn.preprocessing import StandardScaler
10
  from groq import Groq
11
 
12
- # ==========================================
13
- # 🔌 1. GROQ CLIENT
14
- # ==========================================
15
  api_key = os.environ.get("GROQ_API_KEY")
16
- client = None
17
- if api_key:
18
- client = Groq(api_key=api_key)
19
-
20
- # ==========================================
21
- # 📡 2. OKX PUBLIC API (openapi alan adı)
22
- # ==========================================
23
- # HF'de www.okx.com engellenmiş olabilir; openapi.okx.com küresel REST alan adıdır
24
- OKX_BASE = "https://openapi.okx.com"
25
-
26
- # Cloudflare istemci imzası engellemesini aşmak için tarayıcı benzeri başlıklar
27
- OKX_HEADERS = {
28
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
29
- "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
30
- "Accept": "application/json",
31
- "Accept-Language": "en-US,en;q=0.9",
32
- }
33
-
34
- def fetch_okx_ticker(inst_id="BTC-USDT"):
35
- """OKX anlık fiyat. 3 kez dener."""
36
- for attempt in range(3):
37
- try:
38
- r = requests.get(
39
- f"{OKX_BASE}/api/v5/market/ticker",
40
- params={"instId": inst_id},
41
- headers=OKX_HEADERS,
42
- timeout=15
43
- )
44
- r.raise_for_status()
45
- d = r.json()["data"][0]
46
- return {
47
- "last": float(d["last"]),
48
- "open24h": float(d["open24h"]),
49
- "high24h": float(d["high24h"]),
50
- "low24h": float(d["low24h"]),
51
- "vol24h": float(d["vol24h"]),
52
- "change_pct": (float(d["last"]) / float(d["open24h"]) - 1) * 100,
53
- }
54
- except Exception as e:
55
- print(f"OKX ticker attempt {attempt+1} failed: {e}")
56
- if attempt < 2:
57
- time.sleep(2)
58
- return None
59
-
60
- def fetch_okx_candles(inst_id="BTC-USDT", bar="1H", limit=100):
61
- """OKX mum verisi. 3 kez dener."""
62
- for attempt in range(3):
63
- try:
64
- r = requests.get(
65
- f"{OKX_BASE}/api/v5/market/candles",
66
- params={"instId": inst_id, "bar": bar, "limit": limit},
67
- headers=OKX_HEADERS,
68
- timeout=15
69
- )
70
  r.raise_for_status()
71
- raw = r.json()["data"]
72
- # OKX formatı: [ts, open, high, low, close, vol, ...]
73
- df = pd.DataFrame(raw, columns=["ts", "open", "high", "low", "close", "vol"])
74
- for col in ["open", "high", "low", "close", "vol"]:
75
- df[col] = df[col].astype(float)
76
- df["ts"] = pd.to_datetime(df["ts"].astype(int), unit="ms")
77
- return df.sort_values("ts").reset_index(drop=True)
78
- except Exception as e:
79
- print(f"OKX candles attempt {attempt+1} failed: {e}")
80
- if attempt < 2:
81
- time.sleep(2)
82
- return None
83
-
84
- # ==========================================
85
- # 📊 3. YARDIMCI FONKSİYONLAR
86
- # ==========================================
 
 
 
 
 
 
 
 
87
  def compute_rsi(series, period=14):
88
  delta = series.diff()
89
  gain = delta.clip(lower=0).rolling(period).mean()
@@ -91,158 +48,122 @@ def compute_rsi(series, period=14):
91
  rs = gain / loss
92
  return 100 - (100 / (1 + rs))
93
 
94
- def train_models_from_okx():
95
- """OKX mum verisiyle XGBoost ve KNN eğitir."""
96
- df = fetch_okx_candles(limit=500)
97
- if df is None or len(df) < 50:
98
- return None, None, None, None
99
 
 
 
100
  df["ma_5"] = df["close"].rolling(5).mean()
101
  df["ma_20"] = df["close"].rolling(20).mean()
102
  df["rsi"] = compute_rsi(df["close"], 14)
103
  df["macd"] = df["close"].ewm(span=12).mean() - df["close"].ewm(span=26).mean()
104
  df["target"] = (df["close"].shift(-1) > df["close"]).astype(int)
105
  df_model = df.dropna().reset_index(drop=True)
106
-
107
  if len(df_model) < 20:
108
- return None, None, None, None
109
 
110
- features = ["ma_5", "ma_20", "rsi", "macd", "vol"]
111
  X = df_model[features].values
112
  y = df_model["target"].values
113
 
114
  xgb_model = xgb.XGBClassifier(
115
- n_estimators=50, max_depth=3, learning_rate=0.1,
116
  objective="binary:logistic", eval_metric="logloss", random_state=42
117
  )
118
  xgb_model.fit(X, y)
119
 
120
  scaler = StandardScaler()
121
  X_scaled = scaler.fit_transform(X)
122
- knn_model = KNeighborsClassifier(n_neighbors=5)
123
  knn_model.fit(X_scaled, y)
124
 
125
- return xgb_model, knn_model, scaler, features
126
-
127
- # Başlangıçta modelleri OKX verisiyle eğit
128
- xgb_model, knn_model, scaler, feature_cols = train_models_from_okx()
129
-
130
- if xgb_model is None:
131
- print("OKX erişilemedi, dummy modeller kullanılıyor.")
132
- dummy_X = np.random.rand(50, 5)
133
- dummy_y = np.random.randint(0, 2, 50)
134
- xgb_model = xgb.XGBClassifier(n_estimators=10, max_depth=2)
135
- xgb_model.fit(dummy_X, dummy_y)
136
- scaler = StandardScaler()
137
- knn_model = KNeighborsClassifier(n_neighbors=5)
138
- knn_model.fit(scaler.fit_transform(dummy_X), dummy_y)
139
- feature_cols = ["ma_5", "ma_20", "rsi", "macd", "vol"]
140
-
141
- # ==========================================
142
- # 🧠 4. ANALİZ MOTORU (XGB + KNN Ensemble)
143
- # ==========================================
144
- def predict_and_analyze():
145
- ticker = fetch_okx_ticker()
146
- candles = fetch_okx_candles(limit=30)
147
-
148
- if ticker is None or candles is None:
149
- return "❌ OKX API'sine erişilemedi (openapi alan adı + tarayıcı UA denendi). Lütfen sonra tekrar deneyin.", {}
150
-
151
- last_price = ticker["last"]
152
- change_pct = ticker["change_pct"]
153
- vol24h = ticker["vol24h"]
154
 
155
- close = candles["close"]
156
- ma5 = close.rolling(5).mean().iloc[-1]
157
- ma20 = close.rolling(20).mean().iloc[-1]
158
- rsi = compute_rsi(close, 14).iloc[-1]
159
- macd = (close.ewm(span=12).mean() - close.ewm(span=26).mean()).iloc[-1]
160
 
161
- feat_arr = np.array([[ma5, ma20, rsi, macd, vol24h]])
 
 
 
162
 
163
- xgb_prob_up = float(xgb_model.predict_proba(feat_arr)[0][1])
164
- knn_prob_up = float(knn_model.predict_proba(scaler.transform(feat_arr))[0][1])
 
165
 
166
- ensemble_prob_up = (xgb_prob_up + knn_prob_up) / 2
167
- ensemble_prob_down = 1 - ensemble_prob_up
168
- direction = "YUKARI 📈" if ensemble_prob_up > 0.5 else "AŞAĞI 📉"
169
- confidence = max(ensemble_prob_up, ensemble_prob_down) * 100
 
 
 
170
 
171
  prob_dict = {
172
- "XGBoost Yükseliş": xgb_prob_up,
173
- "KNN Yükseliş": knn_prob_up,
174
- "Ensemble Yükseliş (Ortalama)": ensemble_prob_up,
175
  }
176
 
177
  prompt = f"""
178
- Sen uzman bir kripto para analisti ve teknik analiz uzmanısın.
179
-
180
- 📡 OKX Canlı Verileri (BTC/USDT):
181
- - Son Fiyat: ${last_price:,.2f}
182
- - 24s Değişim: %{change_pct:+.2f}
183
- - 24s Hacim: {vol24h:,.0f} BTC
184
- - 24s Yüksek/Düşük: ${ticker['high24h']:,.2f} / ${ticker['low24h']:,.2f}
185
-
186
- 📊 Teknik Göstergeler (1H):
187
- - RSI (14): {rsi:.2f}
188
- - MA5: ${ma5:,.2f} | MA20: ${ma20:,.2f}
189
- - MACD: {macd:.4f}
190
-
191
- 🤖 Model Sonuçları:
192
- - XGBoost Yükseliş: %{xgb_prob_up*100:.1f}
193
- - KNN Yükseliş: %{knn_prob_up*100:.1f}
194
- - Ensemble Yükseliş: %{ensemble_prob_up*100:.1f}
195
- - Tahmin Yönü: {direction} (Güven: %{confidence:.1f})
196
-
197
- Türkçe bir teknik analiz raporu hazırla. Başlıklar:
198
- 1. 🎯 Model Yorumu (XGBoost + KNN karşılaştırması)
199
- 2. 📈 Teknik Analiz (RSI, MA, MACD; destek/direnç)
200
- 3. 💡 İşlem Stratejisi (Long/Short, stop-loss, take-profit)
201
-
202
- Yatırım tavsiyesi olmadığını vurgula.
203
  """
204
 
205
  if client:
206
  try:
207
- response = client.chat.completions.create(
208
  model="openai/gpt-oss-120b",
209
  messages=[{"role": "user", "content": prompt}],
210
  temperature=0.3,
211
  max_tokens=1024
212
  )
213
- analysis_result = response.choices[0].message.content
214
  except Exception as e:
215
- analysis_result = f"Groq API Hatası: {e}"
216
  else:
217
- analysis_result = "GROQ_API_KEY bulunamadı! Hugging Face Secrets'a ekleyin."
218
 
219
  header = (
220
- f"**OKX Canlı: ${last_price:,.2f}** (%{change_pct:+.2f}) | RSI: {rsi:.1f} | "
221
- f"MA5: ${ma5:,.0f} | MA20: ${ma20:,.0f}\n\n"
222
- f"**XGB:** %{xgb_prob_up*100:.1f} | **KNN:** %{knn_prob_up*100:.1f} | "
223
- f"**Ensemble:** %{ensemble_prob_up*100:.1f}\n\n---\n\n"
224
  )
225
- return header + analysis_result, prob_dict
 
226
 
227
- # ==========================================
228
- # 🎨 5. GRADIO ARAYÜZÜ
229
- # ==========================================
230
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="orange", secondary_hue="slate")) as demo:
231
  gr.Markdown(
232
  """
233
- # ₿ BTC/USD XGBoost + KNN & Groq AI Tahmin Radarı (OKX Canlı)
234
- Fiyat ve mum verileri **OKX halka açık API**'sinden (`openapi.okx.com`) otomatik çekilir. **XGBoost + KNN** ensemble tahmini yapar, **Groq** analiz raporu üretir.
235
  """
236
  )
237
  with gr.Row():
238
  with gr.Column():
239
- analyze_btn = gr.Button("🔄 OKX'ten Veri Çek ve Analiz Et", variant="primary", size="lg")
240
- gr.Markdown("**Not**: `openapi.okx.com` + tarayıcı UA + 3 deneme kullanılıyor.")
 
241
  with gr.Column():
242
- prob_output = gr.Label(label="Model Tahminleri (XGB + KNN)")
243
- analysis_output = gr.Markdown(value="Butona basarak OKX'ten canlı veri çekip analizi başlatın.")
244
- analyze_btn.click(fn=predict_and_analyze, inputs=[], outputs=[analysis_output, prob_output])
245
- gr.Markdown("---\n⚠️ **Yatırım Tavsiyesi Değildir**: Bu uygulama eğitim amaçlıdır.")
 
 
 
 
246
 
247
  if __name__ == "__main__":
248
  demo.launch()
 
1
  import os
2
+ import io
3
  import requests
4
  import numpy as np
5
  import pandas as pd
 
9
  from sklearn.preprocessing import StandardScaler
10
  from groq import Groq
11
 
 
 
 
12
  api_key = os.environ.get("GROQ_API_KEY")
13
+ client = Groq(api_key=api_key) if api_key else None
14
+
15
+ def load_dataframe(file_obj, url):
16
+ try:
17
+ if url and url.strip():
18
+ r = requests.get(url.strip(), headers={"User-Agent": "Mozilla/5.0"}, timeout=30)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  r.raise_for_status()
20
+ text = r.text
21
+ elif file_obj is not None:
22
+ text = open(file_obj.name, "r", encoding="utf-8", errors="ignore").read()
23
+ else:
24
+ return None, "Lütfen dosya yükleyin veya link girin."
25
+
26
+ df = pd.read_csv(io.StringIO(text), sep="\t", header=None)
27
+ if df.shape[1] < 6:
28
+ df = pd.read_csv(io.StringIO(text), sep=",", header=None)
29
+ if df.shape[1] < 6:
30
+ return None, f"6 sütun bekleniyordu, {df.shape[1]} bulundu."
31
+
32
+ df = df.iloc[:, :6]
33
+ df.columns = ["date", "open", "high", "low", "close", "volume"]
34
+ for c in ["open", "high", "low", "close", "volume"]:
35
+ df[c] = pd.to_numeric(df[c], errors="coerce")
36
+ df = df.dropna(subset=["close"]).reset_index(drop=True)
37
+ if len(df) < 60:
38
+ return None, f"En az 60 satır gerekli, {len(df)} var."
39
+ return df, None
40
+ except Exception as e:
41
+ return None, f"Veri okunamadı: {e}"
42
+
43
+
44
  def compute_rsi(series, period=14):
45
  delta = series.diff()
46
  gain = delta.clip(lower=0).rolling(period).mean()
 
48
  rs = gain / loss
49
  return 100 - (100 / (1 + rs))
50
 
 
 
 
 
 
51
 
52
+ def train_models(df):
53
+ df = df.copy()
54
  df["ma_5"] = df["close"].rolling(5).mean()
55
  df["ma_20"] = df["close"].rolling(20).mean()
56
  df["rsi"] = compute_rsi(df["close"], 14)
57
  df["macd"] = df["close"].ewm(span=12).mean() - df["close"].ewm(span=26).mean()
58
  df["target"] = (df["close"].shift(-1) > df["close"]).astype(int)
59
  df_model = df.dropna().reset_index(drop=True)
 
60
  if len(df_model) < 20:
61
+ return None, None, None, None, "Yetersiz veri."
62
 
63
+ features = ["ma_5", "ma_20", "rsi", "macd", "volume"]
64
  X = df_model[features].values
65
  y = df_model["target"].values
66
 
67
  xgb_model = xgb.XGBClassifier(
68
+ n_estimators=60, max_depth=3, learning_rate=0.1,
69
  objective="binary:logistic", eval_metric="logloss", random_state=42
70
  )
71
  xgb_model.fit(X, y)
72
 
73
  scaler = StandardScaler()
74
  X_scaled = scaler.fit_transform(X)
75
+ knn_model = KNeighborsClassifier(n_neighbors=7)
76
  knn_model.fit(X_scaled, y)
77
 
78
+ latest = df_model.iloc[-1]
79
+ metrics = {
80
+ "last_close": float(latest["close"]),
81
+ "last_date": str(latest["date"]),
82
+ "ma5": float(latest["ma_5"]),
83
+ "ma20": float(latest["ma_20"]),
84
+ "rsi": float(latest["rsi"]),
85
+ "macd": float(latest["macd"]),
86
+ "volume": float(latest["volume"]),
87
+ }
88
+ return xgb_model, knn_model, scaler, metrics, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
 
 
 
 
 
90
 
91
+ def predict_and_analyze(file_obj, url):
92
+ df, err = load_dataframe(file_obj, url)
93
+ if err:
94
+ return err, {}
95
 
96
+ xgb_model, knn_model, scaler, metrics, err = train_models(df)
97
+ if err:
98
+ return err, {}
99
 
100
+ feat = np.array([[metrics["ma5"], metrics["ma20"], metrics["rsi"], metrics["macd"], metrics["volume"]]])
101
+ xgb_up = float(xgb_model.predict_proba(feat)[0][1])
102
+ knn_up = float(knn_model.predict_proba(scaler.transform(feat))[0][1])
103
+ ens_up = (xgb_up + knn_up) / 2
104
+ ens_down = 1 - ens_up
105
+ direction = "YUKARI 📈" if ens_up > 0.5 else "AŞAĞI 📉"
106
+ conf = max(ens_up, ens_down) * 100
107
 
108
  prob_dict = {
109
+ "XGBoost Yükseliş": xgb_up,
110
+ "KNN Yükseliş": knn_up,
111
+ "Ensemble Yükseliş": ens_up,
112
  }
113
 
114
  prompt = f"""
115
+ BTC/USD teknik analiz raporu (Türkçe).
116
+ Son Kapanış ({metrics['last_date']}): ${metrics['last_close']:,.2f}
117
+ RSI: {metrics['rsi']:.2f}, MA5: ${metrics['ma5']:,.2f}, MA20: ${metrics['ma20']:,.2f}, MACD: {metrics['macd']:.4f}, Hacim: {metrics['volume']:,.2f}
118
+ XGBoost Yükseliş: %{xgb_up*100:.1f}
119
+ KNN Yükseliş: %{knn_up*100:.1f}
120
+ Ensemble: %{ens_up*100:.1f} -> {direction} (Güven %{conf:.1f})
121
+ Başlıklar: 1. Model Yorumu 2. Teknik Analiz 3. İşlem Stratejisi. Yatırım tavsiyesi değildir.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  """
123
 
124
  if client:
125
  try:
126
+ resp = client.chat.completions.create(
127
  model="openai/gpt-oss-120b",
128
  messages=[{"role": "user", "content": prompt}],
129
  temperature=0.3,
130
  max_tokens=1024
131
  )
132
+ analysis = resp.choices[0].message.content
133
  except Exception as e:
134
+ analysis = f"Groq API Hatası: {e}"
135
  else:
136
+ analysis = "GROQ_API_KEY bulunamadı!"
137
 
138
  header = (
139
+ f"**Son: ${metrics['last_close']:,.2f}** | RSI: {metrics['rsi']:.1f} | "
140
+ f"MA5: ${metrics['ma5']:,.0f} | MA20: ${metrics['ma20']:,.0f}\n\n"
141
+ f"**XGB:** %{xgb_up*100:.1f} | **KNN:** %{knn_up*100:.1f} | **Ens:** %{ens_up*100:.1f}\n\n---\n\n"
 
142
  )
143
+ return header + analysis, prob_dict
144
+
145
 
 
 
 
146
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="orange", secondary_hue="slate")) as demo:
147
  gr.Markdown(
148
  """
149
+ # ₿ BTC/USD XGBoost + KNN & Groq AI Tahmin Radarı
150
+ **Başlıksız** TSV/CSV yükleyin (Date, Open, High, Low, Close, Volume) **veya** link girin.
151
  """
152
  )
153
  with gr.Row():
154
  with gr.Column():
155
+ file_input = gr.File(label="Dosya Yükle (.csv / .tsv / .txt)", file_types=[".csv", ".tsv", ".txt"])
156
+ url_input = gr.Textbox(label="veya Link (URL)", placeholder="https://.../BTCUSD30.csv")
157
+ submit_btn = gr.Button("Analiz Et", variant="primary")
158
  with gr.Column():
159
+ prob_output = gr.Label(label="Model Tahminleri")
160
+ analysis_output = gr.Markdown(value="Veri yükleyip butona basın.")
161
+
162
+ submit_btn.click(
163
+ fn=predict_and_analyze,
164
+ inputs=[file_input, url_input],
165
+ outputs=[analysis_output, prob_output]
166
+ )
167
 
168
  if __name__ == "__main__":
169
  demo.launch()