GoshawkVortexAI commited on
Commit
fd1e967
·
verified ·
1 Parent(s): 347e5a5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -29
app.py CHANGED
@@ -37,7 +37,6 @@ CITIES = [
37
  "Caerleon",
38
  ]
39
 
40
- # 100 popüler ürün (T4-T6 kaynaklar, ekipmanlar, tüketim malları)
41
  _ITEM_POOL = [
42
  "T4_BAG", "T5_BAG", "T6_BAG", "T7_BAG", "T8_BAG",
43
  "T4_CAPE", "T5_CAPE", "T6_CAPE", "T7_CAPE", "T8_CAPE",
@@ -79,9 +78,11 @@ _ITEM_POOL = [
79
  ]
80
  ITEM_IDS = list(dict.fromkeys(_ITEM_POOL))[:100]
81
 
 
82
  def item_display_name(item_id: str) -> str:
83
  return item_id.replace("_", " ").title()
84
 
 
85
  SETUP_FEE_RATE = 0.025 # %2.5 listeleme ücreti
86
  TRANSACTION_TAX_RATE = 0.08 # %8 satış vergisi (Premium olmayan varsayılan)
87
 
@@ -103,6 +104,7 @@ RETRY_BACKOFF = 2
103
  # YARDIMCI FONKSİYONLAR
104
  # ---------------------------------------------------------------------------
105
 
 
106
  def safe_request(url: str, params: Optional[dict] = None) -> Optional[list]:
107
  for attempt in range(MAX_RETRIES):
108
  try:
@@ -207,6 +209,7 @@ def save_to_csv(df: pd.DataFrame, name: str) -> str:
207
  # FEATURE ENGINEERING
208
  # ---------------------------------------------------------------------------
209
 
 
210
  def compute_rsi(series: pd.Series, period: int = 14) -> pd.Series:
211
  delta = series.diff()
212
  gain = delta.clip(lower=0).rolling(period).mean()
@@ -350,7 +353,7 @@ def predict_24h_returns(model: lgb.LGBMRegressor, latest_features: pd.DataFrame)
350
  return pd.DataFrame()
351
 
352
  preds = model.predict(X_pred)
353
- result = latest_features.loc[X_pred.index, ["item_id", "city", "avg_price", "item_count"]].copy()
354
  result["predicted_log_return_24h"] = preds
355
  result["predicted_return_pct"] = (np.exp(preds) - 1) * 100
356
  result["predicted_price_24h"] = result["avg_price"] * np.exp(preds)
@@ -362,6 +365,7 @@ def predict_24h_returns(model: lgb.LGBMRegressor, latest_features: pd.DataFrame)
362
  # WALK-FORWARD BACKTEST
363
  # ---------------------------------------------------------------------------
364
 
 
365
  def walk_forward_backtest(featured_df: pd.DataFrame, n_splits: int = 3) -> Dict:
366
  if featured_df.empty:
367
  return {"error": "Veri yok."}
@@ -447,20 +451,17 @@ def walk_forward_backtest(featured_df: pd.DataFrame, n_splits: int = 3) -> Dict:
447
  sim_df = pd.concat(all_predictions)
448
  total_cost_rate = SETUP_FEE_RATE + TRANSACTION_TAX_RATE
449
  sim_df["net_return"] = sim_df["actual_return"] - total_cost_rate
450
- sim_df["gross_return"] = sim_df["actual_return"]
451
  sim_df["trade_signal"] = sim_df["predicted_return"] > 0
452
  sim_trades = sim_df[sim_df["trade_signal"]].copy()
453
 
454
  if len(sim_trades) > 0:
455
  avg_net_return = sim_trades["net_return"].mean()
456
  win_rate = (sim_trades["net_return"] > 0).mean()
457
- total_trades = len(sim_trades)
458
- profitable_trades = int((sim_trades["net_return"] > 0).sum())
459
  simulation = {
460
- "total_trades": int(total_trades),
461
  "avg_net_return_per_trade_pct": round(float(avg_net_return * 100), 4),
462
  "win_rate_pct": round(float(win_rate * 100), 2),
463
- "profitable_trades": profitable_trades,
464
  }
465
  else:
466
  simulation = {"total_trades": 0, "avg_net_return_per_trade_pct": 0.0, "win_rate_pct": 0.0, "profitable_trades": 0}
@@ -478,6 +479,7 @@ def walk_forward_backtest(featured_df: pd.DataFrame, n_splits: int = 3) -> Dict:
478
  # VERİ HATTI
479
  # ---------------------------------------------------------------------------
480
 
 
481
  class DataPipeline:
482
  def __init__(self):
483
  self.history_df = pd.DataFrame()
@@ -495,8 +497,12 @@ class DataPipeline:
495
  cities = CITIES
496
 
497
  self.status_message = "API'den veri çekiliyor..."
498
- hist = fetch_history(item_ids, cities)
499
- prices = fetch_current_prices(item_ids, cities)
 
 
 
 
500
 
501
  if hist.empty:
502
  self.status_message = "Tarihsel veri alınamadı. API bağlantısını kontrol edin."
@@ -568,9 +574,10 @@ pipeline = DataPipeline()
568
  # GRADIO YARDIMCI FONKSİYONLARI
569
  # ---------------------------------------------------------------------------
570
 
 
571
  def get_dashboard_metrics():
572
  if pipeline.featured_df.empty:
573
- return pd.DataFrame({"Metrik": ["Durum"], "Değer": ["Veri yok"]})
574
 
575
  df = pipeline.featured_df
576
  metrics = {
@@ -581,6 +588,7 @@ def get_dashboard_metrics():
581
  "Ortalama Fiyat": f"{df['avg_price'].mean():.0f} silver",
582
  "Ortalama Hacim": f"{df['item_count'].mean():.1f}",
583
  "Model Durumu": "Eğitildi" if pipeline.model else "Eğitilmedi",
 
584
  }
585
  return pd.DataFrame(list(metrics.items()), columns=["Metrik", "Değer"])
586
 
@@ -596,13 +604,20 @@ def get_analysis_table():
596
  pipeline.prices_df[["item_id", "city", "sell_price_min", "buy_price_max"]],
597
  on=["item_id", "city"], how="left"
598
  )
 
 
 
