research(surfer): crypto edge-falsification probes — intraday/cascade dead, stablecoin peg-reversion validated

- crypto_mft_xsec / mft_*: intraday/MFT XS price edge FALSIFIED (fee-trap)
- crypto_cascade_reversion: liquidation-cascade reversion FALSIFIED (continuation)
- crypto_trend_sizing: TS-trend return-engine reconfirmed (Sharpe ~1.25)
- crypto_stablecoin_dislocation/harden/intraday: short-rich peg-reversion VALIDATED (bounded, uncorrelated); long-cheap = death-spiral trap

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-06-21 10:40:34 +02:00
parent 6878aac950
commit f4bd1e2432
9 changed files with 1180 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
#!/usr/bin/env python3
"""Stablecoin peg-reversion existence test — the cleanest crypto-FX dislocation.
Stablecoins are supposed to be worth $1; mint/redeem arbitrage (forced flow) pulls a deviation back
to parity. This tests whether that reversion is harvestable NET OF COST on free Binance spot data, and
— critically — how bad the DEATH-SPIRAL tail is (some "depegs" never revert: UST->0, BUSD wind-down).
Pre-registered: pair STABLE/USDT, deviation d=close-1. Reversion bet when |d|>thresh: position =
-sign(d) (rich->short, cheap->long), hold H days, pnl_net = -sign(d)*(close[t+H]/close[t]-1) - cost_rt.
Report per-pair + pooled: trade count, mean net pnl (bp), hit%, WORST trade (bp, the death-spiral tail),
and a daily-strategy Sharpe. Cost levels bracket Binance stablecoin fees {0,2,10}bp round-trip.
KILL: pooled net mean<=0 OR edge entirely from one terminal name OR worst-trade tail dwarfs mean edge.
LIMITATION: overlapping forward windows (first-look existence test, not a hardened backtest); daily
granularity (intraday depeg spikes under-sampled). Flagged, not hidden.
"""
import json
import math
import os
import time
import urllib.request
import numpy as np
OUT = "data/surfer/stablecoin"
PAIRS = ["USDCUSDT", "FDUSDUSDT", "TUSDUSDT", "DAIUSDT", "BUSDUSDT", "USDPUSDT"]
DAY_MS = 86_400_000
THRESHOLDS_BP = [10, 25, 50]
HOLDS = [1, 2, 5]
COSTS_BP = [0.0, 2.0, 10.0]
def _get(u):
return json.load(urllib.request.urlopen(urllib.request.Request(u, headers={"User-Agent": "curl/8"}), timeout=30))
def fetch(sym):
cache = f"{OUT}/{sym}.npz"
if os.path.exists(cache):
d = np.load(cache); return d["ts"], d["close"]
start = 1_546_300_800_000 # 2019-01-01
end = int(time.time() * 1000)
rows, cur = [], start
for _ in range(400):
k = _get(f"https://api.binance.com/api/v3/klines?symbol={sym}&interval=1d&startTime={cur}&limit=1000")
if not k:
break
rows += k
cur = k[-1][0] + DAY_MS
if len(k) < 1000 or cur >= end:
break
time.sleep(0.05)
if not rows:
return np.array([]), np.array([])
d = {int(r[0]): float(r[4]) for r in rows}
ts = np.array(sorted(d)); close = np.array([d[t] for t in ts])
os.makedirs(OUT, exist_ok=True)
np.savez(cache, ts=ts, close=close)
return ts, close
def reversion(close, thresh_bp, H, cost_bp):
"""Event reversion bet: enter when |d|>thresh, pnl=-sign(d)*(fwd_ret)-cost_rt. Returns net-pnl array (bp)."""
d = close - 1.0
th = thresh_bp / 1e4
pnls = []
for t in range(len(close) - H):
if abs(d[t]) > th and close[t] > 0:
fwd = close[t + H] / close[t] - 1.0
pnl = -np.sign(d[t]) * fwd - cost_bp / 1e4
pnls.append(pnl * 1e4) # in bp
return np.array(pnls)
def run():
series = {}
for s in PAIRS:
ts, c = fetch(s)
if len(ts) > 60:
series[s] = c
print("\n========== STABLECOIN PEG-REVERSION (crypto-FX dislocation, free Binance spot daily) ==========")
print(f"pairs: {', '.join(f'{s}({len(c)}d)' for s, c in series.items())}\n")
# 1) dislocation frequency per pair
print("--- dislocation magnitude (|close-1|) per pair ---")
print(f"{'pair':>9} {'days':>5} {'med_bp':>7} {'p95_bp':>7} {'max_bp':>8} {'>10bp%':>7} {'>50bp%':>7}")
for s, c in series.items():
d = np.abs(c - 1.0) * 1e4
print(f"{s:>9} {len(c):>5} {np.median(d):>7.1f} {np.percentile(d,95):>7.1f} {d.max():>8.0f} "
f"{100*np.mean(d>10):>6.1f}% {100*np.mean(d>50):>6.1f}%")
# 2) reversion edge, pooled across pairs, by (thresh, H, cost)
print("\n--- reversion edge (pooled all pairs); pnl in bp/trade, net of round-trip cost ---")
print(f"{'thr_bp':>6} {'H':>2} {'cost':>5} {'trades':>7} {'mean_bp':>8} {'hit%':>6} {'worst_bp':>9} {'daily_SR':>9}")
for th in THRESHOLDS_BP:
for H in HOLDS:
for cost in COSTS_BP:
allp = np.concatenate([reversion(c, th, H, cost) for c in series.values()]) if series else np.array([])
if len(allp) < 10:
continue
sr = (allp.mean() / allp.std() * math.sqrt(365 / H)) if allp.std() > 0 else float("nan")
print(f"{th:>6} {H:>2} {cost:>4.0f}b {len(allp):>7} {allp.mean():>+8.1f} "
f"{100*np.mean(allp>0):>5.1f}% {allp.min():>+9.0f} {sr:>+9.2f}")
print(" " + "-" * 60)
# 3) per-pair edge at a fixed mid setting (thr=25bp, H=2, cost=2bp) — is it one terminal name?
print("\n--- per-pair edge @ thr=25bp H=2 cost=2bp (is the edge concentrated/terminal?) ---")
print(f"{'pair':>9} {'trades':>7} {'mean_bp':>8} {'hit%':>6} {'worst_bp':>9}")
for s, c in series.items():
p = reversion(c, 25, 2, 2.0)
if len(p) >= 5:
print(f"{s:>9} {len(p):>7} {p.mean():>+8.1f} {100*np.mean(p>0):>5.1f}% {p.min():>+9.0f}")
else:
print(f"{s:>9} {len(p):>7} (too few events)")
print("\nKILL if: pooled mean<=0, OR edge is one terminal name, OR |worst_bp| dwarfs mean (death-spiral tail).")
if __name__ == "__main__":
run()