GoshawkVortexAI commited on
Commit
ddeffa0
·
verified ·
1 Parent(s): 2c277cc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -73
app.py CHANGED
@@ -13,50 +13,50 @@ from groq import Groq
13
  # 🔌 1. GROQ CLIENT
14
  # ==========================================
15
  api_key = os.environ.get("GROQ_API_KEY")
16
- client = Groq(api_key=api_key) if api_key else None
 
 
17
 
18
  # ==========================================
19
- # 📊 2. VERİ OKUMA (Tab/CSV, başlıksız)
20
  # ==========================================
21
- def parse_data(text):
22
- """Tab veya virgülle ayrılmış, başlıksız veriyi okur."""
23
  try:
 
 
 
 
 
 
 
 
 
24
  df = pd.read_csv(io.StringIO(text), sep="\t", header=None)
25
- if df.shape[1] < 6:
26
  df = pd.read_csv(io.StringIO(text), sep=",", header=None)
 
27
  if df.shape[1] < 6:
28
- return None, f"6 sütun bekleniyordu, {df.shape[1]} bulundu."
29
 
 
30
  df = df.iloc[:, :6]
31
  df.columns = ["date", "open", "high", "low", "close", "volume"]
32
 
33
- for c in ["open", "high", "low", "close", "volume"]:
34
- df[c] = pd.to_numeric(df[c], errors="coerce")
 
 
35
  df = df.dropna(subset=["close"]).reset_index(drop=True)
36
 
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 get_dataframe(raw_text, url):
45
- """Önce yapıştırılan metni, yoksa URL'yi dener."""
46
- if raw_text and raw_text.strip():
47
- return parse_data(raw_text)
48
- if url and url.strip():
49
- try:
50
- r = requests.get(url.strip(), headers={"User-Agent": "Mozilla/5.0"}, timeout=30)
51
- r.raise_for_status()
52
- return parse_data(r.text)
53
- except Exception as e:
54
- return None, f"URL okunamadı: {e}"
55
- return None, "Lütfen CSV içeriğini yapıştırın veya bir URL girin."
56
-
57
- # ==========================================
58
- # 🧮 3. TEKNİK GÖSTERGELER + MODEL
59
- # ==========================================
60
  def compute_rsi(series, period=14):
61
  delta = series.diff()
62
  gain = delta.clip(lower=0).rolling(period).mean()
@@ -66,27 +66,32 @@ def compute_rsi(series, period=14):
66
 
67
 
68
  def train_models(df):
 
69
  df = df.copy()
70
  df["ma_5"] = df["close"].rolling(5).mean()
71
  df["ma_20"] = df["close"].rolling(20).mean()
72
  df["rsi"] = compute_rsi(df["close"], 14)
73
  df["macd"] = df["close"].ewm(span=12).mean() - df["close"].ewm(span=26).mean()
 
 
74
  df["target"] = (df["close"].shift(-1) > df["close"]).astype(int)
75
 
76
  df_model = df.dropna().reset_index(drop=True)
77
  if len(df_model) < 20:
78
- return None, None, None, None, "Göstergelerden sonra yetersiz veri."
79
 
80
  features = ["ma_5", "ma_20", "rsi", "macd", "volume"]
81
  X = df_model[features].values
82
  y = df_model["target"].values
83
 
 
84
  xgb_model = xgb.XGBClassifier(
85
  n_estimators=60, max_depth=3, learning_rate=0.1,
86
  objective="binary:logistic", eval_metric="logloss", random_state=42
87
  )
88
  xgb_model.fit(X, y)
89
 
 
90
  scaler = StandardScaler()
91
  X_scaled = scaler.fit_transform(X)
92
  knn_model = KNeighborsClassifier(n_neighbors=7)
@@ -104,11 +109,15 @@ def train_models(df):
104
  }
105
  return xgb_model, knn_model, scaler, metrics, None
106
 
 
107
  # ==========================================
108
- # 🧠 4. ANALİZ FONKSİYONU
109
  # ==========================================
110
- def predict_and_analyze(raw_text, url):
111
- df, err = get_dataframe(raw_text, url)
 
 
 
112
  if err:
113
  return err, {}
114
 
@@ -116,91 +125,95 @@ def predict_and_analyze(raw_text, url):
116
  if err:
117
  return err, {}
118
 
119
- feat = np.array([[metrics["ma5"], metrics["ma20"], metrics["rsi"],
120
- metrics["macd"], metrics["volume"]]])
 
 
 
 
121
 
