00996640fb
PM: 34 binarie riconciliate vs daily options; il gap 11pp si decompone in basis USDT (+4-5pp ATM), tempo 8h (-+5pp) e replica su book morti; residuo tail 2-3pp sotto costi; trade coperto reale: lock /bin/bash.1-5, P(conflitto gambe) 2-22%, margine SM domina -> SKIP. HLP: serie daily trovata (wHLP): Sharpe 0.69 non ~2, +12% 2026 = 1 evento, ex-evento +0.2%/a, coda JELLY = inventario ereditato troncato da voto discrezionale, Kelly f*=0 -> SKIP/WATCH con trigger meccanici. 0DTE: fee cap binding = drag 2-3x weekly, IV<RV al front stanotte; snapshot pipeline scritta e primo capture su disco; decisione pre-registrata a 90g di serie. Book INVARIATO. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
474 lines
18 KiB
Python
474 lines
18 KiB
Python
"""r0724_pm_deribit_probe — Riconciliazione LIVE Polymarket <-> Deribit su digitali BTC/ETH.
|
|
|
|
Domanda: quanto del "gap ~11pp" (arXiv 2606.19517, PM vs prob implicite Deribit) sopravvive
|
|
OGGI a una riconciliazione onesta che aggiusta i mismatch di SPEC, e il trade hedged
|
|
(lato cheap su PM + digitale opposta via VERTICAL di opzioni Deribit) ha senso a ~$600?
|
|
|
|
Mismatch di spec quantificati (non assunti):
|
|
1. TEMPO: i PM "above $K on <date>" risolvono sulla candela 1m Binance delle 12:00 ET
|
|
(=16:00 UTC in estate); le daily Deribit scadono 08:00 UTC (settlement TWAP 30m
|
|
dell'indice) -> 8h di varianza extra lato PM. dP_time = N(d2;T_pm) - N(d2;T_der).
|
|
2. FONTE: PM risolve su Binance BTC/USDT; Deribit su indice BTC-USD. Basis misurato
|
|
live (= sconto USDT/USD): pochi bps di spot MA a orizzonte daily con IV ~15%
|
|
vale svariati pp di probabilita' ATM. dP_src = N(d2; S*(1+basis)) - N(d2; S).
|
|
3. REPLICA: la digitale via vertical ha bound sub/super-replicanti:
|
|
call-spread [K,K+w] <= 1{S>K} <= call-spread [K-w,K] (identico coi put OTM).
|
|
Lato ITM i book Deribit sono MORTI -> si replica SEMPRE dal lato OTM
|
|
(K>=S: call; K<S: put, P_above = 1 - put_spread/w). Stima centrale = spread
|
|
centrato [K-w,K+w] sui mark; banda = [sub_mark, super_mark]; eseguibile =
|
|
sub-replica incrociando bid/ask REALI.
|
|
4. COSTI: PM fee 0 ma spread+depth CLOB; Deribit taker 0.0003 ccy/contratto cap
|
|
12.5% del premio per gamba + delivery 0.00015 (cap 12.5%) sul leg ITM; margine
|
|
del leg corto in standard margin (nessun netting del vertical in SM).
|
|
5. RISCHIO NON HEDGIABILE: P(cross) = probabilita' che S stia da lati OPPOSTI di K
|
|
alle 08:00 e alle 16:00 UTC (le due gambe risolvono in conflitto -> payoff 0 o 2):
|
|
MC bivariato con sigma implicita. Vicino all'ATM e' grande -> il "lock" non esiste.
|
|
|
|
Tutto live, API pubbliche tokenless, zero storage; se un endpoint e' vuoto lo dichiara.
|
|
Riproducibile: uv run python scripts/research/r0724_pm_deribit_probe.py
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import math
|
|
import random
|
|
import time
|
|
import urllib.request
|
|
from datetime import datetime, timezone
|
|
|
|
UA = {"User-Agent": "Mozilla/5.0 (research probe)"}
|
|
|
|
|
|
def get(url: str, timeout: int = 20, retries: int = 2):
|
|
for k in range(retries + 1):
|
|
try:
|
|
req = urllib.request.Request(url, headers=UA)
|
|
with urllib.request.urlopen(req, timeout=timeout) as r:
|
|
return json.load(r)
|
|
except Exception as e: # noqa: BLE001
|
|
if k == retries:
|
|
print(f" [FETCH FAIL] {url[:100]} -> {e}")
|
|
return None
|
|
time.sleep(1.0)
|
|
|
|
|
|
def ncdf(x: float) -> float:
|
|
return 0.5 * (1.0 + math.erf(x / math.sqrt(2.0)))
|
|
|
|
|
|
def bs_digital(S: float, K: float, sig: float, T_yr: float) -> float:
|
|
if T_yr <= 0 or sig <= 0:
|
|
return 1.0 if S > K else 0.0
|
|
d2 = (math.log(S / K) - 0.5 * sig * sig * T_yr) / (sig * math.sqrt(T_yr))
|
|
return ncdf(d2)
|
|
|
|
|
|
# ----------------------------------------------------------------------------- Polymarket
|
|
PM_EVENTS = [
|
|
("BTC", "bitcoin-above-on-july-25-2026", "25JUL26"),
|
|
("ETH", "ethereum-above-on-july-25-2026", "25JUL26"),
|
|
("BTC", "bitcoin-above-on-july-26-2026", "26JUL26"),
|
|
("ETH", "ethereum-above-on-july-26-2026", "26JUL26"),
|
|
("BTC", "bitcoin-above-on-july-27-2026", "27JUL26"),
|
|
("ETH", "ethereum-above-on-july-27-2026", "27JUL26"),
|
|
]
|
|
|
|
|
|
def parse_strike(question: str) -> float | None:
|
|
import re
|
|
|
|
m = re.search(r"\$([\d,]+(?:\.\d+)?)", question)
|
|
return float(m.group(1).replace(",", "")) if m else None
|
|
|
|
|
|
def fetch_pm():
|
|
out = []
|
|
for asset, slug, dexp in PM_EVENTS:
|
|
ev = get(f"https://gamma-api.polymarket.com/events?slug={slug}")
|
|
if not ev:
|
|
print(f"[PM] evento {slug}: VUOTO/bloccato")
|
|
continue
|
|
ev = ev[0]
|
|
for m in ev["markets"]:
|
|
K = parse_strike(m["question"])
|
|
if K is None:
|
|
continue
|
|
desc = m.get("description", "")
|
|
tok = json.loads(m.get("clobTokenIds", "[]"))
|
|
out.append(
|
|
dict(
|
|
asset=asset,
|
|
dexp=dexp,
|
|
end=ev["endDate"],
|
|
K=K,
|
|
yes_bid=float(m["bestBid"]) if m.get("bestBid") else None,
|
|
yes_ask=float(m["bestAsk"]) if m.get("bestAsk") else None,
|
|
vol24=float(m.get("volume24hr") or 0),
|
|
spec_ok=("Binance" in desc and "12:00 in the ET" in desc),
|
|
yes_token=tok[0] if tok else None,
|
|
)
|
|
)
|
|
return out
|
|
|
|
|
|
def pm_book_depth(token_id: str):
|
|
b = get(f"https://clob.polymarket.com/book?token_id={token_id}")
|
|
if not b or not b.get("bids") or not b.get("asks"):
|
|
return None
|
|
bids = [(float(x["price"]), float(x["size"])) for x in b["bids"]]
|
|
asks = [(float(x["price"]), float(x["size"])) for x in b["asks"]]
|
|
bb, ba = max(p for p, _ in bids), min(p for p, _ in asks)
|
|
mid = 0.5 * (bb + ba)
|
|
d = {}
|
|
for w in (0.01, 0.02):
|
|
d[w] = (
|
|
sum(s * p for p, s in bids if p >= mid - w),
|
|
sum(s * p for p, s in asks if p <= mid + w),
|
|
)
|
|
return dict(bb=bb, ba=ba, depth=d)
|
|
|
|
|
|
# ------------------------------------------------------------------------------- Deribit
|
|
def fetch_deribit(ccy: str):
|
|
bs = get(
|
|
"https://www.deribit.com/api/v2/public/get_book_summary_by_currency"
|
|
f"?currency={ccy}&kind=option"
|
|
)
|
|
idx = get(
|
|
f"https://www.deribit.com/api/v2/public/get_index_price?index_name={ccy.lower()}_usd"
|
|
)
|
|
ins = get(
|
|
f"https://www.deribit.com/api/v2/public/get_instruments?currency={ccy}"
|
|
"&kind=option&expired=false"
|
|
)
|
|
if not bs or not idx or not ins:
|
|
return None
|
|
books = {row["instrument_name"]: row for row in bs["result"]}
|
|
expts = {}
|
|
for i in ins["result"]:
|
|
expts[i["instrument_name"].split("-")[1]] = i["expiration_timestamp"] / 1000.0
|
|
return dict(books=books, index=idx["result"]["index_price"], expts=expts)
|
|
|
|
|
|
def _q(books, ccy, dexp, strike, typ, index):
|
|
"""(bid_usd, ask_usd, mark_usd) di uno strumento; None se assente."""
|
|
n = f"{ccy}-{dexp}-{int(strike)}-{typ}"
|
|
r = books.get(n)
|
|
if not r:
|
|
return None
|
|
return dict(
|
|
n=n,
|
|
bid=(r["bid_price"] or 0.0) * index,
|
|
ask=(r["ask_price"] * index) if r["ask_price"] else None,
|
|
mark=(r.get("mark_price") or 0.0) * index,
|
|
)
|
|
|
|
|
|
def deribit_digital(books, ccy, dexp, K, index):
|
|
"""Stima onesta di P(S_der > K) via vertical OTM-side.
|
|
|
|
Ritorna: mark centrato, banda [sub_mark, super_mark], eseguibili
|
|
(exec_buy = costo per COMPRARE la sub-replica dell'above-digitale ai prezzi reali;
|
|
exec_sell = incasso per VENDERLA), gambe usate.
|
|
"""
|
|
typ = "C" if K >= index else "P"
|
|
strikes = sorted(
|
|
float(n.split("-")[2])
|
|
for n in books
|
|
if n.split("-")[1] == dexp and n.endswith(f"-{typ}")
|
|
)
|
|
if K not in strikes:
|
|
return None # tutti gli strike PM qui coincidono con strike listati
|
|
i = strikes.index(K)
|
|
if i == 0 or i == len(strikes) - 1:
|
|
return None
|
|
Km, Kp = strikes[i - 1], strikes[i + 1]
|
|
qm, q0, qp = (
|
|
_q(books, ccy, dexp, Km, typ, index),
|
|
_q(books, ccy, dexp, K, typ, index),
|
|
_q(books, ccy, dexp, Kp, typ, index),
|
|
)
|
|
if not (qm and q0 and qp):
|
|
return None
|
|
|
|
if typ == "C":
|
|
centered = (qm["mark"] - qp["mark"]) / (Kp - Km)
|
|
sub = (q0["mark"] - qp["mark"]) / (Kp - K) # <= P
|
|
sup = (qm["mark"] - q0["mark"]) / (K - Km) # >= P
|
|
# comprare sub-replica: buy C(K), sell C(Kp)
|
|
exec_buy = (
|
|
(q0["ask"] - qp["bid"]) / (Kp - K) if q0["ask"] is not None else None
|
|
)
|
|
exec_sell = (
|
|
(q0["bid"] - qp["ask"]) / (Kp - K) if qp["ask"] is not None else None
|
|
)
|
|
legs = (q0, qp)
|
|
else:
|
|
# P_above = 1 - put_spread/w ; [K,Kp] put spread super-replica il below
|
|
centered = 1.0 - (qp["mark"] - qm["mark"]) / (Kp - Km)
|
|
sub = 1.0 - (qp["mark"] - q0["mark"]) / (Kp - K) # <= P_above
|
|
sup = 1.0 - (q0["mark"] - qm["mark"]) / (K - Km) # >= P_above
|
|
# comprare (sinteticamente) l'above = VENDERE il put spread [K,Kp]:
|
|
# incasso bid(Kp)-ask(K); prezzo implicito pagato = 1 - incasso/w
|
|
exec_buy = (
|
|
1.0 - (qp["bid"] - q0["ask"]) / (Kp - K) if q0["ask"] is not None else None
|
|
)
|
|
exec_sell = (
|
|
1.0 - (qp["ask"] - q0["bid"]) / (Kp - K) if qp["ask"] is not None else None
|
|
)
|
|
legs = (q0, qp)
|
|
return dict(
|
|
typ=typ,
|
|
Km=Km,
|
|
Kp=Kp,
|
|
w=Kp - K,
|
|
centered=centered,
|
|
sub=sub,
|
|
sup=sup,
|
|
exec_buy=exec_buy,
|
|
exec_sell=exec_sell,
|
|
legs=legs,
|
|
)
|
|
|
|
|
|
IV_CACHE: dict = {}
|
|
|
|
|
|
def deribit_iv(ccy: str, dexp: str, name: str) -> float | None:
|
|
if name in IV_CACHE:
|
|
return IV_CACHE[name]
|
|
t = get(f"https://www.deribit.com/api/v2/public/ticker?instrument_name={name}")
|
|
iv = None
|
|
if t:
|
|
iv = t["result"].get("mark_iv")
|
|
iv = iv / 100.0 if iv else None
|
|
IV_CACHE[name] = iv
|
|
return iv
|
|
|
|
|
|
def p_cross(S, K, sig, T1_yr, T2_yr, n=200_000, seed=7):
|
|
"""MC: P(lati opposti di K a T1 e T2) e P(sopra a T2 ma sotto a T1) ecc."""
|
|
rng = random.Random(seed)
|
|
lo_hi = hi_lo = 0
|
|
lnK = math.log(K / S)
|
|
s1 = sig * math.sqrt(T1_yr)
|
|
s2x = sig * math.sqrt(max(T2_yr - T1_yr, 1e-12))
|
|
for _ in range(n):
|
|
x1 = -0.5 * s1 * s1 + s1 * rng.gauss(0, 1)
|
|
x2 = x1 - 0.5 * s2x * s2x + s2x * rng.gauss(0, 1)
|
|
a, b = x1 > lnK, x2 > lnK
|
|
if not a and b:
|
|
lo_hi += 1
|
|
elif a and not b:
|
|
hi_lo += 1
|
|
return lo_hi / n, hi_lo / n
|
|
|
|
|
|
# ----------------------------------------------------------------------------------- run
|
|
def main():
|
|
now = datetime.now(timezone.utc)
|
|
print(f"=== PROBE PM<->DERIBIT {now.isoformat(timespec='seconds')} ===\n")
|
|
|
|
pm = fetch_pm()
|
|
nbad = sum(1 for m in pm if not m["spec_ok"])
|
|
print(f"[PM] {len(pm)} mercati above/below; spec Binance/12:00ET non confermata su {nbad}")
|
|
|
|
der = {c: fetch_deribit(c) for c in ("BTC", "ETH")}
|
|
for c, d in der.items():
|
|
if d:
|
|
print(f"[Deribit] {c} index={d['index']:.2f}")
|
|
|
|
def binance_spot(sym):
|
|
for host in ("https://api.binance.com", "https://data-api.binance.vision"):
|
|
r = get(f"{host}/api/v3/ticker/price?symbol={sym}", timeout=10, retries=0)
|
|
if r and "price" in r:
|
|
return float(r["price"])
|
|
return None
|
|
|
|
binance = {"BTC": binance_spot("BTCUSDT"), "ETH": binance_spot("ETHUSDT")}
|
|
kr = get("https://api.kraken.com/0/public/Ticker?pair=USDTZUSD", timeout=10, retries=1)
|
|
usdtusd = None
|
|
try:
|
|
usdtusd = float(list(kr["result"].values())[0]["c"][0])
|
|
except Exception: # noqa: BLE001
|
|
pass
|
|
print(f"[Binance] BTCUSDT={binance['BTC']} ETHUSDT={binance['ETH']} | USDT/USD={usdtusd}")
|
|
basis = {}
|
|
for c in ("BTC", "ETH"):
|
|
basis[c] = (binance[c] / der[c]["index"] - 1.0) if (der[c] and binance[c]) else 0.0
|
|
print(f" basis {c} BinanceUSDT vs indice Deribit: {basis[c]*1e4:+.1f} bps")
|
|
|
|
rows = []
|
|
for m in pm:
|
|
c, d = m["asset"], der[m["asset"]]
|
|
if not d or m["dexp"] not in d["expts"]:
|
|
continue
|
|
S = d["index"]
|
|
dig = deribit_digital(d["books"], c, m["dexp"], m["K"], S)
|
|
if dig is None:
|
|
continue
|
|
T_der = max(d["expts"][m["dexp"]] - now.timestamp(), 0) / (365.25 * 86400)
|
|
t_pm = datetime.fromisoformat(m["end"].replace("Z", "+00:00")).timestamp()
|
|
T_pm = max(t_pm - now.timestamp(), 0) / (365.25 * 86400)
|
|
near = abs(math.log(m["K"] / S)) < 0.09
|
|
sig = deribit_iv(c, m["dexp"], dig["legs"][0]["n"]) if near else None
|
|
if sig is None:
|
|
sig = 0.45
|
|
dP_time = bs_digital(S, m["K"], sig, T_pm) - bs_digital(S, m["K"], sig, T_der)
|
|
dP_src = bs_digital(S * (1 + basis[c]), m["K"], sig, T_pm) - bs_digital(
|
|
S, m["K"], sig, T_pm
|
|
)
|
|
pm_mid = (
|
|
0.5 * (m["yes_bid"] + m["yes_ask"])
|
|
if (m["yes_bid"] is not None and m["yes_ask"] is not None)
|
|
else (m["yes_ask"] or m["yes_bid"])
|
|
)
|
|
raw = pm_mid - dig["centered"] if pm_mid is not None else None
|
|
resid = raw - dP_time - dP_src if raw is not None else None
|
|
depth = pm_book_depth(m["yes_token"]) if (m["yes_token"] and near) else None
|
|
rows.append(
|
|
dict(
|
|
m=m,
|
|
dig=dig,
|
|
sig=sig,
|
|
T_der=T_der,
|
|
T_pm=T_pm,
|
|
dP_time=dP_time,
|
|
dP_src=dP_src,
|
|
pm_mid=pm_mid,
|
|
raw=raw,
|
|
resid=resid,
|
|
depth=depth,
|
|
S=S,
|
|
near=near,
|
|
)
|
|
)
|
|
|
|
print("\n=== RICONCILIAZIONE (prob %, gap pp; digitale = vertical OTM-side) ===")
|
|
hdr = (
|
|
f"{'mkt':<22}{'PM b/a':>12}{'Der mark[sub,sup]':>20}{'exec b/s':>13}"
|
|
f"{'raw':>7}{'dT':>6}{'dSrc':>6}{'resid':>7}{'iv%':>5}"
|
|
)
|
|
print(hdr)
|
|
print("-" * len(hdr))
|
|
for r in rows:
|
|
m, g = r["m"], r["dig"]
|
|
name = f"{m['asset']} >{int(m['K'])} {m['dexp'][:5]}"
|
|
pmba = (
|
|
f"{(m['yes_bid'] or 0)*100:.1f}/{(m['yes_ask'] or 0)*100:.1f}"
|
|
if (m["yes_bid"] is not None or m["yes_ask"] is not None)
|
|
else "n/a"
|
|
)
|
|
ex = (
|
|
f"{g['exec_buy']*100:.0f}/{g['exec_sell']*100:.0f}"
|
|
if (g["exec_buy"] is not None and g["exec_sell"] is not None)
|
|
else "n/q"
|
|
)
|
|
print(
|
|
f"{name:<22}{pmba:>12}"
|
|
f"{g['centered']*100:>8.1f}[{g['sub']*100:.0f},{g['sup']*100:.0f}]".ljust(42)
|
|
+ f"{ex:>13}"
|
|
f"{(r['raw'] or 0)*100:>+7.1f}{r['dP_time']*100:>+6.1f}"
|
|
f"{r['dP_src']*100:>+6.1f}{(r['resid'] or 0)*100:>+7.1f}"
|
|
f"{r['sig']*100:>5.0f}"
|
|
)
|
|
print(
|
|
"\n Der mark = spread centrato sui mark, [sub,sup] = bound di replica;"
|
|
" exec b/s = comprare/vendere la sub-replica ai bid/ask REALI."
|
|
"\n raw = PM_mid - Der_mark; resid = raw - dT - dSrc"
|
|
" (>0: PM sovraprezza il lato above vs Deribit spec-adjusted)."
|
|
)
|
|
|
|
# sistematicita' per bucket di moneyness
|
|
print("\n=== RESIDUO PER BUCKET (solo quote PM a doppio lato) ===")
|
|
buckets = {"ITM(K<S-1.5%)": [], "ATM(|1.5%|)": [], "OTM(K>S+1.5%)": []}
|
|
for r in rows:
|
|
if r["resid"] is None or r["m"]["yes_bid"] is None or r["m"]["yes_ask"] is None:
|
|
continue
|
|
lm = math.log(r["m"]["K"] / r["S"])
|
|
b = "ITM(K<S-1.5%)" if lm < -0.015 else ("OTM(K>S+1.5%)" if lm > 0.015 else "ATM(|1.5%|)")
|
|
buckets[b].append(r["resid"])
|
|
for b, v in buckets.items():
|
|
if v:
|
|
pos = sum(1 for x in v if x > 0)
|
|
print(
|
|
f" {b:<15} n={len(v):>2} resid medio {sum(v)/len(v)*100:+.1f}pp"
|
|
f" mediana {sorted(v)[len(v)//2]*100:+.1f}pp >0: {pos}/{len(v)}"
|
|
)
|
|
|
|
print("\n=== DEPTH CLOB PM (vicino allo spot) ===")
|
|
for r in rows:
|
|
if r["depth"]:
|
|
m, dp = r["m"], r["depth"]
|
|
d1, d2 = dp["depth"][0.01], dp["depth"][0.02]
|
|
print(
|
|
f" {m['asset']} >{int(m['K'])} {m['dexp']}: book {dp['bb']:.3f}/{dp['ba']:.3f}"
|
|
f" depth±1c ${d1[0]:,.0f}/${d1[1]:,.0f} ±2c ${d2[0]:,.0f}/${d2[1]:,.0f}"
|
|
f" vol24h ${m['vol24']:,.0f}"
|
|
)
|
|
|
|
# ------------------------------------------------------------------ trade hedged demo
|
|
print("\n=== TRADE HEDGED a size minima (0.1 BTC / 1 ETH) — numeri VERI ===")
|
|
min_amt = {"BTC": 0.1, "ETH": 1.0}
|
|
fee_rate, dlv_rate = 0.0003, 0.00015
|
|
for r in rows:
|
|
m, g = r["m"], r["dig"]
|
|
if r["resid"] is None or not r["near"] or abs(r["resid"]) < 0.01:
|
|
continue
|
|
if g["exec_buy"] is None or g["exec_sell"] is None:
|
|
continue
|
|
c, S = m["asset"], r["S"]
|
|
amt = min_amt[c]
|
|
W = g["w"] * amt # notional digitale $
|
|
if r["resid"] > 0:
|
|
# PM ricco sul lato above: buy PM NO al (1-yes_bid) + buy digitale-above Deribit
|
|
pm_px = 1 - (m["yes_bid"] or 0)
|
|
der_px = g["exec_buy"]
|
|
side = "BUY PM NO + LONG vertical OTM (sub-replica above)"
|
|
else:
|
|
pm_px = m["yes_ask"] or 1
|
|
der_px = 1 - g["exec_sell"]
|
|
side = "BUY PM YES + SHORT vertical OTM (sub-replica below)"
|
|
cost = (pm_px + der_px) * W
|
|
lock = W - cost
|
|
fees = 0.0
|
|
for leg in g["legs"]:
|
|
fees += min(fee_rate * amt * S, 0.125 * leg["mark"] * amt)
|
|
dlv = min(dlv_rate * amt * S, 0.125 * max(le["mark"] for le in g["legs"]) * amt)
|
|
otm_frac = abs(g["Kp"] - S) / S
|
|
mark_short = g["legs"][1]["mark"] / S
|
|
im = (max(0.15 - otm_frac, 0.10) + mark_short) * amt
|
|
pc = p_cross(S, m["K"], r["sig"], r["T_der"], r["T_pm"])
|
|
capital = cost + im * S
|
|
net = lock - fees - dlv
|
|
days = r["T_pm"] * 365.25
|
|
print(f"\n {m['asset']} >{int(m['K'])} {m['dexp']} resid {r['resid']*100:+.1f}pp -> {side}")
|
|
print(
|
|
f" gambe Deribit {g['legs'][0]['n']}/{g['legs'][1]['n']} amount {amt} {c}"
|
|
f" -> payout digitale ${W:,.0f}"
|
|
)
|
|
print(
|
|
f" costo PM ${pm_px*W:,.2f} + Deribit ${der_px*W:,.2f} = ${cost:,.2f};"
|
|
f" lock lordo ${lock:,.2f}; fee entry ${fees:.2f} + delivery ${dlv:.2f}"
|
|
f" -> netto ${net:,.2f}"
|
|
)
|
|
print(
|
|
f" margine leg corto (SM, no netting) ~${im*S:,.0f};"
|
|
f" capitale impegnato ~${capital:,.0f};"
|
|
f" ritorno se lock regge: {net/capital*100:.2f}% in {days:.1f}g"
|
|
f" (~{net/capital*365.25/days*100:.0f}%/anno)"
|
|
)
|
|
print(
|
|
f" RISCHIO CROSS 08->16 UTC (MC, iv {r['sig']*100:.0f}%):"
|
|
f" P(sotto@08,sopra@16)={pc[0]*100:.1f}% P(sopra@08,sotto@16)={pc[1]*100:.1f}%"
|
|
f" -> P(gambe in conflitto)={sum(pc)*100:.1f}%"
|
|
)
|
|
|
|
print("\n[NOTE] Deribit settle = TWAP 30m pre-08:00 UTC vs PM candela 1m 16:00 UTC;")
|
|
print("la sub-replica paga <1 nella rampa [K,K+w] -> il 'lock' e' un bound inferiore")
|
|
print("solo FUORI dalla rampa; ATM con w=500 (BTC) la rampa e' ~1-1.5 sigma daily.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|