Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -66,6 +66,7 @@ ALIASES = {
|
|
| 66 |
"exchange": ["exchange"],
|
| 67 |
"limit": ["limit", "count", "n", "bars"],
|
| 68 |
"until": ["until", "end", "end_time", "endTime", "to", "before"],
|
|
|
|
| 69 |
}
|
| 70 |
|
| 71 |
EXTRA_TOOLS = ["detect_divergence", "detect_patterns", "analyze_structure",
|
|
@@ -146,6 +147,69 @@ async def fetch_ohlcv(session, tools, symbol, timeframe, exchange, total):
|
|
| 146 |
return out.to_dict("records")
|
| 147 |
|
| 148 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
def to_df(payload) -> pd.DataFrame:
|
| 150 |
rows = payload
|
| 151 |
if isinstance(payload, dict):
|
|
@@ -304,8 +368,16 @@ def _backtest(p, fwd, horizon, thr, fee):
|
|
| 304 |
"hit": float((tr > 0).mean()), "pf": float(gp / gl) if gl > 0 else np.inf}
|
| 305 |
|
| 306 |
|
| 307 |
-
def predict(df: pd.DataFrame, horizon: int, fee: float = 0.0006, n_folds: int = 5):
|
| 308 |
feats, atr = make_features(df)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 309 |
close = df["close"]
|
| 310 |
fwd = close.shift(-horizon) / close - 1
|
| 311 |
y = (fwd > 0).astype(float)
|
|
@@ -374,6 +446,7 @@ def predict(df: pd.DataFrame, horizon: int, fee: float = 0.0006, n_folds: int =
|
|
| 374 |
"p_up": p_up, "acc": acc, "baseline": base, "auc": auc, "price": price, "atr": a,
|
| 375 |
"center": center, "low": center - move, "high": center + move,
|
| 376 |
"thr": best["thr"], "bt": best, "n_oos": len(oos_p), "fee": fee,
|
|
|
|
| 377 |
}
|
| 378 |
|
| 379 |
|
|
@@ -394,7 +467,8 @@ async def run_async(symbol, timeframe, exchange, horizon, limit):
|
|
| 394 |
deep = await call_tool(session, tools, "deep_analyze", symbol=symbol,
|
| 395 |
timeframe=timeframe, exchange=exchange)
|
| 396 |
ind = await call_tool(session, tools, "compute_indicators", symbol=symbol,
|
| 397 |
-
timeframe=timeframe, exchange=exchange
|
|
|
|
| 398 |
|
| 399 |
# Tickscope'un diğer tüm analiz/piyasa araçları (canlı bağlam; şema uyuşmazsa hata olarak kaydedilir)
|
| 400 |
extra = {}
|
|
@@ -421,7 +495,8 @@ def run(symbol, timeframe, exchange, horizon, limit):
|
|
| 421 |
try:
|
| 422 |
ohlcv, deep, ind, extra = asyncio.run(run_async(symbol, timeframe, exchange, horizon, limit))
|
| 423 |
df = to_df(ohlcv)
|
| 424 |
-
|
|
|
|
| 425 |
except BaseException as e: # noqa: BLE001
|
| 426 |
import traceback
|
| 427 |
traceback.print_exc()
|
|
@@ -441,6 +516,7 @@ def run(symbol, timeframe, exchange, horizon, limit):
|
|
| 441 |
| OOS AUC / doğruluk | {res['auc']:.3f} / {res['acc']:.1%} (baseline {res['baseline']:.1%}) |
|
| 442 |
| OOS işlem sayısı | {bt['n']} (hit {bt['hit']:.1%}, PF {bt['pf']:.2f}) |
|
| 443 |
| Ort. net getiri / işlem | {bt['mean']:.3%} (t = {bt['t']:.2f}, ücret {res['fee']:.2%}/işlem) |
|
|
|
|
| 444 |
| Model edge | {edge} |
|
| 445 |
|
| 446 |
*Walk-forward (purged) out-of-sample sonuçlar. Eşik OOS'ta seçildiği için hafif iyimser olabilir. Eğitim/araştırma amaçlıdır; yatırım tavsiyesi değildir.*"""
|
|
@@ -458,7 +534,7 @@ def run(symbol, timeframe, exchange, horizon, limit):
|
|
| 458 |
arrayminus=[res["center"] - res["low"]])))
|
| 459 |
fig.update_layout(height=450, xaxis_rangeslider_visible=False, margin=dict(l=10, r=10, t=30, b=10))
|
| 460 |
|
| 461 |
-
raw = json.dumps({"deep_analyze": deep, "compute_indicators": ind, **extra},
|
| 462 |
indent=2, ensure_ascii=False, default=str)
|
| 463 |
return md, fig, raw
|
| 464 |
|
|
|
|
| 66 |
"exchange": ["exchange"],
|
| 67 |
"limit": ["limit", "count", "n", "bars"],
|
| 68 |
"until": ["until", "end", "end_time", "endTime", "to", "before"],
|
| 69 |
+
"include_series": ["include_series", "includeSeries", "series", "with_series"],
|
| 70 |
}
|
| 71 |
|
| 72 |
EXTRA_TOOLS = ["detect_divergence", "detect_patterns", "analyze_structure",
|
|
|
|
| 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]))
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def extract_series(payload, n):
|
| 156 |
+
"""compute_indicators çıktısında gezinip bar bazlı sayısal serileri bulur (şemadan bağımsız)."""
|
| 157 |
+
min_len = max(50, int(n * 0.5))
|
| 158 |
+
out = {}
|
| 159 |
+
|
| 160 |
+
def walk(o, path):
|
| 161 |
+
if isinstance(o, list):
|
| 162 |
+
if _numeric_list(o, min_len):
|
| 163 |
+
out[path] = o
|
| 164 |
+
elif len(o) >= min_len and all(isinstance(x, dict) for x in o[:3]):
|
| 165 |
+
for key in o[0]:
|
| 166 |
+
vals = [r.get(key) if isinstance(r, dict) else None for r in o]
|
| 167 |
+
if _numeric_list(vals, min_len) and key.lower() not in ("ts", "time", "timestamp", "t"):
|
| 168 |
+
out[f"{path}.{key}"] = vals
|
| 169 |
+
elif isinstance(o, dict):
|
| 170 |
+
for k, v in o.items():
|
| 171 |
+
walk(v, f"{path}.{k}" if path else str(k))
|
| 172 |
+
|
| 173 |
+
walk(payload, "")
|
| 174 |
+
return out
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def indicator_features(ind, df: pd.DataFrame):
|
| 178 |
+
"""Tickscope'un 73 göstergesinin zaman serilerini (varsa) df'e hizalı özellik tablosuna çevirir.
|
| 179 |
+
Fiyat seviyesi gibi duran (SMA/EMA/bant vb.) seriler kapanışa göre normalize edilir."""
|
| 180 |
+
if not isinstance(ind, dict) or "error" in ind:
|
| 181 |
+
return None
|
| 182 |
+
n = len(df)
|
| 183 |
+
close = df["close"].values
|
| 184 |
+
cols = {}
|
| 185 |
+
for path, vals in extract_series(ind, n).items():
|
| 186 |
+
s = pd.to_numeric(pd.Series(vals), errors="coerce").values.astype(float)
|
| 187 |
+
arr = np.full(n, np.nan)
|
| 188 |
+
m = min(len(s), n)
|
| 189 |
+
arr[-m:] = s[-m:] # seriler sondan hizalanır
|
| 190 |
+
if np.isnan(arr).all() or np.nanstd(arr) == 0:
|
| 191 |
+
continue
|
| 192 |
+
ref = np.nanmedian(close[-m:])
|
| 193 |
+
if ref and abs(np.nanmedian(arr) / ref - 1) < 0.5: # fiyat seviyesi -> göreli mesafe
|
| 194 |
+
arr = arr / close - 1
|
| 195 |
+
name = "ts_" + "".join(ch if ch.isalnum() else "_" for ch in path).strip("_")
|
| 196 |
+
cols[name] = arr
|
| 197 |
+
if not cols:
|
| 198 |
+
return None
|
| 199 |
+
return pd.DataFrame(cols, index=df.index)
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
def _strip_series(o, keep=3):
|
| 203 |
+
"""Ham çıktıyı okunur tutmak için uzun serileri son `keep` değere kısaltır."""
|
| 204 |
+
if isinstance(o, list) and len(o) > 20:
|
| 205 |
+
return [f"... {len(o)} değer, son {keep}:"] + o[-keep:]
|
| 206 |
+
if isinstance(o, list):
|
| 207 |
+
return [_strip_series(x, keep) for x in o]
|
| 208 |
+
if isinstance(o, dict):
|
| 209 |
+
return {k: _strip_series(v, keep) for k, v in o.items()}
|
| 210 |
+
return o
|
| 211 |
+
|
| 212 |
+
|
| 213 |
def to_df(payload) -> pd.DataFrame:
|
| 214 |
rows = payload
|
| 215 |
if isinstance(payload, dict):
|
|
|
|
| 368 |
"hit": float((tr > 0).mean()), "pf": float(gp / gl) if gl > 0 else np.inf}
|
| 369 |
|
| 370 |
|
| 371 |
+
def predict(df: pd.DataFrame, horizon: int, fee: float = 0.0006, n_folds: int = 5, ext=None):
|
| 372 |
feats, atr = make_features(df)
|
| 373 |
+
n_ext = 0
|
| 374 |
+
if ext is not None:
|
| 375 |
+
ext = ext.replace([np.inf, -np.inf], np.nan)
|
| 376 |
+
w0 = min(60, len(df) // 5)
|
| 377 |
+
# ısınma sonrası %10'dan fazla boş olan Tickscope kolonlarını at
|
| 378 |
+
ext = ext.loc[:, ext.iloc[w0:].isna().mean() <= 0.10]
|
| 379 |
+
n_ext = ext.shape[1]
|
| 380 |
+
feats = pd.concat([feats, ext], axis=1)
|
| 381 |
close = df["close"]
|
| 382 |
fwd = close.shift(-horizon) / close - 1
|
| 383 |
y = (fwd > 0).astype(float)
|
|
|
|
| 446 |
"p_up": p_up, "acc": acc, "baseline": base, "auc": auc, "price": price, "atr": a,
|
| 447 |
"center": center, "low": center - move, "high": center + move,
|
| 448 |
"thr": best["thr"], "bt": best, "n_oos": len(oos_p), "fee": fee,
|
| 449 |
+
"n_ext": n_ext, "n_feat": len(cols),
|
| 450 |
}
|
| 451 |
|
| 452 |
|
|
|
|
| 467 |
deep = await call_tool(session, tools, "deep_analyze", symbol=symbol,
|
| 468 |
timeframe=timeframe, exchange=exchange)
|
| 469 |
ind = await call_tool(session, tools, "compute_indicators", symbol=symbol,
|
| 470 |
+
timeframe=timeframe, exchange=exchange,
|
| 471 |
+
limit=int(limit), include_series=True)
|
| 472 |
|
| 473 |
# Tickscope'un diğer tüm analiz/piyasa araçları (canlı bağlam; şema uyuşmazsa hata olarak kaydedilir)
|
| 474 |
extra = {}
|
|
|
|
| 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
|
| 502 |
traceback.print_exc()
|
|
|
|
| 516 |
| OOS AUC / doğruluk | {res['auc']:.3f} / {res['acc']:.1%} (baseline {res['baseline']:.1%}) |
|
| 517 |
| OOS işlem sayısı | {bt['n']} (hit {bt['hit']:.1%}, PF {bt['pf']:.2f}) |
|
| 518 |
| Ort. net getiri / işlem | {bt['mean']:.3%} (t = {bt['t']:.2f}, ücret {res['fee']:.2%}/işlem) |
|
| 519 |
+
| Özellik sayısı | {res['n_feat']} (Tickscope göstergesi: {res['n_ext']}) |
|
| 520 |
| Model edge | {edge} |
|
| 521 |
|
| 522 |
*Walk-forward (purged) out-of-sample sonuçlar. Eşik OOS'ta seçildiği için hafif iyimser olabilir. Eğitim/araştırma amaçlıdır; yatırım tavsiyesi değildir.*"""
|
|
|
|
| 534 |
arrayminus=[res["center"] - res["low"]])))
|
| 535 |
fig.update_layout(height=450, xaxis_rangeslider_visible=False, margin=dict(l=10, r=10, t=30, b=10))
|
| 536 |
|
| 537 |
+
raw = json.dumps(_strip_series({"deep_analyze": deep, "compute_indicators": ind, **extra}),
|
| 538 |
indent=2, ensure_ascii=False, default=str)
|
| 539 |
return md, fig, raw
|
| 540 |
|