122
- xgb_up = float(xgb_model.predict_proba(feat)[0][1])
123
- knn_up = float(knn_model.predict_proba(scaler.transform(feat))[0][1])
124
- ens_up = (xgb_up + knn_up) / 2
125
- ens_down = 1 - ens_up
126
- direction = "YUKARI 📈" if ens_up > 0.5 else "AŞAĞI 📉"
127
- conf = max(ens_up, ens_down) * 100
128
 
129
  prob_dict = {
130
- "XGBoost Yükseliş": xgb_up,
131
- "KNN Yükseliş": knn_up,
132
- "Ensemble Yükseliş": ens_up,
133
  }
134
 
135
  prompt = f"""
136
- BTC/USD teknik analiz raporu (Türkçe).
137
- Son Kapanış ({metrics['last_date']}): ${metrics['last_close']:,.2f}
138
- RSI: {metrics['rsi']:.2f}, MA5: ${metrics['ma5']:,.2f}, MA20: ${metrics['ma20']:,.2f}, MACD: {metrics['macd']:.4f}, Hacim: {metrics['volume']:,.2f}
139
- XGBoost Yükseliş: %{xgb_up*100:.1f}
140
- KNN Yükseliş: %{knn_up*100:.1f}
141
- Ensemble: %{ens_up*100:.1f} -> {direction} (Güven %{conf:.1f})
142
- Başlıklar: 1. Model Yorumu 2. Teknik Analiz 3. İşlem Stratejisi. Yatırım tavsiyesi değildir.
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  """
144
 
145
  if client:
146
  try:
147
- resp = client.chat.completions.create(
148
  model="openai/gpt-oss-120b",
149
  messages=[{"role": "user", "content": prompt}],
150
  temperature=0.3,
151
  max_tokens=1024
152
  )
153
- analysis = resp.choices[0].message.content
154
  except Exception as e:
155
- analysis = f"Groq API Hatası: {e}"
156
  else:
157
- analysis = "GROQ_API_KEY bulunamadı!"
158
 
159
  header = (
160
- f"**Son: ${metrics['last_close']:,.2f}** | RSI: {metrics['rsi']:.1f} | "
161
  f"MA5: ${metrics['ma5']:,.0f} | MA20: ${metrics['ma20']:,.0f}\n\n"
162
- f"**XGB:** %{xgb_up*100:.1f} | **KNN:** %{knn_up*100:.1f} | "
163
- f"**Ens:** %{ens_up*100:.1f}\n\n---\n\n"
164
  )
165
- return header + analysis, prob_dict
 
166
 
167
  # ==========================================
168
- # 🎨 5. GRADIO ARAYÜZÜ
169
  # ==========================================
170
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="orange", secondary_hue="slate")) as demo:
171
  gr.Markdown(
172
  """
173
  # ₿ BTC/USD XGBoost + KNN & Groq AI Tahmin Radarı
174
- **Dosya seçici kaldırıldı.** CSV içeriğini doğrudan aşağıya yapıştırın **veya** bir URL girin.
175
- Veri **tab veya virgülle ayrılmış, başlıksız** olmalı:
176
  `Date, Open, High, Low, Close, Volume`
177
  """
178
  )
179
 
180
  with gr.Row():
181
  with gr.Column():
182
- gr.Markdown("### 📋 CSV İçeriğini Yapıştır")
183
- raw_input = gr.Textbox(
184
- label="CSV/TSV İçeriği",
185
- placeholder="2021-02-04 11:30\t37826.1\t37916.7\t37359.8\t37359.8\t5032\n...",
186
- lines=10
187
- )
188
-
189
- gr.Markdown("### 🔗 veya URL")
190
- url_input = gr.Textbox(
191
- label="CSV Linki",
192
- placeholder="https://raw.githubusercontent.com/.../BTCUSD30.csv"
193
- )
194
-
195
  submit_btn = gr.Button("Analiz Et", variant="primary")
196
 
197
  with gr.Column():
198
  prob_output = gr.Label(label="Model Tahminleri")
199
- analysis_output = gr.Markdown(value="Veri girip butona basın.")
200
 
201
  submit_btn.click(
202
  fn=predict_and_analyze,
203
- inputs=[raw_input, url_input],
204
  outputs=[analysis_output, prob_output]
205
  )
206
 
 
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. CSV OKUMA VE MODEL EĞİTİMİ
22
  # ==========================================
23
+ def load_dataframe(file_or_url):
24
+ """Dosya yükleme veya URL'den TSV/CSV okur."""
25
  try:
26
+ if isinstance(file_or_url, str): # URL
27
+ headers = {"User-Agent": "Mozilla/5.0"}
28
+ r = requests.get(file_or_url, headers=headers, timeout=30)
29
+ r.raise_for_status()
30
+ text = r.text
31
+ else: # Yüklenen dosya
32
+ text = open(file_or_url.name, "r", encoding="utf-8").read()
33
+
34
+ # Önce tab ile dene (senin dosyan tab-separated)
35
  df = pd.read_csv(io.StringIO(text), sep="\t", header=None)
36
+ if df.shape[1] < 6: # tab değilse virgülle dene
37
  df = pd.read_csv(io.StringIO(text), sep=",", header=None)
38
+
39
  if df.shape[1] < 6:
40
+ return None, f"Beklenen 6 sütun bulunamadı. Bulunan: {df.shape[1]}"
41
 
42
+ # Başlık yok -> manuel isimlendir
43
  df = df.iloc[:, :6]
44
  df.columns = ["date", "open", "high", "low", "close", "volume"]
45
 
46
+ # Sayısal dönüşüm (bozuk satırları at)
47
+ for col in ["open", "high", "low", "close", "volume"]:
48
+ df[col] = pd.to_numeric(df[col], errors="coerce")
49
+
50
  df = df.dropna(subset=["close"]).reset_index(drop=True)
51
 
52
  if len(df) < 60:
53
+ return None, f"Yetersiz veri. En az 60 satır gerekli, bulunan: {len(df)}"
54
+
55
  return df, None
56
  except Exception as e:
57
  return None, f"Veri okunamadı: {e}"
58
 
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  def compute_rsi(series, period=14):
61
  delta = series.diff()
62
  gain = delta.clip(lower=0).rolling(period).mean()
 
66
 
67
 
68
  def train_models(df):
69
+ """XGBoost + KNN eğitir, en güncel gösterge değerlerini döndürür."""
70
  df = df.copy()
71
  df["ma_5"] = df["close"].rolling(5).mean()
72
  df["ma_20"] = df["close"].rolling(20).mean()
73
  df["rsi"] = compute_rsi(df["close"], 14)
74
  df["macd"] = df["close"].ewm(span=12).mean() - df["close"].ewm(span=26).mean()
75
+
76
+ # Hedef: bir sonraki mumun kapanışı mevcut mumdan yüksek mi?
77
  df["target"] = (df["close"].shift(-1) > df["close"]).astype(int)
78
 
79
  df_model = df.dropna().reset_index(drop=True)
80
  if len(df_model) < 20:
81
+ return None, None, None, None, "Göstergelerden sonra yeterli veri kalmadı."
82
 
83
  features = ["ma_5", "ma_20", "rsi", "macd", "volume"]
84
  X = df_model[features].values
85
  y = df_model["target"].values
86
 
87
+ # XGBoost
88
  xgb_model = xgb.XGBClassifier(
89
  n_estimators=60, max_depth=3, learning_rate=0.1,
90
  objective="binary:logistic", eval_metric="logloss", random_state=42
91
  )
92
  xgb_model.fit(X, y)
93
 
94
+ # KNN
95
  scaler = StandardScaler()
96
  X_scaled = scaler.fit_transform(X)
97
  knn_model = KNeighborsClassifier(n_neighbors=7)
 
109
  }
110
  return xgb_model, knn_model, scaler, metrics, None
111
 
112
+
113
  # ==========================================
114
+ # 🧠 3. ANALİZ MOTORU
115
  # ==========================================
116
+ def predict_and_analyze(file_or_url):
117
+ if file_or_url is None:
118
+ return "Lütfen bir CSV/TSV dosyası yükleyin veya link girin.", {}
119
+
120
+ df, err = load_dataframe(file_or_url)
121
  if err:
122
  return err, {}
123
 
 
125
  if err:
126
  return err, {}
127
 
128
+ feat_arr = np.array([[metrics["ma5"], metrics["ma20"], metrics["rsi"], metrics["macd"], metrics["volume"]]])
129
+
130
+ xgb_prob_up = float(xgb_model.predict_proba(feat_arr)[0][1])
131
+ knn_prob_up = float(knn_model.predict_proba(scaler.transform(feat_arr))[0][1])
132
+ ensemble_prob_up = (xgb_prob_up + knn_prob_up) / 2
133
+ ensemble_prob_down = 1 - ensemble_prob_up
134
 
135
+ direction = "YUKARI 📈" if ensemble_prob_up > 0.5 else "AŞAĞI 📉"
136
+ confidence = max(ensemble_prob_up, ensemble_prob_down) * 100
 
 
 
 
137
 