599
 
600
  latest["Ürün"] = latest["item_id"].apply(item_display_name)
601
  latest["Şehir"] = latest["city"]
602
  latest["Mevcut Fiyat"] = latest["avg_price"].round(0)
603
  latest["Hacim (24s)"] = latest["item_count"].fillna(0).astype(int)
604
- latest["Spread"] = (latest.get("sell_price_min", np.nan) - latest.get("buy_price_max", np.nan)).round(0)
605
- latest["Likidite"] = pd.cut(latest["item_count"], bins=[-1, 10, 50, 200, np.inf], labels=["Düşük", "Orta", "İyi", "Yüksek"])
 
 
 
 
606
 
607
  cols = ["Ürün", "Şehir", "Mevcut Fiyat", "Hacim (24s)", "Spread", "Likidite"]
608
  return latest[cols].sort_values("Hacim (24s)", ascending=False).head(100)
@@ -611,8 +626,11 @@ def get_analysis_table():
611
  def get_prediction_table():
612
  preds = pipeline.get_latest_predictions()
613
  if preds.empty:
614
- return pd.DataFrame()
 
 
615
 
 
616
  preds["Ürün"] = preds["item_id"].apply(item_display_name)
617
  preds["Şehir"] = preds["city"]
618
  preds["Mevcut Fiyat"] = preds["avg_price"].round(0)
@@ -621,7 +639,11 @@ def get_prediction_table():
621
  preds["Güvenilirlik"] = (preds["confidence"] * 100).round(0).astype(int).astype(str) + "%"
622
  preds["Spread"] = preds["spread"].round(0)
623
  preds["Net Getiri % (maliyet sonrası)"] = preds["net_return_pct"].round(2)
624
- preds["Likidite"] = pd.cut(preds["item_count"], bins=[-1, 10, 50, 200, np.inf], labels=["Düşük", "Orta", "İyi", "Yüksek"])
 
 
 
 
625
 
