GoshawkVortexAI commited on
Commit
e738281
·
verified ·
1 Parent(s): 9c19d74

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +117 -3
app.py CHANGED
@@ -62,7 +62,7 @@ SERVER = StdioServerParameters(
62
  # Tool şemasındaki argüman adları sürümler arası değişebilir; şemaya bakıp eşleştiriyoruz.
63
  ALIASES = {
64
  "symbol": ["symbol", "pair"],
65
- "timeframe": ["timeframe", "interval", "tf"],
66
  "exchange": ["exchange"],
67
  "limit": ["limit", "count", "n", "bars"],
68
  "until": ["until", "end", "end_time", "endTime", "to", "before"],
@@ -147,6 +147,113 @@ async def fetch_ohlcv(session, tools, symbol, timeframe, exchange, total):
147
  return out.to_dict("records")
148
 
149
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  def _numeric_list(o, min_len):
151
  return (isinstance(o, list) and len(o) >= min_len and
152
  all(x is None or (isinstance(x, (int, float)) and not isinstance(x, bool)) for x in o[:50]))
@@ -491,11 +598,17 @@ def _root(e):
491
  return f"{type(e).__name__}: {e}"
492
 
493
 
494
- def run(symbol, timeframe, exchange, horizon, limit):
495
  try:
496
  ohlcv, deep, ind, extra = asyncio.run(run_async(symbol, timeframe, exchange, horizon, limit))
497
  df = to_df(ohlcv)
 
 
 
 
498
  ext = indicator_features(ind, df)
 
 
499
  res = predict(df, int(horizon), ext=ext)
500
  except BaseException as e: # noqa: BLE001
501
  import traceback
@@ -548,12 +661,13 @@ with gr.Blocks(title="Tickscope Tahmin") as demo:
548
  with gr.Row():
549
  horizon = gr.Slider(1, 24, value=4, step=1, label="Tahmin ufku (bar)")
550
  limit = gr.Slider(300, 20000, value=5000, step=100, label="Mum sayısı (1000 üstü sayfalanır)")
 
551
  btn = gr.Button("Tahmin et", variant="primary")
552
  out_md = gr.Markdown()
553
  out_plot = gr.Plot()
554
  with gr.Accordion("Tickscope ham çıktı (deep_analyze / indicators)", open=False):
555
  out_raw = gr.Code(language="json")
556
- btn.click(run, [symbol, timeframe, exchange, horizon, limit], [out_md, out_plot, out_raw])
557
 
558
  if __name__ == "__main__":
559
  demo.launch()
 
62
  # Tool şemasındaki argüman adları sürümler arası değişebilir; şemaya bakıp eşleştiriyoruz.
63
  ALIASES = {
64
  "symbol": ["symbol", "pair"],
65
+ "timeframe": ["timeframe", "interval", "tf", "period"],
66
  "exchange": ["exchange"],
67
  "limit": ["limit", "count", "n", "bars"],
68
  "until": ["until", "end", "end_time", "endTime", "to", "before"],
 
147
  return out.to_dict("records")
148
 
149
 
150
+ # ----------------------------------------------------------------- 2. MCP: crypto-market-data-mcp (türev verisi)
151
+ # Kurulum: git clone https://github.com/eliasfire617/crypto-market-data-mcp
152
+ # (kendi venv'inde) pip install -r requirements.txt
153
+ # Sonra ortam değişkenleri:
154
+ # CRYPTO_MCP_SERVER=/yol/crypto-market-data-mcp/server.py
155
+ # CRYPTO_MCP_PYTHON=/yol/crypto-market-data-mcp/.venv/bin/python (opsiyonel; yoksa bu uygulamanın python'u)
156
+ DERIV_PATH = os.environ.get("CRYPTO_MCP_SERVER", "")
157
+
158
+
159
+ def _perp(symbol):
160
+ s = symbol.strip().upper()
161
+ if "/" in s and ":" not in s:
162
+ s = f"{s}:{s.split('/')[1]}"
163
+ return s
164
+
165
+
166
+ def parse_funding(payload):
167
+ """Funding geçmişi çıktısında (şemadan bağımsız) zaman + oran kolonlarını bulur."""
168
+ def find_rows(o):
169
+ if isinstance(o, list) and len(o) >= 5 and all(isinstance(x, dict) for x in o[:3]):
170
+ return o
171
+ if isinstance(o, dict):
172
+ for v in o.values():
173
+ r = find_rows(v)
174
+ if r:
175
+ return r
176
+ return None
177
+
178
+ rows = find_rows(payload)
179
+ if not rows:
180
+ return None
181
+ d = pd.DataFrame(rows)
182
+ tcol = next((c for c in ("timestamp", "fundingTime", "time", "ts", "datetime") if c in d), None)
183
+ rcol = next((c for c in ("fundingRate", "funding_rate", "rate", "value") if c in d), None)
184
+ if tcol is None or rcol is None:
185
+ return None
186
+ ts = d[tcol]
187
+ if pd.api.types.is_numeric_dtype(ts):
188
+ ts = pd.to_datetime(ts, unit="ms" if ts.iloc[-1] > 1e11 else "s")
189
+ else:
190
+ ts = pd.to_datetime(ts)
191
+ if getattr(ts.dt, "tz", None) is not None:
192
+ ts = ts.dt.tz_convert(None)
193
+ out = pd.DataFrame({"ts": ts.astype("datetime64[ns]"), "r": pd.to_numeric(d[rcol], errors="coerce")})
194
+ return out.dropna().drop_duplicates("ts").sort_values("ts").reset_index(drop=True)
195
+
196
+
197
+ async def fetch_deriv_features(symbol, exchange, timeframe, df):
198
+ """2. MCP'den funding geçmişi (özellik) + OI / long-short / likidasyon (canlı bağlam) çeker.
199
+ Dönen: (özellik tablosu | None, df (funding kapsamına kırpılmış olabilir), ham çıktı sözlüğü)."""
200
+ import sys
201
+ extra = {}
202
+ if not DERIV_PATH or not os.path.exists(DERIV_PATH):
203
+ extra["deriv_note"] = "CRYPTO_MCP_SERVER ayarlı değil / dosya yok; türev verisi atlandı"
204
+ return None, df, extra
205
+ params = StdioServerParameters(
206
+ command=os.environ.get("CRYPTO_MCP_PYTHON", sys.executable),
207
+ args=[DERIV_PATH],
208
+ cwd=os.path.dirname(os.path.abspath(DERIV_PATH)),
209
+ env={**os.environ},
210
+ )
211
+ perp = _perp(symbol)
212
+ try:
213
+ async with stdio_client(params) as (r, w):
214
+ async with ClientSession(r, w) as session:
215
+ await session.initialize()
216
+ tools = {t.name: t for t in (await session.list_tools()).tools}
217
+ hist = await call_tool(session, tools, "get_funding_rate_history",
218
+ symbol=perp, exchange=exchange, limit=1000)
219
+ for name in ("get_funding_rate", "compare_funding", "get_open_interest",
220
+ "get_long_short_ratio", "get_liquidations"):
221
+ if name in tools:
222
+ try:
223
+ extra[f"deriv_{name}"] = await call_tool(
224
+ session, tools, name, symbol=perp, exchange=exchange, timeframe=timeframe)
225
+ except Exception as e: # noqa: BLE001
226
+ extra[f"deriv_{name}"] = {"error": _root(e)}
227
+ except Exception as e: # noqa: BLE001
228
+ extra["deriv_error"] = _root(e)
229
+ return None, df, extra
230
+
231
+ bad = hist is None or (isinstance(hist, dict) and "error" in hist)
232
+ f = None if bad else parse_funding(hist)
233
+ if f is None or len(f) < 60:
234
+ extra["deriv_note"] = "Funding geçmişi okunamadı veya yetersiz; özellik eklenmedi"
235
+ extra["deriv_funding_raw"] = _strip_series(hist)
236
+ return None, df, extra
237
+
238
+ rr = f["r"]
239
+ f["fund"] = rr * 1e4 # baz puan
240
+ f["fund_z"] = (rr - rr.rolling(30).mean()) / (rr.rolling(30).std() + 1e-12)
241
+ f["fund_chg"] = rr.diff() * 1e4
242
+ f["fund_ma9"] = rr.rolling(9).mean() * 1e4
243
+ f = f.dropna().reset_index(drop=True)
244
+ start = f["ts"].iloc[0]
245
+ d2 = df[df["ts"] >= start].reset_index(drop=True)
246
+ if len(d2) < 800:
247
+ extra["deriv_note"] = (f"Funding geçmişi mumların yalnızca {len(d2)} barını kapsıyor (<800); "
248
+ "özellik eklenmedi")
249
+ return None, df, extra
250
+ d2["ts"] = d2["ts"].astype("datetime64[ns]")
251
+ m = pd.merge_asof(d2[["ts"]], f.drop(columns=["r"]), on="ts", direction="backward") # lookahead yok
252
+ m.index = d2.index
253
+ extra["deriv_funding_used"] = {"funding_gozlem": len(f), "baslangic": str(start), "bar": len(d2)}
254
+ return m.drop(columns=["ts"]).add_prefix("dv_"), d2, extra
255
+
256
+
257
  def _numeric_list(o, min_len):
258
  return (isinstance(o, list) and len(o) >= min_len and
259
  all(x is None or (isinstance(x, (int, float)) and not isinstance(x, bool)) for x in o[:50]))
 
598
  return f"{type(e).__name__}: {e}"
599
 
600
 
601
+ def run(symbol, timeframe, exchange, horizon, limit, use_deriv=True):
602
  try:
603
  ohlcv, deep, ind, extra = asyncio.run(run_async(symbol, timeframe, exchange, horizon, limit))
604
  df = to_df(ohlcv)
605
+ dfeat = None
606
+ if use_deriv:
607
+ dfeat, df, dextra = asyncio.run(fetch_deriv_features(symbol, exchange, timeframe, df))
608
+ extra.update(dextra)
609
  ext = indicator_features(ind, df)
610
+ if dfeat is not None:
611
+ ext = dfeat if ext is None else pd.concat([ext, dfeat], axis=1)
612
  res = predict(df, int(horizon), ext=ext)
613
  except BaseException as e: # noqa: BLE001
614
  import traceback
 
661
  with gr.Row():
662
  horizon = gr.Slider(1, 24, value=4, step=1, label="Tahmin ufku (bar)")
663
  limit = gr.Slider(300, 20000, value=5000, step=100, label="Mum sayısı (1000 üstü sayfalanır)")
664
+ use_deriv = gr.Checkbox(True, label="Türev verisi (funding; 2. MCP) — mumları funding geçmişinin kapsadığı aralığa kırpabilir")
665
  btn = gr.Button("Tahmin et", variant="primary")
666
  out_md = gr.Markdown()
667
  out_plot = gr.Plot()
668
  with gr.Accordion("Tickscope ham çıktı (deep_analyze / indicators)", open=False):
669
  out_raw = gr.Code(language="json")
670
+ btn.click(run, [symbol, timeframe, exchange, horizon, limit, use_deriv], [out_md, out_plot, out_raw])
671
 
672
  if __name__ == "__main__":
673
  demo.launch()