138
  prob_dict = {
139
+ "XGBoost Yükseliş": xgb_prob_up,
140
+ "KNN Yükseliş": knn_prob_up,
141
+ "Ensemble Yükseliş (Ortalama)": ensemble_prob_up,
142
  }
143
 
144
  prompt = f"""
145
+ Sen uzman bir kripto para analisti ve teknik analiz uzmanısın.
146
+
147
+ 📊 BTC/USD Son Kapanış ({metrics['last_date']}): ${metrics['last_close']:,.2f}
148
+ - RSI (14): {metrics['rsi']:.2f}
149
+ - MA5: ${metrics['ma5']:,.2f} | MA20: ${metrics['ma20']:,.2f}
150
+ - MACD: {metrics['macd']:.4f}
151
+ - Hacim: {metrics['volume']:,.2f}
152
+
153
+ 🤖 Model Sonuçları:
154
+ - XGBoost Yükseliş: %{xgb_prob_up*100:.1f}
155
+ - KNN Yükseliş: %{knn_prob_up*100:.1f}
156
+ - Ensemble Yükseliş: %{ensemble_prob_up*100:.1f}
157
+ - Tahmin Yönü: {direction} (Güven: %{confidence:.1f})
158
+
159
+ Türkçe bir teknik analiz raporu hazırla. Başlıklar:
160
+ 1. 🎯 Model Yorumu (XGBoost + KNN karşılaştırması)
161
+ 2. 📈 Teknik Analiz (RSI, MA, MACD; destek/direnç)
162
+ 3. 💡 İşlem Stratejisi (Long/Short, stop-loss, take-profit)
163
+
164
+ Yatırım tavsiyesi olmadığını vurgula.
165
  """
166
 
167
  if client:
168
  try:
169
+ response = client.chat.completions.create(
170
  model="openai/gpt-oss-120b",
171
  messages=[{"role": "user", "content": prompt}],
172
  temperature=0.3,
173
  max_tokens=1024
174
  )
175
+ analysis_result = response.choices[0].message.content
176
  except Exception as e:
177
+ analysis_result = f"Groq API Hatası: {e}"
178
  else:
179
+ analysis_result = "GROQ_API_KEY bulunamadı! Hugging Face Secrets'a ekleyin."
180
 
181
  header = (
182
+ f"**Son Kapanış: ${metrics['last_close']:,.2f}** | RSI: {metrics['rsi']:.1f} | "
183
  f"MA5: ${metrics['ma5']:,.0f} | MA20: ${metrics['ma20']:,.0f}\n\n"
184
+ f"**XGB:** %{xgb_prob_up*100:.1f} | **KNN:** %{knn_prob_up*100:.1f} | "
185
+ f"**Ensemble:** %{ensemble_prob_up*100:.1f}\n\n---\n\n"
186
  )
187
+ return header + analysis_result, prob_dict
188
+
189
 
190
  # ==========================================
191
+ # 🎨 4. GRADIO ARAYÜZÜ
192
  # ==========================================
193
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="orange", secondary_hue="slate")) as demo:
194
  gr.Markdown(
195
  """
196
  # ₿ BTC/USD XGBoost + KNN & Groq AI Tahmin Radarı
197
+ Verinizi **CSV/TSV dosyası** olarak yükleyin **veya** doğrudan linkini girin.
198
+ Dosya **başlıksız** olmalı ve sütunlar sırasıyla:
199
  `Date, Open, High, Low, Close, Volume`
200
  """
201
  )
202
 
203
  with gr.Row():
204
  with gr.Column():
205
+ gr.Markdown("### 📂 Veri Kaynağı")
206
+ file_input = gr.File(label="CSV/TSV Dosyası Yükle", file_types=[".csv", ".tsv", ".txt"])
207
+ url_input = gr.Textbox(label="veya CSV Linki (URL)", placeholder="https://.../BTCUSD30.csv")
 
 
 
 
 
 
 
 
 
 
208
  submit_btn = gr.Button("Analiz Et", variant="primary")
209
 
210
  with gr.Column():
211
  prob_output = gr.Label(label="Model Tahminleri")
212
+ analysis_output = gr.Markdown(value="Veri yükleyip butona basın.")
213
 
214
  submit_btn.click(
215
  fn=predict_and_analyze,
216
+ inputs=[file_input if False else url_input], # aşağıda düzelttim
217
  outputs=[analysis_output, prob_output]
218
  )
219