626
  cols = [
627
  "Ürün", "Şehir", "Mevcut Fiyat", "Tahmini Fiyat (24s)",
@@ -633,11 +655,14 @@ def get_prediction_table():
633
 
634
  def get_arbitrage_table():
635
  if pipeline.prices_df.empty:
636
- return pd.DataFrame()
637
 
638
  prices = pipeline.prices_df.copy()
639
  prices = prices[prices["sell_price_min"] > 0]
640
 
 
 
 
641
  buy = prices.loc[prices.groupby("item_id")["sell_price_min"].idxmin()][["item_id", "city", "sell_price_min"]]
642
  buy.columns = ["item_id", "buy_city", "buy_price"]
643
 
@@ -647,7 +672,9 @@ def get_arbitrage_table():
647
  arb = buy.merge(sell, on="item_id")
648
  arb = arb[arb["sell_price"] > arb["buy_price"]].copy()
649
 
650
- # Alışta setup fee, satışta setup fee + transaction tax
 
 
651
  arb["brüt_kâr"] = arb["sell_price"] - arb["buy_price"]
652
  arb["toplam_maliyet"] = (
653
  arb["buy_price"] * SETUP_FEE_RATE
@@ -658,6 +685,9 @@ def get_arbitrage_table():
658
 
659
  arb = arb[arb["net_kâr"] > 0].sort_values("kâr_marjı_%", ascending=False)
660
 
 
 
 
661
  arb["Ürün"] = arb["item_id"].apply(item_display_name)
662
  arb["Alış Şehri"] = arb["buy_city"]
663
  arb["Satış Şehri"] = arb["sell_city"]
@@ -672,13 +702,18 @@ def get_arbitrage_table():
672
 
673
  def get_model_performance_plot():
674
  if pipeline.model is None:
675
- return go.Figure().update_layout(title="Model eğitilmedi", template="plotly_dark")
 
 
 
676
 
677
  try:
678
  importance = pipeline.model.feature_importances_
679
  feature_names = pipeline.model.feature_name_
680
  df_imp = pd.DataFrame({"Özellik": feature_names, "Önem": importance}).sort_values("Önem", ascending=True).tail(20)
681
- fig = px.bar(df_imp, x="Önem", y="Özellik", orientation="h", title="Feature Importance (Top 20)", template="plotly_dark")
 
 
682
  return fig
683
  except Exception as e:
684
  return go.Figure().update_layout(title=f"Grafik hatası: {e}", template="plotly_dark")
@@ -688,7 +723,8 @@ def get_backtest_outputs():
688
  bt = pipeline.get_backtest()
689
 
690
  if "error" in bt:
691
- return pd.DataFrame({"Hata": [bt["error"]]}), go.Figure().update_layout(title="Backtest hatası", template="plotly_dark"), pd.DataFrame()
 
692
 
693
  results_df = pd.DataFrame(bt["results"])
694
 
@@ -711,6 +747,23 @@ def get_backtest_outputs():
711
  return results_df, fig, sim_df
712
 
713
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
714
  def refresh_data_ui():
715
  pipeline.fetch_data()
716
  if not pipeline.featured_df.empty:
@@ -728,6 +781,7 @@ def refresh_data_ui():
728
  bt_table,
729
  bt_fig,
730
  sim_table,
 
731
  )
732
 
733
 
@@ -741,6 +795,7 @@ def initial_load():
741
  pd.DataFrame(),
742
  go.Figure().update_layout(title="Verileri yenilemek için butona tıklayın", template="plotly_dark"),
743
  pd.DataFrame(),
 
744
  )
745
 
746
 
@@ -748,6 +803,7 @@ def initial_load():
748
  # GRADIO ARAYÜZÜ
749
  # ---------------------------------------------------------------------------
750
 
 
751
  with gr.Blocks(title="GOSHAWK ALBION MARKET AI", theme=gr.themes.Soft(primary_hue="cyan", secondary_hue="slate")) as demo:
752
 
753
  gr.Markdown(
@@ -762,18 +818,23 @@ with gr.Blocks(title="GOSHAWK ALBION MARKET AI", theme=gr.themes.Soft(primary_hu
762
 
763
  with gr.Row():
764
  refresh_btn = gr.Button("🔄 Verileri Yenile ve Modeli Eğit", variant="primary", scale=1)
765
- status_text = gr.Textbox(label="Durum", interactive=False, scale=2)
766
 
767
  with gr.Tabs():
768
 
769
  with gr.TabItem("📊 Dashboard"):
770
- dashboard_table = gr.Dataframe(label="Özet Metrikler", interactive=False)
771
  gr.Markdown(
772
  "### Kullanım\n"
773
  "1. 'Verileri Yenile ve Modeli Eğit' butonuna tıklayın.\n"
774
  "2. API'den gerçek piyasa verileri çekilir ve global LightGBM modeli eğitilir.\n"
775
  "3. Diğer sekmelerden analizleri inceleyebilirsiniz.\n\n"
776
- "*Veriler `gos_hawk_data/` dizininde CSV olarak saklanır.*"
 
 
 
 
 
777
  )
778
 
779
  with gr.TabItem("📦 100 Ürün Analizi"):
@@ -782,9 +843,10 @@ with gr.Blocks(title="GOSHAWK ALBION MARKET AI", theme=gr.themes.Soft(primary_hu
782
  with gr.TabItem("🔮 24 Saatlik Fiyat Tahmini"):
783
  prediction_table = gr.Dataframe(label="Tahminler (24 saatlik log getiri modeli)", interactive=False)
784
  gr.Markdown(
785
- "*Güvenilirlik, volatilite ve RSI tabanlı bir göstergedir. "
786
  "Net getiri, %2.5 setup + %8 vergi düşülerek hesaplanmıştır. "
787
- "Spread ve likidite düşükse işlem maliyeti artabilir.*"
 
788
  )
789
 
790
  with gr.TabItem("🚚 Şehirler Arası Arbitraj"):
@@ -798,18 +860,23 @@ with gr.Blocks(title="GOSHAWK ALBION MARKET AI", theme=gr.themes.Soft(primary_hu
798
  performance_plot = gr.Plot(label="Feature Importance")
799
 
800
  with gr.TabItem("🧪 Walk-forward Backtest"):
801
- backtest_table = gr.Dataframe(label="Split Sonuçları")
802
  backtest_plot = gr.Plot(label="MAE Karşılaştırması")
803
- simulation_table = gr.Dataframe(label="İşlem Simülasyonu (maliyetler sonrası)")
804
  gr.Markdown(
805
  "*Walk-forward backtest kronolojik split kullanır; purge (24s) ve embargo (24s) uygulanır. "
806
- "Baseline, 'fiyat değişmez' (getiri=0) varsayımıdır. Simülasyon yalnızca modelin pozitif getiri öngördüğü işlemleri içerir.*"
 
 
807
  )
808
 
809
  with gr.TabItem("🗄️ Veri Yönetimi"):
810
  gr.Markdown("Veriler `gos_hawk_data/` dizininde CSV olarak saklanır.")
811
- data_status = gr.Textbox(label="Veri Durumu", interactive=False)
812
- csv_files = gr.FileExplorer(root=DATA_DIR, label="Kayıtlı CSV Dosyaları")
 
 
 
813
 
814
  refresh_btn.click(
815
  fn=refresh_data_ui,
@@ -824,6 +891,7 @@ with gr.Blocks(title="GOSHAWK ALBION MARKET AI", theme=gr.themes.Soft(primary_hu
824
  backtest_table,
825
  backtest_plot,
826
  simulation_table,
 
827
  ],
828
  )
829
 
@@ -839,6 +907,7 @@ with gr.Blocks(title="GOSHAWK ALBION MARKET AI", theme=gr.themes.Soft(primary_hu
839
  backtest_table,
840
  backtest_plot,
841
  simulation_table,
 
842
  ],
843
  )
844
 
 
37
  "Caerleon",
38
  ]
39
 
 
40
  _ITEM_POOL = [
41
  "T4_BAG", "T5_BAG", "T6_BAG", "T7_BAG", "T8_BAG",
42
  "T4_CAPE", "T5_CAPE", "T6_CAPE", "T7_CAPE", "T8_CAPE",
 
78
  ]
79
  ITEM_IDS = list(dict.fromkeys(_ITEM_POOL))[:100]
80
 
81
+
82
  def item_display_name(item_id: str) -> str:
83
  return item_id.replace("_", " ").title()
84
 
85
+
86
  SETUP_FEE_RATE = 0.025 # %2.5 listeleme ücreti
87
  TRANSACTION_TAX_RATE = 0.08 # %8 satış vergisi (Premium olmayan varsayılan)
88
 
 
104
  # YARDIMCI FONKSİYONLAR
105
  # ---------------------------------------------------------------------------
106
 
107
+
108
  def safe_request(url: str, params: Optional[dict] = None) -> Optional[list]:
109
  for attempt in range(MAX_RETRIES):
110
  try:
 
209
  # FEATURE ENGINEERING
210
  # ---------------------------------------------------------------------------
211
 
212
+
213
  def compute_rsi(series: pd.Series, period: int = 14) -> pd.Series:
214
  delta = series.diff()
215
  gain = delta.clip(lower=0).rolling(period).mean()
 
353
  return pd.DataFrame()
354
 
355
  preds = model.predict(X_pred)
356
+ result = latest_features.loc[X_pred.index, ["item_id", "city", "avg_price", "item_count", "volatility_24h"]].copy()
357
  result["predicted_log_return_24h"] = preds
358
  result["predicted_return_pct"] = (np.exp(preds) - 1) * 100
359
  result["predicted_price_24h"] = result["avg_price"] * np.exp(preds)
 
365
  # WALK-FORWARD BACKTEST
366
  # ---------------------------------------------------------------------------
367
 
368
+
369
  def walk_forward_backtest(featured_df: pd.DataFrame, n_splits: int = 3) -> Dict:
370
  if featured_df.empty:
371
  return {"error": "Veri yok."}
 
451
  sim_df = pd.concat(all_predictions)
452
  total_cost_rate = SETUP_FEE_RATE + TRANSACTION_TAX_RATE
453
  sim_df["net_return"] = sim_df["actual_return"] - total_cost_rate
 
454
  sim_df["trade_signal"] = sim_df["predicted_return"] > 0
455
  sim_trades = sim_df[sim_df["trade_signal"]].copy()
456
 
457
  if len(sim_trades) > 0:
458
  avg_net_return = sim_trades["net_return"].mean()
459
  win_rate = (sim_trades["net_return"] > 0).mean()
 
 
460
  simulation = {
461
+ "total_trades": int(len(sim_trades)),
462
  "avg_net_return_per_trade_pct": round(float(avg_net_return * 100), 4),
463
  "win_rate_pct": round(float(win_rate * 100), 2),
464
+ "profitable_trades": int((sim_trades["net_return"] > 0).sum()),
465
  }
466
  else:
467
  simulation = {"total_trades": 0, "avg_net_return_per_trade_pct": 0.0, "win_rate_pct": 0.0, "profitable_trades": 0}
 
479
  # VERİ HATTI
480
  # ---------------------------------------------------------------------------
481
 
482
+
483
  class DataPipeline:
484
  def __init__(self):
485
  self.history_df = pd.DataFrame()
 
497
  cities = CITIES
498
 
499
  self.status_message = "API'den veri çekiliyor..."
500
+ try:
501
+ hist = fetch_history(item_ids, cities)
502
+ prices = fetch_current_prices(item_ids, cities)
503
+ except Exception as e:
504
+ self.status_message = f"API bağlantı hatası: {e}"
505
+ return
506
 
507
  if hist.empty:
508
  self.status_message = "Tarihsel veri alınamadı. API bağlantısını kontrol edin."
 
574
  # GRADIO YARDIMCI FONKSİYONLARI
575
  # ---------------------------------------------------------------------------
576
 
577
+
578
  def get_dashboard_metrics():
579
  if pipeline.featured_df.empty:
580
+ return pd.DataFrame({"Metrik": ["Durum"], "Değer": ["Veri yok - Lütfen 'Verileri Yenile' butonuna tıklayın."]})
581
 
582
  df = pipeline.featured_df
583
  metrics = {
 
588
  "Ortalama Fiyat": f"{df['avg_price'].mean():.0f} silver",
589
  "Ortalama Hacim": f"{df['item_count'].mean():.1f}",
590
  "Model Durumu": "Eğitildi" if pipeline.model else "Eğitilmedi",
591
+ "Son Güncelleme": pipeline.last_update.strftime("%Y-%m-%d %H:%M") if pipeline.last_update else "—",
592
  }
593
  return pd.DataFrame(list(metrics.items()), columns=["Metrik", "Değer"])
594
 
 
604
  pipeline.prices_df[["item_id", "city", "sell_price_min", "buy_price_max"]],
605
  on=["item_id", "city"], how="left"
606
  )
607
+ else:
608
+ latest["sell_price_min"] = np.nan
609
+ latest["buy_price_max"] = np.nan
610
 
611
  latest["Ürün"] = latest["item_id"].apply(item_display_name)
612
  latest["Şehir"] = latest["city"]
613
  latest["Mevcut Fiyat"] = latest["avg_price"].round(0)
614
  latest["Hacim (24s)"] = latest["item_count"].fillna(0).astype(int)
615
+ latest["Spread"] = (latest["sell_price_min"] - latest["buy_price_max"]).round(0)
616
+ latest["Likidite"] = pd.cut(
617
+ latest["item_count"],
618
+ bins=[-1, 10, 50, 200, np.inf],
619
+ labels=["Düşük", "Orta", "İyi", "Yüksek"]
620
+ ).astype(str)
621
 
622
  cols = ["Ürün", "Şehir", "Mevcut Fiyat", "Hacim (24s)", "Spread", "Likidite"]
623
  return latest[cols].sort_values("Hacim (24s)", ascending=False).head(100)
 
626
  def get_prediction_table():
627
  preds = pipeline.get_latest_predictions()
628
  if preds.empty:
629
+ return pd.DataFrame({
630
+ "Bilgi": ["Tahmin üretilemedi. Veri çekip model eğitin veya yeterli veri olduğundan emin olun."]
631
+ })
632
 
633
+ preds = preds.copy()
634
  preds["Ürün"] = preds["item_id"].apply(item_display_name)
635
  preds["Şehir"] = preds["city"]
636
  preds["Mevcut Fiyat"] = preds["avg_price"].round(0)
 
639
  preds["Güvenilirlik"] = (preds["confidence"] * 100).round(0).astype(int).astype(str) + "%"
640
  preds["Spread"] = preds["spread"].round(0)
641
  preds["Net Getiri % (maliyet sonrası)"] = preds["net_return_pct"].round(2)
642
+ preds["Likidite"] = pd.cut(
643
+ preds["item_count"],
644
+ bins=[-1, 10, 50, 200, np.inf],
645
+ labels=["Düşük", "Orta", "İyi", "Yüksek"]
646
+ ).astype(str)
647
 
648
  cols = [
649
  "Ürün", "Şehir", "Mevcut Fiyat", "Tahmini Fiyat (24s)",
 
655
 
656
  def get_arbitrage_table():
657
  if pipeline.prices_df.empty:
658
+ return pd.DataFrame({"Bilgi": ["Anlık fiyat verisi yok."]})
659
 
660
  prices = pipeline.prices_df.copy()
661
  prices = prices[prices["sell_price_min"] > 0]
662
 
663
+ if prices.empty:
664
+ return pd.DataFrame({"Bilgi": ["Geçerli anlık fiyat yok."]})
665
+
666
  buy = prices.loc[prices.groupby("item_id")["sell_price_min"].idxmin()][["item_id", "city", "sell_price_min"]]
667
  buy.columns = ["item_id", "buy_city", "buy_price"]
668
 
 
672
  arb = buy.merge(sell, on="item_id")
673
  arb = arb[arb["sell_price"] > arb["buy_price"]].copy()
674
 
675
+ if arb.empty:
676
+ return pd.DataFrame({"Bilgi": ["Kârlı arbitraj fırsatı bulunamadı."]})
677
+
678
  arb["brüt_kâr"] = arb["sell_price"] - arb["buy_price"]
679
  arb["toplam_maliyet"] = (
680
  arb["buy_price"] * SETUP_FEE_RATE
 
685
 
686
  arb = arb[arb["net_kâr"] > 0].sort_values("kâr_marjı_%", ascending=False)
687
 
688
+ if arb.empty:
689
+ return pd.DataFrame({"Bilgi": ["İşlem maliyetleri sonrası kârlı arbitraj yok."]})
690
+
691
  arb["Ürün"] = arb["item_id"].apply(item_display_name)
692
  arb["Alış Şehri"] = arb["buy_city"]
693
  arb["Satış Şehri"] = arb["sell_city"]
 
702
 
703
  def get_model_performance_plot():
704
  if pipeline.model is None:
705
+ return go.Figure().update_layout(
706
+ title="Model eğitilmedi - Lütfen 'Verileri Yenile' butonuna tıklayın",
707
+ template="plotly_dark"
708
+ )
709
 
710
  try:
711
  importance = pipeline.model.feature_importances_
712
  feature_names = pipeline.model.feature_name_
713
  df_imp = pd.DataFrame({"Özellik": feature_names, "Önem": importance}).sort_values("Önem", ascending=True).tail(20)
714
+ fig = px.bar(df_imp, x="Önem", y="Özellik", orientation="h",
715
+ title="Feature Importance (Top 20)", template="plotly_dark")
716
+ fig.update_layout(height=600)
717
  return fig
718
  except Exception as e:
719
  return go.Figure().update_layout(title=f"Grafik hatası: {e}", template="plotly_dark")
 
723
  bt = pipeline.get_backtest()
724
 
725
  if "error" in bt:
726
+ empty_fig = go.Figure().update_layout(title=f"Backtest hatası: {bt['error']}", template="plotly_dark")
727
+ return pd.DataFrame({"Bilgi": [bt["error"]]}), empty_fig, pd.DataFrame()
728
 
729
  results_df = pd.DataFrame(bt["results"])
730
 
 
747
  return results_df, fig, sim_df
748
 
749
 
750
+ def list_csv_files() -> pd.DataFrame:
751
+ rows = []
752
+ if os.path.isdir(DATA_DIR):
753
+ for fname in sorted(os.listdir(DATA_DIR)):
754
+ if fname.endswith(".csv"):
755
+ fpath = os.path.join(DATA_DIR, fname)
756
+ try:
757
+ size_kb = round(os.path.getsize(fpath) / 1024, 2)
758
+ mtime = dt.datetime.fromtimestamp(os.path.getmtime(fpath)).strftime("%Y-%m-%d %H:%M:%S")
759
+ rows.append({"Dosya": fname, "Boyut (KB)": size_kb, "Son Değişiklik": mtime})
760
+ except OSError:
761
+ continue
762
+ if not rows:
763
+ return pd.DataFrame(columns=["Dosya", "Boyut (KB)", "Son Değişiklik"])
764
+ return pd.DataFrame(rows)
765
+
766
+
767
  def refresh_data_ui():
768
  pipeline.fetch_data()
769
  if not pipeline.featured_df.empty:
 
781
  bt_table,
782
  bt_fig,
783
  sim_table,
784
+ list_csv_files(),
785
  )
786
 
787
 
 
795
  pd.DataFrame(),
796
  go.Figure().update_layout(title="Verileri yenilemek için butona tıklayın", template="plotly_dark"),
797
  pd.DataFrame(),
798
+ list_csv_files(),
799
  )
800
 
801
 
 
803
  # GRADIO ARAYÜZÜ
804
  # ---------------------------------------------------------------------------
805
 
806
+
807
  with gr.Blocks(title="GOSHAWK ALBION MARKET AI", theme=gr.themes.Soft(primary_hue="cyan", secondary_hue="slate")) as demo:
808
 
809
  gr.Markdown(
 
818
 
819
  with gr.Row():
820
  refresh_btn = gr.Button("🔄 Verileri Yenile ve Modeli Eğit", variant="primary", scale=1)
821
+ status_text = gr.Textbox(label="Durum", interactive=False, scale=2, value=pipeline.status_message)
822
 
823
  with gr.Tabs():
824
 
825
  with gr.TabItem("📊 Dashboard"):
826
+ dashboard_table = gr.Dataframe(label="Özet Metrikler", interactive=False, wrap=True)
827
  gr.Markdown(
828
  "### Kullanım\n"
829
  "1. 'Verileri Yenile ve Modeli Eğit' butonuna tıklayın.\n"
830
  "2. API'den gerçek piyasa verileri çekilir ve global LightGBM modeli eğitilir.\n"
831
  "3. Diğer sekmelerden analizleri inceleyebilirsiniz.\n\n"
832
+ "*Veriler `gos_hawk_data/` dizininde CSV olarak saklanır.*\n\n"
833
+ "### Riskler ve Belirsizlikler\n"
834
+ "- Model tahminleri **olasılıksaldır**, kesin değildir.\n"
835
+ "- Albion Online piyasası oyuncu davranışı, güncellemeler ve sezon değişimlerinden etkilenir.\n"
836
+ "- Backtest sonuçları geçmiş performansı yansıtır; gelecek performansı garanti etmez.\n"
837
+ "- Spread ve likidite düşükse gerçekleşme fiyatı tahminden sapabilir.\n"
838
  )
839
 
840
  with gr.TabItem("📦 100 Ürün Analizi"):
 
843
  with gr.TabItem("🔮 24 Saatlik Fiyat Tahmini"):
844
  prediction_table = gr.Dataframe(label="Tahminler (24 saatlik log getiri modeli)", interactive=False)
845
  gr.Markdown(
846
+ "*Güvenilirlik, volatilite tabanlı bir göstergedir. "
847
  "Net getiri, %2.5 setup + %8 vergi düşülerek hesaplanmıştır. "
848
+ "Spread ve likidite düşükse işlem maliyeti artabilir. "
849
+ "Bu tahminler garanti değildir.*"
850
  )
851
 
852
  with gr.TabItem("🚚 Şehirler Arası Arbitraj"):
 
860
  performance_plot = gr.Plot(label="Feature Importance")
861
 
862
  with gr.TabItem("🧪 Walk-forward Backtest"):
863
+ backtest_table = gr.Dataframe(label="Split Sonuçları", interactive=False)
864
  backtest_plot = gr.Plot(label="MAE Karşılaştırması")
865
+ simulation_table = gr.Dataframe(label="İşlem Simülasyonu (maliyetler sonrası)", interactive=False)
866
  gr.Markdown(
867
  "*Walk-forward backtest kronolojik split kullanır; purge (24s) ve embargo (24s) uygulanır. "
868
+ "Baseline, 'fiyat değişmez' (getiri=0) varsayımıdır. "
869
+ "Simülasyon yalnızca modelin pozitif getiri öngördüğü işlemleri içerir. "
870
+ "Gerçek işlemlerde slippage ve rekabet nedeniyle sonuçlar farklı olabilir.*"
871
  )
872
 
873
  with gr.TabItem("🗄️ Veri Yönetimi"):
874
  gr.Markdown("Veriler `gos_hawk_data/` dizininde CSV olarak saklanır.")
875
+ csv_files = gr.Dataframe(
876
+ label="Kayıtlı CSV Dosyaları (Yenile butonuna basınca güncellenir)",
877
+ interactive=False,
878
+ headers=["Dosya", "Boyut (KB)", "Son Değişiklik"],
879
+ )
880
 
881
  refresh_btn.click(
882
  fn=refresh_data_ui,
 
891
  backtest_table,
892
  backtest_plot,
893
  simulation_table,
894
+ csv_files,
895
  ],
896
  )
897
 
 
907
  backtest_table,
908
  backtest_plot,
909
  simulation_table,
910
+ csv_files,
911
  ],
912
  )
913